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