Copyright (c) 2000, 2019 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Jesper S Moller - Contributions for Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 Bug 406982 - [1.8][compiler] Generation of MethodParameters Attribute in classfile Bug 416885 - [1.8][compiler]IncompatibleClassChange error (edit) Bug 412149 - [1.8][compiler] Emit repeated annotations into the designated container Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) Bug 409236 - [1.8][compiler] Type annotations on intersection cast types dropped by code generator Bug 409246 - [1.8][compiler] Type annotations on catch parameters not handled properly Bug 415541 - [1.8][compiler] Type annotations in the body of static initializer get dropped Bug 415399 - [1.8][compiler] Type annotations on constructor results dropped by the code generator Bug 415470 - [1.8][compiler] Type annotations on class declaration go vanishing Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas Bug 434556 - Broken class file generated for incorrect annotation usage Bug 442416 - $deserializeLambda$ missing cases for nested lambdas Stephan Herrmann - Contribution for Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables Olivier Tardieu tardieu@us.ibm.com - Contributions for Bug 442416 - $deserializeLambda$ missing cases for nested lambdas
/******************************************************************************* * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Jesper S Moller - Contributions for * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 * Bug 406982 - [1.8][compiler] Generation of MethodParameters Attribute in classfile * Bug 416885 - [1.8][compiler]IncompatibleClassChange error (edit) * Bug 412149 - [1.8][compiler] Emit repeated annotations into the designated container * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) * Bug 409236 - [1.8][compiler] Type annotations on intersection cast types dropped by code generator * Bug 409246 - [1.8][compiler] Type annotations on catch parameters not handled properly * Bug 415541 - [1.8][compiler] Type annotations in the body of static initializer get dropped * Bug 415399 - [1.8][compiler] Type annotations on constructor results dropped by the code generator * Bug 415470 - [1.8][compiler] Type annotations on class declaration go vanishing * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas * Bug 434556 - Broken class file generated for incorrect annotation usage * Bug 442416 - $deserializeLambda$ missing cases for nested lambdas * Stephan Herrmann - Contribution for * Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables * Olivier Tardieu tardieu@us.ibm.com - Contributions for * Bug 442416 - $deserializeLambda$ missing cases for nested lambdas *******************************************************************************/
package org.eclipse.jdt.internal.compiler; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.ExportsStatement; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FunctionalExpression; import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration; import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation; import org.eclipse.jdt.internal.compiler.ast.OpensStatement; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.Receiver; import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression; import org.eclipse.jdt.internal.compiler.ast.RequiresStatement; import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.SwitchStatement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.AnnotationContext; import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants; import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants; import org.eclipse.jdt.internal.compiler.codegen.CodeStream; import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; import org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel; import org.eclipse.jdt.internal.compiler.codegen.Opcodes; import org.eclipse.jdt.internal.compiler.codegen.StackMapFrame; import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream; import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream.ExceptionMarker; import org.eclipse.jdt.internal.compiler.codegen.TypeAnnotationCodeStream; import org.eclipse.jdt.internal.compiler.codegen.VerificationTypeInfo; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.impl.StringConstant; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; import org.eclipse.jdt.internal.compiler.lookup.PolymorphicMethodBinding; import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding; import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding; import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; import org.eclipse.jdt.internal.compiler.problem.AbortMethod; import org.eclipse.jdt.internal.compiler.problem.AbortType; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement; import org.eclipse.jdt.internal.compiler.util.Messages; import org.eclipse.jdt.internal.compiler.util.Util;
Represents a class file wrapper on bytes, it is aware of its actual type name. Public APIs are listed below: byte[] getBytes(); Answer the actual bytes of the class file char[][] getCompoundName(); Answer the compound name of the class file. For example, {{java}, {util}, {Hashtable}}. byte[] getReducedBytes(); Answer a smaller byte format, which is only contains some structural information. Those bytes are decodable with a regular class file reader, such as DietClassFileReader
/** * Represents a class file wrapper on bytes, it is aware of its actual * type name. * * Public APIs are listed below: * * byte[] getBytes(); * Answer the actual bytes of the class file * * char[][] getCompoundName(); * Answer the compound name of the class file. * For example, {{java}, {util}, {Hashtable}}. * * byte[] getReducedBytes(); * Answer a smaller byte format, which is only contains some structural * information. Those bytes are decodable with a regular class file reader, * such as DietClassFileReader */
@SuppressWarnings({"rawtypes", "unchecked"}) public class ClassFile implements TypeConstants, TypeIds { private byte[] bytes; public CodeStream codeStream; public ConstantPool constantPool; public int constantPoolOffset; // the header contains all the bytes till the end of the constant pool public byte[] contents; public int contentsOffset; protected boolean creatingProblemType; public ClassFile enclosingClassFile; public byte[] header; // that collection contains all the remaining bytes of the .class file public int headerOffset; public Map<TypeBinding, Boolean> innerClassesBindings; public List bootstrapMethods = null; public int methodCount; public int methodCountOffset; // pool managment boolean isShared = false; // used to generate private access methods // debug and stack map attributes public int produceAttributes; public SourceTypeBinding referenceBinding; public boolean isNestedType; public long targetJDK; public List<TypeBinding> missingTypes = null; public Set visitedTypes; public static final int INITIAL_CONTENTS_SIZE = 400; public static final int INITIAL_HEADER_SIZE = 1500; public static final int INNER_CLASSES_SIZE = 5; public static final int NESTED_MEMBER_SIZE = 5;
INTERNAL USE-ONLY Request the creation of a ClassFile compatible representation of a problematic type
Params:
  • typeDeclaration – org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
  • unitResult – org.eclipse.jdt.internal.compiler.CompilationUnitResult
/** * INTERNAL USE-ONLY * Request the creation of a ClassFile compatible representation of a problematic type * * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult */
public static void createProblemType(TypeDeclaration typeDeclaration, CompilationResult unitResult) { createProblemType(typeDeclaration, null, unitResult); } private static void createProblemType(TypeDeclaration typeDeclaration, ClassFile parentClassFile, CompilationResult unitResult) { SourceTypeBinding typeBinding = typeDeclaration.binding; ClassFile classFile = ClassFile.getNewInstance(typeBinding); classFile.initialize(typeBinding, parentClassFile, true); if (typeBinding.hasMemberTypes()) { // see bug 180109 ReferenceBinding[] members = typeBinding.memberTypes; for (int i = 0, l = members.length; i < l; i++) classFile.recordInnerClasses(members[i]); } // TODO (olivier) handle cases where a field cannot be generated (name too long) // TODO (olivier) handle too many methods // inner attributes if (typeBinding.isNestedType()) { classFile.recordInnerClasses(typeBinding); } TypeVariableBinding[] typeVariables = typeBinding.typeVariables(); for (int i = 0, max = typeVariables.length; i < max; i++) { TypeVariableBinding typeVariableBinding = typeVariables[i]; if ((typeVariableBinding.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { Util.recordNestedType(classFile, typeVariableBinding); } } // add its fields FieldBinding[] fields = typeBinding.fields(); if ((fields != null) && (fields != Binding.NO_FIELDS)) { classFile.addFieldInfos(); } else { // we have to set the number of fields to be equals to 0 if (classFile.contentsOffset + 2 >= classFile.contents.length) { classFile.resizeContents(2); } classFile.contents[classFile.contentsOffset++] = 0; classFile.contents[classFile.contentsOffset++] = 0; } // leave some space for the methodCount classFile.setForMethodInfos(); // add its user defined methods int problemsLength; CategorizedProblem[] problems = unitResult.getErrors(); if (problems == null) { problems = new CategorizedProblem[0]; } CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); AbstractMethodDeclaration[] methodDecls = typeDeclaration.methods; boolean abstractMethodsOnly = false; if (methodDecls != null) { if (typeBinding.isInterface()) { if (typeBinding.scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) abstractMethodsOnly = true; // We generate a clinit which contains all the problems, since we may not be able to generate problem methods (< 1.8) and problem constructors (all levels). classFile.addProblemClinit(problemsCopy); } for (int i = 0, length = methodDecls.length; i < length; i++) { AbstractMethodDeclaration methodDecl = methodDecls[i]; MethodBinding method = methodDecl.binding; if (method == null) continue; if (abstractMethodsOnly) { method.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract; } if (method.isConstructor()) { if (typeBinding.isInterface()) continue; classFile.addProblemConstructor(methodDecl, method, problemsCopy); } else if (method.isAbstract()) { classFile.addAbstractMethod(methodDecl, method); } else { classFile.addProblemMethod(methodDecl, method, problemsCopy); } } // add abstract methods classFile.addDefaultAbstractMethods(); } // propagate generation of (problem) member types if (typeDeclaration.memberTypes != null) { for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) { TypeDeclaration memberType = typeDeclaration.memberTypes[i]; if (memberType.binding != null) { ClassFile.createProblemType(memberType, classFile, unitResult); } } } classFile.addAttributes(); unitResult.record(typeBinding.constantPoolName(), classFile); } public static ClassFile getNewInstance(SourceTypeBinding typeBinding) { LookupEnvironment env = typeBinding.scope.environment(); return env.classFilePool.acquire(typeBinding); }
INTERNAL USE-ONLY This methods creates a new instance of the receiver.
/** * INTERNAL USE-ONLY * This methods creates a new instance of the receiver. */
protected ClassFile() { // default constructor for subclasses } public ClassFile(SourceTypeBinding typeBinding) { // default constructor for subclasses this.constantPool = new ConstantPool(this); final CompilerOptions options = typeBinding.scope.compilerOptions(); this.targetJDK = options.targetJDK; this.produceAttributes = options.produceDebugAttributes; this.referenceBinding = typeBinding; this.isNestedType = typeBinding.isNestedType(); if (this.targetJDK >= ClassFileConstants.JDK1_6) { this.produceAttributes |= ClassFileConstants.ATTR_STACK_MAP_TABLE; if (this.targetJDK >= ClassFileConstants.JDK1_8) { this.produceAttributes |= ClassFileConstants.ATTR_TYPE_ANNOTATION; this.codeStream = new TypeAnnotationCodeStream(this); if (options.produceMethodParameters) { this.produceAttributes |= ClassFileConstants.ATTR_METHOD_PARAMETERS; } } else { this.codeStream = new StackMapFrameCodeStream(this); } } else if (this.targetJDK == ClassFileConstants.CLDC_1_1) { this.targetJDK = ClassFileConstants.JDK1_1; // put back 45.3 this.produceAttributes |= ClassFileConstants.ATTR_STACK_MAP; this.codeStream = new StackMapFrameCodeStream(this); } else { this.codeStream = new CodeStream(this); } initByteArrays(this.referenceBinding.methods().length + this.referenceBinding.fields().length); } public ClassFile(ModuleBinding moduleBinding, CompilerOptions options) { this.constantPool = new ConstantPool(this); this.targetJDK = options.targetJDK; this.produceAttributes = ClassFileConstants.ATTR_SOURCE; this.isNestedType = false; this.codeStream = new StackMapFrameCodeStream(this); initByteArrays(0); }
INTERNAL USE-ONLY Generate the byte for a problem method info that correspond to a bogus method.
Params:
  • method – org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
/** * INTERNAL USE-ONLY * Generate the byte for a problem method info that correspond to a bogus method. * * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding */
public void addAbstractMethod( AbstractMethodDeclaration method, MethodBinding methodBinding) { this.generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; int attributeNumber = this.generateMethodInfoAttributes(methodBinding); completeMethodInfo(methodBinding, methodAttributeOffset, attributeNumber); }
INTERNAL USE-ONLY This methods generate all the attributes for the receiver. For a class they could be: - source file attribute - inner classes attribute - deprecated attribute
/** * INTERNAL USE-ONLY * This methods generate all the attributes for the receiver. * For a class they could be: * - source file attribute * - inner classes attribute * - deprecated attribute */
public void addAttributes() { // update the method count this.contents[this.methodCountOffset++] = (byte) (this.methodCount >> 8); this.contents[this.methodCountOffset] = (byte) this.methodCount; int attributesNumber = 0; // leave two bytes for the number of attributes and store the current offset int attributeOffset = this.contentsOffset; this.contentsOffset += 2; // source attribute if ((this.produceAttributes & ClassFileConstants.ATTR_SOURCE) != 0) { String fullFileName = new String(this.referenceBinding.scope.referenceCompilationUnit().getFileName()); fullFileName = fullFileName.replace('\\', '/'); int lastIndex = fullFileName.lastIndexOf('/'); if (lastIndex != -1) { fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length()); } attributesNumber += generateSourceAttribute(fullFileName); } // Deprecated attribute if (this.referenceBinding.isDeprecated()) { // check that there is enough space to write all the bytes for the field info corresponding // to the @fieldBinding attributesNumber += generateDeprecatedAttribute(); } // add signature attribute char[] genericSignature = this.referenceBinding.genericSignature(); if (genericSignature != null) { attributesNumber += generateSignatureAttribute(genericSignature); } if (this.targetJDK >= ClassFileConstants.JDK1_5 && this.referenceBinding.isNestedType() && !this.referenceBinding.isMemberType()) { // add enclosing method attribute (1.5 mode only) attributesNumber += generateEnclosingMethodAttribute(); } if (this.targetJDK >= ClassFileConstants.JDK1_4) { TypeDeclaration typeDeclaration = this.referenceBinding.scope.referenceContext; if (typeDeclaration != null) { final Annotation[] annotations = typeDeclaration.annotations; if (annotations != null) { long targetMask; if (typeDeclaration.isPackageInfo()) targetMask = TagBits.AnnotationForPackage; else if (this.referenceBinding.isAnnotationType()) targetMask = TagBits.AnnotationForType | TagBits.AnnotationForAnnotationType; else targetMask = TagBits.AnnotationForType | TagBits.AnnotationForTypeUse; attributesNumber += generateRuntimeAnnotations(annotations, targetMask); } } } if (this.referenceBinding.isHierarchyInconsistent()) { ReferenceBinding superclass = this.referenceBinding.superclass; if (superclass != null) { this.missingTypes = superclass.collectMissingTypes(this.missingTypes); } ReferenceBinding[] superInterfaces = this.referenceBinding.superInterfaces(); for (int i = 0, max = superInterfaces.length; i < max; i++) { this.missingTypes = superInterfaces[i].collectMissingTypes(this.missingTypes); } attributesNumber += generateHierarchyInconsistentAttribute(); } // Functional expression and lambda bootstrap methods if (this.bootstrapMethods != null && !this.bootstrapMethods.isEmpty()) { attributesNumber += generateBootstrapMethods(this.bootstrapMethods); } // Inner class attribute int numberOfInnerClasses = this.innerClassesBindings == null ? 0 : this.innerClassesBindings.size(); if (numberOfInnerClasses != 0) { ReferenceBinding[] innerClasses = new ReferenceBinding[numberOfInnerClasses]; this.innerClassesBindings.keySet().toArray(innerClasses); Arrays.sort(innerClasses, new Comparator() { @Override public int compare(Object o1, Object o2) { TypeBinding binding1 = (TypeBinding) o1; TypeBinding binding2 = (TypeBinding) o2; Boolean onBottom1 = ClassFile.this.innerClassesBindings.get(o1); Boolean onBottom2 = ClassFile.this.innerClassesBindings.get(o2); if (onBottom1) { if (!onBottom2) { return 1; } } else { if (onBottom2) { return -1; } } return CharOperation.compareTo(binding1.constantPoolName(), binding2.constantPoolName()); } }); attributesNumber += generateInnerClassAttribute(numberOfInnerClasses, innerClasses); } if (this.missingTypes != null) { generateMissingTypesAttribute(); attributesNumber++; } attributesNumber += generateTypeAnnotationAttributeForTypeDeclaration(); if (this.targetJDK >= ClassFileConstants.JDK11) { // add nestMember and nestHost attributes attributesNumber += generateNestAttributes(); } // update the number of attributes if (attributeOffset + 2 >= this.contents.length) { resizeContents(2); } this.contents[attributeOffset++] = (byte) (attributesNumber >> 8); this.contents[attributeOffset] = (byte) attributesNumber; // resynchronize all offsets of the classfile this.header = this.constantPool.poolContent; this.headerOffset = this.constantPool.currentOffset; int constantPoolCount = this.constantPool.currentIndex; this.header[this.constantPoolOffset++] = (byte) (constantPoolCount >> 8); this.header[this.constantPoolOffset] = (byte) constantPoolCount; }
INTERNAL USE-ONLY This methods generate all the module attributes for the receiver.
/** * INTERNAL USE-ONLY * This methods generate all the module attributes for the receiver. */
public void addModuleAttributes(ModuleBinding module, Annotation[] annotations, CompilationUnitDeclaration cud) { int attributesNumber = 0; // leave two bytes for the number of attributes and store the current offset int attributeOffset = this.contentsOffset; this.contentsOffset += 2; // source attribute if ((this.produceAttributes & ClassFileConstants.ATTR_SOURCE) != 0) { String fullFileName = new String(cud.getFileName()); fullFileName = fullFileName.replace('\\', '/'); int lastIndex = fullFileName.lastIndexOf('/'); if (lastIndex != -1) { fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length()); } attributesNumber += generateSourceAttribute(fullFileName); } attributesNumber += generateModuleAttribute(cud.moduleDeclaration); if (annotations != null) { long targetMask = TagBits.AnnotationForModule; attributesNumber += generateRuntimeAnnotations(annotations, targetMask); } char[] mainClass = cud.moduleDeclaration.binding.mainClassName; if (mainClass != null) { attributesNumber += generateModuleMainClassAttribute(CharOperation.replaceOnCopy(mainClass, '.', '/')); } char[][] packageNames = cud.moduleDeclaration.binding.getPackageNamesForClassFile(); if (packageNames != null) { attributesNumber += generateModulePackagesAttribute(packageNames); } // update the number of attributes if (attributeOffset + 2 >= this.contents.length) { resizeContents(2); } this.contents[attributeOffset++] = (byte) (attributesNumber >> 8); this.contents[attributeOffset] = (byte) attributesNumber; // resynchronize all offsets of the classfile this.header = this.constantPool.poolContent; this.headerOffset = this.constantPool.currentOffset; int constantPoolCount = this.constantPool.currentIndex; this.header[this.constantPoolOffset++] = (byte) (constantPoolCount >> 8); this.header[this.constantPoolOffset] = (byte) constantPoolCount; }
INTERNAL USE-ONLY This methods generate all the default abstract method infos that correpond to the abstract methods inherited from superinterfaces.
/** * INTERNAL USE-ONLY * This methods generate all the default abstract method infos that correpond to * the abstract methods inherited from superinterfaces. */
public void addDefaultAbstractMethods() { // default abstract methods MethodBinding[] defaultAbstractMethods = this.referenceBinding.getDefaultAbstractMethods(); for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) { MethodBinding methodBinding = defaultAbstractMethods[i]; generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; int attributeNumber = generateMethodInfoAttributes(methodBinding); completeMethodInfo(methodBinding, methodAttributeOffset, attributeNumber); } } private int addFieldAttributes(FieldBinding fieldBinding, int fieldAttributeOffset) { int attributesNumber = 0; // 4.7.2 only static constant fields get a ConstantAttribute // Generate the constantValueAttribute Constant fieldConstant = fieldBinding.constant(); if (fieldConstant != Constant.NotAConstant){ attributesNumber += generateConstantValueAttribute(fieldConstant, fieldBinding, fieldAttributeOffset); } if (this.targetJDK < ClassFileConstants.JDK1_5 && fieldBinding.isSynthetic()) { attributesNumber += generateSyntheticAttribute(); } if (fieldBinding.isDeprecated()) { attributesNumber += generateDeprecatedAttribute(); } // add signature attribute char[] genericSignature = fieldBinding.genericSignature(); if (genericSignature != null) { attributesNumber += generateSignatureAttribute(genericSignature); } if (this.targetJDK >= ClassFileConstants.JDK1_4) { FieldDeclaration fieldDeclaration = fieldBinding.sourceField(); if (fieldDeclaration != null) { Annotation[] annotations = fieldDeclaration.annotations; if (annotations != null) { attributesNumber += generateRuntimeAnnotations(annotations, TagBits.AnnotationForField); } if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { List allTypeAnnotationContexts = new ArrayList(); if (annotations != null && (fieldDeclaration.bits & ASTNode.HasTypeAnnotations) != 0) { fieldDeclaration.getAllAnnotationContexts(AnnotationTargetTypeConstants.FIELD, allTypeAnnotationContexts); } int invisibleTypeAnnotationsCounter = 0; int visibleTypeAnnotationsCounter = 0; TypeReference fieldType = fieldDeclaration.type; if (fieldType != null && ((fieldType.bits & ASTNode.HasTypeAnnotations) != 0)) { fieldType.getAllAnnotationContexts(AnnotationTargetTypeConstants.FIELD, allTypeAnnotationContexts); } int size = allTypeAnnotationContexts.size(); if (size != 0) { AnnotationContext[] allTypeAnnotationContextsArray = new AnnotationContext[size]; allTypeAnnotationContexts.toArray(allTypeAnnotationContextsArray); for (int i = 0, max = allTypeAnnotationContextsArray.length; i < max; i++) { AnnotationContext annotationContext = allTypeAnnotationContextsArray[i]; if ((annotationContext.visibility & AnnotationContext.INVISIBLE) != 0) { invisibleTypeAnnotationsCounter++; allTypeAnnotationContexts.add(annotationContext); } else { visibleTypeAnnotationsCounter++; allTypeAnnotationContexts.add(annotationContext); } } attributesNumber += generateRuntimeTypeAnnotations( allTypeAnnotationContextsArray, visibleTypeAnnotationsCounter, invisibleTypeAnnotationsCounter); } } } } if ((fieldBinding.tagBits & TagBits.HasMissingType) != 0) { this.missingTypes = fieldBinding.type.collectMissingTypes(this.missingTypes); } return attributesNumber; }
INTERNAL USE-ONLY This methods generates the bytes for the given field binding
Params:
  • fieldBinding – the given field binding
/** * INTERNAL USE-ONLY * This methods generates the bytes for the given field binding * @param fieldBinding the given field binding */
private void addFieldInfo(FieldBinding fieldBinding) { // check that there is enough space to write all the bytes for the field info corresponding // to the @fieldBinding if (this.contentsOffset + 8 >= this.contents.length) { resizeContents(8); } // Now we can generate all entries into the byte array // First the accessFlags int accessFlags = fieldBinding.getAccessFlags(); if (this.targetJDK < ClassFileConstants.JDK1_5) { // pre 1.5, synthetic was an attribute, not a modifier accessFlags &= ~ClassFileConstants.AccSynthetic; } this.contents[this.contentsOffset++] = (byte) (accessFlags >> 8); this.contents[this.contentsOffset++] = (byte) accessFlags; // Then the nameIndex int nameIndex = this.constantPool.literalIndex(fieldBinding.name); this.contents[this.contentsOffset++] = (byte) (nameIndex >> 8); this.contents[this.contentsOffset++] = (byte) nameIndex; // Then the descriptorIndex int descriptorIndex = this.constantPool.literalIndex(fieldBinding.type); this.contents[this.contentsOffset++] = (byte) (descriptorIndex >> 8); this.contents[this.contentsOffset++] = (byte) descriptorIndex; int fieldAttributeOffset = this.contentsOffset; int attributeNumber = 0; // leave some space for the number of attributes this.contentsOffset += 2; attributeNumber += addFieldAttributes(fieldBinding, fieldAttributeOffset); if (this.contentsOffset + 2 >= this.contents.length) { resizeContents(2); } this.contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[fieldAttributeOffset] = (byte) attributeNumber; } /** * INTERNAL USE-ONLY * This methods generate all the fields infos for the receiver. * This includes: * - a field info for each defined field of that class * - a field info for each synthetic field (e.g. this$0) */
INTERNAL USE-ONLY This methods generate all the fields infos for the receiver. This includes: - a field info for each defined field of that class - a field info for each synthetic field (e.g. this$0)
/** * INTERNAL USE-ONLY * This methods generate all the fields infos for the receiver. * This includes: * - a field info for each defined field of that class * - a field info for each synthetic field (e.g. this$0) */
public void addFieldInfos() { SourceTypeBinding currentBinding = this.referenceBinding; FieldBinding[] syntheticFields = currentBinding.syntheticFields(); int fieldCount = currentBinding.fieldCount() + (syntheticFields == null ? 0 : syntheticFields.length); // write the number of fields if (fieldCount > 0xFFFF) { this.referenceBinding.scope.problemReporter().tooManyFields(this.referenceBinding.scope.referenceType()); } if (this.contentsOffset + 2 >= this.contents.length) { resizeContents(2); } this.contents[this.contentsOffset++] = (byte) (fieldCount >> 8); this.contents[this.contentsOffset++] = (byte) fieldCount; FieldDeclaration[] fieldDecls = currentBinding.scope.referenceContext.fields; for (int i = 0, max = fieldDecls == null ? 0 : fieldDecls.length; i < max; i++) { FieldDeclaration fieldDecl = fieldDecls[i]; if (fieldDecl.binding != null) { addFieldInfo(fieldDecl.binding); } } if (syntheticFields != null) { for (int i = 0, max = syntheticFields.length; i < max; i++) { addFieldInfo(syntheticFields[i]); } } } private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, CategorizedProblem problem, CompilationResult compilationResult) { // always clear the strictfp/native/abstract bit for a problem method generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(ClassFileConstants.AccStrictfp | ClassFileConstants.AccNative | ClassFileConstants.AccAbstract)); int methodAttributeOffset = this.contentsOffset; int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute attributeNumber++; int codeAttributeOffset = this.contentsOffset; generateCodeAttributeHeader(); StringBuffer buffer = new StringBuffer(25); buffer.append("\t" + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ buffer.insert(0, Messages.compilation_unresolvedProblem); String problemString = buffer.toString(); this.codeStream.init(this); this.codeStream.preserveUnusedLocals = true; this.codeStream.initializeMaxLocals(methodBinding); // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") this.codeStream.generateCodeAttributeForProblemMethod(problemString); completeCodeAttributeForMissingAbstractProblemMethod( methodBinding, codeAttributeOffset, compilationResult.getLineSeparatorPositions(), problem.getSourceLineNumber()); completeMethodInfo(methodBinding, methodAttributeOffset, attributeNumber); }
INTERNAL USE-ONLY Generate the byte for a problem clinit method info that correspond to a boggus method.
Params:
  • problems – org.eclipse.jdt.internal.compiler.problem.Problem[]
/** * INTERNAL USE-ONLY * Generate the byte for a problem clinit method info that correspond to a boggus method. * * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] */
public void addProblemClinit(CategorizedProblem[] problems) { generateMethodInfoHeaderForClinit(); // leave two spaces for the number of attributes this.contentsOffset -= 2; int attributeOffset = this.contentsOffset; this.contentsOffset += 2; int attributeNumber = 0; int codeAttributeOffset = this.contentsOffset; generateCodeAttributeHeader(); this.codeStream.resetForProblemClinit(this); String problemString = "" ; //$NON-NLS-1$ int problemLine = 0; if (problems != null) { int max = problems.length; StringBuffer buffer = new StringBuffer(25); int count = 0; for (int i = 0; i < max; i++) { CategorizedProblem problem = problems[i]; if ((problem != null) && (problem.isError())) { buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ count++; if (problemLine == 0) { problemLine = problem.getSourceLineNumber(); } problems[i] = null; } } // insert the top line afterwards, once knowing how many problems we have to consider if (count > 1) { buffer.insert(0, Messages.compilation_unresolvedProblems); } else { buffer.insert(0, Messages.compilation_unresolvedProblem); } problemString = buffer.toString(); } // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") this.codeStream.generateCodeAttributeForProblemMethod(problemString); attributeNumber++; // code attribute completeCodeAttributeForClinit( codeAttributeOffset, problemLine, null); if (this.contentsOffset + 2 >= this.contents.length) { resizeContents(2); } this.contents[attributeOffset++] = (byte) (attributeNumber >> 8); this.contents[attributeOffset] = (byte) attributeNumber; }
INTERNAL USE-ONLY Generate the byte for a problem method info that correspond to a boggus constructor.
Params:
  • method – org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
  • problems – org.eclipse.jdt.internal.compiler.problem.Problem[]
/** * INTERNAL USE-ONLY * Generate the byte for a problem method info that correspond to a boggus constructor. * * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] */
public void addProblemConstructor( AbstractMethodDeclaration method, MethodBinding methodBinding, CategorizedProblem[] problems) { if (methodBinding.declaringClass.isInterface()) { method.abort(ProblemSeverities.AbortType, null); } // always clear the strictfp/native/abstract bit for a problem method generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(ClassFileConstants.AccStrictfp | ClassFileConstants.AccNative | ClassFileConstants.AccAbstract)); int methodAttributeOffset = this.contentsOffset; int attributesNumber = generateMethodInfoAttributes(methodBinding); // Code attribute attributesNumber++; int codeAttributeOffset = this.contentsOffset; generateCodeAttributeHeader(); this.codeStream.reset(method, this); String problemString = "" ; //$NON-NLS-1$ int problemLine = 0; if (problems != null) { int max = problems.length; StringBuffer buffer = new StringBuffer(25); int count = 0; for (int i = 0; i < max; i++) { CategorizedProblem problem = problems[i]; if ((problem != null) && (problem.isError())) { buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ count++; if (problemLine == 0) { problemLine = problem.getSourceLineNumber(); } } } // insert the top line afterwards, once knowing how many problems we have to consider if (count > 1) { buffer.insert(0, Messages.compilation_unresolvedProblems); } else { buffer.insert(0, Messages.compilation_unresolvedProblem); } problemString = buffer.toString(); } // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") this.codeStream.generateCodeAttributeForProblemMethod(problemString); completeCodeAttributeForProblemMethod( method, methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions(), problemLine); completeMethodInfo(methodBinding, methodAttributeOffset, attributesNumber); }
INTERNAL USE-ONLY Generate the byte for a problem method info that correspond to a boggus constructor. Reset the position inside the contents byte array to the savedOffset.
Params:
  • method – org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
  • problems – org.eclipse.jdt.internal.compiler.problem.Problem[]
  • savedOffset – int
/** * INTERNAL USE-ONLY * Generate the byte for a problem method info that correspond to a boggus constructor. * Reset the position inside the contents byte array to the savedOffset. * * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] * @param savedOffset <CODE>int</CODE> */
public void addProblemConstructor( AbstractMethodDeclaration method, MethodBinding methodBinding, CategorizedProblem[] problems, int savedOffset) { // we need to move back the contentsOffset to the value at the beginning of the method this.contentsOffset = savedOffset; this.methodCount--; // we need to remove the method that causes the problem addProblemConstructor(method, methodBinding, problems); }
INTERNAL USE-ONLY Generate the byte for a problem method info that correspond to a boggus method.
Params:
  • method – org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
  • problems – org.eclipse.jdt.internal.compiler.problem.Problem[]
/** * INTERNAL USE-ONLY * Generate the byte for a problem method info that correspond to a boggus method. * * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] */
public void addProblemMethod( AbstractMethodDeclaration method, MethodBinding methodBinding, CategorizedProblem[] problems) { if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) { method.abort(ProblemSeverities.AbortType, null); } // always clear the strictfp/native/abstract bit for a problem method generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(ClassFileConstants.AccStrictfp | ClassFileConstants.AccNative | ClassFileConstants.AccAbstract)); int methodAttributeOffset = this.contentsOffset; int attributesNumber = generateMethodInfoAttributes(methodBinding); // Code attribute attributesNumber++; int codeAttributeOffset = this.contentsOffset; generateCodeAttributeHeader(); this.codeStream.reset(method, this); String problemString = "" ; //$NON-NLS-1$ int problemLine = 0; if (problems != null) { int max = problems.length; StringBuffer buffer = new StringBuffer(25); int count = 0; for (int i = 0; i < max; i++) { CategorizedProblem problem = problems[i]; if ((problem != null) && (problem.isError()) && (problem.getSourceStart() >= method.declarationSourceStart) && (problem.getSourceEnd() <= method.declarationSourceEnd)) { buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ count++; if (problemLine == 0) { problemLine = problem.getSourceLineNumber(); } problems[i] = null; } } // insert the top line afterwards, once knowing how many problems we have to consider if (count > 1) { buffer.insert(0, Messages.compilation_unresolvedProblems); } else { buffer.insert(0, Messages.compilation_unresolvedProblem); } problemString = buffer.toString(); } // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") this.codeStream.generateCodeAttributeForProblemMethod(problemString); completeCodeAttributeForProblemMethod( method, methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions(), problemLine); completeMethodInfo(methodBinding, methodAttributeOffset, attributesNumber); }
INTERNAL USE-ONLY Generate the byte for a problem method info that correspond to a boggus method. Reset the position inside the contents byte array to the savedOffset.
Params:
  • method – org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding
  • problems – org.eclipse.jdt.internal.compiler.problem.Problem[]
  • savedOffset – int
/** * INTERNAL USE-ONLY * Generate the byte for a problem method info that correspond to a boggus method. * Reset the position inside the contents byte array to the savedOffset. * * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] * @param savedOffset <CODE>int</CODE> */
public void addProblemMethod( AbstractMethodDeclaration method, MethodBinding methodBinding, CategorizedProblem[] problems, int savedOffset) { // we need to move back the contentsOffset to the value at the beginning of the method this.contentsOffset = savedOffset; this.methodCount--; // we need to remove the method that causes the problem addProblemMethod(method, methodBinding, problems); }
INTERNAL USE-ONLY Generate the byte for all the special method infos. They are: - synthetic access methods - default abstract methods - lambda methods.
/** * INTERNAL USE-ONLY * Generate the byte for all the special method infos. * They are: * - synthetic access methods * - default abstract methods * - lambda methods. */
public void addSpecialMethods() { // add all methods (default abstract methods and synthetic) // default abstract methods generateMissingAbstractMethods(this.referenceBinding.scope.referenceType().missingAbstractMethods, this.referenceBinding.scope.referenceCompilationUnit().compilationResult); MethodBinding[] defaultAbstractMethods = this.referenceBinding.getDefaultAbstractMethods(); for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) { MethodBinding methodBinding = defaultAbstractMethods[i]; generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; int attributeNumber = generateMethodInfoAttributes(methodBinding); completeMethodInfo(methodBinding, methodAttributeOffset, attributeNumber); } // add synthetic methods infos int emittedSyntheticsCount = 0; SyntheticMethodBinding deserializeLambdaMethod = null; boolean continueScanningSynthetics = true; while (continueScanningSynthetics) { continueScanningSynthetics = false; SyntheticMethodBinding[] syntheticMethods = this.referenceBinding.syntheticMethods(); int currentSyntheticsCount = syntheticMethods == null ? 0: syntheticMethods.length; if (emittedSyntheticsCount != currentSyntheticsCount) { for (int i = emittedSyntheticsCount, max = currentSyntheticsCount; i < max; i++) { SyntheticMethodBinding syntheticMethod = syntheticMethods[i]; switch (syntheticMethod.purpose) { case SyntheticMethodBinding.FieldReadAccess : case SyntheticMethodBinding.SuperFieldReadAccess : // generate a method info to emulate an reading access to // a non-accessible field addSyntheticFieldReadAccessMethod(syntheticMethod); break; case SyntheticMethodBinding.FieldWriteAccess : case SyntheticMethodBinding.SuperFieldWriteAccess : // generate a method info to emulate an writing access to // a non-accessible field addSyntheticFieldWriteAccessMethod(syntheticMethod); break; case SyntheticMethodBinding.MethodAccess : case SyntheticMethodBinding.SuperMethodAccess : case SyntheticMethodBinding.BridgeMethod : // generate a method info to emulate an access to a non-accessible method / super-method or bridge method addSyntheticMethodAccessMethod(syntheticMethod); break; case SyntheticMethodBinding.ConstructorAccess : // generate a method info to emulate an access to a non-accessible constructor addSyntheticConstructorAccessMethod(syntheticMethod); break; case SyntheticMethodBinding.EnumValues : // generate a method info to define <enum>#values() addSyntheticEnumValuesMethod(syntheticMethod); break; case SyntheticMethodBinding.EnumValueOf : // generate a method info to define <enum>#valueOf(String) addSyntheticEnumValueOfMethod(syntheticMethod); break; case SyntheticMethodBinding.SwitchTable : // generate a method info to define the switch table synthetic method addSyntheticSwitchTable(syntheticMethod); break; case SyntheticMethodBinding.TooManyEnumsConstants : addSyntheticEnumInitializationMethod(syntheticMethod); break; case SyntheticMethodBinding.LambdaMethod: syntheticMethod.lambda.generateCode(this.referenceBinding.scope, this); continueScanningSynthetics = true; // lambda code generation could schedule additional nested lambdas for code generation. break; case SyntheticMethodBinding.ArrayConstructor: addSyntheticArrayConstructor(syntheticMethod); break; case SyntheticMethodBinding.ArrayClone: addSyntheticArrayClone(syntheticMethod); break; case SyntheticMethodBinding.FactoryMethod: addSyntheticFactoryMethod(syntheticMethod); break; case SyntheticMethodBinding.DeserializeLambda: deserializeLambdaMethod = syntheticMethod; // delay processing break; case SyntheticMethodBinding.SerializableMethodReference: // Nothing to be done break; } } emittedSyntheticsCount = currentSyntheticsCount; } } if (deserializeLambdaMethod != null) { int problemResetPC = 0; this.codeStream.wideMode = false; boolean restart = false; do { try { problemResetPC = this.contentsOffset; addSyntheticDeserializeLambda(deserializeLambdaMethod,this.referenceBinding.syntheticMethods()); restart = false; } catch (AbortMethod e) { // Restart code generation if possible ... if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { // a branch target required a goto_w, restart code generation in wide mode. this.contentsOffset = problemResetPC; this.methodCount--; this.codeStream.resetInWideMode(); // request wide mode restart = true; } else { throw new AbortType(this.referenceBinding.scope.referenceContext.compilationResult, e.problem); } } } while (restart); } } public void addSyntheticArrayConstructor(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForArrayConstructor(methodBinding); completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; } public void addSyntheticArrayClone(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForArrayClone(methodBinding); completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; } public void addSyntheticFactoryMethod(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForFactoryMethod(methodBinding); completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; }
INTERNAL USE-ONLY Generate the bytes for a synthetic method that provides an access to a private constructor.
Params:
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
/** * INTERNAL USE-ONLY * Generate the bytes for a synthetic method that provides an access to a private constructor. * * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding */
public void addSyntheticConstructorAccessMethod(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForConstructorAccess(methodBinding); completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; }
INTERNAL USE-ONLY Generate the bytes for a synthetic method that implements Enum#valueOf(String) for a given enum type
Params:
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
/** * INTERNAL USE-ONLY * Generate the bytes for a synthetic method that implements Enum#valueOf(String) for a given enum type * * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding */
public void addSyntheticEnumValueOfMethod(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForEnumValueOf(methodBinding); completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); // update the number of attributes if ((this.produceAttributes & ClassFileConstants.ATTR_METHOD_PARAMETERS) != 0) { attributeNumber += generateMethodParameters(methodBinding); } this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; }
INTERNAL USE-ONLY Generate the bytes for a synthetic method that implements Enum#values() for a given enum type
Params:
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
/** * INTERNAL USE-ONLY * Generate the bytes for a synthetic method that implements Enum#values() for a given enum type * * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding */
public void addSyntheticEnumValuesMethod(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForEnumValues(methodBinding); completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; } public void addSyntheticEnumInitializationMethod(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForEnumInitializationMethod(methodBinding); completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; }
INTERNAL USE-ONLY Generate the byte for a problem method info that correspond to a synthetic method that generate an read access to a private field.
Params:
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
/** * INTERNAL USE-ONLY * Generate the byte for a problem method info that correspond to a synthetic method that * generate an read access to a private field. * * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding */
public void addSyntheticFieldReadAccessMethod(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding); completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; }
INTERNAL USE-ONLY Generate the byte for a problem method info that correspond to a synthetic method that generate an write access to a private field.
Params:
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
/** * INTERNAL USE-ONLY * Generate the byte for a problem method info that correspond to a synthetic method that * generate an write access to a private field. * * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding */
public void addSyntheticFieldWriteAccessMethod(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding); completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; }
INTERNAL USE-ONLY Generate the bytes for a synthetic method that provides access to a private method.
Params:
  • methodBinding – org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding
/** * INTERNAL USE-ONLY * Generate the bytes for a synthetic method that provides access to a private method. * * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding */
public void addSyntheticMethodAccessMethod(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForMethodAccess(methodBinding); completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; } public void addSyntheticSwitchTable(SyntheticMethodBinding methodBinding) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForSwitchTable(methodBinding); int code_length = this.codeStream.position; if (code_length > 65535) { SwitchStatement switchStatement = methodBinding.switchStatement; if (switchStatement != null) { switchStatement.scope.problemReporter().bytecodeExceeds64KLimit(switchStatement); } } completeCodeAttributeForSyntheticMethod( true, methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions(), ((SourceTypeBinding) methodBinding.declaringClass) .scope); // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; }
INTERNAL USE-ONLY That method completes the creation of the code attribute by setting - the attribute_length - max_stack - max_locals - code_length - exception table - and debug attributes if necessary.
Params:
  • codeAttributeOffset – int
/** * INTERNAL USE-ONLY * That method completes the creation of the code attribute by setting * - the attribute_length * - max_stack * - max_locals * - code_length * - exception table * - and debug attributes if necessary. * * @param codeAttributeOffset <CODE>int</CODE> */
public void completeCodeAttribute(int codeAttributeOffset, MethodScope scope) { // reinitialize the localContents with the byte modified by the code stream this.contents = this.codeStream.bCodeStream; int localContentsOffset = this.codeStream.classFileOffset; // 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... int code_length = this.codeStream.position; if (code_length > 65535) { if (this.codeStream.methodDeclaration != null) { this.codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(this.codeStream.methodDeclaration); } else { this.codeStream.lambdaExpression.scope.problemReporter().bytecodeExceeds64KLimit(this.codeStream.lambdaExpression); } } if (localContentsOffset + 20 >= this.contents.length) { resizeContents(20); } int max_stack = this.codeStream.stackMax; this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); this.contents[codeAttributeOffset + 7] = (byte) max_stack; int max_locals = this.codeStream.maxLocals; this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); this.contents[codeAttributeOffset + 9] = (byte) max_locals; this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); this.contents[codeAttributeOffset + 13] = (byte) code_length; boolean addStackMaps = (this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0; // write the exception table ExceptionLabel[] exceptionLabels = this.codeStream.exceptionLabels; int exceptionHandlersCount = 0; // each label holds one handler per range (start/end contiguous) for (int i = 0, length = this.codeStream.exceptionLabelsCounter; i < length; i++) { exceptionHandlersCount += this.codeStream.exceptionLabels[i].getCount() / 2; } int exSize = exceptionHandlersCount * 8 + 2; if (exSize + localContentsOffset >= this.contents.length) { resizeContents(exSize); } // there is no exception table, so we need to offset by 2 the current offset and move // on the attribute generation this.contents[localContentsOffset++] = (byte) (exceptionHandlersCount >> 8); this.contents[localContentsOffset++] = (byte) exceptionHandlersCount; for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { ExceptionLabel exceptionLabel = exceptionLabels[i]; if (exceptionLabel != null) { int iRange = 0, maxRange = exceptionLabel.getCount(); if ((maxRange & 1) != 0) { if (this.codeStream.methodDeclaration != null) { this.codeStream.methodDeclaration.scope.problemReporter().abortDueToInternalError( Messages.bind(Messages.abort_invalidExceptionAttribute, new String(this.codeStream.methodDeclaration.selector)), this.codeStream.methodDeclaration); } else { this.codeStream.lambdaExpression.scope.problemReporter().abortDueToInternalError( Messages.bind(Messages.abort_invalidExceptionAttribute, new String(this.codeStream.lambdaExpression.binding.selector)), this.codeStream.lambdaExpression); } } while (iRange < maxRange) { int start = exceptionLabel.ranges[iRange++]; // even ranges are start positions this.contents[localContentsOffset++] = (byte) (start >> 8); this.contents[localContentsOffset++] = (byte) start; int end = exceptionLabel.ranges[iRange++]; // odd ranges are end positions this.contents[localContentsOffset++] = (byte) (end >> 8); this.contents[localContentsOffset++] = (byte) end; int handlerPC = exceptionLabel.position; if (addStackMaps) { StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; stackMapFrameCodeStream.addFramePosition(handlerPC); // stackMapFrameCodeStream.addExceptionMarker(handlerPC, exceptionLabel.exceptionType); } this.contents[localContentsOffset++] = (byte) (handlerPC >> 8); this.contents[localContentsOffset++] = (byte) handlerPC; if (exceptionLabel.exceptionType == null) { // any exception handler this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; } else { int nameIndex; if (exceptionLabel.exceptionType == TypeBinding.NULL) { /* represents ClassNotFoundException, see class literal access*/ nameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName); } else { nameIndex = this.constantPool.literalIndexForType(exceptionLabel.exceptionType); } this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) nameIndex; } } } } // debug attributes int codeAttributeAttributeOffset = localContentsOffset; int attributesNumber = 0; // leave two bytes for the attribute_length localContentsOffset += 2; if (localContentsOffset + 2 >= this.contents.length) { resizeContents(2); } this.contentsOffset = localContentsOffset; // first we handle the linenumber attribute if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { attributesNumber += generateLineNumberAttribute(); } // then we do the local variable attribute if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) { final boolean methodDeclarationIsStatic = this.codeStream.methodDeclaration != null ? this.codeStream.methodDeclaration.isStatic() : this.codeStream.lambdaExpression.binding.isStatic(); attributesNumber += generateLocalVariableTableAttribute(code_length, methodDeclarationIsStatic, false); } if (addStackMaps) { attributesNumber += generateStackMapTableAttribute( this.codeStream.methodDeclaration != null ? this.codeStream.methodDeclaration.binding : this.codeStream.lambdaExpression.binding, code_length, codeAttributeOffset, max_locals, false, scope); } if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { attributesNumber += generateStackMapAttribute( this.codeStream.methodDeclaration != null ? this.codeStream.methodDeclaration.binding : this.codeStream.lambdaExpression.binding, code_length, codeAttributeOffset, max_locals, false, scope); } if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { attributesNumber += generateTypeAnnotationsOnCodeAttribute(); } this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; // update the attribute length int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; } public int generateTypeAnnotationsOnCodeAttribute() { int attributesNumber = 0; List allTypeAnnotationContexts = ((TypeAnnotationCodeStream) this.codeStream).allTypeAnnotationContexts; int invisibleTypeAnnotationsCounter = 0; int visibleTypeAnnotationsCounter = 0; for (int i = 0, max = this.codeStream.allLocalsCounter; i < max; i++) { LocalVariableBinding localVariable = this.codeStream.locals[i]; if (localVariable.isCatchParameter()) continue; LocalDeclaration declaration = localVariable.declaration; if (declaration == null || (declaration.isArgument() && ((declaration.bits & ASTNode.IsUnionType) == 0)) || (localVariable.initializationCount == 0) || ((declaration.bits & ASTNode.HasTypeAnnotations) == 0)) { continue; } int targetType = ((localVariable.tagBits & TagBits.IsResource) == 0) ? AnnotationTargetTypeConstants.LOCAL_VARIABLE : AnnotationTargetTypeConstants.RESOURCE_VARIABLE; declaration.getAllAnnotationContexts(targetType, localVariable, allTypeAnnotationContexts); } ExceptionLabel[] exceptionLabels = this.codeStream.exceptionLabels; for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { ExceptionLabel exceptionLabel = exceptionLabels[i]; if (exceptionLabel.exceptionTypeReference != null && (exceptionLabel.exceptionTypeReference.bits & ASTNode.HasTypeAnnotations) != 0) { exceptionLabel.exceptionTypeReference.getAllAnnotationContexts(AnnotationTargetTypeConstants.EXCEPTION_PARAMETER, i, allTypeAnnotationContexts, exceptionLabel.se7Annotations); } } int size = allTypeAnnotationContexts.size(); if (size != 0) { AnnotationContext[] allTypeAnnotationContextsArray = new AnnotationContext[size]; allTypeAnnotationContexts.toArray(allTypeAnnotationContextsArray); for (int j = 0, max2 = allTypeAnnotationContextsArray.length; j < max2; j++) { AnnotationContext annotationContext = allTypeAnnotationContextsArray[j]; if ((annotationContext.visibility & AnnotationContext.INVISIBLE) != 0) { invisibleTypeAnnotationsCounter++; } else { visibleTypeAnnotationsCounter++; } } attributesNumber += generateRuntimeTypeAnnotations( allTypeAnnotationContextsArray, visibleTypeAnnotationsCounter, invisibleTypeAnnotationsCounter); } return attributesNumber; }
INTERNAL USE-ONLY That method completes the creation of the code attribute by setting - the attribute_length - max_stack - max_locals - code_length - exception table - and debug attributes if necessary.
Params:
  • codeAttributeOffset – int
/** * INTERNAL USE-ONLY * That method completes the creation of the code attribute by setting * - the attribute_length * - max_stack * - max_locals * - code_length * - exception table * - and debug attributes if necessary. * * @param codeAttributeOffset <CODE>int</CODE> */
public void completeCodeAttributeForClinit(int codeAttributeOffset, Scope scope) { // reinitialize the contents with the byte modified by the code stream this.contents = this.codeStream.bCodeStream; int localContentsOffset = this.codeStream.classFileOffset; // codeAttributeOffset is the position inside contents 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... int code_length = this.codeStream.position; if (code_length > 65535) { this.codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit( this.codeStream.methodDeclaration.scope.referenceType()); } if (localContentsOffset + 20 >= this.contents.length) { resizeContents(20); } int max_stack = this.codeStream.stackMax; this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); this.contents[codeAttributeOffset + 7] = (byte) max_stack; int max_locals = this.codeStream.maxLocals; this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); this.contents[codeAttributeOffset + 9] = (byte) max_locals; this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); this.contents[codeAttributeOffset + 13] = (byte) code_length; boolean addStackMaps = (this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0; // write the exception table ExceptionLabel[] exceptionLabels = this.codeStream.exceptionLabels; int exceptionHandlersCount = 0; // each label holds one handler per range (start/end contiguous) for (int i = 0, length = this.codeStream.exceptionLabelsCounter; i < length; i++) { exceptionHandlersCount += this.codeStream.exceptionLabels[i].getCount() / 2; } int exSize = exceptionHandlersCount * 8 + 2; if (exSize + localContentsOffset >= this.contents.length) { resizeContents(exSize); } // there is no exception table, so we need to offset by 2 the current offset and move // on the attribute generation this.contents[localContentsOffset++] = (byte) (exceptionHandlersCount >> 8); this.contents[localContentsOffset++] = (byte) exceptionHandlersCount; for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { ExceptionLabel exceptionLabel = exceptionLabels[i]; if (exceptionLabel != null) { int iRange = 0, maxRange = exceptionLabel.getCount(); if ((maxRange & 1) != 0) { this.codeStream.methodDeclaration.scope.problemReporter().abortDueToInternalError( Messages.bind(Messages.abort_invalidExceptionAttribute, new String(this.codeStream.methodDeclaration.selector)), this.codeStream.methodDeclaration); } while (iRange < maxRange) { int start = exceptionLabel.ranges[iRange++]; // even ranges are start positions this.contents[localContentsOffset++] = (byte) (start >> 8); this.contents[localContentsOffset++] = (byte) start; int end = exceptionLabel.ranges[iRange++]; // odd ranges are end positions this.contents[localContentsOffset++] = (byte) (end >> 8); this.contents[localContentsOffset++] = (byte) end; int handlerPC = exceptionLabel.position; this.contents[localContentsOffset++] = (byte) (handlerPC >> 8); this.contents[localContentsOffset++] = (byte) handlerPC; if (addStackMaps) { StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; stackMapFrameCodeStream.addFramePosition(handlerPC); // stackMapFrameCodeStream.addExceptionMarker(handlerPC, exceptionLabel.exceptionType); } if (exceptionLabel.exceptionType == null) { // any exception handler this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; } else { int nameIndex; if (exceptionLabel.exceptionType == TypeBinding.NULL) { /* represents denote ClassNotFoundException, see class literal access*/ nameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName); } else { nameIndex = this.constantPool.literalIndexForType(exceptionLabel.exceptionType); } this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) nameIndex; } } } } // debug attributes int codeAttributeAttributeOffset = localContentsOffset; int attributesNumber = 0; // leave two bytes for the attribute_length localContentsOffset += 2; if (localContentsOffset + 2 >= this.contents.length) { resizeContents(2); } this.contentsOffset = localContentsOffset; // first we handle the linenumber attribute if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { attributesNumber += generateLineNumberAttribute(); } // then we do the local variable attribute if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) { attributesNumber += generateLocalVariableTableAttribute(code_length, true, false); } if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) { attributesNumber += generateStackMapTableAttribute( null, code_length, codeAttributeOffset, max_locals, true, scope); } if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { attributesNumber += generateStackMapAttribute( null, code_length, codeAttributeOffset, max_locals, true, scope); } if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { attributesNumber += generateTypeAnnotationsOnCodeAttribute(); } // update the number of attributes // ensure first that there is enough space available inside the contents array if (codeAttributeAttributeOffset + 2 >= this.contents.length) { resizeContents(2); } this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; // update the attribute length int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; }
INTERNAL USE-ONLY That method completes the creation of the code attribute by setting - the attribute_length - max_stack - max_locals - code_length - exception table - and debug attributes if necessary.
/** * INTERNAL USE-ONLY * That method completes the creation of the code attribute by setting * - the attribute_length * - max_stack * - max_locals * - code_length * - exception table * - and debug attributes if necessary. */
public void completeCodeAttributeForClinit( int codeAttributeOffset, int problemLine, MethodScope scope) { // reinitialize the contents with the byte modified by the code stream this.contents = this.codeStream.bCodeStream; int localContentsOffset = this.codeStream.classFileOffset; // codeAttributeOffset is the position inside contents 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... int code_length = this.codeStream.position; if (code_length > 65535) { this.codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit( this.codeStream.methodDeclaration.scope.referenceType()); } if (localContentsOffset + 20 >= this.contents.length) { resizeContents(20); } int max_stack = this.codeStream.stackMax; this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); this.contents[codeAttributeOffset + 7] = (byte) max_stack; int max_locals = this.codeStream.maxLocals; this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); this.contents[codeAttributeOffset + 9] = (byte) max_locals; this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); this.contents[codeAttributeOffset + 13] = (byte) code_length; // write the exception table this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; // debug attributes int codeAttributeAttributeOffset = localContentsOffset; int attributesNumber = 0; // leave two bytes for the attribute_length localContentsOffset += 2; // first we handle the linenumber attribute if (localContentsOffset + 2 >= this.contents.length) { resizeContents(2); } this.contentsOffset = localContentsOffset; // first we handle the linenumber attribute if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { attributesNumber += generateLineNumberAttribute(problemLine); } localContentsOffset = this.contentsOffset; // then we do the local variable attribute if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) { int localVariableNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); if (localContentsOffset + 8 >= this.contents.length) { resizeContents(8); } this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); this.contents[localContentsOffset++] = (byte) localVariableNameIndex; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 2; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; attributesNumber++; } this.contentsOffset = localContentsOffset; if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) { attributesNumber += generateStackMapTableAttribute( null, code_length, codeAttributeOffset, max_locals, true, scope); } if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { attributesNumber += generateStackMapAttribute( null, code_length, codeAttributeOffset, max_locals, true, scope); } if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { attributesNumber += generateTypeAnnotationsOnCodeAttribute(); } // update the number of attributes // ensure first that there is enough space available inside the contents array if (codeAttributeAttributeOffset + 2 >= this.contents.length) { resizeContents(2); } this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; // update the attribute length int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; } /** * */ public void completeCodeAttributeForMissingAbstractProblemMethod( MethodBinding binding, int codeAttributeOffset, int[] startLineIndexes, int problemLine) { // reinitialize the localContents with the byte modified by the code stream this.contents = this.codeStream.bCodeStream; int localContentsOffset = this.codeStream.classFileOffset; // 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... int max_stack = this.codeStream.stackMax; this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); this.contents[codeAttributeOffset + 7] = (byte) max_stack; int max_locals = this.codeStream.maxLocals; this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); this.contents[codeAttributeOffset + 9] = (byte) max_locals; int code_length = this.codeStream.position; this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); this.contents[codeAttributeOffset + 13] = (byte) code_length; // write the exception table if (localContentsOffset + 50 >= this.contents.length) { resizeContents(50); } this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; // debug attributes int codeAttributeAttributeOffset = localContentsOffset; int attributesNumber = 0; // leave two bytes for the attribute_length localContentsOffset += 2; // first we handle the linenumber attribute if (localContentsOffset + 2 >= this.contents.length) { resizeContents(2); } this.contentsOffset = localContentsOffset; if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { if (problemLine == 0) { problemLine = Util.getLineNumber(binding.sourceStart(), startLineIndexes, 0, startLineIndexes.length-1); } attributesNumber += generateLineNumberAttribute(problemLine); } if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) { attributesNumber += generateStackMapTableAttribute( binding, code_length, codeAttributeOffset, max_locals, false, null); } if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { attributesNumber += generateStackMapAttribute( binding, code_length, codeAttributeOffset, max_locals, false, null); } // then we do the local variable attribute // update the number of attributes// ensure first that there is enough space available inside the localContents array if (codeAttributeAttributeOffset + 2 >= this.contents.length) { resizeContents(2); } this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; // update the attribute length int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; }
INTERNAL USE-ONLY That method completes the creation of the code attribute by setting - the attribute_length - max_stack - max_locals - code_length - exception table - and debug attributes if necessary.
Params:
  • codeAttributeOffset – int
/** * INTERNAL USE-ONLY * That method completes the creation of the code attribute by setting * - the attribute_length * - max_stack * - max_locals * - code_length * - exception table * - and debug attributes if necessary. * * @param codeAttributeOffset <CODE>int</CODE> */
public void completeCodeAttributeForProblemMethod( AbstractMethodDeclaration method, MethodBinding binding, int codeAttributeOffset, int[] startLineIndexes, int problemLine) { // reinitialize the localContents with the byte modified by the code stream this.contents = this.codeStream.bCodeStream; int localContentsOffset = this.codeStream.classFileOffset; // 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... int max_stack = this.codeStream.stackMax; this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); this.contents[codeAttributeOffset + 7] = (byte) max_stack; int max_locals = this.codeStream.maxLocals; this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); this.contents[codeAttributeOffset + 9] = (byte) max_locals; int code_length = this.codeStream.position; this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); this.contents[codeAttributeOffset + 13] = (byte) code_length; // write the exception table if (localContentsOffset + 50 >= this.contents.length) { resizeContents(50); } // write the exception table this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; // debug attributes int codeAttributeAttributeOffset = localContentsOffset; int attributesNumber = 0; // leave two bytes for the attribute_length localContentsOffset += 2; // first we handle the linenumber attribute if (localContentsOffset + 2 >= this.contents.length) { resizeContents(2); } this.contentsOffset = localContentsOffset; if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { if (problemLine == 0) { problemLine = Util.getLineNumber(binding.sourceStart(), startLineIndexes, 0, startLineIndexes.length-1); } attributesNumber += generateLineNumberAttribute(problemLine); } // then we do the local variable attribute if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) { final boolean methodDeclarationIsStatic = this.codeStream.methodDeclaration.isStatic(); attributesNumber += generateLocalVariableTableAttribute(code_length, methodDeclarationIsStatic, false); } if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) { attributesNumber += generateStackMapTableAttribute( binding, code_length, codeAttributeOffset, max_locals, false, null); } if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { attributesNumber += generateStackMapAttribute( binding, code_length, codeAttributeOffset, max_locals, false, null); } // update the number of attributes// ensure first that there is enough space available inside the localContents array if (codeAttributeAttributeOffset + 2 >= this.contents.length) { resizeContents(2); } this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; // update the attribute length int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; }
INTERNAL USE-ONLY That method completes the creation of the code attribute by setting - the attribute_length - max_stack - max_locals - code_length - exception table - and debug attributes if necessary.
Params:
  • binding – org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
  • codeAttributeOffset – int
/** * INTERNAL USE-ONLY * That method completes the creation of the code attribute by setting * - the attribute_length * - max_stack * - max_locals * - code_length * - exception table * - and debug attributes if necessary. * * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding * @param codeAttributeOffset <CODE>int</CODE> */
public void completeCodeAttributeForSyntheticMethod( boolean hasExceptionHandlers, SyntheticMethodBinding binding, int codeAttributeOffset, int[] startLineIndexes, Scope scope) { // reinitialize the contents with the byte modified by the code stream this.contents = this.codeStream.bCodeStream; int localContentsOffset = this.codeStream.classFileOffset; // codeAttributeOffset is the position inside contents 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... int max_stack = this.codeStream.stackMax; this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); this.contents[codeAttributeOffset + 7] = (byte) max_stack; int max_locals = this.codeStream.maxLocals; this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); this.contents[codeAttributeOffset + 9] = (byte) max_locals; int code_length = this.codeStream.position; this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); this.contents[codeAttributeOffset + 13] = (byte) code_length; if ((localContentsOffset + 40) >= this.contents.length) { resizeContents(40); } boolean addStackMaps = (this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0; if (hasExceptionHandlers) { // write the exception table ExceptionLabel[] exceptionLabels = this.codeStream.exceptionLabels; int exceptionHandlersCount = 0; // each label holds one handler per range (start/end contiguous) for (int i = 0, length = this.codeStream.exceptionLabelsCounter; i < length; i++) { exceptionHandlersCount += this.codeStream.exceptionLabels[i].getCount() / 2; } int exSize = exceptionHandlersCount * 8 + 2; if (exSize + localContentsOffset >= this.contents.length) { resizeContents(exSize); } // there is no exception table, so we need to offset by 2 the current offset and move // on the attribute generation this.contents[localContentsOffset++] = (byte) (exceptionHandlersCount >> 8); this.contents[localContentsOffset++] = (byte) exceptionHandlersCount; for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { ExceptionLabel exceptionLabel = exceptionLabels[i]; if (exceptionLabel != null) { int iRange = 0, maxRange = exceptionLabel.getCount(); if ((maxRange & 1) != 0) { this.referenceBinding.scope.problemReporter().abortDueToInternalError( Messages.bind(Messages.abort_invalidExceptionAttribute, new String(binding.selector), this.referenceBinding.scope.problemReporter().referenceContext)); } while (iRange < maxRange) { int start = exceptionLabel.ranges[iRange++]; // even ranges are start positions this.contents[localContentsOffset++] = (byte) (start >> 8); this.contents[localContentsOffset++] = (byte) start; int end = exceptionLabel.ranges[iRange++]; // odd ranges are end positions this.contents[localContentsOffset++] = (byte) (end >> 8); this.contents[localContentsOffset++] = (byte) end; int handlerPC = exceptionLabel.position; if (addStackMaps) { StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; stackMapFrameCodeStream.addFramePosition(handlerPC); } this.contents[localContentsOffset++] = (byte) (handlerPC >> 8); this.contents[localContentsOffset++] = (byte) handlerPC; if (exceptionLabel.exceptionType == null) { // any exception handler this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; } else { int nameIndex; switch(exceptionLabel.exceptionType.id) { case T_null : /* represents ClassNotFoundException, see class literal access*/ nameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName); break; case T_long : /* represents NoSuchFieldError, see switch table generation*/ nameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangNoSuchFieldErrorConstantPoolName); break; default: nameIndex = this.constantPool.literalIndexForType(exceptionLabel.exceptionType); } this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) nameIndex; } } } } } else { // there is no exception table, so we need to offset by 2 the current offset and move // on the attribute generation this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; } // debug attributes int codeAttributeAttributeOffset = localContentsOffset; int attributesNumber = 0; // leave two bytes for the attribute_length localContentsOffset += 2; if (localContentsOffset + 2 >= this.contents.length) { resizeContents(2); } this.contentsOffset = localContentsOffset; // first we handle the linenumber attribute if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { int lineNumber = Util.getLineNumber(binding.sourceStart, startLineIndexes, 0, startLineIndexes.length-1); attributesNumber += generateLineNumberAttribute(lineNumber); } // then we do the local variable attribute if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) { final boolean methodDeclarationIsStatic = binding.isStatic(); attributesNumber += generateLocalVariableTableAttribute(code_length, methodDeclarationIsStatic, true); } if (addStackMaps) { attributesNumber += generateStackMapTableAttribute(binding, code_length, codeAttributeOffset, max_locals, false, scope); } if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { attributesNumber += generateStackMapAttribute( binding, code_length, codeAttributeOffset, max_locals, false, scope); } // update the number of attributes // ensure first that there is enough space available inside the contents array if (codeAttributeAttributeOffset + 2 >= this.contents.length) { resizeContents(2); } this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; // update the attribute length int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; }
INTERNAL USE-ONLY That method completes the creation of the code attribute by setting - the attribute_length - max_stack - max_locals - code_length - exception table - and debug attributes if necessary.
Params:
  • binding – org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding
  • codeAttributeOffset – int
/** * INTERNAL USE-ONLY * That method completes the creation of the code attribute by setting * - the attribute_length * - max_stack * - max_locals * - code_length * - exception table * - and debug attributes if necessary. * * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding * @param codeAttributeOffset <CODE>int</CODE> */
public void completeCodeAttributeForSyntheticMethod( SyntheticMethodBinding binding, int codeAttributeOffset, int[] startLineIndexes) { this.completeCodeAttributeForSyntheticMethod( false, binding, codeAttributeOffset, startLineIndexes, ((SourceTypeBinding) binding.declaringClass).scope); } private void completeArgumentAnnotationInfo(Argument[] arguments, List allAnnotationContexts) { for (int i = 0, max = arguments.length; i < max; i++) { Argument argument = arguments[i]; if ((argument.bits & ASTNode.HasTypeAnnotations) != 0) { argument.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER, i, allAnnotationContexts); } } }
INTERNAL USE-ONLY Complete the creation of a method info by setting up the number of attributes at the right offset.
Params:
  • methodAttributeOffset – int
  • attributesNumber – int
/** * INTERNAL USE-ONLY * Complete the creation of a method info by setting up the number of attributes at the right offset. * * @param methodAttributeOffset <CODE>int</CODE> * @param attributesNumber <CODE>int</CODE> */
public void completeMethodInfo( MethodBinding binding, int methodAttributeOffset, int attributesNumber) { if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { List allTypeAnnotationContexts = new ArrayList(); int invisibleTypeAnnotationsCounter = 0; int visibleTypeAnnotationsCounter = 0; AbstractMethodDeclaration methodDeclaration = binding.sourceMethod(); if (methodDeclaration != null) { if ((methodDeclaration.bits & ASTNode.HasTypeAnnotations) != 0) { Argument[] arguments = methodDeclaration.arguments; if (arguments != null) { completeArgumentAnnotationInfo(arguments, allTypeAnnotationContexts); } Receiver receiver = methodDeclaration.receiver; if (receiver != null && (receiver.type.bits & ASTNode.HasTypeAnnotations) != 0) { receiver.type.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_RECEIVER, allTypeAnnotationContexts); } } Annotation[] annotations = methodDeclaration.annotations; if (annotations != null && !methodDeclaration.isClinit() && (methodDeclaration.isConstructor() || binding.returnType.id != T_void)) { methodDeclaration.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_RETURN, allTypeAnnotationContexts); } if (!methodDeclaration.isConstructor() && !methodDeclaration.isClinit() && binding.returnType.id != T_void) { MethodDeclaration declaration = (MethodDeclaration) methodDeclaration; TypeReference typeReference = declaration.returnType; if ((typeReference.bits & ASTNode.HasTypeAnnotations) != 0) { typeReference.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_RETURN, allTypeAnnotationContexts); } } TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions; if (thrownExceptions != null) { for (int i = 0, max = thrownExceptions.length; i < max; i++) { TypeReference thrownException = thrownExceptions[i]; thrownException.getAllAnnotationContexts(AnnotationTargetTypeConstants.THROWS, i, allTypeAnnotationContexts); } } TypeParameter[] typeParameters = methodDeclaration.typeParameters(); if (typeParameters != null) { for (int i = 0, max = typeParameters.length; i < max; i++) { TypeParameter typeParameter = typeParameters[i]; if ((typeParameter.bits & ASTNode.HasTypeAnnotations) != 0) { typeParameter.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER, i, allTypeAnnotationContexts); } } } } else if (binding.sourceLambda() != null) { // SyntheticMethodBinding, purpose : LambdaMethod. LambdaExpression lambda = binding.sourceLambda(); if ((lambda.bits & ASTNode.HasTypeAnnotations) != 0) { if (lambda.arguments != null) completeArgumentAnnotationInfo(lambda.arguments, allTypeAnnotationContexts); } } int size = allTypeAnnotationContexts.size(); if (size != 0) { AnnotationContext[] allTypeAnnotationContextsArray = new AnnotationContext[size]; allTypeAnnotationContexts.toArray(allTypeAnnotationContextsArray); for (int j = 0, max2 = allTypeAnnotationContextsArray.length; j < max2; j++) { AnnotationContext annotationContext = allTypeAnnotationContextsArray[j]; if ((annotationContext.visibility & AnnotationContext.INVISIBLE) != 0) { invisibleTypeAnnotationsCounter++; } else { visibleTypeAnnotationsCounter++; } } attributesNumber += generateRuntimeTypeAnnotations( allTypeAnnotationContextsArray, visibleTypeAnnotationsCounter, invisibleTypeAnnotationsCounter); } } if ((this.produceAttributes & ClassFileConstants.ATTR_METHOD_PARAMETERS) != 0) { attributesNumber += generateMethodParameters(binding); } // update the number of attributes this.contents[methodAttributeOffset++] = (byte) (attributesNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributesNumber; } private void dumpLocations(int[] locations) { if (locations == null) { // no type path if (this.contentsOffset + 1 >= this.contents.length) { resizeContents(1); } this.contents[this.contentsOffset++] = (byte) 0; } else { int length = locations.length; if (this.contentsOffset + length >= this.contents.length) { resizeContents(length + 1); } this.contents[this.contentsOffset++] = (byte) (locations.length / 2); for (int i = 0; i < length; i++) { this.contents[this.contentsOffset++] = (byte) locations[i]; } } } private void dumpTargetTypeContents(int targetType, AnnotationContext annotationContext) { switch(targetType) { case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER : case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER : // parameter index this.contents[this.contentsOffset++] = (byte) annotationContext.info; break; case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER_BOUND : // type_parameter_index this.contents[this.contentsOffset++] = (byte) annotationContext.info; // bound_index this.contents[this.contentsOffset++] = (byte) annotationContext.info2; break; case AnnotationTargetTypeConstants.FIELD : case AnnotationTargetTypeConstants.METHOD_RECEIVER : case AnnotationTargetTypeConstants.METHOD_RETURN : // target_info is empty_target break; case AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER : // target_info is parameter index this.contents[this.contentsOffset++] = (byte) annotationContext.info; break; case AnnotationTargetTypeConstants.INSTANCEOF : case AnnotationTargetTypeConstants.NEW : case AnnotationTargetTypeConstants.EXCEPTION_PARAMETER : case AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE : case AnnotationTargetTypeConstants.METHOD_REFERENCE : // bytecode offset for new/instanceof/method_reference // exception table entry index for exception_parameter this.contents[this.contentsOffset++] = (byte) (annotationContext.info >> 8); this.contents[this.contentsOffset++] = (byte) annotationContext.info; break; case AnnotationTargetTypeConstants.CAST : // bytecode offset this.contents[this.contentsOffset++] = (byte) (annotationContext.info >> 8); this.contents[this.contentsOffset++] = (byte) annotationContext.info; this.contents[this.contentsOffset++] = (byte) annotationContext.info2; break; case AnnotationTargetTypeConstants.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT : case AnnotationTargetTypeConstants.METHOD_INVOCATION_TYPE_ARGUMENT : case AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT : case AnnotationTargetTypeConstants.METHOD_REFERENCE_TYPE_ARGUMENT : // bytecode offset this.contents[this.contentsOffset++] = (byte) (annotationContext.info >> 8); this.contents[this.contentsOffset++] = (byte) annotationContext.info; // type_argument_index this.contents[this.contentsOffset++] = (byte) annotationContext.info2; break; case AnnotationTargetTypeConstants.CLASS_EXTENDS : case AnnotationTargetTypeConstants.THROWS : // For CLASS_EXTENDS - info is supertype index (-1 = superclass) // For THROWS - info is exception table index this.contents[this.contentsOffset++] = (byte) (annotationContext.info >> 8); this.contents[this.contentsOffset++] = (byte) annotationContext.info; break; case AnnotationTargetTypeConstants.LOCAL_VARIABLE : case AnnotationTargetTypeConstants.RESOURCE_VARIABLE : int localVariableTableOffset = this.contentsOffset; LocalVariableBinding localVariable = annotationContext.variableBinding; int actualSize = 0; int initializationCount = localVariable.initializationCount; actualSize += 2 /* for number of entries */ + (6 * initializationCount); // reserve enough space if (this.contentsOffset + actualSize >= this.contents.length) { resizeContents(actualSize); } this.contentsOffset += 2; int numberOfEntries = 0; for (int j = 0; j < initializationCount; j++) { int startPC = localVariable.initializationPCs[j << 1]; int endPC = localVariable.initializationPCs[(j << 1) + 1]; if (startPC != endPC) { // only entries for non zero length // now we can safely add the local entry numberOfEntries++; this.contents[this.contentsOffset++] = (byte) (startPC >> 8); this.contents[this.contentsOffset++] = (byte) startPC; int length = endPC - startPC; this.contents[this.contentsOffset++] = (byte) (length >> 8); this.contents[this.contentsOffset++] = (byte) length; int resolvedPosition = localVariable.resolvedPosition; this.contents[this.contentsOffset++] = (byte) (resolvedPosition >> 8); this.contents[this.contentsOffset++] = (byte) resolvedPosition; } } this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); this.contents[localVariableTableOffset] = (byte) numberOfEntries; break; case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER_BOUND : this.contents[this.contentsOffset++] = (byte) annotationContext.info; this.contents[this.contentsOffset++] = (byte) annotationContext.info2; break; } }
INTERNAL USE-ONLY This methods returns a char[] representing the file name of the receiver
Returns:char[]
/** * INTERNAL USE-ONLY * This methods returns a char[] representing the file name of the receiver * * @return char[] */
public char[] fileName() { return this.constantPool.UTF8Cache.returnKeyFor(2); } private void generateAnnotation(Annotation annotation, int currentOffset) { int startingContentsOffset = currentOffset; if (this.contentsOffset + 4 >= this.contents.length) { resizeContents(4); } TypeBinding annotationTypeBinding = annotation.resolvedType; if (annotationTypeBinding == null) { this.contentsOffset = startingContentsOffset; return; } if (annotationTypeBinding.isMemberType()) { this.recordInnerClasses(annotationTypeBinding); } final int typeIndex = this.constantPool.literalIndex(annotationTypeBinding.signature()); this.contents[this.contentsOffset++] = (byte) (typeIndex >> 8); this.contents[this.contentsOffset++] = (byte) typeIndex; if (annotation instanceof NormalAnnotation) { NormalAnnotation normalAnnotation = (NormalAnnotation) annotation; MemberValuePair[] memberValuePairs = normalAnnotation.memberValuePairs; int memberValuePairOffset = this.contentsOffset; if (memberValuePairs != null) { int memberValuePairsCount = 0; int memberValuePairsLengthPosition = this.contentsOffset; this.contentsOffset += 2; // leave space to fill in the pair count later int resetPosition = this.contentsOffset; final int memberValuePairsLength = memberValuePairs.length; loop: for (int i = 0; i < memberValuePairsLength; i++) { MemberValuePair memberValuePair = memberValuePairs[i]; if (this.contentsOffset + 2 >= this.contents.length) { resizeContents(2); } final int elementNameIndex = this.constantPool.literalIndex(memberValuePair.name); this.contents[this.contentsOffset++] = (byte) (elementNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) elementNameIndex; MethodBinding methodBinding = memberValuePair.binding; if (methodBinding == null) { this.contentsOffset = resetPosition; } else { try { generateElementValue(memberValuePair.value, methodBinding.returnType, memberValuePairOffset); if (this.contentsOffset == memberValuePairOffset) { // ignore all annotation values this.contents[this.contentsOffset++] = 0; this.contents[this.contentsOffset++] = 0; break loop; } memberValuePairsCount++; resetPosition = this.contentsOffset; } catch(ClassCastException | ShouldNotImplement e) { this.contentsOffset = resetPosition; } } } this.contents[memberValuePairsLengthPosition++] = (byte) (memberValuePairsCount >> 8); this.contents[memberValuePairsLengthPosition++] = (byte) memberValuePairsCount; } else { this.contents[this.contentsOffset++] = 0; this.contents[this.contentsOffset++] = 0; } } else if (annotation instanceof SingleMemberAnnotation) { SingleMemberAnnotation singleMemberAnnotation = (SingleMemberAnnotation) annotation; // this is a single member annotation (one member value) this.contents[this.contentsOffset++] = 0; this.contents[this.contentsOffset++] = 1; if (this.contentsOffset + 2 >= this.contents.length) { resizeContents(2); } final int elementNameIndex = this.constantPool.literalIndex(VALUE); this.contents[this.contentsOffset++] = (byte) (elementNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) elementNameIndex; MethodBinding methodBinding = singleMemberAnnotation.memberValuePairs()[0].binding; if (methodBinding == null) { this.contentsOffset = startingContentsOffset; } else { int memberValuePairOffset = this.contentsOffset; try { generateElementValue(singleMemberAnnotation.memberValue, methodBinding.returnType, memberValuePairOffset); if (this.contentsOffset == memberValuePairOffset) { // completely remove the annotation as its value is invalid this.contentsOffset = startingContentsOffset; } } catch(ClassCastException | ShouldNotImplement e) { this.contentsOffset = startingContentsOffset; } } } else { // this is a marker annotation (no member value pairs) this.contents[this.contentsOffset++] = 0; this.contents[this.contentsOffset++] = 0; } } private int generateAnnotationDefaultAttribute(AnnotationMethodDeclaration declaration, int attributeOffset) { int attributesNumber = 0; // add an annotation default attribute int annotationDefaultNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.AnnotationDefaultName); if (this.contentsOffset + 6 >= this.contents.length) { resizeContents(6); } this.contents[this.contentsOffset++] = (byte) (annotationDefaultNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) annotationDefaultNameIndex; int attributeLengthOffset = this.contentsOffset; this.contentsOffset += 4; generateElementValue(declaration.defaultValue, declaration.binding.returnType, attributeOffset); if (this.contentsOffset != attributeOffset) { int attributeLength = this.contentsOffset - attributeLengthOffset - 4; this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); this.contents[attributeLengthOffset++] = (byte) attributeLength; attributesNumber++; } return attributesNumber; }
INTERNAL USE-ONLY That method generates the header of a code attribute. - the index inside the constant pool for the attribute name ("Code") - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4).
/** * INTERNAL USE-ONLY * That method generates the header of a code attribute. * - the index inside the constant pool for the attribute name ("Code") * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4). */
public void generateCodeAttributeHeader() { if (this.contentsOffset + 20 >= this.contents.length) { resizeContents(20); } int constantValueNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.CodeName); this.contents[this.contentsOffset++] = (byte) (constantValueNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) constantValueNameIndex; // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4) this.contentsOffset += 12; } private int generateConstantValueAttribute(Constant fieldConstant, FieldBinding fieldBinding, int fieldAttributeOffset) { int localContentsOffset = this.contentsOffset; int attributesNumber = 1; if (localContentsOffset + 8 >= this.contents.length) { resizeContents(8); } // Now we generate the constant attribute corresponding to the fieldBinding int constantValueNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.ConstantValueName); this.contents[localContentsOffset++] = (byte) (constantValueNameIndex >> 8); this.contents[localContentsOffset++] = (byte) constantValueNameIndex; // The attribute length = 2 in case of a constantValue attribute this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 2; // Need to add the constant_value_index switch (fieldConstant.typeID()) { case T_boolean : int booleanValueIndex = this.constantPool.literalIndex(fieldConstant.booleanValue() ? 1 : 0); this.contents[localContentsOffset++] = (byte) (booleanValueIndex >> 8); this.contents[localContentsOffset++] = (byte) booleanValueIndex; break; case T_byte : case T_char : case T_int : case T_short : int integerValueIndex = this.constantPool.literalIndex(fieldConstant.intValue()); this.contents[localContentsOffset++] = (byte) (integerValueIndex >> 8); this.contents[localContentsOffset++] = (byte) integerValueIndex; break; case T_float : int floatValueIndex = this.constantPool.literalIndex(fieldConstant.floatValue()); this.contents[localContentsOffset++] = (byte) (floatValueIndex >> 8); this.contents[localContentsOffset++] = (byte) floatValueIndex; break; case T_double : int doubleValueIndex = this.constantPool.literalIndex(fieldConstant.doubleValue()); this.contents[localContentsOffset++] = (byte) (doubleValueIndex >> 8); this.contents[localContentsOffset++] = (byte) doubleValueIndex; break; case T_long : int longValueIndex = this.constantPool.literalIndex(fieldConstant.longValue()); this.contents[localContentsOffset++] = (byte) (longValueIndex >> 8); this.contents[localContentsOffset++] = (byte) longValueIndex; break; case T_JavaLangString : int stringValueIndex = this.constantPool.literalIndex( ((StringConstant) fieldConstant).stringValue()); if (stringValueIndex == -1) { if (!this.creatingProblemType) { // report an error and abort: will lead to a problem type classfile creation TypeDeclaration typeDeclaration = this.referenceBinding.scope.referenceContext; FieldDeclaration[] fieldDecls = typeDeclaration.fields; int max = fieldDecls == null ? 0 : fieldDecls.length; for (int i = 0; i < max; i++) { if (fieldDecls[i].binding == fieldBinding) { // problem should abort typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit( fieldDecls[i]); } } } else { // already inside a problem type creation : no constant for this field this.contentsOffset = fieldAttributeOffset; attributesNumber = 0; } } else { this.contents[localContentsOffset++] = (byte) (stringValueIndex >> 8); this.contents[localContentsOffset++] = (byte) stringValueIndex; } } this.contentsOffset = localContentsOffset; return attributesNumber; } private int generateDeprecatedAttribute() { int localContentsOffset = this.contentsOffset; if (localContentsOffset + 6 >= this.contents.length) { resizeContents(6); } int deprecatedAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.DeprecatedName); this.contents[localContentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) deprecatedAttributeNameIndex; // the length of a deprecated attribute is equals to 0 this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contentsOffset = localContentsOffset; return 1; } private int generateNestHostAttribute() { SourceTypeBinding nestHost = this.referenceBinding.getNestHost(); if (nestHost == null) return 0; int localContentsOffset = this.contentsOffset; if (localContentsOffset + 10 >= this.contents.length) { resizeContents(10); } int nestHostAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.NestHost); this.contents[localContentsOffset++] = (byte) (nestHostAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) nestHostAttributeNameIndex; // The value of the attribute_length item must be two. this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 2; int nestHostIndex = this.constantPool.literalIndexForType(nestHost.constantPoolName()); this.contents[localContentsOffset++] = (byte) (nestHostIndex >> 8); this.contents[localContentsOffset++] = (byte) nestHostIndex; this.contentsOffset = localContentsOffset; return 1; } private int generateNestMembersAttribute() { int localContentsOffset = this.contentsOffset; List<String> nestedMembers = this.referenceBinding.getNestMembers(); int numberOfNestedMembers = nestedMembers != null ? nestedMembers.size() : 0; if (numberOfNestedMembers == 0) // JVMS 11 4.7.29 says "at most one" NestMembers attribute - return if none. return 0; int exSize = 8 + 2 * numberOfNestedMembers; if (exSize + localContentsOffset >= this.contents.length) { resizeContents(exSize); } int attributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.NestMembers); this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) attributeNameIndex; int value = (numberOfNestedMembers << 1) + 2; this.contents[localContentsOffset++] = (byte) (value >> 24); this.contents[localContentsOffset++] = (byte) (value >> 16); this.contents[localContentsOffset++] = (byte) (value >> 8); this.contents[localContentsOffset++] = (byte) value; this.contents[localContentsOffset++] = (byte) (numberOfNestedMembers >> 8); this.contents[localContentsOffset++] = (byte) numberOfNestedMembers; for (int i = 0; i < numberOfNestedMembers; i++) { char[] nestMemberName = nestedMembers.get(i).toCharArray(); int nestedMemberIndex = this.constantPool.literalIndexForType(nestMemberName); this.contents[localContentsOffset++] = (byte) (nestedMemberIndex >> 8); this.contents[localContentsOffset++] = (byte) nestedMemberIndex; } this.contentsOffset = localContentsOffset; return 1; } private int generateNestAttributes() { int nAttrs = generateNestMembersAttribute(); //either member or host will exist 4.7.29 nAttrs += generateNestHostAttribute(); return nAttrs; } private int generateModuleAttribute(ModuleDeclaration module) { ModuleBinding binding = module.binding; int localContentsOffset = this.contentsOffset; if (localContentsOffset + 10 >= this.contents.length) { resizeContents(10); } int moduleAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.ModuleName); this.contents[localContentsOffset++] = (byte) (moduleAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) moduleAttributeNameIndex; int attrLengthOffset = localContentsOffset; localContentsOffset += 4; int moduleNameIndex = this.constantPool.literalIndexForModule(binding.moduleName); this.contents[localContentsOffset++] = (byte) (moduleNameIndex >> 8); this.contents[localContentsOffset++] = (byte) moduleNameIndex; int flags = module.modifiers & ~(ClassFileConstants.AccModule); this.contents[localContentsOffset++] = (byte) (flags >> 8); this.contents[localContentsOffset++] = (byte) flags; String moduleVersion = module.getModuleVersion(); int module_version_idx = moduleVersion == null ? 0 : this.constantPool.literalIndex(moduleVersion.toCharArray()); this.contents[localContentsOffset++] = (byte) (module_version_idx >> 8); this.contents[localContentsOffset++] = (byte) module_version_idx; int attrLength = 6; // ================= requires section ================= /** u2 requires_count; { u2 requires_index; u2 requires_flags; } requires[requires_count]; **/ int requiresCountOffset = localContentsOffset; int requiresCount = module.requiresCount; int requiresSize = 2 + requiresCount * 6; if (localContentsOffset + requiresSize >= this.contents.length) { resizeContents(requiresSize); } localContentsOffset += 2; ModuleBinding javaBaseBinding = null; for(int i = 0; i < module.requiresCount; i++) { RequiresStatement req = module.requires[i]; ModuleBinding reqBinding = req.resolvedBinding; if (CharOperation.equals(reqBinding.moduleName, TypeConstants.JAVA_BASE)) { javaBaseBinding = reqBinding; } int nameIndex = this.constantPool.literalIndexForModule(reqBinding.moduleName); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) (nameIndex); flags = req.modifiers; this.contents[localContentsOffset++] = (byte) (flags >> 8); this.contents[localContentsOffset++] = (byte) (flags); int required_version = 0; this.contents[localContentsOffset++] = (byte) (required_version >> 8); this.contents[localContentsOffset++] = (byte) (required_version); } if (!CharOperation.equals(binding.moduleName, TypeConstants.JAVA_BASE) && javaBaseBinding == null) { if (localContentsOffset + 6 >= this.contents.length) { resizeContents(6); } javaBaseBinding = binding.environment.javaBaseModule(); int javabase_index = this.constantPool.literalIndexForModule(javaBaseBinding.moduleName); this.contents[localContentsOffset++] = (byte) (javabase_index >> 8); this.contents[localContentsOffset++] = (byte) (javabase_index); flags = ClassFileConstants.AccMandated; this.contents[localContentsOffset++] = (byte) (flags >> 8); this.contents[localContentsOffset++] = (byte) flags; int required_version = 0; this.contents[localContentsOffset++] = (byte) (required_version >> 8); this.contents[localContentsOffset++] = (byte) (required_version); requiresCount++; } this.contents[requiresCountOffset++] = (byte) (requiresCount >> 8); this.contents[requiresCountOffset++] = (byte) requiresCount; attrLength += 2 + 6 * requiresCount; // ================= end requires section ================= // ================= exports section ================= /** * u2 exports_count; * { u2 exports_index; * u2 exports_flags; * u2 exports_to_count; * u2 exports_to_index[exports_to_count]; * } exports[exports_count]; */ int exportsSize = 2 + module.exportsCount * 6; if (localContentsOffset + exportsSize >= this.contents.length) { resizeContents(exportsSize); } this.contents[localContentsOffset++] = (byte) (module.exportsCount >> 8); this.contents[localContentsOffset++] = (byte) module.exportsCount; for (int i = 0; i < module.exportsCount; i++) { ExportsStatement ref = module.exports[i]; if (localContentsOffset + 6 >= this.contents.length) { resizeContents((module.exportsCount - i) * 6); } int nameIndex = this.constantPool.literalIndexForPackage(CharOperation.replaceOnCopy(ref.pkgName, '.', '/')); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) (nameIndex); // TODO exports_flags - check when they are set this.contents[localContentsOffset++] = (byte) 0; this.contents[localContentsOffset++] = (byte) 0; int exportsToCount = ref.isQualified() ? ref.targets.length : 0; this.contents[localContentsOffset++] = (byte) (exportsToCount >> 8); this.contents[localContentsOffset++] = (byte) (exportsToCount); if (exportsToCount > 0) { int targetSize = 2 * exportsToCount; if (localContentsOffset + targetSize >= this.contents.length) { resizeContents(targetSize); } for(int j = 0; j < exportsToCount; j++) { nameIndex = this.constantPool.literalIndexForModule(ref.targets[j].moduleName); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) (nameIndex); } attrLength += targetSize; } } attrLength += exportsSize; // ================= end exports section ================= // ================= opens section ================= /** * u2 opens_count; * { u2 opens_index; * u2 opens_flags; * u2 opens_to_count; * u2 opens_to_index[opens_to_count]; * } exports[exports_count]; */ int opensSize = 2 + module.opensCount * 6; if (localContentsOffset + opensSize >= this.contents.length) { resizeContents(opensSize); } this.contents[localContentsOffset++] = (byte) (module.opensCount >> 8); this.contents[localContentsOffset++] = (byte) module.opensCount; for (int i = 0; i < module.opensCount; i++) { OpensStatement ref = module.opens[i]; if (localContentsOffset + 6 >= this.contents.length) { resizeContents((module.opensCount - i) * 6); } int nameIndex = this.constantPool.literalIndexForPackage(CharOperation.replaceOnCopy(ref.pkgName, '.', '/')); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) (nameIndex); // TODO opens_flags - check when they are set this.contents[localContentsOffset++] = (byte) 0; this.contents[localContentsOffset++] = (byte) 0; int opensToCount = ref.isQualified() ? ref.targets.length : 0; this.contents[localContentsOffset++] = (byte) (opensToCount >> 8); this.contents[localContentsOffset++] = (byte) (opensToCount); if (opensToCount > 0) { int targetSize = 2 * opensToCount; if (localContentsOffset + targetSize >= this.contents.length) { resizeContents(targetSize); } for(int j = 0; j < opensToCount; j++) { nameIndex = this.constantPool.literalIndexForModule(ref.targets[j].moduleName); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) (nameIndex); } attrLength += targetSize; } } attrLength += opensSize; // ================= end opens section ================= // ================= uses section ================= /** * u2 uses_count; * u2 uses_index[uses_count]; */ int usesSize = 2 + 2 * module.usesCount; if (localContentsOffset + usesSize >= this.contents.length) { resizeContents(usesSize); } this.contents[localContentsOffset++] = (byte) (module.usesCount >> 8); this.contents[localContentsOffset++] = (byte) module.usesCount; for(int i = 0; i < module.usesCount; i++) { int nameIndex = this.constantPool.literalIndexForType(module.uses[i].serviceInterface.resolvedType.constantPoolName()); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) (nameIndex); } attrLength += usesSize; // ================= end uses section ================= // ================= provides section ================= /** * u2 provides_count; * { * u2 provides_index; * u2 provides_with_count; * u2 provides_with_index[provides_with_count]; * } provides[provides_count]; */ int servicesSize = 2 + 4 * module.servicesCount; if (localContentsOffset + servicesSize >= this.contents.length) { resizeContents(servicesSize); } this.contents[localContentsOffset++] = (byte) (module.servicesCount >> 8); this.contents[localContentsOffset++] = (byte) module.servicesCount; for(int i = 0; i < module.servicesCount; i++) { if (localContentsOffset + 4 >= this.contents.length) { resizeContents((module.servicesCount - i) * 4); } int nameIndex = this.constantPool.literalIndexForType(module.services[i].serviceInterface.resolvedType.constantPoolName()); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) (nameIndex); TypeReference[] impls = module.services[i].implementations; int implLength = impls.length; this.contents[localContentsOffset++] = (byte) (implLength >> 8); this.contents[localContentsOffset++] = (byte) implLength; int targetSize = implLength * 2; if (localContentsOffset + targetSize >= this.contents.length) { resizeContents(targetSize); } for (int j = 0; j < implLength; j++) { nameIndex = this.constantPool.literalIndexForType(impls[j].resolvedType.constantPoolName()); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) (nameIndex); } attrLength += targetSize; } attrLength += servicesSize; // ================= end provides section ================= this.contents[attrLengthOffset++] = (byte)(attrLength >> 24); this.contents[attrLengthOffset++] = (byte)(attrLength >> 16); this.contents[attrLengthOffset++] = (byte)(attrLength >> 8); this.contents[attrLengthOffset++] = (byte)attrLength; this.contentsOffset = localContentsOffset; return 1; } private int generateModuleMainClassAttribute(char[] moduleMainClass) { int localContentsOffset = this.contentsOffset; if (localContentsOffset + 8 >= this.contents.length) { resizeContents(8); } int moduleAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.ModuleMainClass); this.contents[localContentsOffset++] = (byte) (moduleAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) moduleAttributeNameIndex; int attrLength = 2; this.contents[localContentsOffset++] = (byte)(attrLength >> 24); this.contents[localContentsOffset++] = (byte)(attrLength >> 16); this.contents[localContentsOffset++] = (byte)(attrLength >> 8); this.contents[localContentsOffset++] = (byte)attrLength; int moduleNameIndex = this.constantPool.literalIndexForType(moduleMainClass); this.contents[localContentsOffset++] = (byte) (moduleNameIndex >> 8); this.contents[localContentsOffset++] = (byte) moduleNameIndex; this.contentsOffset = localContentsOffset; return 1; } private int generateModulePackagesAttribute(char[][] packageNames) { int localContentsOffset = this.contentsOffset; int maxSize = 6 + 2*packageNames.length; if (localContentsOffset + maxSize >= this.contents.length) { resizeContents(maxSize); } int moduleAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.ModulePackages); this.contents[localContentsOffset++] = (byte) (moduleAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) moduleAttributeNameIndex; int attrLengthOffset = localContentsOffset; localContentsOffset+= 4; int packageCountOffset = localContentsOffset; localContentsOffset+= 2; int packagesCount = 0; for (char[] packageName : packageNames) { if (packageName == null || packageName.length == 0) continue; int packageNameIndex = this.constantPool.literalIndexForPackage(packageName); this.contents[localContentsOffset++] = (byte) (packageNameIndex >> 8); this.contents[localContentsOffset++] = (byte) packageNameIndex; packagesCount++; } this.contents[packageCountOffset++] = (byte)(packagesCount >> 8); this.contents[packageCountOffset++] = (byte)packagesCount; int attrLength = 2 + 2 * packagesCount; this.contents[attrLengthOffset++] = (byte)(attrLength >> 24); this.contents[attrLengthOffset++] = (byte)(attrLength >> 16); this.contents[attrLengthOffset++] = (byte)(attrLength >> 8); this.contents[attrLengthOffset++] = (byte)attrLength; this.contentsOffset = localContentsOffset; return 1; } private void generateElementValue( Expression defaultValue, TypeBinding memberValuePairReturnType, int attributeOffset) { Constant constant = defaultValue.constant; TypeBinding defaultValueBinding = defaultValue.resolvedType; if (defaultValueBinding == null) { this.contentsOffset = attributeOffset; } else { if (defaultValueBinding.isMemberType()) { this.recordInnerClasses(defaultValueBinding); } if (memberValuePairReturnType.isMemberType()) { this.recordInnerClasses(memberValuePairReturnType); } if (memberValuePairReturnType.isArrayType() && !defaultValueBinding.isArrayType()) { // automatic wrapping if (this.contentsOffset + 3 >= this.contents.length) { resizeContents(3); } this.contents[this.contentsOffset++] = (byte) '['; this.contents[this.contentsOffset++] = (byte) 0; this.contents[this.contentsOffset++] = (byte) 1; } if (constant != null && constant != Constant.NotAConstant) { generateElementValue(attributeOffset, defaultValue, constant, memberValuePairReturnType.leafComponentType()); } else { generateElementValueForNonConstantExpression(defaultValue, attributeOffset, defaultValueBinding); } } }
Params:
  • attributeOffset –
/** * @param attributeOffset */
private void generateElementValue(int attributeOffset, Expression defaultValue, Constant constant, TypeBinding binding) { if (this.contentsOffset + 3 >= this.contents.length) { resizeContents(3); } switch (binding.id) { case T_boolean : this.contents[this.contentsOffset++] = (byte) 'Z'; int booleanValueIndex = this.constantPool.literalIndex(constant.booleanValue() ? 1 : 0); this.contents[this.contentsOffset++] = (byte) (booleanValueIndex >> 8); this.contents[this.contentsOffset++] = (byte) booleanValueIndex; break; case T_byte : this.contents[this.contentsOffset++] = (byte) 'B'; int integerValueIndex = this.constantPool.literalIndex(constant.intValue()); this.contents[this.contentsOffset++] = (byte) (integerValueIndex >> 8); this.contents[this.contentsOffset++] = (byte) integerValueIndex; break; case T_char : this.contents[this.contentsOffset++] = (byte) 'C'; integerValueIndex = this.constantPool.literalIndex(constant.intValue()); this.contents[this.contentsOffset++] = (byte) (integerValueIndex >> 8); this.contents[this.contentsOffset++] = (byte) integerValueIndex; break; case T_int : this.contents[this.contentsOffset++] = (byte) 'I'; integerValueIndex = this.constantPool.literalIndex(constant.intValue()); this.contents[this.contentsOffset++] = (byte) (integerValueIndex >> 8); this.contents[this.contentsOffset++] = (byte) integerValueIndex; break; case T_short : this.contents[this.contentsOffset++] = (byte) 'S'; integerValueIndex = this.constantPool.literalIndex(constant.intValue()); this.contents[this.contentsOffset++] = (byte) (integerValueIndex >> 8); this.contents[this.contentsOffset++] = (byte) integerValueIndex; break; case T_float : this.contents[this.contentsOffset++] = (byte) 'F'; int floatValueIndex = this.constantPool.literalIndex(constant.floatValue()); this.contents[this.contentsOffset++] = (byte) (floatValueIndex >> 8); this.contents[this.contentsOffset++] = (byte) floatValueIndex; break; case T_double : this.contents[this.contentsOffset++] = (byte) 'D'; int doubleValueIndex = this.constantPool.literalIndex(constant.doubleValue()); this.contents[this.contentsOffset++] = (byte) (doubleValueIndex >> 8); this.contents[this.contentsOffset++] = (byte) doubleValueIndex; break; case T_long : this.contents[this.contentsOffset++] = (byte) 'J'; int longValueIndex = this.constantPool.literalIndex(constant.longValue()); this.contents[this.contentsOffset++] = (byte) (longValueIndex >> 8); this.contents[this.contentsOffset++] = (byte) longValueIndex; break; case T_JavaLangString : this.contents[this.contentsOffset++] = (byte) 's'; int stringValueIndex = this.constantPool.literalIndex(((StringConstant) constant).stringValue().toCharArray()); if (stringValueIndex == -1) { if (!this.creatingProblemType) { // report an error and abort: will lead to a problem type classfile creation TypeDeclaration typeDeclaration = this.referenceBinding.scope.referenceContext; typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(defaultValue); } else { // already inside a problem type creation : no attribute this.contentsOffset = attributeOffset; } } else { this.contents[this.contentsOffset++] = (byte) (stringValueIndex >> 8); this.contents[this.contentsOffset++] = (byte) stringValueIndex; } } } private void generateElementValueForNonConstantExpression(Expression defaultValue, int attributeOffset, TypeBinding defaultValueBinding) { if (defaultValueBinding != null) { if (defaultValueBinding.isEnum()) { if (this.contentsOffset + 5 >= this.contents.length) { resizeContents(5); } this.contents[this.contentsOffset++] = (byte) 'e'; FieldBinding fieldBinding = null; if (defaultValue instanceof QualifiedNameReference) { QualifiedNameReference nameReference = (QualifiedNameReference) defaultValue; fieldBinding = (FieldBinding) nameReference.binding; } else if (defaultValue instanceof SingleNameReference) { SingleNameReference nameReference = (SingleNameReference) defaultValue; fieldBinding = (FieldBinding) nameReference.binding; } else { this.contentsOffset = attributeOffset; } if (fieldBinding != null) { final int enumConstantTypeNameIndex = this.constantPool.literalIndex(fieldBinding.type.signature()); final int enumConstantNameIndex = this.constantPool.literalIndex(fieldBinding.name); this.contents[this.contentsOffset++] = (byte) (enumConstantTypeNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) enumConstantTypeNameIndex; this.contents[this.contentsOffset++] = (byte) (enumConstantNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) enumConstantNameIndex; } } else if (defaultValueBinding.isAnnotationType()) { if (this.contentsOffset + 1 >= this.contents.length) { resizeContents(1); } this.contents[this.contentsOffset++] = (byte) '@'; generateAnnotation((Annotation) defaultValue, attributeOffset); } else if (defaultValueBinding.isArrayType()) { // array type if (this.contentsOffset + 3 >= this.contents.length) { resizeContents(3); } this.contents[this.contentsOffset++] = (byte) '['; if (defaultValue instanceof ArrayInitializer) { ArrayInitializer arrayInitializer = (ArrayInitializer) defaultValue; int arrayLength = arrayInitializer.expressions != null ? arrayInitializer.expressions.length : 0; this.contents[this.contentsOffset++] = (byte) (arrayLength >> 8); this.contents[this.contentsOffset++] = (byte) arrayLength; for (int i = 0; i < arrayLength; i++) { generateElementValue(arrayInitializer.expressions[i], defaultValueBinding.leafComponentType(), attributeOffset); } } else { this.contentsOffset = attributeOffset; } } else { // class type if (this.contentsOffset + 3 >= this.contents.length) { resizeContents(3); } this.contents[this.contentsOffset++] = (byte) 'c'; if (defaultValue instanceof ClassLiteralAccess) { ClassLiteralAccess classLiteralAccess = (ClassLiteralAccess) defaultValue; final int classInfoIndex = this.constantPool.literalIndex(classLiteralAccess.targetType.signature()); this.contents[this.contentsOffset++] = (byte) (classInfoIndex >> 8); this.contents[this.contentsOffset++] = (byte) classInfoIndex; } else { this.contentsOffset = attributeOffset; } } } else { this.contentsOffset = attributeOffset; } } private int generateEnclosingMethodAttribute() { int localContentsOffset = this.contentsOffset; // add enclosing method attribute (1.5 mode only) if (localContentsOffset + 10 >= this.contents.length) { resizeContents(10); } int enclosingMethodAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.EnclosingMethodName); this.contents[localContentsOffset++] = (byte) (enclosingMethodAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) enclosingMethodAttributeNameIndex; // the length of a signature attribute is equals to 2 this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 4; int enclosingTypeIndex = this.constantPool.literalIndexForType(this.referenceBinding.enclosingType().constantPoolName()); this.contents[localContentsOffset++] = (byte) (enclosingTypeIndex >> 8); this.contents[localContentsOffset++] = (byte) enclosingTypeIndex; byte methodIndexByte1 = 0; byte methodIndexByte2 = 0; if (this.referenceBinding instanceof LocalTypeBinding) { MethodBinding methodBinding = ((LocalTypeBinding) this.referenceBinding).enclosingMethod; if (methodBinding != null) { int enclosingMethodIndex = this.constantPool.literalIndexForNameAndType(methodBinding.selector, methodBinding.signature(this)); methodIndexByte1 = (byte) (enclosingMethodIndex >> 8); methodIndexByte2 = (byte) enclosingMethodIndex; } } this.contents[localContentsOffset++] = methodIndexByte1; this.contents[localContentsOffset++] = methodIndexByte2; this.contentsOffset = localContentsOffset; return 1; } private int generateExceptionsAttribute(ReferenceBinding[] thrownsExceptions) { int localContentsOffset = this.contentsOffset; int length = thrownsExceptions.length; int exSize = 8 + length * 2; if (exSize + this.contentsOffset >= this.contents.length) { resizeContents(exSize); } int exceptionNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.ExceptionsName); this.contents[localContentsOffset++] = (byte) (exceptionNameIndex >> 8); this.contents[localContentsOffset++] = (byte) exceptionNameIndex; // The attribute length = length * 2 + 2 in case of a exception attribute int attributeLength = length * 2 + 2; this.contents[localContentsOffset++] = (byte) (attributeLength >> 24); this.contents[localContentsOffset++] = (byte) (attributeLength >> 16); this.contents[localContentsOffset++] = (byte) (attributeLength >> 8); this.contents[localContentsOffset++] = (byte) attributeLength; this.contents[localContentsOffset++] = (byte) (length >> 8); this.contents[localContentsOffset++] = (byte) length; for (int i = 0; i < length; i++) { int exceptionIndex = this.constantPool.literalIndexForType(thrownsExceptions[i]); this.contents[localContentsOffset++] = (byte) (exceptionIndex >> 8); this.contents[localContentsOffset++] = (byte) exceptionIndex; } this.contentsOffset = localContentsOffset; return 1; } private int generateHierarchyInconsistentAttribute() { int localContentsOffset = this.contentsOffset; // add an attribute for inconsistent hierarchy if (localContentsOffset + 6 >= this.contents.length) { resizeContents(6); } int inconsistentHierarchyNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.InconsistentHierarchy); this.contents[localContentsOffset++] = (byte) (inconsistentHierarchyNameIndex >> 8); this.contents[localContentsOffset++] = (byte) inconsistentHierarchyNameIndex; // the length of an inconsistent hierarchy attribute is equals to 0 this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contentsOffset = localContentsOffset; return 1; } private int generateInnerClassAttribute(int numberOfInnerClasses, ReferenceBinding[] innerClasses) { int localContentsOffset = this.contentsOffset; // Generate the inner class attribute int exSize = 8 * numberOfInnerClasses + 8; if (exSize + localContentsOffset >= this.contents.length) { resizeContents(exSize); } // Now we now the size of the attribute and the number of entries // attribute name int attributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.InnerClassName); this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) attributeNameIndex; int value = (numberOfInnerClasses << 3) + 2; this.contents[localContentsOffset++] = (byte) (value >> 24); this.contents[localContentsOffset++] = (byte) (value >> 16); this.contents[localContentsOffset++] = (byte) (value >> 8); this.contents[localContentsOffset++] = (byte) value; this.contents[localContentsOffset++] = (byte) (numberOfInnerClasses >> 8); this.contents[localContentsOffset++] = (byte) numberOfInnerClasses; for (int i = 0; i < numberOfInnerClasses; i++) { ReferenceBinding innerClass = innerClasses[i]; int accessFlags = innerClass.getAccessFlags(); int innerClassIndex = this.constantPool.literalIndexForType(innerClass.constantPoolName()); // inner class index this.contents[localContentsOffset++] = (byte) (innerClassIndex >> 8); this.contents[localContentsOffset++] = (byte) innerClassIndex; // outer class index: anonymous and local have no outer class index if (innerClass.isMemberType()) { // member or member of local int outerClassIndex = this.constantPool.literalIndexForType(innerClass.enclosingType().constantPoolName()); this.contents[localContentsOffset++] = (byte) (outerClassIndex >> 8); this.contents[localContentsOffset++] = (byte) outerClassIndex; } else { // equals to 0 if the innerClass is not a member type this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; } // name index if (!innerClass.isAnonymousType()) { int nameIndex = this.constantPool.literalIndex(innerClass.sourceName()); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) nameIndex; } else { // equals to 0 if the innerClass is an anonymous type this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; } // access flag if (innerClass.isAnonymousType()) { accessFlags &= ~ClassFileConstants.AccFinal; } else if (innerClass.isMemberType() && innerClass.isInterface()) { accessFlags |= ClassFileConstants.AccStatic; // implicitely static } this.contents[localContentsOffset++] = (byte) (accessFlags >> 8); this.contents[localContentsOffset++] = (byte) accessFlags; } this.contentsOffset = localContentsOffset; return 1; } private int generateBootstrapMethods(List functionalExpressionList) { /* See JVM spec 4.7.21 The BootstrapMethods attribute has the following format: BootstrapMethods_attribute { u2 attribute_name_index; u4 attribute_length; u2 num_bootstrap_methods; { u2 bootstrap_method_ref; u2 num_bootstrap_arguments; u2 bootstrap_arguments[num_bootstrap_arguments]; } bootstrap_methods[num_bootstrap_methods]; } */ // Record inner classes for MethodHandles$Lookup ReferenceBinding methodHandlesLookup = this.referenceBinding.scope.getJavaLangInvokeMethodHandlesLookup(); if (methodHandlesLookup == null) return 0; // skip bootstrap section, class path problem already reported, just avoid NPE. recordInnerClasses(methodHandlesLookup); // Should be done, it's what javac does also ReferenceBinding javaLangInvokeLambdaMetafactory = this.referenceBinding.scope.getJavaLangInvokeLambdaMetafactory(); // Depending on the complexity of the expression it may be necessary to use the altMetafactory() rather than the metafactory() int indexForMetaFactory = 0; int indexForAltMetaFactory = 0; int numberOfBootstraps = functionalExpressionList.size(); int localContentsOffset = this.contentsOffset; // Generate the boot strap attribute - since we are only making lambdas and // functional expressions, we know the size ahead of time - this less general // than the full invokedynamic scope, but fine for Java 8 final int contentsEntries = 10; int exSize = contentsEntries * numberOfBootstraps + 8; if (exSize + localContentsOffset >= this.contents.length) { resizeContents(exSize); } int attributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.BootstrapMethodsName); this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) attributeNameIndex; // leave space for attribute_length and remember where to insert it int attributeLengthPosition = localContentsOffset; localContentsOffset += 4; this.contents[localContentsOffset++] = (byte) (numberOfBootstraps >> 8); this.contents[localContentsOffset++] = (byte) numberOfBootstraps; for (int i = 0; i < numberOfBootstraps; i++) { FunctionalExpression functional = (FunctionalExpression) functionalExpressionList.get(i); MethodBinding [] bridges = functional.getRequiredBridges(); TypeBinding[] markerInterfaces = null; if ((functional instanceof LambdaExpression && (((markerInterfaces = ((LambdaExpression) functional).getMarkerInterfaces()) != null)) || bridges != null) || functional.isSerializable) { // may need even more space int extraSpace = 2; // at least 2 more than when the normal metafactory is used, for the bitflags entry if (markerInterfaces != null) { // 2 for the marker interface list size then 2 per marker interface index extraSpace += (2 + 2 * markerInterfaces.length); } if (bridges != null) { // 2 for bridge count then 2 per bridge method type. extraSpace += (2 + 2 * bridges.length); } if (extraSpace + contentsEntries + localContentsOffset >= this.contents.length) { resizeContents(extraSpace + contentsEntries); } if (indexForAltMetaFactory == 0) { indexForAltMetaFactory = this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, javaLangInvokeLambdaMetafactory, ConstantPool.ALTMETAFACTORY, ConstantPool.JAVA_LANG_INVOKE_LAMBDAMETAFACTORY_ALTMETAFACTORY_SIGNATURE, false); } this.contents[localContentsOffset++] = (byte) (indexForAltMetaFactory >> 8); this.contents[localContentsOffset++] = (byte) indexForAltMetaFactory; // u2 num_bootstrap_arguments this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = (byte) (4 + (markerInterfaces==null?0:1+markerInterfaces.length) + (bridges == null ? 0 : 1 + bridges.length)); int functionalDescriptorIndex = this.constantPool.literalIndexForMethodType(functional.descriptor.original().signature()); this.contents[localContentsOffset++] = (byte) (functionalDescriptorIndex >> 8); this.contents[localContentsOffset++] = (byte) functionalDescriptorIndex; int methodHandleIndex = this.constantPool.literalIndexForMethodHandle(functional.binding.original()); // Speak of " implementation" (erased) version here, adaptations described below. this.contents[localContentsOffset++] = (byte) (methodHandleIndex >> 8); this.contents[localContentsOffset++] = (byte) methodHandleIndex; char [] instantiatedSignature = functional.descriptor.signature(); int methodTypeIndex = this.constantPool.literalIndexForMethodType(instantiatedSignature); this.contents[localContentsOffset++] = (byte) (methodTypeIndex >> 8); this.contents[localContentsOffset++] = (byte) methodTypeIndex; int bitflags = 0; if (functional.isSerializable) { bitflags |= ClassFileConstants.FLAG_SERIALIZABLE; } if (markerInterfaces!=null) { bitflags |= ClassFileConstants.FLAG_MARKERS; } if (bridges != null) { bitflags |= ClassFileConstants.FLAG_BRIDGES; } int indexForBitflags = this.constantPool.literalIndex(bitflags); this.contents[localContentsOffset++] = (byte)(indexForBitflags>>8); this.contents[localContentsOffset++] = (byte)(indexForBitflags); if (markerInterfaces != null) { int markerInterfaceCountIndex = this.constantPool.literalIndex(markerInterfaces.length); this.contents[localContentsOffset++] = (byte)(markerInterfaceCountIndex>>8); this.contents[localContentsOffset++] = (byte)(markerInterfaceCountIndex); for (int m = 0, maxm = markerInterfaces.length; m < maxm; m++) { int classTypeIndex = this.constantPool.literalIndexForType(markerInterfaces[m]); this.contents[localContentsOffset++] = (byte)(classTypeIndex>>8); this.contents[localContentsOffset++] = (byte)(classTypeIndex); } } if (bridges != null) { int bridgeCountIndex = this.constantPool.literalIndex(bridges.length); this.contents[localContentsOffset++] = (byte) (bridgeCountIndex >> 8); this.contents[localContentsOffset++] = (byte) (bridgeCountIndex); for (int m = 0, maxm = bridges.length; m < maxm; m++) { char [] bridgeSignature = bridges[m].signature(); int bridgeMethodTypeIndex = this.constantPool.literalIndexForMethodType(bridgeSignature); this.contents[localContentsOffset++] = (byte) (bridgeMethodTypeIndex >> 8); this.contents[localContentsOffset++] = (byte) bridgeMethodTypeIndex; } } } else { if (contentsEntries + localContentsOffset >= this.contents.length) { resizeContents(contentsEntries); } if (indexForMetaFactory == 0) { indexForMetaFactory = this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, javaLangInvokeLambdaMetafactory, ConstantPool.METAFACTORY, ConstantPool.JAVA_LANG_INVOKE_LAMBDAMETAFACTORY_METAFACTORY_SIGNATURE, false); } this.contents[localContentsOffset++] = (byte) (indexForMetaFactory >> 8); this.contents[localContentsOffset++] = (byte) indexForMetaFactory; // u2 num_bootstrap_arguments this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = (byte) 3; int functionalDescriptorIndex = this.constantPool.literalIndexForMethodType(functional.descriptor.original().signature()); this.contents[localContentsOffset++] = (byte) (functionalDescriptorIndex >> 8); this.contents[localContentsOffset++] = (byte) functionalDescriptorIndex; int methodHandleIndex = this.constantPool.literalIndexForMethodHandle(functional.binding instanceof PolymorphicMethodBinding ? functional.binding : functional.binding.original()); // Speak of " implementation" (erased) version here, adaptations described below. this.contents[localContentsOffset++] = (byte) (methodHandleIndex >> 8); this.contents[localContentsOffset++] = (byte) methodHandleIndex; char [] instantiatedSignature = functional.descriptor.signature(); int methodTypeIndex = this.constantPool.literalIndexForMethodType(instantiatedSignature); this.contents[localContentsOffset++] = (byte) (methodTypeIndex >> 8); this.contents[localContentsOffset++] = (byte) methodTypeIndex; } } int attributeLength = localContentsOffset - attributeLengthPosition - 4; this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 24); this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 16); this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 8); this.contents[attributeLengthPosition++] = (byte) attributeLength; this.contentsOffset = localContentsOffset; return 1; } private int generateLineNumberAttribute() { int localContentsOffset = this.contentsOffset; int attributesNumber = 0; /* Create and add the line number attribute (used for debugging) * Build the pairs of: * (bytecodePC lineNumber) * according to the table of start line indexes and the pcToSourceMap table * contained into the codestream */ int[] pcToSourceMapTable; if (((pcToSourceMapTable = this.codeStream.pcToSourceMap) != null) && (this.codeStream.pcToSourceMapSize != 0)) { int lineNumberNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); if (localContentsOffset + 8 >= this.contents.length) { resizeContents(8); } this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); this.contents[localContentsOffset++] = (byte) lineNumberNameIndex; int lineNumberTableOffset = localContentsOffset; localContentsOffset += 6; // leave space for attribute_length and line_number_table_length int numberOfEntries = 0; int length = this.codeStream.pcToSourceMapSize; for (int i = 0; i < length;) { // write the entry if (localContentsOffset + 4 >= this.contents.length) { resizeContents(4); } int pc = pcToSourceMapTable[i++]; this.contents[localContentsOffset++] = (byte) (pc >> 8); this.contents[localContentsOffset++] = (byte) pc; int lineNumber = pcToSourceMapTable[i++]; this.contents[localContentsOffset++] = (byte) (lineNumber >> 8); this.contents[localContentsOffset++] = (byte) lineNumber; numberOfEntries++; } // now we change the size of the line number attribute int lineNumberAttr_length = numberOfEntries * 4 + 2; this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24); this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16); this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8); this.contents[lineNumberTableOffset++] = (byte) lineNumberAttr_length; this.contents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8); this.contents[lineNumberTableOffset++] = (byte) numberOfEntries; attributesNumber = 1; } this.contentsOffset = localContentsOffset; return attributesNumber; } // this is used for problem and synthetic methods private int generateLineNumberAttribute(int problemLine) { int localContentsOffset = this.contentsOffset; if (localContentsOffset + 12 >= this.contents.length) { resizeContents(12); } /* Create and add the line number attribute (used for debugging) * Build the pairs of: * (bytecodePC lineNumber) * according to the table of start line indexes and the pcToSourceMap table * contained into the codestream */ int lineNumberNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); this.contents[localContentsOffset++] = (byte) lineNumberNameIndex; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 6; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 1; // first entry at pc = 0 this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = (byte) (problemLine >> 8); this.contents[localContentsOffset++] = (byte) problemLine; // now we change the size of the line number attribute this.contentsOffset = localContentsOffset; return 1; } private int generateLocalVariableTableAttribute(int code_length, boolean methodDeclarationIsStatic, boolean isSynthetic) { int attributesNumber = 0; int localContentsOffset = this.contentsOffset; int numberOfEntries = 0; int localVariableNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); int maxOfEntries = 8 + 10 * (methodDeclarationIsStatic ? 0 : 1); for (int i = 0; i < this.codeStream.allLocalsCounter; i++) { LocalVariableBinding localVariableBinding = this.codeStream.locals[i]; maxOfEntries += 10 * localVariableBinding.initializationCount; } // reserve enough space if (localContentsOffset + maxOfEntries >= this.contents.length) { resizeContents(maxOfEntries); } this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); this.contents[localContentsOffset++] = (byte) localVariableNameIndex; int localVariableTableOffset = localContentsOffset; // leave space for attribute_length and local_variable_table_length localContentsOffset += 6; int nameIndex; int descriptorIndex; SourceTypeBinding declaringClassBinding = null; if (!methodDeclarationIsStatic && !isSynthetic) { numberOfEntries++; this.contents[localContentsOffset++] = 0; // the startPC for this is always 0 this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = (byte) (code_length >> 8); this.contents[localContentsOffset++] = (byte) code_length; nameIndex = this.constantPool.literalIndex(ConstantPool.This); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) nameIndex; declaringClassBinding = (SourceTypeBinding) (this.codeStream.methodDeclaration != null ? this.codeStream.methodDeclaration.binding.declaringClass : this.codeStream.lambdaExpression.binding.declaringClass); descriptorIndex = this.constantPool.literalIndex( declaringClassBinding.signature()); this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); this.contents[localContentsOffset++] = (byte) descriptorIndex; this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0 this.contents[localContentsOffset++] = 0; } // used to remember the local variable with a generic type int genericLocalVariablesCounter = 0; LocalVariableBinding[] genericLocalVariables = null; int numberOfGenericEntries = 0; for (int i = 0, max = this.codeStream.allLocalsCounter; i < max; i++) { LocalVariableBinding localVariable = this.codeStream.locals[i]; int initializationCount = localVariable.initializationCount; if (initializationCount == 0) continue; if (localVariable.declaration == null) continue; final TypeBinding localVariableTypeBinding = localVariable.type; boolean isParameterizedType = localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable(); if (isParameterizedType) { if (genericLocalVariables == null) { // we cannot have more than max locals genericLocalVariables = new LocalVariableBinding[max]; } genericLocalVariables[genericLocalVariablesCounter++] = localVariable; } for (int j = 0; j < initializationCount; j++) { int startPC = localVariable.initializationPCs[j << 1]; int endPC = localVariable.initializationPCs[(j << 1) + 1]; if (startPC != endPC) { // only entries for non zero length if (endPC == -1) { localVariable.declaringScope.problemReporter().abortDueToInternalError( Messages.bind(Messages.abort_invalidAttribute, new String(localVariable.name)), (ASTNode) localVariable.declaringScope.methodScope().referenceContext); } if (isParameterizedType) { numberOfGenericEntries++; } // now we can safely add the local entry numberOfEntries++; this.contents[localContentsOffset++] = (byte) (startPC >> 8); this.contents[localContentsOffset++] = (byte) startPC; int length = endPC - startPC; this.contents[localContentsOffset++] = (byte) (length >> 8); this.contents[localContentsOffset++] = (byte) length; nameIndex = this.constantPool.literalIndex(localVariable.name); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) nameIndex; descriptorIndex = this.constantPool.literalIndex(localVariableTypeBinding.signature()); this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); this.contents[localContentsOffset++] = (byte) descriptorIndex; int resolvedPosition = localVariable.resolvedPosition; this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8); this.contents[localContentsOffset++] = (byte) resolvedPosition; } } } int value = numberOfEntries * 10 + 2; this.contents[localVariableTableOffset++] = (byte) (value >> 24); this.contents[localVariableTableOffset++] = (byte) (value >> 16); this.contents[localVariableTableOffset++] = (byte) (value >> 8); this.contents[localVariableTableOffset++] = (byte) value; this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); this.contents[localVariableTableOffset] = (byte) numberOfEntries; attributesNumber++; final boolean currentInstanceIsGeneric = !methodDeclarationIsStatic && declaringClassBinding != null && declaringClassBinding.typeVariables != Binding.NO_TYPE_VARIABLES; if (genericLocalVariablesCounter != 0 || currentInstanceIsGeneric) { // add the local variable type table attribute numberOfGenericEntries += (currentInstanceIsGeneric ? 1 : 0); maxOfEntries = 8 + numberOfGenericEntries * 10; // reserve enough space if (localContentsOffset + maxOfEntries >= this.contents.length) { resizeContents(maxOfEntries); } int localVariableTypeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.LocalVariableTypeTableName); this.contents[localContentsOffset++] = (byte) (localVariableTypeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) localVariableTypeNameIndex; value = numberOfGenericEntries * 10 + 2; this.contents[localContentsOffset++] = (byte) (value >> 24); this.contents[localContentsOffset++] = (byte) (value >> 16); this.contents[localContentsOffset++] = (byte) (value >> 8); this.contents[localContentsOffset++] = (byte) value; this.contents[localContentsOffset++] = (byte) (numberOfGenericEntries >> 8); this.contents[localContentsOffset++] = (byte) numberOfGenericEntries; if (currentInstanceIsGeneric) { this.contents[localContentsOffset++] = 0; // the startPC for this is always 0 this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = (byte) (code_length >> 8); this.contents[localContentsOffset++] = (byte) code_length; nameIndex = this.constantPool.literalIndex(ConstantPool.This); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) nameIndex; descriptorIndex = this.constantPool.literalIndex(declaringClassBinding.genericTypeSignature()); this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); this.contents[localContentsOffset++] = (byte) descriptorIndex; this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0 this.contents[localContentsOffset++] = 0; } for (int i = 0; i < genericLocalVariablesCounter; i++) { LocalVariableBinding localVariable = genericLocalVariables[i]; for (int j = 0; j < localVariable.initializationCount; j++) { int startPC = localVariable.initializationPCs[j << 1]; int endPC = localVariable.initializationPCs[(j << 1) + 1]; if (startPC != endPC) { // only entries for non zero length // now we can safely add the local entry this.contents[localContentsOffset++] = (byte) (startPC >> 8); this.contents[localContentsOffset++] = (byte) startPC; int length = endPC - startPC; this.contents[localContentsOffset++] = (byte) (length >> 8); this.contents[localContentsOffset++] = (byte) length; nameIndex = this.constantPool.literalIndex(localVariable.name); this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); this.contents[localContentsOffset++] = (byte) nameIndex; descriptorIndex = this.constantPool.literalIndex(localVariable.type.genericTypeSignature()); this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); this.contents[localContentsOffset++] = (byte) descriptorIndex; int resolvedPosition = localVariable.resolvedPosition; this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8); this.contents[localContentsOffset++] = (byte) resolvedPosition; } } } attributesNumber++; } this.contentsOffset = localContentsOffset; return attributesNumber; }
INTERNAL USE-ONLY That method generates the attributes of a code attribute. They could be: - an exception attribute for each try/catch found inside the method - a deprecated attribute - a synthetic attribute for synthetic access methods It returns the number of attributes created for the code attribute.
Params:
  • methodBinding – org.eclipse.jdt.internal.compiler.lookup.MethodBinding
Returns:int
/** * INTERNAL USE-ONLY * That method generates the attributes of a code attribute. * They could be: * - an exception attribute for each try/catch found inside the method * - a deprecated attribute * - a synthetic attribute for synthetic access methods * * It returns the number of attributes created for the code attribute. * * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding * @return <CODE>int</CODE> */
public int generateMethodInfoAttributes(MethodBinding methodBinding) { // leave two bytes for the attribute_number this.contentsOffset += 2; if (this.contentsOffset + 2 >= this.contents.length) { resizeContents(2); } // now we can handle all the attribute for that method info: // it could be: // - a CodeAttribute // - a ExceptionAttribute // - a DeprecatedAttribute // - a SyntheticAttribute // Exception attribute ReferenceBinding[] thrownsExceptions; int attributesNumber = 0; if ((thrownsExceptions = methodBinding.thrownExceptions) != Binding.NO_EXCEPTIONS) { // The method has a throw clause. So we need to add an exception attribute // check that there is enough space to write all the bytes for the exception attribute attributesNumber += generateExceptionsAttribute(thrownsExceptions); } if (methodBinding.isDeprecated()) { // Deprecated attribute attributesNumber += generateDeprecatedAttribute(); } if (this.targetJDK < ClassFileConstants.JDK1_5) { if (methodBinding.isSynthetic()) { attributesNumber += generateSyntheticAttribute(); } if (methodBinding.isVarargs()) { attributesNumber += generateVarargsAttribute(); } } // add signature attribute char[] genericSignature = methodBinding.genericSignature(); if (genericSignature != null) { attributesNumber += generateSignatureAttribute(genericSignature); } if (this.targetJDK >= ClassFileConstants.JDK1_4) { AbstractMethodDeclaration methodDeclaration = methodBinding.sourceMethod(); if (methodBinding instanceof SyntheticMethodBinding) { SyntheticMethodBinding syntheticMethod = (SyntheticMethodBinding) methodBinding; if (syntheticMethod.purpose == SyntheticMethodBinding.SuperMethodAccess && CharOperation.equals(syntheticMethod.selector, syntheticMethod.targetMethod.selector)) methodDeclaration = ((SyntheticMethodBinding)methodBinding).targetMethod.sourceMethod(); } if (methodDeclaration != null) { Annotation[] annotations = methodDeclaration.annotations; if (annotations != null) { attributesNumber += generateRuntimeAnnotations(annotations, methodBinding.isConstructor() ? TagBits.AnnotationForConstructor : TagBits.AnnotationForMethod); } if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) { Argument[] arguments = methodDeclaration.arguments; if (arguments != null) { attributesNumber += generateRuntimeAnnotationsForParameters(arguments); } } } else { LambdaExpression lambda = methodBinding.sourceLambda(); if (lambda != null) { if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) { Argument[] arguments = lambda.arguments(); if (arguments != null) { int parameterCount = methodBinding.parameters.length; int argumentCount = arguments.length; if (parameterCount > argumentCount) { // synthetics prefixed int redShift = parameterCount - argumentCount; System.arraycopy(arguments, 0, arguments = new Argument[parameterCount], redShift, argumentCount); for (int i = 0; i < redShift; i++) arguments[i] = new Argument(CharOperation.NO_CHAR, 0, null, 0); } attributesNumber += generateRuntimeAnnotationsForParameters(arguments); } } } } } if ((methodBinding.tagBits & TagBits.HasMissingType) != 0) { this.missingTypes = methodBinding.collectMissingTypes(this.missingTypes); } return attributesNumber; } public int generateMethodInfoAttributes(MethodBinding methodBinding, AnnotationMethodDeclaration declaration) { int attributesNumber = generateMethodInfoAttributes(methodBinding); int attributeOffset = this.contentsOffset; if ((declaration.modifiers & ClassFileConstants.AccAnnotationDefault) != 0) { // add an annotation default attribute attributesNumber += generateAnnotationDefaultAttribute(declaration, attributeOffset); } return attributesNumber; }
INTERNAL USE-ONLY That method generates the header of a method info: The header consists in: - the access flags - the name index of the method name inside the constant pool - the descriptor index of the signature of the method inside the constant pool.
Params:
  • methodBinding – org.eclipse.jdt.internal.compiler.lookup.MethodBinding
/** * INTERNAL USE-ONLY * That method generates the header of a method info: * The header consists in: * - the access flags * - the name index of the method name inside the constant pool * - the descriptor index of the signature of the method inside the constant pool. * * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding */
public void generateMethodInfoHeader(MethodBinding methodBinding) { generateMethodInfoHeader(methodBinding, methodBinding.modifiers); }
INTERNAL USE-ONLY That method generates the header of a method info: The header consists in: - the access flags - the name index of the method name inside the constant pool - the descriptor index of the signature of the method inside the constant pool.
Params:
  • methodBinding – org.eclipse.jdt.internal.compiler.lookup.MethodBinding
  • accessFlags – the access flags
/** * INTERNAL USE-ONLY * That method generates the header of a method info: * The header consists in: * - the access flags * - the name index of the method name inside the constant pool * - the descriptor index of the signature of the method inside the constant pool. * * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding * @param accessFlags the access flags */
public void generateMethodInfoHeader(MethodBinding methodBinding, int accessFlags) { // check that there is enough space to write all the bytes for the method info corresponding // to the @methodBinding this.methodCount++; // add one more method if (this.contentsOffset + 10 >= this.contents.length) { resizeContents(10); } if (this.targetJDK < ClassFileConstants.JDK1_5) { // pre 1.5, synthetic is an attribute, not a modifier // pre 1.5, varargs is an attribute, not a modifier (-target jsr14 mode) accessFlags &= ~(ClassFileConstants.AccSynthetic | ClassFileConstants.AccVarargs); } if ((methodBinding.tagBits & TagBits.ClearPrivateModifier) != 0) { accessFlags &= ~ClassFileConstants.AccPrivate; } this.contents[this.contentsOffset++] = (byte) (accessFlags >> 8); this.contents[this.contentsOffset++] = (byte) accessFlags; int nameIndex = this.constantPool.literalIndex(methodBinding.selector); this.contents[this.contentsOffset++] = (byte) (nameIndex >> 8); this.contents[this.contentsOffset++] = (byte) nameIndex; int descriptorIndex = this.constantPool.literalIndex(methodBinding.signature(this)); this.contents[this.contentsOffset++] = (byte) (descriptorIndex >> 8); this.contents[this.contentsOffset++] = (byte) descriptorIndex; } public void addSyntheticDeserializeLambda(SyntheticMethodBinding methodBinding, SyntheticMethodBinding[] syntheticMethodBindings ) { generateMethodInfoHeader(methodBinding); int methodAttributeOffset = this.contentsOffset; // this will add exception attribute, synthetic attribute, deprecated attribute,... int attributeNumber = generateMethodInfoAttributes(methodBinding); // Code attribute int codeAttributeOffset = this.contentsOffset; attributeNumber++; // add code attribute generateCodeAttributeHeader(); this.codeStream.init(this); this.codeStream.generateSyntheticBodyForDeserializeLambda(methodBinding, syntheticMethodBindings); int code_length = this.codeStream.position; if (code_length > 65535) { this.referenceBinding.scope.problemReporter().bytecodeExceeds64KLimit( methodBinding, this.referenceBinding.sourceStart(), this.referenceBinding.sourceEnd()); } completeCodeAttributeForSyntheticMethod( methodBinding, codeAttributeOffset, ((SourceTypeBinding) methodBinding.declaringClass) .scope .referenceCompilationUnit() .compilationResult .getLineSeparatorPositions()); this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); this.contents[methodAttributeOffset] = (byte) attributeNumber; }
INTERNAL USE-ONLY That method generates the method info header of a clinit: The header consists in: - the access flags (always default access + static) - the name index of the method name (always ) inside the constant pool - the descriptor index of the signature (always ()V) of the method inside the constant pool.
/** * INTERNAL USE-ONLY * That method generates the method info header of a clinit: * The header consists in: * - the access flags (always default access + static) * - the name index of the method name (always <clinit>) inside the constant pool * - the descriptor index of the signature (always ()V) of the method inside the constant pool. */
public void generateMethodInfoHeaderForClinit() { // check that there is enough space to write all the bytes for the method info corresponding // to the @methodBinding this.methodCount++; // add one more method if (this.contentsOffset + 10 >= this.contents.length) { resizeContents(10); } this.contents[this.contentsOffset++] = (byte) ((ClassFileConstants.AccDefault | ClassFileConstants.AccStatic) >> 8); this.contents[this.contentsOffset++] = (byte) (ClassFileConstants.AccDefault | ClassFileConstants.AccStatic); int nameIndex = this.constantPool.literalIndex(ConstantPool.Clinit); this.contents[this.contentsOffset++] = (byte) (nameIndex >> 8); this.contents[this.contentsOffset++] = (byte) nameIndex; int descriptorIndex = this.constantPool.literalIndex(ConstantPool.ClinitSignature); this.contents[this.contentsOffset++] = (byte) (descriptorIndex >> 8); this.contents[this.contentsOffset++] = (byte) descriptorIndex; // We know that we won't get more than 1 attribute: the code attribute this.contents[this.contentsOffset++] = 0; this.contents[this.contentsOffset++] = 1; }
INTERNAL USE-ONLY Generate the byte for problem method infos that correspond to missing abstract methods. http://dev.eclipse.org/bugs/show_bug.cgi?id=3179
Params:
  • methodDeclarations – Array of all missing abstract methods
/** * INTERNAL USE-ONLY * Generate the byte for problem method infos that correspond to missing abstract methods. * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179 * * @param methodDeclarations Array of all missing abstract methods */
public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) { if (methodDeclarations != null) { TypeDeclaration currentDeclaration = this.referenceBinding.scope.referenceContext; int typeDeclarationSourceStart = currentDeclaration.sourceStart(); int typeDeclarationSourceEnd = currentDeclaration.sourceEnd(); for (int i = 0, max = methodDeclarations.length; i < max; i++) { MethodDeclaration methodDeclaration = methodDeclarations[i]; MethodBinding methodBinding = methodDeclaration.binding; String readableName = new String(methodBinding.readableName()); CategorizedProblem[] problems = compilationResult.problems; int problemsCount = compilationResult.problemCount; for (int j = 0; j < problemsCount; j++) { CategorizedProblem problem = problems[j]; if (problem != null && problem.getID() == IProblem.AbstractMethodMustBeImplemented && problem.getMessage().indexOf(readableName) != -1 && problem.getSourceStart() >= typeDeclarationSourceStart && problem.getSourceEnd() <= typeDeclarationSourceEnd) { // we found a match addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult); } } } } } private void generateMissingTypesAttribute() { int initialSize = this.missingTypes.size(); int[] missingTypesIndexes = new int[initialSize]; int numberOfMissingTypes = 0; if (initialSize > 1) { Collections.sort(this.missingTypes, new Comparator() { @Override public int compare(Object o1, Object o2) { TypeBinding typeBinding1 = (TypeBinding) o1; TypeBinding typeBinding2 = (TypeBinding) o2; return CharOperation.compareTo(typeBinding1.constantPoolName(), typeBinding2.constantPoolName()); } }); } int previousIndex = 0; next: for (int i = 0; i < initialSize; i++) { int missingTypeIndex = this.constantPool.literalIndexForType(this.missingTypes.get(i)); if (previousIndex == missingTypeIndex) { continue next; } previousIndex = missingTypeIndex; missingTypesIndexes[numberOfMissingTypes++] = missingTypeIndex; } // we don't need to resize as we interate from 0 to numberOfMissingTypes when recording the indexes in the .class file int attributeLength = numberOfMissingTypes * 2 + 2; if (this.contentsOffset + attributeLength + 6 >= this.contents.length) { resizeContents(attributeLength + 6); } int missingTypesNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.MissingTypesName); this.contents[this.contentsOffset++] = (byte) (missingTypesNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) missingTypesNameIndex; // generate attribute length this.contents[this.contentsOffset++] = (byte) (attributeLength >> 24); this.contents[this.contentsOffset++] = (byte) (attributeLength >> 16); this.contents[this.contentsOffset++] = (byte) (attributeLength >> 8); this.contents[this.contentsOffset++] = (byte) attributeLength; // generate number of missing types this.contents[this.contentsOffset++] = (byte) (numberOfMissingTypes >> 8); this.contents[this.contentsOffset++] = (byte) numberOfMissingTypes; // generate entry for each missing type for (int i = 0; i < numberOfMissingTypes; i++) { int missingTypeIndex = missingTypesIndexes[i]; this.contents[this.contentsOffset++] = (byte) (missingTypeIndex >> 8); this.contents[this.contentsOffset++] = (byte) missingTypeIndex; } } private boolean jdk16packageInfoAnnotation(final long annotationMask, final long targetMask) { if (this.targetJDK <= ClassFileConstants.JDK1_6 && targetMask == TagBits.AnnotationForPackage && annotationMask != 0 && (annotationMask & TagBits.AnnotationForPackage) == 0) { return true; } return false; }
Params:
  • annotations –
  • targetMask – allowed targets
Returns:the number of attributes created while dumping the annotations in the .class file
/** * @param annotations * @param targetMask allowed targets * @return the number of attributes created while dumping the annotations in the .class file */
private int generateRuntimeAnnotations(final Annotation[] annotations, final long targetMask) { int attributesNumber = 0; final int length = annotations.length; int visibleAnnotationsCounter = 0; int invisibleAnnotationsCounter = 0; for (int i = 0; i < length; i++) { Annotation annotation; if ((annotation = annotations[i].getPersistibleAnnotation()) == null) continue; // already packaged into container. long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; if (annotationMask != 0 && (annotationMask & targetMask) == 0) { if (!jdk16packageInfoAnnotation(annotationMask, targetMask)) continue; } if (annotation.isRuntimeInvisible() || annotation.isRuntimeTypeInvisible()) { invisibleAnnotationsCounter++; } else if (annotation.isRuntimeVisible() || annotation.isRuntimeTypeVisible()) { visibleAnnotationsCounter++; } } int annotationAttributeOffset = this.contentsOffset; if (invisibleAnnotationsCounter != 0) { if (this.contentsOffset + 10 >= this.contents.length) { resizeContents(10); } int runtimeInvisibleAnnotationsAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.RuntimeInvisibleAnnotationsName); this.contents[this.contentsOffset++] = (byte) (runtimeInvisibleAnnotationsAttributeNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) runtimeInvisibleAnnotationsAttributeNameIndex; int attributeLengthOffset = this.contentsOffset; this.contentsOffset += 4; // leave space for the attribute length int annotationsLengthOffset = this.contentsOffset; this.contentsOffset += 2; // leave space for the annotations length int counter = 0; loop: for (int i = 0; i < length; i++) { if (invisibleAnnotationsCounter == 0) break loop; Annotation annotation; if ((annotation = annotations[i].getPersistibleAnnotation()) == null) continue; // already packaged into container. long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; if (annotationMask != 0 && (annotationMask & targetMask) == 0) { if (!jdk16packageInfoAnnotation(annotationMask, targetMask)) continue; } if (annotation.isRuntimeInvisible() || annotation.isRuntimeTypeInvisible()) { int currentAnnotationOffset = this.contentsOffset; generateAnnotation(annotation, currentAnnotationOffset); invisibleAnnotationsCounter--; if (this.contentsOffset != currentAnnotationOffset) { counter++; } } } if (counter != 0) { this.contents[annotationsLengthOffset++] = (byte) (counter >> 8); this.contents[annotationsLengthOffset++] = (byte) counter; int attributeLength = this.contentsOffset - attributeLengthOffset - 4; this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); this.contents[attributeLengthOffset++] = (byte) attributeLength; attributesNumber++; } else { this.contentsOffset = annotationAttributeOffset; } } annotationAttributeOffset = this.contentsOffset; if (visibleAnnotationsCounter != 0) { if (this.contentsOffset + 10 >= this.contents.length) { resizeContents(10); } int runtimeVisibleAnnotationsAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.RuntimeVisibleAnnotationsName); this.contents[this.contentsOffset++] = (byte) (runtimeVisibleAnnotationsAttributeNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) runtimeVisibleAnnotationsAttributeNameIndex; int attributeLengthOffset = this.contentsOffset; this.contentsOffset += 4; // leave space for the attribute length int annotationsLengthOffset = this.contentsOffset; this.contentsOffset += 2; // leave space for the annotations length int counter = 0; loop: for (int i = 0; i < length; i++) { if (visibleAnnotationsCounter == 0) break loop; Annotation annotation; if ((annotation = annotations[i].getPersistibleAnnotation()) == null) continue; // already packaged into container. long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; if (annotationMask != 0 && (annotationMask & targetMask) == 0) { if (!jdk16packageInfoAnnotation(annotationMask, targetMask)) continue; } if (annotation.isRuntimeVisible() || annotation.isRuntimeTypeVisible()) { visibleAnnotationsCounter--; int currentAnnotationOffset = this.contentsOffset; generateAnnotation(annotation, currentAnnotationOffset); if (this.contentsOffset != currentAnnotationOffset) { counter++; } } } if (counter != 0) { this.contents[annotationsLengthOffset++] = (byte) (counter >> 8); this.contents[annotationsLengthOffset++] = (byte) counter; int attributeLength = this.contentsOffset - attributeLengthOffset - 4; this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); this.contents[attributeLengthOffset++] = (byte) attributeLength; attributesNumber++; } else { this.contentsOffset = annotationAttributeOffset; } } return attributesNumber; } private int generateRuntimeAnnotationsForParameters(Argument[] arguments) { final int argumentsLength = arguments.length; final int VISIBLE_INDEX = 0; final int INVISIBLE_INDEX = 1; int invisibleParametersAnnotationsCounter = 0; int visibleParametersAnnotationsCounter = 0; int[][] annotationsCounters = new int[argumentsLength][2]; for (int i = 0; i < argumentsLength; i++) { Argument argument = arguments[i]; Annotation[] annotations = argument.annotations; if (annotations != null) { for (int j = 0, max2 = annotations.length; j < max2; j++) { Annotation annotation; if ((annotation = annotations[j].getPersistibleAnnotation()) == null) continue; // already packaged into container. long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; if (annotationMask != 0 && (annotationMask & TagBits.AnnotationForParameter) == 0) continue; if (annotation.isRuntimeInvisible()) { annotationsCounters[i][INVISIBLE_INDEX]++; invisibleParametersAnnotationsCounter++; } else if (annotation.isRuntimeVisible()) { annotationsCounters[i][VISIBLE_INDEX]++; visibleParametersAnnotationsCounter++; } } } } int attributesNumber = 0; int annotationAttributeOffset = this.contentsOffset; if (invisibleParametersAnnotationsCounter != 0) { int globalCounter = 0; if (this.contentsOffset + 7 >= this.contents.length) { resizeContents(7); } int attributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.RuntimeInvisibleParameterAnnotationsName); this.contents[this.contentsOffset++] = (byte) (attributeNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) attributeNameIndex; int attributeLengthOffset = this.contentsOffset; this.contentsOffset += 4; // leave space for the attribute length this.contents[this.contentsOffset++] = (byte) argumentsLength; for (int i = 0; i < argumentsLength; i++) { if (this.contentsOffset + 2 >= this.contents.length) { resizeContents(2); } if (invisibleParametersAnnotationsCounter == 0) { this.contents[this.contentsOffset++] = (byte) 0; this.contents[this.contentsOffset++] = (byte) 0; } else { final int numberOfInvisibleAnnotations = annotationsCounters[i][INVISIBLE_INDEX]; int invisibleAnnotationsOffset = this.contentsOffset; // leave space for number of annotations this.contentsOffset += 2; int counter = 0; if (numberOfInvisibleAnnotations != 0) { Argument argument = arguments[i]; Annotation[] annotations = argument.annotations; for (int j = 0, max = annotations.length; j < max; j++) { Annotation annotation; if ((annotation = annotations[j].getPersistibleAnnotation()) == null) continue; // already packaged into container. long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; if (annotationMask != 0 && (annotationMask & TagBits.AnnotationForParameter) == 0) continue; if (annotation.isRuntimeInvisible()) { int currentAnnotationOffset = this.contentsOffset; generateAnnotation(annotation, currentAnnotationOffset); if (this.contentsOffset != currentAnnotationOffset) { counter++; globalCounter++; } invisibleParametersAnnotationsCounter--; } } } this.contents[invisibleAnnotationsOffset++] = (byte) (counter >> 8); this.contents[invisibleAnnotationsOffset] = (byte) counter; } } if (globalCounter != 0) { int attributeLength = this.contentsOffset - attributeLengthOffset - 4; this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); this.contents[attributeLengthOffset++] = (byte) attributeLength; attributesNumber++; } else { // if globalCounter is 0, this means that the code generation for all visible annotations failed this.contentsOffset = annotationAttributeOffset; } } if (visibleParametersAnnotationsCounter != 0) { int globalCounter = 0; if (this.contentsOffset + 7 >= this.contents.length) { resizeContents(7); } int attributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.RuntimeVisibleParameterAnnotationsName); this.contents[this.contentsOffset++] = (byte) (attributeNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) attributeNameIndex; int attributeLengthOffset = this.contentsOffset; this.contentsOffset += 4; // leave space for the attribute length this.contents[this.contentsOffset++] = (byte) argumentsLength; for (int i = 0; i < argumentsLength; i++) { if (this.contentsOffset + 2 >= this.contents.length) { resizeContents(2); } if (visibleParametersAnnotationsCounter == 0) { this.contents[this.contentsOffset++] = (byte) 0; this.contents[this.contentsOffset++] = (byte) 0; } else { final int numberOfVisibleAnnotations = annotationsCounters[i][VISIBLE_INDEX]; int visibleAnnotationsOffset = this.contentsOffset; // leave space for number of annotations this.contentsOffset += 2; int counter = 0; if (numberOfVisibleAnnotations != 0) { Argument argument = arguments[i]; Annotation[] annotations = argument.annotations; for (int j = 0, max = annotations.length; j < max; j++) { Annotation annotation; if ((annotation = annotations[j].getPersistibleAnnotation()) == null) continue; // already packaged into container. long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; if (annotationMask != 0 && (annotationMask & TagBits.AnnotationForParameter) == 0) continue; if (annotation.isRuntimeVisible()) { int currentAnnotationOffset = this.contentsOffset; generateAnnotation(annotation, currentAnnotationOffset); if (this.contentsOffset != currentAnnotationOffset) { counter++; globalCounter++; } visibleParametersAnnotationsCounter--; } } } this.contents[visibleAnnotationsOffset++] = (byte) (counter >> 8); this.contents[visibleAnnotationsOffset] = (byte) counter; } } if (globalCounter != 0) { int attributeLength = this.contentsOffset - attributeLengthOffset - 4; this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); this.contents[attributeLengthOffset++] = (byte) attributeLength; attributesNumber++; } else { // if globalCounter is 0, this means that the code generation for all visible annotations failed this.contentsOffset = annotationAttributeOffset; } } return attributesNumber; }
Params:
  • annotationContexts – the given annotation contexts
  • visibleTypeAnnotationsNumber – the given number of visible type annotations
  • invisibleTypeAnnotationsNumber – the given number of invisible type annotations
Returns:the number of attributes created while dumping the annotations in the .class file
/** * @param annotationContexts the given annotation contexts * @param visibleTypeAnnotationsNumber the given number of visible type annotations * @param invisibleTypeAnnotationsNumber the given number of invisible type annotations * @return the number of attributes created while dumping the annotations in the .class file */
private int generateRuntimeTypeAnnotations( final AnnotationContext[] annotationContexts, int visibleTypeAnnotationsNumber, int invisibleTypeAnnotationsNumber) { int attributesNumber = 0; final int length = annotationContexts.length; int visibleTypeAnnotationsCounter = visibleTypeAnnotationsNumber; int invisibleTypeAnnotationsCounter = invisibleTypeAnnotationsNumber; int annotationAttributeOffset = this.contentsOffset; if (invisibleTypeAnnotationsCounter != 0) { if (this.contentsOffset + 10 >= this.contents.length) { resizeContents(10); } int runtimeInvisibleAnnotationsAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.RuntimeInvisibleTypeAnnotationsName); this.contents[this.contentsOffset++] = (byte) (runtimeInvisibleAnnotationsAttributeNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) runtimeInvisibleAnnotationsAttributeNameIndex; int attributeLengthOffset = this.contentsOffset; this.contentsOffset += 4; // leave space for the attribute length int annotationsLengthOffset = this.contentsOffset; this.contentsOffset += 2; // leave space for the annotations length int counter = 0; loop: for (int i = 0; i < length; i++) { if (invisibleTypeAnnotationsCounter == 0) break loop; AnnotationContext annotationContext = annotationContexts[i]; if ((annotationContext.visibility & AnnotationContext.INVISIBLE) != 0) { int currentAnnotationOffset = this.contentsOffset; generateTypeAnnotation(annotationContext, currentAnnotationOffset); invisibleTypeAnnotationsCounter--; if (this.contentsOffset != currentAnnotationOffset) { counter++; } } } if (counter != 0) { this.contents[annotationsLengthOffset++] = (byte) (counter >> 8); this.contents[annotationsLengthOffset++] = (byte) counter; int attributeLength = this.contentsOffset - attributeLengthOffset - 4; this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); this.contents[attributeLengthOffset++] = (byte) attributeLength; attributesNumber++; } else { this.contentsOffset = annotationAttributeOffset; } } annotationAttributeOffset = this.contentsOffset; if (visibleTypeAnnotationsCounter != 0) { if (this.contentsOffset + 10 >= this.contents.length) { resizeContents(10); } int runtimeVisibleAnnotationsAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.RuntimeVisibleTypeAnnotationsName); this.contents[this.contentsOffset++] = (byte) (runtimeVisibleAnnotationsAttributeNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) runtimeVisibleAnnotationsAttributeNameIndex; int attributeLengthOffset = this.contentsOffset; this.contentsOffset += 4; // leave space for the attribute length int annotationsLengthOffset = this.contentsOffset; this.contentsOffset += 2; // leave space for the annotations length int counter = 0; loop: for (int i = 0; i < length; i++) { if (visibleTypeAnnotationsCounter == 0) break loop; AnnotationContext annotationContext = annotationContexts[i]; if ((annotationContext.visibility & AnnotationContext.VISIBLE) != 0) { visibleTypeAnnotationsCounter--; int currentAnnotationOffset = this.contentsOffset; generateTypeAnnotation(annotationContext, currentAnnotationOffset); if (this.contentsOffset != currentAnnotationOffset) { counter++; } } } if (counter != 0) { this.contents[annotationsLengthOffset++] = (byte) (counter >> 8); this.contents[annotationsLengthOffset++] = (byte) counter; int attributeLength = this.contentsOffset - attributeLengthOffset - 4; this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); this.contents[attributeLengthOffset++] = (byte) attributeLength; attributesNumber++; } else { this.contentsOffset = annotationAttributeOffset; } } return attributesNumber; }
Params:
  • binding – the given method binding
Returns:the number of attributes created while dumping he method's parameters in the .class file (0 or 1)
/** * @param binding the given method binding * @return the number of attributes created while dumping he method's parameters in the .class file (0 or 1) */
private int generateMethodParameters(final MethodBinding binding) { if (binding.sourceLambda() != null) return 0; int initialContentsOffset = this.contentsOffset; int length = 0; // count of actual parameters AbstractMethodDeclaration methodDeclaration = binding.sourceMethod(); boolean isConstructor = binding.isConstructor(); TypeBinding[] targetParameters = binding.parameters; ReferenceBinding declaringClass = binding.declaringClass; if (declaringClass.isEnum()) { if (isConstructor) { // insert String name,int ordinal length = writeArgumentName(ConstantPool.EnumName, ClassFileConstants.AccSynthetic, length); length = writeArgumentName(ConstantPool.EnumOrdinal, ClassFileConstants.AccSynthetic, length); } else if (binding instanceof SyntheticMethodBinding && CharOperation.equals(ConstantPool.ValueOf, binding.selector)) { // insert String name length = writeArgumentName(ConstantPool.Name, ClassFileConstants.AccMandated, length); targetParameters = Binding.NO_PARAMETERS; // Override "unknown" synthetics below } } boolean needSynthetics = isConstructor && declaringClass.isNestedType(); if (needSynthetics) { // Take into account the synthetic argument names // This tracks JLS8, paragraph 8.8.9 boolean anonymousWithLocalSuper = declaringClass.isAnonymousType() && declaringClass.superclass().isLocalType(); boolean anonymousWithNestedSuper = declaringClass.isAnonymousType() && declaringClass.superclass().isNestedType(); boolean isImplicitlyDeclared = ((! declaringClass.isPrivate()) || declaringClass.isAnonymousType()) && !anonymousWithLocalSuper; ReferenceBinding[] syntheticArgumentTypes = declaringClass.syntheticEnclosingInstanceTypes(); if (syntheticArgumentTypes != null) { for (int i = 0, count = syntheticArgumentTypes.length; i < count; i++) { // This behaviour tracks JLS 15.9.5.1 // This covers that the parameter ending up in a nested class must be mandated "on the way in", even if it // isn't the first. The practical relevance of this is questionable, since the constructor call will be // generated by the same constructor. boolean couldForwardToMandated = anonymousWithNestedSuper ? declaringClass.superclass().enclosingType().equals(syntheticArgumentTypes[i]) : true; int modifier = couldForwardToMandated && isImplicitlyDeclared ? ClassFileConstants.AccMandated : ClassFileConstants.AccSynthetic; char[] name = CharOperation.concat( TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX, String.valueOf(i).toCharArray()); // cannot use depth, can be identical length = writeArgumentName(name, modifier | ClassFileConstants.AccFinal, length); } } if (binding instanceof SyntheticMethodBinding) { targetParameters = ((SyntheticMethodBinding)binding).targetMethod.parameters; methodDeclaration = ((SyntheticMethodBinding)binding).targetMethod.sourceMethod(); } } if (targetParameters != Binding.NO_PARAMETERS) { Argument[] arguments = null; if (methodDeclaration != null && methodDeclaration.arguments != null) { arguments = methodDeclaration.arguments; } for (int i = 0, max = targetParameters.length, argumentsLength = arguments != null ? arguments.length : 0; i < max; i++) { if (argumentsLength > i && arguments[i] != null) { Argument argument = arguments[i]; length = writeArgumentName(argument.name, argument.binding.modifiers, length); } else { length = writeArgumentName(null, ClassFileConstants.AccSynthetic, length); } } } if (needSynthetics) { SyntheticArgumentBinding[] syntheticOuterArguments = declaringClass.syntheticOuterLocalVariables(); int count = syntheticOuterArguments == null ? 0 : syntheticOuterArguments.length; for (int i = 0; i < count; i++) { length = writeArgumentName(syntheticOuterArguments[i].name, syntheticOuterArguments[i].modifiers | ClassFileConstants.AccSynthetic, length); } // move the extra padding arguments of the synthetic constructor invocation to the end for (int i = targetParameters.length, extraLength = binding.parameters.length; i < extraLength; i++) { TypeBinding parameter = binding.parameters[i]; length = writeArgumentName(parameter.constantPoolName(), ClassFileConstants.AccSynthetic, length); } } if (length > 0) { // so we actually output the parameter int attributeLength = 1 + 4 * length; // u1 for count, u2+u2 per parameter if (this.contentsOffset + 6 + attributeLength >= this.contents.length) { resizeContents(6 + attributeLength); } int methodParametersNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.MethodParametersName); this.contents[initialContentsOffset++] = (byte) (methodParametersNameIndex >> 8); this.contents[initialContentsOffset++] = (byte) methodParametersNameIndex; this.contents[initialContentsOffset++] = (byte) (attributeLength >> 24); this.contents[initialContentsOffset++] = (byte) (attributeLength >> 16); this.contents[initialContentsOffset++] = (byte) (attributeLength >> 8); this.contents[initialContentsOffset++] = (byte) attributeLength; this.contents[initialContentsOffset++] = (byte) length; return 1; } else { return 0; } } private int writeArgumentName(char[] name, int modifiers, int oldLength) { int ensureRoomForBytes = 4; if (oldLength == 0) { // Make room for ensureRoomForBytes += 7; this.contentsOffset += 7; // Make room for attribute header + count byte } if (this.contentsOffset + ensureRoomForBytes > this.contents.length) { resizeContents(ensureRoomForBytes); } int parameterNameIndex = name == null ? 0 : this.constantPool.literalIndex(name); this.contents[this.contentsOffset++] = (byte) (parameterNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) parameterNameIndex; int flags = modifiers & (ClassFileConstants.AccFinal | ClassFileConstants.AccSynthetic | ClassFileConstants.AccMandated); this.contents[this.contentsOffset++] = (byte) (flags >> 8); this.contents[this.contentsOffset++] = (byte) flags; return oldLength + 1; } private int generateSignatureAttribute(char[] genericSignature) { int localContentsOffset = this.contentsOffset; if (localContentsOffset + 8 >= this.contents.length) { resizeContents(8); } int signatureAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.SignatureName); this.contents[localContentsOffset++] = (byte) (signatureAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) signatureAttributeNameIndex; // the length of a signature attribute is equals to 2 this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 2; int signatureIndex = this.constantPool.literalIndex(genericSignature); this.contents[localContentsOffset++] = (byte) (signatureIndex >> 8); this.contents[localContentsOffset++] = (byte) signatureIndex; this.contentsOffset = localContentsOffset; return 1; } private int generateSourceAttribute(String fullFileName) { int localContentsOffset = this.contentsOffset; // check that there is enough space to write all the bytes for the field info corresponding // to the @fieldBinding if (localContentsOffset + 8 >= this.contents.length) { resizeContents(8); } int sourceAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.SourceName); this.contents[localContentsOffset++] = (byte) (sourceAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) sourceAttributeNameIndex; // The length of a source file attribute is 2. This is a fixed-length // attribute this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 2; // write the source file name int fileNameIndex = this.constantPool.literalIndex(fullFileName.toCharArray()); this.contents[localContentsOffset++] = (byte) (fileNameIndex >> 8); this.contents[localContentsOffset++] = (byte) fileNameIndex; this.contentsOffset = localContentsOffset; return 1; } private int generateStackMapAttribute( MethodBinding methodBinding, int code_length, int codeAttributeOffset, int max_locals, boolean isClinit, Scope scope) { int attributesNumber = 0; int localContentsOffset = this.contentsOffset; StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; stackMapFrameCodeStream.removeFramePosition(code_length); if (stackMapFrameCodeStream.hasFramePositions()) { Map frames = new HashMap(); List realFrames = traverse(isClinit ? null : methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit, scope); int numberOfFrames = realFrames.size(); if (numberOfFrames > 1) { int stackMapTableAttributeOffset = localContentsOffset; // add the stack map table attribute if (localContentsOffset + 8 >= this.contents.length) { resizeContents(8); } int stackMapAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.StackMapName); this.contents[localContentsOffset++] = (byte) (stackMapAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) stackMapAttributeNameIndex; int stackMapAttributeLengthOffset = localContentsOffset; // generate the attribute localContentsOffset += 4; if (localContentsOffset + 4 >= this.contents.length) { resizeContents(4); } int numberOfFramesOffset = localContentsOffset; localContentsOffset += 2; if (localContentsOffset + 2 >= this.contents.length) { resizeContents(2); } StackMapFrame currentFrame = (StackMapFrame) realFrames.get(0); for (int j = 1; j < numberOfFrames; j++) { // select next frame currentFrame = (StackMapFrame) realFrames.get(j); // generate current frame // need to find differences between the current frame and the previous frame int frameOffset = currentFrame.pc; // FULL_FRAME if (localContentsOffset + 5 >= this.contents.length) { resizeContents(5); } this.contents[localContentsOffset++] = (byte) (frameOffset >> 8); this.contents[localContentsOffset++] = (byte) frameOffset; int numberOfLocalOffset = localContentsOffset; localContentsOffset += 2; // leave two spots for number of locals int numberOfLocalEntries = 0; int numberOfLocals = currentFrame.getNumberOfLocals(); int numberOfEntries = 0; int localsLength = currentFrame.locals == null ? 0 : currentFrame.locals.length; for (int i = 0; i < localsLength && numberOfLocalEntries < numberOfLocals; i++) { if (localContentsOffset + 3 >= this.contents.length) { resizeContents(3); } VerificationTypeInfo info = currentFrame.locals[i]; if (info == null) { this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; } else { switch(info.id()) { case T_boolean : case T_byte : case T_char : case T_int : case T_short : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; break; case T_float : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; break; case T_long : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; i++; break; case T_double : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; i++; break; case T_null : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; break; default: this.contents[localContentsOffset++] = (byte) info.tag; switch (info.tag) { case VerificationTypeInfo.ITEM_UNINITIALIZED : int offset = info.offset; this.contents[localContentsOffset++] = (byte) (offset >> 8); this.contents[localContentsOffset++] = (byte) offset; break; case VerificationTypeInfo.ITEM_OBJECT : int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); this.contents[localContentsOffset++] = (byte) (indexForType >> 8); this.contents[localContentsOffset++] = (byte) indexForType; } } numberOfLocalEntries++; } numberOfEntries++; } if (localContentsOffset + 4 >= this.contents.length) { resizeContents(4); } this.contents[numberOfLocalOffset++] = (byte) (numberOfEntries >> 8); this.contents[numberOfLocalOffset] = (byte) numberOfEntries; int numberOfStackItems = currentFrame.numberOfStackItems; this.contents[localContentsOffset++] = (byte) (numberOfStackItems >> 8); this.contents[localContentsOffset++] = (byte) numberOfStackItems; for (int i = 0; i < numberOfStackItems; i++) { if (localContentsOffset + 3 >= this.contents.length) { resizeContents(3); } VerificationTypeInfo info = currentFrame.stackItems[i]; if (info == null) { this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; } else { switch(info.id()) { case T_boolean : case T_byte : case T_char : case T_int : case T_short : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; break; case T_float : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; break; case T_long : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; break; case T_double : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; break; case T_null : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; break; default: this.contents[localContentsOffset++] = (byte) info.tag; switch (info.tag) { case VerificationTypeInfo.ITEM_UNINITIALIZED : int offset = info.offset; this.contents[localContentsOffset++] = (byte) (offset >> 8); this.contents[localContentsOffset++] = (byte) offset; break; case VerificationTypeInfo.ITEM_OBJECT : int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); this.contents[localContentsOffset++] = (byte) (indexForType >> 8); this.contents[localContentsOffset++] = (byte) indexForType; } } } } } numberOfFrames--; if (numberOfFrames != 0) { this.contents[numberOfFramesOffset++] = (byte) (numberOfFrames >> 8); this.contents[numberOfFramesOffset] = (byte) numberOfFrames; int attributeLength = localContentsOffset - stackMapAttributeLengthOffset - 4; this.contents[stackMapAttributeLengthOffset++] = (byte) (attributeLength >> 24); this.contents[stackMapAttributeLengthOffset++] = (byte) (attributeLength >> 16); this.contents[stackMapAttributeLengthOffset++] = (byte) (attributeLength >> 8); this.contents[stackMapAttributeLengthOffset] = (byte) attributeLength; attributesNumber++; } else { localContentsOffset = stackMapTableAttributeOffset; } } } this.contentsOffset = localContentsOffset; return attributesNumber; } private int generateStackMapTableAttribute( MethodBinding methodBinding, int code_length, int codeAttributeOffset, int max_locals, boolean isClinit, Scope scope) { int attributesNumber = 0; int localContentsOffset = this.contentsOffset; StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; stackMapFrameCodeStream.removeFramePosition(code_length); if (stackMapFrameCodeStream.hasFramePositions()) { Map frames = new HashMap(); List realFrames = traverse(isClinit ? null: methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit, scope); int numberOfFrames = realFrames.size(); if (numberOfFrames > 1) { int stackMapTableAttributeOffset = localContentsOffset; // add the stack map table attribute if (localContentsOffset + 8 >= this.contents.length) { resizeContents(8); } int stackMapTableAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.StackMapTableName); this.contents[localContentsOffset++] = (byte) (stackMapTableAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) stackMapTableAttributeNameIndex; int stackMapTableAttributeLengthOffset = localContentsOffset; // generate the attribute localContentsOffset += 4; if (localContentsOffset + 4 >= this.contents.length) { resizeContents(4); } int numberOfFramesOffset = localContentsOffset; localContentsOffset += 2; if (localContentsOffset + 2 >= this.contents.length) { resizeContents(2); } StackMapFrame currentFrame = (StackMapFrame) realFrames.get(0); StackMapFrame prevFrame = null; for (int j = 1; j < numberOfFrames; j++) { // select next frame prevFrame = currentFrame; currentFrame = (StackMapFrame) realFrames.get(j); // generate current frame // need to find differences between the current frame and the previous frame int offsetDelta = currentFrame.getOffsetDelta(prevFrame); switch (currentFrame.getFrameType(prevFrame)) { case StackMapFrame.APPEND_FRAME : if (localContentsOffset + 3 >= this.contents.length) { resizeContents(3); } int numberOfDifferentLocals = currentFrame.numberOfDifferentLocals(prevFrame); this.contents[localContentsOffset++] = (byte) (251 + numberOfDifferentLocals); this.contents[localContentsOffset++] = (byte) (offsetDelta >> 8); this.contents[localContentsOffset++] = (byte) offsetDelta; int index = currentFrame.getIndexOfDifferentLocals(numberOfDifferentLocals); int numberOfLocals = currentFrame.getNumberOfLocals(); for (int i = index; i < currentFrame.locals.length && numberOfDifferentLocals > 0; i++) { if (localContentsOffset + 6 >= this.contents.length) { resizeContents(6); } VerificationTypeInfo info = currentFrame.locals[i]; if (info == null) { this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; } else { switch(info.id()) { case T_boolean : case T_byte : case T_char : case T_int : case T_short : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; break; case T_float : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; break; case T_long : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; i++; break; case T_double : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; i++; break; case T_null : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; break; default: this.contents[localContentsOffset++] = (byte) info.tag; switch (info.tag) { case VerificationTypeInfo.ITEM_UNINITIALIZED : int offset = info.offset; this.contents[localContentsOffset++] = (byte) (offset >> 8); this.contents[localContentsOffset++] = (byte) offset; break; case VerificationTypeInfo.ITEM_OBJECT : int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); this.contents[localContentsOffset++] = (byte) (indexForType >> 8); this.contents[localContentsOffset++] = (byte) indexForType; } } numberOfDifferentLocals--; } } break; case StackMapFrame.SAME_FRAME : if (localContentsOffset + 1 >= this.contents.length) { resizeContents(1); } this.contents[localContentsOffset++] = (byte) offsetDelta; break; case StackMapFrame.SAME_FRAME_EXTENDED : if (localContentsOffset + 3 >= this.contents.length) { resizeContents(3); } this.contents[localContentsOffset++] = (byte) 251; this.contents[localContentsOffset++] = (byte) (offsetDelta >> 8); this.contents[localContentsOffset++] = (byte) offsetDelta; break; case StackMapFrame.CHOP_FRAME : if (localContentsOffset + 3 >= this.contents.length) { resizeContents(3); } numberOfDifferentLocals = -currentFrame.numberOfDifferentLocals(prevFrame); this.contents[localContentsOffset++] = (byte) (251 - numberOfDifferentLocals); this.contents[localContentsOffset++] = (byte) (offsetDelta >> 8); this.contents[localContentsOffset++] = (byte) offsetDelta; break; case StackMapFrame.SAME_LOCALS_1_STACK_ITEMS : if (localContentsOffset + 4 >= this.contents.length) { resizeContents(4); } this.contents[localContentsOffset++] = (byte) (offsetDelta + 64); if (currentFrame.stackItems[0] == null) { this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; } else { switch(currentFrame.stackItems[0].id()) { case T_boolean : case T_byte : case T_char : case T_int : case T_short : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; break; case T_float : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; break; case T_long : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; break; case T_double : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; break; case T_null : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; break; default: VerificationTypeInfo info = currentFrame.stackItems[0]; byte tag = (byte) info.tag; this.contents[localContentsOffset++] = tag; switch (tag) { case VerificationTypeInfo.ITEM_UNINITIALIZED : int offset = info.offset; this.contents[localContentsOffset++] = (byte) (offset >> 8); this.contents[localContentsOffset++] = (byte) offset; break; case VerificationTypeInfo.ITEM_OBJECT : int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); this.contents[localContentsOffset++] = (byte) (indexForType >> 8); this.contents[localContentsOffset++] = (byte) indexForType; } } } break; case StackMapFrame.SAME_LOCALS_1_STACK_ITEMS_EXTENDED : if (localContentsOffset + 6 >= this.contents.length) { resizeContents(6); } this.contents[localContentsOffset++] = (byte) 247; this.contents[localContentsOffset++] = (byte) (offsetDelta >> 8); this.contents[localContentsOffset++] = (byte) offsetDelta; if (currentFrame.stackItems[0] == null) { this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; } else { switch(currentFrame.stackItems[0].id()) { case T_boolean : case T_byte : case T_char : case T_int : case T_short : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; break; case T_float : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; break; case T_long : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; break; case T_double : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; break; case T_null : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; break; default: VerificationTypeInfo info = currentFrame.stackItems[0]; byte tag = (byte) info.tag; this.contents[localContentsOffset++] = tag; switch (tag) { case VerificationTypeInfo.ITEM_UNINITIALIZED : int offset = info.offset; this.contents[localContentsOffset++] = (byte) (offset >> 8); this.contents[localContentsOffset++] = (byte) offset; break; case VerificationTypeInfo.ITEM_OBJECT : int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); this.contents[localContentsOffset++] = (byte) (indexForType >> 8); this.contents[localContentsOffset++] = (byte) indexForType; } } } break; default : // FULL_FRAME if (localContentsOffset + 5 >= this.contents.length) { resizeContents(5); } this.contents[localContentsOffset++] = (byte) 255; this.contents[localContentsOffset++] = (byte) (offsetDelta >> 8); this.contents[localContentsOffset++] = (byte) offsetDelta; int numberOfLocalOffset = localContentsOffset; localContentsOffset += 2; // leave two spots for number of locals int numberOfLocalEntries = 0; numberOfLocals = currentFrame.getNumberOfLocals(); int numberOfEntries = 0; int localsLength = currentFrame.locals == null ? 0 : currentFrame.locals.length; for (int i = 0; i < localsLength && numberOfLocalEntries < numberOfLocals; i++) { if (localContentsOffset + 3 >= this.contents.length) { resizeContents(3); } VerificationTypeInfo info = currentFrame.locals[i]; if (info == null) { this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; } else { switch(info.id()) { case T_boolean : case T_byte : case T_char : case T_int : case T_short : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; break; case T_float : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; break; case T_long : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; i++; break; case T_double : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; i++; break; case T_null : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; break; default: this.contents[localContentsOffset++] = (byte) info.tag; switch (info.tag) { case VerificationTypeInfo.ITEM_UNINITIALIZED : int offset = info.offset; this.contents[localContentsOffset++] = (byte) (offset >> 8); this.contents[localContentsOffset++] = (byte) offset; break; case VerificationTypeInfo.ITEM_OBJECT : int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); this.contents[localContentsOffset++] = (byte) (indexForType >> 8); this.contents[localContentsOffset++] = (byte) indexForType; } } numberOfLocalEntries++; } numberOfEntries++; } if (localContentsOffset + 4 >= this.contents.length) { resizeContents(4); } this.contents[numberOfLocalOffset++] = (byte) (numberOfEntries >> 8); this.contents[numberOfLocalOffset] = (byte) numberOfEntries; int numberOfStackItems = currentFrame.numberOfStackItems; this.contents[localContentsOffset++] = (byte) (numberOfStackItems >> 8); this.contents[localContentsOffset++] = (byte) numberOfStackItems; for (int i = 0; i < numberOfStackItems; i++) { if (localContentsOffset + 3 >= this.contents.length) { resizeContents(3); } VerificationTypeInfo info = currentFrame.stackItems[i]; if (info == null) { this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; } else { switch(info.id()) { case T_boolean : case T_byte : case T_char : case T_int : case T_short : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; break; case T_float : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; break; case T_long : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; break; case T_double : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; break; case T_null : this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; break; default: this.contents[localContentsOffset++] = (byte) info.tag; switch (info.tag) { case VerificationTypeInfo.ITEM_UNINITIALIZED : int offset = info.offset; this.contents[localContentsOffset++] = (byte) (offset >> 8); this.contents[localContentsOffset++] = (byte) offset; break; case VerificationTypeInfo.ITEM_OBJECT : int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); this.contents[localContentsOffset++] = (byte) (indexForType >> 8); this.contents[localContentsOffset++] = (byte) indexForType; } } } } } } numberOfFrames--; if (numberOfFrames != 0) { this.contents[numberOfFramesOffset++] = (byte) (numberOfFrames >> 8); this.contents[numberOfFramesOffset] = (byte) numberOfFrames; int attributeLength = localContentsOffset - stackMapTableAttributeLengthOffset - 4; this.contents[stackMapTableAttributeLengthOffset++] = (byte) (attributeLength >> 24); this.contents[stackMapTableAttributeLengthOffset++] = (byte) (attributeLength >> 16); this.contents[stackMapTableAttributeLengthOffset++] = (byte) (attributeLength >> 8); this.contents[stackMapTableAttributeLengthOffset] = (byte) attributeLength; attributesNumber++; } else { localContentsOffset = stackMapTableAttributeOffset; } } } this.contentsOffset = localContentsOffset; return attributesNumber; } private int generateSyntheticAttribute() { int localContentsOffset = this.contentsOffset; if (localContentsOffset + 6 >= this.contents.length) { resizeContents(6); } int syntheticAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.SyntheticName); this.contents[localContentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) syntheticAttributeNameIndex; // the length of a synthetic attribute is equals to 0 this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contentsOffset = localContentsOffset; return 1; } private void generateTypeAnnotation(AnnotationContext annotationContext, int currentOffset) { Annotation annotation = annotationContext.annotation.getPersistibleAnnotation(); if (annotation == null || annotation.resolvedType == null) return; int targetType = annotationContext.targetType; int[] locations = Annotation.getLocations( annotationContext.typeReference, annotationContext.annotation); if (this.contentsOffset + 5 >= this.contents.length) { resizeContents(5); } this.contents[this.contentsOffset++] = (byte) targetType; dumpTargetTypeContents(targetType, annotationContext); dumpLocations(locations); generateAnnotation(annotation, currentOffset); } private int generateTypeAnnotationAttributeForTypeDeclaration() { TypeDeclaration typeDeclaration = this.referenceBinding.scope.referenceContext; if ((typeDeclaration.bits & ASTNode.HasTypeAnnotations) == 0) { return 0; } int attributesNumber = 0; int visibleTypeAnnotationsCounter = 0; int invisibleTypeAnnotationsCounter = 0; TypeReference superclass = typeDeclaration.superclass; List allTypeAnnotationContexts = new ArrayList(); if (superclass != null && (superclass.bits & ASTNode.HasTypeAnnotations) != 0) { superclass.getAllAnnotationContexts(AnnotationTargetTypeConstants.CLASS_EXTENDS, -1, allTypeAnnotationContexts); } TypeReference[] superInterfaces = typeDeclaration.superInterfaces; if (superInterfaces != null) { for (int i = 0; i < superInterfaces.length; i++) { TypeReference superInterface = superInterfaces[i]; if ((superInterface.bits & ASTNode.HasTypeAnnotations) == 0) { continue; } superInterface.getAllAnnotationContexts(AnnotationTargetTypeConstants.CLASS_EXTENDS, i, allTypeAnnotationContexts); } } TypeParameter[] typeParameters = typeDeclaration.typeParameters; if (typeParameters != null) { for (int i = 0, max = typeParameters.length; i < max; i++) { TypeParameter typeParameter = typeParameters[i]; if ((typeParameter.bits & ASTNode.HasTypeAnnotations) != 0) { typeParameter.getAllAnnotationContexts(AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER, i, allTypeAnnotationContexts); } } } int size = allTypeAnnotationContexts.size(); if (size != 0) { AnnotationContext[] allTypeAnnotationContextsArray = new AnnotationContext[size]; allTypeAnnotationContexts.toArray(allTypeAnnotationContextsArray); for (int j = 0, max = allTypeAnnotationContextsArray.length; j < max; j++) { AnnotationContext annotationContext = allTypeAnnotationContextsArray[j]; if ((annotationContext.visibility & AnnotationContext.INVISIBLE) != 0) { invisibleTypeAnnotationsCounter++; allTypeAnnotationContexts.add(annotationContext); } else { visibleTypeAnnotationsCounter++; allTypeAnnotationContexts.add(annotationContext); } } attributesNumber += generateRuntimeTypeAnnotations( allTypeAnnotationContextsArray, visibleTypeAnnotationsCounter, invisibleTypeAnnotationsCounter); } return attributesNumber; } private int generateVarargsAttribute() { int localContentsOffset = this.contentsOffset; /* * handle of the target jsr14 for varargs in the source * Varargs attribute * Check that there is enough space to write the attribute */ if (localContentsOffset + 6 >= this.contents.length) { resizeContents(6); } int varargsAttributeNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.VarargsName); this.contents[localContentsOffset++] = (byte) (varargsAttributeNameIndex >> 8); this.contents[localContentsOffset++] = (byte) varargsAttributeNameIndex; // the length of a varargs attribute is equals to 0 this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contents[localContentsOffset++] = 0; this.contentsOffset = localContentsOffset; return 1; }
EXTERNAL API Answer the actual bytes of the class file This method encodes the receiver structure into a byte array which is the content of the classfile. Returns the byte array that represents the encoded structure of the receiver.
Returns:byte[]
/** * EXTERNAL API * Answer the actual bytes of the class file * * This method encodes the receiver structure into a byte array which is the content of the classfile. * Returns the byte array that represents the encoded structure of the receiver. * * @return byte[] */
public byte[] getBytes() { if (this.bytes == null) { this.bytes = new byte[this.headerOffset + this.contentsOffset]; System.arraycopy(this.header, 0, this.bytes, 0, this.headerOffset); System.arraycopy(this.contents, 0, this.bytes, this.headerOffset, this.contentsOffset); } return this.bytes; }
EXTERNAL API Answer the compound name of the class file.
Returns:char[][] e.g. {{java}, {util}, {Hashtable}}.
/** * EXTERNAL API * Answer the compound name of the class file. * @return char[][] * e.g. {{java}, {util}, {Hashtable}}. */
public char[][] getCompoundName() { return CharOperation.splitOn('/', fileName()); } private int getParametersCount(char[] methodSignature) { int i = CharOperation.indexOf('(', methodSignature); i++; char currentCharacter = methodSignature[i]; if (currentCharacter == ')') { return 0; } int result = 0; while (true) { currentCharacter = methodSignature[i]; if (currentCharacter == ')') { return result; } switch (currentCharacter) { case '[': // array type int scanType = scanType(methodSignature, i + 1); result++; i = scanType + 1; break; case 'L': scanType = CharOperation.indexOf(';', methodSignature, i + 1); result++; i = scanType + 1; break; case 'Z': case 'B': case 'C': case 'D': case 'F': case 'I': case 'J': case 'S': result++; i++; break; default: throw new IllegalArgumentException("Invalid starting type character : " + currentCharacter); //$NON-NLS-1$ } } } private char[] getReturnType(char[] methodSignature) { // skip type parameters int paren = CharOperation.lastIndexOf(')', methodSignature); // there could be thrown exceptions behind, thus scan one type exactly return CharOperation.subarray(methodSignature, paren + 1, methodSignature.length); } private final int i4At(byte[] reference, int relativeOffset, int structOffset) { int position = relativeOffset + structOffset; return ((reference[position++] & 0xFF) << 24) + ((reference[position++] & 0xFF) << 16) + ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF); } protected void initByteArrays(int members) { this.header = new byte[INITIAL_HEADER_SIZE]; this.contents = new byte[members < 15 ? INITIAL_CONTENTS_SIZE : INITIAL_HEADER_SIZE]; } private void initializeHeader(ClassFile parentClassFile, int accessFlags) { // generate the magic numbers inside the header this.header[this.headerOffset++] = (byte) (0xCAFEBABEL >> 24); this.header[this.headerOffset++] = (byte) (0xCAFEBABEL >> 16); this.header[this.headerOffset++] = (byte) (0xCAFEBABEL >> 8); this.header[this.headerOffset++] = (byte) (0xCAFEBABEL >> 0); long targetVersion = this.targetJDK; this.header[this.headerOffset++] = (byte) (targetVersion >> 8); // minor high this.header[this.headerOffset++] = (byte) (targetVersion>> 0); // minor low this.header[this.headerOffset++] = (byte) (targetVersion >> 24); // major high this.header[this.headerOffset++] = (byte) (targetVersion >> 16); // major low this.constantPoolOffset = this.headerOffset; this.headerOffset += 2; this.constantPool.initialize(this); this.enclosingClassFile = parentClassFile; // now we continue to generate the bytes inside the contents array this.contents[this.contentsOffset++] = (byte) (accessFlags >> 8); this.contents[this.contentsOffset++] = (byte) accessFlags; } public void initialize(SourceTypeBinding aType, ClassFile parentClassFile, boolean createProblemType) { // Modifier manipulations for classfile int accessFlags = aType.getAccessFlags(); if (aType.isPrivate()) { // rewrite private to non-public accessFlags &= ~ClassFileConstants.AccPublic; } if (aType.isProtected()) { // rewrite protected into public accessFlags |= ClassFileConstants.AccPublic; } // clear all bits that are illegal for a class or an interface accessFlags &= ~( ClassFileConstants.AccStrictfp | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative); // set the AccSuper flag (has to be done after clearing AccSynchronized - since same value) if (!aType.isInterface()) { // class or enum accessFlags |= ClassFileConstants.AccSuper; } if (aType.isAnonymousType()) { accessFlags &= ~ClassFileConstants.AccFinal; } int finalAbstract = ClassFileConstants.AccFinal | ClassFileConstants.AccAbstract; if ((accessFlags & finalAbstract) == finalAbstract) { accessFlags &= ~finalAbstract; } initializeHeader(parentClassFile, accessFlags); // innerclasses get their names computed at code gen time int classNameIndex = this.constantPool.literalIndexForType(aType); this.contents[this.contentsOffset++] = (byte) (classNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) classNameIndex; int superclassNameIndex; if (aType.isInterface()) { superclassNameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangObjectConstantPoolName); } else { if (aType.superclass != null) { if ((aType.superclass.tagBits & TagBits.HasMissingType) != 0) { superclassNameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangObjectConstantPoolName); } else { superclassNameIndex = this.constantPool.literalIndexForType(aType.superclass); } } else { superclassNameIndex = 0; } } this.contents[this.contentsOffset++] = (byte) (superclassNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) superclassNameIndex; ReferenceBinding[] superInterfacesBinding = aType.superInterfaces(); int interfacesCount = superInterfacesBinding.length; int interfacesCountPosition = this.contentsOffset; this.contentsOffset += 2; int interfaceCounter = 0; for (int i = 0; i < interfacesCount; i++) { ReferenceBinding binding = superInterfacesBinding[i]; if ((binding.tagBits & TagBits.HasMissingType) != 0) { continue; } interfaceCounter++; int interfaceIndex = this.constantPool.literalIndexForType(binding); this.contents[this.contentsOffset++] = (byte) (interfaceIndex >> 8); this.contents[this.contentsOffset++] = (byte) interfaceIndex; } this.contents[interfacesCountPosition++] = (byte) (interfaceCounter >> 8); this.contents[interfacesCountPosition] = (byte) interfaceCounter; this.creatingProblemType = createProblemType; // retrieve the enclosing one guaranteed to be the one matching the propagated flow info // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check) this.codeStream.maxFieldCount = aType.scope.outerMostClassScope().referenceType().maxFieldCount; } public void initializeForModule(ModuleBinding module) { initializeHeader(null, ClassFileConstants.AccModule); int classNameIndex = this.constantPool.literalIndexForType(TypeConstants.MODULE_INFO_NAME); this.contents[this.contentsOffset++] = (byte) (classNameIndex >> 8); this.contents[this.contentsOffset++] = (byte) classNameIndex; this.codeStream.maxFieldCount = 0; // superclass: this.contents[this.contentsOffset++] = 0; this.contents[this.contentsOffset++] = 0; // superInterfacesCount this.contents[this.contentsOffset++] = 0; this.contents[this.contentsOffset++] = 0; // fieldsCount this.contents[this.contentsOffset++] = 0; this.contents[this.contentsOffset++] = 0; // methodsCount this.contents[this.contentsOffset++] = 0; this.contents[this.contentsOffset++] = 0; } private void initializeDefaultLocals(StackMapFrame frame, MethodBinding methodBinding, int maxLocals, int codeLength) { if (maxLocals != 0) { int resolvedPosition = 0; // take into account enum constructor synthetic name+ordinal final boolean isConstructor = methodBinding.isConstructor(); if (isConstructor || !methodBinding.isStatic()) { LocalVariableBinding localVariableBinding = new LocalVariableBinding(ConstantPool.This, methodBinding.declaringClass, 0, false); localVariableBinding.resolvedPosition = 0; this.codeStream.record(localVariableBinding); localVariableBinding.recordInitializationStartPC(0); localVariableBinding.recordInitializationEndPC(codeLength); frame.putLocal(resolvedPosition, new VerificationTypeInfo( isConstructor ? VerificationTypeInfo.ITEM_UNINITIALIZED_THIS : VerificationTypeInfo.ITEM_OBJECT, methodBinding.declaringClass)); resolvedPosition++; } if (isConstructor) { if (methodBinding.declaringClass.isEnum()) { LocalVariableBinding localVariableBinding = new LocalVariableBinding(" name".toCharArray(), this.referenceBinding.scope.getJavaLangString(), 0, false); //$NON-NLS-1$ localVariableBinding.resolvedPosition = resolvedPosition; this.codeStream.record(localVariableBinding); localVariableBinding.recordInitializationStartPC(0); localVariableBinding.recordInitializationEndPC(codeLength); frame.putLocal(resolvedPosition, new VerificationTypeInfo(this.referenceBinding.scope.getJavaLangString())); resolvedPosition++; localVariableBinding = new LocalVariableBinding(" ordinal".toCharArray(), TypeBinding.INT, 0, false); //$NON-NLS-1$ localVariableBinding.resolvedPosition = resolvedPosition; this.codeStream.record(localVariableBinding); localVariableBinding.recordInitializationStartPC(0); localVariableBinding.recordInitializationEndPC(codeLength); frame.putLocal(resolvedPosition, new VerificationTypeInfo(TypeBinding.INT)); resolvedPosition++; } // take into account the synthetic parameters if (methodBinding.declaringClass.isNestedType()) { ReferenceBinding enclosingInstanceTypes[]; if ((enclosingInstanceTypes = methodBinding.declaringClass.syntheticEnclosingInstanceTypes()) != null) { for (int i = 0, max = enclosingInstanceTypes.length; i < max; i++) { // an enclosingInstanceType can only be a reference // binding. It cannot be // LongBinding or DoubleBinding LocalVariableBinding localVariableBinding = new LocalVariableBinding((" enclosingType" + i).toCharArray(), enclosingInstanceTypes[i], 0, false); //$NON-NLS-1$ localVariableBinding.resolvedPosition = resolvedPosition; this.codeStream.record(localVariableBinding); localVariableBinding.recordInitializationStartPC(0); localVariableBinding.recordInitializationEndPC(codeLength); frame.putLocal(resolvedPosition, new VerificationTypeInfo(enclosingInstanceTypes[i])); resolvedPosition++; } } TypeBinding[] arguments; if ((arguments = methodBinding.parameters) != null) { for (int i = 0, max = arguments.length; i < max; i++) { final TypeBinding typeBinding = arguments[i]; frame.putLocal(resolvedPosition, new VerificationTypeInfo(typeBinding)); switch (typeBinding.id) { case TypeIds.T_double: case TypeIds.T_long: resolvedPosition += 2; break; default: resolvedPosition++; } } } SyntheticArgumentBinding syntheticArguments[]; if ((syntheticArguments = methodBinding.declaringClass.syntheticOuterLocalVariables()) != null) { for (int i = 0, max = syntheticArguments.length; i < max; i++) { final TypeBinding typeBinding = syntheticArguments[i].type; LocalVariableBinding localVariableBinding = new LocalVariableBinding((" synthetic" + i).toCharArray(), typeBinding, 0, false); //$NON-NLS-1$ localVariableBinding.resolvedPosition = resolvedPosition; this.codeStream.record(localVariableBinding); localVariableBinding.recordInitializationStartPC(0); localVariableBinding.recordInitializationEndPC(codeLength); frame.putLocal(resolvedPosition, new VerificationTypeInfo(typeBinding)); switch (typeBinding.id) { case TypeIds.T_double: case TypeIds.T_long: resolvedPosition += 2; break; default: resolvedPosition++; } } } } else { TypeBinding[] arguments; if ((arguments = methodBinding.parameters) != null) { for (int i = 0, max = arguments.length; i < max; i++) { final TypeBinding typeBinding = arguments[i]; frame.putLocal(resolvedPosition, new VerificationTypeInfo(typeBinding)); switch (typeBinding.id) { case TypeIds.T_double: case TypeIds.T_long: resolvedPosition += 2; break; default: resolvedPosition++; } } } } } else { TypeBinding[] arguments; if ((arguments = methodBinding.parameters) != null) { for (int i = 0, max = arguments.length; i < max; i++) { final TypeBinding typeBinding = arguments[i]; // For the branching complexities in the generated $deserializeLambda$ we need the local variable LocalVariableBinding localVariableBinding = new LocalVariableBinding((" synthetic"+i).toCharArray(), typeBinding, 0, true); //$NON-NLS-1$ localVariableBinding.resolvedPosition = i; this.codeStream.record(localVariableBinding); localVariableBinding.recordInitializationStartPC(0); localVariableBinding.recordInitializationEndPC(codeLength); frame.putLocal(resolvedPosition, new VerificationTypeInfo(typeBinding)); switch (typeBinding.id) { case TypeIds.T_double: case TypeIds.T_long: resolvedPosition += 2; break; default: resolvedPosition++; } } } } } } private void initializeLocals(boolean isStatic, int currentPC, StackMapFrame currentFrame) { VerificationTypeInfo[] locals = currentFrame.locals; int localsLength = locals.length; int i = 0; if (!isStatic) { // we don't want to reset the first local if the method is not static i = 1; } for (; i < localsLength; i++) { locals[i] = null; } i = 0; locals: for (int max = this.codeStream.allLocalsCounter; i < max; i++) { LocalVariableBinding localVariable = this.codeStream.locals[i]; if (localVariable == null) continue; int resolvedPosition = localVariable.resolvedPosition; final TypeBinding localVariableTypeBinding = localVariable.type; inits: for (int j = 0; j < localVariable.initializationCount; j++) { int startPC = localVariable.initializationPCs[j << 1]; int endPC = localVariable.initializationPCs[(j << 1) + 1]; if (currentPC < startPC) { continue inits; } else if (currentPC < endPC) { // the current local is an active local if (currentFrame.locals[resolvedPosition] == null) { currentFrame.locals[resolvedPosition] = new VerificationTypeInfo( localVariableTypeBinding); } continue locals; } } } }
INTERNAL USE-ONLY Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name for all inner types of the receiver.
Returns:org.eclipse.jdt.internal.compiler.codegen.ClassFile
/** * INTERNAL USE-ONLY * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name * for all inner types of the receiver. * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile */
public ClassFile outerMostEnclosingClassFile() { ClassFile current = this; while (current.enclosingClassFile != null) current = current.enclosingClassFile; return current; } public void recordInnerClasses(TypeBinding binding) { recordInnerClasses(binding, false); } public void recordInnerClasses(TypeBinding binding, boolean onBottomForBug445231) { if (this.innerClassesBindings == null) { this.innerClassesBindings = new HashMap(INNER_CLASSES_SIZE); } ReferenceBinding innerClass = (ReferenceBinding) binding; this.innerClassesBindings.put(innerClass.erasure().unannotated(), onBottomForBug445231); // should not emit yet another inner class for Outer.@Inner Inner. ReferenceBinding enclosingType = innerClass.enclosingType(); while (enclosingType != null && enclosingType.isNestedType()) { this.innerClassesBindings.put(enclosingType.erasure().unannotated(), onBottomForBug445231); enclosingType = enclosingType.enclosingType(); } } public int recordBootstrapMethod(FunctionalExpression expression) { if (this.bootstrapMethods == null) { this.bootstrapMethods = new ArrayList(); } if (expression instanceof ReferenceExpression) { for (int i = 0; i < this.bootstrapMethods.size(); i++) { FunctionalExpression fexp = (FunctionalExpression) this.bootstrapMethods.get(i); if (fexp.binding == expression.binding && TypeBinding.equalsEquals(fexp.expectedType(), expression.expectedType())) return expression.bootstrapMethodNumber = i; } } this.bootstrapMethods.add(expression); // Record which bootstrap method was assigned to the expression return expression.bootstrapMethodNumber = this.bootstrapMethods.size() - 1; } public void reset(/*@Nullable*/SourceTypeBinding typeBinding, CompilerOptions options) { // the code stream is reinitialized for each method if (typeBinding != null) { this.referenceBinding = typeBinding; this.isNestedType = typeBinding.isNestedType(); } else { this.referenceBinding = null; this.isNestedType = false; } this.targetJDK = options.targetJDK; this.produceAttributes = options.produceDebugAttributes; if (this.targetJDK >= ClassFileConstants.JDK1_6) { this.produceAttributes |= ClassFileConstants.ATTR_STACK_MAP_TABLE; if (this.targetJDK >= ClassFileConstants.JDK1_8) { this.produceAttributes |= ClassFileConstants.ATTR_TYPE_ANNOTATION; if (!(this.codeStream instanceof TypeAnnotationCodeStream) && this.referenceBinding != null) this.codeStream = new TypeAnnotationCodeStream(this); if (options.produceMethodParameters) { this.produceAttributes |= ClassFileConstants.ATTR_METHOD_PARAMETERS; } } } else if (this.targetJDK == ClassFileConstants.CLDC_1_1) { this.targetJDK = ClassFileConstants.JDK1_1; // put back 45.3 this.produceAttributes |= ClassFileConstants.ATTR_STACK_MAP; } this.bytes = null; this.constantPool.reset(); this.codeStream.reset(this); this.constantPoolOffset = 0; this.contentsOffset = 0; this.creatingProblemType = false; this.enclosingClassFile = null; this.headerOffset = 0; this.methodCount = 0; this.methodCountOffset = 0; if (this.innerClassesBindings != null) { this.innerClassesBindings.clear(); } if (this.bootstrapMethods != null) { this.bootstrapMethods.clear(); } this.missingTypes = null; this.visitedTypes = null; }
Resize the pool contents
/** * Resize the pool contents */
private final void resizeContents(int minimalSize) { int length = this.contents.length; int toAdd = length; if (toAdd < minimalSize) toAdd = minimalSize; System.arraycopy(this.contents, 0, this.contents = new byte[length + toAdd], 0, length); } private VerificationTypeInfo retrieveLocal(int currentPC, int resolvedPosition) { for (int i = 0, max = this.codeStream.allLocalsCounter; i < max; i++) { LocalVariableBinding localVariable = this.codeStream.locals[i]; if (localVariable == null) continue; if (resolvedPosition == localVariable.resolvedPosition) { inits: for (int j = 0; j < localVariable.initializationCount; j++) { int startPC = localVariable.initializationPCs[j << 1]; int endPC = localVariable.initializationPCs[(j << 1) + 1]; if (currentPC < startPC) { continue inits; } else if (currentPC < endPC) { // the current local is an active local return new VerificationTypeInfo(localVariable.type); } } } } return null; } private int scanType(char[] methodSignature, int index) { switch (methodSignature[index]) { case '[': // array type return scanType(methodSignature, index + 1); case 'L': return CharOperation.indexOf(';', methodSignature, index + 1); case 'Z': case 'B': case 'C': case 'D': case 'F': case 'I': case 'J': case 'S': return index; default: throw newIllegalArgumentException(methodSignature, index); } } private static IllegalArgumentException newIllegalArgumentException(char[] string, int index) { return new IllegalArgumentException("\"" + String.valueOf(string) + "\" at " + index); //$NON-NLS-1$ //$NON-NLS-2$ }
INTERNAL USE-ONLY This methods leaves the space for method counts recording.
/** * INTERNAL USE-ONLY * This methods leaves the space for method counts recording. */
public void setForMethodInfos() { // leave some space for the methodCount this.methodCountOffset = this.contentsOffset; this.contentsOffset += 2; } private List filterFakeFrames(Set realJumpTargets, Map frames, int codeLength) { // no more frame to generate // filter out "fake" frames realJumpTargets.remove(Integer.valueOf(codeLength)); List result = new ArrayList(); for (Iterator iterator = realJumpTargets.iterator(); iterator.hasNext(); ) { Integer jumpTarget = (Integer) iterator.next(); StackMapFrame frame = (StackMapFrame) frames.get(jumpTarget); if (frame != null) { result.add(frame); } } Collections.sort(result, new Comparator() { @Override public int compare(Object o1, Object o2) { StackMapFrame frame = (StackMapFrame) o1; StackMapFrame frame2 = (StackMapFrame) o2; return frame.pc - frame2.pc; } }); return result; } private TypeBinding getTypeBinding(char[] typeConstantPoolName, Scope scope, boolean checkcast) { if (typeConstantPoolName.length == 1) { // base type switch(typeConstantPoolName[0]) { case 'Z': return TypeBinding.BOOLEAN; case 'B': return TypeBinding.BYTE; case 'C': return TypeBinding.CHAR; case 'D': return TypeBinding.DOUBLE; case 'F': return TypeBinding.FLOAT; case 'I': return TypeBinding.INT; case 'J': return TypeBinding.LONG; case 'S': return TypeBinding.SHORT; default: return null; } } else if (typeConstantPoolName[0] == '[') { int dimensions = getDimensions(typeConstantPoolName); if (typeConstantPoolName.length - dimensions == 1) { // array of base types TypeBinding baseType = null; switch(typeConstantPoolName[typeConstantPoolName.length - 1]) { case 'Z': baseType = TypeBinding.BOOLEAN; break; case 'B': baseType = TypeBinding.BYTE; break; case 'C': baseType = TypeBinding.CHAR; break; case 'D': baseType = TypeBinding.DOUBLE; break; case 'F': baseType = TypeBinding.FLOAT; break; case 'I': baseType = TypeBinding.INT; break; case 'J': baseType = TypeBinding.LONG; break; case 'S': baseType = TypeBinding.SHORT; break; case 'V': baseType = TypeBinding.VOID; } return scope.createArrayType(baseType, dimensions); } else { // array of object types char[] typeName = CharOperation.subarray(typeConstantPoolName, dimensions + 1, typeConstantPoolName.length - 1); TypeBinding type = (TypeBinding) scope.getTypeOrPackage(CharOperation.splitOn('/', typeName)); if (!type.isValidBinding()) { ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type; if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) { type = problemReferenceBinding.closestMatch(); } else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) { // check local inner types to see if this is a anonymous type Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet(); for (TypeBinding binding : innerTypeBindings) { if (CharOperation.equals(binding.constantPoolName(), typeName)) { type = binding; break; } } } } return scope.createArrayType(type, dimensions); } } else { char[] typeName = checkcast ? typeConstantPoolName : CharOperation.subarray(typeConstantPoolName, 1, typeConstantPoolName.length - 1); TypeBinding type = (TypeBinding) scope.getTypeOrPackage(CharOperation.splitOn('/', typeName)); if (!type.isValidBinding()) { ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type; if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) { type = problemReferenceBinding.closestMatch(); } else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) { // check local inner types to see if this is a anonymous type Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet(); for (TypeBinding binding : innerTypeBindings) { if (CharOperation.equals(binding.constantPoolName(), typeName)) { type = binding; break; } } } } return type; } } private TypeBinding getNewTypeBinding(char[] typeConstantPoolName, Scope scope) { char[] typeName = typeConstantPoolName; TypeBinding type = (TypeBinding) scope.getTypeOrPackage(CharOperation.splitOn('/', typeName)); if (!type.isValidBinding()) { ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type; if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) { type = problemReferenceBinding.closestMatch(); } else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) { // check local inner types to see if this is a anonymous type Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet(); for (TypeBinding binding : innerTypeBindings) { if (CharOperation.equals(binding.constantPoolName(), typeName)) { type = binding; break; } } } } return type; } private TypeBinding getANewArrayTypeBinding(char[] typeConstantPoolName, Scope scope) { if (typeConstantPoolName[0] == '[') { int dimensions = getDimensions(typeConstantPoolName); if (typeConstantPoolName.length - dimensions == 1) { // array of base types TypeBinding baseType = null; switch(typeConstantPoolName[typeConstantPoolName.length - 1]) { case 'Z': baseType = TypeBinding.BOOLEAN; break; case 'B': baseType = TypeBinding.BYTE; break; case 'C': baseType = TypeBinding.CHAR; break; case 'D': baseType = TypeBinding.DOUBLE; break; case 'F': baseType = TypeBinding.FLOAT; break; case 'I': baseType = TypeBinding.INT; break; case 'J': baseType = TypeBinding.LONG; break; case 'S': baseType = TypeBinding.SHORT; break; case 'V': baseType = TypeBinding.VOID; } return scope.createArrayType(baseType, dimensions); } else { // array of object types char[] elementTypeClassName = CharOperation.subarray(typeConstantPoolName, dimensions + 1, typeConstantPoolName.length - 1); TypeBinding type = (TypeBinding) scope.getTypeOrPackage( CharOperation.splitOn('/', elementTypeClassName)); if (!type.isValidBinding()) { ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type; if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) { type = problemReferenceBinding.closestMatch(); } else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) { // check local inner types to see if this is a anonymous type Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet(); for (TypeBinding binding : innerTypeBindings) { if (CharOperation.equals(binding.constantPoolName(), elementTypeClassName)) { type = binding; break; } } } } return scope.createArrayType(type, dimensions); } } else { TypeBinding type = (TypeBinding) scope.getTypeOrPackage( CharOperation.splitOn('/', typeConstantPoolName)); if (!type.isValidBinding()) { ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type; if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) { type = problemReferenceBinding.closestMatch(); } else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) { // check local inner types to see if this is a anonymous type Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet(); for (TypeBinding binding : innerTypeBindings) { if (CharOperation.equals(binding.constantPoolName(), typeConstantPoolName)) { type = binding; break; } } } } return type; } } public List traverse( MethodBinding methodBinding, int maxLocals, byte[] bytecodes, int codeOffset, int codeLength, Map<Integer, StackMapFrame> frames, boolean isClinit, Scope scope) { Set realJumpTarget = new HashSet(); StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; int[] framePositions = stackMapFrameCodeStream.getFramePositions(); int pc = codeOffset; int index; int[] constantPoolOffsets = this.constantPool.offsets; byte[] poolContents = this.constantPool.poolContent; // set initial values for frame positions int indexInFramePositions = 0; int framePositionsLength = framePositions.length; int currentFramePosition = framePositions[0]; // set initial values for exception markers int indexInExceptionMarkers = 0; ExceptionMarker[] exceptionMarkers= stackMapFrameCodeStream.getExceptionMarkers(); int exceptionsMarkersLength = exceptionMarkers == null ? 0 : exceptionMarkers.length; boolean hasExceptionMarkers = exceptionsMarkersLength != 0; ExceptionMarker exceptionMarker = null; if (hasExceptionMarkers) { exceptionMarker = exceptionMarkers[0]; } StackMapFrame frame = new StackMapFrame(maxLocals); if (!isClinit) { initializeDefaultLocals(frame, methodBinding, maxLocals, codeLength); } frame.pc = -1; add(frames, frame.duplicate(), scope); addRealJumpTarget(realJumpTarget, -1); for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { ExceptionLabel exceptionLabel = this.codeStream.exceptionLabels[i]; if (exceptionLabel != null) { addRealJumpTarget(realJumpTarget, exceptionLabel.position); } } while (true) { int currentPC = pc - codeOffset; if (hasExceptionMarkers && exceptionMarker.pc == currentPC) { frame.numberOfStackItems = 0; frame.addStackItem(new VerificationTypeInfo(exceptionMarker.getBinding())); indexInExceptionMarkers++; if (indexInExceptionMarkers < exceptionsMarkersLength) { exceptionMarker = exceptionMarkers[indexInExceptionMarkers]; } else { hasExceptionMarkers = false; } } if (currentFramePosition < currentPC) { do { indexInFramePositions++; if (indexInFramePositions < framePositionsLength) { currentFramePosition = framePositions[indexInFramePositions]; } else { currentFramePosition = Integer.MAX_VALUE; } } while (currentFramePosition < currentPC); } if (currentFramePosition == currentPC) { // need to build a new frame and create a stack map attribute entry StackMapFrame currentFrame = frames.get(Integer.valueOf(currentPC)); if (currentFrame == null) { currentFrame = createNewFrame(currentPC, frame, isClinit, methodBinding); add(frames, currentFrame, scope); } else { frame = currentFrame.merge(frame.duplicate(), scope).duplicate(); } indexInFramePositions++; if (indexInFramePositions < framePositionsLength) { currentFramePosition = framePositions[indexInFramePositions]; } else { currentFramePosition = Integer.MAX_VALUE; } } byte opcode = (byte) u1At(bytecodes, 0, pc); switch (opcode) { case Opcodes.OPC_nop: pc++; break; case Opcodes.OPC_aconst_null: frame.addStackItem(new VerificationTypeInfo(TypeBinding.NULL)); pc++; break; case Opcodes.OPC_iconst_m1: case Opcodes.OPC_iconst_0: case Opcodes.OPC_iconst_1: case Opcodes.OPC_iconst_2: case Opcodes.OPC_iconst_3: case Opcodes.OPC_iconst_4: case Opcodes.OPC_iconst_5: frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); pc++; break; case Opcodes.OPC_lconst_0: case Opcodes.OPC_lconst_1: frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); pc++; break; case Opcodes.OPC_fconst_0: case Opcodes.OPC_fconst_1: case Opcodes.OPC_fconst_2: frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); pc++; break; case Opcodes.OPC_dconst_0: case Opcodes.OPC_dconst_1: frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); pc++; break; case Opcodes.OPC_bipush: frame.addStackItem(new VerificationTypeInfo(TypeBinding.BYTE)); pc += 2; break; case Opcodes.OPC_sipush: frame.addStackItem(new VerificationTypeInfo(TypeBinding.SHORT)); pc += 3; break; case Opcodes.OPC_ldc: index = u1At(bytecodes, 1, pc); switch (u1At(poolContents, 0, constantPoolOffsets[index])) { case ClassFileConstants.StringTag: frame .addStackItem(new VerificationTypeInfo(scope.getJavaLangString())); break; case ClassFileConstants.IntegerTag: frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); break; case ClassFileConstants.FloatTag: frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); break; case ClassFileConstants.ClassTag: frame.addStackItem(new VerificationTypeInfo(scope.getJavaLangClass())); } pc += 2; break; case Opcodes.OPC_ldc_w: index = u2At(bytecodes, 1, pc); switch (u1At(poolContents, 0, constantPoolOffsets[index])) { case ClassFileConstants.StringTag: frame .addStackItem(new VerificationTypeInfo(scope.getJavaLangString())); break; case ClassFileConstants.IntegerTag: frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); break; case ClassFileConstants.FloatTag: frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); break; case ClassFileConstants.ClassTag: frame.addStackItem(new VerificationTypeInfo(scope.getJavaLangClass())); } pc += 3; break; case Opcodes.OPC_ldc2_w: index = u2At(bytecodes, 1, pc); switch (u1At(poolContents, 0, constantPoolOffsets[index])) { case ClassFileConstants.DoubleTag: frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); break; case ClassFileConstants.LongTag: frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); break; } pc += 3; break; case Opcodes.OPC_iload: frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); pc += 2; break; case Opcodes.OPC_lload: frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); pc += 2; break; case Opcodes.OPC_fload: frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); pc += 2; break; case Opcodes.OPC_dload: frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); pc += 2; break; case Opcodes.OPC_aload: index = u1At(bytecodes, 1, pc); VerificationTypeInfo localsN = retrieveLocal(currentPC, index); frame.addStackItem(localsN); pc += 2; break; case Opcodes.OPC_iload_0: case Opcodes.OPC_iload_1: case Opcodes.OPC_iload_2: case Opcodes.OPC_iload_3: frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); pc++; break; case Opcodes.OPC_lload_0: case Opcodes.OPC_lload_1: case Opcodes.OPC_lload_2: case Opcodes.OPC_lload_3: frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); pc++; break; case Opcodes.OPC_fload_0: case Opcodes.OPC_fload_1: case Opcodes.OPC_fload_2: case Opcodes.OPC_fload_3: frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); pc++; break; case Opcodes.OPC_dload_0: case Opcodes.OPC_dload_1: case Opcodes.OPC_dload_2: case Opcodes.OPC_dload_3: frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); pc++; break; case Opcodes.OPC_aload_0: VerificationTypeInfo locals0 = frame.locals[0]; if (locals0 == null || locals0.tag != VerificationTypeInfo.ITEM_UNINITIALIZED_THIS) { // special case to handle uninitialized object locals0 = retrieveLocal(currentPC, 0); } frame.addStackItem(locals0); pc++; break; case Opcodes.OPC_aload_1: VerificationTypeInfo locals1 = retrieveLocal(currentPC, 1); frame.addStackItem(locals1); pc++; break; case Opcodes.OPC_aload_2: VerificationTypeInfo locals2 = retrieveLocal(currentPC, 2); frame.addStackItem(locals2); pc++; break; case Opcodes.OPC_aload_3: VerificationTypeInfo locals3 = retrieveLocal(currentPC, 3); frame.addStackItem(locals3); pc++; break; case Opcodes.OPC_iaload: frame.numberOfStackItems -=2; frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); pc++; break; case Opcodes.OPC_laload: frame.numberOfStackItems -=2; frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); pc++; break; case Opcodes.OPC_faload: frame.numberOfStackItems -=2; frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); pc++; break; case Opcodes.OPC_daload: frame.numberOfStackItems -=2; frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); pc++; break; case Opcodes.OPC_aaload: frame.numberOfStackItems--; frame.replaceWithElementType(); pc++; break; case Opcodes.OPC_baload: frame.numberOfStackItems -=2; frame.addStackItem(new VerificationTypeInfo(TypeBinding.BYTE)); pc++; break; case Opcodes.OPC_caload: frame.numberOfStackItems -=2; frame.addStackItem(new VerificationTypeInfo(TypeBinding.CHAR)); pc++; break; case Opcodes.OPC_saload: frame.numberOfStackItems -=2; frame.addStackItem(new VerificationTypeInfo(TypeBinding.SHORT)); pc++; break; case Opcodes.OPC_istore: case Opcodes.OPC_lstore: case Opcodes.OPC_fstore: case Opcodes.OPC_dstore: frame.numberOfStackItems--; pc += 2; break; case Opcodes.OPC_astore: index = u1At(bytecodes, 1, pc); frame.numberOfStackItems--; pc += 2; break; case Opcodes.OPC_astore_0: frame.locals[0] = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; pc++; break; case Opcodes.OPC_astore_1: case Opcodes.OPC_astore_2: case Opcodes.OPC_astore_3: case Opcodes.OPC_istore_0: case Opcodes.OPC_istore_1: case Opcodes.OPC_istore_2: case Opcodes.OPC_istore_3: case Opcodes.OPC_lstore_0: case Opcodes.OPC_lstore_1: case Opcodes.OPC_lstore_2: case Opcodes.OPC_lstore_3: case Opcodes.OPC_fstore_0: case Opcodes.OPC_fstore_1: case Opcodes.OPC_fstore_2: case Opcodes.OPC_fstore_3: case Opcodes.OPC_dstore_0: case Opcodes.OPC_dstore_1: case Opcodes.OPC_dstore_2: case Opcodes.OPC_dstore_3: frame.numberOfStackItems--; pc++; break; case Opcodes.OPC_iastore: case Opcodes.OPC_lastore: case Opcodes.OPC_fastore: case Opcodes.OPC_dastore: case Opcodes.OPC_aastore: case Opcodes.OPC_bastore: case Opcodes.OPC_castore: case Opcodes.OPC_sastore: frame.numberOfStackItems-=3; pc++; break; case Opcodes.OPC_pop: frame.numberOfStackItems--; pc++; break; case Opcodes.OPC_pop2: int numberOfStackItems = frame.numberOfStackItems; switch(frame.stackItems[numberOfStackItems - 1].id()) { case TypeIds.T_long : case TypeIds.T_double : frame.numberOfStackItems--; break; default: frame.numberOfStackItems -= 2; } pc++; break; case Opcodes.OPC_dup: frame.addStackItem(frame.stackItems[frame.numberOfStackItems - 1]); pc++; break; case Opcodes.OPC_dup_x1: VerificationTypeInfo info = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; VerificationTypeInfo info2 = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; frame.addStackItem(info); frame.addStackItem(info2); frame.addStackItem(info); pc++; break; case Opcodes.OPC_dup_x2: info = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; info2 = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; switch(info2.id()) { case TypeIds.T_long : case TypeIds.T_double : frame.addStackItem(info); frame.addStackItem(info2); frame.addStackItem(info); break; default: numberOfStackItems = frame.numberOfStackItems; VerificationTypeInfo info3 = frame.stackItems[numberOfStackItems - 1]; frame.numberOfStackItems--; frame.addStackItem(info); frame.addStackItem(info3); frame.addStackItem(info2); frame.addStackItem(info); } pc++; break; case Opcodes.OPC_dup2: info = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; switch(info.id()) { case TypeIds.T_double : case TypeIds.T_long : frame.addStackItem(info); frame.addStackItem(info); break; default: info2 = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; frame.addStackItem(info2); frame.addStackItem(info); frame.addStackItem(info2); frame.addStackItem(info); } pc++; break; case Opcodes.OPC_dup2_x1: info = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; info2 = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; switch(info.id()) { case TypeIds.T_double : case TypeIds.T_long : frame.addStackItem(info); frame.addStackItem(info2); frame.addStackItem(info); break; default: VerificationTypeInfo info3 = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; frame.addStackItem(info2); frame.addStackItem(info); frame.addStackItem(info3); frame.addStackItem(info2); frame.addStackItem(info); } pc++; break; case Opcodes.OPC_dup2_x2: numberOfStackItems = frame.numberOfStackItems; info = frame.stackItems[numberOfStackItems - 1]; frame.numberOfStackItems--; info2 = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; switch(info.id()) { case TypeIds.T_long : case TypeIds.T_double : switch(info2.id()) { case TypeIds.T_long : case TypeIds.T_double : // form 4 frame.addStackItem(info); frame.addStackItem(info2); frame.addStackItem(info); break; default: // form 2 numberOfStackItems = frame.numberOfStackItems; VerificationTypeInfo info3 = frame.stackItems[numberOfStackItems - 1]; frame.numberOfStackItems--; frame.addStackItem(info); frame.addStackItem(info3); frame.addStackItem(info2); frame.addStackItem(info); } break; default: numberOfStackItems = frame.numberOfStackItems; VerificationTypeInfo info3 = frame.stackItems[numberOfStackItems - 1]; frame.numberOfStackItems--; switch(info3.id()) { case TypeIds.T_long : case TypeIds.T_double : // form 3 frame.addStackItem(info2); frame.addStackItem(info); frame.addStackItem(info3); frame.addStackItem(info2); frame.addStackItem(info); break; default: // form 1 numberOfStackItems = frame.numberOfStackItems; VerificationTypeInfo info4 = frame.stackItems[numberOfStackItems - 1]; frame.numberOfStackItems--; frame.addStackItem(info2); frame.addStackItem(info); frame.addStackItem(info4); frame.addStackItem(info3); frame.addStackItem(info2); frame.addStackItem(info); } } pc++; break; case Opcodes.OPC_swap: numberOfStackItems = frame.numberOfStackItems; info = frame.stackItems[numberOfStackItems - 1]; info2 = frame.stackItems[numberOfStackItems - 2]; frame.stackItems[numberOfStackItems - 1] = info2; frame.stackItems[numberOfStackItems - 2] = info; pc++; break; case Opcodes.OPC_iadd: case Opcodes.OPC_ladd: case Opcodes.OPC_fadd: case Opcodes.OPC_dadd: case Opcodes.OPC_isub: case Opcodes.OPC_lsub: case Opcodes.OPC_fsub: case Opcodes.OPC_dsub: case Opcodes.OPC_imul: case Opcodes.OPC_lmul: case Opcodes.OPC_fmul: case Opcodes.OPC_dmul: case Opcodes.OPC_idiv: case Opcodes.OPC_ldiv: case Opcodes.OPC_fdiv: case Opcodes.OPC_ddiv: case Opcodes.OPC_irem: case Opcodes.OPC_lrem: case Opcodes.OPC_frem: case Opcodes.OPC_drem: case Opcodes.OPC_ishl: case Opcodes.OPC_lshl: case Opcodes.OPC_ishr: case Opcodes.OPC_lshr: case Opcodes.OPC_iushr: case Opcodes.OPC_lushr: case Opcodes.OPC_iand: case Opcodes.OPC_land: case Opcodes.OPC_ior: case Opcodes.OPC_lor: case Opcodes.OPC_ixor: case Opcodes.OPC_lxor: frame.numberOfStackItems--; pc++; break; case Opcodes.OPC_ineg: case Opcodes.OPC_lneg: case Opcodes.OPC_fneg: case Opcodes.OPC_dneg: pc++; break; case Opcodes.OPC_iinc: pc += 3; break; case Opcodes.OPC_i2l: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.LONG); pc++; break; case Opcodes.OPC_i2f: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.FLOAT); pc++; break; case Opcodes.OPC_i2d: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.DOUBLE); pc++; break; case Opcodes.OPC_l2i: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.INT); pc++; break; case Opcodes.OPC_l2f: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.FLOAT); pc++; break; case Opcodes.OPC_l2d: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.DOUBLE); pc++; break; case Opcodes.OPC_f2i: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.INT); pc++; break; case Opcodes.OPC_f2l: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.LONG); pc++; break; case Opcodes.OPC_f2d: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.DOUBLE); pc++; break; case Opcodes.OPC_d2i: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.INT); pc++; break; case Opcodes.OPC_d2l: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.LONG); pc++; break; case Opcodes.OPC_d2f: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.FLOAT); pc++; break; case Opcodes.OPC_i2b: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.BYTE); pc++; break; case Opcodes.OPC_i2c: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.CHAR); pc++; break; case Opcodes.OPC_i2s: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.SHORT); pc++; break; case Opcodes.OPC_lcmp: case Opcodes.OPC_fcmpl: case Opcodes.OPC_fcmpg: case Opcodes.OPC_dcmpl: case Opcodes.OPC_dcmpg: frame.numberOfStackItems-=2; frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); pc++; break; case Opcodes.OPC_ifeq: case Opcodes.OPC_ifne: case Opcodes.OPC_iflt: case Opcodes.OPC_ifge: case Opcodes.OPC_ifgt: case Opcodes.OPC_ifle: frame.numberOfStackItems--; int jumpPC = currentPC + i2At(bytecodes, 1, pc); addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); pc += 3; break; case Opcodes.OPC_if_icmpeq: case Opcodes.OPC_if_icmpne: case Opcodes.OPC_if_icmplt: case Opcodes.OPC_if_icmpge: case Opcodes.OPC_if_icmpgt: case Opcodes.OPC_if_icmple: case Opcodes.OPC_if_acmpeq: case Opcodes.OPC_if_acmpne: frame.numberOfStackItems -= 2; jumpPC = currentPC + i2At(bytecodes, 1, pc); addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); pc += 3; break; case Opcodes.OPC_goto: jumpPC = currentPC + i2At(bytecodes, 1, pc); addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); pc += 3; addRealJumpTarget(realJumpTarget, pc - codeOffset); break; case Opcodes.OPC_tableswitch: frame.numberOfStackItems--; pc++; while (((pc - codeOffset) & 0x03) != 0) { pc++; } // default offset jumpPC = currentPC + i4At(bytecodes, 0, pc); addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); pc += 4; // default int low = i4At(bytecodes, 0, pc); pc += 4; int high = i4At(bytecodes, 0, pc); pc += 4; int length = high - low + 1; for (int i = 0; i < length; i++) { // pair offset jumpPC = currentPC + i4At(bytecodes, 0, pc); addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); pc += 4; } break; case Opcodes.OPC_lookupswitch: frame.numberOfStackItems--; pc++; while (((pc - codeOffset) & 0x03) != 0) { pc++; } jumpPC = currentPC + i4At(bytecodes, 0, pc); addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); pc += 4; // default offset int npairs = (int) u4At(bytecodes, 0, pc); pc += 4; // npair value for (int i = 0; i < npairs; i++) { pc += 4; // case value // pair offset jumpPC = currentPC + i4At(bytecodes, 0, pc); addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); pc += 4; } break; case Opcodes.OPC_ireturn: case Opcodes.OPC_lreturn: case Opcodes.OPC_freturn: case Opcodes.OPC_dreturn: case Opcodes.OPC_areturn: frame.numberOfStackItems--; pc++; addRealJumpTarget(realJumpTarget, pc - codeOffset); break; case Opcodes.OPC_return: pc++; addRealJumpTarget(realJumpTarget, pc - codeOffset); break; case Opcodes.OPC_getstatic: index = u2At(bytecodes, 1, pc); int nameAndTypeIndex = u2At(poolContents, 3, constantPoolOffsets[index]); int utf8index = u2At(poolContents, 3, constantPoolOffsets[nameAndTypeIndex]); char[] descriptor = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); TypeBinding typeBinding = getTypeBinding(descriptor, scope, false); if (typeBinding != null) { frame.addStackItem(new VerificationTypeInfo(typeBinding)); } pc += 3; break; case Opcodes.OPC_putstatic: frame.numberOfStackItems--; pc += 3; break; case Opcodes.OPC_getfield: index = u2At(bytecodes, 1, pc); nameAndTypeIndex = u2At(poolContents, 3, constantPoolOffsets[index]); utf8index = u2At(poolContents, 3, constantPoolOffsets[nameAndTypeIndex]); descriptor = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); frame.numberOfStackItems--; typeBinding = getTypeBinding(descriptor, scope, false); if (typeBinding != null) { frame.addStackItem(new VerificationTypeInfo(typeBinding)); } pc += 3; break; case Opcodes.OPC_putfield: frame.numberOfStackItems -= 2; pc += 3; break; case Opcodes.OPC_invokevirtual: index = u2At(bytecodes, 1, pc); nameAndTypeIndex = u2At(poolContents, 3, constantPoolOffsets[index]); utf8index = u2At(poolContents, 3, constantPoolOffsets[nameAndTypeIndex]); descriptor = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); utf8index = u2At(poolContents, 1, constantPoolOffsets[nameAndTypeIndex]); char[] name = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); frame.numberOfStackItems -= (getParametersCount(descriptor) + 1); char[] returnType = getReturnType(descriptor); typeBinding = getTypeBinding(returnType, scope, false); if (typeBinding != null) { frame.addStackItem(new VerificationTypeInfo(typeBinding)); } pc += 3; break; case Opcodes.OPC_invokedynamic: index = u2At(bytecodes, 1, pc); nameAndTypeIndex = u2At(poolContents, 3, constantPoolOffsets[index]); utf8index = u2At(poolContents, 3, constantPoolOffsets[nameAndTypeIndex]); descriptor = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); frame.numberOfStackItems -= getParametersCount(descriptor); returnType = getReturnType(descriptor); typeBinding = getTypeBinding(returnType, scope, false); if (typeBinding != null) { frame.addStackItem(new VerificationTypeInfo(typeBinding)); } pc += 5; break; case Opcodes.OPC_invokespecial: index = u2At(bytecodes, 1, pc); nameAndTypeIndex = u2At(poolContents, 3, constantPoolOffsets[index]); utf8index = u2At(poolContents, 3, constantPoolOffsets[nameAndTypeIndex]); descriptor = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); utf8index = u2At(poolContents, 1, constantPoolOffsets[nameAndTypeIndex]); name = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); frame.numberOfStackItems -= getParametersCount(descriptor); if (CharOperation.equals(ConstantPool.Init, name)) { // constructor frame.stackItems[frame.numberOfStackItems - 1].tag = VerificationTypeInfo.ITEM_OBJECT; } frame.numberOfStackItems--; returnType = getReturnType(descriptor); typeBinding = getTypeBinding(returnType, scope, false); if (typeBinding != null) { frame.addStackItem(new VerificationTypeInfo(typeBinding)); } pc += 3; break; case Opcodes.OPC_invokestatic: index = u2At(bytecodes, 1, pc); nameAndTypeIndex = u2At(poolContents, 3, constantPoolOffsets[index]); utf8index = u2At(poolContents, 3, constantPoolOffsets[nameAndTypeIndex]); descriptor = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); utf8index = u2At(poolContents, 1, constantPoolOffsets[nameAndTypeIndex]); name = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); frame.numberOfStackItems -= getParametersCount(descriptor); returnType = getReturnType(descriptor); typeBinding = getTypeBinding(returnType, scope, false); if (typeBinding != null) { frame.addStackItem(new VerificationTypeInfo(typeBinding)); } pc += 3; break; case Opcodes.OPC_invokeinterface: index = u2At(bytecodes, 1, pc); nameAndTypeIndex = u2At(poolContents, 3, constantPoolOffsets[index]); utf8index = u2At(poolContents, 3, constantPoolOffsets[nameAndTypeIndex]); descriptor = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); utf8index = u2At(poolContents, 1, constantPoolOffsets[nameAndTypeIndex]); name = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); // we don't need count and args // u1At(bytecodes, 3, pc); // count // u1At(bytecodes, 4, pc); // extra args frame.numberOfStackItems -= (getParametersCount(descriptor) + 1); returnType = getReturnType(descriptor); typeBinding = getTypeBinding(returnType, scope, false); if (typeBinding != null) { frame.addStackItem(new VerificationTypeInfo(typeBinding)); } pc += 5; break; case Opcodes.OPC_new: index = u2At(bytecodes, 1, pc); utf8index = u2At(poolContents, 1, constantPoolOffsets[index]); char[] className = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); typeBinding = getNewTypeBinding(className, scope); VerificationTypeInfo verificationTypeInfo = new VerificationTypeInfo(VerificationTypeInfo.ITEM_UNINITIALIZED, typeBinding); verificationTypeInfo.offset = currentPC; frame.addStackItem(verificationTypeInfo); pc += 3; break; case Opcodes.OPC_newarray: TypeBinding arrayType = null; switch (u1At(bytecodes, 1, pc)) { case ClassFileConstants.INT_ARRAY : arrayType = scope.createArrayType(TypeBinding.INT, 1); break; case ClassFileConstants.BYTE_ARRAY : arrayType = scope.createArrayType(TypeBinding.BYTE, 1); break; case ClassFileConstants.BOOLEAN_ARRAY : arrayType = scope.createArrayType(TypeBinding.BOOLEAN, 1); break; case ClassFileConstants.SHORT_ARRAY : arrayType = scope.createArrayType(TypeBinding.SHORT, 1); break; case ClassFileConstants.CHAR_ARRAY : arrayType = scope.createArrayType(TypeBinding.CHAR, 1); break; case ClassFileConstants.LONG_ARRAY : arrayType = scope.createArrayType(TypeBinding.LONG, 1); break; case ClassFileConstants.FLOAT_ARRAY : arrayType = scope.createArrayType(TypeBinding.FLOAT, 1); break; case ClassFileConstants.DOUBLE_ARRAY : arrayType = scope.createArrayType(TypeBinding.DOUBLE, 1); break; } frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(arrayType); pc += 2; break; case Opcodes.OPC_anewarray: index = u2At(bytecodes, 1, pc); utf8index = u2At(poolContents, 1, constantPoolOffsets[index]); className = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); frame.numberOfStackItems--; typeBinding = getANewArrayTypeBinding(className, scope); if (typeBinding != null) { if (typeBinding.isArrayType()) { ArrayBinding arrayBinding = (ArrayBinding) typeBinding; frame.addStackItem(new VerificationTypeInfo(scope.createArrayType(arrayBinding.leafComponentType(), arrayBinding.dimensions + 1))); } else { frame.addStackItem(new VerificationTypeInfo(scope.createArrayType(typeBinding, 1))); } } pc += 3; break; case Opcodes.OPC_arraylength: frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.INT); pc++; break; case Opcodes.OPC_athrow: frame.numberOfStackItems--; pc++; addRealJumpTarget(realJumpTarget, pc - codeOffset); break; case Opcodes.OPC_checkcast: index = u2At(bytecodes, 1, pc); utf8index = u2At(poolContents, 1, constantPoolOffsets[index]); className = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); typeBinding = getTypeBinding(className, scope, true); if (typeBinding != null) { frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(typeBinding); } pc += 3; break; case Opcodes.OPC_instanceof: // no need to know the class index = u2At(bytecodes, 1, pc); frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.INT); pc += 3; break; case Opcodes.OPC_monitorenter: case Opcodes.OPC_monitorexit: frame.numberOfStackItems--; pc++; break; case Opcodes.OPC_wide: opcode = (byte) u1At(bytecodes, 1, pc); if (opcode == Opcodes.OPC_iinc) { // index = u2At(bytecodes, 2, pc); // i2At(bytecodes, 4, pc); // const // we don't need the index and the const value pc += 6; } else { index = u2At(bytecodes, 2, pc); // need to handle iload, fload, aload, lload, dload, istore, fstore, astore, lstore or dstore switch(opcode) { case Opcodes.OPC_iload : frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); break; case Opcodes.OPC_fload : frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); break; case Opcodes.OPC_aload : localsN = frame.locals[index]; if (localsN == null) { localsN = retrieveLocal(currentPC, index); } frame.addStackItem(localsN); break; case Opcodes.OPC_lload : frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); break; case Opcodes.OPC_dload : frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); break; case Opcodes.OPC_istore : frame.numberOfStackItems--; break; case Opcodes.OPC_fstore : frame.numberOfStackItems--; break; case Opcodes.OPC_astore : frame.locals[index] = frame.stackItems[frame.numberOfStackItems - 1]; frame.numberOfStackItems--; break; case Opcodes.OPC_lstore : frame.numberOfStackItems--; break; case Opcodes.OPC_dstore : frame.numberOfStackItems--; break; } pc += 4; } break; case Opcodes.OPC_multianewarray: index = u2At(bytecodes, 1, pc); utf8index = u2At(poolContents, 1, constantPoolOffsets[index]); className = utf8At(poolContents, constantPoolOffsets[utf8index] + 3, u2At( poolContents, 1, constantPoolOffsets[utf8index])); int dimensions = u1At(bytecodes, 3, pc); // dimensions frame.numberOfStackItems -= dimensions; // class name is already the name of the right array type with all dimensions typeBinding = getTypeBinding(className, scope, false); if (typeBinding != null) { frame.addStackItem(new VerificationTypeInfo(typeBinding)); } pc += 4; break; case Opcodes.OPC_ifnull: case Opcodes.OPC_ifnonnull: frame.numberOfStackItems--; jumpPC = currentPC + i2At(bytecodes, 1, pc); addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); pc += 3; break; case Opcodes.OPC_goto_w: jumpPC = currentPC + i4At(bytecodes, 1, pc); addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); pc += 5; addRealJumpTarget(realJumpTarget, pc - codeOffset); // handle infinite loop break; default: // should not occur if (this.codeStream.methodDeclaration != null) { this.codeStream.methodDeclaration.scope.problemReporter().abortDueToInternalError( Messages.bind( Messages.abort_invalidOpcode, new Object[] { Byte.valueOf(opcode), Integer.valueOf(pc), new String(methodBinding.shortReadableName()), }), this.codeStream.methodDeclaration); } else { this.codeStream.lambdaExpression.scope.problemReporter().abortDueToInternalError( Messages.bind( Messages.abort_invalidOpcode, new Object[] { Byte.valueOf(opcode), Integer.valueOf(pc), new String(methodBinding.shortReadableName()), }), this.codeStream.lambdaExpression); } break; } if (pc >= (codeLength + codeOffset)) { break; } } return filterFakeFrames(realJumpTarget, frames, codeLength); } private StackMapFrame createNewFrame(int currentPC, StackMapFrame frame, boolean isClinit, MethodBinding methodBinding) { StackMapFrame newFrame = frame.duplicate(); newFrame.pc = currentPC; // initialize locals initializeLocals(isClinit ? true : methodBinding.isStatic(), currentPC, newFrame); return newFrame; } private int getDimensions(char[] returnType) { int dimensions = 0; while (returnType[dimensions] == '[') { dimensions++; } return dimensions; } private void addRealJumpTarget(Set realJumpTarget, int pc) { realJumpTarget.add(Integer.valueOf(pc)); } private void addRealJumpTarget(Set realJumpTarget, int pc, Map frames, StackMapFrame frame, Scope scope) { realJumpTarget.add(Integer.valueOf(pc)); add(frames, frame, scope); } private void add(Map<Integer, StackMapFrame> frames, StackMapFrame frame, Scope scope) { Integer key = Integer.valueOf(frame.pc); StackMapFrame existingFrame = frames.get(key); if(existingFrame == null) { frames.put(key, frame); } else { // we need to merge frames.put(key, existingFrame.merge(frame, scope)); } } private final int u1At(byte[] reference, int relativeOffset, int structOffset) { return (reference[relativeOffset + structOffset] & 0xFF); } private final int u2At(byte[] reference, int relativeOffset, int structOffset) { int position = relativeOffset + structOffset; return ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF); } private final long u4At(byte[] reference, int relativeOffset, int structOffset) { int position = relativeOffset + structOffset; return (((reference[position++] & 0xFFL) << 24) + ((reference[position++] & 0xFF) << 16) + ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF)); } private final int i2At(byte[] reference, int relativeOffset, int structOffset) { int position = relativeOffset + structOffset; return (reference[position++] << 8) + (reference[position] & 0xFF); } public char[] utf8At(byte[] reference, int absoluteOffset, int bytesAvailable) { int length = bytesAvailable; char outputBuf[] = new char[bytesAvailable]; int outputPos = 0; int readOffset = absoluteOffset; while (length != 0) { int x = reference[readOffset++] & 0xFF; length--; if ((0x80 & x) != 0) { if ((x & 0x20) != 0) { length -= 2; x = ((x & 0xF) << 12) | ((reference[readOffset++] & 0x3F) << 6) | (reference[readOffset++] & 0x3F); } else { length--; x = ((x & 0x1F) << 6) | (reference[readOffset++] & 0x3F); } } outputBuf[outputPos++] = (char) x; } if (outputPos != bytesAvailable) { System.arraycopy(outputBuf, 0, (outputBuf = new char[outputPos]), 0, outputPos); } return outputBuf; } }