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