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;
13 import java.io.BufferedOutputStream;
15 import java.io.FileOutputStream;
16 import java.io.IOException;
17 import java.util.StringTokenizer;
19 import net.sourceforge.phpdt.core.compiler.IProblem;
20 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
21 import net.sourceforge.phpdt.internal.compiler.ast.Argument;
22 import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
23 import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration;
24 import net.sourceforge.phpdt.internal.compiler.ast.FieldReference;
25 import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration;
26 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
27 import net.sourceforge.phpdt.internal.compiler.codegen.AttributeNamesConstants;
28 import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
29 import net.sourceforge.phpdt.internal.compiler.codegen.ConstantPool;
30 import net.sourceforge.phpdt.internal.compiler.codegen.ExceptionLabel;
31 import net.sourceforge.phpdt.internal.compiler.codegen.QualifiedNamesConstants;
32 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
33 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
34 import net.sourceforge.phpdt.internal.compiler.impl.StringConstant;
35 import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers;
36 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
37 import net.sourceforge.phpdt.internal.compiler.lookup.LocalTypeBinding;
38 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
39 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
40 import net.sourceforge.phpdt.internal.compiler.lookup.NestedTypeBinding;
41 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
42 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
43 import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticAccessMethodBinding;
44 import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticArgumentBinding;
45 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
46 import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
47 import net.sourceforge.phpdt.internal.compiler.lookup.TypeIds;
48 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
49 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
50 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfType;
51 import net.sourceforge.phpdt.internal.compiler.util.Util;
54 * Represents a class file wrapper on bytes, it is aware of its actual
57 * Public APIs are listed below:
60 * Answer the actual bytes of the class file
62 * char[][] getCompoundName();
63 * Answer the compound name of the class file.
64 * For example, {{java}, {util}, {Hashtable}}.
66 * byte[] getReducedBytes();
67 * Answer a smaller byte format, which is only contains some structural
68 * information. Those bytes are decodable with a regular class file reader,
69 * such as DietClassFileReader
71 public class ClassFile
72 implements AttributeNamesConstants, CompilerModifiers, TypeConstants, TypeIds {
73 public SourceTypeBinding referenceBinding;
74 public ConstantPool constantPool;
75 public ClassFile enclosingClassFile;
76 // used to generate private access methods
77 public int produceDebugAttributes;
78 public ReferenceBinding[] innerClassesBindings;
79 public int numberOfInnerClasses;
81 // the header contains all the bytes till the end of the constant pool
82 public byte[] contents;
83 // that collection contains all the remaining bytes of the .class file
84 public int headerOffset;
85 public int contentsOffset;
86 public int constantPoolOffset;
87 public int methodCountOffset;
88 public int methodCount;
89 protected boolean creatingProblemType;
90 public static final int INITIAL_CONTENTS_SIZE = 1000;
91 public static final int INITIAL_HEADER_SIZE = 1000;
92 public static final int INCREMENT_SIZE = 1000;
93 public static final int INNER_CLASSES_SIZE = 5;
94 protected HashtableOfType nameUsage;
95 public CodeStream codeStream;
96 protected int problemLine; // used to create line number attributes for problem methods
100 * This methods creates a new instance of the receiver.
107 * This methods creates a new instance of the receiver.
109 * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding
110 * @param enclosingClassFile org.eclipse.jdt.internal.compiler.ClassFile
111 * @param creatingProblemType <CODE>boolean</CODE>
114 SourceTypeBinding aType,
115 ClassFile enclosingClassFile,
116 boolean creatingProblemType) {
117 referenceBinding = aType;
118 header = new byte[INITIAL_HEADER_SIZE];
119 // generate the magic numbers inside the header
120 header[headerOffset++] = (byte) (0xCAFEBABEL >> 24);
121 header[headerOffset++] = (byte) (0xCAFEBABEL >> 16);
122 header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
123 header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
124 switch(((SourceTypeBinding) referenceBinding).scope.environment().options.targetJDK) {
125 case CompilerOptions.JDK1_4 :
126 // Compatible with JDK 1.4
127 header[headerOffset++] = 0;
128 header[headerOffset++] = 0;
129 header[headerOffset++] = 0;
130 header[headerOffset++] = 48;
132 case CompilerOptions.JDK1_3 :
133 // Compatible with JDK 1.3
134 header[headerOffset++] = 0;
135 header[headerOffset++] = 0;
136 header[headerOffset++] = 0;
137 header[headerOffset++] = 47;
139 case CompilerOptions.JDK1_2 :
140 // Compatible with JDK 1.2
141 header[headerOffset++] = 0;
142 header[headerOffset++] = 0;
143 header[headerOffset++] = 0;
144 header[headerOffset++] = 46;
146 case CompilerOptions.JDK1_1 :
147 // Compatible with JDK 1.1
148 header[headerOffset++] = 0;
149 header[headerOffset++] = 3;
150 header[headerOffset++] = 0;
151 header[headerOffset++] = 45;
153 constantPoolOffset = headerOffset;
155 constantPool = new ConstantPool(this);
157 // Modifier manipulations for classfile
158 int accessFlags = aType.getAccessFlags();
159 if (aType.isPrivate()) { // rewrite private to non-public
160 accessFlags &= ~AccPublic;
162 if (aType.isProtected()) { // rewrite protected into public
163 accessFlags |= AccPublic;
165 // clear all bits that are illegal for a class or an interface
175 // set the AccSuper flag (has to be done after clearing AccSynchronized - since same value)
176 accessFlags |= AccSuper;
178 this.enclosingClassFile = enclosingClassFile;
179 // innerclasses get their names computed at code gen time
180 if (aType.isLocalType()) {
181 ((LocalTypeBinding) aType).constantPoolName(
182 computeConstantPoolName((LocalTypeBinding) aType));
183 ReferenceBinding[] memberTypes = aType.memberTypes();
184 for (int i = 0, max = memberTypes.length; i < max; i++) {
185 ((LocalTypeBinding) memberTypes[i]).constantPoolName(
186 computeConstantPoolName((LocalTypeBinding) memberTypes[i]));
189 contents = new byte[INITIAL_CONTENTS_SIZE];
190 // now we continue to generate the bytes inside the contents array
191 contents[contentsOffset++] = (byte) (accessFlags >> 8);
192 contents[contentsOffset++] = (byte) accessFlags;
193 int classNameIndex = constantPool.literalIndex(aType);
194 contents[contentsOffset++] = (byte) (classNameIndex >> 8);
195 contents[contentsOffset++] = (byte) classNameIndex;
196 int superclassNameIndex;
197 if (aType.isInterface()) {
198 superclassNameIndex = constantPool.literalIndexForJavaLangObject();
200 superclassNameIndex =
201 (aType.superclass == null ? 0 : constantPool.literalIndex(aType.superclass));
203 contents[contentsOffset++] = (byte) (superclassNameIndex >> 8);
204 contents[contentsOffset++] = (byte) superclassNameIndex;
205 ReferenceBinding[] superInterfacesBinding = aType.superInterfaces();
206 int interfacesCount = superInterfacesBinding.length;
207 contents[contentsOffset++] = (byte) (interfacesCount >> 8);
208 contents[contentsOffset++] = (byte) interfacesCount;
209 if (superInterfacesBinding != null) {
210 for (int i = 0; i < interfacesCount; i++) {
211 int interfaceIndex = constantPool.literalIndex(superInterfacesBinding[i]);
212 contents[contentsOffset++] = (byte) (interfaceIndex >> 8);
213 contents[contentsOffset++] = (byte) interfaceIndex;
216 produceDebugAttributes =
217 ((SourceTypeBinding) referenceBinding)
221 .produceDebugAttributes;
222 innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE];
223 this.creatingProblemType = creatingProblemType;
224 codeStream = new CodeStream(this);
226 // retrieve the enclosing one guaranteed to be the one matching the propagated flow info
227 // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check)
228 ClassFile outermostClassFile = this.outerMostEnclosingClassFile();
229 if (this == outermostClassFile) {
230 codeStream.maxFieldCount = aType.scope.referenceType().maxFieldCount;
232 codeStream.maxFieldCount = outermostClassFile.codeStream.maxFieldCount;
238 * Generate the byte for a problem method info that correspond to a boggus method.
240 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
241 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
243 public void addAbstractMethod(
244 AbstractMethodDeclaration method,
245 MethodBinding methodBinding) {
247 // force the modifiers to be public and abstract
248 methodBinding.modifiers = AccPublic | AccAbstract;
250 this.generateMethodInfoHeader(methodBinding);
251 int methodAttributeOffset = this.contentsOffset;
252 int attributeNumber = this.generateMethodInfoAttribute(methodBinding);
253 this.completeMethodInfo(methodAttributeOffset, attributeNumber);
258 * This methods generate all the attributes for the receiver.
259 * For a class they could be:
260 * - source file attribute
261 * - inner classes attribute
262 * - deprecated attribute
264 public void addAttributes() {
265 // update the method count
266 contents[methodCountOffset++] = (byte) (methodCount >> 8);
267 contents[methodCountOffset] = (byte) methodCount;
269 int attributeNumber = 0;
270 // leave two bytes for the number of attributes and store the current offset
271 int attributeOffset = contentsOffset;
276 if ((produceDebugAttributes & CompilerOptions.Source) != 0) {
277 String fullFileName =
278 new String(referenceBinding.scope.referenceCompilationUnit().getFileName());
279 fullFileName = fullFileName.replace('\\', '/');
280 int lastIndex = fullFileName.lastIndexOf('/');
281 if (lastIndex != -1) {
282 fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length());
284 // check that there is enough space to write all the bytes for the field info corresponding
285 // to the @fieldBinding
286 if (contentsOffset + 8 >= (contentsLength = contents.length)) {
290 (contents = new byte[contentsLength + INCREMENT_SIZE]),
294 int sourceAttributeNameIndex =
295 constantPool.literalIndex(AttributeNamesConstants.SourceName);
296 contents[contentsOffset++] = (byte) (sourceAttributeNameIndex >> 8);
297 contents[contentsOffset++] = (byte) sourceAttributeNameIndex;
298 // The length of a source file attribute is 2. This is a fixed-length
300 contents[contentsOffset++] = 0;
301 contents[contentsOffset++] = 0;
302 contents[contentsOffset++] = 0;
303 contents[contentsOffset++] = 2;
304 // write the source file name
305 int fileNameIndex = constantPool.literalIndex(fullFileName.toCharArray());
306 contents[contentsOffset++] = (byte) (fileNameIndex >> 8);
307 contents[contentsOffset++] = (byte) fileNameIndex;
310 // Deprecated attribute
311 if (referenceBinding.isDeprecated()) {
312 // check that there is enough space to write all the bytes for the field info corresponding
313 // to the @fieldBinding
314 if (contentsOffset + 6 >= (contentsLength = contents.length)) {
318 (contents = new byte[contentsLength + INCREMENT_SIZE]),
322 int deprecatedAttributeNameIndex =
323 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
324 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
325 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
326 // the length of a deprecated attribute is equals to 0
327 contents[contentsOffset++] = 0;
328 contents[contentsOffset++] = 0;
329 contents[contentsOffset++] = 0;
330 contents[contentsOffset++] = 0;
333 // Inner class attribute
334 if (numberOfInnerClasses != 0) {
335 // Generate the inner class attribute
337 if (contentsOffset + (exSize = (8 * numberOfInnerClasses + 8))
338 >= (contentsLength = contents.length)) {
343 new byte[contentsLength
344 + (exSize >= INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
348 // Now we now the size of the attribute and the number of entries
350 int attributeNameIndex =
351 constantPool.literalIndex(AttributeNamesConstants.InnerClassName);
352 contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
353 contents[contentsOffset++] = (byte) attributeNameIndex;
354 int value = (numberOfInnerClasses << 3) + 2;
355 contents[contentsOffset++] = (byte) (value >> 24);
356 contents[contentsOffset++] = (byte) (value >> 16);
357 contents[contentsOffset++] = (byte) (value >> 8);
358 contents[contentsOffset++] = (byte) value;
359 contents[contentsOffset++] = (byte) (numberOfInnerClasses >> 8);
360 contents[contentsOffset++] = (byte) numberOfInnerClasses;
361 for (int i = 0; i < numberOfInnerClasses; i++) {
362 ReferenceBinding innerClass = innerClassesBindings[i];
363 int accessFlags = innerClass.getAccessFlags();
364 int innerClassIndex = constantPool.literalIndex(innerClass);
366 contents[contentsOffset++] = (byte) (innerClassIndex >> 8);
367 contents[contentsOffset++] = (byte) innerClassIndex;
368 // outer class index: anonymous and local have no outer class index
369 if (innerClass.isMemberType()) {
370 // member or member of local
371 int outerClassIndex = constantPool.literalIndex(innerClass.enclosingType());
372 contents[contentsOffset++] = (byte) (outerClassIndex >> 8);
373 contents[contentsOffset++] = (byte) outerClassIndex;
375 // equals to 0 if the innerClass is not a member type
376 contents[contentsOffset++] = 0;
377 contents[contentsOffset++] = 0;
380 if (!innerClass.isAnonymousType()) {
381 int nameIndex = constantPool.literalIndex(innerClass.sourceName());
382 contents[contentsOffset++] = (byte) (nameIndex >> 8);
383 contents[contentsOffset++] = (byte) nameIndex;
385 // equals to 0 if the innerClass is an anonymous type
386 contents[contentsOffset++] = 0;
387 contents[contentsOffset++] = 0;
390 if (innerClass.isAnonymousType()) {
391 accessFlags |= AccPrivate;
393 if (innerClass.isLocalType() && !innerClass.isMemberType()) {
394 accessFlags |= AccPrivate;
396 contents[contentsOffset++] = (byte) (accessFlags >> 8);
397 contents[contentsOffset++] = (byte) accessFlags;
401 // update the number of attributes
402 contentsLength = contents.length;
403 if (attributeOffset + 2 >= contentsLength) {
407 (contents = new byte[contentsLength + INCREMENT_SIZE]),
411 contents[attributeOffset++] = (byte) (attributeNumber >> 8);
412 contents[attributeOffset] = (byte) attributeNumber;
414 // resynchronize all offsets of the classfile
415 header = constantPool.poolContent;
416 headerOffset = constantPool.currentOffset;
417 int constantPoolCount = constantPool.currentIndex;
418 header[constantPoolOffset++] = (byte) (constantPoolCount >> 8);
419 header[constantPoolOffset] = (byte) constantPoolCount;
424 * This methods generate all the default abstract method infos that correpond to
425 * the abstract methods inherited from superinterfaces.
427 public void addDefaultAbstractMethods() { // default abstract methods
428 MethodBinding[] defaultAbstractMethods =
429 referenceBinding.getDefaultAbstractMethods();
430 for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
431 generateMethodInfoHeader(defaultAbstractMethods[i]);
432 int methodAttributeOffset = contentsOffset;
433 int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
434 completeMethodInfo(methodAttributeOffset, attributeNumber);
440 * This methods generates the bytes for the field binding passed like a parameter
441 * @param fieldBinding org.eclipse.jdt.internal.compiler.lookup.FieldBinding
443 public void addFieldInfo(FieldBinding fieldBinding) {
444 int attributeNumber = 0;
445 // check that there is enough space to write all the bytes for the field info corresponding
446 // to the @fieldBinding
448 if (contentsOffset + 30 >= (contentsLength = contents.length)) {
452 (contents = new byte[contentsLength + INCREMENT_SIZE]),
456 // Generate two attribute: constantValueAttribute and SyntheticAttribute
457 // Now we can generate all entries into the byte array
458 // First the accessFlags
459 int accessFlags = fieldBinding.getAccessFlags();
460 contents[contentsOffset++] = (byte) (accessFlags >> 8);
461 contents[contentsOffset++] = (byte) accessFlags;
462 // Then the nameIndex
463 int nameIndex = constantPool.literalIndex(fieldBinding.name);
464 contents[contentsOffset++] = (byte) (nameIndex >> 8);
465 contents[contentsOffset++] = (byte) nameIndex;
466 // Then the descriptorIndex
467 int descriptorIndex = constantPool.literalIndex(fieldBinding.type.signature());
468 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
469 contents[contentsOffset++] = (byte) descriptorIndex;
470 // leave some space for the number of attributes
471 int fieldAttributeOffset = contentsOffset;
473 // 4.7.2 only static constant fields get a ConstantAttribute
474 if (fieldBinding.constant != Constant.NotAConstant
475 && fieldBinding.constant.typeID() != T_null) {
476 // Now we generate the constant attribute corresponding to the fieldBinding
477 int constantValueNameIndex =
478 constantPool.literalIndex(AttributeNamesConstants.ConstantValueName);
479 contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
480 contents[contentsOffset++] = (byte) constantValueNameIndex;
481 // The attribute length = 2 in case of a constantValue attribute
482 contents[contentsOffset++] = 0;
483 contents[contentsOffset++] = 0;
484 contents[contentsOffset++] = 0;
485 contents[contentsOffset++] = 2;
487 // Need to add the constant_value_index
488 switch (fieldBinding.constant.typeID()) {
490 int booleanValueIndex =
491 constantPool.literalIndex(fieldBinding.constant.booleanValue() ? 1 : 0);
492 contents[contentsOffset++] = (byte) (booleanValueIndex >> 8);
493 contents[contentsOffset++] = (byte) booleanValueIndex;
499 int integerValueIndex =
500 constantPool.literalIndex(fieldBinding.constant.intValue());
501 contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
502 contents[contentsOffset++] = (byte) integerValueIndex;
505 int floatValueIndex =
506 constantPool.literalIndex(fieldBinding.constant.floatValue());
507 contents[contentsOffset++] = (byte) (floatValueIndex >> 8);
508 contents[contentsOffset++] = (byte) floatValueIndex;
511 int doubleValueIndex =
512 constantPool.literalIndex(fieldBinding.constant.doubleValue());
513 contents[contentsOffset++] = (byte) (doubleValueIndex >> 8);
514 contents[contentsOffset++] = (byte) doubleValueIndex;
518 constantPool.literalIndex(fieldBinding.constant.longValue());
519 contents[contentsOffset++] = (byte) (longValueIndex >> 8);
520 contents[contentsOffset++] = (byte) longValueIndex;
523 int stringValueIndex =
524 constantPool.literalIndex(
525 ((StringConstant) fieldBinding.constant).stringValue());
526 if (stringValueIndex == -1) {
527 if (!creatingProblemType) {
528 // report an error and abort: will lead to a problem type classfile creation
529 TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
530 FieldDeclaration[] fieldDecls = typeDeclaration.fields;
531 for (int i = 0, max = fieldDecls.length; i < max; i++) {
532 if (fieldDecls[i].binding == fieldBinding) {
533 // problem should abort
534 typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(
539 // already inside a problem type creation : no constant for this field
540 contentsOffset = fieldAttributeOffset + 2;
541 // +2 is necessary to keep the two byte space for the attribute number
545 contents[contentsOffset++] = (byte) (stringValueIndex >> 8);
546 contents[contentsOffset++] = (byte) stringValueIndex;
550 if (fieldBinding.isSynthetic()) {
551 int syntheticAttributeNameIndex =
552 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
553 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
554 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
555 // the length of a synthetic attribute is equals to 0
556 contents[contentsOffset++] = 0;
557 contents[contentsOffset++] = 0;
558 contents[contentsOffset++] = 0;
559 contents[contentsOffset++] = 0;
562 if (fieldBinding.isDeprecated()) {
563 int deprecatedAttributeNameIndex =
564 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
565 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
566 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
567 // the length of a deprecated attribute is equals to 0
568 contents[contentsOffset++] = 0;
569 contents[contentsOffset++] = 0;
570 contents[contentsOffset++] = 0;
571 contents[contentsOffset++] = 0;
574 contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8);
575 contents[fieldAttributeOffset] = (byte) attributeNumber;
580 * This methods generate all the fields infos for the receiver.
582 * - a field info for each defined field of that class
583 * - a field info for each synthetic field (e.g. this$0)
585 public void addFieldInfos() {
586 SourceTypeBinding currentBinding = referenceBinding;
587 FieldBinding[] syntheticFields = currentBinding.syntheticFields();
589 currentBinding.fieldCount()
590 + (syntheticFields == null ? 0 : syntheticFields.length);
592 // write the number of fields
593 contents[contentsOffset++] = (byte) (fieldCount >> 8);
594 contents[contentsOffset++] = (byte) fieldCount;
596 FieldBinding[] fieldBindings = currentBinding.fields();
597 for (int i = 0, max = fieldBindings.length; i < max; i++) {
598 addFieldInfo(fieldBindings[i]);
600 if (syntheticFields != null) {
601 for (int i = 0, max = syntheticFields.length; i < max; i++) {
602 addFieldInfo(syntheticFields[i]);
609 * This methods stores the bindings for each inner class. They will be used to know which entries
610 * have to be generated for the inner classes attributes.
611 * @param referenceBinding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
613 public void addInnerClasses(ReferenceBinding referenceBinding) {
614 // check first if that reference binding is there
615 for (int i = 0; i < numberOfInnerClasses; i++) {
616 if (innerClassesBindings[i] == referenceBinding)
619 int length = innerClassesBindings.length;
620 if (numberOfInnerClasses == length) {
622 innerClassesBindings,
624 (innerClassesBindings = new ReferenceBinding[length * 2]),
628 innerClassesBindings[numberOfInnerClasses++] = referenceBinding;
633 * Generate the byte for a problem clinit method info that correspond to a boggus method.
635 * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
637 public void addProblemClinit(IProblem[] problems) {
638 generateMethodInfoHeaderForClinit();
639 // leave two spaces for the number of attributes
641 int attributeOffset = contentsOffset;
643 int attributeNumber = 0;
645 int codeAttributeOffset = contentsOffset;
646 generateCodeAttributeHeader();
647 codeStream.resetForProblemClinit(this);
648 String problemString = "" ; //$NON-NLS-1$
649 if (problems != null) {
650 int max = problems.length;
651 StringBuffer buffer = new StringBuffer(25);
653 for (int i = 0; i < max; i++) {
654 IProblem problem = problems[i];
655 if ((problem != null) && (problem.isError())) {
656 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
658 if (problemLine == 0) {
659 problemLine = problem.getSourceLineNumber();
663 } // insert the top line afterwards, once knowing how many problems we have to consider
665 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
667 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
669 problemString = buffer.toString();
672 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
673 int[] exceptionHandler =
674 codeStream.generateCodeAttributeForProblemMethod(
679 .runtimeExceptionNameForCompileError,
681 attributeNumber++; // code attribute
682 completeCodeAttributeForClinit(
687 .referenceCompilationUnit()
689 .lineSeparatorPositions);
690 contents[attributeOffset++] = (byte) (attributeNumber >> 8);
691 contents[attributeOffset] = (byte) attributeNumber;
696 * Generate the byte for a problem method info that correspond to a boggus constructor.
698 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
699 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
700 * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
702 public void addProblemConstructor(
703 AbstractMethodDeclaration method,
704 MethodBinding methodBinding,
705 IProblem[] problems) {
707 // always clear the strictfp/native/abstract bit for a problem method
708 methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
710 generateMethodInfoHeader(methodBinding);
711 int methodAttributeOffset = contentsOffset;
712 int attributeNumber = generateMethodInfoAttribute(methodBinding);
716 int codeAttributeOffset = contentsOffset;
717 generateCodeAttributeHeader();
718 final ProblemReporter problemReporter = method.scope.problemReporter();
719 codeStream.reset(method, this);
720 String problemString = "" ; //$NON-NLS-1$
721 if (problems != null) {
722 int max = problems.length;
723 StringBuffer buffer = new StringBuffer(25);
725 for (int i = 0; i < max; i++) {
726 IProblem problem = problems[i];
727 if ((problem != null) && (problem.isError())) {
728 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
730 if (problemLine == 0) {
731 problemLine = problem.getSourceLineNumber();
734 } // insert the top line afterwards, once knowing how many problems we have to consider
736 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
738 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
740 problemString = buffer.toString();
743 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
744 int[] exceptionHandler =
745 codeStream.generateCodeAttributeForProblemMethod(
746 problemReporter.options.runtimeExceptionNameForCompileError,
748 completeCodeAttributeForProblemMethod(
753 ((SourceTypeBinding) methodBinding.declaringClass)
755 .referenceCompilationUnit()
757 .lineSeparatorPositions);
758 completeMethodInfo(methodAttributeOffset, attributeNumber);
763 * Generate the byte for a problem method info that correspond to a boggus constructor.
764 * Reset the position inside the contents byte array to the savedOffset.
766 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
767 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
768 * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
769 * @param savedOffset <CODE>int</CODE>
771 public void addProblemConstructor(
772 AbstractMethodDeclaration method,
773 MethodBinding methodBinding,
776 // we need to move back the contentsOffset to the value at the beginning of the method
777 contentsOffset = savedOffset;
778 methodCount--; // we need to remove the method that causes the problem
779 addProblemConstructor(method, methodBinding, problems);
784 * Generate the byte for a problem method info that correspond to a boggus method.
786 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
787 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
788 * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
790 public void addProblemMethod(
791 AbstractMethodDeclaration method,
792 MethodBinding methodBinding,
793 IProblem[] problems) {
794 if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) {
795 method.abort(AbstractMethodDeclaration.AbortType);
797 // always clear the strictfp/native/abstract bit for a problem method
798 methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
800 generateMethodInfoHeader(methodBinding);
801 int methodAttributeOffset = contentsOffset;
802 int attributeNumber = generateMethodInfoAttribute(methodBinding);
807 int codeAttributeOffset = contentsOffset;
808 generateCodeAttributeHeader();
809 final ProblemReporter problemReporter = method.scope.problemReporter();
810 codeStream.reset(method, this);
811 String problemString = "" ; //$NON-NLS-1$
812 if (problems != null) {
813 int max = problems.length;
814 StringBuffer buffer = new StringBuffer(25);
816 for (int i = 0; i < max; i++) {
817 IProblem problem = problems[i];
818 if ((problem != null)
819 && (problem.isError())
820 && (problem.getSourceStart() >= method.declarationSourceStart)
821 && (problem.getSourceEnd() <= method.declarationSourceEnd)) {
822 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
824 if (problemLine == 0) {
825 problemLine = problem.getSourceLineNumber();
829 } // insert the top line afterwards, once knowing how many problems we have to consider
831 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
833 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
835 problemString = buffer.toString();
838 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
839 int[] exceptionHandler =
840 codeStream.generateCodeAttributeForProblemMethod(
841 problemReporter.options.runtimeExceptionNameForCompileError,
843 completeCodeAttributeForProblemMethod(
848 ((SourceTypeBinding) methodBinding.declaringClass)
850 .referenceCompilationUnit()
852 .lineSeparatorPositions);
853 completeMethodInfo(methodAttributeOffset, attributeNumber);
858 * Generate the byte for a problem method info that correspond to a boggus method.
859 * Reset the position inside the contents byte array to the savedOffset.
861 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
862 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
863 * @param problem org.eclipse.jdt.internal.compiler.problem.Problem[]
864 * @param savedOffset <CODE>int</CODE>
866 public void addProblemMethod(
867 AbstractMethodDeclaration method,
868 MethodBinding methodBinding,
871 // we need to move back the contentsOffset to the value at the beginning of the method
872 contentsOffset = savedOffset;
873 methodCount--; // we need to remove the method that causes the problem
874 addProblemMethod(method, methodBinding, problems);
879 * Generate the byte for all the special method infos.
881 * - synthetic access methods
882 * - default abstract methods
884 public void addSpecialMethods() {
885 // add all methods (default abstract methods and synthetic)
887 // default abstract methods
888 SourceTypeBinding currentBinding = referenceBinding;
889 MethodBinding[] defaultAbstractMethods =
890 currentBinding.getDefaultAbstractMethods();
891 for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
892 generateMethodInfoHeader(defaultAbstractMethods[i]);
893 int methodAttributeOffset = contentsOffset;
894 int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
895 completeMethodInfo(methodAttributeOffset, attributeNumber);
897 // add synthetic methods infos
898 SyntheticAccessMethodBinding[] syntheticAccessMethods =
899 currentBinding.syntheticAccessMethods();
900 if (syntheticAccessMethods != null) {
901 for (int i = 0, max = syntheticAccessMethods.length; i < max; i++) {
902 SyntheticAccessMethodBinding accessMethodBinding = syntheticAccessMethods[i];
903 switch (accessMethodBinding.accessType) {
904 case SyntheticAccessMethodBinding.FieldReadAccess :
905 // generate a method info to emulate an reading access to
907 addSyntheticFieldReadAccessMethod(syntheticAccessMethods[i]);
909 case SyntheticAccessMethodBinding.FieldWriteAccess :
910 // generate a method info to emulate an writing access to
912 addSyntheticFieldWriteAccessMethod(syntheticAccessMethods[i]);
914 case SyntheticAccessMethodBinding.MethodAccess :
915 // generate a method info to emulate an access to a private method
916 addSyntheticMethodAccessMethod(syntheticAccessMethods[i]);
918 case SyntheticAccessMethodBinding.ConstructorAccess :
919 // generate a method info to emulate an access to a private method
920 addSyntheticConstructorAccessMethod(syntheticAccessMethods[i]);
928 * Generate the byte for problem method infos that correspond to missing abstract methods.
929 * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179
931 * @param methodDeclarations Array of all missing abstract methods
933 public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) {
934 if (methodDeclarations != null) {
935 for (int i = 0, max = methodDeclarations.length; i < max; i++) {
936 MethodDeclaration methodDeclaration = methodDeclarations[i];
937 MethodBinding methodBinding = methodDeclaration.binding;
938 String readableName = new String(methodBinding.readableName());
939 IProblem[] problems = compilationResult.problems;
940 int problemsCount = compilationResult.problemCount;
941 for (int j = 0; j < problemsCount; j++) {
942 IProblem problem = problems[j];
944 && problem.getID() == IProblem.AbstractMethodMustBeImplemented
945 && problem.getMessage().indexOf(readableName) != -1) {
947 addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult);
954 private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, IProblem problem, CompilationResult compilationResult) {
955 // always clear the strictfp/native/abstract bit for a problem method
956 methodBinding.modifiers &= ~(AccStrictfp | AccNative | AccAbstract);
958 generateMethodInfoHeader(methodBinding);
959 int methodAttributeOffset = contentsOffset;
960 int attributeNumber = generateMethodInfoAttribute(methodBinding);
965 int codeAttributeOffset = contentsOffset;
966 generateCodeAttributeHeader();
967 StringBuffer buffer = new StringBuffer(25);
968 buffer.append("\t" + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
969 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
970 String problemString = buffer.toString();
971 this.problemLine = problem.getSourceLineNumber();
973 final ProblemReporter problemReporter = methodDeclaration.scope.problemReporter();
974 codeStream.init(this);
975 codeStream.preserveUnusedLocals = true;
976 codeStream.initializeMaxLocals(methodBinding);
978 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
979 int[] exceptionHandler =
980 codeStream.generateCodeAttributeForProblemMethod(
981 problemReporter.options.runtimeExceptionNameForCompileError,
984 completeCodeAttributeForMissingAbstractProblemMethod(
988 compilationResult.lineSeparatorPositions);
990 completeMethodInfo(methodAttributeOffset, attributeNumber);
996 public void completeCodeAttributeForMissingAbstractProblemMethod(
997 MethodBinding binding,
998 int codeAttributeOffset,
999 int[] exceptionHandler,
1000 int[] startLineIndexes) {
1001 // reinitialize the localContents with the byte modified by the code stream
1002 byte[] localContents = contents = codeStream.bCodeStream;
1003 int localContentsOffset = codeStream.classFileOffset;
1004 // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
1005 int max_stack = codeStream.stackMax;
1006 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1007 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1008 int max_locals = codeStream.maxLocals;
1009 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1010 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1011 int code_length = codeStream.position;
1012 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1013 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1014 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1015 localContents[codeAttributeOffset + 13] = (byte) code_length;
1016 // write the exception table
1018 if (localContentsOffset + 50 >= (contentsLength = localContents.length)) {
1022 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1026 localContents[localContentsOffset++] = 0;
1027 localContents[localContentsOffset++] = 1;
1028 int start = exceptionHandler[0];
1029 localContents[localContentsOffset++] = (byte) (start >> 8);
1030 localContents[localContentsOffset++] = (byte) start;
1031 int end = exceptionHandler[1];
1032 localContents[localContentsOffset++] = (byte) (end >> 8);
1033 localContents[localContentsOffset++] = (byte) end;
1034 int handlerPC = exceptionHandler[2];
1035 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1036 localContents[localContentsOffset++] = (byte) handlerPC;
1037 int nameIndex = constantPool.literalIndexForJavaLangException();
1038 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1039 localContents[localContentsOffset++] = (byte) nameIndex; // debug attributes
1040 int codeAttributeAttributeOffset = localContentsOffset;
1041 int attributeNumber = 0; // leave two bytes for the attribute_length
1042 localContentsOffset += 2; // first we handle the linenumber attribute
1044 if (codeStream.generateLineNumberAttributes) {
1045 /* Create and add the line number attribute (used for debugging)
1046 * Build the pairs of:
1047 * (bytecodePC lineNumber)
1048 * according to the table of start line indexes and the pcToSourceMap table
1049 * contained into the codestream
1051 int lineNumberNameIndex =
1052 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1053 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1054 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1055 localContents[localContentsOffset++] = 0;
1056 localContents[localContentsOffset++] = 0;
1057 localContents[localContentsOffset++] = 0;
1058 localContents[localContentsOffset++] = 6;
1059 localContents[localContentsOffset++] = 0;
1060 localContents[localContentsOffset++] = 1;
1061 if (problemLine == 0) {
1062 problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
1064 // first entry at pc = 0
1065 localContents[localContentsOffset++] = 0;
1066 localContents[localContentsOffset++] = 0;
1067 localContents[localContentsOffset++] = (byte) (problemLine >> 8);
1068 localContents[localContentsOffset++] = (byte) problemLine;
1069 // now we change the size of the line number attribute
1073 // then we do the local variable attribute
1074 // update the number of attributes// ensure first that there is enough space available inside the localContents array
1075 if (codeAttributeAttributeOffset + 2
1076 >= (contentsLength = localContents.length)) {
1080 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1084 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1085 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1086 // update the attribute length
1087 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1088 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1089 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1090 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1091 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1092 contentsOffset = localContentsOffset;
1097 * Generate the byte for a problem method info that correspond to a synthetic method that
1098 * generate an access to a private constructor.
1100 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1102 public void addSyntheticConstructorAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1103 generateMethodInfoHeader(methodBinding);
1104 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1105 contents[contentsOffset++] = 0;
1106 contents[contentsOffset++] = 2;
1108 int codeAttributeOffset = contentsOffset;
1109 generateCodeAttributeHeader();
1110 codeStream.init(this);
1111 codeStream.generateSyntheticBodyForConstructorAccess(methodBinding);
1112 completeCodeAttributeForSyntheticAccessMethod(
1114 codeAttributeOffset,
1115 ((SourceTypeBinding) methodBinding.declaringClass)
1117 .referenceCompilationUnit()
1119 .lineSeparatorPositions);
1120 // add the synthetic attribute
1121 int syntheticAttributeNameIndex =
1122 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1123 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1124 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1125 // the length of a synthetic attribute is equals to 0
1126 contents[contentsOffset++] = 0;
1127 contents[contentsOffset++] = 0;
1128 contents[contentsOffset++] = 0;
1129 contents[contentsOffset++] = 0;
1134 * Generate the byte for a problem method info that correspond to a synthetic method that
1135 * generate an read access to a private field.
1137 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1139 public void addSyntheticFieldReadAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1140 generateMethodInfoHeader(methodBinding);
1141 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1142 contents[contentsOffset++] = 0;
1143 contents[contentsOffset++] = 2;
1145 int codeAttributeOffset = contentsOffset;
1146 generateCodeAttributeHeader();
1147 codeStream.init(this);
1148 codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding);
1149 completeCodeAttributeForSyntheticAccessMethod(
1151 codeAttributeOffset,
1152 ((SourceTypeBinding) methodBinding.declaringClass)
1154 .referenceCompilationUnit()
1156 .lineSeparatorPositions);
1157 // add the synthetic attribute
1158 int syntheticAttributeNameIndex =
1159 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1160 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1161 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1162 // the length of a synthetic attribute is equals to 0
1163 contents[contentsOffset++] = 0;
1164 contents[contentsOffset++] = 0;
1165 contents[contentsOffset++] = 0;
1166 contents[contentsOffset++] = 0;
1171 * Generate the byte for a problem method info that correspond to a synthetic method that
1172 * generate an write access to a private field.
1174 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1176 public void addSyntheticFieldWriteAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1177 generateMethodInfoHeader(methodBinding);
1178 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1179 contents[contentsOffset++] = 0;
1180 contents[contentsOffset++] = 2;
1182 int codeAttributeOffset = contentsOffset;
1183 generateCodeAttributeHeader();
1184 codeStream.init(this);
1185 codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding);
1186 completeCodeAttributeForSyntheticAccessMethod(
1188 codeAttributeOffset,
1189 ((SourceTypeBinding) methodBinding.declaringClass)
1191 .referenceCompilationUnit()
1193 .lineSeparatorPositions);
1194 // add the synthetic attribute
1195 int syntheticAttributeNameIndex =
1196 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1197 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1198 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1199 // the length of a synthetic attribute is equals to 0
1200 contents[contentsOffset++] = 0;
1201 contents[contentsOffset++] = 0;
1202 contents[contentsOffset++] = 0;
1203 contents[contentsOffset++] = 0;
1208 * Generate the byte for a problem method info that correspond to a synthetic method that
1209 * generate an access to a private method.
1211 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1213 public void addSyntheticMethodAccessMethod(SyntheticAccessMethodBinding methodBinding) {
1214 generateMethodInfoHeader(methodBinding);
1215 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1216 contents[contentsOffset++] = 0;
1217 contents[contentsOffset++] = 2;
1219 int codeAttributeOffset = contentsOffset;
1220 generateCodeAttributeHeader();
1221 codeStream.init(this);
1222 codeStream.generateSyntheticBodyForMethodAccess(methodBinding);
1223 completeCodeAttributeForSyntheticAccessMethod(
1225 codeAttributeOffset,
1226 ((SourceTypeBinding) methodBinding.declaringClass)
1228 .referenceCompilationUnit()
1230 .lineSeparatorPositions);
1231 // add the synthetic attribute
1232 int syntheticAttributeNameIndex =
1233 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1234 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1235 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1236 // the length of a synthetic attribute is equals to 0
1237 contents[contentsOffset++] = 0;
1238 contents[contentsOffset++] = 0;
1239 contents[contentsOffset++] = 0;
1240 contents[contentsOffset++] = 0;
1245 * Build all the directories and subdirectories corresponding to the packages names
1246 * into the directory specified in parameters.
1248 * outputPath is formed like:
1249 * c:\temp\ the last character is a file separator
1250 * relativeFileName is formed like:
1251 * java\lang\String.class *
1253 * @param outputPath java.lang.String
1254 * @param relativeFileName java.lang.String
1255 * @return java.lang.String
1257 public static String buildAllDirectoriesInto(
1259 String relativeFileName)
1260 throws IOException {
1261 char fileSeparatorChar = File.separatorChar;
1262 String fileSeparator = File.separator;
1264 // First we ensure that the outputPath exists
1265 outputPath = outputPath.replace('/', fileSeparatorChar);
1266 // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
1267 if (outputPath.endsWith(fileSeparator)) {
1268 outputPath = outputPath.substring(0, outputPath.length() - 1);
1270 f = new File(outputPath);
1272 if (!f.isDirectory()) {
1273 System.out.println(Util.bind("output.isFile" , f.getAbsolutePath())); //$NON-NLS-1$
1274 throw new IOException(Util.bind("output.isFileNotDirectory" )); //$NON-NLS-1$
1277 // we have to create that directory
1279 System.out.println(Util.bind("output.dirName" , f.getAbsolutePath())); //$NON-NLS-1$
1280 throw new IOException(Util.bind("output.notValidAll" )); //$NON-NLS-1$
1283 StringBuffer outDir = new StringBuffer(outputPath);
1284 outDir.append(fileSeparator);
1285 StringTokenizer tokenizer =
1286 new StringTokenizer(relativeFileName, fileSeparator);
1287 String token = tokenizer.nextToken();
1288 while (tokenizer.hasMoreTokens()) {
1289 f = new File(outDir.append(token).append(fileSeparator).toString());
1291 // The outDir already exists, so we proceed the next entry
1292 // System.out.println("outDir: " + outDir + " already exists.");
1294 // Need to add the outDir
1296 System.out.println(Util.bind("output.fileName" , f.getName())); //$NON-NLS-1$
1297 throw new IOException(Util.bind("output.notValid" )); //$NON-NLS-1$
1300 token = tokenizer.nextToken();
1302 // token contains the last one
1303 return outDir.append(token).toString();
1308 * That method completes the creation of the code attribute by setting
1309 * - the attribute_length
1314 * - and debug attributes if necessary.
1316 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1317 * @param codeAttributeOffset <CODE>int</CODE>
1319 public void completeCodeAttribute(int codeAttributeOffset) {
1320 // reinitialize the localContents with the byte modified by the code stream
1321 byte[] localContents = contents = codeStream.bCodeStream;
1322 int localContentsOffset = codeStream.classFileOffset;
1323 // codeAttributeOffset is the position inside localContents byte array before we started to write
1324 // any information about the codeAttribute
1325 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1326 // to get the right position, 6 for the max_stack etc...
1328 int code_length = codeStream.position;
1329 if (code_length > 65535) {
1330 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1331 codeStream.methodDeclaration);
1333 if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
1337 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1341 int max_stack = codeStream.stackMax;
1342 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1343 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1344 int max_locals = codeStream.maxLocals;
1345 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1346 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1347 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1348 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1349 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1350 localContents[codeAttributeOffset + 13] = (byte) code_length;
1352 // write the exception table
1353 int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
1354 ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
1356 if (localContentsOffset + (exSize = (exceptionHandlersNumber * 8 + 2))
1357 >= (contentsLength = localContents.length)) {
1363 new byte[contentsLength + (exSize > INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
1367 // there is no exception table, so we need to offset by 2 the current offset and move
1368 // on the attribute generation
1369 localContents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
1370 localContents[localContentsOffset++] = (byte) exceptionHandlersNumber;
1371 for (int i = 0; i < exceptionHandlersNumber; i++) {
1372 ExceptionLabel exceptionHandler = exceptionHandlers[i];
1373 int start = exceptionHandler.start;
1374 localContents[localContentsOffset++] = (byte) (start >> 8);
1375 localContents[localContentsOffset++] = (byte) start;
1376 int end = exceptionHandler.end;
1377 localContents[localContentsOffset++] = (byte) (end >> 8);
1378 localContents[localContentsOffset++] = (byte) end;
1379 int handlerPC = exceptionHandler.position;
1380 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1381 localContents[localContentsOffset++] = (byte) handlerPC;
1382 if (exceptionHandler.exceptionType == null) {
1383 // any exception handler
1384 localContents[localContentsOffset++] = 0;
1385 localContents[localContentsOffset++] = 0;
1388 if (exceptionHandler.exceptionType == TypeBinding.NullBinding) {
1389 /* represents ClassNotFoundException, see class literal access*/
1390 nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
1392 nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
1394 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1395 localContents[localContentsOffset++] = (byte) nameIndex;
1399 int codeAttributeAttributeOffset = localContentsOffset;
1400 int attributeNumber = 0;
1401 // leave two bytes for the attribute_length
1402 localContentsOffset += 2;
1404 // first we handle the linenumber attribute
1405 if (codeStream.generateLineNumberAttributes) {
1406 /* Create and add the line number attribute (used for debugging)
1407 * Build the pairs of:
1408 * (bytecodePC lineNumber)
1409 * according to the table of start line indexes and the pcToSourceMap table
1410 * contained into the codestream
1412 int[] pcToSourceMapTable;
1413 if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
1414 && (codeStream.pcToSourceMapSize != 0)) {
1415 int lineNumberNameIndex =
1416 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1417 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1421 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1425 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1426 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1427 int lineNumberTableOffset = localContentsOffset;
1428 localContentsOffset += 6;
1429 // leave space for attribute_length and line_number_table_length
1430 int numberOfEntries = 0;
1431 int length = codeStream.pcToSourceMapSize;
1432 for (int i = 0; i < length;) {
1434 if (localContentsOffset + 4 >= (contentsLength = localContents.length)) {
1438 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1442 int pc = pcToSourceMapTable[i++];
1443 localContents[localContentsOffset++] = (byte) (pc >> 8);
1444 localContents[localContentsOffset++] = (byte) pc;
1445 int lineNumber = pcToSourceMapTable[i++];
1446 localContents[localContentsOffset++] = (byte) (lineNumber >> 8);
1447 localContents[localContentsOffset++] = (byte) lineNumber;
1450 // now we change the size of the line number attribute
1451 int lineNumberAttr_length = numberOfEntries * 4 + 2;
1452 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
1453 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
1454 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
1455 localContents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
1456 localContents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
1457 localContents[lineNumberTableOffset++] = (byte) numberOfEntries;
1461 // then we do the local variable attribute
1462 if (codeStream.generateLocalVariableTableAttributes) {
1463 int localVariableTableOffset = localContentsOffset;
1464 int numberOfEntries = 0;
1465 int localVariableNameIndex =
1466 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1467 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1471 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1475 localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1476 localContents[localContentsOffset++] = (byte) localVariableNameIndex;
1477 localContentsOffset += 6;
1478 // leave space for attribute_length and local_variable_table_length
1480 int descriptorIndex;
1481 if (!codeStream.methodDeclaration.isStatic()) {
1483 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
1487 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1491 localContentsOffset += 2; // the startPC for this is always 0
1492 localContents[localContentsOffset++] = (byte) (code_length >> 8);
1493 localContents[localContentsOffset++] = (byte) code_length;
1494 nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
1495 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1496 localContents[localContentsOffset++] = (byte) nameIndex;
1498 constantPool.literalIndex(
1499 codeStream.methodDeclaration.binding.declaringClass.signature());
1500 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1501 localContents[localContentsOffset++] = (byte) descriptorIndex;
1502 localContentsOffset += 2; // the resolved position for this is always 0
1504 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
1505 LocalVariableBinding localVariable = codeStream.locals[i];
1506 for (int j = 0; j < localVariable.initializationCount; j++) {
1507 int startPC = localVariable.initializationPCs[j << 1];
1508 int endPC = localVariable.initializationPCs[(j << 1) + 1];
1509 if (startPC != endPC) { // only entries for non zero length
1511 localVariable.declaringScope.problemReporter().abortDueToInternalError(
1512 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
1513 (AstNode) localVariable.declaringScope.methodScope().referenceContext);
1515 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
1519 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1523 // now we can safely add the local entry
1525 localContents[localContentsOffset++] = (byte) (startPC >> 8);
1526 localContents[localContentsOffset++] = (byte) startPC;
1527 int length = endPC - startPC;
1528 localContents[localContentsOffset++] = (byte) (length >> 8);
1529 localContents[localContentsOffset++] = (byte) length;
1530 nameIndex = constantPool.literalIndex(localVariable.name);
1531 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1532 localContents[localContentsOffset++] = (byte) nameIndex;
1533 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
1534 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1535 localContents[localContentsOffset++] = (byte) descriptorIndex;
1536 int resolvedPosition = localVariable.resolvedPosition;
1537 localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1538 localContents[localContentsOffset++] = (byte) resolvedPosition;
1542 int value = numberOfEntries * 10 + 2;
1543 localVariableTableOffset += 2;
1544 localContents[localVariableTableOffset++] = (byte) (value >> 24);
1545 localContents[localVariableTableOffset++] = (byte) (value >> 16);
1546 localContents[localVariableTableOffset++] = (byte) (value >> 8);
1547 localContents[localVariableTableOffset++] = (byte) value;
1548 localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1549 localContents[localVariableTableOffset] = (byte) numberOfEntries;
1552 // update the number of attributes
1553 // ensure first that there is enough space available inside the localContents array
1554 if (codeAttributeAttributeOffset + 2
1555 >= (contentsLength = localContents.length)) {
1559 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1563 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1564 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1566 // update the attribute length
1567 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1568 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1569 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1570 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1571 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1572 contentsOffset = localContentsOffset;
1577 * That method completes the creation of the code attribute by setting
1578 * - the attribute_length
1583 * - and debug attributes if necessary.
1585 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1586 * @param codeAttributeOffset <CODE>int</CODE>
1588 public void completeCodeAttributeForClinit(int codeAttributeOffset) {
1589 // reinitialize the contents with the byte modified by the code stream
1590 byte[] localContents = contents = codeStream.bCodeStream;
1591 int localContentsOffset = codeStream.classFileOffset;
1592 // codeAttributeOffset is the position inside contents byte array before we started to write
1593 // any information about the codeAttribute
1594 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1595 // to get the right position, 6 for the max_stack etc...
1597 int code_length = codeStream.position;
1598 if (code_length > 65535) {
1599 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1600 codeStream.methodDeclaration.scope.referenceType());
1602 if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
1606 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1610 int max_stack = codeStream.stackMax;
1611 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1612 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1613 int max_locals = codeStream.maxLocals;
1614 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1615 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1616 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1617 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1618 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1619 localContents[codeAttributeOffset + 13] = (byte) code_length;
1621 // write the exception table
1622 int exceptionHandlersNumber = codeStream.exceptionHandlersNumber;
1623 ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
1625 if (localContentsOffset + (exSize = (exceptionHandlersNumber * 8 + 2))
1626 >= (contentsLength = localContents.length)) {
1632 new byte[contentsLength + (exSize > INCREMENT_SIZE ? exSize : INCREMENT_SIZE)]),
1636 // there is no exception table, so we need to offset by 2 the current offset and move
1637 // on the attribute generation
1638 localContents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
1639 localContents[localContentsOffset++] = (byte) exceptionHandlersNumber;
1640 for (int i = 0; i < exceptionHandlersNumber; i++) {
1641 ExceptionLabel exceptionHandler = exceptionHandlers[i];
1642 int start = exceptionHandler.start;
1643 localContents[localContentsOffset++] = (byte) (start >> 8);
1644 localContents[localContentsOffset++] = (byte) start;
1645 int end = exceptionHandler.end;
1646 localContents[localContentsOffset++] = (byte) (end >> 8);
1647 localContents[localContentsOffset++] = (byte) end;
1648 int handlerPC = exceptionHandler.position;
1649 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1650 localContents[localContentsOffset++] = (byte) handlerPC;
1651 if (exceptionHandler.exceptionType == null) {
1652 // any exception handler
1653 localContentsOffset += 2;
1656 if (exceptionHandler.exceptionType == TypeBinding.NullBinding) {
1657 /* represents denote ClassNotFoundException, see class literal access*/
1658 nameIndex = constantPool.literalIndexForJavaLangClassNotFoundException();
1660 nameIndex = constantPool.literalIndex(exceptionHandler.exceptionType);
1662 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1663 localContents[localContentsOffset++] = (byte) nameIndex;
1667 int codeAttributeAttributeOffset = localContentsOffset;
1668 int attributeNumber = 0;
1669 // leave two bytes for the attribute_length
1670 localContentsOffset += 2;
1672 // first we handle the linenumber attribute
1673 if (codeStream.generateLineNumberAttributes) {
1674 /* Create and add the line number attribute (used for debugging)
1675 * Build the pairs of:
1676 * (bytecodePC lineNumber)
1677 * according to the table of start line indexes and the pcToSourceMap table
1678 * contained into the codestream
1680 int[] pcToSourceMapTable;
1681 if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
1682 && (codeStream.pcToSourceMapSize != 0)) {
1683 int lineNumberNameIndex =
1684 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1685 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1689 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1693 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1694 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1695 int lineNumberTableOffset = localContentsOffset;
1696 localContentsOffset += 6;
1697 // leave space for attribute_length and line_number_table_length
1698 int numberOfEntries = 0;
1699 int length = codeStream.pcToSourceMapSize;
1700 for (int i = 0; i < length;) {
1702 if (localContentsOffset + 4 >= (contentsLength = localContents.length)) {
1706 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1710 int pc = pcToSourceMapTable[i++];
1711 localContents[localContentsOffset++] = (byte) (pc >> 8);
1712 localContents[localContentsOffset++] = (byte) pc;
1713 int lineNumber = pcToSourceMapTable[i++];
1714 localContents[localContentsOffset++] = (byte) (lineNumber >> 8);
1715 localContents[localContentsOffset++] = (byte) lineNumber;
1718 // now we change the size of the line number attribute
1719 int lineNumberAttr_length = numberOfEntries * 4 + 2;
1720 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
1721 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
1722 localContents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
1723 localContents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
1724 localContents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
1725 localContents[lineNumberTableOffset++] = (byte) numberOfEntries;
1729 // then we do the local variable attribute
1730 if (codeStream.generateLocalVariableTableAttributes) {
1731 int localVariableTableOffset = localContentsOffset;
1732 int numberOfEntries = 0;
1733 // codeAttribute.addLocalVariableTableAttribute(this);
1734 if ((codeStream.pcToSourceMap != null)
1735 && (codeStream.pcToSourceMapSize != 0)) {
1736 int localVariableNameIndex =
1737 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1738 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1742 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1746 localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1747 localContents[localContentsOffset++] = (byte) localVariableNameIndex;
1748 localContentsOffset += 6;
1749 // leave space for attribute_length and local_variable_table_length
1751 int descriptorIndex;
1752 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
1753 LocalVariableBinding localVariable = codeStream.locals[i];
1754 for (int j = 0; j < localVariable.initializationCount; j++) {
1755 int startPC = localVariable.initializationPCs[j << 1];
1756 int endPC = localVariable.initializationPCs[(j << 1) + 1];
1757 if (startPC != endPC) { // only entries for non zero length
1759 localVariable.declaringScope.problemReporter().abortDueToInternalError(
1760 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
1761 (AstNode) localVariable.declaringScope.methodScope().referenceContext);
1763 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
1767 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1771 // now we can safely add the local entry
1773 localContents[localContentsOffset++] = (byte) (startPC >> 8);
1774 localContents[localContentsOffset++] = (byte) startPC;
1775 int length = endPC - startPC;
1776 localContents[localContentsOffset++] = (byte) (length >> 8);
1777 localContents[localContentsOffset++] = (byte) length;
1778 nameIndex = constantPool.literalIndex(localVariable.name);
1779 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1780 localContents[localContentsOffset++] = (byte) nameIndex;
1781 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
1782 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1783 localContents[localContentsOffset++] = (byte) descriptorIndex;
1784 int resolvedPosition = localVariable.resolvedPosition;
1785 localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1786 localContents[localContentsOffset++] = (byte) resolvedPosition;
1790 int value = numberOfEntries * 10 + 2;
1791 localVariableTableOffset += 2;
1792 localContents[localVariableTableOffset++] = (byte) (value >> 24);
1793 localContents[localVariableTableOffset++] = (byte) (value >> 16);
1794 localContents[localVariableTableOffset++] = (byte) (value >> 8);
1795 localContents[localVariableTableOffset++] = (byte) value;
1796 localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1797 localContents[localVariableTableOffset] = (byte) numberOfEntries;
1801 // update the number of attributes
1802 // ensure first that there is enough space available inside the contents array
1803 if (codeAttributeAttributeOffset + 2
1804 >= (contentsLength = localContents.length)) {
1808 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1812 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1813 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1814 // update the attribute length
1815 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1816 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1817 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1818 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1819 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1820 contentsOffset = localContentsOffset;
1825 * That method completes the creation of the code attribute by setting
1826 * - the attribute_length
1831 * - and debug attributes if necessary.
1833 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1834 * @param codeAttributeOffset <CODE>int</CODE>
1835 * @param exceptionHandler int[]
1836 * @param startIndexes int[]
1838 public void completeCodeAttributeForClinit(
1839 int codeAttributeOffset,
1840 int[] exceptionHandler,
1841 int[] startLineIndexes) {
1842 // reinitialize the contents with the byte modified by the code stream
1843 byte[] localContents = contents = codeStream.bCodeStream;
1844 int localContentsOffset = codeStream.classFileOffset;
1845 // codeAttributeOffset is the position inside contents byte array before we started to write
1846 // any information about the codeAttribute
1847 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1848 // to get the right position, 6 for the max_stack etc...
1850 int code_length = codeStream.position;
1851 if (code_length > 65535) {
1852 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1853 codeStream.methodDeclaration.scope.referenceType());
1855 if (localContentsOffset + 20 >= (contentsLength = localContents.length)) {
1859 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1863 int max_stack = codeStream.stackMax;
1864 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1865 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1866 int max_locals = codeStream.maxLocals;
1867 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1868 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1869 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1870 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1871 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1872 localContents[codeAttributeOffset + 13] = (byte) code_length;
1874 // write the exception table
1875 localContents[localContentsOffset++] = 0;
1876 localContents[localContentsOffset++] = 1;
1877 int start = exceptionHandler[0];
1878 localContents[localContentsOffset++] = (byte) (start >> 8);
1879 localContents[localContentsOffset++] = (byte) start;
1880 int end = exceptionHandler[1];
1881 localContents[localContentsOffset++] = (byte) (end >> 8);
1882 localContents[localContentsOffset++] = (byte) end;
1883 int handlerPC = exceptionHandler[2];
1884 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
1885 localContents[localContentsOffset++] = (byte) handlerPC;
1886 int nameIndex = constantPool.literalIndexForJavaLangException();
1887 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
1888 localContents[localContentsOffset++] = (byte) nameIndex;
1891 int codeAttributeAttributeOffset = localContentsOffset;
1892 int attributeNumber = 0; // leave two bytes for the attribute_length
1893 localContentsOffset += 2; // first we handle the linenumber attribute
1895 // first we handle the linenumber attribute
1896 if (codeStream.generateLineNumberAttributes) {
1897 /* Create and add the line number attribute (used for debugging)
1898 * Build the pairs of:
1899 * (bytecodePC lineNumber)
1900 * according to the table of start line indexes and the pcToSourceMap table
1901 * contained into the codestream
1903 int lineNumberNameIndex =
1904 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1905 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1906 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
1907 localContents[localContentsOffset++] = 0;
1908 localContents[localContentsOffset++] = 0;
1909 localContents[localContentsOffset++] = 0;
1910 localContents[localContentsOffset++] = 6;
1911 localContents[localContentsOffset++] = 0;
1912 localContents[localContentsOffset++] = 1;
1913 // first entry at pc = 0
1914 localContents[localContentsOffset++] = 0;
1915 localContents[localContentsOffset++] = 0;
1916 localContents[localContentsOffset++] = (byte) (problemLine >> 8);
1917 localContents[localContentsOffset++] = (byte) problemLine;
1918 // now we change the size of the line number attribute
1921 // then we do the local variable attribute
1922 if (codeStream.generateLocalVariableTableAttributes) {
1923 int localVariableNameIndex =
1924 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1925 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
1929 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1933 localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1934 localContents[localContentsOffset++] = (byte) localVariableNameIndex;
1935 localContents[localContentsOffset++] = 0;
1936 localContents[localContentsOffset++] = 0;
1937 localContents[localContentsOffset++] = 0;
1938 localContents[localContentsOffset++] = 2;
1939 localContents[localContentsOffset++] = 0;
1940 localContents[localContentsOffset++] = 0;
1943 // update the number of attributes
1944 // ensure first that there is enough space available inside the contents array
1945 if (codeAttributeAttributeOffset + 2
1946 >= (contentsLength = localContents.length)) {
1950 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
1954 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1955 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1956 // update the attribute length
1957 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1958 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1959 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1960 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1961 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1962 contentsOffset = localContentsOffset;
1967 * That method completes the creation of the code attribute by setting
1968 * - the attribute_length
1973 * - and debug attributes if necessary.
1975 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
1976 * @param codeAttributeOffset <CODE>int</CODE>
1977 * @param exceptionHandler int[]
1979 public void completeCodeAttributeForProblemMethod(
1980 AbstractMethodDeclaration method,
1981 MethodBinding binding,
1982 int codeAttributeOffset,
1983 int[] exceptionHandler,
1984 int[] startLineIndexes) {
1985 // reinitialize the localContents with the byte modified by the code stream
1986 byte[] localContents = contents = codeStream.bCodeStream;
1987 int localContentsOffset = codeStream.classFileOffset;
1988 // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc...
1989 int max_stack = codeStream.stackMax;
1990 localContents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1991 localContents[codeAttributeOffset + 7] = (byte) max_stack;
1992 int max_locals = codeStream.maxLocals;
1993 localContents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1994 localContents[codeAttributeOffset + 9] = (byte) max_locals;
1995 int code_length = codeStream.position;
1996 localContents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1997 localContents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1998 localContents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1999 localContents[codeAttributeOffset + 13] = (byte) code_length;
2000 // write the exception table
2002 if (localContentsOffset + 50 >= (contentsLength = localContents.length)) {
2006 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2010 localContents[localContentsOffset++] = 0;
2011 localContents[localContentsOffset++] = 1;
2012 int start = exceptionHandler[0];
2013 localContents[localContentsOffset++] = (byte) (start >> 8);
2014 localContents[localContentsOffset++] = (byte) start;
2015 int end = exceptionHandler[1];
2016 localContents[localContentsOffset++] = (byte) (end >> 8);
2017 localContents[localContentsOffset++] = (byte) end;
2018 int handlerPC = exceptionHandler[2];
2019 localContents[localContentsOffset++] = (byte) (handlerPC >> 8);
2020 localContents[localContentsOffset++] = (byte) handlerPC;
2021 int nameIndex = constantPool.literalIndexForJavaLangException();
2022 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2023 localContents[localContentsOffset++] = (byte) nameIndex; // debug attributes
2024 int codeAttributeAttributeOffset = localContentsOffset;
2025 int attributeNumber = 0; // leave two bytes for the attribute_length
2026 localContentsOffset += 2; // first we handle the linenumber attribute
2028 if (codeStream.generateLineNumberAttributes) {
2029 /* Create and add the line number attribute (used for debugging)
2030 * Build the pairs of:
2031 * (bytecodePC lineNumber)
2032 * according to the table of start line indexes and the pcToSourceMap table
2033 * contained into the codestream
2035 int lineNumberNameIndex =
2036 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
2037 localContents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
2038 localContents[localContentsOffset++] = (byte) lineNumberNameIndex;
2039 localContents[localContentsOffset++] = 0;
2040 localContents[localContentsOffset++] = 0;
2041 localContents[localContentsOffset++] = 0;
2042 localContents[localContentsOffset++] = 6;
2043 localContents[localContentsOffset++] = 0;
2044 localContents[localContentsOffset++] = 1;
2045 if (problemLine == 0) {
2046 problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
2048 // first entry at pc = 0
2049 localContents[localContentsOffset++] = 0;
2050 localContents[localContentsOffset++] = 0;
2051 localContents[localContentsOffset++] = (byte) (problemLine >> 8);
2052 localContents[localContentsOffset++] = (byte) problemLine;
2053 // now we change the size of the line number attribute
2056 // then we do the local variable attribute
2057 if (codeStream.generateLocalVariableTableAttributes) {
2058 // compute the resolved position for the arguments of the method
2060 int localVariableTableOffset = localContentsOffset;
2061 int numberOfEntries = 0;
2062 // codeAttribute.addLocalVariableTableAttribute(this);
2063 int localVariableNameIndex =
2064 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
2065 if (localContentsOffset + 8 >= (contentsLength = localContents.length)) {
2069 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2073 localContents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
2074 localContents[localContentsOffset++] = (byte) localVariableNameIndex;
2075 localContentsOffset += 6;
2076 // leave space for attribute_length and local_variable_table_length
2077 int descriptorIndex;
2078 if (!codeStream.methodDeclaration.isStatic()) {
2080 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
2084 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2088 localContents[localContentsOffset++] = 0;
2089 localContents[localContentsOffset++] = 0;
2090 localContents[localContentsOffset++] = (byte) (code_length >> 8);
2091 localContents[localContentsOffset++] = (byte) code_length;
2092 nameIndex = constantPool.literalIndex(QualifiedNamesConstants.This);
2093 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2094 localContents[localContentsOffset++] = (byte) nameIndex;
2096 constantPool.literalIndex(
2097 codeStream.methodDeclaration.binding.declaringClass.signature());
2098 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2099 localContents[localContentsOffset++] = (byte) descriptorIndex;
2100 // the resolved position for this is always 0
2101 localContents[localContentsOffset++] = 0;
2102 localContents[localContentsOffset++] = 0;
2104 if (binding.isConstructor()) {
2105 ReferenceBinding declaringClass = binding.declaringClass;
2106 if (declaringClass.isNestedType()) {
2107 NestedTypeBinding methodDeclaringClass = (NestedTypeBinding) declaringClass;
2108 argSize = methodDeclaringClass.syntheticArgumentsOffset;
2109 SyntheticArgumentBinding[] syntheticArguments;
2110 if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances())
2112 for (int i = 0, max = syntheticArguments.length; i < max; i++) {
2113 LocalVariableBinding localVariable = syntheticArguments[i];
2114 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
2118 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2122 // now we can safely add the local entry
2124 localContents[localContentsOffset++] = 0;
2125 localContents[localContentsOffset++] = 0;
2126 localContents[localContentsOffset++] = (byte) (code_length >> 8);
2127 localContents[localContentsOffset++] = (byte) code_length;
2128 nameIndex = constantPool.literalIndex(localVariable.name);
2129 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2130 localContents[localContentsOffset++] = (byte) nameIndex;
2131 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
2132 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2133 localContents[localContentsOffset++] = (byte) descriptorIndex;
2134 int resolvedPosition = localVariable.resolvedPosition;
2135 localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2136 localContents[localContentsOffset++] = (byte) resolvedPosition;
2143 argSize = binding.isStatic() ? 0 : 1;
2145 if (method.binding != null) {
2146 TypeBinding[] parameters = method.binding.parameters;
2147 Argument[] arguments = method.arguments;
2148 if ((parameters != null) && (arguments != null)) {
2149 for (int i = 0, max = parameters.length; i < max; i++) {
2150 TypeBinding argumentBinding = parameters[i];
2151 if (localContentsOffset + 10 >= (contentsLength = localContents.length)) {
2155 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2159 // now we can safely add the local entry
2161 localContents[localContentsOffset++] = 0;
2162 localContents[localContentsOffset++] = 0;
2163 localContents[localContentsOffset++] = (byte) (code_length >> 8);
2164 localContents[localContentsOffset++] = (byte) code_length;
2165 nameIndex = constantPool.literalIndex(arguments[i].name);
2166 localContents[localContentsOffset++] = (byte) (nameIndex >> 8);
2167 localContents[localContentsOffset++] = (byte) nameIndex;
2168 descriptorIndex = constantPool.literalIndex(argumentBinding.signature());
2169 localContents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2170 localContents[localContentsOffset++] = (byte) descriptorIndex;
2171 int resolvedPosition = argSize;
2172 if ((argumentBinding == TypeBinding.LongBinding)
2173 || (argumentBinding == TypeBinding.DoubleBinding))
2177 localContents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2178 localContents[localContentsOffset++] = (byte) resolvedPosition;
2182 int value = numberOfEntries * 10 + 2;
2183 localVariableTableOffset += 2;
2184 localContents[localVariableTableOffset++] = (byte) (value >> 24);
2185 localContents[localVariableTableOffset++] = (byte) (value >> 16);
2186 localContents[localVariableTableOffset++] = (byte) (value >> 8);
2187 localContents[localVariableTableOffset++] = (byte) value;
2188 localContents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
2189 localContents[localVariableTableOffset] = (byte) numberOfEntries;
2192 // update the number of attributes// ensure first that there is enough space available inside the localContents array
2193 if (codeAttributeAttributeOffset + 2
2194 >= (contentsLength = localContents.length)) {
2198 (localContents = contents = new byte[contentsLength + INCREMENT_SIZE]),
2202 localContents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2203 localContents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2204 // update the attribute length
2205 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2206 localContents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2207 localContents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2208 localContents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2209 localContents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2210 contentsOffset = localContentsOffset;
2215 * That method completes the creation of the code attribute by setting
2216 * - the attribute_length
2221 * - and debug attributes if necessary.
2223 * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
2224 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
2225 * @param codeAttributeOffset <CODE>int</CODE>
2227 public void completeCodeAttributeForSyntheticAccessMethod(
2228 SyntheticAccessMethodBinding binding,
2229 int codeAttributeOffset,
2230 int[] startLineIndexes) {
2231 // reinitialize the contents with the byte modified by the code stream
2232 contents = codeStream.bCodeStream;
2233 int localContentsOffset = codeStream.classFileOffset;
2234 // codeAttributeOffset is the position inside contents byte array before we started to write
2235 // any information about the codeAttribute
2236 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
2237 // to get the right position, 6 for the max_stack etc...
2238 int max_stack = codeStream.stackMax;
2239 contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
2240 contents[codeAttributeOffset + 7] = (byte) max_stack;
2241 int max_locals = codeStream.maxLocals;
2242 contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
2243 contents[codeAttributeOffset + 9] = (byte) max_locals;
2244 int code_length = codeStream.position;
2245 contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
2246 contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
2247 contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
2248 contents[codeAttributeOffset + 13] = (byte) code_length;
2250 if ((localContentsOffset + 40) >= (contentsLength = contents.length)) {
2254 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2258 // there is no exception table, so we need to offset by 2 the current offset and move
2259 // on the attribute generation
2260 localContentsOffset += 2;
2262 int codeAttributeAttributeOffset = localContentsOffset;
2263 int attributeNumber = 0;
2264 // leave two bytes for the attribute_length
2265 localContentsOffset += 2;
2267 // first we handle the linenumber attribute
2268 if (codeStream.generateLineNumberAttributes) {
2270 int lineNumberNameIndex =
2271 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
2272 contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
2273 contents[localContentsOffset++] = (byte) lineNumberNameIndex;
2274 int lineNumberTableOffset = localContentsOffset;
2275 localContentsOffset += 6;
2276 // leave space for attribute_length and line_number_table_length
2277 // Seems like do would be better, but this preserves the existing behavior.
2278 index = searchLineNumber(startLineIndexes, binding.sourceStart);
2279 contents[localContentsOffset++] = 0;
2280 contents[localContentsOffset++] = 0;
2281 contents[localContentsOffset++] = (byte) (index >> 8);
2282 contents[localContentsOffset++] = (byte) index;
2283 // now we change the size of the line number attribute
2284 contents[lineNumberTableOffset++] = 0;
2285 contents[lineNumberTableOffset++] = 0;
2286 contents[lineNumberTableOffset++] = 0;
2287 contents[lineNumberTableOffset++] = 6;
2288 contents[lineNumberTableOffset++] = 0;
2289 contents[lineNumberTableOffset++] = 1;
2292 // then we do the local variable attribute
2293 if (codeStream.generateLocalVariableTableAttributes) {
2294 int localVariableTableOffset = localContentsOffset;
2295 int numberOfEntries = 0;
2296 int localVariableNameIndex =
2297 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
2298 if (localContentsOffset + 8 > (contentsLength = contents.length)) {
2302 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2306 contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
2307 contents[localContentsOffset++] = (byte) localVariableNameIndex;
2308 localContentsOffset += 6;
2309 // leave space for attribute_length and local_variable_table_length
2311 int descriptorIndex;
2312 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
2313 LocalVariableBinding localVariable = codeStream.locals[i];
2314 for (int j = 0; j < localVariable.initializationCount; j++) {
2315 int startPC = localVariable.initializationPCs[j << 1];
2316 int endPC = localVariable.initializationPCs[(j << 1) + 1];
2317 if (startPC != endPC) { // only entries for non zero length
2319 localVariable.declaringScope.problemReporter().abortDueToInternalError(
2320 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
2321 (AstNode) localVariable.declaringScope.methodScope().referenceContext);
2323 if (localContentsOffset + 10 > (contentsLength = contents.length)) {
2327 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2331 // now we can safely add the local entry
2333 contents[localContentsOffset++] = (byte) (startPC >> 8);
2334 contents[localContentsOffset++] = (byte) startPC;
2335 int length = endPC - startPC;
2336 contents[localContentsOffset++] = (byte) (length >> 8);
2337 contents[localContentsOffset++] = (byte) length;
2338 nameIndex = constantPool.literalIndex(localVariable.name);
2339 contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2340 contents[localContentsOffset++] = (byte) nameIndex;
2341 descriptorIndex = constantPool.literalIndex(localVariable.type.signature());
2342 contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2343 contents[localContentsOffset++] = (byte) descriptorIndex;
2344 int resolvedPosition = localVariable.resolvedPosition;
2345 contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2346 contents[localContentsOffset++] = (byte) resolvedPosition;
2350 int value = numberOfEntries * 10 + 2;
2351 localVariableTableOffset += 2;
2352 contents[localVariableTableOffset++] = (byte) (value >> 24);
2353 contents[localVariableTableOffset++] = (byte) (value >> 16);
2354 contents[localVariableTableOffset++] = (byte) (value >> 8);
2355 contents[localVariableTableOffset++] = (byte) value;
2356 contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
2357 contents[localVariableTableOffset] = (byte) numberOfEntries;
2360 // update the number of attributes
2361 // ensure first that there is enough space available inside the contents array
2362 if (codeAttributeAttributeOffset + 2 >= (contentsLength = contents.length)) {
2366 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2370 contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2371 contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2373 // update the attribute length
2374 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2375 contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2376 contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2377 contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2378 contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2379 contentsOffset = localContentsOffset;
2384 * Complete the creation of a method info by setting up the number of attributes at the right offset.
2386 * @param methodAttributeOffset <CODE>int</CODE>
2387 * @param attributeNumber <CODE>int</CODE>
2389 public void completeMethodInfo(
2390 int methodAttributeOffset,
2391 int attributeNumber) {
2392 // update the number of attributes
2393 contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
2394 contents[methodAttributeOffset] = (byte) attributeNumber;
2399 * Innerclasses get their name computed as they are generated, since some may not
2400 * be actually outputed if sitting inside unreachable code.
2402 * @param localType org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding
2404 public char[] computeConstantPoolName(LocalTypeBinding localType) {
2405 if (localType.constantPoolName() != null) {
2406 return localType.constantPoolName();
2408 // delegates to the outermost enclosing classfile, since it is the only one with a global vision of its innertypes.
2409 if (enclosingClassFile != null) {
2410 return this.outerMostEnclosingClassFile().computeConstantPoolName(localType);
2412 if (nameUsage == null)
2413 nameUsage = new HashtableOfType();
2415 // ensure there is not already such a local type name defined by the user
2417 char[] candidateName;
2419 if (localType.isMemberType()){
2421 candidateName = CharOperation.concat(
2422 localType.enclosingType().constantPoolName(),
2423 localType.sourceName,
2426 // in case of collision, then member name gets extra $1 inserted
2427 // e.g. class X { { class L{} new X(){ class L{} } } }
2428 candidateName = CharOperation.concat(
2429 localType.enclosingType().constantPoolName(),
2431 String.valueOf(index).toCharArray(),
2433 localType.sourceName);
2435 } else if (localType.isAnonymousType()){
2436 candidateName = CharOperation.concat(
2437 referenceBinding.constantPoolName(),
2438 String.valueOf(index+1).toCharArray(),
2441 candidateName = CharOperation.concat(
2442 referenceBinding.constantPoolName(),
2444 String.valueOf(index+1).toCharArray(),
2446 localType.sourceName);
2448 if (nameUsage.get(candidateName) != null) {
2451 nameUsage.put(candidateName, localType);
2455 return candidateName;
2460 * Request the creation of a ClassFile compatible representation of a problematic type
2462 * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
2463 * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult
2465 public static void createProblemType(
2466 TypeDeclaration typeDeclaration,
2467 CompilationResult unitResult) {
2468 SourceTypeBinding typeBinding = typeDeclaration.binding;
2469 ClassFile classFile = new ClassFile(typeBinding, null, true);
2472 if (typeBinding.isMemberType())
2473 classFile.recordEnclosingTypeAttributes(typeBinding);
2476 FieldBinding[] fields = typeBinding.fields;
2477 if ((fields != null) && (fields != NoFields)) {
2478 for (int i = 0, max = fields.length; i < max; i++) {
2479 if (fields[i].constant == null) {
2480 FieldReference.getConstantFor(fields[i], false, null, null, 0);
2483 classFile.addFieldInfos();
2485 // we have to set the number of fields to be equals to 0
2486 classFile.contents[classFile.contentsOffset++] = 0;
2487 classFile.contents[classFile.contentsOffset++] = 0;
2489 // leave some space for the methodCount
2490 classFile.setForMethodInfos();
2491 // add its user defined methods
2492 MethodBinding[] methods = typeBinding.methods;
2493 AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods;
2494 int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length;
2496 IProblem[] problems = unitResult.getProblems();
2497 if (problems == null) {
2498 problems = new IProblem[0];
2500 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
2501 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
2502 if (methods != null) {
2503 if (typeBinding.isInterface()) {
2504 // we cannot create problem methods for an interface. So we have to generate a clinit
2505 // which should contain all the problem
2506 classFile.addProblemClinit(problemsCopy);
2507 for (int i = 0, max = methods.length; i < max; i++) {
2508 MethodBinding methodBinding;
2509 if ((methodBinding = methods[i]) != null) {
2510 // find the corresponding method declaration
2511 for (int j = 0; j < maxMethodDecl; j++) {
2512 if ((methodDeclarations[j] != null)
2513 && (methodDeclarations[j].binding == methods[i])) {
2514 if (!methodBinding.isConstructor()) {
2515 classFile.addAbstractMethod(methodDeclarations[j], methodBinding);
2523 for (int i = 0, max = methods.length; i < max; i++) {
2524 MethodBinding methodBinding;
2525 if ((methodBinding = methods[i]) != null) {
2526 // find the corresponding method declaration
2527 for (int j = 0; j < maxMethodDecl; j++) {
2528 if ((methodDeclarations[j] != null)
2529 && (methodDeclarations[j].binding == methods[i])) {
2530 AbstractMethodDeclaration methodDecl;
2531 if ((methodDecl = methodDeclarations[j]).isConstructor()) {
2532 classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy);
2534 classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy);
2542 // add abstract methods
2543 classFile.addDefaultAbstractMethods();
2545 // propagate generation of (problem) member types
2546 if (typeDeclaration.memberTypes != null) {
2547 for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) {
2548 TypeDeclaration memberType = typeDeclaration.memberTypes[i];
2549 if (memberType.binding != null) {
2550 classFile.recordNestedMemberAttribute(memberType.binding);
2551 ClassFile.createProblemType(memberType, unitResult);
2555 classFile.addAttributes();
2556 unitResult.record(typeBinding.constantPoolName(), classFile);
2561 * This methods returns a char[] representing the file name of the receiver
2565 public char[] fileName() {
2566 return constantPool.UTF8Cache.returnKeyFor(1);
2571 * That method generates the header of a code attribute.
2572 * - the index inside the constant pool for the attribute name (i.e. Code)
2573 * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4).
2575 public void generateCodeAttributeHeader() {
2577 if (contentsOffset + 20 >= (contentsLength = contents.length)) {
2581 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2585 int constantValueNameIndex =
2586 constantPool.literalIndex(AttributeNamesConstants.CodeName);
2587 contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
2588 contents[contentsOffset++] = (byte) constantValueNameIndex;
2589 // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4)
2590 contentsOffset += 12;
2595 * That method generates the attributes of a code attribute.
2597 * - an exception attribute for each try/catch found inside the method
2598 * - a deprecated attribute
2599 * - a synthetic attribute for synthetic access methods
2601 * It returns the number of attributes created for the code attribute.
2603 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2604 * @return <CODE>int</CODE>
2606 public int generateMethodInfoAttribute(MethodBinding methodBinding) {
2607 // leave two bytes for the attribute_number
2608 contentsOffset += 2;
2609 // now we can handle all the attribute for that method info:
2611 // - a CodeAttribute
2612 // - a ExceptionAttribute
2613 // - a DeprecatedAttribute
2614 // - a SyntheticAttribute
2616 // Exception attribute
2617 ReferenceBinding[] thrownsExceptions;
2619 int attributeNumber = 0;
2620 if ((thrownsExceptions = methodBinding.thrownExceptions) != NoExceptions) {
2621 // The method has a throw clause. So we need to add an exception attribute
2622 // check that there is enough space to write all the bytes for the exception attribute
2623 int length = thrownsExceptions.length;
2624 if (contentsOffset + (8 + length * 2) >= (contentsLength = contents.length)) {
2629 new byte[contentsLength + Math.max(INCREMENT_SIZE, (8 + length * 2))]),
2633 int exceptionNameIndex =
2634 constantPool.literalIndex(AttributeNamesConstants.ExceptionsName);
2635 contents[contentsOffset++] = (byte) (exceptionNameIndex >> 8);
2636 contents[contentsOffset++] = (byte) exceptionNameIndex;
2637 // The attribute length = length * 2 + 2 in case of a exception attribute
2638 int attributeLength = length * 2 + 2;
2639 contents[contentsOffset++] = (byte) (attributeLength >> 24);
2640 contents[contentsOffset++] = (byte) (attributeLength >> 16);
2641 contents[contentsOffset++] = (byte) (attributeLength >> 8);
2642 contents[contentsOffset++] = (byte) attributeLength;
2643 contents[contentsOffset++] = (byte) (length >> 8);
2644 contents[contentsOffset++] = (byte) length;
2645 for (int i = 0; i < length; i++) {
2646 int exceptionIndex = constantPool.literalIndex(thrownsExceptions[i]);
2647 contents[contentsOffset++] = (byte) (exceptionIndex >> 8);
2648 contents[contentsOffset++] = (byte) exceptionIndex;
2652 // Deprecated attribute
2653 // Check that there is enough space to write the deprecated attribute
2654 if (contentsOffset + 6 >= (contentsLength = contents.length)) {
2658 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2662 if (methodBinding.isDeprecated()) {
2663 int deprecatedAttributeNameIndex =
2664 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
2665 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
2666 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
2667 // the length of a deprecated attribute is equals to 0
2668 contents[contentsOffset++] = 0;
2669 contents[contentsOffset++] = 0;
2670 contents[contentsOffset++] = 0;
2671 contents[contentsOffset++] = 0;
2675 // Synthetic attribute
2676 // Check that there is enough space to write the deprecated attribute
2677 if (contentsOffset + 6 >= (contentsLength = contents.length)) {
2681 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2685 if (methodBinding.isSynthetic()) {
2686 int syntheticAttributeNameIndex =
2687 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
2688 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
2689 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
2690 // the length of a synthetic attribute is equals to 0
2691 contents[contentsOffset++] = 0;
2692 contents[contentsOffset++] = 0;
2693 contents[contentsOffset++] = 0;
2694 contents[contentsOffset++] = 0;
2698 return attributeNumber;
2703 * That method generates the header of a method info:
2704 * The header consists in:
2705 * - the access flags
2706 * - the name index of the method name inside the constant pool
2707 * - the descriptor index of the signature of the method inside the constant pool.
2709 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2711 public void generateMethodInfoHeader(MethodBinding methodBinding) {
2712 // check that there is enough space to write all the bytes for the method info corresponding
2713 // to the @methodBinding
2715 methodCount++; // add one more method
2716 if (contentsOffset + 10 >= (contentsLength = contents.length)) {
2720 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2724 int accessFlags = methodBinding.getAccessFlags();
2725 if (methodBinding.isRequiredToClearPrivateModifier()) {
2726 accessFlags &= ~AccPrivate;
2728 contents[contentsOffset++] = (byte) (accessFlags >> 8);
2729 contents[contentsOffset++] = (byte) accessFlags;
2730 int nameIndex = constantPool.literalIndex(methodBinding.selector);
2731 contents[contentsOffset++] = (byte) (nameIndex >> 8);
2732 contents[contentsOffset++] = (byte) nameIndex;
2733 int descriptorIndex = constantPool.literalIndex(methodBinding.signature());
2734 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
2735 contents[contentsOffset++] = (byte) descriptorIndex;
2740 * That method generates the method info header of a clinit:
2741 * The header consists in:
2742 * - the access flags (always default access + static)
2743 * - the name index of the method name (always <clinit>) inside the constant pool
2744 * - the descriptor index of the signature (always ()V) of the method inside the constant pool.
2746 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
2748 public void generateMethodInfoHeaderForClinit() {
2749 // check that there is enough space to write all the bytes for the method info corresponding
2750 // to the @methodBinding
2752 methodCount++; // add one more method
2753 if (contentsOffset + 10 >= (contentsLength = contents.length)) {
2757 (contents = new byte[contentsLength + INCREMENT_SIZE]),
2761 contents[contentsOffset++] = (byte) ((AccDefault | AccStatic) >> 8);
2762 contents[contentsOffset++] = (byte) (AccDefault | AccStatic);
2763 int nameIndex = constantPool.literalIndex(QualifiedNamesConstants.Clinit);
2764 contents[contentsOffset++] = (byte) (nameIndex >> 8);
2765 contents[contentsOffset++] = (byte) nameIndex;
2766 int descriptorIndex =
2767 constantPool.literalIndex(QualifiedNamesConstants.ClinitSignature);
2768 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
2769 contents[contentsOffset++] = (byte) descriptorIndex;
2770 // We know that we won't get more than 1 attribute: the code attribute
2771 contents[contentsOffset++] = 0;
2772 contents[contentsOffset++] = 1;
2777 * Answer the actual bytes of the class file
2779 * This method encodes the receiver structure into a byte array which is the content of the classfile.
2780 * Returns the byte array that represents the encoded structure of the receiver.
2784 public byte[] getBytes() {
2785 byte[] fullContents = new byte[headerOffset + contentsOffset];
2786 System.arraycopy(header, 0, fullContents, 0, headerOffset);
2787 System.arraycopy(contents, 0, fullContents, headerOffset, contentsOffset);
2788 return fullContents;
2793 * Answer the compound name of the class file.
2795 * e.g. {{java}, {util}, {Hashtable}}.
2797 public char[][] getCompoundName() {
2798 return CharOperation.splitOn('/', fileName());
2803 * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name
2804 * for all inner types of the receiver.
2805 * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile
2807 public ClassFile outerMostEnclosingClassFile() {
2808 ClassFile current = this;
2809 while (current.enclosingClassFile != null)
2810 current = current.enclosingClassFile;
2816 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2817 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2819 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2821 public void recordEnclosingTypeAttributes(ReferenceBinding binding) {
2822 // add all the enclosing types
2823 ReferenceBinding enclosingType = referenceBinding.enclosingType();
2825 while (enclosingType != null) {
2827 enclosingType = enclosingType.enclosingType();
2829 enclosingType = referenceBinding;
2830 ReferenceBinding enclosingTypes[];
2832 enclosingTypes = new ReferenceBinding[depth];
2833 for (int i = depth - 1; i >= 0; i--) {
2834 enclosingTypes[i] = enclosingType;
2835 enclosingType = enclosingType.enclosingType();
2837 for (int i = 0; i < depth; i++) {
2838 addInnerClasses(enclosingTypes[i]);
2841 addInnerClasses(referenceBinding);
2847 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2848 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2850 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2852 public void recordNestedLocalAttribute(ReferenceBinding binding) {
2853 // add all the enclosing types
2854 ReferenceBinding enclosingType = referenceBinding.enclosingType();
2856 while (enclosingType != null) {
2858 enclosingType = enclosingType.enclosingType();
2860 enclosingType = referenceBinding;
2861 ReferenceBinding enclosingTypes[];
2863 enclosingTypes = new ReferenceBinding[depth];
2864 for (int i = depth - 1; i >= 0; i--) {
2865 enclosingTypes[i] = enclosingType;
2866 enclosingType = enclosingType.enclosingType();
2868 for (int i = 0; i < depth; i++)
2869 addInnerClasses(enclosingTypes[i]);
2871 addInnerClasses(binding);
2877 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
2878 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
2880 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
2882 public void recordNestedMemberAttribute(ReferenceBinding binding) {
2883 addInnerClasses(binding);
2888 * Search the line number corresponding to a specific position
2890 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
2892 public static final int searchLineNumber(
2893 int[] startLineIndexes,
2895 // this code is completely useless, but it is the same implementation than
2896 // org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int)
2897 // if (startLineIndexes == null)
2899 int length = startLineIndexes.length;
2902 int g = 0, d = length - 1;
2906 if (position < startLineIndexes[m]) {
2909 if (position > startLineIndexes[m]) {
2915 if (position < startLineIndexes[m]) {
2923 * This methods leaves the space for method counts recording.
2925 public void setForMethodInfos() {
2926 // leave some space for the methodCount
2927 methodCountOffset = contentsOffset;
2928 contentsOffset += 2;
2933 * outputPath is formed like:
2934 * c:\temp\ the last character is a file separator
2935 * relativeFileName is formed like:
2936 * java\lang\String.class
2937 * @param generatePackagesStructure a flag to know if the packages structure has to be generated.
2938 * @param outputPath the output directory
2939 * @param relativeFileName java.lang.String
2940 * @param contents byte[]
2943 public static void writeToDisk(
2944 boolean generatePackagesStructure,
2946 String relativeFileName,
2948 throws IOException {
2950 BufferedOutputStream output = null;
2951 if (generatePackagesStructure) {
2952 output = new BufferedOutputStream(
2953 new FileOutputStream(
2954 new File(buildAllDirectoriesInto(outputPath, relativeFileName))));
2956 String fileName = null;
2957 char fileSeparatorChar = File.separatorChar;
2958 String fileSeparator = File.separator;
2959 // First we ensure that the outputPath exists
2960 outputPath = outputPath.replace('/', fileSeparatorChar);
2961 // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
2962 int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar);
2963 if (indexOfPackageSeparator == -1) {
2964 if (outputPath.endsWith(fileSeparator)) {
2965 fileName = outputPath + relativeFileName;
2967 fileName = outputPath + fileSeparator + relativeFileName;
2970 int length = relativeFileName.length();
2971 if (outputPath.endsWith(fileSeparator)) {
2972 fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length);
2974 fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length);
2977 output = new BufferedOutputStream(
2978 new FileOutputStream(
2979 new File(fileName)));
2982 output.write(contents);