1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler;
14 import java.util.StringTokenizer;
16 import org.eclipse.jdt.core.compiler.CharOperation;
17 import org.eclipse.jdt.core.compiler.IProblem;
18 import org.eclipse.jdt.internal.compiler.ast.*;
19 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
20 import org.eclipse.jdt.internal.compiler.codegen.*;
21 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
22 import org.eclipse.jdt.internal.compiler.impl.Constant;
23 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
24 import org.eclipse.jdt.internal.compiler.impl.StringConstant;
25 import org.eclipse.jdt.internal.compiler.lookup.*;
26 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
27 import org.eclipse.jdt.internal.compiler.util.Util;
30 * Represents a class file wrapper on bytes, it is aware of its actual
33 * Public APIs are listed below:
36 * Answer the actual bytes of the class file
38 * char[][] getCompoundName();
39 * Answer the compound name of the class file.
40 * For example, {{java}, {util}, {Hashtable}}.
42 * byte[] getReducedBytes();
43 * Answer a smaller byte format, which is only contains some structural
44 * information. Those bytes are decodable with a regular class file reader,
45 * such as DietClassFileReader
47 public class ClassFile
48 implements AttributeNamesConstants, CompilerModifiers, TypeConstants, TypeIds {
49 public static final int INITIAL_CONTENTS_SIZE = 400;
50 public static final int INITIAL_HEADER_SIZE = 1500;
51 public static final int INNER_CLASSES_SIZE = 5;
55 * Build all the directories and subdirectories corresponding to the packages names
56 * into the directory specified in parameters.
58 * outputPath is formed like:
59 * c:\temp\ the last character is a file separator
60 * relativeFileName is formed like:
61 * java\lang\String.class *
63 * @param outputPath java.lang.String
64 * @param relativeFileName java.lang.String
65 * @return java.lang.String
67 public static String buildAllDirectoriesInto(
69 String relativeFileName)
71 char fileSeparatorChar = File.separatorChar;
72 String fileSeparator = File.separator;
74 // First we ensure that the outputPath exists
75 outputPath = outputPath.replace('/', fileSeparatorChar);
76 // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
77 if (outputPath.endsWith(fileSeparator)) {
78 outputPath = outputPath.substring(0, outputPath.length() - 1);
80 f = new File(outputPath);
82 if (!f.isDirectory()) {
83 System.out.println(Util.bind("output.isFile" , f.getAbsolutePath())); //$NON-NLS-1$
84 throw new IOException(Util.bind("output.isFileNotDirectory" )); //$NON-NLS-1$
87 // we have to create that directory
89 System.out.println(Util.bind("output.dirName" , f.getAbsolutePath())); //$NON-NLS-1$
90 throw new IOException(Util.bind("output.notValidAll" )); //$NON-NLS-1$
93 StringBuffer outDir = new StringBuffer(outputPath);
94 outDir.append(fileSeparator);
95 StringTokenizer tokenizer =
96 new StringTokenizer(relativeFileName, fileSeparator);
97 String token = tokenizer.nextToken();
98 while (tokenizer.hasMoreTokens()) {
99 f = new File(outDir.append(token).append(fileSeparator).toString());
101 // The outDir already exists, so we proceed the next entry
102 // System.out.println("outDir: " + outDir + " already exists.");
104 // Need to add the outDir
106 System.out.println(Util.bind("output.fileName" , f.getName())); //$NON-NLS-1$
107 throw new IOException(Util.bind("output.notValid" )); //$NON-NLS-1$
110 token = tokenizer.nextToken();
112 // token contains the last one
113 return outDir.append(token).toString();
118 * Request the creation of a ClassFile compatible representation of a problematic type
120 * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
121 * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult
123 public static void createProblemType(
124 TypeDeclaration typeDeclaration,
125 CompilationResult unitResult) {
126 SourceTypeBinding typeBinding = typeDeclaration.binding;
127 ClassFile classFile = new ClassFile(typeBinding, null, true);
129 // TODO (olivier) handle cases where a field cannot be generated (name too long)
130 // TODO (olivier) handle too many methods
132 if (typeBinding.isMemberType())
133 classFile.recordEnclosingTypeAttributes(typeBinding);
136 FieldBinding[] fields = typeBinding.fields;
137 if ((fields != null) && (fields != NoFields)) {
138 for (int i = 0, max = fields.length; i < max; i++) {
139 if (fields[i].constant() == null) {
140 FieldReference.getConstantFor(fields[i], null, false, null);
143 classFile.addFieldInfos();
145 // we have to set the number of fields to be equals to 0
146 classFile.contents[classFile.contentsOffset++] = 0;
147 classFile.contents[classFile.contentsOffset++] = 0;
149 // leave some space for the methodCount
150 classFile.setForMethodInfos();
151 // add its user defined methods
152 MethodBinding[] methods = typeBinding.methods;
153 AbstractMethodDeclaration[] methodDeclarations = typeDeclaration.methods;
154 int maxMethodDecl = methodDeclarations == null ? 0 : methodDeclarations.length;
156 IProblem[] problems = unitResult.getErrors();
157 if (problems == null) {
158 problems = new IProblem[0];
160 IProblem[] problemsCopy = new IProblem[problemsLength = problems.length];
161 System.arraycopy(problems, 0, problemsCopy, 0, problemsLength);
162 if (methods != null) {
163 if (typeBinding.isInterface()) {
164 // we cannot create problem methods for an interface. So we have to generate a clinit
165 // which should contain all the problem
166 classFile.addProblemClinit(problemsCopy);
167 for (int i = 0, max = methods.length; i < max; i++) {
168 MethodBinding methodBinding;
169 if ((methodBinding = methods[i]) != null) {
170 // find the corresponding method declaration
171 for (int j = 0; j < maxMethodDecl; j++) {
172 if ((methodDeclarations[j] != null)
173 && (methodDeclarations[j].binding == methods[i])) {
174 if (!methodBinding.isConstructor()) {
175 classFile.addAbstractMethod(methodDeclarations[j], methodBinding);
183 for (int i = 0, max = methods.length; i < max; i++) {
184 MethodBinding methodBinding;
185 if ((methodBinding = methods[i]) != null) {
186 // find the corresponding method declaration
187 for (int j = 0; j < maxMethodDecl; j++) {
188 if ((methodDeclarations[j] != null)
189 && (methodDeclarations[j].binding == methods[i])) {
190 AbstractMethodDeclaration methodDecl;
191 if ((methodDecl = methodDeclarations[j]).isConstructor()) {
192 classFile.addProblemConstructor(methodDecl, methodBinding, problemsCopy);
194 classFile.addProblemMethod(methodDecl, methodBinding, problemsCopy);
202 // add abstract methods
203 classFile.addDefaultAbstractMethods();
205 // propagate generation of (problem) member types
206 if (typeDeclaration.memberTypes != null) {
207 for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) {
208 TypeDeclaration memberType = typeDeclaration.memberTypes[i];
209 if (memberType.binding != null) {
210 classFile.recordNestedMemberAttribute(memberType.binding);
211 ClassFile.createProblemType(memberType, unitResult);
215 classFile.addAttributes();
216 unitResult.record(typeBinding.constantPoolName(), classFile);
221 * Search the line number corresponding to a specific position
223 public static final int searchLineNumber(
224 int[] startLineIndexes,
226 // this code is completely useless, but it is the same implementation than
227 // org.eclipse.jdt.internal.compiler.problem.ProblemHandler.searchLineNumber(int[], int)
228 // if (startLineIndexes == null)
230 int length = startLineIndexes.length;
233 int g = 0, d = length - 1;
237 if (position < startLineIndexes[m]) {
240 if (position > startLineIndexes[m]) {
246 if (position < startLineIndexes[m]) {
254 * outputPath is formed like:
255 * c:\temp\ the last character is a file separator
256 * relativeFileName is formed like:
257 * java\lang\String.class
258 * @param generatePackagesStructure a flag to know if the packages structure has to be generated.
259 * @param outputPath the output directory
260 * @param relativeFileName java.lang.String
261 * @param contents byte[]
264 public static void writeToDisk(
265 boolean generatePackagesStructure,
267 String relativeFileName,
271 BufferedOutputStream output = null;
272 if (generatePackagesStructure) {
273 output = new BufferedOutputStream(
274 new FileOutputStream(
275 new File(buildAllDirectoriesInto(outputPath, relativeFileName))));
277 String fileName = null;
278 char fileSeparatorChar = File.separatorChar;
279 String fileSeparator = File.separator;
280 // First we ensure that the outputPath exists
281 outputPath = outputPath.replace('/', fileSeparatorChar);
282 // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
283 int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar);
284 if (indexOfPackageSeparator == -1) {
285 if (outputPath.endsWith(fileSeparator)) {
286 fileName = outputPath + relativeFileName;
288 fileName = outputPath + fileSeparator + relativeFileName;
291 int length = relativeFileName.length();
292 if (outputPath.endsWith(fileSeparator)) {
293 fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length);
295 fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length);
298 output = new BufferedOutputStream(
299 new FileOutputStream(
300 new File(fileName)));
303 output.write(contents);
309 public CodeStream codeStream;
310 public ConstantPool constantPool;
311 public int constantPoolOffset;
312 // the header contains all the bytes till the end of the constant pool
313 public byte[] contents;
314 public int contentsOffset;
315 protected boolean creatingProblemType;
316 public ClassFile enclosingClassFile;
317 public byte[] header;
318 // that collection contains all the remaining bytes of the .class file
319 public int headerOffset;
320 public ReferenceBinding[] innerClassesBindings;
321 public int methodCount;
322 public int methodCountOffset;
323 public int numberOfInnerClasses;
324 public boolean ownSharedArrays = false; // flag set when header/contents are set to shared arrays
325 // used to generate private access methods
326 public int produceDebugAttributes;
327 public SourceTypeBinding referenceBinding;
328 public long targetJDK;
332 * This methods creates a new instance of the receiver.
335 // default constructor for subclasses
340 * This methods creates a new instance of the receiver.
342 * @param aType org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding
343 * @param enclosingClassFile org.eclipse.jdt.internal.compiler.ClassFile
344 * @param creatingProblemType <CODE>boolean</CODE>
347 SourceTypeBinding aType,
348 ClassFile enclosingClassFile,
349 boolean creatingProblemType) {
351 this.referenceBinding = aType;
354 // generate the magic numbers inside the header
355 header[headerOffset++] = (byte) (0xCAFEBABEL >> 24);
356 header[headerOffset++] = (byte) (0xCAFEBABEL >> 16);
357 header[headerOffset++] = (byte) (0xCAFEBABEL >> 8);
358 header[headerOffset++] = (byte) (0xCAFEBABEL >> 0);
360 final CompilerOptions options = aType.scope.environment().options;
361 this.targetJDK = options.targetJDK;
362 header[headerOffset++] = (byte) (this.targetJDK >> 8); // minor high
363 header[headerOffset++] = (byte) (this.targetJDK >> 0); // minor low
364 header[headerOffset++] = (byte) (this.targetJDK >> 24); // major high
365 header[headerOffset++] = (byte) (this.targetJDK >> 16); // major low
367 constantPoolOffset = headerOffset;
369 constantPool = new ConstantPool(this);
371 // Modifier manipulations for classfile
372 int accessFlags = aType.getAccessFlags();
373 if (aType.isPrivate()) { // rewrite private to non-public
374 accessFlags &= ~AccPublic;
376 if (aType.isProtected()) { // rewrite protected into public
377 accessFlags |= AccPublic;
379 // clear all bits that are illegal for a class or an interface
389 // set the AccSuper flag (has to be done after clearing AccSynchronized - since same value)
390 if (aType.isClass()) {
391 accessFlags |= AccSuper;
394 this.enclosingClassFile = enclosingClassFile;
395 // innerclasses get their names computed at code gen time
397 // now we continue to generate the bytes inside the contents array
398 contents[contentsOffset++] = (byte) (accessFlags >> 8);
399 contents[contentsOffset++] = (byte) accessFlags;
400 int classNameIndex = constantPool.literalIndexForType(aType.constantPoolName());
401 contents[contentsOffset++] = (byte) (classNameIndex >> 8);
402 contents[contentsOffset++] = (byte) classNameIndex;
403 int superclassNameIndex;
404 if (aType.isInterface()) {
405 superclassNameIndex = constantPool.literalIndexForType(ConstantPool.JavaLangObjectConstantPoolName);
407 superclassNameIndex =
408 (aType.superclass == null ? 0 : constantPool.literalIndexForType(aType.superclass.constantPoolName()));
410 contents[contentsOffset++] = (byte) (superclassNameIndex >> 8);
411 contents[contentsOffset++] = (byte) superclassNameIndex;
412 ReferenceBinding[] superInterfacesBinding = aType.superInterfaces();
413 int interfacesCount = superInterfacesBinding.length;
414 contents[contentsOffset++] = (byte) (interfacesCount >> 8);
415 contents[contentsOffset++] = (byte) interfacesCount;
416 for (int i = 0; i < interfacesCount; i++) {
417 int interfaceIndex = constantPool.literalIndexForType(superInterfacesBinding[i].constantPoolName());
418 contents[contentsOffset++] = (byte) (interfaceIndex >> 8);
419 contents[contentsOffset++] = (byte) interfaceIndex;
421 produceDebugAttributes = options.produceDebugAttributes;
422 innerClassesBindings = new ReferenceBinding[INNER_CLASSES_SIZE];
423 this.creatingProblemType = creatingProblemType;
424 codeStream = new CodeStream(this, this.targetJDK);
426 // retrieve the enclosing one guaranteed to be the one matching the propagated flow info
427 // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check)
428 ClassFile outermostClassFile = this.outerMostEnclosingClassFile();
429 if (this == outermostClassFile) {
430 codeStream.maxFieldCount = aType.scope.referenceType().maxFieldCount;
432 codeStream.maxFieldCount = outermostClassFile.codeStream.maxFieldCount;
438 * Generate the byte for a problem method info that correspond to a boggus method.
440 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
441 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
443 public void addAbstractMethod(
444 AbstractMethodDeclaration method,
445 MethodBinding methodBinding) {
447 // force the modifiers to be public and abstract
448 methodBinding.modifiers = AccPublic | AccAbstract;
450 this.generateMethodInfoHeader(methodBinding);
451 int methodAttributeOffset = this.contentsOffset;
452 int attributeNumber = this.generateMethodInfoAttribute(methodBinding);
453 this.completeMethodInfo(methodAttributeOffset, attributeNumber);
458 * This methods generate all the attributes for the receiver.
459 * For a class they could be:
460 * - source file attribute
461 * - inner classes attribute
462 * - deprecated attribute
464 public void addAttributes() {
465 // update the method count
466 contents[methodCountOffset++] = (byte) (methodCount >> 8);
467 contents[methodCountOffset] = (byte) methodCount;
469 int attributeNumber = 0;
470 // leave two bytes for the number of attributes and store the current offset
471 int attributeOffset = contentsOffset;
475 if ((produceDebugAttributes & CompilerOptions.Source) != 0) {
476 String fullFileName =
477 new String(referenceBinding.scope.referenceCompilationUnit().getFileName());
478 fullFileName = fullFileName.replace('\\', '/');
479 int lastIndex = fullFileName.lastIndexOf('/');
480 if (lastIndex != -1) {
481 fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length());
483 // check that there is enough space to write all the bytes for the field info corresponding
484 // to the @fieldBinding
485 if (contentsOffset + 8 >= contents.length) {
488 int sourceAttributeNameIndex =
489 constantPool.literalIndex(AttributeNamesConstants.SourceName);
490 contents[contentsOffset++] = (byte) (sourceAttributeNameIndex >> 8);
491 contents[contentsOffset++] = (byte) sourceAttributeNameIndex;
492 // The length of a source file attribute is 2. This is a fixed-length
494 contents[contentsOffset++] = 0;
495 contents[contentsOffset++] = 0;
496 contents[contentsOffset++] = 0;
497 contents[contentsOffset++] = 2;
498 // write the source file name
499 int fileNameIndex = constantPool.literalIndex(fullFileName.toCharArray());
500 contents[contentsOffset++] = (byte) (fileNameIndex >> 8);
501 contents[contentsOffset++] = (byte) fileNameIndex;
504 // Deprecated attribute
505 if (referenceBinding.isDeprecated()) {
506 // check that there is enough space to write all the bytes for the field info corresponding
507 // to the @fieldBinding
508 if (contentsOffset + 6 >= contents.length) {
511 int deprecatedAttributeNameIndex =
512 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
513 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
514 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
515 // the length of a deprecated attribute is equals to 0
516 contents[contentsOffset++] = 0;
517 contents[contentsOffset++] = 0;
518 contents[contentsOffset++] = 0;
519 contents[contentsOffset++] = 0;
522 // Inner class attribute
523 if (numberOfInnerClasses != 0) {
524 // Generate the inner class attribute
525 int exSize = 8 * numberOfInnerClasses + 8;
526 if (exSize + contentsOffset >= this.contents.length) {
527 resizeContents(exSize);
529 // Now we now the size of the attribute and the number of entries
531 int attributeNameIndex =
532 constantPool.literalIndex(AttributeNamesConstants.InnerClassName);
533 contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
534 contents[contentsOffset++] = (byte) attributeNameIndex;
535 int value = (numberOfInnerClasses << 3) + 2;
536 contents[contentsOffset++] = (byte) (value >> 24);
537 contents[contentsOffset++] = (byte) (value >> 16);
538 contents[contentsOffset++] = (byte) (value >> 8);
539 contents[contentsOffset++] = (byte) value;
540 contents[contentsOffset++] = (byte) (numberOfInnerClasses >> 8);
541 contents[contentsOffset++] = (byte) numberOfInnerClasses;
542 for (int i = 0; i < numberOfInnerClasses; i++) {
543 ReferenceBinding innerClass = innerClassesBindings[i];
544 int accessFlags = innerClass.getAccessFlags();
545 int innerClassIndex = constantPool.literalIndexForType(innerClass.constantPoolName());
547 contents[contentsOffset++] = (byte) (innerClassIndex >> 8);
548 contents[contentsOffset++] = (byte) innerClassIndex;
549 // outer class index: anonymous and local have no outer class index
550 if (innerClass.isMemberType()) {
551 // member or member of local
552 int outerClassIndex = constantPool.literalIndexForType(innerClass.enclosingType().constantPoolName());
553 contents[contentsOffset++] = (byte) (outerClassIndex >> 8);
554 contents[contentsOffset++] = (byte) outerClassIndex;
556 // equals to 0 if the innerClass is not a member type
557 contents[contentsOffset++] = 0;
558 contents[contentsOffset++] = 0;
561 if (!innerClass.isAnonymousType()) {
562 int nameIndex = constantPool.literalIndex(innerClass.sourceName());
563 contents[contentsOffset++] = (byte) (nameIndex >> 8);
564 contents[contentsOffset++] = (byte) nameIndex;
566 // equals to 0 if the innerClass is an anonymous type
567 contents[contentsOffset++] = 0;
568 contents[contentsOffset++] = 0;
571 if (innerClass.isAnonymousType()) {
572 accessFlags |= AccPrivate;
573 } else if (innerClass.isLocalType() && !innerClass.isMemberType()) {
574 accessFlags |= AccPrivate;
575 } else if (innerClass.isMemberType() && (innerClass.isInterface() || innerClass.isAnnotationType())) {
576 accessFlags |= AccStatic; // implicitely static
578 contents[contentsOffset++] = (byte) (accessFlags >> 8);
579 contents[contentsOffset++] = (byte) accessFlags;
583 // add signature attribute
584 char[] genericSignature = referenceBinding.genericSignature();
585 if (genericSignature != null) {
586 // check that there is enough space to write all the bytes for the field info corresponding
587 // to the @fieldBinding
588 if (contentsOffset + 8 >= contents.length) {
591 int signatureAttributeNameIndex =
592 constantPool.literalIndex(AttributeNamesConstants.SignatureName);
593 contents[contentsOffset++] = (byte) (signatureAttributeNameIndex >> 8);
594 contents[contentsOffset++] = (byte) signatureAttributeNameIndex;
595 // the length of a signature attribute is equals to 2
596 contents[contentsOffset++] = 0;
597 contents[contentsOffset++] = 0;
598 contents[contentsOffset++] = 0;
599 contents[contentsOffset++] = 2;
601 constantPool.literalIndex(genericSignature);
602 contents[contentsOffset++] = (byte) (signatureIndex >> 8);
603 contents[contentsOffset++] = (byte) signatureIndex;
606 if (targetJDK >= ClassFileConstants.JDK1_5
607 && (this.referenceBinding.isAnonymousType() || this.referenceBinding.isLocalType())) {
608 // add enclosing method attribute (1.5 mode only)
609 if (contentsOffset + 10 >= contents.length) {
612 int enclosingMethodAttributeNameIndex =
613 constantPool.literalIndex(AttributeNamesConstants.EnclosingMethodName);
614 contents[contentsOffset++] = (byte) (enclosingMethodAttributeNameIndex >> 8);
615 contents[contentsOffset++] = (byte) enclosingMethodAttributeNameIndex;
616 // the length of a signature attribute is equals to 2
617 contents[contentsOffset++] = 0;
618 contents[contentsOffset++] = 0;
619 contents[contentsOffset++] = 0;
620 contents[contentsOffset++] = 4;
622 int enclosingTypeIndex = constantPool.literalIndexForType(this.referenceBinding.enclosingType().constantPoolName());
623 contents[contentsOffset++] = (byte) (enclosingTypeIndex >> 8);
624 contents[contentsOffset++] = (byte) enclosingTypeIndex;
625 byte methodIndexByte1 = 0;
626 byte methodIndexByte2 = 0;
627 if (this.referenceBinding.scope != null) {
628 MethodScope methodScope = this.referenceBinding.scope.methodScope();
629 if (methodScope != null) {
630 ReferenceContext referenceContext = methodScope.referenceContext;
631 if (referenceContext instanceof AbstractMethodDeclaration) {
632 AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) referenceContext;
633 MethodBinding methodBinding = methodDeclaration.binding;
634 int enclosingMethodIndex = constantPool.literalIndexForMethod(methodBinding.selector, methodBinding.signature());
635 methodIndexByte1 = (byte) (enclosingMethodIndex >> 8);
636 methodIndexByte2 = (byte) enclosingMethodIndex;
640 contents[contentsOffset++] = methodIndexByte1;
641 contents[contentsOffset++] = methodIndexByte2;
644 if (this.targetJDK >= ClassFileConstants.JDK1_5 && !this.creatingProblemType) {
645 TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
646 if (typeDeclaration != null) {
647 final Annotation[] annotations = typeDeclaration.annotations;
648 if (annotations != null) {
649 attributeNumber += generateRuntimeAnnotations(annotations);
653 // update the number of attributes
654 if (attributeOffset + 2 >= this.contents.length) {
657 contents[attributeOffset++] = (byte) (attributeNumber >> 8);
658 contents[attributeOffset] = (byte) attributeNumber;
660 // resynchronize all offsets of the classfile
661 header = constantPool.poolContent;
662 headerOffset = constantPool.currentOffset;
663 int constantPoolCount = constantPool.currentIndex;
664 header[constantPoolOffset++] = (byte) (constantPoolCount >> 8);
665 header[constantPoolOffset] = (byte) constantPoolCount;
670 * This methods generate all the default abstract method infos that correpond to
671 * the abstract methods inherited from superinterfaces.
673 public void addDefaultAbstractMethods() { // default abstract methods
674 MethodBinding[] defaultAbstractMethods =
675 referenceBinding.getDefaultAbstractMethods();
676 for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
677 generateMethodInfoHeader(defaultAbstractMethods[i]);
678 int methodAttributeOffset = contentsOffset;
679 int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
680 completeMethodInfo(methodAttributeOffset, attributeNumber);
684 private int addFieldAttributes(FieldBinding fieldBinding, int fieldAttributeOffset) {
685 int attributesNumber = 0;
686 // 4.7.2 only static constant fields get a ConstantAttribute
687 // Generate the constantValueAttribute
688 if (fieldBinding.isConstantValue()){
689 if (contentsOffset + 8 >= contents.length) {
692 // Now we generate the constant attribute corresponding to the fieldBinding
693 int constantValueNameIndex =
694 constantPool.literalIndex(AttributeNamesConstants.ConstantValueName);
695 contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
696 contents[contentsOffset++] = (byte) constantValueNameIndex;
697 // The attribute length = 2 in case of a constantValue attribute
698 contents[contentsOffset++] = 0;
699 contents[contentsOffset++] = 0;
700 contents[contentsOffset++] = 0;
701 contents[contentsOffset++] = 2;
703 // Need to add the constant_value_index
704 Constant fieldConstant = fieldBinding.constant();
705 switch (fieldConstant.typeID()) {
707 int booleanValueIndex =
708 constantPool.literalIndex(fieldConstant.booleanValue() ? 1 : 0);
709 contents[contentsOffset++] = (byte) (booleanValueIndex >> 8);
710 contents[contentsOffset++] = (byte) booleanValueIndex;
716 int integerValueIndex =
717 constantPool.literalIndex(fieldConstant.intValue());
718 contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
719 contents[contentsOffset++] = (byte) integerValueIndex;
722 int floatValueIndex =
723 constantPool.literalIndex(fieldConstant.floatValue());
724 contents[contentsOffset++] = (byte) (floatValueIndex >> 8);
725 contents[contentsOffset++] = (byte) floatValueIndex;
728 int doubleValueIndex =
729 constantPool.literalIndex(fieldConstant.doubleValue());
730 contents[contentsOffset++] = (byte) (doubleValueIndex >> 8);
731 contents[contentsOffset++] = (byte) doubleValueIndex;
735 constantPool.literalIndex(fieldConstant.longValue());
736 contents[contentsOffset++] = (byte) (longValueIndex >> 8);
737 contents[contentsOffset++] = (byte) longValueIndex;
739 case T_JavaLangString :
740 int stringValueIndex =
741 constantPool.literalIndex(
742 ((StringConstant) fieldConstant).stringValue());
743 if (stringValueIndex == -1) {
744 if (!creatingProblemType) {
745 // report an error and abort: will lead to a problem type classfile creation
746 TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
747 FieldDeclaration[] fieldDecls = typeDeclaration.fields;
748 for (int i = 0, max = fieldDecls.length; i < max; i++) {
749 if (fieldDecls[i].binding == fieldBinding) {
750 // problem should abort
751 typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(
756 // already inside a problem type creation : no constant for this field
757 contentsOffset = fieldAttributeOffset;
760 contents[contentsOffset++] = (byte) (stringValueIndex >> 8);
761 contents[contentsOffset++] = (byte) stringValueIndex;
765 if (this.targetJDK < ClassFileConstants.JDK1_5 && fieldBinding.isSynthetic()) {
766 if (contentsOffset + 6 >= contents.length) {
769 int syntheticAttributeNameIndex =
770 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
771 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
772 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
773 // the length of a synthetic attribute is equals to 0
774 contents[contentsOffset++] = 0;
775 contents[contentsOffset++] = 0;
776 contents[contentsOffset++] = 0;
777 contents[contentsOffset++] = 0;
780 if (fieldBinding.isDeprecated()) {
781 if (contentsOffset + 6 >= contents.length) {
784 int deprecatedAttributeNameIndex =
785 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
786 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
787 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
788 // the length of a deprecated attribute is equals to 0
789 contents[contentsOffset++] = 0;
790 contents[contentsOffset++] = 0;
791 contents[contentsOffset++] = 0;
792 contents[contentsOffset++] = 0;
795 // add signature attribute
796 char[] genericSignature = fieldBinding.genericSignature();
797 if (genericSignature != null) {
798 // check that there is enough space to write all the bytes for the field info corresponding
799 // to the @fieldBinding
800 if (contentsOffset + 8 >= contents.length) {
803 int signatureAttributeNameIndex =
804 constantPool.literalIndex(AttributeNamesConstants.SignatureName);
805 contents[contentsOffset++] = (byte) (signatureAttributeNameIndex >> 8);
806 contents[contentsOffset++] = (byte) signatureAttributeNameIndex;
807 // the length of a signature attribute is equals to 2
808 contents[contentsOffset++] = 0;
809 contents[contentsOffset++] = 0;
810 contents[contentsOffset++] = 0;
811 contents[contentsOffset++] = 2;
813 constantPool.literalIndex(genericSignature);
814 contents[contentsOffset++] = (byte) (signatureIndex >> 8);
815 contents[contentsOffset++] = (byte) signatureIndex;
818 if (this.targetJDK >= ClassFileConstants.JDK1_5 && !this.creatingProblemType) {
819 FieldDeclaration fieldDeclaration = fieldBinding.sourceField();
820 if (fieldDeclaration != null) {
821 Annotation[] annotations = fieldDeclaration.annotations;
822 if (annotations != null) {
823 attributesNumber += generateRuntimeAnnotations(annotations);
827 return attributesNumber;
831 * This methods generates the bytes for the given field binding
832 * @param fieldBinding the given field binding
834 private void addFieldInfo(FieldBinding fieldBinding) {
835 // check that there is enough space to write all the bytes for the field info corresponding
836 // to the @fieldBinding
837 if (contentsOffset + 8 >= contents.length) {
840 // Now we can generate all entries into the byte array
841 // First the accessFlags
842 int accessFlags = fieldBinding.getAccessFlags();
843 if (targetJDK < ClassFileConstants.JDK1_5) {
844 // pre 1.5, synthetic was an attribute, not a modifier
845 accessFlags &= ~AccSynthetic;
847 contents[contentsOffset++] = (byte) (accessFlags >> 8);
848 contents[contentsOffset++] = (byte) accessFlags;
849 // Then the nameIndex
850 int nameIndex = constantPool.literalIndex(fieldBinding.name);
851 contents[contentsOffset++] = (byte) (nameIndex >> 8);
852 contents[contentsOffset++] = (byte) nameIndex;
853 // Then the descriptorIndex
854 int descriptorIndex = constantPool.literalIndex(fieldBinding.type.signature());
855 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
856 contents[contentsOffset++] = (byte) descriptorIndex;
857 int fieldAttributeOffset = contentsOffset;
858 int attributeNumber = 0;
859 // leave some space for the number of attributes
861 attributeNumber += addFieldAttributes(fieldBinding, fieldAttributeOffset);
862 contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8);
863 contents[fieldAttributeOffset] = (byte) attributeNumber;
868 * This methods generate all the fields infos for the receiver.
870 * - a field info for each defined field of that class
871 * - a field info for each synthetic field (e.g. this$0)
875 * This methods generate all the fields infos for the receiver.
877 * - a field info for each defined field of that class
878 * - a field info for each synthetic field (e.g. this$0)
880 public void addFieldInfos() {
881 SourceTypeBinding currentBinding = referenceBinding;
882 FieldBinding[] syntheticFields = currentBinding.syntheticFields();
884 currentBinding.fieldCount()
885 + (syntheticFields == null ? 0 : syntheticFields.length);
887 // write the number of fields
888 if (fieldCount > 0xFFFF) {
889 referenceBinding.scope.problemReporter().tooManyFields(referenceBinding.scope.referenceType());
891 contents[contentsOffset++] = (byte) (fieldCount >> 8);
892 contents[contentsOffset++] = (byte) fieldCount;
894 FieldBinding[] fieldBindings = currentBinding.fields();
895 for (int i = 0, max = fieldBindings.length; i < max; i++) {
896 addFieldInfo(fieldBindings[i]);
898 if (syntheticFields != null) {
899 for (int i = 0, max = syntheticFields.length; i < max; i++) {
900 addFieldInfo(syntheticFields[i]);
907 * This methods stores the bindings for each inner class. They will be used to know which entries
908 * have to be generated for the inner classes attributes.
909 * @param refBinding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
911 private void addInnerClasses(ReferenceBinding refBinding) {
912 // check first if that reference binding is there
913 for (int i = 0; i < numberOfInnerClasses; i++) {
914 if (innerClassesBindings[i] == refBinding)
917 int length = innerClassesBindings.length;
918 if (numberOfInnerClasses == length) {
920 innerClassesBindings,
922 innerClassesBindings = new ReferenceBinding[length * 2],
926 innerClassesBindings[numberOfInnerClasses++] = refBinding;
929 private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, IProblem problem, CompilationResult compilationResult) {
930 // always clear the strictfp/native/abstract bit for a problem method
931 generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
932 int methodAttributeOffset = contentsOffset;
933 int attributeNumber = generateMethodInfoAttribute(methodBinding);
938 int codeAttributeOffset = contentsOffset;
939 generateCodeAttributeHeader();
940 StringBuffer buffer = new StringBuffer(25);
941 buffer.append("\t" + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
942 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
943 String problemString = buffer.toString();
945 codeStream.init(this);
946 codeStream.preserveUnusedLocals = true;
947 codeStream.initializeMaxLocals(methodBinding);
949 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
950 codeStream.generateCodeAttributeForProblemMethod(problemString);
952 completeCodeAttributeForMissingAbstractProblemMethod(
955 compilationResult.lineSeparatorPositions,
956 problem.getSourceLineNumber());
958 completeMethodInfo(methodAttributeOffset, attributeNumber);
963 * Generate the byte for a problem clinit method info that correspond to a boggus method.
965 * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
967 public void addProblemClinit(IProblem[] problems) {
968 generateMethodInfoHeaderForClinit();
969 // leave two spaces for the number of attributes
971 int attributeOffset = contentsOffset;
973 int attributeNumber = 0;
975 int codeAttributeOffset = contentsOffset;
976 generateCodeAttributeHeader();
977 codeStream.resetForProblemClinit(this);
978 String problemString = "" ; //$NON-NLS-1$
980 if (problems != null) {
981 int max = problems.length;
982 StringBuffer buffer = new StringBuffer(25);
984 for (int i = 0; i < max; i++) {
985 IProblem problem = problems[i];
986 if ((problem != null) && (problem.isError())) {
987 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
989 if (problemLine == 0) {
990 problemLine = problem.getSourceLineNumber();
994 } // insert the top line afterwards, once knowing how many problems we have to consider
996 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
998 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
1000 problemString = buffer.toString();
1003 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
1004 codeStream.generateCodeAttributeForProblemMethod(problemString);
1005 attributeNumber++; // code attribute
1006 completeCodeAttributeForClinit(
1007 codeAttributeOffset,
1010 .referenceCompilationUnit()
1012 .lineSeparatorPositions,
1014 contents[attributeOffset++] = (byte) (attributeNumber >> 8);
1015 contents[attributeOffset] = (byte) attributeNumber;
1020 * Generate the byte for a problem method info that correspond to a boggus constructor.
1022 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
1023 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
1024 * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
1026 public void addProblemConstructor(
1027 AbstractMethodDeclaration method,
1028 MethodBinding methodBinding,
1029 IProblem[] problems) {
1031 // always clear the strictfp/native/abstract bit for a problem method
1032 generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
1033 int methodAttributeOffset = contentsOffset;
1034 int attributeNumber = generateMethodInfoAttribute(methodBinding, true);
1038 int codeAttributeOffset = contentsOffset;
1039 generateCodeAttributeHeader();
1040 codeStream.reset(method, this);
1041 String problemString = "" ; //$NON-NLS-1$
1042 int problemLine = 0;
1043 if (problems != null) {
1044 int max = problems.length;
1045 StringBuffer buffer = new StringBuffer(25);
1047 for (int i = 0; i < max; i++) {
1048 IProblem problem = problems[i];
1049 if ((problem != null) && (problem.isError())) {
1050 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
1052 if (problemLine == 0) {
1053 problemLine = problem.getSourceLineNumber();
1056 } // insert the top line afterwards, once knowing how many problems we have to consider
1058 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
1060 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
1062 problemString = buffer.toString();
1065 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
1066 codeStream.generateCodeAttributeForProblemMethod(problemString);
1067 completeCodeAttributeForProblemMethod(
1070 codeAttributeOffset,
1071 ((SourceTypeBinding) methodBinding.declaringClass)
1073 .referenceCompilationUnit()
1075 .lineSeparatorPositions,
1077 completeMethodInfo(methodAttributeOffset, attributeNumber);
1082 * Generate the byte for a problem method info that correspond to a boggus constructor.
1083 * Reset the position inside the contents byte array to the savedOffset.
1085 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
1086 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
1087 * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
1088 * @param savedOffset <CODE>int</CODE>
1090 public void addProblemConstructor(
1091 AbstractMethodDeclaration method,
1092 MethodBinding methodBinding,
1093 IProblem[] problems,
1095 // we need to move back the contentsOffset to the value at the beginning of the method
1096 contentsOffset = savedOffset;
1097 methodCount--; // we need to remove the method that causes the problem
1098 addProblemConstructor(method, methodBinding, problems);
1103 * Generate the byte for a problem method info that correspond to a boggus method.
1105 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
1106 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
1107 * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
1109 public void addProblemMethod(
1110 AbstractMethodDeclaration method,
1111 MethodBinding methodBinding,
1112 IProblem[] problems) {
1113 if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) {
1114 method.abort(ProblemSeverities.AbortType, null);
1116 // always clear the strictfp/native/abstract bit for a problem method
1117 generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(AccStrictfp | AccNative | AccAbstract));
1118 int methodAttributeOffset = contentsOffset;
1119 int attributeNumber = generateMethodInfoAttribute(methodBinding, true);
1124 int codeAttributeOffset = contentsOffset;
1125 generateCodeAttributeHeader();
1126 codeStream.reset(method, this);
1127 String problemString = "" ; //$NON-NLS-1$
1128 int problemLine = 0;
1129 if (problems != null) {
1130 int max = problems.length;
1131 StringBuffer buffer = new StringBuffer(25);
1133 for (int i = 0; i < max; i++) {
1134 IProblem problem = problems[i];
1135 if ((problem != null)
1136 && (problem.isError())
1137 && (problem.getSourceStart() >= method.declarationSourceStart)
1138 && (problem.getSourceEnd() <= method.declarationSourceEnd)) {
1139 buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$
1141 if (problemLine == 0) {
1142 problemLine = problem.getSourceLineNumber();
1146 } // insert the top line afterwards, once knowing how many problems we have to consider
1148 buffer.insert(0, Util.bind("compilation.unresolvedProblems" )); //$NON-NLS-1$
1150 buffer.insert(0, Util.bind("compilation.unresolvedProblem" )); //$NON-NLS-1$
1152 problemString = buffer.toString();
1155 // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "")
1156 codeStream.generateCodeAttributeForProblemMethod(problemString);
1157 completeCodeAttributeForProblemMethod(
1160 codeAttributeOffset,
1161 ((SourceTypeBinding) methodBinding.declaringClass)
1163 .referenceCompilationUnit()
1165 .lineSeparatorPositions,
1167 completeMethodInfo(methodAttributeOffset, attributeNumber);
1172 * Generate the byte for a problem method info that correspond to a boggus method.
1173 * Reset the position inside the contents byte array to the savedOffset.
1175 * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
1176 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
1177 * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[]
1178 * @param savedOffset <CODE>int</CODE>
1180 public void addProblemMethod(
1181 AbstractMethodDeclaration method,
1182 MethodBinding methodBinding,
1183 IProblem[] problems,
1185 // we need to move back the contentsOffset to the value at the beginning of the method
1186 contentsOffset = savedOffset;
1187 methodCount--; // we need to remove the method that causes the problem
1188 addProblemMethod(method, methodBinding, problems);
1193 * Generate the byte for all the special method infos.
1195 * - synthetic access methods
1196 * - default abstract methods
1198 public void addSpecialMethods() {
1200 // add all methods (default abstract methods and synthetic)
1202 // default abstract methods
1203 generateMissingAbstractMethods(referenceBinding.scope.referenceType().missingAbstractMethods, referenceBinding.scope.referenceCompilationUnit().compilationResult);
1205 MethodBinding[] defaultAbstractMethods = this.referenceBinding.getDefaultAbstractMethods();
1206 for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) {
1207 generateMethodInfoHeader(defaultAbstractMethods[i]);
1208 int methodAttributeOffset = contentsOffset;
1209 int attributeNumber = generateMethodInfoAttribute(defaultAbstractMethods[i]);
1210 completeMethodInfo(methodAttributeOffset, attributeNumber);
1212 // add synthetic methods infos
1213 SyntheticMethodBinding[] syntheticMethods = this.referenceBinding.syntheticMethods();
1214 if (syntheticMethods != null) {
1215 for (int i = 0, max = syntheticMethods.length; i < max; i++) {
1216 SyntheticMethodBinding syntheticMethod = syntheticMethods[i];
1217 switch (syntheticMethod.kind) {
1218 case SyntheticMethodBinding.FieldReadAccess :
1219 // generate a method info to emulate an reading access to
1220 // a non-accessible field
1221 addSyntheticFieldReadAccessMethod(syntheticMethod);
1223 case SyntheticMethodBinding.FieldWriteAccess :
1224 // generate a method info to emulate an writing access to
1225 // a non-accessible field
1226 addSyntheticFieldWriteAccessMethod(syntheticMethod);
1228 case SyntheticMethodBinding.MethodAccess :
1229 case SyntheticMethodBinding.SuperMethodAccess :
1230 case SyntheticMethodBinding.BridgeMethod :
1231 // generate a method info to emulate an access to a non-accessible method / super-method or bridge method
1232 addSyntheticMethodAccessMethod(syntheticMethod);
1234 case SyntheticMethodBinding.ConstructorAccess :
1235 // generate a method info to emulate an access to a non-accessible constructor
1236 addSyntheticConstructorAccessMethod(syntheticMethod);
1238 case SyntheticMethodBinding.EnumValues :
1239 // generate a method info to define <enum>#values()
1240 addSyntheticEnumValuesMethod(syntheticMethod);
1242 case SyntheticMethodBinding.EnumValueOf :
1243 // generate a method info to define <enum>#valueOf(String)
1244 addSyntheticEnumValueOfMethod(syntheticMethod);
1253 * Generate the bytes for a synthetic method that provides an access to a private constructor.
1255 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1257 public void addSyntheticConstructorAccessMethod(SyntheticMethodBinding methodBinding) {
1258 generateMethodInfoHeader(methodBinding);
1259 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1260 contents[contentsOffset++] = 0;
1261 contents[contentsOffset++] = 2;
1263 int codeAttributeOffset = contentsOffset;
1264 generateCodeAttributeHeader();
1265 codeStream.init(this);
1266 codeStream.generateSyntheticBodyForConstructorAccess(methodBinding);
1267 completeCodeAttributeForSyntheticMethod(
1269 codeAttributeOffset,
1270 ((SourceTypeBinding) methodBinding.declaringClass)
1272 .referenceCompilationUnit()
1274 .lineSeparatorPositions);
1275 // add the synthetic attribute
1276 int syntheticAttributeNameIndex =
1277 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1278 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1279 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1280 // the length of a synthetic attribute is equals to 0
1281 contents[contentsOffset++] = 0;
1282 contents[contentsOffset++] = 0;
1283 contents[contentsOffset++] = 0;
1284 contents[contentsOffset++] = 0;
1289 * Generate the bytes for a synthetic method that implements Enum#valueOf(String) for a given enum type
1291 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1293 public void addSyntheticEnumValueOfMethod(SyntheticMethodBinding methodBinding) {
1295 generateMethodInfoHeader(methodBinding);
1296 // We know that we won't get more than 1 attribute: the code attribute
1297 contents[contentsOffset++] = 0;
1298 contents[contentsOffset++] = 1;
1300 int codeAttributeOffset = contentsOffset;
1301 generateCodeAttributeHeader();
1302 codeStream.init(this);
1303 codeStream.generateSyntheticBodyForEnumValueOf(methodBinding);
1304 completeCodeAttributeForSyntheticMethod(
1306 codeAttributeOffset,
1307 ((SourceTypeBinding) methodBinding.declaringClass)
1309 .referenceCompilationUnit()
1311 .lineSeparatorPositions);
1312 // // add the synthetic attribute
1313 // int syntheticAttributeNameIndex =
1314 // constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1315 // contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1316 // contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1317 // // the length of a synthetic attribute is equals to 0
1318 // contents[contentsOffset++] = 0;
1319 // contents[contentsOffset++] = 0;
1320 // contents[contentsOffset++] = 0;
1321 // contents[contentsOffset++] = 0;
1327 * Generate the bytes for a synthetic method that implements Enum#values() for a given enum type
1329 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1331 public void addSyntheticEnumValuesMethod(SyntheticMethodBinding methodBinding) {
1333 generateMethodInfoHeader(methodBinding);
1334 // We know that we won't get more than 1 attribute: the code attribute
1335 contents[contentsOffset++] = 0;
1336 contents[contentsOffset++] = 1;
1338 int codeAttributeOffset = contentsOffset;
1339 generateCodeAttributeHeader();
1340 codeStream.init(this);
1341 codeStream.generateSyntheticBodyForEnumValues(methodBinding);
1342 completeCodeAttributeForSyntheticMethod(
1344 codeAttributeOffset,
1345 ((SourceTypeBinding) methodBinding.declaringClass)
1347 .referenceCompilationUnit()
1349 .lineSeparatorPositions);
1350 // // add the synthetic attribute
1351 // int syntheticAttributeNameIndex =
1352 // constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1353 // contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1354 // contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1355 // // the length of a synthetic attribute is equals to 0
1356 // contents[contentsOffset++] = 0;
1357 // contents[contentsOffset++] = 0;
1358 // contents[contentsOffset++] = 0;
1359 // contents[contentsOffset++] = 0;
1365 * Generate the byte for a problem method info that correspond to a synthetic method that
1366 * generate an read access to a private field.
1368 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1370 public void addSyntheticFieldReadAccessMethod(SyntheticMethodBinding methodBinding) {
1371 generateMethodInfoHeader(methodBinding);
1372 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1373 contents[contentsOffset++] = 0;
1374 contents[contentsOffset++] = 2;
1376 int codeAttributeOffset = contentsOffset;
1377 generateCodeAttributeHeader();
1378 codeStream.init(this);
1379 codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding);
1380 completeCodeAttributeForSyntheticMethod(
1382 codeAttributeOffset,
1383 ((SourceTypeBinding) methodBinding.declaringClass)
1385 .referenceCompilationUnit()
1387 .lineSeparatorPositions);
1388 // add the synthetic attribute
1389 int syntheticAttributeNameIndex =
1390 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1391 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1392 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1393 // the length of a synthetic attribute is equals to 0
1394 contents[contentsOffset++] = 0;
1395 contents[contentsOffset++] = 0;
1396 contents[contentsOffset++] = 0;
1397 contents[contentsOffset++] = 0;
1402 * Generate the byte for a problem method info that correspond to a synthetic method that
1403 * generate an write access to a private field.
1405 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1407 public void addSyntheticFieldWriteAccessMethod(SyntheticMethodBinding methodBinding) {
1408 generateMethodInfoHeader(methodBinding);
1409 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1410 contents[contentsOffset++] = 0;
1411 contents[contentsOffset++] = 2;
1413 int codeAttributeOffset = contentsOffset;
1414 generateCodeAttributeHeader();
1415 codeStream.init(this);
1416 codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding);
1417 completeCodeAttributeForSyntheticMethod(
1419 codeAttributeOffset,
1420 ((SourceTypeBinding) methodBinding.declaringClass)
1422 .referenceCompilationUnit()
1424 .lineSeparatorPositions);
1425 // add the synthetic attribute
1426 int syntheticAttributeNameIndex =
1427 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1428 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1429 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1430 // the length of a synthetic attribute is equals to 0
1431 contents[contentsOffset++] = 0;
1432 contents[contentsOffset++] = 0;
1433 contents[contentsOffset++] = 0;
1434 contents[contentsOffset++] = 0;
1439 * Generate the bytes for a synthetic method that provides access to a private method.
1441 * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
1443 public void addSyntheticMethodAccessMethod(SyntheticMethodBinding methodBinding) {
1444 generateMethodInfoHeader(methodBinding);
1445 // We know that we won't get more than 2 attribute: the code attribute + synthetic attribute
1446 contents[contentsOffset++] = 0;
1447 contents[contentsOffset++] = 2;
1449 int codeAttributeOffset = contentsOffset;
1450 generateCodeAttributeHeader();
1451 codeStream.init(this);
1452 codeStream.generateSyntheticBodyForMethodAccess(methodBinding);
1453 completeCodeAttributeForSyntheticMethod(
1455 codeAttributeOffset,
1456 ((SourceTypeBinding) methodBinding.declaringClass)
1458 .referenceCompilationUnit()
1460 .lineSeparatorPositions);
1461 // add the synthetic attribute
1462 int syntheticAttributeNameIndex =
1463 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
1464 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
1465 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
1466 // the length of a synthetic attribute is equals to 0
1467 contents[contentsOffset++] = 0;
1468 contents[contentsOffset++] = 0;
1469 contents[contentsOffset++] = 0;
1470 contents[contentsOffset++] = 0;
1475 * That method completes the creation of the code attribute by setting
1476 * - the attribute_length
1481 * - and debug attributes if necessary.
1483 * @param codeAttributeOffset <CODE>int</CODE>
1485 public void completeCodeAttribute(int codeAttributeOffset) {
1486 // reinitialize the localContents with the byte modified by the code stream
1487 this.contents = codeStream.bCodeStream;
1488 int localContentsOffset = codeStream.classFileOffset;
1489 // codeAttributeOffset is the position inside localContents byte array before we started to write
1490 // any information about the codeAttribute
1491 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1492 // to get the right position, 6 for the max_stack etc...
1493 int code_length = codeStream.position;
1494 if (code_length > 65535) {
1495 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1496 codeStream.methodDeclaration);
1498 if (localContentsOffset + 20 >= this.contents.length) {
1501 int max_stack = codeStream.stackMax;
1502 this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1503 this.contents[codeAttributeOffset + 7] = (byte) max_stack;
1504 int max_locals = codeStream.maxLocals;
1505 this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1506 this.contents[codeAttributeOffset + 9] = (byte) max_locals;
1507 this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1508 this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1509 this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1510 this.contents[codeAttributeOffset + 13] = (byte) code_length;
1512 // write the exception table
1513 int exceptionHandlersNumber = codeStream.exceptionHandlersCounter;
1514 ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
1515 int exSize = exceptionHandlersNumber * 8 + 2;
1516 if (exSize + localContentsOffset >= this.contents.length) {
1517 resizeContents(exSize);
1519 // there is no exception table, so we need to offset by 2 the current offset and move
1520 // on the attribute generation
1521 this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
1522 this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber;
1523 for (int i = 0, max = codeStream.exceptionHandlersIndex; i < max; i++) {
1524 ExceptionLabel exceptionHandler = exceptionHandlers[i];
1525 if (exceptionHandler != null) {
1526 int start = exceptionHandler.start;
1527 this.contents[localContentsOffset++] = (byte) (start >> 8);
1528 this.contents[localContentsOffset++] = (byte) start;
1529 int end = exceptionHandler.end;
1530 this.contents[localContentsOffset++] = (byte) (end >> 8);
1531 this.contents[localContentsOffset++] = (byte) end;
1532 int handlerPC = exceptionHandler.position;
1533 this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
1534 this.contents[localContentsOffset++] = (byte) handlerPC;
1535 if (exceptionHandler.exceptionType == null) {
1536 // any exception handler
1537 this.contents[localContentsOffset++] = 0;
1538 this.contents[localContentsOffset++] = 0;
1541 if (exceptionHandler.exceptionType == BaseTypes.NullBinding) {
1542 /* represents ClassNotFoundException, see class literal access*/
1543 nameIndex = constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName);
1545 nameIndex = constantPool.literalIndexForType(exceptionHandler.exceptionType.constantPoolName());
1547 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1548 this.contents[localContentsOffset++] = (byte) nameIndex;
1553 int codeAttributeAttributeOffset = localContentsOffset;
1554 int attributeNumber = 0;
1555 // leave two bytes for the attribute_length
1556 localContentsOffset += 2;
1558 // first we handle the linenumber attribute
1559 if (codeStream.generateLineNumberAttributes) {
1560 /* Create and add the line number attribute (used for debugging)
1561 * Build the pairs of:
1562 * (bytecodePC lineNumber)
1563 * according to the table of start line indexes and the pcToSourceMap table
1564 * contained into the codestream
1566 int[] pcToSourceMapTable;
1567 if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
1568 && (codeStream.pcToSourceMapSize != 0)) {
1569 int lineNumberNameIndex =
1570 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1571 if (localContentsOffset + 8 >= this.contents.length) {
1574 this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1575 this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
1576 int lineNumberTableOffset = localContentsOffset;
1577 localContentsOffset += 6;
1578 // leave space for attribute_length and line_number_table_length
1579 int numberOfEntries = 0;
1580 int length = codeStream.pcToSourceMapSize;
1581 for (int i = 0; i < length;) {
1583 if (localContentsOffset + 4 >= this.contents.length) {
1586 int pc = pcToSourceMapTable[i++];
1587 this.contents[localContentsOffset++] = (byte) (pc >> 8);
1588 this.contents[localContentsOffset++] = (byte) pc;
1589 int lineNumber = pcToSourceMapTable[i++];
1590 this.contents[localContentsOffset++] = (byte) (lineNumber >> 8);
1591 this.contents[localContentsOffset++] = (byte) lineNumber;
1594 // now we change the size of the line number attribute
1595 int lineNumberAttr_length = numberOfEntries * 4 + 2;
1596 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
1597 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
1598 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
1599 this.contents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
1600 this.contents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
1601 this.contents[lineNumberTableOffset++] = (byte) numberOfEntries;
1605 // then we do the local variable attribute
1606 if (codeStream.generateLocalVariableTableAttributes) {
1607 int localVariableTableOffset = localContentsOffset;
1608 int numberOfEntries = 0;
1609 int localVariableNameIndex =
1610 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1611 final boolean methodDeclarationIsStatic = codeStream.methodDeclaration.isStatic();
1612 int maxOfEntries = 8 + 10 * (methodDeclarationIsStatic ? 0 : 1);
1613 for (int i = 0; i < codeStream.allLocalsCounter; i++) {
1614 maxOfEntries += 10 * codeStream.locals[i].initializationCount;
1616 // reserve enough space
1617 if (localContentsOffset + maxOfEntries >= this.contents.length) {
1618 resizeContents(maxOfEntries);
1620 this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1621 this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
1622 localContentsOffset += 6;
1623 // leave space for attribute_length and local_variable_table_length
1625 int descriptorIndex;
1626 SourceTypeBinding declaringClassBinding = null;
1627 if (!methodDeclarationIsStatic) {
1629 this.contents[localContentsOffset++] = 0; // the startPC for this is always 0
1630 this.contents[localContentsOffset++] = 0;
1631 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
1632 this.contents[localContentsOffset++] = (byte) code_length;
1633 nameIndex = constantPool.literalIndex(ConstantPool.This);
1634 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1635 this.contents[localContentsOffset++] = (byte) nameIndex;
1636 declaringClassBinding = (SourceTypeBinding) codeStream.methodDeclaration.binding.declaringClass;
1638 constantPool.literalIndex(
1639 declaringClassBinding.signature());
1640 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1641 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1642 this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0
1643 this.contents[localContentsOffset++] = 0;
1645 // used to remember the local variable with a generic type
1646 int genericLocalVariablesCounter = 0;
1647 LocalVariableBinding[] genericLocalVariables = null;
1648 int numberOfGenericEntries = 0;
1650 for (int i = 0, max = codeStream.allLocalsCounter; i < max; i++) {
1651 LocalVariableBinding localVariable = codeStream.locals[i];
1652 final TypeBinding localVariableTypeBinding = localVariable.type;
1653 boolean isParameterizedType = localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable();
1654 if (localVariable.initializationCount != 0 && isParameterizedType) {
1655 if (genericLocalVariables == null) {
1656 // we cannot have more than max locals
1657 genericLocalVariables = new LocalVariableBinding[max];
1659 genericLocalVariables[genericLocalVariablesCounter++] = localVariable;
1661 for (int j = 0; j < localVariable.initializationCount; j++) {
1662 int startPC = localVariable.initializationPCs[j << 1];
1663 int endPC = localVariable.initializationPCs[(j << 1) + 1];
1664 if (startPC != endPC) { // only entries for non zero length
1666 localVariable.declaringScope.problemReporter().abortDueToInternalError(
1667 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
1668 (ASTNode) localVariable.declaringScope.methodScope().referenceContext);
1670 if (isParameterizedType) {
1671 numberOfGenericEntries++;
1673 // now we can safely add the local entry
1675 this.contents[localContentsOffset++] = (byte) (startPC >> 8);
1676 this.contents[localContentsOffset++] = (byte) startPC;
1677 int length = endPC - startPC;
1678 this.contents[localContentsOffset++] = (byte) (length >> 8);
1679 this.contents[localContentsOffset++] = (byte) length;
1680 nameIndex = constantPool.literalIndex(localVariable.name);
1681 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1682 this.contents[localContentsOffset++] = (byte) nameIndex;
1683 descriptorIndex = constantPool.literalIndex(localVariableTypeBinding.signature());
1684 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1685 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1686 int resolvedPosition = localVariable.resolvedPosition;
1687 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1688 this.contents[localContentsOffset++] = (byte) resolvedPosition;
1692 int value = numberOfEntries * 10 + 2;
1693 localVariableTableOffset += 2;
1694 this.contents[localVariableTableOffset++] = (byte) (value >> 24);
1695 this.contents[localVariableTableOffset++] = (byte) (value >> 16);
1696 this.contents[localVariableTableOffset++] = (byte) (value >> 8);
1697 this.contents[localVariableTableOffset++] = (byte) value;
1698 this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1699 this.contents[localVariableTableOffset] = (byte) numberOfEntries;
1702 final boolean currentInstanceIsGeneric =
1703 !methodDeclarationIsStatic
1704 && declaringClassBinding != null
1705 && declaringClassBinding.typeVariables != NoTypeVariables;
1706 if (genericLocalVariablesCounter != 0 || currentInstanceIsGeneric) {
1707 // add the local variable type table attribute
1708 numberOfGenericEntries += (currentInstanceIsGeneric ? 1 : 0);
1709 maxOfEntries = 8 + numberOfGenericEntries * 10;
1710 // reserve enough space
1711 if (localContentsOffset + maxOfEntries >= this.contents.length) {
1712 resizeContents(maxOfEntries);
1714 int localVariableTypeNameIndex =
1715 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTypeTableName);
1716 this.contents[localContentsOffset++] = (byte) (localVariableTypeNameIndex >> 8);
1717 this.contents[localContentsOffset++] = (byte) localVariableTypeNameIndex;
1718 value = numberOfGenericEntries * 10 + 2;
1719 this.contents[localContentsOffset++] = (byte) (value >> 24);
1720 this.contents[localContentsOffset++] = (byte) (value >> 16);
1721 this.contents[localContentsOffset++] = (byte) (value >> 8);
1722 this.contents[localContentsOffset++] = (byte) value;
1723 this.contents[localContentsOffset++] = (byte) (numberOfGenericEntries >> 8);
1724 this.contents[localContentsOffset++] = (byte) numberOfGenericEntries;
1725 if (currentInstanceIsGeneric) {
1726 this.contents[localContentsOffset++] = 0; // the startPC for this is always 0
1727 this.contents[localContentsOffset++] = 0;
1728 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
1729 this.contents[localContentsOffset++] = (byte) code_length;
1730 nameIndex = constantPool.literalIndex(ConstantPool.This);
1731 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1732 this.contents[localContentsOffset++] = (byte) nameIndex;
1733 descriptorIndex = constantPool.literalIndex(declaringClassBinding.genericTypeSignature());
1734 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1735 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1736 this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0
1737 this.contents[localContentsOffset++] = 0;
1740 for (int i = 0; i < genericLocalVariablesCounter; i++) {
1741 LocalVariableBinding localVariable = genericLocalVariables[i];
1742 for (int j = 0; j < localVariable.initializationCount; j++) {
1743 int startPC = localVariable.initializationPCs[j << 1];
1744 int endPC = localVariable.initializationPCs[(j << 1) + 1];
1745 if (startPC != endPC) {
1746 // only entries for non zero length
1747 // now we can safely add the local entry
1748 this.contents[localContentsOffset++] = (byte) (startPC >> 8);
1749 this.contents[localContentsOffset++] = (byte) startPC;
1750 int length = endPC - startPC;
1751 this.contents[localContentsOffset++] = (byte) (length >> 8);
1752 this.contents[localContentsOffset++] = (byte) length;
1753 nameIndex = constantPool.literalIndex(localVariable.name);
1754 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1755 this.contents[localContentsOffset++] = (byte) nameIndex;
1756 descriptorIndex = constantPool.literalIndex(localVariable.type.genericTypeSignature());
1757 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1758 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1759 int resolvedPosition = localVariable.resolvedPosition;
1760 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1761 this.contents[localContentsOffset++] = (byte) resolvedPosition;
1768 // update the number of attributes
1769 // ensure first that there is enough space available inside the localContents array
1770 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
1773 this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
1774 this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
1776 // update the attribute length
1777 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
1778 this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
1779 this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
1780 this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
1781 this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
1782 contentsOffset = localContentsOffset;
1787 * That method completes the creation of the code attribute by setting
1788 * - the attribute_length
1793 * - and debug attributes if necessary.
1795 * @param codeAttributeOffset <CODE>int</CODE>
1797 public void completeCodeAttributeForClinit(int codeAttributeOffset) {
1798 // reinitialize the contents with the byte modified by the code stream
1799 this.contents = codeStream.bCodeStream;
1800 int localContentsOffset = codeStream.classFileOffset;
1801 // codeAttributeOffset is the position inside contents byte array before we started to write
1802 // any information about the codeAttribute
1803 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
1804 // to get the right position, 6 for the max_stack etc...
1805 int code_length = codeStream.position;
1806 if (code_length > 65535) {
1807 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
1808 codeStream.methodDeclaration.scope.referenceType());
1810 if (localContentsOffset + 20 >= this.contents.length) {
1813 int max_stack = codeStream.stackMax;
1814 this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
1815 this.contents[codeAttributeOffset + 7] = (byte) max_stack;
1816 int max_locals = codeStream.maxLocals;
1817 this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
1818 this.contents[codeAttributeOffset + 9] = (byte) max_locals;
1819 this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
1820 this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
1821 this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
1822 this.contents[codeAttributeOffset + 13] = (byte) code_length;
1824 // write the exception table
1825 int exceptionHandlersNumber = codeStream.exceptionHandlersCounter;
1826 ExceptionLabel[] exceptionHandlers = codeStream.exceptionHandlers;
1827 int exSize = exceptionHandlersNumber * 8 + 2;
1828 if (exSize + localContentsOffset >= this.contents.length) {
1829 resizeContents(exSize);
1831 // there is no exception table, so we need to offset by 2 the current offset and move
1832 // on the attribute generation
1833 this.contents[localContentsOffset++] = (byte) (exceptionHandlersNumber >> 8);
1834 this.contents[localContentsOffset++] = (byte) exceptionHandlersNumber;
1835 for (int i = 0, max = codeStream.exceptionHandlersIndex; i < max; i++) {
1836 ExceptionLabel exceptionHandler = exceptionHandlers[i];
1837 if (exceptionHandler != null) {
1838 int start = exceptionHandler.start;
1839 this.contents[localContentsOffset++] = (byte) (start >> 8);
1840 this.contents[localContentsOffset++] = (byte) start;
1841 int end = exceptionHandler.end;
1842 this.contents[localContentsOffset++] = (byte) (end >> 8);
1843 this.contents[localContentsOffset++] = (byte) end;
1844 int handlerPC = exceptionHandler.position;
1845 this.contents[localContentsOffset++] = (byte) (handlerPC >> 8);
1846 this.contents[localContentsOffset++] = (byte) handlerPC;
1847 if (exceptionHandler.exceptionType == null) {
1848 // any exception handler
1849 this.contents[localContentsOffset++] = 0;
1850 this.contents[localContentsOffset++] = 0;
1853 if (exceptionHandler.exceptionType == BaseTypes.NullBinding) {
1854 /* represents denote ClassNotFoundException, see class literal access*/
1855 nameIndex = constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName);
1857 nameIndex = constantPool.literalIndexForType(exceptionHandler.exceptionType.constantPoolName());
1859 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1860 this.contents[localContentsOffset++] = (byte) nameIndex;
1865 int codeAttributeAttributeOffset = localContentsOffset;
1866 int attributeNumber = 0;
1867 // leave two bytes for the attribute_length
1868 localContentsOffset += 2;
1870 // first we handle the linenumber attribute
1871 if (codeStream.generateLineNumberAttributes) {
1872 /* Create and add the line number attribute (used for debugging)
1873 * Build the pairs of:
1874 * (bytecodePC lineNumber)
1875 * according to the table of start line indexes and the pcToSourceMap table
1876 * contained into the codestream
1878 int[] pcToSourceMapTable;
1879 if (((pcToSourceMapTable = codeStream.pcToSourceMap) != null)
1880 && (codeStream.pcToSourceMapSize != 0)) {
1881 int lineNumberNameIndex =
1882 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
1883 if (localContentsOffset + 8 >= this.contents.length) {
1886 this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
1887 this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
1888 int lineNumberTableOffset = localContentsOffset;
1889 localContentsOffset += 6;
1890 // leave space for attribute_length and line_number_table_length
1891 int numberOfEntries = 0;
1892 int length = codeStream.pcToSourceMapSize;
1893 for (int i = 0; i < length;) {
1895 if (localContentsOffset + 4 >= this.contents.length) {
1898 int pc = pcToSourceMapTable[i++];
1899 this.contents[localContentsOffset++] = (byte) (pc >> 8);
1900 this.contents[localContentsOffset++] = (byte) pc;
1901 int lineNumber = pcToSourceMapTable[i++];
1902 this.contents[localContentsOffset++] = (byte) (lineNumber >> 8);
1903 this.contents[localContentsOffset++] = (byte) lineNumber;
1906 // now we change the size of the line number attribute
1907 int lineNumberAttr_length = numberOfEntries * 4 + 2;
1908 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24);
1909 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16);
1910 this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8);
1911 this.contents[lineNumberTableOffset++] = (byte) lineNumberAttr_length;
1912 this.contents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8);
1913 this.contents[lineNumberTableOffset++] = (byte) numberOfEntries;
1917 // then we do the local variable attribute
1918 if (codeStream.generateLocalVariableTableAttributes) {
1919 int localVariableTableOffset = localContentsOffset;
1920 int numberOfEntries = 0;
1921 // codeAttribute.addLocalVariableTableAttribute(this);
1922 if ((codeStream.pcToSourceMap != null)
1923 && (codeStream.pcToSourceMapSize != 0)) {
1924 int localVariableNameIndex =
1925 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
1926 if (localContentsOffset + 8 >= this.contents.length) {
1929 this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
1930 this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
1931 localContentsOffset += 6;
1933 // leave space for attribute_length and local_variable_table_length
1935 int descriptorIndex;
1937 // used to remember the local variable with a generic type
1938 int genericLocalVariablesCounter = 0;
1939 LocalVariableBinding[] genericLocalVariables = null;
1940 int numberOfGenericEntries = 0;
1942 for (int i = 0, max = codeStream.allLocalsCounter; i < max; i++) {
1943 LocalVariableBinding localVariable = codeStream.locals[i];
1944 final TypeBinding localVariableTypeBinding = localVariable.type;
1945 boolean isParameterizedType = localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable();
1946 if (localVariable.initializationCount != 0 && isParameterizedType) {
1947 if (genericLocalVariables == null) {
1948 // we cannot have more than max locals
1949 genericLocalVariables = new LocalVariableBinding[max];
1951 genericLocalVariables[genericLocalVariablesCounter++] = localVariable;
1953 for (int j = 0; j < localVariable.initializationCount; j++) {
1954 int startPC = localVariable.initializationPCs[j << 1];
1955 int endPC = localVariable.initializationPCs[(j << 1) + 1];
1956 if (startPC != endPC) { // only entries for non zero length
1958 localVariable.declaringScope.problemReporter().abortDueToInternalError(
1959 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
1960 (ASTNode) localVariable.declaringScope.methodScope().referenceContext);
1962 if (localContentsOffset + 10 >= this.contents.length) {
1965 // now we can safely add the local entry
1967 if (isParameterizedType) {
1968 numberOfGenericEntries++;
1970 this.contents[localContentsOffset++] = (byte) (startPC >> 8);
1971 this.contents[localContentsOffset++] = (byte) startPC;
1972 int length = endPC - startPC;
1973 this.contents[localContentsOffset++] = (byte) (length >> 8);
1974 this.contents[localContentsOffset++] = (byte) length;
1975 nameIndex = constantPool.literalIndex(localVariable.name);
1976 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
1977 this.contents[localContentsOffset++] = (byte) nameIndex;
1978 descriptorIndex = constantPool.literalIndex(localVariableTypeBinding.signature());
1979 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
1980 this.contents[localContentsOffset++] = (byte) descriptorIndex;
1981 int resolvedPosition = localVariable.resolvedPosition;
1982 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
1983 this.contents[localContentsOffset++] = (byte) resolvedPosition;
1987 int value = numberOfEntries * 10 + 2;
1988 localVariableTableOffset += 2;
1989 this.contents[localVariableTableOffset++] = (byte) (value >> 24);
1990 this.contents[localVariableTableOffset++] = (byte) (value >> 16);
1991 this.contents[localVariableTableOffset++] = (byte) (value >> 8);
1992 this.contents[localVariableTableOffset++] = (byte) value;
1993 this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
1994 this.contents[localVariableTableOffset] = (byte) numberOfEntries;
1997 if (genericLocalVariablesCounter != 0) {
1998 // add the local variable type table attribute
1999 // reserve enough space
2000 int maxOfEntries = 8 + numberOfGenericEntries * 10;
2002 if (localContentsOffset + maxOfEntries >= this.contents.length) {
2003 resizeContents(maxOfEntries);
2005 int localVariableTypeNameIndex =
2006 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTypeTableName);
2007 this.contents[localContentsOffset++] = (byte) (localVariableTypeNameIndex >> 8);
2008 this.contents[localContentsOffset++] = (byte) localVariableTypeNameIndex;
2009 value = numberOfGenericEntries * 10 + 2;
2010 this.contents[localContentsOffset++] = (byte) (value >> 24);
2011 this.contents[localContentsOffset++] = (byte) (value >> 16);
2012 this.contents[localContentsOffset++] = (byte) (value >> 8);
2013 this.contents[localContentsOffset++] = (byte) value;
2014 this.contents[localContentsOffset++] = (byte) (numberOfGenericEntries >> 8);
2015 this.contents[localContentsOffset++] = (byte) numberOfGenericEntries;
2016 for (int i = 0; i < genericLocalVariablesCounter; i++) {
2017 LocalVariableBinding localVariable = genericLocalVariables[i];
2018 for (int j = 0; j < localVariable.initializationCount; j++) {
2019 int startPC = localVariable.initializationPCs[j << 1];
2020 int endPC = localVariable.initializationPCs[(j << 1) + 1];
2021 if (startPC != endPC) { // only entries for non zero length
2022 // now we can safely add the local entry
2023 this.contents[localContentsOffset++] = (byte) (startPC >> 8);
2024 this.contents[localContentsOffset++] = (byte) startPC;
2025 int length = endPC - startPC;
2026 this.contents[localContentsOffset++] = (byte) (length >> 8);
2027 this.contents[localContentsOffset++] = (byte) length;
2028 nameIndex = constantPool.literalIndex(localVariable.name);
2029 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2030 this.contents[localContentsOffset++] = (byte) nameIndex;
2031 descriptorIndex = constantPool.literalIndex(localVariable.type.genericTypeSignature());
2032 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2033 this.contents[localContentsOffset++] = (byte) descriptorIndex;
2034 int resolvedPosition = localVariable.resolvedPosition;
2035 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2036 this.contents[localContentsOffset++] = (byte) resolvedPosition;
2044 // update the number of attributes
2045 // ensure first that there is enough space available inside the contents array
2046 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
2049 this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2050 this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2051 // update the attribute length
2052 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2053 this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2054 this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2055 this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2056 this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2057 contentsOffset = localContentsOffset;
2062 * That method completes the creation of the code attribute by setting
2063 * - the attribute_length
2068 * - and debug attributes if necessary.
2070 * @param codeAttributeOffset <CODE>int</CODE>
2071 * @param startLineIndexes int[]
2073 public void completeCodeAttributeForClinit(
2074 int codeAttributeOffset,
2075 int[] startLineIndexes,
2077 // reinitialize the contents with the byte modified by the code stream
2078 this.contents = codeStream.bCodeStream;
2079 int localContentsOffset = codeStream.classFileOffset;
2080 // codeAttributeOffset is the position inside contents byte array before we started to write
2081 // any information about the codeAttribute
2082 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
2083 // to get the right position, 6 for the max_stack etc...
2084 int code_length = codeStream.position;
2085 if (code_length > 65535) {
2086 codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
2087 codeStream.methodDeclaration.scope.referenceType());
2089 if (localContentsOffset + 20 >= this.contents.length) {
2092 int max_stack = codeStream.stackMax;
2093 this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
2094 this.contents[codeAttributeOffset + 7] = (byte) max_stack;
2095 int max_locals = codeStream.maxLocals;
2096 this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
2097 this.contents[codeAttributeOffset + 9] = (byte) max_locals;
2098 this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
2099 this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
2100 this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
2101 this.contents[codeAttributeOffset + 13] = (byte) code_length;
2103 // write the exception table
2104 this.contents[localContentsOffset++] = 0;
2105 this.contents[localContentsOffset++] = 0;
2108 int codeAttributeAttributeOffset = localContentsOffset;
2109 int attributeNumber = 0; // leave two bytes for the attribute_length
2110 localContentsOffset += 2; // first we handle the linenumber attribute
2112 // first we handle the linenumber attribute
2113 if (codeStream.generateLineNumberAttributes) {
2114 if (localContentsOffset + 20 >= this.contents.length) {
2117 /* Create and add the line number attribute (used for debugging)
2118 * Build the pairs of:
2119 * (bytecodePC lineNumber)
2120 * according to the table of start line indexes and the pcToSourceMap table
2121 * contained into the codestream
2123 int lineNumberNameIndex =
2124 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
2125 this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
2126 this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
2127 this.contents[localContentsOffset++] = 0;
2128 this.contents[localContentsOffset++] = 0;
2129 this.contents[localContentsOffset++] = 0;
2130 this.contents[localContentsOffset++] = 6;
2131 this.contents[localContentsOffset++] = 0;
2132 this.contents[localContentsOffset++] = 1;
2133 // first entry at pc = 0
2134 this.contents[localContentsOffset++] = 0;
2135 this.contents[localContentsOffset++] = 0;
2136 this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
2137 this.contents[localContentsOffset++] = (byte) problemLine;
2138 // now we change the size of the line number attribute
2141 // then we do the local variable attribute
2142 if (codeStream.generateLocalVariableTableAttributes) {
2143 int localVariableNameIndex =
2144 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
2145 if (localContentsOffset + 8 >= this.contents.length) {
2148 this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
2149 this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
2150 this.contents[localContentsOffset++] = 0;
2151 this.contents[localContentsOffset++] = 0;
2152 this.contents[localContentsOffset++] = 0;
2153 this.contents[localContentsOffset++] = 2;
2154 this.contents[localContentsOffset++] = 0;
2155 this.contents[localContentsOffset++] = 0;
2158 // update the number of attributes
2159 // ensure first that there is enough space available inside the contents array
2160 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
2163 this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2164 this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2165 // update the attribute length
2166 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2167 this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2168 this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2169 this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2170 this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2171 contentsOffset = localContentsOffset;
2177 public void completeCodeAttributeForMissingAbstractProblemMethod(
2178 MethodBinding binding,
2179 int codeAttributeOffset,
2180 int[] startLineIndexes,
2182 // reinitialize the localContents with the byte modified by the code stream
2183 this.contents = codeStream.bCodeStream;
2184 int localContentsOffset = codeStream.classFileOffset;
2185 // 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...
2186 int max_stack = codeStream.stackMax;
2187 this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
2188 this.contents[codeAttributeOffset + 7] = (byte) max_stack;
2189 int max_locals = codeStream.maxLocals;
2190 this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
2191 this.contents[codeAttributeOffset + 9] = (byte) max_locals;
2192 int code_length = codeStream.position;
2193 this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
2194 this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
2195 this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
2196 this.contents[codeAttributeOffset + 13] = (byte) code_length;
2197 // write the exception table
2198 if (localContentsOffset + 50 >= this.contents.length) {
2201 this.contents[localContentsOffset++] = 0;
2202 this.contents[localContentsOffset++] = 0;
2204 int codeAttributeAttributeOffset = localContentsOffset;
2205 int attributeNumber = 0; // leave two bytes for the attribute_length
2206 localContentsOffset += 2; // first we handle the linenumber attribute
2208 if (codeStream.generateLineNumberAttributes) {
2209 /* Create and add the line number attribute (used for debugging)
2210 * Build the pairs of:
2211 * (bytecodePC lineNumber)
2212 * according to the table of start line indexes and the pcToSourceMap table
2213 * contained into the codestream
2215 int lineNumberNameIndex =
2216 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
2217 this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
2218 this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
2219 this.contents[localContentsOffset++] = 0;
2220 this.contents[localContentsOffset++] = 0;
2221 this.contents[localContentsOffset++] = 0;
2222 this.contents[localContentsOffset++] = 6;
2223 this.contents[localContentsOffset++] = 0;
2224 this.contents[localContentsOffset++] = 1;
2225 if (problemLine == 0) {
2226 problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
2228 // first entry at pc = 0
2229 this.contents[localContentsOffset++] = 0;
2230 this.contents[localContentsOffset++] = 0;
2231 this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
2232 this.contents[localContentsOffset++] = (byte) problemLine;
2233 // now we change the size of the line number attribute
2237 // then we do the local variable attribute
2238 // update the number of attributes// ensure first that there is enough space available inside the localContents array
2239 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
2242 this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2243 this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2244 // update the attribute length
2245 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2246 this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2247 this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2248 this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2249 this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2250 contentsOffset = localContentsOffset;
2255 * That method completes the creation of the code attribute by setting
2256 * - the attribute_length
2261 * - and debug attributes if necessary.
2263 * @param codeAttributeOffset <CODE>int</CODE>
2265 public void completeCodeAttributeForProblemMethod(
2266 AbstractMethodDeclaration method,
2267 MethodBinding binding,
2268 int codeAttributeOffset,
2269 int[] startLineIndexes,
2271 // reinitialize the localContents with the byte modified by the code stream
2272 this.contents = codeStream.bCodeStream;
2273 int localContentsOffset = codeStream.classFileOffset;
2274 // 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...
2275 int max_stack = codeStream.stackMax;
2276 this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
2277 this.contents[codeAttributeOffset + 7] = (byte) max_stack;
2278 int max_locals = codeStream.maxLocals;
2279 this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
2280 this.contents[codeAttributeOffset + 9] = (byte) max_locals;
2281 int code_length = codeStream.position;
2282 this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
2283 this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
2284 this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
2285 this.contents[codeAttributeOffset + 13] = (byte) code_length;
2286 // write the exception table
2287 if (localContentsOffset + 50 >= this.contents.length) {
2291 // write the exception table
2292 this.contents[localContentsOffset++] = 0;
2293 this.contents[localContentsOffset++] = 0;
2295 int codeAttributeAttributeOffset = localContentsOffset;
2296 int attributeNumber = 0; // leave two bytes for the attribute_length
2297 localContentsOffset += 2; // first we handle the linenumber attribute
2299 if (codeStream.generateLineNumberAttributes) {
2300 if (localContentsOffset + 20 >= this.contents.length) {
2303 /* Create and add the line number attribute (used for debugging)
2304 * Build the pairs of:
2305 * (bytecodePC lineNumber)
2306 * according to the table of start line indexes and the pcToSourceMap table
2307 * contained into the codestream
2309 int lineNumberNameIndex =
2310 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
2311 this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
2312 this.contents[localContentsOffset++] = (byte) lineNumberNameIndex;
2313 this.contents[localContentsOffset++] = 0;
2314 this.contents[localContentsOffset++] = 0;
2315 this.contents[localContentsOffset++] = 0;
2316 this.contents[localContentsOffset++] = 6;
2317 this.contents[localContentsOffset++] = 0;
2318 this.contents[localContentsOffset++] = 1;
2319 if (problemLine == 0) {
2320 problemLine = searchLineNumber(startLineIndexes, binding.sourceStart());
2322 // first entry at pc = 0
2323 this.contents[localContentsOffset++] = 0;
2324 this.contents[localContentsOffset++] = 0;
2325 this.contents[localContentsOffset++] = (byte) (problemLine >> 8);
2326 this.contents[localContentsOffset++] = (byte) problemLine;
2327 // now we change the size of the line number attribute
2330 // then we do the local variable attribute
2331 if (codeStream.generateLocalVariableTableAttributes) {
2332 // compute the resolved position for the arguments of the method
2334 int localVariableTableOffset = localContentsOffset;
2335 int numberOfEntries = 0;
2336 // codeAttribute.addLocalVariableTableAttribute(this);
2337 int localVariableNameIndex =
2338 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
2339 if (localContentsOffset + 8 >= this.contents.length) {
2342 this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
2343 this.contents[localContentsOffset++] = (byte) localVariableNameIndex;
2344 localContentsOffset += 6;
2345 // leave space for attribute_length and local_variable_table_length
2346 int descriptorIndex;
2348 SourceTypeBinding declaringClassBinding = null;
2349 final boolean methodDeclarationIsStatic = codeStream.methodDeclaration.isStatic();
2350 if (!methodDeclarationIsStatic) {
2352 if (localContentsOffset + 10 >= this.contents.length) {
2355 this.contents[localContentsOffset++] = 0;
2356 this.contents[localContentsOffset++] = 0;
2357 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
2358 this.contents[localContentsOffset++] = (byte) code_length;
2359 nameIndex = constantPool.literalIndex(ConstantPool.This);
2360 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2361 this.contents[localContentsOffset++] = (byte) nameIndex;
2362 declaringClassBinding = (SourceTypeBinding) codeStream.methodDeclaration.binding.declaringClass;
2364 constantPool.literalIndex(declaringClassBinding.signature());
2365 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2366 this.contents[localContentsOffset++] = (byte) descriptorIndex;
2367 // the resolved position for this is always 0
2368 this.contents[localContentsOffset++] = 0;
2369 this.contents[localContentsOffset++] = 0;
2371 // used to remember the local variable with a generic type
2372 int genericLocalVariablesCounter = 0;
2373 LocalVariableBinding[] genericLocalVariables = null;
2374 int numberOfGenericEntries = 0;
2376 if (binding.isConstructor()) {
2377 ReferenceBinding declaringClass = binding.declaringClass;
2378 if (declaringClass.isNestedType()) {
2379 NestedTypeBinding methodDeclaringClass = (NestedTypeBinding) declaringClass;
2380 argSize = methodDeclaringClass.enclosingInstancesSlotSize;
2381 SyntheticArgumentBinding[] syntheticArguments;
2382 if ((syntheticArguments = methodDeclaringClass.syntheticEnclosingInstances()) != null) {
2383 for (int i = 0, max = syntheticArguments.length; i < max; i++) {
2384 LocalVariableBinding localVariable = syntheticArguments[i];
2385 final TypeBinding localVariableTypeBinding = localVariable.type;
2386 if (localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable()) {
2387 if (genericLocalVariables == null) {
2388 // we cannot have more than max locals
2389 genericLocalVariables = new LocalVariableBinding[max];
2391 genericLocalVariables[genericLocalVariablesCounter++] = localVariable;
2392 numberOfGenericEntries++;
2394 if (localContentsOffset + 10 >= this.contents.length) {
2397 // now we can safely add the local entry
2399 this.contents[localContentsOffset++] = 0;
2400 this.contents[localContentsOffset++] = 0;
2401 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
2402 this.contents[localContentsOffset++] = (byte) code_length;
2403 nameIndex = constantPool.literalIndex(localVariable.name);
2404 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2405 this.contents[localContentsOffset++] = (byte) nameIndex;
2406 descriptorIndex = constantPool.literalIndex(localVariableTypeBinding.signature());
2407 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2408 this.contents[localContentsOffset++] = (byte) descriptorIndex;
2409 int resolvedPosition = localVariable.resolvedPosition;
2410 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2411 this.contents[localContentsOffset++] = (byte) resolvedPosition;
2418 argSize = binding.isStatic() ? 0 : 1;
2421 int genericArgumentsCounter = 0;
2422 int[] genericArgumentsNameIndexes = null;
2423 int[] genericArgumentsResolvedPositions = null;
2424 TypeBinding[] genericArgumentsTypeBindings = null;
2426 if (method.binding != null) {
2427 TypeBinding[] parameters = method.binding.parameters;
2428 Argument[] arguments = method.arguments;
2429 if ((parameters != null) && (arguments != null)) {
2430 for (int i = 0, max = parameters.length; i < max; i++) {
2431 TypeBinding argumentBinding = parameters[i];
2432 if (localContentsOffset + 10 >= this.contents.length) {
2435 // now we can safely add the local entry
2437 this.contents[localContentsOffset++] = 0;
2438 this.contents[localContentsOffset++] = 0;
2439 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
2440 this.contents[localContentsOffset++] = (byte) code_length;
2441 nameIndex = constantPool.literalIndex(arguments[i].name);
2442 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2443 this.contents[localContentsOffset++] = (byte) nameIndex;
2444 int resolvedPosition = argSize;
2445 if (argumentBinding.isParameterizedType() || argumentBinding.isTypeVariable()) {
2446 if (genericArgumentsCounter == 0) {
2447 // we cannot have more than max locals
2448 genericArgumentsNameIndexes = new int[max];
2449 genericArgumentsResolvedPositions = new int[max];
2450 genericArgumentsTypeBindings = new TypeBinding[max];
2452 genericArgumentsNameIndexes[genericArgumentsCounter] = nameIndex;
2453 genericArgumentsResolvedPositions[genericArgumentsCounter] = resolvedPosition;
2454 genericArgumentsTypeBindings[genericArgumentsCounter++] = argumentBinding;
2456 descriptorIndex = constantPool.literalIndex(argumentBinding.signature());
2457 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2458 this.contents[localContentsOffset++] = (byte) descriptorIndex;
2459 if ((argumentBinding == BaseTypes.LongBinding)
2460 || (argumentBinding == BaseTypes.DoubleBinding))
2464 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2465 this.contents[localContentsOffset++] = (byte) resolvedPosition;
2469 int value = numberOfEntries * 10 + 2;
2470 localVariableTableOffset += 2;
2471 this.contents[localVariableTableOffset++] = (byte) (value >> 24);
2472 this.contents[localVariableTableOffset++] = (byte) (value >> 16);
2473 this.contents[localVariableTableOffset++] = (byte) (value >> 8);
2474 this.contents[localVariableTableOffset++] = (byte) value;
2475 this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
2476 this.contents[localVariableTableOffset] = (byte) numberOfEntries;
2479 final boolean currentInstanceIsGeneric =
2480 !methodDeclarationIsStatic
2481 && declaringClassBinding != null
2482 && declaringClassBinding.typeVariables != NoTypeVariables;
2483 if (genericLocalVariablesCounter != 0 || genericArgumentsCounter != 0 || currentInstanceIsGeneric) {
2484 // add the local variable type table attribute
2485 numberOfEntries = numberOfGenericEntries + genericArgumentsCounter + (currentInstanceIsGeneric ? 1 : 0);
2486 // reserve enough space
2487 int maxOfEntries = 8 + numberOfEntries * 10;
2488 if (localContentsOffset + maxOfEntries >= this.contents.length) {
2489 resizeContents(maxOfEntries);
2491 int localVariableTypeNameIndex =
2492 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTypeTableName);
2493 this.contents[localContentsOffset++] = (byte) (localVariableTypeNameIndex >> 8);
2494 this.contents[localContentsOffset++] = (byte) localVariableTypeNameIndex;
2495 value = numberOfEntries * 10 + 2;
2496 this.contents[localContentsOffset++] = (byte) (value >> 24);
2497 this.contents[localContentsOffset++] = (byte) (value >> 16);
2498 this.contents[localContentsOffset++] = (byte) (value >> 8);
2499 this.contents[localContentsOffset++] = (byte) value;
2500 this.contents[localContentsOffset++] = (byte) (numberOfEntries >> 8);
2501 this.contents[localContentsOffset++] = (byte) numberOfEntries;
2502 if (currentInstanceIsGeneric) {
2504 this.contents[localContentsOffset++] = 0; // the startPC for this is always 0
2505 this.contents[localContentsOffset++] = 0;
2506 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
2507 this.contents[localContentsOffset++] = (byte) code_length;
2508 nameIndex = constantPool.literalIndex(ConstantPool.This);
2509 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2510 this.contents[localContentsOffset++] = (byte) nameIndex;
2511 descriptorIndex = constantPool.literalIndex(declaringClassBinding.genericTypeSignature());
2512 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2513 this.contents[localContentsOffset++] = (byte) descriptorIndex;
2514 this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0
2515 this.contents[localContentsOffset++] = 0;
2518 for (int i = 0; i < genericLocalVariablesCounter; i++) {
2519 LocalVariableBinding localVariable = genericLocalVariables[i];
2520 this.contents[localContentsOffset++] = 0;
2521 this.contents[localContentsOffset++] = 0;
2522 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
2523 this.contents[localContentsOffset++] = (byte) code_length;
2524 nameIndex = constantPool.literalIndex(localVariable.name);
2525 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2526 this.contents[localContentsOffset++] = (byte) nameIndex;
2527 descriptorIndex = constantPool.literalIndex(localVariable.type.genericTypeSignature());
2528 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2529 this.contents[localContentsOffset++] = (byte) descriptorIndex;
2530 int resolvedPosition = localVariable.resolvedPosition;
2531 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2532 this.contents[localContentsOffset++] = (byte) resolvedPosition;
2534 for (int i = 0; i < genericArgumentsCounter; i++) {
2535 this.contents[localContentsOffset++] = 0;
2536 this.contents[localContentsOffset++] = 0;
2537 this.contents[localContentsOffset++] = (byte) (code_length >> 8);
2538 this.contents[localContentsOffset++] = (byte) code_length;
2539 nameIndex = genericArgumentsNameIndexes[i];
2540 this.contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2541 this.contents[localContentsOffset++] = (byte) nameIndex;
2542 descriptorIndex = constantPool.literalIndex(genericArgumentsTypeBindings[i].genericTypeSignature());
2543 this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2544 this.contents[localContentsOffset++] = (byte) descriptorIndex;
2545 int resolvedPosition = genericArgumentsResolvedPositions[i];
2546 this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2547 this.contents[localContentsOffset++] = (byte) resolvedPosition;
2552 // update the number of attributes// ensure first that there is enough space available inside the localContents array
2553 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
2556 this.contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2557 this.contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2558 // update the attribute length
2559 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2560 this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2561 this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2562 this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2563 this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2564 contentsOffset = localContentsOffset;
2569 * That method completes the creation of the code attribute by setting
2570 * - the attribute_length
2575 * - and debug attributes if necessary.
2577 * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
2578 * @param codeAttributeOffset <CODE>int</CODE>
2580 public void completeCodeAttributeForSyntheticMethod(
2581 SyntheticMethodBinding binding,
2582 int codeAttributeOffset,
2583 int[] startLineIndexes) {
2584 // reinitialize the contents with the byte modified by the code stream
2585 this.contents = codeStream.bCodeStream;
2586 int localContentsOffset = codeStream.classFileOffset;
2587 // codeAttributeOffset is the position inside contents byte array before we started to write
2588 // any information about the codeAttribute
2589 // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset
2590 // to get the right position, 6 for the max_stack etc...
2591 int max_stack = codeStream.stackMax;
2592 contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8);
2593 contents[codeAttributeOffset + 7] = (byte) max_stack;
2594 int max_locals = codeStream.maxLocals;
2595 contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8);
2596 contents[codeAttributeOffset + 9] = (byte) max_locals;
2597 int code_length = codeStream.position;
2598 contents[codeAttributeOffset + 10] = (byte) (code_length >> 24);
2599 contents[codeAttributeOffset + 11] = (byte) (code_length >> 16);
2600 contents[codeAttributeOffset + 12] = (byte) (code_length >> 8);
2601 contents[codeAttributeOffset + 13] = (byte) code_length;
2602 if ((localContentsOffset + 40) >= this.contents.length) {
2605 // there is no exception table, so we need to offset by 2 the current offset and move
2606 // on the attribute generation
2607 contents[localContentsOffset++] = 0;
2608 contents[localContentsOffset++] = 0;
2610 int codeAttributeAttributeOffset = localContentsOffset;
2611 int attributeNumber = 0;
2612 // leave two bytes for the attribute_length
2613 localContentsOffset += 2;
2615 // first we handle the linenumber attribute
2616 if (codeStream.generateLineNumberAttributes) {
2618 int lineNumberNameIndex =
2619 constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
2620 contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8);
2621 contents[localContentsOffset++] = (byte) lineNumberNameIndex;
2622 int lineNumberTableOffset = localContentsOffset;
2623 localContentsOffset += 6;
2624 // leave space for attribute_length and line_number_table_length
2625 // Seems like do would be better, but this preserves the existing behavior.
2626 index = searchLineNumber(startLineIndexes, binding.sourceStart);
2627 contents[localContentsOffset++] = 0;
2628 contents[localContentsOffset++] = 0;
2629 contents[localContentsOffset++] = (byte) (index >> 8);
2630 contents[localContentsOffset++] = (byte) index;
2631 // now we change the size of the line number attribute
2632 contents[lineNumberTableOffset++] = 0;
2633 contents[lineNumberTableOffset++] = 0;
2634 contents[lineNumberTableOffset++] = 0;
2635 contents[lineNumberTableOffset++] = 6;
2636 contents[lineNumberTableOffset++] = 0;
2637 contents[lineNumberTableOffset++] = 1;
2640 // then we do the local variable attribute
2641 if (codeStream.generateLocalVariableTableAttributes) {
2642 int localVariableTableOffset = localContentsOffset;
2643 int numberOfEntries = 0;
2644 int localVariableNameIndex =
2645 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
2646 if (localContentsOffset + 8 > this.contents.length) {
2649 contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8);
2650 contents[localContentsOffset++] = (byte) localVariableNameIndex;
2651 localContentsOffset += 6;
2652 // leave space for attribute_length and local_variable_table_length
2654 int descriptorIndex;
2656 // used to remember the local variable with a generic type
2657 int genericLocalVariablesCounter = 0;
2658 LocalVariableBinding[] genericLocalVariables = null;
2659 int numberOfGenericEntries = 0;
2661 for (int i = 0, max = codeStream.allLocalsCounter; i < max; i++) {
2662 LocalVariableBinding localVariable = codeStream.locals[i];
2663 final TypeBinding localVariableTypeBinding = localVariable.type;
2664 boolean isParameterizedType = localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable();
2665 if (localVariable.initializationCount != 0 && isParameterizedType) {
2666 if (genericLocalVariables == null) {
2667 // we cannot have more than max locals
2668 genericLocalVariables = new LocalVariableBinding[max];
2670 genericLocalVariables[genericLocalVariablesCounter++] = localVariable;
2672 for (int j = 0; j < localVariable.initializationCount; j++) {
2673 int startPC = localVariable.initializationPCs[j << 1];
2674 int endPC = localVariable.initializationPCs[(j << 1) + 1];
2675 if (startPC != endPC) { // only entries for non zero length
2677 localVariable.declaringScope.problemReporter().abortDueToInternalError(
2678 Util.bind("abort.invalidAttribute" , new String(localVariable.name)), //$NON-NLS-1$
2679 (ASTNode) localVariable.declaringScope.methodScope().referenceContext);
2681 if (localContentsOffset + 10 > this.contents.length) {
2684 // now we can safely add the local entry
2686 if (isParameterizedType) {
2687 numberOfGenericEntries++;
2689 contents[localContentsOffset++] = (byte) (startPC >> 8);
2690 contents[localContentsOffset++] = (byte) startPC;
2691 int length = endPC - startPC;
2692 contents[localContentsOffset++] = (byte) (length >> 8);
2693 contents[localContentsOffset++] = (byte) length;
2694 nameIndex = constantPool.literalIndex(localVariable.name);
2695 contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2696 contents[localContentsOffset++] = (byte) nameIndex;
2697 descriptorIndex = constantPool.literalIndex(localVariableTypeBinding.signature());
2698 contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2699 contents[localContentsOffset++] = (byte) descriptorIndex;
2700 int resolvedPosition = localVariable.resolvedPosition;
2701 contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2702 contents[localContentsOffset++] = (byte) resolvedPosition;
2706 int value = numberOfEntries * 10 + 2;
2707 localVariableTableOffset += 2;
2708 contents[localVariableTableOffset++] = (byte) (value >> 24);
2709 contents[localVariableTableOffset++] = (byte) (value >> 16);
2710 contents[localVariableTableOffset++] = (byte) (value >> 8);
2711 contents[localVariableTableOffset++] = (byte) value;
2712 contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8);
2713 contents[localVariableTableOffset] = (byte) numberOfEntries;
2716 if (genericLocalVariablesCounter != 0) {
2717 // add the local variable type table attribute
2718 int maxOfEntries = 8 + numberOfGenericEntries * 10;
2719 // reserve enough space
2720 if (localContentsOffset + maxOfEntries >= this.contents.length) {
2721 resizeContents(maxOfEntries);
2723 int localVariableTypeNameIndex =
2724 constantPool.literalIndex(AttributeNamesConstants.LocalVariableTypeTableName);
2725 contents[localContentsOffset++] = (byte) (localVariableTypeNameIndex >> 8);
2726 contents[localContentsOffset++] = (byte) localVariableTypeNameIndex;
2727 value = numberOfGenericEntries * 10 + 2;
2728 contents[localContentsOffset++] = (byte) (value >> 24);
2729 contents[localContentsOffset++] = (byte) (value >> 16);
2730 contents[localContentsOffset++] = (byte) (value >> 8);
2731 contents[localContentsOffset++] = (byte) value;
2732 contents[localContentsOffset++] = (byte) (numberOfGenericEntries >> 8);
2733 contents[localContentsOffset++] = (byte) numberOfGenericEntries;
2735 for (int i = 0; i < genericLocalVariablesCounter; i++) {
2736 LocalVariableBinding localVariable = genericLocalVariables[i];
2737 for (int j = 0; j < localVariable.initializationCount; j++) {
2738 int startPC = localVariable.initializationPCs[j << 1];
2739 int endPC = localVariable.initializationPCs[(j << 1) + 1];
2740 if (startPC != endPC) { // only entries for non zero length
2741 // now we can safely add the local entry
2742 contents[localContentsOffset++] = (byte) (startPC >> 8);
2743 contents[localContentsOffset++] = (byte) startPC;
2744 int length = endPC - startPC;
2745 contents[localContentsOffset++] = (byte) (length >> 8);
2746 contents[localContentsOffset++] = (byte) length;
2747 nameIndex = constantPool.literalIndex(localVariable.name);
2748 contents[localContentsOffset++] = (byte) (nameIndex >> 8);
2749 contents[localContentsOffset++] = (byte) nameIndex;
2750 descriptorIndex = constantPool.literalIndex(localVariable.type.genericTypeSignature());
2751 contents[localContentsOffset++] = (byte) (descriptorIndex >> 8);
2752 contents[localContentsOffset++] = (byte) descriptorIndex;
2753 int resolvedPosition = localVariable.resolvedPosition;
2754 contents[localContentsOffset++] = (byte) (resolvedPosition >> 8);
2755 contents[localContentsOffset++] = (byte) resolvedPosition;
2762 // update the number of attributes
2763 // ensure first that there is enough space available inside the contents array
2764 if (codeAttributeAttributeOffset + 2 >= this.contents.length) {
2767 contents[codeAttributeAttributeOffset++] = (byte) (attributeNumber >> 8);
2768 contents[codeAttributeAttributeOffset] = (byte) attributeNumber;
2770 // update the attribute length
2771 int codeAttributeLength = localContentsOffset - (codeAttributeOffset + 6);
2772 contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24);
2773 contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16);
2774 contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8);
2775 contents[codeAttributeOffset + 5] = (byte) codeAttributeLength;
2776 contentsOffset = localContentsOffset;
2781 * Complete the creation of a method info by setting up the number of attributes at the right offset.
2783 * @param methodAttributeOffset <CODE>int</CODE>
2784 * @param attributeNumber <CODE>int</CODE>
2786 public void completeMethodInfo(
2787 int methodAttributeOffset,
2788 int attributeNumber) {
2789 // update the number of attributes
2790 contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
2791 contents[methodAttributeOffset] = (byte) attributeNumber;
2796 * This methods returns a char[] representing the file name of the receiver
2800 public char[] fileName() {
2801 return constantPool.UTF8Cache.returnKeyFor(1);
2804 private void generateAnnotation(Annotation annotation, int attributeOffset) {
2805 if (contentsOffset + 4 >= this.contents.length) {
2808 TypeBinding annotationTypeBinding = annotation.resolvedType;
2809 if (annotationTypeBinding == null) {
2810 this.contentsOffset = attributeOffset;
2813 final int typeIndex = constantPool.literalIndex(annotationTypeBinding.signature());
2814 contents[contentsOffset++] = (byte) (typeIndex >> 8);
2815 contents[contentsOffset++] = (byte) typeIndex;
2816 if (annotation instanceof NormalAnnotation) {
2817 NormalAnnotation normalAnnotation = (NormalAnnotation) annotation;
2818 MemberValuePair[] memberValuePairs = normalAnnotation.memberValuePairs;
2819 if (memberValuePairs != null) {
2820 final int memberValuePairsLength = memberValuePairs.length;
2821 contents[contentsOffset++] = (byte) (memberValuePairsLength >> 8);
2822 contents[contentsOffset++] = (byte) memberValuePairsLength;
2823 for (int i = 0; i < memberValuePairsLength; i++) {
2824 MemberValuePair memberValuePair = memberValuePairs[i];
2825 if (contentsOffset + 2 >= this.contents.length) {
2828 final int elementNameIndex = constantPool.literalIndex(memberValuePair.name);
2829 contents[contentsOffset++] = (byte) (elementNameIndex >> 8);
2830 contents[contentsOffset++] = (byte) elementNameIndex;
2831 MethodBinding methodBinding = memberValuePair.binding;
2832 if (methodBinding == null) {
2833 contentsOffset = attributeOffset;
2835 generateElementValue(memberValuePair.value, methodBinding.returnType, attributeOffset);
2839 contents[contentsOffset++] = 0;
2840 contents[contentsOffset++] = 0;
2842 } else if (annotation instanceof SingleMemberAnnotation) {
2843 SingleMemberAnnotation singleMemberAnnotation = (SingleMemberAnnotation) annotation;
2844 // this is a single member annotation (one member value)
2845 contents[contentsOffset++] = 0;
2846 contents[contentsOffset++] = 1;
2847 if (contentsOffset + 2 >= this.contents.length) {
2850 final int elementNameIndex = constantPool.literalIndex(VALUE);
2851 contents[contentsOffset++] = (byte) (elementNameIndex >> 8);
2852 contents[contentsOffset++] = (byte) elementNameIndex;
2853 MethodBinding methodBinding = singleMemberAnnotation.singlePair.binding;
2854 if (methodBinding == null) {
2855 contentsOffset = attributeOffset;
2857 generateElementValue(singleMemberAnnotation.memberValue, methodBinding.returnType, attributeOffset);
2860 // this is a marker annotation (no member value pairs)
2861 contents[contentsOffset++] = 0;
2862 contents[contentsOffset++] = 0;
2868 * That method generates the header of a code attribute.
2869 * - the index inside the constant pool for the attribute name ("Code")
2870 * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4).
2872 public void generateCodeAttributeHeader() {
2873 if (contentsOffset + 20 >= this.contents.length) {
2876 int constantValueNameIndex =
2877 constantPool.literalIndex(AttributeNamesConstants.CodeName);
2878 contents[contentsOffset++] = (byte) (constantValueNameIndex >> 8);
2879 contents[contentsOffset++] = (byte) constantValueNameIndex;
2880 // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4)
2881 contentsOffset += 12;
2884 private void generateElementValue(
2885 Expression defaultValue,
2886 TypeBinding memberValuePairReturnType,
2887 int attributeOffset) {
2888 Constant constant = defaultValue.constant;
2889 TypeBinding defaultValueBinding = defaultValue.resolvedType;
2890 if (defaultValueBinding == null) {
2891 contentsOffset = attributeOffset;
2893 if (memberValuePairReturnType.isArrayType() && !defaultValueBinding.isArrayType()) {
2894 // automatic wrapping
2895 if (contentsOffset + 3 >= this.contents.length) {
2898 contents[contentsOffset++] = (byte) '[';
2899 contents[contentsOffset++] = (byte) 0;
2900 contents[contentsOffset++] = (byte) 1;
2902 if (constant != null && constant != Constant.NotAConstant) {
2903 generateElementValue(attributeOffset, defaultValue, constant, memberValuePairReturnType.leafComponentType());
2905 generateElementValueForNonConstantExpression(defaultValue, attributeOffset, defaultValueBinding);
2911 * @param attributeOffset
2913 private void generateElementValue(int attributeOffset, Expression defaultValue, Constant constant, TypeBinding binding) {
2914 if (contentsOffset + 3 >= this.contents.length) {
2917 switch (binding.id) {
2919 contents[contentsOffset++] = (byte) 'Z';
2920 int booleanValueIndex =
2921 constantPool.literalIndex(constant.booleanValue() ? 1 : 0);
2922 contents[contentsOffset++] = (byte) (booleanValueIndex >> 8);
2923 contents[contentsOffset++] = (byte) booleanValueIndex;
2926 contents[contentsOffset++] = (byte) 'B';
2927 int integerValueIndex =
2928 constantPool.literalIndex(constant.intValue());
2929 contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
2930 contents[contentsOffset++] = (byte) integerValueIndex;
2933 contents[contentsOffset++] = (byte) 'C';
2935 constantPool.literalIndex(constant.intValue());
2936 contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
2937 contents[contentsOffset++] = (byte) integerValueIndex;
2940 contents[contentsOffset++] = (byte) 'I';
2942 constantPool.literalIndex(constant.intValue());
2943 contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
2944 contents[contentsOffset++] = (byte) integerValueIndex;
2947 contents[contentsOffset++] = (byte) 'S';
2949 constantPool.literalIndex(constant.intValue());
2950 contents[contentsOffset++] = (byte) (integerValueIndex >> 8);
2951 contents[contentsOffset++] = (byte) integerValueIndex;
2954 contents[contentsOffset++] = (byte) 'F';
2955 int floatValueIndex =
2956 constantPool.literalIndex(constant.floatValue());
2957 contents[contentsOffset++] = (byte) (floatValueIndex >> 8);
2958 contents[contentsOffset++] = (byte) floatValueIndex;
2961 contents[contentsOffset++] = (byte) 'D';
2962 int doubleValueIndex =
2963 constantPool.literalIndex(constant.doubleValue());
2964 contents[contentsOffset++] = (byte) (doubleValueIndex >> 8);
2965 contents[contentsOffset++] = (byte) doubleValueIndex;
2968 contents[contentsOffset++] = (byte) 'J';
2969 int longValueIndex =
2970 constantPool.literalIndex(constant.longValue());
2971 contents[contentsOffset++] = (byte) (longValueIndex >> 8);
2972 contents[contentsOffset++] = (byte) longValueIndex;
2974 case T_JavaLangString :
2975 contents[contentsOffset++] = (byte) 's';
2976 int stringValueIndex =
2977 constantPool.literalIndex(((StringConstant) constant).stringValue().toCharArray());
2978 if (stringValueIndex == -1) {
2979 if (!creatingProblemType) {
2980 // report an error and abort: will lead to a problem type classfile creation
2981 TypeDeclaration typeDeclaration = referenceBinding.scope.referenceContext;
2982 typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(defaultValue);
2984 // already inside a problem type creation : no attribute
2985 contentsOffset = attributeOffset;
2988 contents[contentsOffset++] = (byte) (stringValueIndex >> 8);
2989 contents[contentsOffset++] = (byte) stringValueIndex;
2994 private void generateElementValueForNonConstantExpression(Expression defaultValue, int attributeOffset, TypeBinding defaultValueBinding) {
2995 if (defaultValueBinding != null) {
2996 if (defaultValueBinding.isEnum()) {
2997 if (contentsOffset + 5 >= this.contents.length) {
3000 contents[contentsOffset++] = (byte) 'e';
3001 FieldBinding fieldBinding = null;
3002 if (defaultValue instanceof QualifiedNameReference) {
3003 QualifiedNameReference nameReference = (QualifiedNameReference) defaultValue;
3004 fieldBinding = (FieldBinding) nameReference.binding;
3005 } else if (defaultValue instanceof SingleNameReference) {
3006 SingleNameReference nameReference = (SingleNameReference) defaultValue;
3007 fieldBinding = (FieldBinding) nameReference.binding;
3009 contentsOffset = attributeOffset;
3011 if (fieldBinding != null) {
3012 final int enumConstantTypeNameIndex = constantPool.literalIndex(fieldBinding.type.signature());
3013 final int enumConstantNameIndex = constantPool.literalIndex(fieldBinding.name);
3014 contents[contentsOffset++] = (byte) (enumConstantTypeNameIndex >> 8);
3015 contents[contentsOffset++] = (byte) enumConstantTypeNameIndex;
3016 contents[contentsOffset++] = (byte) (enumConstantNameIndex >> 8);
3017 contents[contentsOffset++] = (byte) enumConstantNameIndex;
3019 } else if (defaultValueBinding.isAnnotationType()) {
3020 if (contentsOffset + 1 >= this.contents.length) {
3023 contents[contentsOffset++] = (byte) '@';
3024 generateAnnotation((Annotation) defaultValue, attributeOffset);
3025 } else if (defaultValueBinding.isArrayType()) {
3027 if (contentsOffset + 3 >= this.contents.length) {
3030 contents[contentsOffset++] = (byte) '[';
3031 if (defaultValue instanceof ArrayInitializer) {
3032 ArrayInitializer arrayInitializer = (ArrayInitializer) defaultValue;
3033 int arrayLength = arrayInitializer.expressions != null ? arrayInitializer.expressions.length : 0;
3034 contents[contentsOffset++] = (byte) (arrayLength >> 8);
3035 contents[contentsOffset++] = (byte) arrayLength;
3036 for (int i = 0; i < arrayLength; i++) {
3037 generateElementValue(arrayInitializer.expressions[i], defaultValueBinding.leafComponentType(), attributeOffset);
3040 contentsOffset = attributeOffset;
3044 if (contentsOffset + 3 >= this.contents.length) {
3047 contents[contentsOffset++] = (byte) 'c';
3048 if (defaultValue instanceof ClassLiteralAccess) {
3049 ClassLiteralAccess classLiteralAccess = (ClassLiteralAccess) defaultValue;
3050 final int classInfoIndex = constantPool.literalIndex(classLiteralAccess.targetType.signature());
3051 contents[contentsOffset++] = (byte) (classInfoIndex >> 8);
3052 contents[contentsOffset++] = (byte) classInfoIndex;
3054 contentsOffset = attributeOffset;
3058 contentsOffset = attributeOffset;
3062 public int generateMethodInfoAttribute(MethodBinding methodBinding) {
3063 return generateMethodInfoAttribute(methodBinding, false);
3067 * That method generates the attributes of a code attribute.
3069 * - an exception attribute for each try/catch found inside the method
3070 * - a deprecated attribute
3071 * - a synthetic attribute for synthetic access methods
3073 * It returns the number of attributes created for the code attribute.
3075 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
3076 * @return <CODE>int</CODE>
3078 public int generateMethodInfoAttribute(MethodBinding methodBinding, boolean createProblemMethod) {
3079 // leave two bytes for the attribute_number
3080 contentsOffset += 2;
3081 // now we can handle all the attribute for that method info:
3083 // - a CodeAttribute
3084 // - a ExceptionAttribute
3085 // - a DeprecatedAttribute
3086 // - a SyntheticAttribute
3088 // Exception attribute
3089 ReferenceBinding[] thrownsExceptions;
3090 int attributeNumber = 0;
3091 if ((thrownsExceptions = methodBinding.thrownExceptions) != NoExceptions) {
3092 // The method has a throw clause. So we need to add an exception attribute
3093 // check that there is enough space to write all the bytes for the exception attribute
3094 int length = thrownsExceptions.length;
3095 int exSize = 8 + length * 2;
3096 if (exSize + contentsOffset >= this.contents.length) {
3097 resizeContents(exSize);
3099 int exceptionNameIndex =
3100 constantPool.literalIndex(AttributeNamesConstants.ExceptionsName);
3101 contents[contentsOffset++] = (byte) (exceptionNameIndex >> 8);
3102 contents[contentsOffset++] = (byte) exceptionNameIndex;
3103 // The attribute length = length * 2 + 2 in case of a exception attribute
3104 int attributeLength = length * 2 + 2;
3105 contents[contentsOffset++] = (byte) (attributeLength >> 24);
3106 contents[contentsOffset++] = (byte) (attributeLength >> 16);
3107 contents[contentsOffset++] = (byte) (attributeLength >> 8);
3108 contents[contentsOffset++] = (byte) attributeLength;
3109 contents[contentsOffset++] = (byte) (length >> 8);
3110 contents[contentsOffset++] = (byte) length;
3111 for (int i = 0; i < length; i++) {
3112 int exceptionIndex = constantPool.literalIndexForType(thrownsExceptions[i].constantPoolName());
3113 contents[contentsOffset++] = (byte) (exceptionIndex >> 8);
3114 contents[contentsOffset++] = (byte) exceptionIndex;
3118 if (methodBinding.isDeprecated()) {
3119 // Deprecated attribute
3120 // Check that there is enough space to write the deprecated attribute
3121 if (contentsOffset + 6 >= this.contents.length) {
3124 int deprecatedAttributeNameIndex =
3125 constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
3126 contents[contentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8);
3127 contents[contentsOffset++] = (byte) deprecatedAttributeNameIndex;
3128 // the length of a deprecated attribute is equals to 0
3129 contents[contentsOffset++] = 0;
3130 contents[contentsOffset++] = 0;
3131 contents[contentsOffset++] = 0;
3132 contents[contentsOffset++] = 0;
3136 if (this.targetJDK < ClassFileConstants.JDK1_5 && methodBinding.isSynthetic()) {
3137 // Synthetic attribute
3138 // Check that there is enough space to write the deprecated attribute
3139 if (contentsOffset + 6 >= this.contents.length) {
3142 int syntheticAttributeNameIndex =
3143 constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
3144 contents[contentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8);
3145 contents[contentsOffset++] = (byte) syntheticAttributeNameIndex;
3146 // the length of a synthetic attribute is equals to 0
3147 contents[contentsOffset++] = 0;
3148 contents[contentsOffset++] = 0;
3149 contents[contentsOffset++] = 0;
3150 contents[contentsOffset++] = 0;
3154 // add signature attribute
3155 char[] genericSignature = methodBinding.genericSignature();
3156 if (genericSignature != null) {
3157 // check that there is enough space to write all the bytes for the field info corresponding
3158 // to the @fieldBinding
3159 if (contentsOffset + 8 >= this.contents.length) {
3162 int signatureAttributeNameIndex =
3163 constantPool.literalIndex(AttributeNamesConstants.SignatureName);
3164 contents[contentsOffset++] = (byte) (signatureAttributeNameIndex >> 8);
3165 contents[contentsOffset++] = (byte) signatureAttributeNameIndex;
3166 // the length of a signature attribute is equals to 2
3167 contents[contentsOffset++] = 0;
3168 contents[contentsOffset++] = 0;
3169 contents[contentsOffset++] = 0;
3170 contents[contentsOffset++] = 2;
3171 int signatureIndex =
3172 constantPool.literalIndex(genericSignature);
3173 contents[contentsOffset++] = (byte) (signatureIndex >> 8);
3174 contents[contentsOffset++] = (byte) signatureIndex;
3177 if (this.targetJDK >= ClassFileConstants.JDK1_5 && !this.creatingProblemType && !createProblemMethod) {
3178 AbstractMethodDeclaration methodDeclaration = methodBinding.sourceMethod();
3179 if (methodDeclaration != null) {
3180 Annotation[] annotations = methodDeclaration.annotations;
3181 if (annotations != null) {
3182 attributeNumber += generateRuntimeAnnotations(annotations);
3184 if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) {
3185 Argument[] arguments = methodDeclaration.arguments;
3186 if (arguments != null) {
3187 attributeNumber += generateRuntimeAnnotationsForParameters(arguments);
3192 return attributeNumber;
3195 public int generateMethodInfoAttribute(MethodBinding methodBinding, AnnotationMethodDeclaration declaration) {
3196 int attributesNumber = generateMethodInfoAttribute(methodBinding);
3197 int attributeOffset = contentsOffset;
3198 if ((declaration.modifiers & AccAnnotationDefault) != 0) {
3199 // add an annotation default attribute
3200 int annotationDefaultNameIndex =
3201 constantPool.literalIndex(AttributeNamesConstants.AnnotationDefaultName);
3202 contents[contentsOffset++] = (byte) (annotationDefaultNameIndex >> 8);
3203 contents[contentsOffset++] = (byte) annotationDefaultNameIndex;
3204 int attributeLengthOffset = contentsOffset;
3205 contentsOffset += 4;
3207 generateElementValue(declaration.defaultValue, declaration.binding.returnType, attributeOffset);
3208 if (contentsOffset != attributeOffset) {
3209 int attributeLength = contentsOffset - attributeLengthOffset - 4;
3210 contents[attributeLengthOffset++] = (byte) (attributeLength >> 24);
3211 contents[attributeLengthOffset++] = (byte) (attributeLength >> 16);
3212 contents[attributeLengthOffset++] = (byte) (attributeLength >> 8);
3213 contents[attributeLengthOffset++] = (byte) attributeLength;
3217 return attributesNumber;
3222 * That method generates the header of a method info:
3223 * The header consists in:
3224 * - the access flags
3225 * - the name index of the method name inside the constant pool
3226 * - the descriptor index of the signature of the method inside the constant pool.
3228 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
3230 public void generateMethodInfoHeader(MethodBinding methodBinding) {
3231 generateMethodInfoHeader(methodBinding, methodBinding.modifiers);
3235 * That method generates the header of a method info:
3236 * The header consists in:
3237 * - the access flags
3238 * - the name index of the method name inside the constant pool
3239 * - the descriptor index of the signature of the method inside the constant pool.
3241 * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding
3242 * @param accessFlags the access flags
3244 public void generateMethodInfoHeader(MethodBinding methodBinding, int accessFlags) {
3245 // check that there is enough space to write all the bytes for the method info corresponding
3246 // to the @methodBinding
3247 methodCount++; // add one more method
3248 if (contentsOffset + 10 >= this.contents.length) {
3251 if (targetJDK < ClassFileConstants.JDK1_5) {
3252 // pre 1.5, synthetic was an attribute, not a modifier
3253 accessFlags &= ~AccSynthetic;
3255 if (methodBinding.isRequiredToClearPrivateModifier()) {
3256 accessFlags &= ~AccPrivate;
3258 contents[contentsOffset++] = (byte) (accessFlags >> 8);
3259 contents[contentsOffset++] = (byte) accessFlags;
3260 int nameIndex = constantPool.literalIndex(methodBinding.selector);
3261 contents[contentsOffset++] = (byte) (nameIndex >> 8);
3262 contents[contentsOffset++] = (byte) nameIndex;
3263 int descriptorIndex = constantPool.literalIndex(methodBinding.signature());
3264 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
3265 contents[contentsOffset++] = (byte) descriptorIndex;
3270 * That method generates the method info header of a clinit:
3271 * The header consists in:
3272 * - the access flags (always default access + static)
3273 * - the name index of the method name (always <clinit>) inside the constant pool
3274 * - the descriptor index of the signature (always ()V) of the method inside the constant pool.
3276 public void generateMethodInfoHeaderForClinit() {
3277 // check that there is enough space to write all the bytes for the method info corresponding
3278 // to the @methodBinding
3279 methodCount++; // add one more method
3280 if (contentsOffset + 10 >= this.contents.length) {
3283 contents[contentsOffset++] = (byte) ((AccDefault | AccStatic) >> 8);
3284 contents[contentsOffset++] = (byte) (AccDefault | AccStatic);
3285 int nameIndex = constantPool.literalIndex(ConstantPool.Clinit);
3286 contents[contentsOffset++] = (byte) (nameIndex >> 8);
3287 contents[contentsOffset++] = (byte) nameIndex;
3288 int descriptorIndex =
3289 constantPool.literalIndex(ConstantPool.ClinitSignature);
3290 contents[contentsOffset++] = (byte) (descriptorIndex >> 8);
3291 contents[contentsOffset++] = (byte) descriptorIndex;
3292 // We know that we won't get more than 1 attribute: the code attribute
3293 contents[contentsOffset++] = 0;
3294 contents[contentsOffset++] = 1;
3299 * Generate the byte for problem method infos that correspond to missing abstract methods.
3300 * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179
3302 * @param methodDeclarations Array of all missing abstract methods
3304 public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) {
3305 if (methodDeclarations != null) {
3306 for (int i = 0, max = methodDeclarations.length; i < max; i++) {
3307 MethodDeclaration methodDeclaration = methodDeclarations[i];
3308 MethodBinding methodBinding = methodDeclaration.binding;
3309 String readableName = new String(methodBinding.readableName());
3310 IProblem[] problems = compilationResult.problems;
3311 int problemsCount = compilationResult.problemCount;
3312 for (int j = 0; j < problemsCount; j++) {
3313 IProblem problem = problems[j];
3315 && problem.getID() == IProblem.AbstractMethodMustBeImplemented
3316 && problem.getMessage().indexOf(readableName) != -1) {
3318 addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult);
3326 * @param annotations
3327 * @return the number of attributes created while dumping the annotations in the .class file
3329 private int generateRuntimeAnnotations(final Annotation[] annotations) {
3330 int attributesNumber = 0;
3331 final int length = annotations.length;
3332 int visibleAnnotationsCounter = 0;
3333 int invisibleAnnotationsCounter = 0;
3335 for (int i = 0; i < length; i++) {
3336 Annotation annotation = annotations[i];
3337 if (isRuntimeInvisible(annotation)) {
3338 invisibleAnnotationsCounter++;
3339 } else if (isRuntimeVisible(annotation)) {
3340 visibleAnnotationsCounter++;
3344 if (invisibleAnnotationsCounter != 0) {
3345 int annotationAttributeOffset = contentsOffset;
3346 if (contentsOffset + 10 >= contents.length) {
3349 int runtimeInvisibleAnnotationsAttributeNameIndex =
3350 constantPool.literalIndex(AttributeNamesConstants.RuntimeInvisibleAnnotationsName);
3351 contents[contentsOffset++] = (byte) (runtimeInvisibleAnnotationsAttributeNameIndex >> 8);
3352 contents[contentsOffset++] = (byte) runtimeInvisibleAnnotationsAttributeNameIndex;
3353 int attributeLengthOffset = contentsOffset;
3354 contentsOffset += 4; // leave space for the attribute length
3356 int annotationsLengthOffset = contentsOffset;
3357 contentsOffset += 2; // leave space for the annotations length
3359 contents[annotationsLengthOffset++] = (byte) (invisibleAnnotationsCounter >> 8);
3360 contents[annotationsLengthOffset++] = (byte) invisibleAnnotationsCounter;
3362 loop: for (int i = 0; i < length; i++) {
3363 if (invisibleAnnotationsCounter == 0) break loop;
3364 Annotation annotation = annotations[i];
3365 if (isRuntimeInvisible(annotation)) {
3366 generateAnnotation(annotation, annotationAttributeOffset);
3367 invisibleAnnotationsCounter--;
3368 if (this.contentsOffset == annotationAttributeOffset) {
3373 if (contentsOffset != annotationAttributeOffset) {
3374 int attributeLength = contentsOffset - attributeLengthOffset - 4;
3375 contents[attributeLengthOffset++] = (byte) (attributeLength >> 24);
3376 contents[attributeLengthOffset++] = (byte) (attributeLength >> 16);
3377 contents[attributeLengthOffset++] = (byte) (attributeLength >> 8);
3378 contents[attributeLengthOffset++] = (byte) attributeLength;
3381 contentsOffset = annotationAttributeOffset;
3385 if (visibleAnnotationsCounter != 0) {
3386 int annotationAttributeOffset = contentsOffset;
3387 if (contentsOffset + 10 >= contents.length) {
3390 int runtimeVisibleAnnotationsAttributeNameIndex =
3391 constantPool.literalIndex(AttributeNamesConstants.RuntimeVisibleAnnotationsName);
3392 contents[contentsOffset++] = (byte) (runtimeVisibleAnnotationsAttributeNameIndex >> 8);
3393 contents[contentsOffset++] = (byte) runtimeVisibleAnnotationsAttributeNameIndex;
3394 int attributeLengthOffset = contentsOffset;
3395 contentsOffset += 4; // leave space for the attribute length
3397 int annotationsLengthOffset = contentsOffset;
3398 contentsOffset += 2; // leave space for the annotations length
3400 contents[annotationsLengthOffset++] = (byte) (visibleAnnotationsCounter >> 8);
3401 contents[annotationsLengthOffset++] = (byte) visibleAnnotationsCounter;
3403 loop: for (int i = 0; i < length; i++) {
3404 if (visibleAnnotationsCounter == 0) break loop;
3405 Annotation annotation = annotations[i];
3406 if (isRuntimeVisible(annotation)) {
3407 visibleAnnotationsCounter--;
3408 generateAnnotation(annotation, annotationAttributeOffset);
3409 if (this.contentsOffset == annotationAttributeOffset) {
3414 if (contentsOffset != annotationAttributeOffset) {
3415 int attributeLength = contentsOffset - attributeLengthOffset - 4;
3416 contents[attributeLengthOffset++] = (byte) (attributeLength >> 24);
3417 contents[attributeLengthOffset++] = (byte) (attributeLength >> 16);
3418 contents[attributeLengthOffset++] = (byte) (attributeLength >> 8);
3419 contents[attributeLengthOffset++] = (byte) attributeLength;
3422 contentsOffset = annotationAttributeOffset;
3425 return attributesNumber;
3428 private int generateRuntimeAnnotationsForParameters(Argument[] arguments) {
3429 final int argumentsLength = arguments.length;
3430 final int VISIBLE_INDEX = 0;
3431 final int INVISIBLE_INDEX = 1;
3432 int invisibleParametersAnnotationsCounter = 0;
3433 int visibleParametersAnnotationsCounter = 0;
3434 int[][] annotationsCounters = new int[argumentsLength][2];
3435 for (int i = 0; i < argumentsLength; i++) {
3436 Argument argument = arguments[i];
3437 Annotation[] annotations = argument.annotations;
3438 if (annotations != null) {
3439 for (int j = 0, max2 = annotations.length; j < max2; j++) {
3440 Annotation annotation = annotations[j];
3441 if (isRuntimeInvisible(annotation)) {
3442 annotationsCounters[i][INVISIBLE_INDEX]++;
3443 invisibleParametersAnnotationsCounter++;
3444 } else if (isRuntimeVisible(annotation)) {
3445 annotationsCounters[i][VISIBLE_INDEX]++;
3446 visibleParametersAnnotationsCounter++;
3451 int attributesNumber = 0;
3452 int annotationAttributeOffset = contentsOffset;
3453 if (invisibleParametersAnnotationsCounter != 0) {
3454 if (contentsOffset + 7 >= contents.length) {
3457 int attributeNameIndex =
3458 constantPool.literalIndex(AttributeNamesConstants.RuntimeInvisibleParameterAnnotationsName);
3459 contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
3460 contents[contentsOffset++] = (byte) attributeNameIndex;
3461 int attributeLengthOffset = contentsOffset;
3462 contentsOffset += 4; // leave space for the attribute length
3464 contents[contentsOffset++] = (byte) argumentsLength;
3465 invisibleLoop: for (int i = 0; i < argumentsLength; i++) {
3466 if (contentsOffset + 2 >= contents.length) {
3469 if (invisibleParametersAnnotationsCounter == 0) {
3470 contents[contentsOffset++] = (byte) 0;
3471 contents[contentsOffset++] = (byte) 0;
3473 final int numberOfInvisibleAnnotations = annotationsCounters[i][INVISIBLE_INDEX];
3474 contents[contentsOffset++] = (byte) (numberOfInvisibleAnnotations >> 8);
3475 contents[contentsOffset++] = (byte) numberOfInvisibleAnnotations;
3476 if (numberOfInvisibleAnnotations != 0) {
3477 Argument argument = arguments[i];
3478 Annotation[] annotations = argument.annotations;
3479 for (int j = 0, max = annotations.length; j < max; j++) {
3480 Annotation annotation = annotations[j];
3481 if (isRuntimeInvisible(annotation)) {
3482 generateAnnotation(annotation, annotationAttributeOffset);
3483 if (contentsOffset == annotationAttributeOffset) {
3484 break invisibleLoop;
3486 invisibleParametersAnnotationsCounter--;
3492 if (contentsOffset != annotationAttributeOffset) {
3493 int attributeLength = contentsOffset - attributeLengthOffset - 4;
3494 contents[attributeLengthOffset++] = (byte) (attributeLength >> 24);
3495 contents[attributeLengthOffset++] = (byte) (attributeLength >> 16);
3496 contents[attributeLengthOffset++] = (byte) (attributeLength >> 8);
3497 contents[attributeLengthOffset++] = (byte) attributeLength;
3500 contentsOffset = annotationAttributeOffset;
3503 if (visibleParametersAnnotationsCounter != 0) {
3504 if (contentsOffset + 7 >= contents.length) {
3507 int attributeNameIndex =
3508 constantPool.literalIndex(AttributeNamesConstants.RuntimeVisibleParameterAnnotationsName);
3509 contents[contentsOffset++] = (byte) (attributeNameIndex >> 8);
3510 contents[contentsOffset++] = (byte) attributeNameIndex;
3511 int attributeLengthOffset = contentsOffset;
3512 contentsOffset += 4; // leave space for the attribute length
3514 contents[contentsOffset++] = (byte) argumentsLength;
3515 visibleLoop: for (int i = 0; i < argumentsLength; i++) {
3516 if (contentsOffset + 2 >= contents.length) {
3519 if (visibleParametersAnnotationsCounter == 0) {
3520 contents[contentsOffset++] = (byte) 0;
3521 contents[contentsOffset++] = (byte) 0;
3523 final int numberOfVisibleAnnotations = annotationsCounters[i][VISIBLE_INDEX];
3524 contents[contentsOffset++] = (byte) (numberOfVisibleAnnotations >> 8);
3525 contents[contentsOffset++] = (byte) numberOfVisibleAnnotations;
3526 if (numberOfVisibleAnnotations != 0) {
3527 Argument argument = arguments[i];
3528 Annotation[] annotations = argument.annotations;
3529 for (int j = 0, max = annotations.length; j < max; j++) {
3530 Annotation annotation = annotations[j];
3531 if (isRuntimeVisible(annotation)) {
3532 generateAnnotation(annotation, annotationAttributeOffset);
3533 if (contentsOffset == annotationAttributeOffset) {
3536 visibleParametersAnnotationsCounter--;
3542 if (contentsOffset != annotationAttributeOffset) {
3543 int attributeLength = contentsOffset - attributeLengthOffset - 4;
3544 contents[attributeLengthOffset++] = (byte) (attributeLength >> 24);
3545 contents[attributeLengthOffset++] = (byte) (attributeLength >> 16);
3546 contents[attributeLengthOffset++] = (byte) (attributeLength >> 8);
3547 contents[attributeLengthOffset++] = (byte) attributeLength;
3550 contentsOffset = annotationAttributeOffset;
3553 return attributesNumber;
3557 * Answer the actual bytes of the class file
3559 * This method encodes the receiver structure into a byte array which is the content of the classfile.
3560 * Returns the byte array that represents the encoded structure of the receiver.
3564 public byte[] getBytes() {
3565 byte[] fullContents = new byte[headerOffset + contentsOffset];
3566 System.arraycopy(header, 0, fullContents, 0, headerOffset);
3567 System.arraycopy(contents, 0, fullContents, headerOffset, contentsOffset);
3568 return fullContents;
3573 * Answer the compound name of the class file.
3575 * e.g. {{java}, {util}, {Hashtable}}.
3577 public char[][] getCompoundName() {
3578 return CharOperation.splitOn('/', fileName());
3581 protected void initByteArrays() {
3582 LookupEnvironment env = this.referenceBinding.scope.environment();
3583 synchronized (env) {
3584 if (env.sharedArraysUsed) {
3585 this.ownSharedArrays = false;
3586 int members = referenceBinding.methods().length + referenceBinding.fields().length;
3587 this.header = new byte[INITIAL_HEADER_SIZE];
3588 this.contents = new byte[members < 15 ? INITIAL_CONTENTS_SIZE : INITIAL_HEADER_SIZE];
3590 this.ownSharedArrays = env.sharedArraysUsed = true;
3591 this.header = env.sharedClassFileHeader;
3592 this.contents = env.sharedClassFileContents;
3598 private boolean isRuntimeInvisible(Annotation annotation) {
3599 final TypeBinding annotationBinding = annotation.resolvedType;
3600 if (annotationBinding == null) {
3603 long metaTagBits = annotationBinding.getAnnotationTagBits();
3604 if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
3605 return true; // by default the retention is CLASS
3607 return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationClassRetention;
3610 private boolean isRuntimeVisible(Annotation annotation) {
3611 final TypeBinding annotationBinding = annotation.resolvedType;
3612 if (annotationBinding == null) {
3615 long metaTagBits = annotationBinding.tagBits;
3616 if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
3617 return false; // by default the retention is CLASS
3619 return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationRuntimeRetention;
3624 * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name
3625 * for all inner types of the receiver.
3626 * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile
3628 public ClassFile outerMostEnclosingClassFile() {
3629 ClassFile current = this;
3630 while (current.enclosingClassFile != null)
3631 current = current.enclosingClassFile;
3637 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
3638 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
3640 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
3642 public void recordEnclosingTypeAttributes(ReferenceBinding binding) {
3643 // add all the enclosing types
3644 ReferenceBinding enclosingType = referenceBinding.enclosingType();
3646 while (enclosingType != null) {
3648 enclosingType = enclosingType.enclosingType();
3650 enclosingType = referenceBinding;
3651 ReferenceBinding enclosingTypes[];
3653 enclosingTypes = new ReferenceBinding[depth];
3654 for (int i = depth - 1; i >= 0; i--) {
3655 enclosingTypes[i] = enclosingType;
3656 enclosingType = enclosingType.enclosingType();
3658 for (int i = 0; i < depth; i++) {
3659 addInnerClasses(enclosingTypes[i]);
3662 addInnerClasses(referenceBinding);
3668 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
3669 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
3671 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
3673 public void recordNestedLocalAttribute(ReferenceBinding binding) {
3674 // add all the enclosing types
3675 ReferenceBinding enclosingType = referenceBinding.enclosingType();
3677 while (enclosingType != null) {
3679 enclosingType = enclosingType.enclosingType();
3681 enclosingType = referenceBinding;
3682 ReferenceBinding enclosingTypes[];
3684 enclosingTypes = new ReferenceBinding[depth];
3685 for (int i = depth - 1; i >= 0; i--) {
3686 enclosingTypes[i] = enclosingType;
3687 enclosingType = enclosingType.enclosingType();
3689 for (int i = 0; i < depth; i++)
3690 addInnerClasses(enclosingTypes[i]);
3692 addInnerClasses(binding);
3698 * This is used to store a new inner class. It checks that the binding @binding doesn't already exist inside the
3699 * collection of inner classes. Add all the necessary classes in the right order to fit to the specifications.
3701 * @param binding org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding
3703 public void recordNestedMemberAttribute(ReferenceBinding binding) {
3704 addInnerClasses(binding);
3708 * Resize the pool contents
3710 private final void resizeContents(int minimalSize) {
3711 int length = this.contents.length;
3713 if (toAdd < minimalSize)
3714 toAdd = minimalSize;
3715 System.arraycopy(this.contents, 0, this.contents = new byte[length + toAdd], 0, length);
3720 * This methods leaves the space for method counts recording.
3722 public void setForMethodInfos() {
3723 // leave some space for the methodCount
3724 methodCountOffset = contentsOffset;
3725 contentsOffset += 2;