deleted: export="true"
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ClassFile.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler;
12
13 import java.io.BufferedOutputStream;
14 import java.io.File;
15 import java.io.FileOutputStream;
16 import java.io.IOException;
17 import java.util.StringTokenizer;
18
19 import net.sourceforge.phpdt.core.compiler.IProblem;
20 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
21 import net.sourceforge.phpdt.internal.compiler.ast.Argument;
22 import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
23 import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration;
24 import net.sourceforge.phpdt.internal.compiler.ast.FieldReference;
25 import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration;
26 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
27 import net.sourceforge.phpdt.internal.compiler.codegen.AttributeNamesConstants;
28 import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
29 import net.sourceforge.phpdt.internal.compiler.codegen.ConstantPool;
30 import net.sourceforge.phpdt.internal.compiler.codegen.ExceptionLabel;
31 import net.sourceforge.phpdt.internal.compiler.codegen.QualifiedNamesConstants;
32 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
33 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
34 import net.sourceforge.phpdt.internal.compiler.impl.StringConstant;
35 import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers;
36 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
37 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
38 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
39 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
40 import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding;
41 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
42 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
43 import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticAccessMethodBinding;
44 import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticArgumentBinding;
45 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
46 import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
47 import net.sourceforge.phpdt.internal.compiler.lookup.TypeIds;
48 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
49 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
50 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfType;
51 import net.sourceforge.phpdt.internal.compiler.util.Util;
52
53 /**
54  * Represents a class file wrapper on bytes, it is aware of its actual
55  * type name.
56  *
57  * Public APIs are listed below:
58  *
59  * byte[] getBytes();
60  *              Answer the actual bytes of the class file
61  *
62  * char[][] getCompoundName();
63  *              Answer the compound name of the class file.
64  *              For example, {{java}, {util}, {Hashtable}}.
65  *
66  * byte[] getReducedBytes();
67  *              Answer a smaller byte format, which is only contains some structural 
68  *      information. Those bytes are decodable with a regular class file reader, 
69  *      such as DietClassFileReader
70  */
71 public class ClassFile
72         implements AttributeNamesConstants, CompilerModifiers, TypeConstants, TypeIds {
73         public SourceTypeBinding referenceBinding;
74         public ConstantPool constantPool;
75         public ClassFile enclosingClassFile;
76         // used to generate private access methods
77         public int produceDebugAttributes;
78         public ReferenceBinding[] innerClassesBindings;
79         public int numberOfInnerClasses;
80         public byte[] header;
81         // the header contains all the bytes till the end of the constant pool
82         public byte[] contents;
83         // that collection contains all the remaining bytes of the .class file
84         public int headerOffset;
85         public int contentsOffset;
86         public int constantPoolOffset;
87         public int methodCountOffset;
88         public int methodCount;
89         protected boolean creatingProblemType;
90         public static final int INITIAL_CONTENTS_SIZE = 1000;
91         public static final int INITIAL_HEADER_SIZE = 1000;
92         public static final int INCREMENT_SIZE = 1000;
93         public static final int INNER_CLASSES_SIZE = 5;
94         protected HashtableOfType nameUsage;
95         public CodeStream codeStream;
96         protected int problemLine;      // used to create line number attributes for problem methods
97
98         /**
99          * INTERNAL USE-ONLY
100          * This methods creates a new instance of the receiver.
101          */
102         public ClassFile() {
103         }
104
105         /**
106          * INTERNAL USE-ONLY
107          * This methods creates a new instance of the receiver.
108          *
109          * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding
110          * @param enclosingClassFile org.eclipse.jdt.internal.compiler.ClassFile
111          * @param creatingProblemType <CODE>boolean</CODE>
112          */
113         public ClassFile(
114                 SourceTypeBinding aType,
115                 ClassFile enclosingClassFile,
116                 boolean creatingProblemType) {
117                 referenceBinding = aType;
118                 header = new byte[INITIAL_HEADER_SIZE];
119                 // generate the magic numbers inside the header
120                 header[headerOffset++] = (byte) (0xCAFEBABEL >> 24);
121                 header[headerOffset++] = (byte) (0xCAFEBABEL >> 16);
122                 header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
123                 header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
124                 switch(((SourceTypeBinding) referenceBinding).scope.environment().options.targetJDK) {
125                         case CompilerOptions.JDK1_4 :
126                                 // Compatible with JDK 1.4
127                                 header[headerOffset++] = 0;
128                                 header[headerOffset++] = 0;
129                                 header[headerOffset++] = 0;
130                                 header[headerOffset++] = 48;
131                                 break;
132                         case CompilerOptions.JDK1_3 :
133                                 // Compatible with JDK 1.3
134                                 header[headerOffset++] = 0;
135                                 header[headerOffset++] = 0;
136                                 header[headerOffset++] = 0;
137                                 header[headerOffset++] = 47;
138                                 break;
139                         case CompilerOptions.JDK1_2 :
140                                 // Compatible with JDK 1.2
141                                 header[headerOffset++] = 0;
142                                 header[headerOffset++] = 0;
143                                 header[headerOffset++] = 0;
144                                 header[headerOffset++] = 46;
145                                 break;
146                         case CompilerOptions.JDK1_1 :
147                                 // Compatible with JDK 1.1
148                                 header[headerOffset++] = 0;
149                                 header[headerOffset++] = 3;
150                                 header[headerOffset++] = 0;
151                                 header[headerOffset++] = 45;
152                 }
153                 constantPoolOffset = headerOffset;
154                 headerOffset += 2;
155                 constantPool = new ConstantPool(this);
156                 
157                 // Modifier manipulations for classfile
158                 int accessFlags = aType.getAccessFlags();
159                 if (aType.isPrivate()) { // rewrite private to non-public
160                         accessFlags &= ~AccPublic;
161                 }
162                 if (aType.isProtected()) { // rewrite protected into public
163                         accessFlags |= AccPublic;
164                 }
165                 // clear all bits that are illegal for a class or an interface
166                 accessFlags
167                         &= ~(
168                                 AccStrictfp
169                                         | AccProtected
170                                         | AccPrivate
171                                         | AccStatic
172                                         | AccSynchronized
173                                         | AccNative);
174                                         
175                 // set the AccSuper flag (has to be done after clearing AccSynchronized - since same value)
176                 accessFlags |= AccSuper;
177                 
178                 this.enclosingClassFile = enclosingClassFile;
179                 // innerclasses get their names computed at code gen time
180                 if (aType.isLocalType()) {
181                         ((LocalTypeBinding) aType).constantPoolName(
182                                 computeConstantPoolName((LocalTypeBinding) aType));
183                         ReferenceBinding[] memberTypes = aType.memberTypes();
184                         for (int i = 0, max = memberTypes.length; i < max; i++) {
185                                 ((LocalTypeBinding) memberTypes[i]).constantPoolName(
186                                         computeConstantPoolName((LocalTypeBinding) memberTypes[i]));
187                         }
188                 }
189                 contents = new byte[INITIAL_CONTENTS_SIZE];
190                 // now we continue to generate the bytes inside the contents array
191                 contents[contentsOffset++] = (byte) (accessFlags >> 8);
192                 contents[contentsOffset++] = (byte) accessFlags;
193                 int classNameIndex = constantPool.literalIndex(aType);
194                 contents[contentsOffset++] = (byte) (classNameIndex >> 8);
195                 contents[contentsOffset++] = (byte) classNameIndex;
196                 int superclassNameIndex;
197                 if (aType.isInterface()) {
198                         superclassNameIndex = constantPool.literalIndexForJavaLangObject();
199                 } else {
200                         superclassNameIndex =
201                                 (aType.superclass == null ? 0 : constantPool.literalIndex(aType.superclass));
202                 }
203                 contents[contentsOffset++] = (byte) (superclassNameIndex >> 8);
204                 contents[contentsOffset++] = (byte) superclassNameIndex;
205                 ReferenceBinding[] superInterfacesBinding = aType.superInterfaces();
206                 int interfacesCount = superInterfacesBinding.length;
207                 contents[contentsOffset++] = (byte) (interfacesCount >> 8);
208                 contents[contentsOffset++] = (byte) interfacesCount;
209                 if (superInterfacesBinding != null) {
210                         for (int i = 0; i < interfacesCount; i++) {
211                                 int interfaceIndex = constantPool.literalIndex(superInterfacesBinding[i]);
212                                 contents[contentsOffset++] = (byte) (interfaceIndex >> 8);
213                                 contents[contentsOffset++] = (byte) interfaceIndex;
214                         }
215                 }
216                 produceDebugAttributes =
217                         ((SourceTypeBinding) referenceBinding)
218                                 .scope
219                                 .environment()
220                                 .options
221                                 .produceDebugAttributes;
222                 innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE];
223                 this.creatingProblemType = creatingProblemType;
224                 codeStream = new CodeStream(this);
225
226                 // retrieve the enclosing one guaranteed to be the one matching the propagated flow info
227                 // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check)
228                 ClassFile outermostClassFile = this.outerMostEnclosingClassFile();
229                 if (this == outermostClassFile) {
230                         codeStream.maxFieldCount = aType.scope.referenceType().maxFieldCount;
231                 } else {
232                         codeStream.maxFieldCount = outermostClassFile.codeStream.maxFieldCount;
233                 }
234         }
235
236         /**
237          * INTERNAL USE-ONLY
238          * Generate the byte for a problem method info that correspond to a boggus method.
239          *
240          * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
241          * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
242          */
243         public void addAbstractMethod(
244                 AbstractMethodDeclaration method,
245                 MethodBinding methodBinding) {
246
247                 // force the modifiers to be public and abstract
248                 methodBinding.modifiers = AccPublic | AccAbstract;
249
250                 this.generateMethodInfoHeader(methodBinding);
251                 int methodAttributeOffset = this.contentsOffset;
252                 int attributeNumber = this.generateMethodInfoAttribute(methodBinding);
253                 this.completeMethodInfo(methodAttributeOffset, attributeNumber);
254         }
255
256         /**
257          * INTERNAL USE-ONLY
258          * This methods generate all the attributes for the receiver.
259          * For a class they could be:
260          * - source file attribute
261          * - inner classes attribute
262          * - deprecated attribute
263          */
264         public void addAttributes() {
265                 // update the method count
266                 contents[methodCountOffset++] = (byte) (methodCount >> 8);
267                 contents[methodCountOffset] = (byte) methodCount;
268
269                 int attributeNumber = 0;
270                 // leave two bytes for the number of attributes and store the current offset
271                 int attributeOffset = contentsOffset;
272                 contentsOffset += 2;
273                 int contentsLength;
274
275                 // source attribute
276                 if ((produceDebugAttributes & CompilerOptions.Source) != 0) {
277                         String fullFileName =
278                                 new String(referenceBinding.scope.referenceCompilationUnit().getFileName());
279                         fullFileName = fullFileName.replace('\\', '/');
280                         int lastIndex = fullFileName.lastIndexOf('/');
281                         if (lastIndex != -1) {
282                                 fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length());
283                         }
284                         // check that there is enough space to write all the bytes for the field info corresponding
285                         // to the @fieldBinding
286                         if (contentsOffset + 8 >= (contentsLength = contents.length)) {
287                                 System.arraycopy(
288                                         contents,
289                                         0,
290                                         (contents = new byte[contentsLength + INCREMENT_SIZE]),
291                                         0,
292                                         contentsLength);
293                         }
294                         int sourceAttributeNameIndex =
295                                 constantPool.literalIndex(AttributeNamesConstants.SourceName);
296                         contents[contentsOffset++] = (byte) (sourceAttributeNameIndex >> 8);
297                         contents[contentsOffset++] = (byte) sourceAttributeNameIndex;
298                         // The length of a source file attribute is 2. This is a fixed-length
299                         // attribute
300                         contents[contentsOffset++] = 0;
301                         contents[contentsOffset++] = 0;
302                         contents[contentsOffset++] = 0;
303                         contents[contentsOffset++] = 2;
304                         // write the source file name
305                         int fileNameIndex = constantPool.literalIndex(fullFileName.toCharArray());
306                         contents[contentsOffset++] = (byte) (fileNameIndex >> 8);
307                         contents[contentsOffset++] = (byte) fileNameIndex;
308                         attributeNumber++;
309                 }
310                 // Deprecated attribute
311                 if (referenceBinding.isDeprecated()) {
312                         // check that there is enough space to write all the bytes for the field info corresponding
313                         // to the @fieldBinding
314                         if (contentsOffset + 6 >= (contentsLength = contents.length)) {
315                                 System.arraycopy(
316                                         contents,
317                                         0,
318                                         (contents = new byte[contentsLength + INCREMENT_SIZE]),
319                                         0,
320                                         contentsLength);
321                         }
322                         int deprecatedAttributeNameIndex =
323                                 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
324                         contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
325                         contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
326                         // the length of a deprecated attribute is equals to 0
327                         contents[contentsOffset++] = 0;
328                         contents[contentsOffset++] = 0;
329                         contents[contentsOffset++] = 0;
330                         contents[contentsOffset++] = 0;
331                         attributeNumber++;
332                 }
333                 // Inner class attribute
334                 if (numberOfInnerClasses != 0) {
335                         // Generate the inner class attribute
336                         int exSize;
337                         if (contentsOffset + (exSize = (8 * numberOfInnerClasses + 8))
338                                 >= (contentsLength = contents.length)) {
339                                 System.arraycopy(
340                                         contents,
341                                         0,
342                                         (contents =
343                                                 new byte[contentsLength
344                                                         + (exSize >= INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
345                                         0,
346                                         contentsLength);
347                         }
348                         // Now we now the size of the attribute and the number of entries
349                         // attribute name
350                         int attributeNameIndex =
351                                 constantPool.literalIndex(AttributeNamesConstants.InnerClassName);
352                         contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
353                         contents[contentsOffset++] = (byte) attributeNameIndex;
354                         int value = (numberOfInnerClasses << 3) + 2;
355                         contents[contentsOffset++] = (byte) (value >> 24);
356                         contents[contentsOffset++] = (byte) (value >> 16);
357                         contents[contentsOffset++] = (byte) (value >> 8);
358                         contents[contentsOffset++] = (byte) value;
359                         contents[contentsOffset++] = (byte) (numberOfInnerClasses >> 8);
360                         contents[contentsOffset++] = (byte) numberOfInnerClasses;
361                         for (int i = 0; i < numberOfInnerClasses; i++) {
362                                 ReferenceBinding innerClass = innerClassesBindings[i];
363                                 int accessFlags = innerClass.getAccessFlags();
364                                 int innerClassIndex = constantPool.literalIndex(innerClass);
365                                 // inner class index
366                                 contents[contentsOffset++] = (byte) (innerClassIndex >> 8);
367                                 contents[contentsOffset++] = (byte) innerClassIndex;
368                                 // outer class index: anonymous and local have no outer class index
369                                 if (innerClass.isMemberType()) {
370                                         // member or member of local
371                                         int outerClassIndex = constantPool.literalIndex(innerClass.enclosingType());
372                                         contents[contentsOffset++] = (byte) (outerClassIndex >> 8);
373                                         contents[contentsOffset++] = (byte) outerClassIndex;
374                                 } else {
375                                         // equals to 0 if the innerClass is not a member type
376                                         contents[contentsOffset++] = 0;
377                                         contents[contentsOffset++] = 0;
378                                 }
379                                 // name index
380                                 if (!innerClass.isAnonymousType()) {
381                                         int nameIndex = constantPool.literalIndex(innerClass.sourceName());
382                                         contents[contentsOffset++] = (byte) (nameIndex >> 8);
383                                         contents[contentsOffset++] = (byte) nameIndex;
384                                 } else {
385                                         // equals to 0 if the innerClass is an anonymous type
386                                         contents[contentsOffset++] = 0;
387                                         contents[contentsOffset++] = 0;
388                                 }
389                                 // access flag
390                                 if (innerClass.isAnonymousType()) {
391                                         accessFlags |= AccPrivate;
392                                 } else
393                                         if (innerClass.isLocalType() && !innerClass.isMemberType()) {
394                                                 accessFlags |= AccPrivate;
395                                         }
396                                 contents[contentsOffset++] = (byte) (accessFlags >> 8);
397                                 contents[contentsOffset++] = (byte) accessFlags;
398                         }
399                         attributeNumber++;
400                 }
401                 // update the number of attributes
402                 contentsLength = contents.length;
403                 if (attributeOffset + 2 >= contentsLength) {
404                         System.arraycopy(
405                                 contents,
406                                 0,
407                                 (contents = new byte[contentsLength + INCREMENT_SIZE]),
408                                 0,
409                                 contentsLength);
410                 }
411                 contents[attributeOffset++] = (byte) (attributeNumber >> 8);
412                 contents[attributeOffset] = (byte) attributeNumber;
413
414                 // resynchronize all offsets of the classfile
415                 header = constantPool.poolContent;
416                 headerOffset = constantPool.currentOffset;
417                 int constantPoolCount = constantPool.currentIndex;
418                 header[constantPoolOffset++] = (byte) (constantPoolCount >> 8);
419                 header[constantPoolOffset] = (byte) constantPoolCount;
420         }
421
422         /**
423          * INTERNAL USE-ONLY
424          * This methods generate all the default abstract method infos that correpond to
425          * the abstract methods inherited from superinterfaces.
426          */
427         public void addDefaultAbstractMethods() { // default abstract methods
428                 MethodBinding[] defaultAbstractMethods =
429                         referenceBinding.getDefaultAbstractMethods();
430                 for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
431                         generateMethodInfoHeader(defaultAbstractMethods[i]);
432                         int methodAttributeOffset = contentsOffset;
433                         int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
434                         completeMethodInfo(methodAttributeOffset, attributeNumber);
435                 }
436         }
437
438         /**
439          * INTERNAL USE-ONLY
440          * This methods generates the bytes for the field binding passed like a parameter
441          * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding
442          */
443         public void addFieldInfo(FieldBinding fieldBinding) {
444                 int attributeNumber = 0;
445                 // check that there is enough space to write all the bytes for the field info corresponding
446                 // to the @fieldBinding
447                 int contentsLength;
448                 if (contentsOffset + 30 >= (contentsLength = contents.length)) {
449                         System.arraycopy(
450                                 contents,
451                                 0,
452                                 (contents = new byte[contentsLength + INCREMENT_SIZE]),
453                                 0,
454                                 contentsLength);
455                 }
456                 // Generate two attribute: constantValueAttribute and SyntheticAttribute
457                 // Now we can generate all entries into the byte array
458                 // First the accessFlags
459                 int accessFlags = fieldBinding.getAccessFlags();
460                 contents[contentsOffset++] = (byte) (accessFlags >> 8);
461                 contents[contentsOffset++] = (byte) accessFlags;
462                 // Then the nameIndex
463                 int nameIndex = constantPool.literalIndex(fieldBinding.name);
464                 contents[contentsOffset++] = (byte) (nameIndex >> 8);
465                 contents[contentsOffset++] = (byte) nameIndex;
466                 // Then the descriptorIndex
467                 int descriptorIndex = constantPool.literalIndex(fieldBinding.type.signature());
468                 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
469                 contents[contentsOffset++] = (byte) descriptorIndex;
470                 // leave some space for the number of attributes
471                 int fieldAttributeOffset = contentsOffset;
472                 contentsOffset += 2;
473                 // 4.7.2 only static constant fields get a ConstantAttribute
474                 if (fieldBinding.constant != Constant.NotAConstant
475                         && fieldBinding.constant.typeID() != T_null) {
476                         // Now we generate the constant attribute corresponding to the fieldBinding
477                         int constantValueNameIndex =
478                                 constantPool.literalIndex(AttributeNamesConstants.ConstantValueName);
479                         contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
480                         contents[contentsOffset++] = (byte) constantValueNameIndex;
481                         // The attribute length = 2 in case of a constantValue attribute
482                         contents[contentsOffset++] = 0;
483                         contents[contentsOffset++] = 0;
484                         contents[contentsOffset++] = 0;
485                         contents[contentsOffset++] = 2;
486                         attributeNumber++;
487                         // Need to add the constant_value_index
488                         switch (fieldBinding.constant.typeID()) {
489                                 case T_boolean :
490                                         int booleanValueIndex =
491                                                 constantPool.literalIndex(fieldBinding.constant.booleanValue() ? 1 : 0);
492                                         contents[contentsOffset++] = (byte) (booleanValueIndex >> 8);
493                                         contents[contentsOffset++] = (byte) booleanValueIndex;
494                                         break;
495                                 case T_byte :
496                                 case T_char :
497                                 case T_int :
498                                 case T_short :
499                                         int integerValueIndex =
500                                                 constantPool.literalIndex(fieldBinding.constant.intValue());
501                                         contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
502                                         contents[contentsOffset++] = (byte) integerValueIndex;
503                                         break;
504                                 case T_float :
505                                         int floatValueIndex =
506                                                 constantPool.literalIndex(fieldBinding.constant.floatValue());
507                                         contents[contentsOffset++] = (byte) (floatValueIndex >> 8);
508                                         contents[contentsOffset++] = (byte) floatValueIndex;
509                                         break;
510                                 case T_double :
511                                         int doubleValueIndex =
512                                                 constantPool.literalIndex(fieldBinding.constant.doubleValue());
513                                         contents[contentsOffset++] = (byte) (doubleValueIndex >> 8);
514                                         contents[contentsOffset++] = (byte) doubleValueIndex;
515                                         break;
516                                 case T_long :
517                                         int longValueIndex =
518                                                 constantPool.literalIndex(fieldBinding.constant.longValue());
519                                         contents[contentsOffset++] = (byte) (longValueIndex >> 8);
520                                         contents[contentsOffset++] = (byte) longValueIndex;
521                                         break;
522                                 case T_String :
523                                         int stringValueIndex =
524                                                 constantPool.literalIndex(
525                                                         ((StringConstant) fieldBinding.constant).stringValue());
526                                         if (stringValueIndex == -1) {
527                                                 if (!creatingProblemType) {
528                                                         // report an error and abort: will lead to a problem type classfile creation
529                                                         TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
530                                                         FieldDeclaration[] fieldDecls = typeDeclaration.fields;
531                                                         for (int i = 0, max = fieldDecls.length; i < max; i++) {
532                                                                 if (fieldDecls[i].binding == fieldBinding) {
533                                                                         // problem should abort
534                                                                         typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(
535                                                                                 fieldDecls[i]);
536                                                                 }
537                                                         }
538                                                 } else {
539                                                         // already inside a problem type creation : no constant for this field
540                                                         contentsOffset = fieldAttributeOffset + 2;
541                                                         // +2 is necessary to keep the two byte space for the attribute number
542                                                         attributeNumber--;
543                                                 }
544                                         } else {
545                                                 contents[contentsOffset++] = (byte) (stringValueIndex >> 8);
546                                                 contents[contentsOffset++] = (byte) stringValueIndex;
547                                         }
548                         }
549                 }
550                 if (fieldBinding.isSynthetic()) {
551                         int syntheticAttributeNameIndex =
552                                 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
553                         contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
554                         contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
555                         // the length of a synthetic attribute is equals to 0
556                         contents[contentsOffset++] = 0;
557                         contents[contentsOffset++] = 0;
558                         contents[contentsOffset++] = 0;
559                         contents[contentsOffset++] = 0;
560                         attributeNumber++;
561                 }
562                 if (fieldBinding.isDeprecated()) {
563                         int deprecatedAttributeNameIndex =
564                                 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
565                         contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
566                         contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
567                         // the length of a deprecated attribute is equals to 0
568                         contents[contentsOffset++] = 0;
569                         contents[contentsOffset++] = 0;
570                         contents[contentsOffset++] = 0;
571                         contents[contentsOffset++] = 0;
572                         attributeNumber++;
573                 }
574                 contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8);
575                 contents[fieldAttributeOffset] = (byte) attributeNumber;
576         }
577
578         /**
579          * INTERNAL USE-ONLY
580          * This methods generate all the fields infos for the receiver.
581          * This includes:
582          * - a field info for each defined field of that class
583          * - a field info for each synthetic field (e.g. this$0)
584          */
585         public void addFieldInfos() {
586                 SourceTypeBinding currentBinding = referenceBinding;
587                 FieldBinding[] syntheticFields = currentBinding.syntheticFields();
588                 int fieldCount =
589                         currentBinding.fieldCount()
590                                 + (syntheticFields == null ? 0 : syntheticFields.length);
591
592                 // write the number of fields
593                 contents[contentsOffset++] = (byte) (fieldCount >> 8);
594                 contents[contentsOffset++] = (byte) fieldCount;
595
596                 FieldBinding[] fieldBindings = currentBinding.fields();
597                 for (int i = 0, max = fieldBindings.length; i < max; i++) {
598                         addFieldInfo(fieldBindings[i]);
599                 }
600                 if (syntheticFields != null) {
601                         for (int i = 0, max = syntheticFields.length; i < max; i++) {
602                                 addFieldInfo(syntheticFields[i]);
603                         }
604                 }
605         }
606
607         /**
608          * INTERNAL USE-ONLY
609          * This methods stores the bindings for each inner class. They will be used to know which entries
610          * have to be generated for the inner classes attributes.
611          * @param referenceBinding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding 
612          */
613         public void addInnerClasses(ReferenceBinding referenceBinding) {
614                 // check first if that reference binding is there
615                 for (int i = 0; i < numberOfInnerClasses; i++) {
616                         if (innerClassesBindings[i] == referenceBinding)
617                                 return;
618                 }
619                 int length = innerClassesBindings.length;
620                 if (numberOfInnerClasses == length) {
621                         System.arraycopy(
622                                 innerClassesBindings,
623                                 0,
624                                 (innerClassesBindings = new ReferenceBinding[length * 2]),
625                                 0,
626                                 length);
627                 }
628                 innerClassesBindings[numberOfInnerClasses++] = referenceBinding;
629         }
630
631         /**
632          * INTERNAL USE-ONLY
633          * Generate the byte for a problem clinit method info that correspond to a boggus method.
634          *
635          * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
636          */
637         public void addProblemClinit(IProblem[] problems) {
638                 generateMethodInfoHeaderForClinit();
639                 // leave two spaces for the number of attributes
640                 contentsOffset -= 2;
641                 int attributeOffset = contentsOffset;
642                 contentsOffset += 2;
643                 int attributeNumber = 0;
644
645                 int codeAttributeOffset = contentsOffset;
646                 generateCodeAttributeHeader();
647                 codeStream.resetForProblemClinit(this);
648                 String problemString = "" ; //$NON-NLS-1$
649                 if (problems != null) {
650                         int max = problems.length;
651                         StringBuffer buffer = new StringBuffer(25);
652                         int count = 0;
653                         for (int i = 0; i < max; i++) {
654                                 IProblem problem = problems[i];
655                                 if ((problem != null) && (problem.isError())) {
656                                         buffer.append("\t"  +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
657                                         count++;
658                                         if (problemLine == 0) {
659                                                 problemLine = problem.getSourceLineNumber();
660                                         }
661                                         problems[i] = null;
662                                 }
663                         } // insert the top line afterwards, once knowing how many problems we have to consider
664                         if (count > 1) {
665                                 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
666                         } else {
667                                 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
668                         }
669                         problemString = buffer.toString();
670                 }
671
672                 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
673                 int[] exceptionHandler =
674                         codeStream.generateCodeAttributeForProblemMethod(
675                                 referenceBinding
676                                         .scope
677                                         .environment()
678                                         .options
679                                         .runtimeExceptionNameForCompileError,
680                                 problemString);
681                 attributeNumber++; // code attribute
682                 completeCodeAttributeForClinit(
683                         codeAttributeOffset,
684                         exceptionHandler,
685                         referenceBinding
686                                 .scope
687                                 .referenceCompilationUnit()
688                                 .compilationResult
689                                 .lineSeparatorPositions);
690                 contents[attributeOffset++] = (byte) (attributeNumber >> 8);
691                 contents[attributeOffset] = (byte) attributeNumber;
692         }
693
694         /**
695          * INTERNAL USE-ONLY
696          * Generate the byte for a problem method info that correspond to a boggus constructor.
697          *
698          * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
699          * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
700          * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
701          */
702         public void addProblemConstructor(
703                 AbstractMethodDeclaration method,
704                 MethodBinding methodBinding,
705                 IProblem[] problems) {
706
707                 // always clear the strictfp/native/abstract bit for a problem method
708                 methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
709
710                 generateMethodInfoHeader(methodBinding);
711                 int methodAttributeOffset = contentsOffset;
712                 int attributeNumber = generateMethodInfoAttribute(methodBinding);
713                 
714                 // Code attribute
715                 attributeNumber++;
716                 int codeAttributeOffset = contentsOffset;
717                 generateCodeAttributeHeader();
718                 final ProblemReporter problemReporter = method.scope.problemReporter();
719                 codeStream.reset(method, this);
720                 String problemString = "" ; //$NON-NLS-1$
721                 if (problems != null) {
722                         int max = problems.length;
723                         StringBuffer buffer = new StringBuffer(25);
724                         int count = 0;
725                         for (int i = 0; i < max; i++) {
726                                 IProblem problem = problems[i];
727                                 if ((problem != null) && (problem.isError())) {
728                                         buffer.append("\t"  +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
729                                         count++;
730                                         if (problemLine == 0) {
731                                                 problemLine = problem.getSourceLineNumber();
732                                         }
733                                 }
734                         } // insert the top line afterwards, once knowing how many problems we have to consider
735                         if (count > 1) {
736                                 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
737                         } else {
738                                 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
739                         }
740                         problemString = buffer.toString();
741                 }
742
743                 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
744                 int[] exceptionHandler =
745                         codeStream.generateCodeAttributeForProblemMethod(
746                                 problemReporter.options.runtimeExceptionNameForCompileError,
747                                 problemString);
748                 completeCodeAttributeForProblemMethod(
749                         method,
750                         methodBinding,
751                         codeAttributeOffset,
752                         exceptionHandler,
753                         ((SourceTypeBinding) methodBinding.declaringClass)
754                                 .scope
755                                 .referenceCompilationUnit()
756                                 .compilationResult
757                                 .lineSeparatorPositions);
758                 completeMethodInfo(methodAttributeOffset, attributeNumber);
759         }
760
761         /**
762          * INTERNAL USE-ONLY
763          * Generate the byte for a problem method info that correspond to a boggus constructor.
764          * Reset the position inside the contents byte array to the savedOffset.
765          *
766          * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
767          * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
768          * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
769          * @param savedOffset <CODE>int</CODE>
770          */
771         public void addProblemConstructor(
772                 AbstractMethodDeclaration method,
773                 MethodBinding methodBinding,
774                 IProblem[] problems,
775                 int savedOffset) {
776                 // we need to move back the contentsOffset to the value at the beginning of the method
777                 contentsOffset = savedOffset;
778                 methodCount--; // we need to remove the method that causes the problem
779                 addProblemConstructor(method, methodBinding, problems);
780         }
781
782         /**
783          * INTERNAL USE-ONLY
784          * Generate the byte for a problem method info that correspond to a boggus method.
785          *
786          * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
787          * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
788          * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
789          */
790         public void addProblemMethod(
791                 AbstractMethodDeclaration method,
792                 MethodBinding methodBinding,
793                 IProblem[] problems) {
794                 if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) {
795                         method.abort(AbstractMethodDeclaration.AbortType);
796                 }
797                 // always clear the strictfp/native/abstract bit for a problem method
798                 methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
799
800                 generateMethodInfoHeader(methodBinding);
801                 int methodAttributeOffset = contentsOffset;
802                 int attributeNumber = generateMethodInfoAttribute(methodBinding);
803                 
804                 // Code attribute
805                 attributeNumber++;
806                 
807                 int codeAttributeOffset = contentsOffset;
808                 generateCodeAttributeHeader();
809                 final ProblemReporter problemReporter = method.scope.problemReporter();
810                 codeStream.reset(method, this);
811                 String problemString = "" ; //$NON-NLS-1$
812                 if (problems != null) {
813                         int max = problems.length;
814                         StringBuffer buffer = new StringBuffer(25);
815                         int count = 0;
816                         for (int i = 0; i < max; i++) {
817                                 IProblem problem = problems[i];
818                                 if ((problem != null)
819                                         && (problem.isError())
820                                         && (problem.getSourceStart() >= method.declarationSourceStart)
821                                         && (problem.getSourceEnd() <= method.declarationSourceEnd)) {
822                                         buffer.append("\t"  +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
823                                         count++;
824                                         if (problemLine == 0) {
825                                                 problemLine = problem.getSourceLineNumber();
826                                         }
827                                         problems[i] = null;
828                                 }
829                         } // insert the top line afterwards, once knowing how many problems we have to consider
830                         if (count > 1) {
831                                 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
832                         } else {
833                                 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
834                         }
835                         problemString = buffer.toString();
836                 }
837
838                 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
839                 int[] exceptionHandler =
840                         codeStream.generateCodeAttributeForProblemMethod(
841                                 problemReporter.options.runtimeExceptionNameForCompileError,
842                                 problemString);
843                 completeCodeAttributeForProblemMethod(
844                         method,
845                         methodBinding,
846                         codeAttributeOffset,
847                         exceptionHandler,
848                         ((SourceTypeBinding) methodBinding.declaringClass)
849                                 .scope
850                                 .referenceCompilationUnit()
851                                 .compilationResult
852                                 .lineSeparatorPositions);
853                 completeMethodInfo(methodAttributeOffset, attributeNumber);
854         }
855
856         /**
857          * INTERNAL USE-ONLY
858          * Generate the byte for a problem method info that correspond to a boggus method.
859          * Reset the position inside the contents byte array to the savedOffset.
860          *
861          * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
862          * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
863          * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
864          * @param savedOffset <CODE>int</CODE>
865          */
866         public void addProblemMethod(
867                 AbstractMethodDeclaration method,
868                 MethodBinding methodBinding,
869                 IProblem[] problems,
870                 int savedOffset) {
871                 // we need to move back the contentsOffset to the value at the beginning of the method
872                 contentsOffset = savedOffset;
873                 methodCount--; // we need to remove the method that causes the problem
874                 addProblemMethod(method, methodBinding, problems);
875         }
876
877         /**
878          * INTERNAL USE-ONLY
879          * Generate the byte for all the special method infos.
880          * They are:
881          * - synthetic access methods
882          * - default abstract methods
883          */
884         public void addSpecialMethods() {
885                 // add all methods (default abstract methods and synthetic)
886
887                 // default abstract methods
888                 SourceTypeBinding currentBinding = referenceBinding;
889                 MethodBinding[] defaultAbstractMethods =
890                         currentBinding.getDefaultAbstractMethods();
891                 for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
892                         generateMethodInfoHeader(defaultAbstractMethods[i]);
893                         int methodAttributeOffset = contentsOffset;
894                         int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
895                         completeMethodInfo(methodAttributeOffset, attributeNumber);
896                 }
897                 // add synthetic methods infos
898                 SyntheticAccessMethodBinding[] syntheticAccessMethods =
899                         currentBinding.syntheticAccessMethods();
900                 if (syntheticAccessMethods != null) {
901                         for (int i = 0, max = syntheticAccessMethods.length; i < max; i++) {
902                                 SyntheticAccessMethodBinding accessMethodBinding = syntheticAccessMethods[i];
903                                 switch (accessMethodBinding.accessType) {
904                                         case SyntheticAccessMethodBinding.FieldReadAccess :
905                                                 // generate a method info to emulate an reading access to
906                                                 // a private field
907                                                 addSyntheticFieldReadAccessMethod(syntheticAccessMethods[i]);
908                                                 break;
909                                         case SyntheticAccessMethodBinding.FieldWriteAccess :
910                                                 // generate a method info to emulate an writing access to
911                                                 // a private field
912                                                 addSyntheticFieldWriteAccessMethod(syntheticAccessMethods[i]);
913                                                 break;
914                                         case SyntheticAccessMethodBinding.MethodAccess :
915                                                 // generate a method info to emulate an access to a private method
916                                                 addSyntheticMethodAccessMethod(syntheticAccessMethods[i]);
917                                                 break;
918                                         case SyntheticAccessMethodBinding.ConstructorAccess :
919                                                 // generate a method info to emulate an access to a private method
920                                                 addSyntheticConstructorAccessMethod(syntheticAccessMethods[i]);
921                                 }
922                         }
923                 }
924         }
925
926         /**
927          * INTERNAL USE-ONLY
928          * Generate the byte for problem method infos that correspond to missing abstract methods.
929          * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179
930          *
931          * @param methodDeclarations Array of all missing abstract methods
932          */
933         public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) {
934                 if (methodDeclarations != null) {
935                         for (int i = 0, max = methodDeclarations.length; i < max; i++) {
936                                 MethodDeclaration methodDeclaration = methodDeclarations[i];
937                                 MethodBinding methodBinding = methodDeclaration.binding;
938                                 String readableName = new String(methodBinding.readableName());
939                                 IProblem[] problems = compilationResult.problems;
940                                 int problemsCount = compilationResult.problemCount;
941                                 for (int j = 0; j < problemsCount; j++) {
942                                         IProblem problem = problems[j];
943                                         if (problem != null
944                                                 && problem.getID() == IProblem.AbstractMethodMustBeImplemented
945                                                 && problem.getMessage().indexOf(readableName) != -1) {
946                                                         // we found a match
947                                                         addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult);
948                                                 }
949                                 }
950                         }
951                 }
952         }
953         
954         private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, IProblem problem, CompilationResult compilationResult) {
955                 // always clear the strictfp/native/abstract bit for a problem method
956                 methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
957                 
958                 generateMethodInfoHeader(methodBinding);
959                 int methodAttributeOffset = contentsOffset;
960                 int attributeNumber = generateMethodInfoAttribute(methodBinding);
961                 
962                 // Code attribute
963                 attributeNumber++;
964                 
965                 int codeAttributeOffset = contentsOffset;
966                 generateCodeAttributeHeader();
967                 StringBuffer buffer = new StringBuffer(25);
968                 buffer.append("\t"  + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
969                 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
970                 String problemString = buffer.toString();
971                 this.problemLine = problem.getSourceLineNumber();
972                 
973                 final ProblemReporter problemReporter = methodDeclaration.scope.problemReporter();
974                 codeStream.init(this);
975                 codeStream.preserveUnusedLocals = true;
976                 codeStream.initializeMaxLocals(methodBinding);
977
978                 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
979                 int[] exceptionHandler =
980                         codeStream.generateCodeAttributeForProblemMethod(
981                                 problemReporter.options.runtimeExceptionNameForCompileError,
982                                 problemString);
983                                 
984                 completeCodeAttributeForMissingAbstractProblemMethod(
985                         methodBinding,
986                         codeAttributeOffset,
987                         exceptionHandler,
988                         compilationResult.lineSeparatorPositions);
989                         
990                 completeMethodInfo(methodAttributeOffset, attributeNumber);
991         }
992
993         /**
994          * 
995          */
996         public void completeCodeAttributeForMissingAbstractProblemMethod(
997                 MethodBinding binding,
998                 int codeAttributeOffset,
999                 int[] exceptionHandler,
1000                 int[] startLineIndexes) {
1001                 // reinitialize the localContents with the byte modified by the code stream
1002                 byte[] localContents = contents = codeStream.bCodeStream;
1003                 int localContentsOffset = codeStream.classFileOffset;
1004                 // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
1005                 int max_stack = codeStream.stackMax;
1006                 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1007                 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1008                 int max_locals = codeStream.maxLocals;
1009                 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1010                 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1011                 int code_length = codeStream.position;
1012                 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1013                 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1014                 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1015                 localContents[codeAttributeOffset + 13] = (byte) code_length;
1016                 // write the exception table
1017                 int contentsLength;
1018                 if (localContentsOffset + 50 >= (contentsLength = localContents.length)) {
1019                         System.arraycopy(
1020                                 contents,
1021                                 0,
1022                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1023                                 0,
1024                                 contentsLength);
1025                 }
1026                 localContents[localContentsOffset++] = 0;
1027                 localContents[localContentsOffset++] = 1;
1028                 int start = exceptionHandler[0];
1029                 localContents[localContentsOffset++] = (byte) (start >> 8);
1030                 localContents[localContentsOffset++] = (byte) start;
1031                 int end = exceptionHandler[1];
1032                 localContents[localContentsOffset++] = (byte) (end >> 8);
1033                 localContents[localContentsOffset++] = (byte) end;
1034                 int handlerPC = exceptionHandler[2];
1035                 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1036                 localContents[localContentsOffset++] = (byte) handlerPC;
1037                 int nameIndex = constantPool.literalIndexForJavaLangException();
1038                 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1039                 localContents[localContentsOffset++] = (byte) nameIndex; // debug attributes
1040                 int codeAttributeAttributeOffset = localContentsOffset;
1041                 int attributeNumber = 0; // leave two bytes for the attribute_length
1042                 localContentsOffset += 2; // first we handle the linenumber attribute
1043
1044                 if (codeStream.generateLineNumberAttributes) {
1045                         /* Create and add the line number attribute (used for debugging) 
1046                             * Build the pairs of:
1047                             * (bytecodePC lineNumber)
1048                             * according to the table of start line indexes and the pcToSourceMap table
1049                             * contained into the codestream
1050                             */
1051                         int lineNumberNameIndex =
1052                                 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1053                         localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1054                         localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1055                         localContents[localContentsOffset++] = 0;
1056                         localContents[localContentsOffset++] = 0;
1057                         localContents[localContentsOffset++] = 0;
1058                         localContents[localContentsOffset++] = 6;
1059                         localContents[localContentsOffset++] = 0;
1060                         localContents[localContentsOffset++] = 1;
1061                         if (problemLine == 0) {
1062                                 problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
1063                         }
1064                         // first entry at pc = 0
1065                         localContents[localContentsOffset++] = 0;
1066                         localContents[localContentsOffset++] = 0;
1067                         localContents[localContentsOffset++] = (byte) (problemLine >> 8);
1068                         localContents[localContentsOffset++] = (byte) problemLine;
1069                         // now we change the size of the line number attribute
1070                         attributeNumber++;
1071                 }
1072                 
1073                 // then we do the local variable attribute
1074                 // update the number of attributes// ensure first that there is enough space available inside the localContents array
1075                 if (codeAttributeAttributeOffset + 2
1076                         >= (contentsLength = localContents.length)) {
1077                         System.arraycopy(
1078                                 contents,
1079                                 0,
1080                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1081                                 0,
1082                                 contentsLength);
1083                 }
1084                 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1085                 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1086                 // update the attribute length
1087                 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1088                 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1089                 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1090                 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1091                 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1092                 contentsOffset = localContentsOffset;
1093         }
1094
1095         /**
1096          * INTERNAL USE-ONLY
1097          * Generate the byte for a problem method info that correspond to a synthetic method that
1098          * generate an access to a private constructor.
1099          *
1100          * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1101          */
1102         public void addSyntheticConstructorAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1103                 generateMethodInfoHeader(methodBinding);
1104                 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1105                 contents[contentsOffset++] = 0;
1106                 contents[contentsOffset++] = 2;
1107                 // Code attribute
1108                 int codeAttributeOffset = contentsOffset;
1109                 generateCodeAttributeHeader();
1110                 codeStream.init(this);
1111                 codeStream.generateSyntheticBodyForConstructorAccess(methodBinding);
1112                 completeCodeAttributeForSyntheticAccessMethod(
1113                         methodBinding,
1114                         codeAttributeOffset,
1115                         ((SourceTypeBinding) methodBinding.declaringClass)
1116                                 .scope
1117                                 .referenceCompilationUnit()
1118                                 .compilationResult
1119                                 .lineSeparatorPositions);
1120                 // add the synthetic attribute
1121                 int syntheticAttributeNameIndex =
1122                         constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1123                 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1124                 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1125                 // the length of a synthetic attribute is equals to 0
1126                 contents[contentsOffset++] = 0;
1127                 contents[contentsOffset++] = 0;
1128                 contents[contentsOffset++] = 0;
1129                 contents[contentsOffset++] = 0;
1130         }
1131
1132         /**
1133          * INTERNAL USE-ONLY
1134          * Generate the byte for a problem method info that correspond to a synthetic method that
1135          * generate an read access to a private field.
1136          *
1137          * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1138          */
1139         public void addSyntheticFieldReadAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1140                 generateMethodInfoHeader(methodBinding);
1141                 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1142                 contents[contentsOffset++] = 0;
1143                 contents[contentsOffset++] = 2;
1144                 // Code attribute
1145                 int codeAttributeOffset = contentsOffset;
1146                 generateCodeAttributeHeader();
1147                 codeStream.init(this);
1148                 codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding);
1149                 completeCodeAttributeForSyntheticAccessMethod(
1150                         methodBinding,
1151                         codeAttributeOffset,
1152                         ((SourceTypeBinding) methodBinding.declaringClass)
1153                                 .scope
1154                                 .referenceCompilationUnit()
1155                                 .compilationResult
1156                                 .lineSeparatorPositions);
1157                 // add the synthetic attribute
1158                 int syntheticAttributeNameIndex =
1159                         constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1160                 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1161                 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1162                 // the length of a synthetic attribute is equals to 0
1163                 contents[contentsOffset++] = 0;
1164                 contents[contentsOffset++] = 0;
1165                 contents[contentsOffset++] = 0;
1166                 contents[contentsOffset++] = 0;
1167         }
1168
1169         /**
1170          * INTERNAL USE-ONLY
1171          * Generate the byte for a problem method info that correspond to a synthetic method that
1172          * generate an write access to a private field.
1173          *
1174          * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1175          */
1176         public void addSyntheticFieldWriteAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1177                 generateMethodInfoHeader(methodBinding);
1178                 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1179                 contents[contentsOffset++] = 0;
1180                 contents[contentsOffset++] = 2;
1181                 // Code attribute
1182                 int codeAttributeOffset = contentsOffset;
1183                 generateCodeAttributeHeader();
1184                 codeStream.init(this);
1185                 codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding);
1186                 completeCodeAttributeForSyntheticAccessMethod(
1187                         methodBinding,
1188                         codeAttributeOffset,
1189                         ((SourceTypeBinding) methodBinding.declaringClass)
1190                                 .scope
1191                                 .referenceCompilationUnit()
1192                                 .compilationResult
1193                                 .lineSeparatorPositions);
1194                 // add the synthetic attribute
1195                 int syntheticAttributeNameIndex =
1196                         constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1197                 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1198                 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1199                 // the length of a synthetic attribute is equals to 0
1200                 contents[contentsOffset++] = 0;
1201                 contents[contentsOffset++] = 0;
1202                 contents[contentsOffset++] = 0;
1203                 contents[contentsOffset++] = 0;
1204         }
1205
1206         /**
1207          * INTERNAL USE-ONLY
1208          * Generate the byte for a problem method info that correspond to a synthetic method that
1209          * generate an access to a private method.
1210          *
1211          * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1212          */
1213         public void addSyntheticMethodAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1214                 generateMethodInfoHeader(methodBinding);
1215                 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1216                 contents[contentsOffset++] = 0;
1217                 contents[contentsOffset++] = 2;
1218                 // Code attribute
1219                 int codeAttributeOffset = contentsOffset;
1220                 generateCodeAttributeHeader();
1221                 codeStream.init(this);
1222                 codeStream.generateSyntheticBodyForMethodAccess(methodBinding);
1223                 completeCodeAttributeForSyntheticAccessMethod(
1224                         methodBinding,
1225                         codeAttributeOffset,
1226                         ((SourceTypeBinding) methodBinding.declaringClass)
1227                                 .scope
1228                                 .referenceCompilationUnit()
1229                                 .compilationResult
1230                                 .lineSeparatorPositions);
1231                 // add the synthetic attribute
1232                 int syntheticAttributeNameIndex =
1233                         constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1234                 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1235                 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1236                 // the length of a synthetic attribute is equals to 0
1237                 contents[contentsOffset++] = 0;
1238                 contents[contentsOffset++] = 0;
1239                 contents[contentsOffset++] = 0;
1240                 contents[contentsOffset++] = 0;
1241         }
1242
1243         /**
1244          * INTERNAL USE-ONLY
1245          * Build all the directories and subdirectories corresponding to the packages names
1246          * into the directory specified in parameters.
1247          *
1248          * outputPath is formed like:
1249          *         c:\temp\ the last character is a file separator
1250          * relativeFileName is formed like:
1251          *     java\lang\String.class *
1252          * 
1253          * @param outputPath java.lang.String
1254          * @param relativeFileName java.lang.String
1255          * @return java.lang.String
1256          */
1257         public static String buildAllDirectoriesInto(
1258                 String outputPath,
1259                 String relativeFileName)
1260                 throws IOException {
1261                 char fileSeparatorChar = File.separatorChar;
1262                 String fileSeparator = File.separator;
1263                 File f;
1264                 // First we ensure that the outputPath exists
1265                 outputPath = outputPath.replace('/', fileSeparatorChar);
1266                 // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
1267                 if (outputPath.endsWith(fileSeparator)) {
1268                         outputPath = outputPath.substring(0, outputPath.length() - 1);
1269                 }
1270                 f = new File(outputPath);
1271                 if (f.exists()) {
1272                         if (!f.isDirectory()) {
1273                                 System.out.println(Util.bind("output.isFile" , f.getAbsolutePath())); //$NON-NLS-1$
1274                                 throw new IOException(Util.bind("output.isFileNotDirectory" )); //$NON-NLS-1$
1275                         }
1276                 } else {
1277                         // we have to create that directory
1278                         if (!f.mkdirs()) {
1279                                 System.out.println(Util.bind("output.dirName" , f.getAbsolutePath())); //$NON-NLS-1$
1280                                 throw new IOException(Util.bind("output.notValidAll" )); //$NON-NLS-1$
1281                         }
1282                 }
1283                 StringBuffer outDir = new StringBuffer(outputPath);
1284                 outDir.append(fileSeparator);
1285                 StringTokenizer tokenizer =
1286                         new StringTokenizer(relativeFileName, fileSeparator);
1287                 String token = tokenizer.nextToken();
1288                 while (tokenizer.hasMoreTokens()) {
1289                         f = new File(outDir.append(token).append(fileSeparator).toString());
1290                         if (f.exists()) {
1291                                 // The outDir already exists, so we proceed the next entry
1292                                 // System.out.println("outDir: " + outDir + " already exists.");
1293                         } else {
1294                                 // Need to add the outDir
1295                                 if (!f.mkdir()) {
1296                                         System.out.println(Util.bind("output.fileName" , f.getName())); //$NON-NLS-1$
1297                                         throw new IOException(Util.bind("output.notValid" )); //$NON-NLS-1$
1298                                 }
1299                         }
1300                         token = tokenizer.nextToken();
1301                 }
1302                 // token contains the last one
1303                 return outDir.append(token).toString();
1304         }
1305
1306         /**
1307          * INTERNAL USE-ONLY
1308          * That method completes the creation of the code attribute by setting
1309          * - the attribute_length
1310          * - max_stack
1311          * - max_locals
1312          * - code_length
1313          * - exception table
1314          * - and debug attributes if necessary.
1315          *
1316          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1317          * @param codeAttributeOffset <CODE>int</CODE>
1318          */
1319         public void completeCodeAttribute(int codeAttributeOffset) {
1320                 // reinitialize the localContents with the byte modified by the code stream
1321                 byte[] localContents = contents = codeStream.bCodeStream;
1322                 int localContentsOffset = codeStream.classFileOffset;
1323                 // codeAttributeOffset is the position inside localContents byte array before we started to write
1324                 // any information about the codeAttribute
1325                 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1326                 // to get the right position, 6 for the max_stack etc...
1327                 int contentsLength;
1328                 int code_length = codeStream.position;
1329                 if (code_length > 65535) {
1330                         codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1331                                 codeStream.methodDeclaration);
1332                 }
1333                 if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
1334                         System.arraycopy(
1335                                 contents,
1336                                 0,
1337                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1338                                 0,
1339                                 contentsLength);
1340                 }
1341                 int max_stack = codeStream.stackMax;
1342                 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1343                 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1344                 int max_locals = codeStream.maxLocals;
1345                 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1346                 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1347                 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1348                 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1349                 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1350                 localContents[codeAttributeOffset + 13] = (byte) code_length;
1351
1352                 // write the exception table
1353                 int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
1354                 ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
1355                 int exSize;
1356                 if (localContentsOffset + (exSize = (exceptionHandlersNumber * 8 + 2))
1357                         >= (contentsLength = localContents.length)) {
1358                         System.arraycopy(
1359                                 contents,
1360                                 0,
1361                                 (localContents =
1362                                         contents =
1363                                                 new byte[contentsLength + (exSize > INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
1364                                 0,
1365                                 contentsLength);
1366                 }
1367                 // there is no exception table, so we need to offset by 2 the current offset and move 
1368                 // on the attribute generation
1369                 localContents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
1370                 localContents[localContentsOffset++] = (byte) exceptionHandlersNumber;
1371                 for (int i = 0; i < exceptionHandlersNumber; i++) {
1372                         ExceptionLabel exceptionHandler = exceptionHandlers[i];
1373                         int start = exceptionHandler.start;
1374                         localContents[localContentsOffset++] = (byte) (start >> 8);
1375                         localContents[localContentsOffset++] = (byte) start;
1376                         int end = exceptionHandler.end;
1377                         localContents[localContentsOffset++] = (byte) (end >> 8);
1378                         localContents[localContentsOffset++] = (byte) end;
1379                         int handlerPC = exceptionHandler.position;
1380                         localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1381                         localContents[localContentsOffset++] = (byte) handlerPC;
1382                         if (exceptionHandler.exceptionType == null) {
1383                                 // any exception handler
1384                                 localContents[localContentsOffset++] = 0;
1385                                 localContents[localContentsOffset++] = 0;
1386                         } else {
1387                                 int nameIndex;
1388                                 if (exceptionHandler.exceptionType == TypeBinding.NullBinding) {
1389                                         /* represents ClassNotFoundException, see class literal access*/
1390                                         nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
1391                                 } else {
1392                                         nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
1393                                 }
1394                                 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1395                                 localContents[localContentsOffset++] = (byte) nameIndex;
1396                         }
1397                 }
1398                 // debug attributes
1399                 int codeAttributeAttributeOffset = localContentsOffset;
1400                 int attributeNumber = 0;
1401                 // leave two bytes for the attribute_length
1402                 localContentsOffset += 2;
1403
1404                 // first we handle the linenumber attribute
1405                 if (codeStream.generateLineNumberAttributes) {
1406                         /* Create and add the line number attribute (used for debugging) 
1407                          * Build the pairs of:
1408                          *      (bytecodePC lineNumber)
1409                          * according to the table of start line indexes and the pcToSourceMap table
1410                          * contained into the codestream
1411                          */
1412                         int[] pcToSourceMapTable;
1413                         if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
1414                                 && (codeStream.pcToSourceMapSize != 0)) {
1415                                 int lineNumberNameIndex =
1416                                         constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1417                                 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1418                                         System.arraycopy(
1419                                                 contents,
1420                                                 0,
1421                                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1422                                                 0,
1423                                                 contentsLength);
1424                                 }
1425                                 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1426                                 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1427                                 int lineNumberTableOffset = localContentsOffset;
1428                                 localContentsOffset += 6;
1429                                 // leave space for attribute_length and line_number_table_length
1430                                 int numberOfEntries = 0;
1431                                 int length = codeStream.pcToSourceMapSize;
1432                                 for (int i = 0; i < length;) {
1433                                         // write the entry
1434                                         if (localContentsOffset + 4 >= (contentsLength = localContents.length)) {
1435                                                 System.arraycopy(
1436                                                         contents,
1437                                                         0,
1438                                                         (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1439                                                         0,
1440                                                         contentsLength);
1441                                         }
1442                                         int pc = pcToSourceMapTable[i++];
1443                                         localContents[localContentsOffset++] = (byte) (pc >> 8);
1444                                         localContents[localContentsOffset++] = (byte) pc;
1445                                         int lineNumber = pcToSourceMapTable[i++];
1446                                         localContents[localContentsOffset++] = (byte) (lineNumber >> 8);
1447                                         localContents[localContentsOffset++] = (byte) lineNumber;
1448                                         numberOfEntries++;
1449                                 }
1450                                 // now we change the size of the line number attribute
1451                                 int lineNumberAttr_length = numberOfEntries * 4 + 2;
1452                                 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
1453                                 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
1454                                 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
1455                                 localContents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
1456                                 localContents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
1457                                 localContents[lineNumberTableOffset++] = (byte) numberOfEntries;
1458                                 attributeNumber++;
1459                         }
1460                 }
1461                 // then we do the local variable attribute
1462                 if (codeStream.generateLocalVariableTableAttributes) {
1463                         int localVariableTableOffset = localContentsOffset;
1464                         int numberOfEntries = 0;
1465                         int localVariableNameIndex =
1466                                 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1467                         if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1468                                 System.arraycopy(
1469                                         contents,
1470                                         0,
1471                                         (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1472                                         0,
1473                                         contentsLength);
1474                         }
1475                         localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1476                         localContents[localContentsOffset++] = (byte) localVariableNameIndex;
1477                         localContentsOffset += 6;
1478                         // leave space for attribute_length and local_variable_table_length
1479                         int nameIndex;
1480                         int descriptorIndex;
1481                         if (!codeStream.methodDeclaration.isStatic()) {
1482                                 numberOfEntries++;
1483                                 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
1484                                         System.arraycopy(
1485                                                 contents,
1486                                                 0,
1487                                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1488                                                 0,
1489                                                 contentsLength);
1490                                 }
1491                                 localContentsOffset += 2; // the startPC for this is always 0
1492                                 localContents[localContentsOffset++] = (byte) (code_length >> 8);
1493                                 localContents[localContentsOffset++] = (byte) code_length;
1494                                 nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
1495                                 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1496                                 localContents[localContentsOffset++] = (byte) nameIndex;
1497                                 descriptorIndex =
1498                                         constantPool.literalIndex(
1499                                                 codeStream.methodDeclaration.binding.declaringClass.signature());
1500                                 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1501                                 localContents[localContentsOffset++] = (byte) descriptorIndex;
1502                                 localContentsOffset += 2; // the resolved position for this is always 0
1503                         }
1504                         for (int i = 0; i < codeStream.allLocalsCounter; i++) {
1505                                 LocalVariableBinding localVariable = codeStream.locals[i];
1506                                 for (int j = 0; j < localVariable.initializationCount; j++) {
1507                                         int startPC = localVariable.initializationPCs[j << 1];
1508                                         int endPC = localVariable.initializationPCs[(j << 1) + 1];
1509                                         if (startPC != endPC) { // only entries for non zero length
1510                                                 if (endPC == -1) {
1511                                                         localVariable.declaringScope.problemReporter().abortDueToInternalError(
1512                                                                 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
1513                                                                 (AstNode) localVariable.declaringScope.methodScope().referenceContext);
1514                                                 }
1515                                                 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
1516                                                         System.arraycopy(
1517                                                                 contents,
1518                                                                 0,
1519                                                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1520                                                                 0,
1521                                                                 contentsLength);
1522                                                 }
1523                                                 // now we can safely add the local entry
1524                                                 numberOfEntries++;
1525                                                 localContents[localContentsOffset++] = (byte) (startPC >> 8);
1526                                                 localContents[localContentsOffset++] = (byte) startPC;
1527                                                 int length = endPC - startPC;
1528                                                 localContents[localContentsOffset++] = (byte) (length >> 8);
1529                                                 localContents[localContentsOffset++] = (byte) length;
1530                                                 nameIndex = constantPool.literalIndex(localVariable.name);
1531                                                 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1532                                                 localContents[localContentsOffset++] = (byte) nameIndex;
1533                                                 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
1534                                                 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1535                                                 localContents[localContentsOffset++] = (byte) descriptorIndex;
1536                                                 int resolvedPosition = localVariable.resolvedPosition;
1537                                                 localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1538                                                 localContents[localContentsOffset++] = (byte) resolvedPosition;
1539                                         }
1540                                 }
1541                         }
1542                         int value = numberOfEntries * 10 + 2;
1543                         localVariableTableOffset += 2;
1544                         localContents[localVariableTableOffset++] = (byte) (value >> 24);
1545                         localContents[localVariableTableOffset++] = (byte) (value >> 16);
1546                         localContents[localVariableTableOffset++] = (byte) (value >> 8);
1547                         localContents[localVariableTableOffset++] = (byte) value;
1548                         localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1549                         localContents[localVariableTableOffset] = (byte) numberOfEntries;
1550                         attributeNumber++;
1551                 }
1552                 // update the number of attributes
1553                 // ensure first that there is enough space available inside the localContents array
1554                 if (codeAttributeAttributeOffset + 2
1555                         >= (contentsLength = localContents.length)) {
1556                         System.arraycopy(
1557                                 contents,
1558                                 0,
1559                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1560                                 0,
1561                                 contentsLength);
1562                 }
1563                 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1564                 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1565
1566                 // update the attribute length
1567                 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1568                 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1569                 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1570                 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1571                 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1572                 contentsOffset = localContentsOffset;
1573         }
1574
1575         /**
1576          * INTERNAL USE-ONLY
1577          * That method completes the creation of the code attribute by setting
1578          * - the attribute_length
1579          * - max_stack
1580          * - max_locals
1581          * - code_length
1582          * - exception table
1583          * - and debug attributes if necessary.
1584          *
1585          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1586          * @param codeAttributeOffset <CODE>int</CODE>
1587          */
1588         public void completeCodeAttributeForClinit(int codeAttributeOffset) {
1589                 // reinitialize the contents with the byte modified by the code stream
1590                 byte[] localContents = contents = codeStream.bCodeStream;
1591                 int localContentsOffset = codeStream.classFileOffset;
1592                 // codeAttributeOffset is the position inside contents byte array before we started to write
1593                 // any information about the codeAttribute
1594                 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1595                 // to get the right position, 6 for the max_stack etc...
1596                 int contentsLength;
1597                 int code_length = codeStream.position;
1598                 if (code_length > 65535) {
1599                         codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1600                                 codeStream.methodDeclaration.scope.referenceType());
1601                 }
1602                 if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
1603                         System.arraycopy(
1604                                 contents,
1605                                 0,
1606                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1607                                 0,
1608                                 contentsLength);
1609                 }
1610                 int max_stack = codeStream.stackMax;
1611                 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1612                 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1613                 int max_locals = codeStream.maxLocals;
1614                 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1615                 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1616                 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1617                 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1618                 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1619                 localContents[codeAttributeOffset + 13] = (byte) code_length;
1620
1621                 // write the exception table
1622                 int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
1623                 ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
1624                 int exSize;
1625                 if (localContentsOffset + (exSize = (exceptionHandlersNumber * 8 + 2))
1626                         >= (contentsLength = localContents.length)) {
1627                         System.arraycopy(
1628                                 contents,
1629                                 0,
1630                                 (localContents =
1631                                         contents =
1632                                                 new byte[contentsLength + (exSize > INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
1633                                 0,
1634                                 contentsLength);
1635                 }
1636                 // there is no exception table, so we need to offset by 2 the current offset and move 
1637                 // on the attribute generation
1638                 localContents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
1639                 localContents[localContentsOffset++] = (byte) exceptionHandlersNumber;
1640                 for (int i = 0; i < exceptionHandlersNumber; i++) {
1641                         ExceptionLabel exceptionHandler = exceptionHandlers[i];
1642                         int start = exceptionHandler.start;
1643                         localContents[localContentsOffset++] = (byte) (start >> 8);
1644                         localContents[localContentsOffset++] = (byte) start;
1645                         int end = exceptionHandler.end;
1646                         localContents[localContentsOffset++] = (byte) (end >> 8);
1647                         localContents[localContentsOffset++] = (byte) end;
1648                         int handlerPC = exceptionHandler.position;
1649                         localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1650                         localContents[localContentsOffset++] = (byte) handlerPC;
1651                         if (exceptionHandler.exceptionType == null) {
1652                                 // any exception handler
1653                                 localContentsOffset += 2;
1654                         } else {
1655                                 int nameIndex;
1656                                 if (exceptionHandler.exceptionType == TypeBinding.NullBinding) {
1657                                         /* represents denote ClassNotFoundException, see class literal access*/
1658                                         nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
1659                                 } else {
1660                                         nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
1661                                 }
1662                                 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1663                                 localContents[localContentsOffset++] = (byte) nameIndex;
1664                         }
1665                 }
1666                 // debug attributes
1667                 int codeAttributeAttributeOffset = localContentsOffset;
1668                 int attributeNumber = 0;
1669                 // leave two bytes for the attribute_length
1670                 localContentsOffset += 2;
1671
1672                 // first we handle the linenumber attribute
1673                 if (codeStream.generateLineNumberAttributes) {
1674                         /* Create and add the line number attribute (used for debugging) 
1675                          * Build the pairs of:
1676                          *      (bytecodePC lineNumber)
1677                          * according to the table of start line indexes and the pcToSourceMap table
1678                          * contained into the codestream
1679                          */
1680                         int[] pcToSourceMapTable;
1681                         if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
1682                                 && (codeStream.pcToSourceMapSize != 0)) {
1683                                 int lineNumberNameIndex =
1684                                         constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1685                                 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1686                                         System.arraycopy(
1687                                                 contents,
1688                                                 0,
1689                                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1690                                                 0,
1691                                                 contentsLength);
1692                                 }
1693                                 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1694                                 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1695                                 int lineNumberTableOffset = localContentsOffset;
1696                                 localContentsOffset += 6;
1697                                 // leave space for attribute_length and line_number_table_length
1698                                 int numberOfEntries = 0;
1699                                 int length = codeStream.pcToSourceMapSize;
1700                                 for (int i = 0; i < length;) {
1701                                         // write the entry
1702                                         if (localContentsOffset + 4 >= (contentsLength = localContents.length)) {
1703                                                 System.arraycopy(
1704                                                         contents,
1705                                                         0,
1706                                                         (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1707                                                         0,
1708                                                         contentsLength);
1709                                         }
1710                                         int pc = pcToSourceMapTable[i++];
1711                                         localContents[localContentsOffset++] = (byte) (pc >> 8);
1712                                         localContents[localContentsOffset++] = (byte) pc;
1713                                         int lineNumber = pcToSourceMapTable[i++];
1714                                         localContents[localContentsOffset++] = (byte) (lineNumber >> 8);
1715                                         localContents[localContentsOffset++] = (byte) lineNumber;
1716                                         numberOfEntries++;
1717                                 }
1718                                 // now we change the size of the line number attribute
1719                                 int lineNumberAttr_length = numberOfEntries * 4 + 2;
1720                                 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
1721                                 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
1722                                 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
1723                                 localContents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
1724                                 localContents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
1725                                 localContents[lineNumberTableOffset++] = (byte) numberOfEntries;
1726                                 attributeNumber++;
1727                         }
1728                 }
1729                 // then we do the local variable attribute
1730                 if (codeStream.generateLocalVariableTableAttributes) {
1731                         int localVariableTableOffset = localContentsOffset;
1732                         int numberOfEntries = 0;
1733                         //              codeAttribute.addLocalVariableTableAttribute(this);
1734                         if ((codeStream.pcToSourceMap != null)
1735                                 && (codeStream.pcToSourceMapSize != 0)) {
1736                                 int localVariableNameIndex =
1737                                         constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1738                                 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1739                                         System.arraycopy(
1740                                                 contents,
1741                                                 0,
1742                                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1743                                                 0,
1744                                                 contentsLength);
1745                                 }
1746                                 localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1747                                 localContents[localContentsOffset++] = (byte) localVariableNameIndex;
1748                                 localContentsOffset += 6;
1749                                 // leave space for attribute_length and local_variable_table_length
1750                                 int nameIndex;
1751                                 int descriptorIndex;
1752                                 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
1753                                         LocalVariableBinding localVariable = codeStream.locals[i];
1754                                         for (int j = 0; j < localVariable.initializationCount; j++) {
1755                                                 int startPC = localVariable.initializationPCs[j << 1];
1756                                                 int endPC = localVariable.initializationPCs[(j << 1) + 1];
1757                                                 if (startPC != endPC) { // only entries for non zero length
1758                                                         if (endPC == -1) {
1759                                                                 localVariable.declaringScope.problemReporter().abortDueToInternalError(
1760                                                                         Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
1761                                                                         (AstNode) localVariable.declaringScope.methodScope().referenceContext);
1762                                                         }
1763                                                         if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
1764                                                                 System.arraycopy(
1765                                                                         contents,
1766                                                                         0,
1767                                                                         (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1768                                                                         0,
1769                                                                         contentsLength);
1770                                                         }
1771                                                         // now we can safely add the local entry
1772                                                         numberOfEntries++;
1773                                                         localContents[localContentsOffset++] = (byte) (startPC >> 8);
1774                                                         localContents[localContentsOffset++] = (byte) startPC;
1775                                                         int length = endPC - startPC;
1776                                                         localContents[localContentsOffset++] = (byte) (length >> 8);
1777                                                         localContents[localContentsOffset++] = (byte) length;
1778                                                         nameIndex = constantPool.literalIndex(localVariable.name);
1779                                                         localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1780                                                         localContents[localContentsOffset++] = (byte) nameIndex;
1781                                                         descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
1782                                                         localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1783                                                         localContents[localContentsOffset++] = (byte) descriptorIndex;
1784                                                         int resolvedPosition = localVariable.resolvedPosition;
1785                                                         localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1786                                                         localContents[localContentsOffset++] = (byte) resolvedPosition;
1787                                                 }
1788                                         }
1789                                 }
1790                                 int value = numberOfEntries * 10 + 2;
1791                                 localVariableTableOffset += 2;
1792                                 localContents[localVariableTableOffset++] = (byte) (value >> 24);
1793                                 localContents[localVariableTableOffset++] = (byte) (value >> 16);
1794                                 localContents[localVariableTableOffset++] = (byte) (value >> 8);
1795                                 localContents[localVariableTableOffset++] = (byte) value;
1796                                 localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1797                                 localContents[localVariableTableOffset] = (byte) numberOfEntries;
1798                                 attributeNumber++;
1799                         }
1800                 }
1801                 // update the number of attributes
1802                 // ensure first that there is enough space available inside the contents array
1803                 if (codeAttributeAttributeOffset + 2
1804                         >= (contentsLength = localContents.length)) {
1805                         System.arraycopy(
1806                                 contents,
1807                                 0,
1808                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1809                                 0,
1810                                 contentsLength);
1811                 }
1812                 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1813                 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1814                 // update the attribute length
1815                 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1816                 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1817                 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1818                 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1819                 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1820                 contentsOffset = localContentsOffset;
1821         }
1822
1823         /**
1824          * INTERNAL USE-ONLY
1825          * That method completes the creation of the code attribute by setting
1826          * - the attribute_length
1827          * - max_stack
1828          * - max_locals
1829          * - code_length
1830          * - exception table
1831          * - and debug attributes if necessary.
1832          *
1833          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1834          * @param codeAttributeOffset <CODE>int</CODE>
1835          * @param exceptionHandler int[]
1836          * @param startIndexes int[]
1837          */
1838         public void completeCodeAttributeForClinit(
1839                 int codeAttributeOffset,
1840                 int[] exceptionHandler,
1841                 int[] startLineIndexes) {
1842                 // reinitialize the contents with the byte modified by the code stream
1843                 byte[] localContents = contents = codeStream.bCodeStream;
1844                 int localContentsOffset = codeStream.classFileOffset;
1845                 // codeAttributeOffset is the position inside contents byte array before we started to write
1846                 // any information about the codeAttribute
1847                 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1848                 // to get the right position, 6 for the max_stack etc...
1849                 int contentsLength;
1850                 int code_length = codeStream.position;
1851                 if (code_length > 65535) {
1852                         codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1853                                 codeStream.methodDeclaration.scope.referenceType());
1854                 }
1855                 if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
1856                         System.arraycopy(
1857                                 contents,
1858                                 0,
1859                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1860                                 0,
1861                                 contentsLength);
1862                 }
1863                 int max_stack = codeStream.stackMax;
1864                 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1865                 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1866                 int max_locals = codeStream.maxLocals;
1867                 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1868                 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1869                 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1870                 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1871                 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1872                 localContents[codeAttributeOffset + 13] = (byte) code_length;
1873
1874                 // write the exception table
1875                 localContents[localContentsOffset++] = 0;
1876                 localContents[localContentsOffset++] = 1;
1877                 int start = exceptionHandler[0];
1878                 localContents[localContentsOffset++] = (byte) (start >> 8);
1879                 localContents[localContentsOffset++] = (byte) start;
1880                 int end = exceptionHandler[1];
1881                 localContents[localContentsOffset++] = (byte) (end >> 8);
1882                 localContents[localContentsOffset++] = (byte) end;
1883                 int handlerPC = exceptionHandler[2];
1884                 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1885                 localContents[localContentsOffset++] = (byte) handlerPC;
1886                 int nameIndex = constantPool.literalIndexForJavaLangException();
1887                 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1888                 localContents[localContentsOffset++] = (byte) nameIndex;
1889
1890                 // debug attributes
1891                 int codeAttributeAttributeOffset = localContentsOffset;
1892                 int attributeNumber = 0; // leave two bytes for the attribute_length
1893                 localContentsOffset += 2; // first we handle the linenumber attribute
1894
1895                 // first we handle the linenumber attribute
1896                 if (codeStream.generateLineNumberAttributes) {
1897                         /* Create and add the line number attribute (used for debugging) 
1898                             * Build the pairs of:
1899                             * (bytecodePC lineNumber)
1900                             * according to the table of start line indexes and the pcToSourceMap table
1901                             * contained into the codestream
1902                             */
1903                         int lineNumberNameIndex =
1904                                 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1905                         localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1906                         localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1907                         localContents[localContentsOffset++] = 0;
1908                         localContents[localContentsOffset++] = 0;
1909                         localContents[localContentsOffset++] = 0;
1910                         localContents[localContentsOffset++] = 6;
1911                         localContents[localContentsOffset++] = 0;
1912                         localContents[localContentsOffset++] = 1;
1913                         // first entry at pc = 0
1914                         localContents[localContentsOffset++] = 0;
1915                         localContents[localContentsOffset++] = 0;
1916                         localContents[localContentsOffset++] = (byte) (problemLine >> 8);
1917                         localContents[localContentsOffset++] = (byte) problemLine;
1918                         // now we change the size of the line number attribute
1919                         attributeNumber++;
1920                 }
1921                 // then we do the local variable attribute
1922                 if (codeStream.generateLocalVariableTableAttributes) {
1923                         int localVariableNameIndex =
1924                                 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1925                         if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1926                                 System.arraycopy(
1927                                         contents,
1928                                         0,
1929                                         (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1930                                         0,
1931                                         contentsLength);
1932                         }
1933                         localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1934                         localContents[localContentsOffset++] = (byte) localVariableNameIndex;
1935                         localContents[localContentsOffset++] = 0;
1936                         localContents[localContentsOffset++] = 0;
1937                         localContents[localContentsOffset++] = 0;
1938                         localContents[localContentsOffset++] = 2;
1939                         localContents[localContentsOffset++] = 0;
1940                         localContents[localContentsOffset++] = 0;
1941                         attributeNumber++;
1942                 }
1943                 // update the number of attributes
1944                 // ensure first that there is enough space available inside the contents array
1945                 if (codeAttributeAttributeOffset + 2
1946                         >= (contentsLength = localContents.length)) {
1947                         System.arraycopy(
1948                                 contents,
1949                                 0,
1950                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1951                                 0,
1952                                 contentsLength);
1953                 }
1954                 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1955                 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1956                 // update the attribute length
1957                 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1958                 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1959                 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1960                 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1961                 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1962                 contentsOffset = localContentsOffset;
1963         }
1964
1965         /**
1966          * INTERNAL USE-ONLY
1967          * That method completes the creation of the code attribute by setting
1968          * - the attribute_length
1969          * - max_stack
1970          * - max_locals
1971          * - code_length
1972          * - exception table
1973          * - and debug attributes if necessary.
1974          *
1975          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1976          * @param codeAttributeOffset <CODE>int</CODE>
1977          * @param exceptionHandler int[] 
1978          */
1979         public void completeCodeAttributeForProblemMethod(
1980                 AbstractMethodDeclaration method,
1981                 MethodBinding binding,
1982                 int codeAttributeOffset,
1983                 int[] exceptionHandler,
1984                 int[] startLineIndexes) {
1985                 // reinitialize the localContents with the byte modified by the code stream
1986                 byte[] localContents = contents = codeStream.bCodeStream;
1987                 int localContentsOffset = codeStream.classFileOffset;
1988                 // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
1989                 int max_stack = codeStream.stackMax;
1990                 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1991                 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1992                 int max_locals = codeStream.maxLocals;
1993                 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1994                 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1995                 int code_length = codeStream.position;
1996                 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1997                 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1998                 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1999                 localContents[codeAttributeOffset + 13] = (byte) code_length;
2000                 // write the exception table
2001                 int contentsLength;
2002                 if (localContentsOffset + 50 >= (contentsLength = localContents.length)) {
2003                         System.arraycopy(
2004                                 contents,
2005                                 0,
2006                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2007                                 0,
2008                                 contentsLength);
2009                 }
2010                 localContents[localContentsOffset++] = 0;
2011                 localContents[localContentsOffset++] = 1;
2012                 int start = exceptionHandler[0];
2013                 localContents[localContentsOffset++] = (byte) (start >> 8);
2014                 localContents[localContentsOffset++] = (byte) start;
2015                 int end = exceptionHandler[1];
2016                 localContents[localContentsOffset++] = (byte) (end >> 8);
2017                 localContents[localContentsOffset++] = (byte) end;
2018                 int handlerPC = exceptionHandler[2];
2019                 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
2020                 localContents[localContentsOffset++] = (byte) handlerPC;
2021                 int nameIndex = constantPool.literalIndexForJavaLangException();
2022                 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2023                 localContents[localContentsOffset++] = (byte) nameIndex; // debug attributes
2024                 int codeAttributeAttributeOffset = localContentsOffset;
2025                 int attributeNumber = 0; // leave two bytes for the attribute_length
2026                 localContentsOffset += 2; // first we handle the linenumber attribute
2027
2028                 if (codeStream.generateLineNumberAttributes) {
2029                         /* Create and add the line number attribute (used for debugging) 
2030                             * Build the pairs of:
2031                             * (bytecodePC lineNumber)
2032                             * according to the table of start line indexes and the pcToSourceMap table
2033                             * contained into the codestream
2034                             */
2035                         int lineNumberNameIndex =
2036                                 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
2037                         localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
2038                         localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
2039                         localContents[localContentsOffset++] = 0;
2040                         localContents[localContentsOffset++] = 0;
2041                         localContents[localContentsOffset++] = 0;
2042                         localContents[localContentsOffset++] = 6;
2043                         localContents[localContentsOffset++] = 0;
2044                         localContents[localContentsOffset++] = 1;
2045                         if (problemLine == 0) {
2046                                 problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
2047                         }
2048                         // first entry at pc = 0
2049                         localContents[localContentsOffset++] = 0;
2050                         localContents[localContentsOffset++] = 0;
2051                         localContents[localContentsOffset++] = (byte) (problemLine >> 8);
2052                         localContents[localContentsOffset++] = (byte) problemLine;
2053                         // now we change the size of the line number attribute
2054                         attributeNumber++;
2055                 }
2056                 // then we do the local variable attribute
2057                 if (codeStream.generateLocalVariableTableAttributes) {
2058                         // compute the resolved position for the arguments of the method
2059                         int argSize;
2060                         int localVariableTableOffset = localContentsOffset;
2061                         int numberOfEntries = 0;
2062                         //              codeAttribute.addLocalVariableTableAttribute(this);
2063                         int localVariableNameIndex =
2064                                 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
2065                         if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
2066                                 System.arraycopy(
2067                                         contents,
2068                                         0,
2069                                         (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2070                                         0,
2071                                         contentsLength);
2072                         }
2073                         localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
2074                         localContents[localContentsOffset++] = (byte) localVariableNameIndex;
2075                         localContentsOffset += 6;
2076                         // leave space for attribute_length and local_variable_table_length
2077                         int descriptorIndex;
2078                         if (!codeStream.methodDeclaration.isStatic()) {
2079                                 numberOfEntries++;
2080                                 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
2081                                         System.arraycopy(
2082                                                 contents,
2083                                                 0,
2084                                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2085                                                 0,
2086                                                 contentsLength);
2087                                 }
2088                                 localContents[localContentsOffset++] = 0;
2089                                 localContents[localContentsOffset++] = 0;
2090                                 localContents[localContentsOffset++] = (byte) (code_length >> 8);
2091                                 localContents[localContentsOffset++] = (byte) code_length;
2092                                 nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
2093                                 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2094                                 localContents[localContentsOffset++] = (byte) nameIndex;
2095                                 descriptorIndex =
2096                                         constantPool.literalIndex(
2097                                                 codeStream.methodDeclaration.binding.declaringClass.signature());
2098                                 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2099                                 localContents[localContentsOffset++] = (byte) descriptorIndex;
2100                                 // the resolved position for this is always 0
2101                                 localContents[localContentsOffset++] = 0;
2102                                 localContents[localContentsOffset++] = 0;
2103                         }
2104                         if (binding.isConstructor()) {
2105                                 ReferenceBinding declaringClass = binding.declaringClass;
2106                                 if (declaringClass.isNestedType()) {
2107                                         NestedTypeBinding methodDeclaringClass = (NestedTypeBinding) declaringClass;
2108                                         argSize = methodDeclaringClass.syntheticArgumentsOffset;
2109                                         SyntheticArgumentBinding[] syntheticArguments;
2110                                         if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances())
2111                                                 != null) {
2112                                                 for (int i = 0, max = syntheticArguments.length; i < max; i++) {
2113                                                         LocalVariableBinding localVariable = syntheticArguments[i];
2114                                                         if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
2115                                                                 System.arraycopy(
2116                                                                         contents,
2117                                                                         0,
2118                                                                         (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2119                                                                         0,
2120                                                                         contentsLength);
2121                                                         }
2122                                                         // now we can safely add the local entry
2123                                                         numberOfEntries++;
2124                                                         localContents[localContentsOffset++] = 0;
2125                                                         localContents[localContentsOffset++] = 0;
2126                                                         localContents[localContentsOffset++] = (byte) (code_length >> 8);
2127                                                         localContents[localContentsOffset++] = (byte) code_length;
2128                                                         nameIndex = constantPool.literalIndex(localVariable.name);
2129                                                         localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2130                                                         localContents[localContentsOffset++] = (byte) nameIndex;
2131                                                         descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
2132                                                         localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2133                                                         localContents[localContentsOffset++] = (byte) descriptorIndex;
2134                                                         int resolvedPosition = localVariable.resolvedPosition;
2135                                                         localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2136                                                         localContents[localContentsOffset++] = (byte) resolvedPosition;
2137                                                 }
2138                                         }
2139                                 } else {
2140                                         argSize = 1;
2141                                 }
2142                         } else {
2143                                 argSize = binding.isStatic() ? 0 : 1;
2144                         }
2145                         if (method.binding != null) {
2146                                 TypeBinding[] parameters = method.binding.parameters;
2147                                 Argument[] arguments = method.arguments;
2148                                 if ((parameters != null) && (arguments != null)) {
2149                                         for (int i = 0, max = parameters.length; i < max; i++) {
2150                                                 TypeBinding argumentBinding = parameters[i];
2151                                                 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
2152                                                         System.arraycopy(
2153                                                                 contents,
2154                                                                 0,
2155                                                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2156                                                                 0,
2157                                                                 contentsLength);
2158                                                 }
2159                                                 // now we can safely add the local entry
2160                                                 numberOfEntries++;
2161                                                 localContents[localContentsOffset++] = 0;
2162                                                 localContents[localContentsOffset++] = 0;
2163                                                 localContents[localContentsOffset++] = (byte) (code_length >> 8);
2164                                                 localContents[localContentsOffset++] = (byte) code_length;
2165                                                 nameIndex = constantPool.literalIndex(arguments[i].name);
2166                                                 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2167                                                 localContents[localContentsOffset++] = (byte) nameIndex;
2168                                                 descriptorIndex = constantPool.literalIndex(argumentBinding.signature());
2169                                                 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2170                                                 localContents[localContentsOffset++] = (byte) descriptorIndex;
2171                                                 int resolvedPosition = argSize;
2172                                                 if ((argumentBinding == TypeBinding.LongBinding)
2173                                                         || (argumentBinding == TypeBinding.DoubleBinding))
2174                                                         argSize += 2;
2175                                                 else
2176                                                         argSize++;
2177                                                 localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2178                                                 localContents[localContentsOffset++] = (byte) resolvedPosition;
2179                                         }
2180                                 }
2181                         }
2182                         int value = numberOfEntries * 10 + 2;
2183                         localVariableTableOffset += 2;
2184                         localContents[localVariableTableOffset++] = (byte) (value >> 24);
2185                         localContents[localVariableTableOffset++] = (byte) (value >> 16);
2186                         localContents[localVariableTableOffset++] = (byte) (value >> 8);
2187                         localContents[localVariableTableOffset++] = (byte) value;
2188                         localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
2189                         localContents[localVariableTableOffset] = (byte) numberOfEntries;
2190                         attributeNumber++;
2191                 }
2192                 // update the number of attributes// ensure first that there is enough space available inside the localContents array
2193                 if (codeAttributeAttributeOffset + 2
2194                         >= (contentsLength = localContents.length)) {
2195                         System.arraycopy(
2196                                 contents,
2197                                 0,
2198                                 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2199                                 0,
2200                                 contentsLength);
2201                 }
2202                 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2203                 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2204                 // update the attribute length
2205                 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2206                 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2207                 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2208                 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2209                 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2210                 contentsOffset = localContentsOffset;
2211         }
2212
2213         /**
2214          * INTERNAL USE-ONLY
2215          * That method completes the creation of the code attribute by setting
2216          * - the attribute_length
2217          * - max_stack
2218          * - max_locals
2219          * - code_length
2220          * - exception table
2221          * - and debug attributes if necessary.
2222          *
2223          * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
2224          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
2225          * @param codeAttributeOffset <CODE>int</CODE>
2226          */
2227         public void completeCodeAttributeForSyntheticAccessMethod(
2228                 SyntheticAccessMethodBinding binding,
2229                 int codeAttributeOffset,
2230                 int[] startLineIndexes) {
2231                 // reinitialize the contents with the byte modified by the code stream
2232                 contents = codeStream.bCodeStream;
2233                 int localContentsOffset = codeStream.classFileOffset;
2234                 // codeAttributeOffset is the position inside contents byte array before we started to write
2235                 // any information about the codeAttribute
2236                 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
2237                 // to get the right position, 6 for the max_stack etc...
2238                 int max_stack = codeStream.stackMax;
2239                 contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
2240                 contents[codeAttributeOffset + 7] = (byte) max_stack;
2241                 int max_locals = codeStream.maxLocals;
2242                 contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
2243                 contents[codeAttributeOffset + 9] = (byte) max_locals;
2244                 int code_length = codeStream.position;
2245                 contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
2246                 contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
2247                 contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
2248                 contents[codeAttributeOffset + 13] = (byte) code_length;
2249                 int contentsLength;
2250                 if ((localContentsOffset + 40) >= (contentsLength = contents.length)) {
2251                         System.arraycopy(
2252                                 contents,
2253                                 0,
2254                                 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2255                                 0,
2256                                 contentsLength);
2257                 }
2258                 // there is no exception table, so we need to offset by 2 the current offset and move 
2259                 // on the attribute generation
2260                 localContentsOffset += 2;
2261                 // debug attributes
2262                 int codeAttributeAttributeOffset = localContentsOffset;
2263                 int attributeNumber = 0;
2264                 // leave two bytes for the attribute_length
2265                 localContentsOffset += 2;
2266
2267                 // first we handle the linenumber attribute
2268                 if (codeStream.generateLineNumberAttributes) {
2269                         int index = 0;
2270                         int lineNumberNameIndex =
2271                                 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
2272                         contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
2273                         contents[localContentsOffset++] = (byte) lineNumberNameIndex;
2274                         int lineNumberTableOffset = localContentsOffset;
2275                         localContentsOffset += 6;
2276                         // leave space for attribute_length and line_number_table_length
2277                         // Seems like do would be better, but this preserves the existing behavior.
2278                         index = searchLineNumber(startLineIndexes, binding.sourceStart);
2279                         contents[localContentsOffset++] = 0;
2280                         contents[localContentsOffset++] = 0;
2281                         contents[localContentsOffset++] = (byte) (index >> 8);
2282                         contents[localContentsOffset++] = (byte) index;
2283                         // now we change the size of the line number attribute
2284                         contents[lineNumberTableOffset++] = 0;
2285                         contents[lineNumberTableOffset++] = 0;
2286                         contents[lineNumberTableOffset++] = 0;
2287                         contents[lineNumberTableOffset++] = 6;
2288                         contents[lineNumberTableOffset++] = 0;
2289                         contents[lineNumberTableOffset++] = 1;
2290                         attributeNumber++;
2291                 }
2292                 // then we do the local variable attribute
2293                 if (codeStream.generateLocalVariableTableAttributes) {
2294                         int localVariableTableOffset = localContentsOffset;
2295                         int numberOfEntries = 0;
2296                         int localVariableNameIndex =
2297                                 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
2298                         if (localContentsOffset + 8 > (contentsLength = contents.length)) {
2299                                 System.arraycopy(
2300                                         contents,
2301                                         0,
2302                                         (contents = new byte[contentsLength + INCREMENT_SIZE]),
2303                                         0,
2304                                         contentsLength);
2305                         }
2306                         contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
2307                         contents[localContentsOffset++] = (byte) localVariableNameIndex;
2308                         localContentsOffset += 6;
2309                         // leave space for attribute_length and local_variable_table_length
2310                         int nameIndex;
2311                         int descriptorIndex;
2312                         for (int i = 0; i < codeStream.allLocalsCounter; i++) {
2313                                 LocalVariableBinding localVariable = codeStream.locals[i];
2314                                 for (int j = 0; j < localVariable.initializationCount; j++) {
2315                                         int startPC = localVariable.initializationPCs[j << 1];
2316                                         int endPC = localVariable.initializationPCs[(j << 1) + 1];
2317                                         if (startPC != endPC) { // only entries for non zero length
2318                                                 if (endPC == -1) {
2319                                                         localVariable.declaringScope.problemReporter().abortDueToInternalError(
2320                                                                 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
2321                                                                 (AstNode) localVariable.declaringScope.methodScope().referenceContext);
2322                                                 }
2323                                                 if (localContentsOffset + 10 > (contentsLength = contents.length)) {
2324                                                         System.arraycopy(
2325                                                                 contents,
2326                                                                 0,
2327                                                                 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2328                                                                 0,
2329                                                                 contentsLength);
2330                                                 }
2331                                                 // now we can safely add the local entry
2332                                                 numberOfEntries++;
2333                                                 contents[localContentsOffset++] = (byte) (startPC >> 8);
2334                                                 contents[localContentsOffset++] = (byte) startPC;
2335                                                 int length = endPC - startPC;
2336                                                 contents[localContentsOffset++] = (byte) (length >> 8);
2337                                                 contents[localContentsOffset++] = (byte) length;
2338                                                 nameIndex = constantPool.literalIndex(localVariable.name);
2339                                                 contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2340                                                 contents[localContentsOffset++] = (byte) nameIndex;
2341                                                 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
2342                                                 contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2343                                                 contents[localContentsOffset++] = (byte) descriptorIndex;
2344                                                 int resolvedPosition = localVariable.resolvedPosition;
2345                                                 contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2346                                                 contents[localContentsOffset++] = (byte) resolvedPosition;
2347                                         }
2348                                 }
2349                         }
2350                         int value = numberOfEntries * 10 + 2;
2351                         localVariableTableOffset += 2;
2352                         contents[localVariableTableOffset++] = (byte) (value >> 24);
2353                         contents[localVariableTableOffset++] = (byte) (value >> 16);
2354                         contents[localVariableTableOffset++] = (byte) (value >> 8);
2355                         contents[localVariableTableOffset++] = (byte) value;
2356                         contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
2357                         contents[localVariableTableOffset] = (byte) numberOfEntries;
2358                         attributeNumber++;
2359                 }
2360                 // update the number of attributes
2361                 // ensure first that there is enough space available inside the contents array
2362                 if (codeAttributeAttributeOffset + 2 >= (contentsLength = contents.length)) {
2363                         System.arraycopy(
2364                                 contents,
2365                                 0,
2366                                 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2367                                 0,
2368                                 contentsLength);
2369                 }
2370                 contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2371                 contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2372
2373                 // update the attribute length
2374                 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2375                 contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2376                 contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2377                 contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2378                 contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2379                 contentsOffset = localContentsOffset;
2380         }
2381
2382         /**
2383          * INTERNAL USE-ONLY
2384          * Complete the creation of a method info by setting up the number of attributes at the right offset.
2385          *
2386          * @param methodAttributeOffset <CODE>int</CODE>
2387          * @param attributeNumber <CODE>int</CODE> 
2388          */
2389         public void completeMethodInfo(
2390                 int methodAttributeOffset,
2391                 int attributeNumber) {
2392                 // update the number of attributes
2393                 contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
2394                 contents[methodAttributeOffset] = (byte) attributeNumber;
2395         }
2396
2397         /*
2398          * INTERNAL USE-ONLY
2399          * Innerclasses get their name computed as they are generated, since some may not
2400          * be actually outputed if sitting inside unreachable code.
2401          *
2402          * @param localType org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding
2403          */
2404         public char[] computeConstantPoolName(LocalTypeBinding localType) {
2405                 if (localType.constantPoolName() != null) {
2406                         return localType.constantPoolName();
2407                 }
2408                 // delegates to the outermost enclosing classfile, since it is the only one with a global vision of its innertypes.
2409                 if (enclosingClassFile != null) {
2410                         return this.outerMostEnclosingClassFile().computeConstantPoolName(localType);
2411                 }
2412                 if (nameUsage == null)
2413                         nameUsage = new HashtableOfType();
2414
2415                 // ensure there is not already such a local type name defined by the user
2416                 int index = 0;
2417                 char[] candidateName;
2418                 while(true) {
2419                         if (localType.isMemberType()){
2420                                 if (index == 0){
2421                                         candidateName = CharOperation.concat(
2422                                                 localType.enclosingType().constantPoolName(),
2423                                                 localType.sourceName,
2424                                                 '$');
2425                                 } else {
2426                                         // in case of collision, then member name gets extra $1 inserted
2427                                         // e.g. class X { { class L{} new X(){ class L{} } } }
2428                                         candidateName = CharOperation.concat(
2429                                                 localType.enclosingType().constantPoolName(),
2430                                                 '$',
2431                                                 String.valueOf(index).toCharArray(),
2432                                                 '$',
2433                                                 localType.sourceName);
2434                                 }
2435                         } else if (localType.isAnonymousType()){
2436                                         candidateName = CharOperation.concat(
2437                                                 referenceBinding.constantPoolName(),
2438                                                 String.valueOf(index+1).toCharArray(),
2439                                                 '$');
2440                         } else {
2441                                         candidateName = CharOperation.concat(
2442                                                 referenceBinding.constantPoolName(),
2443                                                 '$',
2444                                                 String.valueOf(index+1).toCharArray(),
2445                                                 '$',
2446                                                 localType.sourceName);
2447                         }                                               
2448                         if (nameUsage.get(candidateName) != null) {
2449                                 index ++;
2450                         } else {
2451                                 nameUsage.put(candidateName, localType);
2452                                 break;
2453                         }
2454                 }
2455                 return candidateName;
2456         }
2457
2458         /**
2459          * INTERNAL USE-ONLY
2460          * Request the creation of a ClassFile compatible representation of a problematic type
2461          *
2462          * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
2463          * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult
2464          */
2465         public static void createProblemType(
2466                 TypeDeclaration typeDeclaration,
2467                 CompilationResult unitResult) {
2468                 SourceTypeBinding typeBinding = typeDeclaration.binding;
2469                 ClassFile classFile = new ClassFile(typeBinding, null, true);
2470
2471                 // inner attributes
2472                 if (typeBinding.isMemberType())
2473                         classFile.recordEnclosingTypeAttributes(typeBinding);
2474
2475                 // add its fields
2476                 FieldBinding[] fields = typeBinding.fields;
2477                 if ((fields != null) && (fields != NoFields)) {
2478                         for (int i = 0, max = fields.length; i < max; i++) {
2479                                 if (fields[i].constant == null) {
2480                                         FieldReference.getConstantFor(fields[i], false, null, null, 0);
2481                                 }
2482                         }
2483                         classFile.addFieldInfos();
2484                 } else {
2485                         // we have to set the number of fields to be equals to 0
2486                         classFile.contents[classFile.contentsOffset++] = 0;
2487                         classFile.contents[classFile.contentsOffset++] = 0;
2488                 }
2489                 // leave some space for the methodCount
2490                 classFile.setForMethodInfos();
2491                 // add its user defined methods
2492                 MethodBinding[] methods = typeBinding.methods;
2493                 AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods;
2494                 int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length;
2495                 int problemsLength;
2496                 IProblem[] problems = unitResult.getProblems();
2497                 if (problems == null) {
2498                         problems = new IProblem[0];
2499                 }
2500                 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
2501                 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
2502                 if (methods != null) {
2503                         if (typeBinding.isInterface()) {
2504                                 // we cannot create problem methods for an interface. So we have to generate a clinit
2505                                 // which should contain all the problem
2506                                 classFile.addProblemClinit(problemsCopy);
2507                                 for (int i = 0, max = methods.length; i < max; i++) {
2508                                         MethodBinding methodBinding;
2509                                         if ((methodBinding = methods[i]) != null) {
2510                                                 // find the corresponding method declaration
2511                                                 for (int j = 0; j < maxMethodDecl; j++) {
2512                                                         if ((methodDeclarations[j] != null)
2513                                                                 && (methodDeclarations[j].binding == methods[i])) {
2514                                                                 if (!methodBinding.isConstructor()) {
2515                                                                         classFile.addAbstractMethod(methodDeclarations[j], methodBinding);
2516                                                                 }
2517                                                                 break;
2518                                                         }
2519                                                 }
2520                                         }
2521                                 }
2522                         } else {
2523                                 for (int i = 0, max = methods.length; i < max; i++) {
2524                                         MethodBinding methodBinding;
2525                                         if ((methodBinding = methods[i]) != null) {
2526                                                 // find the corresponding method declaration
2527                                                 for (int j = 0; j < maxMethodDecl; j++) {
2528                                                         if ((methodDeclarations[j] != null)
2529                                                                 && (methodDeclarations[j].binding == methods[i])) {
2530                                                                 AbstractMethodDeclaration methodDecl;
2531                                                                 if ((methodDecl = methodDeclarations[j]).isConstructor()) {
2532                                                                         classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy);
2533                                                                 } else {
2534                                                                         classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy);
2535                                                                 }
2536                                                                 break;
2537                                                         }
2538                                                 }
2539                                         }
2540                                 }
2541                         }
2542                         // add abstract methods
2543                         classFile.addDefaultAbstractMethods();
2544                 }
2545                 // propagate generation of (problem) member types
2546                 if (typeDeclaration.memberTypes != null) {
2547                         for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) {
2548                                 TypeDeclaration memberType = typeDeclaration.memberTypes[i];
2549                                 if (memberType.binding != null) {
2550                                         classFile.recordNestedMemberAttribute(memberType.binding);
2551                                         ClassFile.createProblemType(memberType, unitResult);
2552                                 }
2553                         }
2554                 }
2555                 classFile.addAttributes();
2556                 unitResult.record(typeBinding.constantPoolName(), classFile);
2557         }
2558
2559         /**
2560          * INTERNAL USE-ONLY
2561          * This methods returns a char[] representing the file name of the receiver
2562          *
2563          * @return char[]
2564          */
2565         public char[] fileName() {
2566                 return constantPool.UTF8Cache.returnKeyFor(1);
2567         }
2568
2569         /**
2570          * INTERNAL USE-ONLY
2571          * That method generates the header of a code attribute.
2572          * - the index inside the constant pool for the attribute name (i.e.&nbsp;Code)
2573          * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4).
2574          */
2575         public void generateCodeAttributeHeader() {
2576                 int contentsLength;
2577                 if (contentsOffset + 20 >= (contentsLength = contents.length)) {
2578                         System.arraycopy(
2579                                 contents,
2580                                 0,
2581                                 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2582                                 0,
2583                                 contentsLength);
2584                 }
2585                 int constantValueNameIndex =
2586                         constantPool.literalIndex(AttributeNamesConstants.CodeName);
2587                 contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
2588                 contents[contentsOffset++] = (byte) constantValueNameIndex;
2589                 // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4)
2590                 contentsOffset += 12;
2591         }
2592
2593         /**
2594          * INTERNAL USE-ONLY
2595          * That method generates the attributes of a code attribute.
2596          * They could be:
2597          * - an exception attribute for each try/catch found inside the method
2598          * - a deprecated attribute
2599          * - a synthetic attribute for synthetic access methods
2600          *
2601          * It returns the number of attributes created for the code attribute.
2602          *
2603          * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2604          * @return <CODE>int</CODE>
2605          */
2606         public int generateMethodInfoAttribute(MethodBinding methodBinding) {
2607                 // leave two bytes for the attribute_number
2608                 contentsOffset += 2;
2609                 // now we can handle all the attribute for that method info:
2610                 // it could be:
2611                 // - a CodeAttribute
2612                 // - a ExceptionAttribute
2613                 // - a DeprecatedAttribute
2614                 // - a SyntheticAttribute
2615
2616                 // Exception attribute
2617                 ReferenceBinding[] thrownsExceptions;
2618                 int contentsLength;
2619                 int attributeNumber = 0;
2620                 if ((thrownsExceptions = methodBinding.thrownExceptions) != NoExceptions) {
2621                         // The method has a throw clause. So we need to add an exception attribute
2622                         // check that there is enough space to write all the bytes for the exception attribute
2623                         int length = thrownsExceptions.length;
2624                         if (contentsOffset + (8 + length * 2) >= (contentsLength = contents.length)) {
2625                                 System.arraycopy(
2626                                         contents,
2627                                         0,
2628                                         (contents =
2629                                                 new byte[contentsLength + Math.max(INCREMENT_SIZE, (8 + length * 2))]),
2630                                         0,
2631                                         contentsLength);
2632                         }
2633                         int exceptionNameIndex =
2634                                 constantPool.literalIndex(AttributeNamesConstants.ExceptionsName);
2635                         contents[contentsOffset++] = (byte) (exceptionNameIndex >> 8);
2636                         contents[contentsOffset++] = (byte) exceptionNameIndex;
2637                         // The attribute length = length * 2 + 2 in case of a exception attribute
2638                         int attributeLength = length * 2 + 2;
2639                         contents[contentsOffset++] = (byte) (attributeLength >> 24);
2640                         contents[contentsOffset++] = (byte) (attributeLength >> 16);
2641                         contents[contentsOffset++] = (byte) (attributeLength >> 8);
2642                         contents[contentsOffset++] = (byte) attributeLength;
2643                         contents[contentsOffset++] = (byte) (length >> 8);
2644                         contents[contentsOffset++] = (byte) length;
2645                         for (int i = 0; i < length; i++) {
2646                                 int exceptionIndex = constantPool.literalIndex(thrownsExceptions[i]);
2647                                 contents[contentsOffset++] = (byte) (exceptionIndex >> 8);
2648                                 contents[contentsOffset++] = (byte) exceptionIndex;
2649                         }
2650                         attributeNumber++;
2651                 }
2652                 // Deprecated attribute
2653                 // Check that there is enough space to write the deprecated attribute
2654                 if (contentsOffset + 6 >= (contentsLength = contents.length)) {
2655                         System.arraycopy(
2656                                 contents,
2657                                 0,
2658                                 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2659                                 0,
2660                                 contentsLength);
2661                 }
2662                 if (methodBinding.isDeprecated()) {
2663                         int deprecatedAttributeNameIndex =
2664                                 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
2665                         contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
2666                         contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
2667                         // the length of a deprecated attribute is equals to 0
2668                         contents[contentsOffset++] = 0;
2669                         contents[contentsOffset++] = 0;
2670                         contents[contentsOffset++] = 0;
2671                         contents[contentsOffset++] = 0;
2672
2673                         attributeNumber++;
2674                 }
2675                 // Synthetic attribute
2676                 // Check that there is enough space to write the deprecated attribute
2677                 if (contentsOffset + 6 >= (contentsLength = contents.length)) {
2678                         System.arraycopy(
2679                                 contents,
2680                                 0,
2681                                 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2682                                 0,
2683                                 contentsLength);
2684                 }
2685                 if (methodBinding.isSynthetic()) {
2686                         int syntheticAttributeNameIndex =
2687                                 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
2688                         contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
2689                         contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
2690                         // the length of a synthetic attribute is equals to 0
2691                         contents[contentsOffset++] = 0;
2692                         contents[contentsOffset++] = 0;
2693                         contents[contentsOffset++] = 0;
2694                         contents[contentsOffset++] = 0;
2695
2696                         attributeNumber++;
2697                 }
2698                 return attributeNumber;
2699         }
2700
2701         /**
2702          * INTERNAL USE-ONLY
2703          * That method generates the header of a method info:
2704          * The header consists in:
2705          * - the access flags
2706          * - the name index of the method name inside the constant pool
2707          * - the descriptor index of the signature of the method inside the constant pool.
2708          *
2709          * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2710          */
2711         public void generateMethodInfoHeader(MethodBinding methodBinding) {
2712                 // check that there is enough space to write all the bytes for the method info corresponding
2713                 // to the @methodBinding
2714                 int contentsLength;
2715                 methodCount++; // add one more method
2716                 if (contentsOffset + 10 >= (contentsLength = contents.length)) {
2717                         System.arraycopy(
2718                                 contents,
2719                                 0,
2720                                 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2721                                 0,
2722                                 contentsLength);
2723                 }
2724                 int accessFlags = methodBinding.getAccessFlags();
2725                 if (methodBinding.isRequiredToClearPrivateModifier()) {
2726                         accessFlags &= ~AccPrivate;
2727                 }
2728                 contents[contentsOffset++] = (byte) (accessFlags >> 8);
2729                 contents[contentsOffset++] = (byte) accessFlags;
2730                 int nameIndex = constantPool.literalIndex(methodBinding.selector);
2731                 contents[contentsOffset++] = (byte) (nameIndex >> 8);
2732                 contents[contentsOffset++] = (byte) nameIndex;
2733                 int descriptorIndex = constantPool.literalIndex(methodBinding.signature());
2734                 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
2735                 contents[contentsOffset++] = (byte) descriptorIndex;
2736         }
2737
2738         /**
2739          * INTERNAL USE-ONLY
2740          * That method generates the method info header of a clinit:
2741          * The header consists in:
2742          * - the access flags (always default access + static)
2743          * - the name index of the method name (always <clinit>) inside the constant pool 
2744          * - the descriptor index of the signature (always ()V) of the method inside the constant pool.
2745          *
2746          * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2747          */
2748         public void generateMethodInfoHeaderForClinit() {
2749                 // check that there is enough space to write all the bytes for the method info corresponding
2750                 // to the @methodBinding
2751                 int contentsLength;
2752                 methodCount++; // add one more method
2753                 if (contentsOffset + 10 >= (contentsLength = contents.length)) {
2754                         System.arraycopy(
2755                                 contents,
2756                                 0,
2757                                 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2758                                 0,
2759                                 contentsLength);
2760                 }
2761                 contents[contentsOffset++] = (byte) ((AccDefault | AccStatic) >> 8);
2762                 contents[contentsOffset++] = (byte) (AccDefault | AccStatic);
2763                 int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.Clinit);
2764                 contents[contentsOffset++] = (byte) (nameIndex >> 8);
2765                 contents[contentsOffset++] = (byte) nameIndex;
2766                 int descriptorIndex =
2767                         constantPool.literalIndex(QualifiedNamesConstants.ClinitSignature);
2768                 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
2769                 contents[contentsOffset++] = (byte) descriptorIndex;
2770                 // We know that we won't get more than 1 attribute: the code attribute
2771                 contents[contentsOffset++] = 0;
2772                 contents[contentsOffset++] = 1;
2773         }
2774
2775         /**
2776          * EXTERNAL API
2777          * Answer the actual bytes of the class file
2778          *
2779          * This method encodes the receiver structure into a byte array which is the content of the classfile.
2780          * Returns the byte array that represents the encoded structure of the receiver.
2781          *
2782          * @return byte[]
2783          */
2784         public byte[] getBytes() {
2785                 byte[] fullContents = new byte[headerOffset + contentsOffset];
2786                 System.arraycopy(header, 0, fullContents, 0, headerOffset);
2787                 System.arraycopy(contents, 0, fullContents, headerOffset, contentsOffset);
2788                 return fullContents;
2789         }
2790
2791         /**
2792          * EXTERNAL API
2793          * Answer the compound name of the class file.
2794          * @return char[][]
2795          * e.g. {{java}, {util}, {Hashtable}}.
2796          */
2797         public char[][] getCompoundName() {
2798                 return CharOperation.splitOn('/', fileName());
2799         }
2800
2801         /**
2802          * INTERNAL USE-ONLY
2803          * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name
2804          * for all inner types of the receiver.
2805          * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile
2806          */
2807         public ClassFile outerMostEnclosingClassFile() {
2808                 ClassFile current = this;
2809                 while (current.enclosingClassFile != null)
2810                         current = current.enclosingClassFile;
2811                 return current;
2812         }
2813
2814         /**
2815          * INTERNAL USE-ONLY
2816          * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2817          * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2818          *
2819          * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2820          */
2821         public void recordEnclosingTypeAttributes(ReferenceBinding binding) {
2822                 // add all the enclosing types
2823                 ReferenceBinding enclosingType = referenceBinding.enclosingType();
2824                 int depth = 0;
2825                 while (enclosingType != null) {
2826                         depth++;
2827                         enclosingType = enclosingType.enclosingType();
2828                 }
2829                 enclosingType = referenceBinding;
2830                 ReferenceBinding enclosingTypes[];
2831                 if (depth >= 2) {
2832                         enclosingTypes = new ReferenceBinding[depth];
2833                         for (int i = depth - 1; i >= 0; i--) {
2834                                 enclosingTypes[i] = enclosingType;
2835                                 enclosingType = enclosingType.enclosingType();
2836                         }
2837                         for (int i = 0; i < depth; i++) {
2838                                 addInnerClasses(enclosingTypes[i]);
2839                         }
2840                 } else {
2841                         addInnerClasses(referenceBinding);
2842                 }
2843         }
2844
2845         /**
2846          * INTERNAL USE-ONLY
2847          * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2848          * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2849          *
2850          * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2851          */
2852         public void recordNestedLocalAttribute(ReferenceBinding binding) {
2853                 // add all the enclosing types
2854                 ReferenceBinding enclosingType = referenceBinding.enclosingType();
2855                 int depth = 0;
2856                 while (enclosingType != null) {
2857                         depth++;
2858                         enclosingType = enclosingType.enclosingType();
2859                 }
2860                 enclosingType = referenceBinding;
2861                 ReferenceBinding enclosingTypes[];
2862                 if (depth >= 2) {
2863                         enclosingTypes = new ReferenceBinding[depth];
2864                         for (int i = depth - 1; i >= 0; i--) {
2865                                 enclosingTypes[i] = enclosingType;
2866                                 enclosingType = enclosingType.enclosingType();
2867                         }
2868                         for (int i = 0; i < depth; i++)
2869                                 addInnerClasses(enclosingTypes[i]);
2870                 } else {
2871                         addInnerClasses(binding);
2872                 }
2873         }
2874
2875         /**
2876          * INTERNAL USE-ONLY
2877          * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2878          * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2879          *
2880          * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2881          */
2882         public void recordNestedMemberAttribute(ReferenceBinding binding) {
2883                 addInnerClasses(binding);
2884         }
2885
2886         /**
2887          * INTERNAL USE-ONLY
2888          * Search the line number corresponding to a specific position
2889          *
2890          * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
2891          */
2892         public static final int searchLineNumber(
2893                 int[] startLineIndexes,
2894                 int position) {
2895                 // this code is completely useless, but it is the same implementation than
2896                 // org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int)
2897                 // if (startLineIndexes == null)
2898                 //      return 1;
2899                 int length = startLineIndexes.length;
2900                 if (length == 0)
2901                         return 1;
2902                 int g = 0, d = length - 1;
2903                 int m = 0;
2904                 while (g <= d) {
2905                         m = (g + d) / 2;
2906                         if (position < startLineIndexes[m]) {
2907                                 d = m - 1;
2908                         } else
2909                                 if (position > startLineIndexes[m]) {
2910                                         g = m + 1;
2911                                 } else {
2912                                         return m + 1;
2913                                 }
2914                 }
2915                 if (position < startLineIndexes[m]) {
2916                         return m + 1;
2917                 }
2918                 return m + 2;
2919         }
2920
2921         /**
2922          * INTERNAL USE-ONLY
2923          * This methods leaves the space for method counts recording.
2924          */
2925         public void setForMethodInfos() {
2926                 // leave some space for the methodCount
2927                 methodCountOffset = contentsOffset;
2928                 contentsOffset += 2;
2929         }
2930
2931         /**
2932          * INTERNAL USE-ONLY
2933          * outputPath is formed like:
2934          *         c:\temp\ the last character is a file separator
2935          * relativeFileName is formed like:
2936          *     java\lang\String.class
2937          * @param generatePackagesStructure a flag to know if the packages structure has to be generated.
2938          * @param outputPath the output directory
2939          * @param relativeFileName java.lang.String
2940          * @param contents byte[]
2941          * 
2942          */
2943         public static void writeToDisk(
2944                 boolean generatePackagesStructure,
2945                 String outputPath,
2946                 String relativeFileName,
2947                 byte[] contents)
2948                 throws IOException {
2949                         
2950                 BufferedOutputStream output = null;
2951                 if (generatePackagesStructure) {
2952                         output = new BufferedOutputStream(
2953                                 new FileOutputStream(
2954                                                 new File(buildAllDirectoriesInto(outputPath, relativeFileName))));
2955                 } else {
2956                         String fileName = null;
2957                         char fileSeparatorChar = File.separatorChar;
2958                         String fileSeparator = File.separator;
2959                         // First we ensure that the outputPath exists
2960                         outputPath = outputPath.replace('/', fileSeparatorChar);
2961                         // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
2962                         int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar);
2963                         if (indexOfPackageSeparator == -1) {
2964                                 if (outputPath.endsWith(fileSeparator)) {
2965                                         fileName = outputPath + relativeFileName;
2966                                 } else {
2967                                         fileName = outputPath + fileSeparator + relativeFileName;
2968                                 }
2969                         } else {
2970                                 int length = relativeFileName.length();
2971                                 if (outputPath.endsWith(fileSeparator)) {
2972                                         fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length);
2973                                 } else {
2974                                         fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length);
2975                                 }
2976                         }
2977                         output = new BufferedOutputStream(
2978                                 new FileOutputStream(
2979                                                 new File(fileName)));
2980                 }
2981                 try {
2982                         output.write(contents);
2983                 } finally {
2984                         output.flush();
2985                         output.close();
2986                 }
2987         }
2988 }