1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler;
16 import net.sourceforge.phpdt.internal.compiler.impl.*;
17 import net.sourceforge.phpdt.core.compiler.*;
18 import net.sourceforge.phpdt.internal.compiler.ast.*;
19 import net.sourceforge.phpdt.internal.compiler.codegen.*;
20 import net.sourceforge.phpdt.internal.compiler.lookup.*;
21 import net.sourceforge.phpdt.internal.compiler.problem.*;
22 import net.sourceforge.phpdt.internal.compiler.util.*;
25 * Represents a class file wrapper on bytes, it is aware of its actual
28 * Public APIs are listed below:
31 * Answer the actual bytes of the class file
33 * char[][] getCompoundName();
34 * Answer the compound name of the class file.
35 * For example, {{java}, {util}, {Hashtable}}.
37 * byte[] getReducedBytes();
38 * Answer a smaller byte format, which is only contains some structural
39 * information. Those bytes are decodable with a regular class file reader,
40 * such as DietClassFileReader
42 public class ClassFile
43 implements AttributeNamesConstants, CompilerModifiers, TypeConstants, TypeIds {
44 public SourceTypeBinding referenceBinding;
45 public ConstantPool constantPool;
46 public ClassFile enclosingClassFile;
47 // used to generate private access methods
48 public int produceDebugAttributes;
49 public ReferenceBinding[] innerClassesBindings;
50 public int numberOfInnerClasses;
52 // the header contains all the bytes till the end of the constant pool
53 public byte[] contents;
54 // that collection contains all the remaining bytes of the .class file
55 public int headerOffset;
56 public int contentsOffset;
57 public int constantPoolOffset;
58 public int methodCountOffset;
59 public int methodCount;
60 protected boolean creatingProblemType;
61 public static final int INITIAL_CONTENTS_SIZE = 1000;
62 public static final int INITIAL_HEADER_SIZE = 1000;
63 public static final int INCREMENT_SIZE = 1000;
64 public static final int INNER_CLASSES_SIZE = 5;
65 protected HashtableOfType nameUsage;
66 public CodeStream codeStream;
67 protected int problemLine; // used to create line number attributes for problem methods
71 * This methods creates a new instance of the receiver.
78 * This methods creates a new instance of the receiver.
80 * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding
81 * @param enclosingClassFile org.eclipse.jdt.internal.compiler.ClassFile
82 * @param creatingProblemType <CODE>boolean</CODE>
85 SourceTypeBinding aType,
86 ClassFile enclosingClassFile,
87 boolean creatingProblemType) {
88 referenceBinding = aType;
89 header = new byte[INITIAL_HEADER_SIZE];
90 // generate the magic numbers inside the header
91 header[headerOffset++] = (byte) (0xCAFEBABEL >> 24);
92 header[headerOffset++] = (byte) (0xCAFEBABEL >> 16);
93 header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
94 header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
95 switch(((SourceTypeBinding) referenceBinding).scope.environment().options.targetJDK) {
96 case CompilerOptions.JDK1_4 :
97 // Compatible with JDK 1.4
98 header[headerOffset++] = 0;
99 header[headerOffset++] = 0;
100 header[headerOffset++] = 0;
101 header[headerOffset++] = 48;
103 case CompilerOptions.JDK1_3 :
104 // Compatible with JDK 1.3
105 header[headerOffset++] = 0;
106 header[headerOffset++] = 0;
107 header[headerOffset++] = 0;
108 header[headerOffset++] = 47;
110 case CompilerOptions.JDK1_2 :
111 // Compatible with JDK 1.2
112 header[headerOffset++] = 0;
113 header[headerOffset++] = 0;
114 header[headerOffset++] = 0;
115 header[headerOffset++] = 46;
117 case CompilerOptions.JDK1_1 :
118 // Compatible with JDK 1.1
119 header[headerOffset++] = 0;
120 header[headerOffset++] = 3;
121 header[headerOffset++] = 0;
122 header[headerOffset++] = 45;
124 constantPoolOffset = headerOffset;
126 constantPool = new ConstantPool(this);
128 // Modifier manipulations for classfile
129 int accessFlags = aType.getAccessFlags();
130 if (aType.isPrivate()) { // rewrite private to non-public
131 accessFlags &= ~AccPublic;
133 if (aType.isProtected()) { // rewrite protected into public
134 accessFlags |= AccPublic;
136 // clear all bits that are illegal for a class or an interface
146 // set the AccSuper flag (has to be done after clearing AccSynchronized - since same value)
147 accessFlags |= AccSuper;
149 this.enclosingClassFile = enclosingClassFile;
150 // innerclasses get their names computed at code gen time
151 if (aType.isLocalType()) {
152 ((LocalTypeBinding) aType).constantPoolName(
153 computeConstantPoolName((LocalTypeBinding) aType));
154 ReferenceBinding[] memberTypes = aType.memberTypes();
155 for (int i = 0, max = memberTypes.length; i < max; i++) {
156 ((LocalTypeBinding) memberTypes[i]).constantPoolName(
157 computeConstantPoolName((LocalTypeBinding) memberTypes[i]));
160 contents = new byte[INITIAL_CONTENTS_SIZE];
161 // now we continue to generate the bytes inside the contents array
162 contents[contentsOffset++] = (byte) (accessFlags >> 8);
163 contents[contentsOffset++] = (byte) accessFlags;
164 int classNameIndex = constantPool.literalIndex(aType);
165 contents[contentsOffset++] = (byte) (classNameIndex >> 8);
166 contents[contentsOffset++] = (byte) classNameIndex;
167 int superclassNameIndex;
168 if (aType.isInterface()) {
169 superclassNameIndex = constantPool.literalIndexForJavaLangObject();
171 superclassNameIndex =
172 (aType.superclass == null ? 0 : constantPool.literalIndex(aType.superclass));
174 contents[contentsOffset++] = (byte) (superclassNameIndex >> 8);
175 contents[contentsOffset++] = (byte) superclassNameIndex;
176 ReferenceBinding[] superInterfacesBinding = aType.superInterfaces();
177 int interfacesCount = superInterfacesBinding.length;
178 contents[contentsOffset++] = (byte) (interfacesCount >> 8);
179 contents[contentsOffset++] = (byte) interfacesCount;
180 if (superInterfacesBinding != null) {
181 for (int i = 0; i < interfacesCount; i++) {
182 int interfaceIndex = constantPool.literalIndex(superInterfacesBinding[i]);
183 contents[contentsOffset++] = (byte) (interfaceIndex >> 8);
184 contents[contentsOffset++] = (byte) interfaceIndex;
187 produceDebugAttributes =
188 ((SourceTypeBinding) referenceBinding)
192 .produceDebugAttributes;
193 innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE];
194 this.creatingProblemType = creatingProblemType;
195 codeStream = new CodeStream(this);
197 // retrieve the enclosing one guaranteed to be the one matching the propagated flow info
198 // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check)
199 ClassFile outermostClassFile = this.outerMostEnclosingClassFile();
200 if (this == outermostClassFile) {
201 codeStream.maxFieldCount = aType.scope.referenceType().maxFieldCount;
203 codeStream.maxFieldCount = outermostClassFile.codeStream.maxFieldCount;
209 * Generate the byte for a problem method info that correspond to a boggus method.
211 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
212 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
214 public void addAbstractMethod(
215 AbstractMethodDeclaration method,
216 MethodBinding methodBinding) {
218 // force the modifiers to be public and abstract
219 methodBinding.modifiers = AccPublic | AccAbstract;
221 this.generateMethodInfoHeader(methodBinding);
222 int methodAttributeOffset = this.contentsOffset;
223 int attributeNumber = this.generateMethodInfoAttribute(methodBinding);
224 this.completeMethodInfo(methodAttributeOffset, attributeNumber);
229 * This methods generate all the attributes for the receiver.
230 * For a class they could be:
231 * - source file attribute
232 * - inner classes attribute
233 * - deprecated attribute
235 public void addAttributes() {
236 // update the method count
237 contents[methodCountOffset++] = (byte) (methodCount >> 8);
238 contents[methodCountOffset] = (byte) methodCount;
240 int attributeNumber = 0;
241 // leave two bytes for the number of attributes and store the current offset
242 int attributeOffset = contentsOffset;
247 if ((produceDebugAttributes & CompilerOptions.Source) != 0) {
248 String fullFileName =
249 new String(referenceBinding.scope.referenceCompilationUnit().getFileName());
250 fullFileName = fullFileName.replace('\\', '/');
251 int lastIndex = fullFileName.lastIndexOf('/');
252 if (lastIndex != -1) {
253 fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length());
255 // check that there is enough space to write all the bytes for the field info corresponding
256 // to the @fieldBinding
257 if (contentsOffset + 8 >= (contentsLength = contents.length)) {
261 (contents = new byte[contentsLength + INCREMENT_SIZE]),
265 int sourceAttributeNameIndex =
266 constantPool.literalIndex(AttributeNamesConstants.SourceName);
267 contents[contentsOffset++] = (byte) (sourceAttributeNameIndex >> 8);
268 contents[contentsOffset++] = (byte) sourceAttributeNameIndex;
269 // The length of a source file attribute is 2. This is a fixed-length
271 contents[contentsOffset++] = 0;
272 contents[contentsOffset++] = 0;
273 contents[contentsOffset++] = 0;
274 contents[contentsOffset++] = 2;
275 // write the source file name
276 int fileNameIndex = constantPool.literalIndex(fullFileName.toCharArray());
277 contents[contentsOffset++] = (byte) (fileNameIndex >> 8);
278 contents[contentsOffset++] = (byte) fileNameIndex;
281 // Deprecated attribute
282 if (referenceBinding.isDeprecated()) {
283 // check that there is enough space to write all the bytes for the field info corresponding
284 // to the @fieldBinding
285 if (contentsOffset + 6 >= (contentsLength = contents.length)) {
289 (contents = new byte[contentsLength + INCREMENT_SIZE]),
293 int deprecatedAttributeNameIndex =
294 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
295 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
296 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
297 // the length of a deprecated attribute is equals to 0
298 contents[contentsOffset++] = 0;
299 contents[contentsOffset++] = 0;
300 contents[contentsOffset++] = 0;
301 contents[contentsOffset++] = 0;
304 // Inner class attribute
305 if (numberOfInnerClasses != 0) {
306 // Generate the inner class attribute
308 if (contentsOffset + (exSize = (8 * numberOfInnerClasses + 8))
309 >= (contentsLength = contents.length)) {
314 new byte[contentsLength
315 + (exSize >= INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
319 // Now we now the size of the attribute and the number of entries
321 int attributeNameIndex =
322 constantPool.literalIndex(AttributeNamesConstants.InnerClassName);
323 contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
324 contents[contentsOffset++] = (byte) attributeNameIndex;
325 int value = (numberOfInnerClasses << 3) + 2;
326 contents[contentsOffset++] = (byte) (value >> 24);
327 contents[contentsOffset++] = (byte) (value >> 16);
328 contents[contentsOffset++] = (byte) (value >> 8);
329 contents[contentsOffset++] = (byte) value;
330 contents[contentsOffset++] = (byte) (numberOfInnerClasses >> 8);
331 contents[contentsOffset++] = (byte) numberOfInnerClasses;
332 for (int i = 0; i < numberOfInnerClasses; i++) {
333 ReferenceBinding innerClass = innerClassesBindings[i];
334 int accessFlags = innerClass.getAccessFlags();
335 int innerClassIndex = constantPool.literalIndex(innerClass);
337 contents[contentsOffset++] = (byte) (innerClassIndex >> 8);
338 contents[contentsOffset++] = (byte) innerClassIndex;
339 // outer class index: anonymous and local have no outer class index
340 if (innerClass.isMemberType()) {
341 // member or member of local
342 int outerClassIndex = constantPool.literalIndex(innerClass.enclosingType());
343 contents[contentsOffset++] = (byte) (outerClassIndex >> 8);
344 contents[contentsOffset++] = (byte) outerClassIndex;
346 // equals to 0 if the innerClass is not a member type
347 contents[contentsOffset++] = 0;
348 contents[contentsOffset++] = 0;
351 if (!innerClass.isAnonymousType()) {
352 int nameIndex = constantPool.literalIndex(innerClass.sourceName());
353 contents[contentsOffset++] = (byte) (nameIndex >> 8);
354 contents[contentsOffset++] = (byte) nameIndex;
356 // equals to 0 if the innerClass is an anonymous type
357 contents[contentsOffset++] = 0;
358 contents[contentsOffset++] = 0;
361 if (innerClass.isAnonymousType()) {
362 accessFlags |= AccPrivate;
364 if (innerClass.isLocalType() && !innerClass.isMemberType()) {
365 accessFlags |= AccPrivate;
367 contents[contentsOffset++] = (byte) (accessFlags >> 8);
368 contents[contentsOffset++] = (byte) accessFlags;
372 // update the number of attributes
373 contentsLength = contents.length;
374 if (attributeOffset + 2 >= contentsLength) {
378 (contents = new byte[contentsLength + INCREMENT_SIZE]),
382 contents[attributeOffset++] = (byte) (attributeNumber >> 8);
383 contents[attributeOffset] = (byte) attributeNumber;
385 // resynchronize all offsets of the classfile
386 header = constantPool.poolContent;
387 headerOffset = constantPool.currentOffset;
388 int constantPoolCount = constantPool.currentIndex;
389 header[constantPoolOffset++] = (byte) (constantPoolCount >> 8);
390 header[constantPoolOffset] = (byte) constantPoolCount;
395 * This methods generate all the default abstract method infos that correpond to
396 * the abstract methods inherited from superinterfaces.
398 public void addDefaultAbstractMethods() { // default abstract methods
399 MethodBinding[] defaultAbstractMethods =
400 referenceBinding.getDefaultAbstractMethods();
401 for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
402 generateMethodInfoHeader(defaultAbstractMethods[i]);
403 int methodAttributeOffset = contentsOffset;
404 int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
405 completeMethodInfo(methodAttributeOffset, attributeNumber);
411 * This methods generates the bytes for the field binding passed like a parameter
412 * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding
414 public void addFieldInfo(FieldBinding fieldBinding) {
415 int attributeNumber = 0;
416 // check that there is enough space to write all the bytes for the field info corresponding
417 // to the @fieldBinding
419 if (contentsOffset + 30 >= (contentsLength = contents.length)) {
423 (contents = new byte[contentsLength + INCREMENT_SIZE]),
427 // Generate two attribute: constantValueAttribute and SyntheticAttribute
428 // Now we can generate all entries into the byte array
429 // First the accessFlags
430 int accessFlags = fieldBinding.getAccessFlags();
431 contents[contentsOffset++] = (byte) (accessFlags >> 8);
432 contents[contentsOffset++] = (byte) accessFlags;
433 // Then the nameIndex
434 int nameIndex = constantPool.literalIndex(fieldBinding.name);
435 contents[contentsOffset++] = (byte) (nameIndex >> 8);
436 contents[contentsOffset++] = (byte) nameIndex;
437 // Then the descriptorIndex
438 int descriptorIndex = constantPool.literalIndex(fieldBinding.type.signature());
439 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
440 contents[contentsOffset++] = (byte) descriptorIndex;
441 // leave some space for the number of attributes
442 int fieldAttributeOffset = contentsOffset;
444 // 4.7.2 only static constant fields get a ConstantAttribute
445 if (fieldBinding.constant != Constant.NotAConstant
446 && fieldBinding.constant.typeID() != T_null) {
447 // Now we generate the constant attribute corresponding to the fieldBinding
448 int constantValueNameIndex =
449 constantPool.literalIndex(AttributeNamesConstants.ConstantValueName);
450 contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
451 contents[contentsOffset++] = (byte) constantValueNameIndex;
452 // The attribute length = 2 in case of a constantValue attribute
453 contents[contentsOffset++] = 0;
454 contents[contentsOffset++] = 0;
455 contents[contentsOffset++] = 0;
456 contents[contentsOffset++] = 2;
458 // Need to add the constant_value_index
459 switch (fieldBinding.constant.typeID()) {
461 int booleanValueIndex =
462 constantPool.literalIndex(fieldBinding.constant.booleanValue() ? 1 : 0);
463 contents[contentsOffset++] = (byte) (booleanValueIndex >> 8);
464 contents[contentsOffset++] = (byte) booleanValueIndex;
470 int integerValueIndex =
471 constantPool.literalIndex(fieldBinding.constant.intValue());
472 contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
473 contents[contentsOffset++] = (byte) integerValueIndex;
476 int floatValueIndex =
477 constantPool.literalIndex(fieldBinding.constant.floatValue());
478 contents[contentsOffset++] = (byte) (floatValueIndex >> 8);
479 contents[contentsOffset++] = (byte) floatValueIndex;
482 int doubleValueIndex =
483 constantPool.literalIndex(fieldBinding.constant.doubleValue());
484 contents[contentsOffset++] = (byte) (doubleValueIndex >> 8);
485 contents[contentsOffset++] = (byte) doubleValueIndex;
489 constantPool.literalIndex(fieldBinding.constant.longValue());
490 contents[contentsOffset++] = (byte) (longValueIndex >> 8);
491 contents[contentsOffset++] = (byte) longValueIndex;
494 int stringValueIndex =
495 constantPool.literalIndex(
496 ((StringConstant) fieldBinding.constant).stringValue());
497 if (stringValueIndex == -1) {
498 if (!creatingProblemType) {
499 // report an error and abort: will lead to a problem type classfile creation
500 TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
501 FieldDeclaration[] fieldDecls = typeDeclaration.fields;
502 for (int i = 0, max = fieldDecls.length; i < max; i++) {
503 if (fieldDecls[i].binding == fieldBinding) {
504 // problem should abort
505 typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(
510 // already inside a problem type creation : no constant for this field
511 contentsOffset = fieldAttributeOffset + 2;
512 // +2 is necessary to keep the two byte space for the attribute number
516 contents[contentsOffset++] = (byte) (stringValueIndex >> 8);
517 contents[contentsOffset++] = (byte) stringValueIndex;
521 if (fieldBinding.isSynthetic()) {
522 int syntheticAttributeNameIndex =
523 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
524 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
525 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
526 // the length of a synthetic attribute is equals to 0
527 contents[contentsOffset++] = 0;
528 contents[contentsOffset++] = 0;
529 contents[contentsOffset++] = 0;
530 contents[contentsOffset++] = 0;
533 if (fieldBinding.isDeprecated()) {
534 int deprecatedAttributeNameIndex =
535 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
536 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
537 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
538 // the length of a deprecated attribute is equals to 0
539 contents[contentsOffset++] = 0;
540 contents[contentsOffset++] = 0;
541 contents[contentsOffset++] = 0;
542 contents[contentsOffset++] = 0;
545 contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8);
546 contents[fieldAttributeOffset] = (byte) attributeNumber;
551 * This methods generate all the fields infos for the receiver.
553 * - a field info for each defined field of that class
554 * - a field info for each synthetic field (e.g. this$0)
556 public void addFieldInfos() {
557 SourceTypeBinding currentBinding = referenceBinding;
558 FieldBinding[] syntheticFields = currentBinding.syntheticFields();
560 currentBinding.fieldCount()
561 + (syntheticFields == null ? 0 : syntheticFields.length);
563 // write the number of fields
564 contents[contentsOffset++] = (byte) (fieldCount >> 8);
565 contents[contentsOffset++] = (byte) fieldCount;
567 FieldBinding[] fieldBindings = currentBinding.fields();
568 for (int i = 0, max = fieldBindings.length; i < max; i++) {
569 addFieldInfo(fieldBindings[i]);
571 if (syntheticFields != null) {
572 for (int i = 0, max = syntheticFields.length; i < max; i++) {
573 addFieldInfo(syntheticFields[i]);
580 * This methods stores the bindings for each inner class. They will be used to know which entries
581 * have to be generated for the inner classes attributes.
582 * @param referenceBinding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
584 public void addInnerClasses(ReferenceBinding referenceBinding) {
585 // check first if that reference binding is there
586 for (int i = 0; i < numberOfInnerClasses; i++) {
587 if (innerClassesBindings[i] == referenceBinding)
590 int length = innerClassesBindings.length;
591 if (numberOfInnerClasses == length) {
593 innerClassesBindings,
595 (innerClassesBindings = new ReferenceBinding[length * 2]),
599 innerClassesBindings[numberOfInnerClasses++] = referenceBinding;
604 * Generate the byte for a problem clinit method info that correspond to a boggus method.
606 * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
608 public void addProblemClinit(IProblem[] problems) {
609 generateMethodInfoHeaderForClinit();
610 // leave two spaces for the number of attributes
612 int attributeOffset = contentsOffset;
614 int attributeNumber = 0;
616 int codeAttributeOffset = contentsOffset;
617 generateCodeAttributeHeader();
618 codeStream.resetForProblemClinit(this);
619 String problemString = "" ; //$NON-NLS-1$
620 if (problems != null) {
621 int max = problems.length;
622 StringBuffer buffer = new StringBuffer(25);
624 for (int i = 0; i < max; i++) {
625 IProblem problem = problems[i];
626 if ((problem != null) && (problem.isError())) {
627 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
629 if (problemLine == 0) {
630 problemLine = problem.getSourceLineNumber();
634 } // insert the top line afterwards, once knowing how many problems we have to consider
636 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
638 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
640 problemString = buffer.toString();
643 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
644 int[] exceptionHandler =
645 codeStream.generateCodeAttributeForProblemMethod(
650 .runtimeExceptionNameForCompileError,
652 attributeNumber++; // code attribute
653 completeCodeAttributeForClinit(
658 .referenceCompilationUnit()
660 .lineSeparatorPositions);
661 contents[attributeOffset++] = (byte) (attributeNumber >> 8);
662 contents[attributeOffset] = (byte) attributeNumber;
667 * Generate the byte for a problem method info that correspond to a boggus constructor.
669 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
670 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
671 * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
673 public void addProblemConstructor(
674 AbstractMethodDeclaration method,
675 MethodBinding methodBinding,
676 IProblem[] problems) {
678 // always clear the strictfp/native/abstract bit for a problem method
679 methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
681 generateMethodInfoHeader(methodBinding);
682 int methodAttributeOffset = contentsOffset;
683 int attributeNumber = generateMethodInfoAttribute(methodBinding);
687 int codeAttributeOffset = contentsOffset;
688 generateCodeAttributeHeader();
689 final ProblemReporter problemReporter = method.scope.problemReporter();
690 codeStream.reset(method, this);
691 String problemString = "" ; //$NON-NLS-1$
692 if (problems != null) {
693 int max = problems.length;
694 StringBuffer buffer = new StringBuffer(25);
696 for (int i = 0; i < max; i++) {
697 IProblem problem = problems[i];
698 if ((problem != null) && (problem.isError())) {
699 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
701 if (problemLine == 0) {
702 problemLine = problem.getSourceLineNumber();
705 } // insert the top line afterwards, once knowing how many problems we have to consider
707 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
709 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
711 problemString = buffer.toString();
714 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
715 int[] exceptionHandler =
716 codeStream.generateCodeAttributeForProblemMethod(
717 problemReporter.options.runtimeExceptionNameForCompileError,
719 completeCodeAttributeForProblemMethod(
724 ((SourceTypeBinding) methodBinding.declaringClass)
726 .referenceCompilationUnit()
728 .lineSeparatorPositions);
729 completeMethodInfo(methodAttributeOffset, attributeNumber);
734 * Generate the byte for a problem method info that correspond to a boggus constructor.
735 * Reset the position inside the contents byte array to the savedOffset.
737 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
738 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
739 * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
740 * @param savedOffset <CODE>int</CODE>
742 public void addProblemConstructor(
743 AbstractMethodDeclaration method,
744 MethodBinding methodBinding,
747 // we need to move back the contentsOffset to the value at the beginning of the method
748 contentsOffset = savedOffset;
749 methodCount--; // we need to remove the method that causes the problem
750 addProblemConstructor(method, methodBinding, problems);
755 * Generate the byte for a problem method info that correspond to a boggus method.
757 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
758 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
759 * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
761 public void addProblemMethod(
762 AbstractMethodDeclaration method,
763 MethodBinding methodBinding,
764 IProblem[] problems) {
765 if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) {
766 method.abort(AbstractMethodDeclaration.AbortType);
768 // always clear the strictfp/native/abstract bit for a problem method
769 methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
771 generateMethodInfoHeader(methodBinding);
772 int methodAttributeOffset = contentsOffset;
773 int attributeNumber = generateMethodInfoAttribute(methodBinding);
778 int codeAttributeOffset = contentsOffset;
779 generateCodeAttributeHeader();
780 final ProblemReporter problemReporter = method.scope.problemReporter();
781 codeStream.reset(method, this);
782 String problemString = "" ; //$NON-NLS-1$
783 if (problems != null) {
784 int max = problems.length;
785 StringBuffer buffer = new StringBuffer(25);
787 for (int i = 0; i < max; i++) {
788 IProblem problem = problems[i];
789 if ((problem != null)
790 && (problem.isError())
791 && (problem.getSourceStart() >= method.declarationSourceStart)
792 && (problem.getSourceEnd() <= method.declarationSourceEnd)) {
793 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
795 if (problemLine == 0) {
796 problemLine = problem.getSourceLineNumber();
800 } // insert the top line afterwards, once knowing how many problems we have to consider
802 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
804 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
806 problemString = buffer.toString();
809 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
810 int[] exceptionHandler =
811 codeStream.generateCodeAttributeForProblemMethod(
812 problemReporter.options.runtimeExceptionNameForCompileError,
814 completeCodeAttributeForProblemMethod(
819 ((SourceTypeBinding) methodBinding.declaringClass)
821 .referenceCompilationUnit()
823 .lineSeparatorPositions);
824 completeMethodInfo(methodAttributeOffset, attributeNumber);
829 * Generate the byte for a problem method info that correspond to a boggus method.
830 * Reset the position inside the contents byte array to the savedOffset.
832 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
833 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
834 * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
835 * @param savedOffset <CODE>int</CODE>
837 public void addProblemMethod(
838 AbstractMethodDeclaration method,
839 MethodBinding methodBinding,
842 // we need to move back the contentsOffset to the value at the beginning of the method
843 contentsOffset = savedOffset;
844 methodCount--; // we need to remove the method that causes the problem
845 addProblemMethod(method, methodBinding, problems);
850 * Generate the byte for all the special method infos.
852 * - synthetic access methods
853 * - default abstract methods
855 public void addSpecialMethods() {
856 // add all methods (default abstract methods and synthetic)
858 // default abstract methods
859 SourceTypeBinding currentBinding = referenceBinding;
860 MethodBinding[] defaultAbstractMethods =
861 currentBinding.getDefaultAbstractMethods();
862 for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
863 generateMethodInfoHeader(defaultAbstractMethods[i]);
864 int methodAttributeOffset = contentsOffset;
865 int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
866 completeMethodInfo(methodAttributeOffset, attributeNumber);
868 // add synthetic methods infos
869 SyntheticAccessMethodBinding[] syntheticAccessMethods =
870 currentBinding.syntheticAccessMethods();
871 if (syntheticAccessMethods != null) {
872 for (int i = 0, max = syntheticAccessMethods.length; i < max; i++) {
873 SyntheticAccessMethodBinding accessMethodBinding = syntheticAccessMethods[i];
874 switch (accessMethodBinding.accessType) {
875 case SyntheticAccessMethodBinding.FieldReadAccess :
876 // generate a method info to emulate an reading access to
878 addSyntheticFieldReadAccessMethod(syntheticAccessMethods[i]);
880 case SyntheticAccessMethodBinding.FieldWriteAccess :
881 // generate a method info to emulate an writing access to
883 addSyntheticFieldWriteAccessMethod(syntheticAccessMethods[i]);
885 case SyntheticAccessMethodBinding.MethodAccess :
886 // generate a method info to emulate an access to a private method
887 addSyntheticMethodAccessMethod(syntheticAccessMethods[i]);
889 case SyntheticAccessMethodBinding.ConstructorAccess :
890 // generate a method info to emulate an access to a private method
891 addSyntheticConstructorAccessMethod(syntheticAccessMethods[i]);
899 * Generate the byte for problem method infos that correspond to missing abstract methods.
900 * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179
902 * @param methodDeclarations Array of all missing abstract methods
904 public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) {
905 if (methodDeclarations != null) {
906 for (int i = 0, max = methodDeclarations.length; i < max; i++) {
907 MethodDeclaration methodDeclaration = methodDeclarations[i];
908 MethodBinding methodBinding = methodDeclaration.binding;
909 String readableName = new String(methodBinding.readableName());
910 IProblem[] problems = compilationResult.problems;
911 int problemsCount = compilationResult.problemCount;
912 for (int j = 0; j < problemsCount; j++) {
913 IProblem problem = problems[j];
915 && problem.getID() == IProblem.AbstractMethodMustBeImplemented
916 && problem.getMessage().indexOf(readableName) != -1) {
918 addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult);
925 private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, IProblem problem, CompilationResult compilationResult) {
926 // always clear the strictfp/native/abstract bit for a problem method
927 methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
929 generateMethodInfoHeader(methodBinding);
930 int methodAttributeOffset = contentsOffset;
931 int attributeNumber = generateMethodInfoAttribute(methodBinding);
936 int codeAttributeOffset = contentsOffset;
937 generateCodeAttributeHeader();
938 StringBuffer buffer = new StringBuffer(25);
939 buffer.append("\t" + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
940 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
941 String problemString = buffer.toString();
942 this.problemLine = problem.getSourceLineNumber();
944 final ProblemReporter problemReporter = methodDeclaration.scope.problemReporter();
945 codeStream.init(this);
946 codeStream.preserveUnusedLocals = true;
947 codeStream.initializeMaxLocals(methodBinding);
949 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
950 int[] exceptionHandler =
951 codeStream.generateCodeAttributeForProblemMethod(
952 problemReporter.options.runtimeExceptionNameForCompileError,
955 completeCodeAttributeForMissingAbstractProblemMethod(
959 compilationResult.lineSeparatorPositions);
961 completeMethodInfo(methodAttributeOffset, attributeNumber);
967 public void completeCodeAttributeForMissingAbstractProblemMethod(
968 MethodBinding binding,
969 int codeAttributeOffset,
970 int[] exceptionHandler,
971 int[] startLineIndexes) {
972 // reinitialize the localContents with the byte modified by the code stream
973 byte[] localContents = contents = codeStream.bCodeStream;
974 int localContentsOffset = codeStream.classFileOffset;
975 // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
976 int max_stack = codeStream.stackMax;
977 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
978 localContents[codeAttributeOffset + 7] = (byte) max_stack;
979 int max_locals = codeStream.maxLocals;
980 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
981 localContents[codeAttributeOffset + 9] = (byte) max_locals;
982 int code_length = codeStream.position;
983 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
984 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
985 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
986 localContents[codeAttributeOffset + 13] = (byte) code_length;
987 // write the exception table
989 if (localContentsOffset + 50 >= (contentsLength = localContents.length)) {
993 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
997 localContents[localContentsOffset++] = 0;
998 localContents[localContentsOffset++] = 1;
999 int start = exceptionHandler[0];
1000 localContents[localContentsOffset++] = (byte) (start >> 8);
1001 localContents[localContentsOffset++] = (byte) start;
1002 int end = exceptionHandler[1];
1003 localContents[localContentsOffset++] = (byte) (end >> 8);
1004 localContents[localContentsOffset++] = (byte) end;
1005 int handlerPC = exceptionHandler[2];
1006 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1007 localContents[localContentsOffset++] = (byte) handlerPC;
1008 int nameIndex = constantPool.literalIndexForJavaLangException();
1009 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1010 localContents[localContentsOffset++] = (byte) nameIndex; // debug attributes
1011 int codeAttributeAttributeOffset = localContentsOffset;
1012 int attributeNumber = 0; // leave two bytes for the attribute_length
1013 localContentsOffset += 2; // first we handle the linenumber attribute
1015 if (codeStream.generateLineNumberAttributes) {
1016 /* Create and add the line number attribute (used for debugging)
1017 * Build the pairs of:
1018 * (bytecodePC lineNumber)
1019 * according to the table of start line indexes and the pcToSourceMap table
1020 * contained into the codestream
1022 int lineNumberNameIndex =
1023 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1024 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1025 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1026 localContents[localContentsOffset++] = 0;
1027 localContents[localContentsOffset++] = 0;
1028 localContents[localContentsOffset++] = 0;
1029 localContents[localContentsOffset++] = 6;
1030 localContents[localContentsOffset++] = 0;
1031 localContents[localContentsOffset++] = 1;
1032 if (problemLine == 0) {
1033 problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
1035 // first entry at pc = 0
1036 localContents[localContentsOffset++] = 0;
1037 localContents[localContentsOffset++] = 0;
1038 localContents[localContentsOffset++] = (byte) (problemLine >> 8);
1039 localContents[localContentsOffset++] = (byte) problemLine;
1040 // now we change the size of the line number attribute
1044 // then we do the local variable attribute
1045 // update the number of attributes// ensure first that there is enough space available inside the localContents array
1046 if (codeAttributeAttributeOffset + 2
1047 >= (contentsLength = localContents.length)) {
1051 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1055 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1056 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1057 // update the attribute length
1058 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1059 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1060 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1061 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1062 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1063 contentsOffset = localContentsOffset;
1068 * Generate the byte for a problem method info that correspond to a synthetic method that
1069 * generate an access to a private constructor.
1071 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1073 public void addSyntheticConstructorAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1074 generateMethodInfoHeader(methodBinding);
1075 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1076 contents[contentsOffset++] = 0;
1077 contents[contentsOffset++] = 2;
1079 int codeAttributeOffset = contentsOffset;
1080 generateCodeAttributeHeader();
1081 codeStream.init(this);
1082 codeStream.generateSyntheticBodyForConstructorAccess(methodBinding);
1083 completeCodeAttributeForSyntheticAccessMethod(
1085 codeAttributeOffset,
1086 ((SourceTypeBinding) methodBinding.declaringClass)
1088 .referenceCompilationUnit()
1090 .lineSeparatorPositions);
1091 // add the synthetic attribute
1092 int syntheticAttributeNameIndex =
1093 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1094 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1095 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1096 // the length of a synthetic attribute is equals to 0
1097 contents[contentsOffset++] = 0;
1098 contents[contentsOffset++] = 0;
1099 contents[contentsOffset++] = 0;
1100 contents[contentsOffset++] = 0;
1105 * Generate the byte for a problem method info that correspond to a synthetic method that
1106 * generate an read access to a private field.
1108 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1110 public void addSyntheticFieldReadAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1111 generateMethodInfoHeader(methodBinding);
1112 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1113 contents[contentsOffset++] = 0;
1114 contents[contentsOffset++] = 2;
1116 int codeAttributeOffset = contentsOffset;
1117 generateCodeAttributeHeader();
1118 codeStream.init(this);
1119 codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding);
1120 completeCodeAttributeForSyntheticAccessMethod(
1122 codeAttributeOffset,
1123 ((SourceTypeBinding) methodBinding.declaringClass)
1125 .referenceCompilationUnit()
1127 .lineSeparatorPositions);
1128 // add the synthetic attribute
1129 int syntheticAttributeNameIndex =
1130 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1131 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1132 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1133 // the length of a synthetic attribute is equals to 0
1134 contents[contentsOffset++] = 0;
1135 contents[contentsOffset++] = 0;
1136 contents[contentsOffset++] = 0;
1137 contents[contentsOffset++] = 0;
1142 * Generate the byte for a problem method info that correspond to a synthetic method that
1143 * generate an write access to a private field.
1145 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1147 public void addSyntheticFieldWriteAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1148 generateMethodInfoHeader(methodBinding);
1149 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1150 contents[contentsOffset++] = 0;
1151 contents[contentsOffset++] = 2;
1153 int codeAttributeOffset = contentsOffset;
1154 generateCodeAttributeHeader();
1155 codeStream.init(this);
1156 codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding);
1157 completeCodeAttributeForSyntheticAccessMethod(
1159 codeAttributeOffset,
1160 ((SourceTypeBinding) methodBinding.declaringClass)
1162 .referenceCompilationUnit()
1164 .lineSeparatorPositions);
1165 // add the synthetic attribute
1166 int syntheticAttributeNameIndex =
1167 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1168 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1169 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1170 // the length of a synthetic attribute is equals to 0
1171 contents[contentsOffset++] = 0;
1172 contents[contentsOffset++] = 0;
1173 contents[contentsOffset++] = 0;
1174 contents[contentsOffset++] = 0;
1179 * Generate the byte for a problem method info that correspond to a synthetic method that
1180 * generate an access to a private method.
1182 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1184 public void addSyntheticMethodAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1185 generateMethodInfoHeader(methodBinding);
1186 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1187 contents[contentsOffset++] = 0;
1188 contents[contentsOffset++] = 2;
1190 int codeAttributeOffset = contentsOffset;
1191 generateCodeAttributeHeader();
1192 codeStream.init(this);
1193 codeStream.generateSyntheticBodyForMethodAccess(methodBinding);
1194 completeCodeAttributeForSyntheticAccessMethod(
1196 codeAttributeOffset,
1197 ((SourceTypeBinding) methodBinding.declaringClass)
1199 .referenceCompilationUnit()
1201 .lineSeparatorPositions);
1202 // add the synthetic attribute
1203 int syntheticAttributeNameIndex =
1204 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1205 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1206 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1207 // the length of a synthetic attribute is equals to 0
1208 contents[contentsOffset++] = 0;
1209 contents[contentsOffset++] = 0;
1210 contents[contentsOffset++] = 0;
1211 contents[contentsOffset++] = 0;
1216 * Build all the directories and subdirectories corresponding to the packages names
1217 * into the directory specified in parameters.
1219 * outputPath is formed like:
1220 * c:\temp\ the last character is a file separator
1221 * relativeFileName is formed like:
1222 * java\lang\String.class *
1224 * @param outputPath java.lang.String
1225 * @param relativeFileName java.lang.String
1226 * @return java.lang.String
1228 public static String buildAllDirectoriesInto(
1230 String relativeFileName)
1231 throws IOException {
1232 char fileSeparatorChar = File.separatorChar;
1233 String fileSeparator = File.separator;
1235 // First we ensure that the outputPath exists
1236 outputPath = outputPath.replace('/', fileSeparatorChar);
1237 // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
1238 if (outputPath.endsWith(fileSeparator)) {
1239 outputPath = outputPath.substring(0, outputPath.length() - 1);
1241 f = new File(outputPath);
1243 if (!f.isDirectory()) {
1244 System.out.println(Util.bind("output.isFile" , f.getAbsolutePath())); //$NON-NLS-1$
1245 throw new IOException(Util.bind("output.isFileNotDirectory" )); //$NON-NLS-1$
1248 // we have to create that directory
1250 System.out.println(Util.bind("output.dirName" , f.getAbsolutePath())); //$NON-NLS-1$
1251 throw new IOException(Util.bind("output.notValidAll" )); //$NON-NLS-1$
1254 StringBuffer outDir = new StringBuffer(outputPath);
1255 outDir.append(fileSeparator);
1256 StringTokenizer tokenizer =
1257 new StringTokenizer(relativeFileName, fileSeparator);
1258 String token = tokenizer.nextToken();
1259 while (tokenizer.hasMoreTokens()) {
1260 f = new File(outDir.append(token).append(fileSeparator).toString());
1262 // The outDir already exists, so we proceed the next entry
1263 // System.out.println("outDir: " + outDir + " already exists.");
1265 // Need to add the outDir
1267 System.out.println(Util.bind("output.fileName" , f.getName())); //$NON-NLS-1$
1268 throw new IOException(Util.bind("output.notValid" )); //$NON-NLS-1$
1271 token = tokenizer.nextToken();
1273 // token contains the last one
1274 return outDir.append(token).toString();
1279 * That method completes the creation of the code attribute by setting
1280 * - the attribute_length
1285 * - and debug attributes if necessary.
1287 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1288 * @param codeAttributeOffset <CODE>int</CODE>
1290 public void completeCodeAttribute(int codeAttributeOffset) {
1291 // reinitialize the localContents with the byte modified by the code stream
1292 byte[] localContents = contents = codeStream.bCodeStream;
1293 int localContentsOffset = codeStream.classFileOffset;
1294 // codeAttributeOffset is the position inside localContents byte array before we started to write
1295 // any information about the codeAttribute
1296 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1297 // to get the right position, 6 for the max_stack etc...
1299 int code_length = codeStream.position;
1300 if (code_length > 65535) {
1301 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1302 codeStream.methodDeclaration);
1304 if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
1308 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1312 int max_stack = codeStream.stackMax;
1313 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1314 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1315 int max_locals = codeStream.maxLocals;
1316 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1317 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1318 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1319 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1320 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1321 localContents[codeAttributeOffset + 13] = (byte) code_length;
1323 // write the exception table
1324 int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
1325 ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
1327 if (localContentsOffset + (exSize = (exceptionHandlersNumber * 8 + 2))
1328 >= (contentsLength = localContents.length)) {
1334 new byte[contentsLength + (exSize > INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
1338 // there is no exception table, so we need to offset by 2 the current offset and move
1339 // on the attribute generation
1340 localContents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
1341 localContents[localContentsOffset++] = (byte) exceptionHandlersNumber;
1342 for (int i = 0; i < exceptionHandlersNumber; i++) {
1343 ExceptionLabel exceptionHandler = exceptionHandlers[i];
1344 int start = exceptionHandler.start;
1345 localContents[localContentsOffset++] = (byte) (start >> 8);
1346 localContents[localContentsOffset++] = (byte) start;
1347 int end = exceptionHandler.end;
1348 localContents[localContentsOffset++] = (byte) (end >> 8);
1349 localContents[localContentsOffset++] = (byte) end;
1350 int handlerPC = exceptionHandler.position;
1351 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1352 localContents[localContentsOffset++] = (byte) handlerPC;
1353 if (exceptionHandler.exceptionType == null) {
1354 // any exception handler
1355 localContents[localContentsOffset++] = 0;
1356 localContents[localContentsOffset++] = 0;
1359 if (exceptionHandler.exceptionType == TypeBinding.NullBinding) {
1360 /* represents ClassNotFoundException, see class literal access*/
1361 nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
1363 nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
1365 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1366 localContents[localContentsOffset++] = (byte) nameIndex;
1370 int codeAttributeAttributeOffset = localContentsOffset;
1371 int attributeNumber = 0;
1372 // leave two bytes for the attribute_length
1373 localContentsOffset += 2;
1375 // first we handle the linenumber attribute
1376 if (codeStream.generateLineNumberAttributes) {
1377 /* Create and add the line number attribute (used for debugging)
1378 * Build the pairs of:
1379 * (bytecodePC lineNumber)
1380 * according to the table of start line indexes and the pcToSourceMap table
1381 * contained into the codestream
1383 int[] pcToSourceMapTable;
1384 if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
1385 && (codeStream.pcToSourceMapSize != 0)) {
1386 int lineNumberNameIndex =
1387 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1388 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1392 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1396 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1397 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1398 int lineNumberTableOffset = localContentsOffset;
1399 localContentsOffset += 6;
1400 // leave space for attribute_length and line_number_table_length
1401 int numberOfEntries = 0;
1402 int length = codeStream.pcToSourceMapSize;
1403 for (int i = 0; i < length;) {
1405 if (localContentsOffset + 4 >= (contentsLength = localContents.length)) {
1409 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1413 int pc = pcToSourceMapTable[i++];
1414 localContents[localContentsOffset++] = (byte) (pc >> 8);
1415 localContents[localContentsOffset++] = (byte) pc;
1416 int lineNumber = pcToSourceMapTable[i++];
1417 localContents[localContentsOffset++] = (byte) (lineNumber >> 8);
1418 localContents[localContentsOffset++] = (byte) lineNumber;
1421 // now we change the size of the line number attribute
1422 int lineNumberAttr_length = numberOfEntries * 4 + 2;
1423 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
1424 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
1425 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
1426 localContents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
1427 localContents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
1428 localContents[lineNumberTableOffset++] = (byte) numberOfEntries;
1432 // then we do the local variable attribute
1433 if (codeStream.generateLocalVariableTableAttributes) {
1434 int localVariableTableOffset = localContentsOffset;
1435 int numberOfEntries = 0;
1436 int localVariableNameIndex =
1437 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1438 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1442 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1446 localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1447 localContents[localContentsOffset++] = (byte) localVariableNameIndex;
1448 localContentsOffset += 6;
1449 // leave space for attribute_length and local_variable_table_length
1451 int descriptorIndex;
1452 if (!codeStream.methodDeclaration.isStatic()) {
1454 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
1458 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1462 localContentsOffset += 2; // the startPC for this is always 0
1463 localContents[localContentsOffset++] = (byte) (code_length >> 8);
1464 localContents[localContentsOffset++] = (byte) code_length;
1465 nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
1466 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1467 localContents[localContentsOffset++] = (byte) nameIndex;
1469 constantPool.literalIndex(
1470 codeStream.methodDeclaration.binding.declaringClass.signature());
1471 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1472 localContents[localContentsOffset++] = (byte) descriptorIndex;
1473 localContentsOffset += 2; // the resolved position for this is always 0
1475 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
1476 LocalVariableBinding localVariable = codeStream.locals[i];
1477 for (int j = 0; j < localVariable.initializationCount; j++) {
1478 int startPC = localVariable.initializationPCs[j << 1];
1479 int endPC = localVariable.initializationPCs[(j << 1) + 1];
1480 if (startPC != endPC) { // only entries for non zero length
1482 localVariable.declaringScope.problemReporter().abortDueToInternalError(
1483 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
1484 (AstNode) localVariable.declaringScope.methodScope().referenceContext);
1486 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
1490 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1494 // now we can safely add the local entry
1496 localContents[localContentsOffset++] = (byte) (startPC >> 8);
1497 localContents[localContentsOffset++] = (byte) startPC;
1498 int length = endPC - startPC;
1499 localContents[localContentsOffset++] = (byte) (length >> 8);
1500 localContents[localContentsOffset++] = (byte) length;
1501 nameIndex = constantPool.literalIndex(localVariable.name);
1502 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1503 localContents[localContentsOffset++] = (byte) nameIndex;
1504 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
1505 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1506 localContents[localContentsOffset++] = (byte) descriptorIndex;
1507 int resolvedPosition = localVariable.resolvedPosition;
1508 localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1509 localContents[localContentsOffset++] = (byte) resolvedPosition;
1513 int value = numberOfEntries * 10 + 2;
1514 localVariableTableOffset += 2;
1515 localContents[localVariableTableOffset++] = (byte) (value >> 24);
1516 localContents[localVariableTableOffset++] = (byte) (value >> 16);
1517 localContents[localVariableTableOffset++] = (byte) (value >> 8);
1518 localContents[localVariableTableOffset++] = (byte) value;
1519 localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1520 localContents[localVariableTableOffset] = (byte) numberOfEntries;
1523 // update the number of attributes
1524 // ensure first that there is enough space available inside the localContents array
1525 if (codeAttributeAttributeOffset + 2
1526 >= (contentsLength = localContents.length)) {
1530 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1534 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1535 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1537 // update the attribute length
1538 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1539 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1540 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1541 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1542 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1543 contentsOffset = localContentsOffset;
1548 * That method completes the creation of the code attribute by setting
1549 * - the attribute_length
1554 * - and debug attributes if necessary.
1556 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1557 * @param codeAttributeOffset <CODE>int</CODE>
1559 public void completeCodeAttributeForClinit(int codeAttributeOffset) {
1560 // reinitialize the contents with the byte modified by the code stream
1561 byte[] localContents = contents = codeStream.bCodeStream;
1562 int localContentsOffset = codeStream.classFileOffset;
1563 // codeAttributeOffset is the position inside contents byte array before we started to write
1564 // any information about the codeAttribute
1565 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1566 // to get the right position, 6 for the max_stack etc...
1568 int code_length = codeStream.position;
1569 if (code_length > 65535) {
1570 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1571 codeStream.methodDeclaration.scope.referenceType());
1573 if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
1577 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1581 int max_stack = codeStream.stackMax;
1582 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1583 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1584 int max_locals = codeStream.maxLocals;
1585 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1586 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1587 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1588 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1589 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1590 localContents[codeAttributeOffset + 13] = (byte) code_length;
1592 // write the exception table
1593 int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
1594 ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
1596 if (localContentsOffset + (exSize = (exceptionHandlersNumber * 8 + 2))
1597 >= (contentsLength = localContents.length)) {
1603 new byte[contentsLength + (exSize > INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
1607 // there is no exception table, so we need to offset by 2 the current offset and move
1608 // on the attribute generation
1609 localContents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
1610 localContents[localContentsOffset++] = (byte) exceptionHandlersNumber;
1611 for (int i = 0; i < exceptionHandlersNumber; i++) {
1612 ExceptionLabel exceptionHandler = exceptionHandlers[i];
1613 int start = exceptionHandler.start;
1614 localContents[localContentsOffset++] = (byte) (start >> 8);
1615 localContents[localContentsOffset++] = (byte) start;
1616 int end = exceptionHandler.end;
1617 localContents[localContentsOffset++] = (byte) (end >> 8);
1618 localContents[localContentsOffset++] = (byte) end;
1619 int handlerPC = exceptionHandler.position;
1620 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1621 localContents[localContentsOffset++] = (byte) handlerPC;
1622 if (exceptionHandler.exceptionType == null) {
1623 // any exception handler
1624 localContentsOffset += 2;
1627 if (exceptionHandler.exceptionType == TypeBinding.NullBinding) {
1628 /* represents denote ClassNotFoundException, see class literal access*/
1629 nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
1631 nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
1633 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1634 localContents[localContentsOffset++] = (byte) nameIndex;
1638 int codeAttributeAttributeOffset = localContentsOffset;
1639 int attributeNumber = 0;
1640 // leave two bytes for the attribute_length
1641 localContentsOffset += 2;
1643 // first we handle the linenumber attribute
1644 if (codeStream.generateLineNumberAttributes) {
1645 /* Create and add the line number attribute (used for debugging)
1646 * Build the pairs of:
1647 * (bytecodePC lineNumber)
1648 * according to the table of start line indexes and the pcToSourceMap table
1649 * contained into the codestream
1651 int[] pcToSourceMapTable;
1652 if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
1653 && (codeStream.pcToSourceMapSize != 0)) {
1654 int lineNumberNameIndex =
1655 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1656 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1660 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1664 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1665 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1666 int lineNumberTableOffset = localContentsOffset;
1667 localContentsOffset += 6;
1668 // leave space for attribute_length and line_number_table_length
1669 int numberOfEntries = 0;
1670 int length = codeStream.pcToSourceMapSize;
1671 for (int i = 0; i < length;) {
1673 if (localContentsOffset + 4 >= (contentsLength = localContents.length)) {
1677 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1681 int pc = pcToSourceMapTable[i++];
1682 localContents[localContentsOffset++] = (byte) (pc >> 8);
1683 localContents[localContentsOffset++] = (byte) pc;
1684 int lineNumber = pcToSourceMapTable[i++];
1685 localContents[localContentsOffset++] = (byte) (lineNumber >> 8);
1686 localContents[localContentsOffset++] = (byte) lineNumber;
1689 // now we change the size of the line number attribute
1690 int lineNumberAttr_length = numberOfEntries * 4 + 2;
1691 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
1692 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
1693 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
1694 localContents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
1695 localContents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
1696 localContents[lineNumberTableOffset++] = (byte) numberOfEntries;
1700 // then we do the local variable attribute
1701 if (codeStream.generateLocalVariableTableAttributes) {
1702 int localVariableTableOffset = localContentsOffset;
1703 int numberOfEntries = 0;
1704 // codeAttribute.addLocalVariableTableAttribute(this);
1705 if ((codeStream.pcToSourceMap != null)
1706 && (codeStream.pcToSourceMapSize != 0)) {
1707 int localVariableNameIndex =
1708 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1709 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1713 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1717 localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1718 localContents[localContentsOffset++] = (byte) localVariableNameIndex;
1719 localContentsOffset += 6;
1720 // leave space for attribute_length and local_variable_table_length
1722 int descriptorIndex;
1723 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
1724 LocalVariableBinding localVariable = codeStream.locals[i];
1725 for (int j = 0; j < localVariable.initializationCount; j++) {
1726 int startPC = localVariable.initializationPCs[j << 1];
1727 int endPC = localVariable.initializationPCs[(j << 1) + 1];
1728 if (startPC != endPC) { // only entries for non zero length
1730 localVariable.declaringScope.problemReporter().abortDueToInternalError(
1731 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
1732 (AstNode) localVariable.declaringScope.methodScope().referenceContext);
1734 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
1738 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1742 // now we can safely add the local entry
1744 localContents[localContentsOffset++] = (byte) (startPC >> 8);
1745 localContents[localContentsOffset++] = (byte) startPC;
1746 int length = endPC - startPC;
1747 localContents[localContentsOffset++] = (byte) (length >> 8);
1748 localContents[localContentsOffset++] = (byte) length;
1749 nameIndex = constantPool.literalIndex(localVariable.name);
1750 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1751 localContents[localContentsOffset++] = (byte) nameIndex;
1752 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
1753 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1754 localContents[localContentsOffset++] = (byte) descriptorIndex;
1755 int resolvedPosition = localVariable.resolvedPosition;
1756 localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1757 localContents[localContentsOffset++] = (byte) resolvedPosition;
1761 int value = numberOfEntries * 10 + 2;
1762 localVariableTableOffset += 2;
1763 localContents[localVariableTableOffset++] = (byte) (value >> 24);
1764 localContents[localVariableTableOffset++] = (byte) (value >> 16);
1765 localContents[localVariableTableOffset++] = (byte) (value >> 8);
1766 localContents[localVariableTableOffset++] = (byte) value;
1767 localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1768 localContents[localVariableTableOffset] = (byte) numberOfEntries;
1772 // update the number of attributes
1773 // ensure first that there is enough space available inside the contents array
1774 if (codeAttributeAttributeOffset + 2
1775 >= (contentsLength = localContents.length)) {
1779 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1783 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1784 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1785 // update the attribute length
1786 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1787 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1788 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1789 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1790 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1791 contentsOffset = localContentsOffset;
1796 * That method completes the creation of the code attribute by setting
1797 * - the attribute_length
1802 * - and debug attributes if necessary.
1804 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1805 * @param codeAttributeOffset <CODE>int</CODE>
1806 * @param exceptionHandler int[]
1807 * @param startIndexes int[]
1809 public void completeCodeAttributeForClinit(
1810 int codeAttributeOffset,
1811 int[] exceptionHandler,
1812 int[] startLineIndexes) {
1813 // reinitialize the contents with the byte modified by the code stream
1814 byte[] localContents = contents = codeStream.bCodeStream;
1815 int localContentsOffset = codeStream.classFileOffset;
1816 // codeAttributeOffset is the position inside contents byte array before we started to write
1817 // any information about the codeAttribute
1818 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1819 // to get the right position, 6 for the max_stack etc...
1821 int code_length = codeStream.position;
1822 if (code_length > 65535) {
1823 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1824 codeStream.methodDeclaration.scope.referenceType());
1826 if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
1830 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1834 int max_stack = codeStream.stackMax;
1835 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1836 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1837 int max_locals = codeStream.maxLocals;
1838 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1839 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1840 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1841 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1842 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1843 localContents[codeAttributeOffset + 13] = (byte) code_length;
1845 // write the exception table
1846 localContents[localContentsOffset++] = 0;
1847 localContents[localContentsOffset++] = 1;
1848 int start = exceptionHandler[0];
1849 localContents[localContentsOffset++] = (byte) (start >> 8);
1850 localContents[localContentsOffset++] = (byte) start;
1851 int end = exceptionHandler[1];
1852 localContents[localContentsOffset++] = (byte) (end >> 8);
1853 localContents[localContentsOffset++] = (byte) end;
1854 int handlerPC = exceptionHandler[2];
1855 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1856 localContents[localContentsOffset++] = (byte) handlerPC;
1857 int nameIndex = constantPool.literalIndexForJavaLangException();
1858 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1859 localContents[localContentsOffset++] = (byte) nameIndex;
1862 int codeAttributeAttributeOffset = localContentsOffset;
1863 int attributeNumber = 0; // leave two bytes for the attribute_length
1864 localContentsOffset += 2; // first we handle the linenumber attribute
1866 // first we handle the linenumber attribute
1867 if (codeStream.generateLineNumberAttributes) {
1868 /* Create and add the line number attribute (used for debugging)
1869 * Build the pairs of:
1870 * (bytecodePC lineNumber)
1871 * according to the table of start line indexes and the pcToSourceMap table
1872 * contained into the codestream
1874 int lineNumberNameIndex =
1875 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1876 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1877 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1878 localContents[localContentsOffset++] = 0;
1879 localContents[localContentsOffset++] = 0;
1880 localContents[localContentsOffset++] = 0;
1881 localContents[localContentsOffset++] = 6;
1882 localContents[localContentsOffset++] = 0;
1883 localContents[localContentsOffset++] = 1;
1884 // first entry at pc = 0
1885 localContents[localContentsOffset++] = 0;
1886 localContents[localContentsOffset++] = 0;
1887 localContents[localContentsOffset++] = (byte) (problemLine >> 8);
1888 localContents[localContentsOffset++] = (byte) problemLine;
1889 // now we change the size of the line number attribute
1892 // then we do the local variable attribute
1893 if (codeStream.generateLocalVariableTableAttributes) {
1894 int localVariableNameIndex =
1895 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1896 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1900 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1904 localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1905 localContents[localContentsOffset++] = (byte) localVariableNameIndex;
1906 localContents[localContentsOffset++] = 0;
1907 localContents[localContentsOffset++] = 0;
1908 localContents[localContentsOffset++] = 0;
1909 localContents[localContentsOffset++] = 2;
1910 localContents[localContentsOffset++] = 0;
1911 localContents[localContentsOffset++] = 0;
1914 // update the number of attributes
1915 // ensure first that there is enough space available inside the contents array
1916 if (codeAttributeAttributeOffset + 2
1917 >= (contentsLength = localContents.length)) {
1921 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1925 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1926 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1927 // update the attribute length
1928 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1929 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1930 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1931 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1932 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1933 contentsOffset = localContentsOffset;
1938 * That method completes the creation of the code attribute by setting
1939 * - the attribute_length
1944 * - and debug attributes if necessary.
1946 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1947 * @param codeAttributeOffset <CODE>int</CODE>
1948 * @param exceptionHandler int[]
1950 public void completeCodeAttributeForProblemMethod(
1951 AbstractMethodDeclaration method,
1952 MethodBinding binding,
1953 int codeAttributeOffset,
1954 int[] exceptionHandler,
1955 int[] startLineIndexes) {
1956 // reinitialize the localContents with the byte modified by the code stream
1957 byte[] localContents = contents = codeStream.bCodeStream;
1958 int localContentsOffset = codeStream.classFileOffset;
1959 // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
1960 int max_stack = codeStream.stackMax;
1961 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1962 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1963 int max_locals = codeStream.maxLocals;
1964 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1965 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1966 int code_length = codeStream.position;
1967 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1968 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1969 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1970 localContents[codeAttributeOffset + 13] = (byte) code_length;
1971 // write the exception table
1973 if (localContentsOffset + 50 >= (contentsLength = localContents.length)) {
1977 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1981 localContents[localContentsOffset++] = 0;
1982 localContents[localContentsOffset++] = 1;
1983 int start = exceptionHandler[0];
1984 localContents[localContentsOffset++] = (byte) (start >> 8);
1985 localContents[localContentsOffset++] = (byte) start;
1986 int end = exceptionHandler[1];
1987 localContents[localContentsOffset++] = (byte) (end >> 8);
1988 localContents[localContentsOffset++] = (byte) end;
1989 int handlerPC = exceptionHandler[2];
1990 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1991 localContents[localContentsOffset++] = (byte) handlerPC;
1992 int nameIndex = constantPool.literalIndexForJavaLangException();
1993 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1994 localContents[localContentsOffset++] = (byte) nameIndex; // debug attributes
1995 int codeAttributeAttributeOffset = localContentsOffset;
1996 int attributeNumber = 0; // leave two bytes for the attribute_length
1997 localContentsOffset += 2; // first we handle the linenumber attribute
1999 if (codeStream.generateLineNumberAttributes) {
2000 /* Create and add the line number attribute (used for debugging)
2001 * Build the pairs of:
2002 * (bytecodePC lineNumber)
2003 * according to the table of start line indexes and the pcToSourceMap table
2004 * contained into the codestream
2006 int lineNumberNameIndex =
2007 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
2008 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
2009 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
2010 localContents[localContentsOffset++] = 0;
2011 localContents[localContentsOffset++] = 0;
2012 localContents[localContentsOffset++] = 0;
2013 localContents[localContentsOffset++] = 6;
2014 localContents[localContentsOffset++] = 0;
2015 localContents[localContentsOffset++] = 1;
2016 if (problemLine == 0) {
2017 problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
2019 // first entry at pc = 0
2020 localContents[localContentsOffset++] = 0;
2021 localContents[localContentsOffset++] = 0;
2022 localContents[localContentsOffset++] = (byte) (problemLine >> 8);
2023 localContents[localContentsOffset++] = (byte) problemLine;
2024 // now we change the size of the line number attribute
2027 // then we do the local variable attribute
2028 if (codeStream.generateLocalVariableTableAttributes) {
2029 // compute the resolved position for the arguments of the method
2031 int localVariableTableOffset = localContentsOffset;
2032 int numberOfEntries = 0;
2033 // codeAttribute.addLocalVariableTableAttribute(this);
2034 int localVariableNameIndex =
2035 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
2036 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
2040 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2044 localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
2045 localContents[localContentsOffset++] = (byte) localVariableNameIndex;
2046 localContentsOffset += 6;
2047 // leave space for attribute_length and local_variable_table_length
2048 int descriptorIndex;
2049 if (!codeStream.methodDeclaration.isStatic()) {
2051 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
2055 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2059 localContents[localContentsOffset++] = 0;
2060 localContents[localContentsOffset++] = 0;
2061 localContents[localContentsOffset++] = (byte) (code_length >> 8);
2062 localContents[localContentsOffset++] = (byte) code_length;
2063 nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
2064 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2065 localContents[localContentsOffset++] = (byte) nameIndex;
2067 constantPool.literalIndex(
2068 codeStream.methodDeclaration.binding.declaringClass.signature());
2069 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2070 localContents[localContentsOffset++] = (byte) descriptorIndex;
2071 // the resolved position for this is always 0
2072 localContents[localContentsOffset++] = 0;
2073 localContents[localContentsOffset++] = 0;
2075 if (binding.isConstructor()) {
2076 ReferenceBinding declaringClass = binding.declaringClass;
2077 if (declaringClass.isNestedType()) {
2078 NestedTypeBinding methodDeclaringClass = (NestedTypeBinding) declaringClass;
2079 argSize = methodDeclaringClass.syntheticArgumentsOffset;
2080 SyntheticArgumentBinding[] syntheticArguments;
2081 if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances())
2083 for (int i = 0, max = syntheticArguments.length; i < max; i++) {
2084 LocalVariableBinding localVariable = syntheticArguments[i];
2085 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
2089 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2093 // now we can safely add the local entry
2095 localContents[localContentsOffset++] = 0;
2096 localContents[localContentsOffset++] = 0;
2097 localContents[localContentsOffset++] = (byte) (code_length >> 8);
2098 localContents[localContentsOffset++] = (byte) code_length;
2099 nameIndex = constantPool.literalIndex(localVariable.name);
2100 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2101 localContents[localContentsOffset++] = (byte) nameIndex;
2102 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
2103 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2104 localContents[localContentsOffset++] = (byte) descriptorIndex;
2105 int resolvedPosition = localVariable.resolvedPosition;
2106 localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2107 localContents[localContentsOffset++] = (byte) resolvedPosition;
2114 argSize = binding.isStatic() ? 0 : 1;
2116 if (method.binding != null) {
2117 TypeBinding[] parameters = method.binding.parameters;
2118 Argument[] arguments = method.arguments;
2119 if ((parameters != null) && (arguments != null)) {
2120 for (int i = 0, max = parameters.length; i < max; i++) {
2121 TypeBinding argumentBinding = parameters[i];
2122 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
2126 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2130 // now we can safely add the local entry
2132 localContents[localContentsOffset++] = 0;
2133 localContents[localContentsOffset++] = 0;
2134 localContents[localContentsOffset++] = (byte) (code_length >> 8);
2135 localContents[localContentsOffset++] = (byte) code_length;
2136 nameIndex = constantPool.literalIndex(arguments[i].name);
2137 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2138 localContents[localContentsOffset++] = (byte) nameIndex;
2139 descriptorIndex = constantPool.literalIndex(argumentBinding.signature());
2140 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2141 localContents[localContentsOffset++] = (byte) descriptorIndex;
2142 int resolvedPosition = argSize;
2143 if ((argumentBinding == TypeBinding.LongBinding)
2144 || (argumentBinding == TypeBinding.DoubleBinding))
2148 localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2149 localContents[localContentsOffset++] = (byte) resolvedPosition;
2153 int value = numberOfEntries * 10 + 2;
2154 localVariableTableOffset += 2;
2155 localContents[localVariableTableOffset++] = (byte) (value >> 24);
2156 localContents[localVariableTableOffset++] = (byte) (value >> 16);
2157 localContents[localVariableTableOffset++] = (byte) (value >> 8);
2158 localContents[localVariableTableOffset++] = (byte) value;
2159 localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
2160 localContents[localVariableTableOffset] = (byte) numberOfEntries;
2163 // update the number of attributes// ensure first that there is enough space available inside the localContents array
2164 if (codeAttributeAttributeOffset + 2
2165 >= (contentsLength = localContents.length)) {
2169 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2173 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2174 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2175 // update the attribute length
2176 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2177 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2178 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2179 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2180 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2181 contentsOffset = localContentsOffset;
2186 * That method completes the creation of the code attribute by setting
2187 * - the attribute_length
2192 * - and debug attributes if necessary.
2194 * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
2195 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
2196 * @param codeAttributeOffset <CODE>int</CODE>
2198 public void completeCodeAttributeForSyntheticAccessMethod(
2199 SyntheticAccessMethodBinding binding,
2200 int codeAttributeOffset,
2201 int[] startLineIndexes) {
2202 // reinitialize the contents with the byte modified by the code stream
2203 contents = codeStream.bCodeStream;
2204 int localContentsOffset = codeStream.classFileOffset;
2205 // codeAttributeOffset is the position inside contents byte array before we started to write
2206 // any information about the codeAttribute
2207 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
2208 // to get the right position, 6 for the max_stack etc...
2209 int max_stack = codeStream.stackMax;
2210 contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
2211 contents[codeAttributeOffset + 7] = (byte) max_stack;
2212 int max_locals = codeStream.maxLocals;
2213 contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
2214 contents[codeAttributeOffset + 9] = (byte) max_locals;
2215 int code_length = codeStream.position;
2216 contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
2217 contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
2218 contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
2219 contents[codeAttributeOffset + 13] = (byte) code_length;
2221 if ((localContentsOffset + 40) >= (contentsLength = contents.length)) {
2225 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2229 // there is no exception table, so we need to offset by 2 the current offset and move
2230 // on the attribute generation
2231 localContentsOffset += 2;
2233 int codeAttributeAttributeOffset = localContentsOffset;
2234 int attributeNumber = 0;
2235 // leave two bytes for the attribute_length
2236 localContentsOffset += 2;
2238 // first we handle the linenumber attribute
2239 if (codeStream.generateLineNumberAttributes) {
2241 int lineNumberNameIndex =
2242 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
2243 contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
2244 contents[localContentsOffset++] = (byte) lineNumberNameIndex;
2245 int lineNumberTableOffset = localContentsOffset;
2246 localContentsOffset += 6;
2247 // leave space for attribute_length and line_number_table_length
2248 // Seems like do would be better, but this preserves the existing behavior.
2249 index = searchLineNumber(startLineIndexes, binding.sourceStart);
2250 contents[localContentsOffset++] = 0;
2251 contents[localContentsOffset++] = 0;
2252 contents[localContentsOffset++] = (byte) (index >> 8);
2253 contents[localContentsOffset++] = (byte) index;
2254 // now we change the size of the line number attribute
2255 contents[lineNumberTableOffset++] = 0;
2256 contents[lineNumberTableOffset++] = 0;
2257 contents[lineNumberTableOffset++] = 0;
2258 contents[lineNumberTableOffset++] = 6;
2259 contents[lineNumberTableOffset++] = 0;
2260 contents[lineNumberTableOffset++] = 1;
2263 // then we do the local variable attribute
2264 if (codeStream.generateLocalVariableTableAttributes) {
2265 int localVariableTableOffset = localContentsOffset;
2266 int numberOfEntries = 0;
2267 int localVariableNameIndex =
2268 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
2269 if (localContentsOffset + 8 > (contentsLength = contents.length)) {
2273 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2277 contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
2278 contents[localContentsOffset++] = (byte) localVariableNameIndex;
2279 localContentsOffset += 6;
2280 // leave space for attribute_length and local_variable_table_length
2282 int descriptorIndex;
2283 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
2284 LocalVariableBinding localVariable = codeStream.locals[i];
2285 for (int j = 0; j < localVariable.initializationCount; j++) {
2286 int startPC = localVariable.initializationPCs[j << 1];
2287 int endPC = localVariable.initializationPCs[(j << 1) + 1];
2288 if (startPC != endPC) { // only entries for non zero length
2290 localVariable.declaringScope.problemReporter().abortDueToInternalError(
2291 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
2292 (AstNode) localVariable.declaringScope.methodScope().referenceContext);
2294 if (localContentsOffset + 10 > (contentsLength = contents.length)) {
2298 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2302 // now we can safely add the local entry
2304 contents[localContentsOffset++] = (byte) (startPC >> 8);
2305 contents[localContentsOffset++] = (byte) startPC;
2306 int length = endPC - startPC;
2307 contents[localContentsOffset++] = (byte) (length >> 8);
2308 contents[localContentsOffset++] = (byte) length;
2309 nameIndex = constantPool.literalIndex(localVariable.name);
2310 contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2311 contents[localContentsOffset++] = (byte) nameIndex;
2312 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
2313 contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2314 contents[localContentsOffset++] = (byte) descriptorIndex;
2315 int resolvedPosition = localVariable.resolvedPosition;
2316 contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2317 contents[localContentsOffset++] = (byte) resolvedPosition;
2321 int value = numberOfEntries * 10 + 2;
2322 localVariableTableOffset += 2;
2323 contents[localVariableTableOffset++] = (byte) (value >> 24);
2324 contents[localVariableTableOffset++] = (byte) (value >> 16);
2325 contents[localVariableTableOffset++] = (byte) (value >> 8);
2326 contents[localVariableTableOffset++] = (byte) value;
2327 contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
2328 contents[localVariableTableOffset] = (byte) numberOfEntries;
2331 // update the number of attributes
2332 // ensure first that there is enough space available inside the contents array
2333 if (codeAttributeAttributeOffset + 2 >= (contentsLength = contents.length)) {
2337 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2341 contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2342 contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2344 // update the attribute length
2345 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2346 contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2347 contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2348 contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2349 contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2350 contentsOffset = localContentsOffset;
2355 * Complete the creation of a method info by setting up the number of attributes at the right offset.
2357 * @param methodAttributeOffset <CODE>int</CODE>
2358 * @param attributeNumber <CODE>int</CODE>
2360 public void completeMethodInfo(
2361 int methodAttributeOffset,
2362 int attributeNumber) {
2363 // update the number of attributes
2364 contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
2365 contents[methodAttributeOffset] = (byte) attributeNumber;
2370 * Innerclasses get their name computed as they are generated, since some may not
2371 * be actually outputed if sitting inside unreachable code.
2373 * @param localType org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding
2375 public char[] computeConstantPoolName(LocalTypeBinding localType) {
2376 if (localType.constantPoolName() != null) {
2377 return localType.constantPoolName();
2379 // delegates to the outermost enclosing classfile, since it is the only one with a global vision of its innertypes.
2380 if (enclosingClassFile != null) {
2381 return this.outerMostEnclosingClassFile().computeConstantPoolName(localType);
2383 if (nameUsage == null)
2384 nameUsage = new HashtableOfType();
2386 // ensure there is not already such a local type name defined by the user
2388 char[] candidateName;
2390 if (localType.isMemberType()){
2392 candidateName = CharOperation.concat(
2393 localType.enclosingType().constantPoolName(),
2394 localType.sourceName,
2397 // in case of collision, then member name gets extra $1 inserted
2398 // e.g. class X { { class L{} new X(){ class L{} } } }
2399 candidateName = CharOperation.concat(
2400 localType.enclosingType().constantPoolName(),
2402 String.valueOf(index).toCharArray(),
2404 localType.sourceName);
2406 } else if (localType.isAnonymousType()){
2407 candidateName = CharOperation.concat(
2408 referenceBinding.constantPoolName(),
2409 String.valueOf(index+1).toCharArray(),
2412 candidateName = CharOperation.concat(
2413 referenceBinding.constantPoolName(),
2415 String.valueOf(index+1).toCharArray(),
2417 localType.sourceName);
2419 if (nameUsage.get(candidateName) != null) {
2422 nameUsage.put(candidateName, localType);
2426 return candidateName;
2431 * Request the creation of a ClassFile compatible representation of a problematic type
2433 * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
2434 * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult
2436 public static void createProblemType(
2437 TypeDeclaration typeDeclaration,
2438 CompilationResult unitResult) {
2439 SourceTypeBinding typeBinding = typeDeclaration.binding;
2440 ClassFile classFile = new ClassFile(typeBinding, null, true);
2443 if (typeBinding.isMemberType())
2444 classFile.recordEnclosingTypeAttributes(typeBinding);
2447 FieldBinding[] fields = typeBinding.fields;
2448 if ((fields != null) && (fields != NoFields)) {
2449 for (int i = 0, max = fields.length; i < max; i++) {
2450 if (fields[i].constant == null) {
2451 FieldReference.getConstantFor(fields[i], false, null, null, 0);
2454 classFile.addFieldInfos();
2456 // we have to set the number of fields to be equals to 0
2457 classFile.contents[classFile.contentsOffset++] = 0;
2458 classFile.contents[classFile.contentsOffset++] = 0;
2460 // leave some space for the methodCount
2461 classFile.setForMethodInfos();
2462 // add its user defined methods
2463 MethodBinding[] methods = typeBinding.methods;
2464 AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods;
2465 int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length;
2467 IProblem[] problems = unitResult.getProblems();
2468 if (problems == null) {
2469 problems = new IProblem[0];
2471 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
2472 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
2473 if (methods != null) {
2474 if (typeBinding.isInterface()) {
2475 // we cannot create problem methods for an interface. So we have to generate a clinit
2476 // which should contain all the problem
2477 classFile.addProblemClinit(problemsCopy);
2478 for (int i = 0, max = methods.length; i < max; i++) {
2479 MethodBinding methodBinding;
2480 if ((methodBinding = methods[i]) != null) {
2481 // find the corresponding method declaration
2482 for (int j = 0; j < maxMethodDecl; j++) {
2483 if ((methodDeclarations[j] != null)
2484 && (methodDeclarations[j].binding == methods[i])) {
2485 if (!methodBinding.isConstructor()) {
2486 classFile.addAbstractMethod(methodDeclarations[j], methodBinding);
2494 for (int i = 0, max = methods.length; i < max; i++) {
2495 MethodBinding methodBinding;
2496 if ((methodBinding = methods[i]) != null) {
2497 // find the corresponding method declaration
2498 for (int j = 0; j < maxMethodDecl; j++) {
2499 if ((methodDeclarations[j] != null)
2500 && (methodDeclarations[j].binding == methods[i])) {
2501 AbstractMethodDeclaration methodDecl;
2502 if ((methodDecl = methodDeclarations[j]).isConstructor()) {
2503 classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy);
2505 classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy);
2513 // add abstract methods
2514 classFile.addDefaultAbstractMethods();
2516 // propagate generation of (problem) member types
2517 if (typeDeclaration.memberTypes != null) {
2518 for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) {
2519 TypeDeclaration memberType = typeDeclaration.memberTypes[i];
2520 if (memberType.binding != null) {
2521 classFile.recordNestedMemberAttribute(memberType.binding);
2522 ClassFile.createProblemType(memberType, unitResult);
2526 classFile.addAttributes();
2527 unitResult.record(typeBinding.constantPoolName(), classFile);
2532 * This methods returns a char[] representing the file name of the receiver
2536 public char[] fileName() {
2537 return constantPool.UTF8Cache.returnKeyFor(1);
2542 * That method generates the header of a code attribute.
2543 * - the index inside the constant pool for the attribute name (i.e. Code)
2544 * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4).
2546 public void generateCodeAttributeHeader() {
2548 if (contentsOffset + 20 >= (contentsLength = contents.length)) {
2552 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2556 int constantValueNameIndex =
2557 constantPool.literalIndex(AttributeNamesConstants.CodeName);
2558 contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
2559 contents[contentsOffset++] = (byte) constantValueNameIndex;
2560 // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4)
2561 contentsOffset += 12;
2566 * That method generates the attributes of a code attribute.
2568 * - an exception attribute for each try/catch found inside the method
2569 * - a deprecated attribute
2570 * - a synthetic attribute for synthetic access methods
2572 * It returns the number of attributes created for the code attribute.
2574 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2575 * @return <CODE>int</CODE>
2577 public int generateMethodInfoAttribute(MethodBinding methodBinding) {
2578 // leave two bytes for the attribute_number
2579 contentsOffset += 2;
2580 // now we can handle all the attribute for that method info:
2582 // - a CodeAttribute
2583 // - a ExceptionAttribute
2584 // - a DeprecatedAttribute
2585 // - a SyntheticAttribute
2587 // Exception attribute
2588 ReferenceBinding[] thrownsExceptions;
2590 int attributeNumber = 0;
2591 if ((thrownsExceptions = methodBinding.thrownExceptions) != NoExceptions) {
2592 // The method has a throw clause. So we need to add an exception attribute
2593 // check that there is enough space to write all the bytes for the exception attribute
2594 int length = thrownsExceptions.length;
2595 if (contentsOffset + (8 + length * 2) >= (contentsLength = contents.length)) {
2600 new byte[contentsLength + Math.max(INCREMENT_SIZE, (8 + length * 2))]),
2604 int exceptionNameIndex =
2605 constantPool.literalIndex(AttributeNamesConstants.ExceptionsName);
2606 contents[contentsOffset++] = (byte) (exceptionNameIndex >> 8);
2607 contents[contentsOffset++] = (byte) exceptionNameIndex;
2608 // The attribute length = length * 2 + 2 in case of a exception attribute
2609 int attributeLength = length * 2 + 2;
2610 contents[contentsOffset++] = (byte) (attributeLength >> 24);
2611 contents[contentsOffset++] = (byte) (attributeLength >> 16);
2612 contents[contentsOffset++] = (byte) (attributeLength >> 8);
2613 contents[contentsOffset++] = (byte) attributeLength;
2614 contents[contentsOffset++] = (byte) (length >> 8);
2615 contents[contentsOffset++] = (byte) length;
2616 for (int i = 0; i < length; i++) {
2617 int exceptionIndex = constantPool.literalIndex(thrownsExceptions[i]);
2618 contents[contentsOffset++] = (byte) (exceptionIndex >> 8);
2619 contents[contentsOffset++] = (byte) exceptionIndex;
2623 // Deprecated attribute
2624 // Check that there is enough space to write the deprecated attribute
2625 if (contentsOffset + 6 >= (contentsLength = contents.length)) {
2629 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2633 if (methodBinding.isDeprecated()) {
2634 int deprecatedAttributeNameIndex =
2635 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
2636 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
2637 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
2638 // the length of a deprecated attribute is equals to 0
2639 contents[contentsOffset++] = 0;
2640 contents[contentsOffset++] = 0;
2641 contents[contentsOffset++] = 0;
2642 contents[contentsOffset++] = 0;
2646 // Synthetic attribute
2647 // Check that there is enough space to write the deprecated attribute
2648 if (contentsOffset + 6 >= (contentsLength = contents.length)) {
2652 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2656 if (methodBinding.isSynthetic()) {
2657 int syntheticAttributeNameIndex =
2658 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
2659 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
2660 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
2661 // the length of a synthetic attribute is equals to 0
2662 contents[contentsOffset++] = 0;
2663 contents[contentsOffset++] = 0;
2664 contents[contentsOffset++] = 0;
2665 contents[contentsOffset++] = 0;
2669 return attributeNumber;
2674 * That method generates the header of a method info:
2675 * The header consists in:
2676 * - the access flags
2677 * - the name index of the method name inside the constant pool
2678 * - the descriptor index of the signature of the method inside the constant pool.
2680 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2682 public void generateMethodInfoHeader(MethodBinding methodBinding) {
2683 // check that there is enough space to write all the bytes for the method info corresponding
2684 // to the @methodBinding
2686 methodCount++; // add one more method
2687 if (contentsOffset + 10 >= (contentsLength = contents.length)) {
2691 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2695 int accessFlags = methodBinding.getAccessFlags();
2696 if (methodBinding.isRequiredToClearPrivateModifier()) {
2697 accessFlags &= ~AccPrivate;
2699 contents[contentsOffset++] = (byte) (accessFlags >> 8);
2700 contents[contentsOffset++] = (byte) accessFlags;
2701 int nameIndex = constantPool.literalIndex(methodBinding.selector);
2702 contents[contentsOffset++] = (byte) (nameIndex >> 8);
2703 contents[contentsOffset++] = (byte) nameIndex;
2704 int descriptorIndex = constantPool.literalIndex(methodBinding.signature());
2705 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
2706 contents[contentsOffset++] = (byte) descriptorIndex;
2711 * That method generates the method info header of a clinit:
2712 * The header consists in:
2713 * - the access flags (always default access + static)
2714 * - the name index of the method name (always <clinit>) inside the constant pool
2715 * - the descriptor index of the signature (always ()V) of the method inside the constant pool.
2717 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2719 public void generateMethodInfoHeaderForClinit() {
2720 // check that there is enough space to write all the bytes for the method info corresponding
2721 // to the @methodBinding
2723 methodCount++; // add one more method
2724 if (contentsOffset + 10 >= (contentsLength = contents.length)) {
2728 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2732 contents[contentsOffset++] = (byte) ((AccDefault | AccStatic) >> 8);
2733 contents[contentsOffset++] = (byte) (AccDefault | AccStatic);
2734 int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.Clinit);
2735 contents[contentsOffset++] = (byte) (nameIndex >> 8);
2736 contents[contentsOffset++] = (byte) nameIndex;
2737 int descriptorIndex =
2738 constantPool.literalIndex(QualifiedNamesConstants.ClinitSignature);
2739 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
2740 contents[contentsOffset++] = (byte) descriptorIndex;
2741 // We know that we won't get more than 1 attribute: the code attribute
2742 contents[contentsOffset++] = 0;
2743 contents[contentsOffset++] = 1;
2748 * Answer the actual bytes of the class file
2750 * This method encodes the receiver structure into a byte array which is the content of the classfile.
2751 * Returns the byte array that represents the encoded structure of the receiver.
2755 public byte[] getBytes() {
2756 byte[] fullContents = new byte[headerOffset + contentsOffset];
2757 System.arraycopy(header, 0, fullContents, 0, headerOffset);
2758 System.arraycopy(contents, 0, fullContents, headerOffset, contentsOffset);
2759 return fullContents;
2764 * Answer the compound name of the class file.
2766 * e.g. {{java}, {util}, {Hashtable}}.
2768 public char[][] getCompoundName() {
2769 return CharOperation.splitOn('/', fileName());
2774 * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name
2775 * for all inner types of the receiver.
2776 * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile
2778 public ClassFile outerMostEnclosingClassFile() {
2779 ClassFile current = this;
2780 while (current.enclosingClassFile != null)
2781 current = current.enclosingClassFile;
2787 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2788 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2790 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2792 public void recordEnclosingTypeAttributes(ReferenceBinding binding) {
2793 // add all the enclosing types
2794 ReferenceBinding enclosingType = referenceBinding.enclosingType();
2796 while (enclosingType != null) {
2798 enclosingType = enclosingType.enclosingType();
2800 enclosingType = referenceBinding;
2801 ReferenceBinding enclosingTypes[];
2803 enclosingTypes = new ReferenceBinding[depth];
2804 for (int i = depth - 1; i >= 0; i--) {
2805 enclosingTypes[i] = enclosingType;
2806 enclosingType = enclosingType.enclosingType();
2808 for (int i = 0; i < depth; i++) {
2809 addInnerClasses(enclosingTypes[i]);
2812 addInnerClasses(referenceBinding);
2818 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2819 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2821 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2823 public void recordNestedLocalAttribute(ReferenceBinding binding) {
2824 // add all the enclosing types
2825 ReferenceBinding enclosingType = referenceBinding.enclosingType();
2827 while (enclosingType != null) {
2829 enclosingType = enclosingType.enclosingType();
2831 enclosingType = referenceBinding;
2832 ReferenceBinding enclosingTypes[];
2834 enclosingTypes = new ReferenceBinding[depth];
2835 for (int i = depth - 1; i >= 0; i--) {
2836 enclosingTypes[i] = enclosingType;
2837 enclosingType = enclosingType.enclosingType();
2839 for (int i = 0; i < depth; i++)
2840 addInnerClasses(enclosingTypes[i]);
2842 addInnerClasses(binding);
2848 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2849 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2851 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2853 public void recordNestedMemberAttribute(ReferenceBinding binding) {
2854 addInnerClasses(binding);
2859 * Search the line number corresponding to a specific position
2861 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
2863 public static final int searchLineNumber(
2864 int[] startLineIndexes,
2866 // this code is completely useless, but it is the same implementation than
2867 // org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int)
2868 // if (startLineIndexes == null)
2870 int length = startLineIndexes.length;
2873 int g = 0, d = length - 1;
2877 if (position < startLineIndexes[m]) {
2880 if (position > startLineIndexes[m]) {
2886 if (position < startLineIndexes[m]) {
2894 * This methods leaves the space for method counts recording.
2896 public void setForMethodInfos() {
2897 // leave some space for the methodCount
2898 methodCountOffset = contentsOffset;
2899 contentsOffset += 2;
2904 * outputPath is formed like:
2905 * c:\temp\ the last character is a file separator
2906 * relativeFileName is formed like:
2907 * java\lang\String.class
2908 * @param generatePackagesStructure a flag to know if the packages structure has to be generated.
2909 * @param outputPath the output directory
2910 * @param relativeFileName java.lang.String
2911 * @param contents byte[]
2914 public static void writeToDisk(
2915 boolean generatePackagesStructure,
2917 String relativeFileName,
2919 throws IOException {
2921 BufferedOutputStream output = null;
2922 if (generatePackagesStructure) {
2923 output = new BufferedOutputStream(
2924 new FileOutputStream(
2925 new File(buildAllDirectoriesInto(outputPath, relativeFileName))));
2927 String fileName = null;
2928 char fileSeparatorChar = File.separatorChar;
2929 String fileSeparator = File.separator;
2930 // First we ensure that the outputPath exists
2931 outputPath = outputPath.replace('/', fileSeparatorChar);
2932 // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
2933 int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar);
2934 if (indexOfPackageSeparator == -1) {
2935 if (outputPath.endsWith(fileSeparator)) {
2936 fileName = outputPath + relativeFileName;
2938 fileName = outputPath + fileSeparator + relativeFileName;
2941 int length = relativeFileName.length();
2942 if (outputPath.endsWith(fileSeparator)) {
2943 fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length);
2945 fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length);
2948 output = new BufferedOutputStream(
2949 new FileOutputStream(
2950 new File(fileName)));
2953 output.write(contents);