/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
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.HashSet;
import java.util.List;
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.Expression;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
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.StackMapFrameCodeStream.StackDepthMarker;
import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream.StackMarker;
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.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.NestedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
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.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
*/
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 Set innerClassesBindings;
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 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;
/**
* 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) {
SourceTypeBinding typeBinding= typeDeclaration.binding;
ClassFile classFile= ClassFile.getNewInstance(typeBinding);
classFile.initialize(typeBinding, null, 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
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;
if (methodDecls != null) {
if (typeBinding.isInterface()) {
// we cannot create problem methods for an interface. So we have to generate a clinit
// which should contain all the problem
classFile.addProblemClinit(problemsCopy);
for (int i= 0, length= methodDecls.length; i < length; i++) {
AbstractMethodDeclaration methodDecl= methodDecls[i];
MethodBinding method= methodDecl.binding;
if (method == null || method.isConstructor())
continue;
method.modifiers= ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract;
classFile.addAbstractMethod(methodDecl, method);
}
} else {
for (int i= 0, length= methodDecls.length; i < length; i++) {
AbstractMethodDeclaration methodDecl= methodDecls[i];
MethodBinding method= methodDecl.binding;
if (method == null)
continue;
if (method.isConstructor()) {
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, 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.
*/
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;
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();
}
/**
* 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.generateMethodInfoAttribute(methodBinding);
completeMethodInfo(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
*/
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());
}
// 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);
}
int sourceAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.SourceName);
this.contents[this.contentsOffset++]= (byte)(sourceAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)sourceAttributeNameIndex;
// The length of a source file attribute is 2. This is a fixed-length
// attribute
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 2;
// write the source file name
int fileNameIndex= this.constantPool.literalIndex(fullFileName.toCharArray());
this.contents[this.contentsOffset++]= (byte)(fileNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)fileNameIndex;
attributesNumber++;
}
// 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
if (this.contentsOffset + 6 >= this.contents.length) {
resizeContents(6);
}
int deprecatedAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
this.contents[this.contentsOffset++]= (byte)(deprecatedAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)deprecatedAttributeNameIndex;
// the length of a deprecated attribute is equals to 0
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
attributesNumber++;
}
// add signature attribute
char[] genericSignature= this.referenceBinding.genericSignature();
if (genericSignature != null) {
// 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);
}
int signatureAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.SignatureName);
this.contents[this.contentsOffset++]= (byte)(signatureAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)signatureAttributeNameIndex;
// the length of a signature attribute is equals to 2
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 2;
int signatureIndex=
this.constantPool.literalIndex(genericSignature);
this.contents[this.contentsOffset++]= (byte)(signatureIndex >> 8);
this.contents[this.contentsOffset++]= (byte)signatureIndex;
attributesNumber++;
}
if (this.targetJDK >= ClassFileConstants.JDK1_5
&& this.referenceBinding.isNestedType()
&& !this.referenceBinding.isMemberType()) {
// add enclosing method attribute (1.5 mode only)
if (this.contentsOffset + 10 >= this.contents.length) {
resizeContents(10);
}
int enclosingMethodAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.EnclosingMethodName);
this.contents[this.contentsOffset++]= (byte)(enclosingMethodAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)enclosingMethodAttributeNameIndex;
// the length of a signature attribute is equals to 2
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 4;
int enclosingTypeIndex= this.constantPool.literalIndexForType(this.referenceBinding.enclosingType().constantPoolName());
this.contents[this.contentsOffset++]= (byte)(enclosingTypeIndex >> 8);
this.contents[this.contentsOffset++]= (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[this.contentsOffset++]= methodIndexByte1;
this.contents[this.contentsOffset++]= methodIndexByte2;
attributesNumber++;
}
if (this.targetJDK >= ClassFileConstants.JDK1_4) {
TypeDeclaration typeDeclaration= this.referenceBinding.scope.referenceContext;
if (typeDeclaration != null) {
final Annotation[] annotations= typeDeclaration.annotations;
if (annotations != null) {
attributesNumber+= generateRuntimeAnnotations(annotations);
}
}
}
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);
}
// add an attribute for inconsistent hierarchy
if (this.contentsOffset + 6 >= this.contents.length) {
resizeContents(6);
}
int inconsistentHierarchyNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.InconsistentHierarchy);
this.contents[this.contentsOffset++]= (byte)(inconsistentHierarchyNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)inconsistentHierarchyNameIndex;
// the length of an inconsistent hierarchy attribute is equals to 0
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
attributesNumber++;
}
// Inner class attribute
int numberOfInnerClasses= this.innerClassesBindings == null ? 0 : this.innerClassesBindings.size();
if (numberOfInnerClasses != 0) {
ReferenceBinding[] innerClasses= new ReferenceBinding[numberOfInnerClasses];
this.innerClassesBindings.toArray(innerClasses);
Arrays.sort(innerClasses, new Comparator() {
public int compare(Object o1, Object o2) {
TypeBinding binding1= (TypeBinding)o1;
TypeBinding binding2= (TypeBinding)o2;
return CharOperation.compareTo(binding1.constantPoolName(), binding2.constantPoolName());
}
});
// Generate the inner class attribute
int exSize= 8 * numberOfInnerClasses + 8;
if (exSize + this.contentsOffset >= 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[this.contentsOffset++]= (byte)(attributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)attributeNameIndex;
int value= (numberOfInnerClasses << 3) + 2;
this.contents[this.contentsOffset++]= (byte)(value >> 24);
this.contents[this.contentsOffset++]= (byte)(value >> 16);
this.contents[this.contentsOffset++]= (byte)(value >> 8);
this.contents[this.contentsOffset++]= (byte)value;
this.contents[this.contentsOffset++]= (byte)(numberOfInnerClasses >> 8);
this.contents[this.contentsOffset++]= (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[this.contentsOffset++]= (byte)(innerClassIndex >> 8);
this.contents[this.contentsOffset++]= (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[this.contentsOffset++]= (byte)(outerClassIndex >> 8);
this.contents[this.contentsOffset++]= (byte)outerClassIndex;
} else {
// equals to 0 if the innerClass is not a member type
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
}
// name index
if (!innerClass.isAnonymousType()) {
int nameIndex= this.constantPool.literalIndex(innerClass.sourceName());
this.contents[this.contentsOffset++]= (byte)(nameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)nameIndex;
} else {
// equals to 0 if the innerClass is an anonymous type
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
}
// access flag
if (innerClass.isAnonymousType()) {
accessFlags&= ~ClassFileConstants.AccFinal;
} else if (innerClass.isMemberType() && innerClass.isInterface()) {
accessFlags|= ClassFileConstants.AccStatic; // implicitely static
}
this.contents[this.contentsOffset++]= (byte)(accessFlags >> 8);
this.contents[this.contentsOffset++]= (byte)accessFlags;
}
attributesNumber++;
}
if (this.missingTypes != null) {
generateMissingTypesAttribute();
attributesNumber++;
}
// 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.
*/
public void addDefaultAbstractMethods() { // default abstract methods
MethodBinding[] defaultAbstractMethods=
this.referenceBinding.getDefaultAbstractMethods();
for (int i= 0, max= defaultAbstractMethods.length; i < max; i++) {
generateMethodInfoHeader(defaultAbstractMethods[i]);
int methodAttributeOffset= this.contentsOffset;
int attributeNumber= generateMethodInfoAttribute(defaultAbstractMethods[i]);
completeMethodInfo(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) {
if (this.contentsOffset + 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[this.contentsOffset++]= (byte)(constantValueNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)constantValueNameIndex;
// The attribute length = 2 in case of a constantValue attribute
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 2;
attributesNumber++;
// Need to add the constant_value_index
switch (fieldConstant.typeID()) {
case T_boolean:
int booleanValueIndex=
this.constantPool.literalIndex(fieldConstant.booleanValue() ? 1 : 0);
this.contents[this.contentsOffset++]= (byte)(booleanValueIndex >> 8);
this.contents[this.contentsOffset++]= (byte)booleanValueIndex;
break;
case T_byte:
case T_char:
case T_int:
case T_short:
int integerValueIndex=
this.constantPool.literalIndex(fieldConstant.intValue());
this.contents[this.contentsOffset++]= (byte)(integerValueIndex >> 8);
this.contents[this.contentsOffset++]= (byte)integerValueIndex;
break;
case T_float:
int floatValueIndex=
this.constantPool.literalIndex(fieldConstant.floatValue());
this.contents[this.contentsOffset++]= (byte)(floatValueIndex >> 8);
this.contents[this.contentsOffset++]= (byte)floatValueIndex;
break;
case T_double:
int doubleValueIndex=
this.constantPool.literalIndex(fieldConstant.doubleValue());
this.contents[this.contentsOffset++]= (byte)(doubleValueIndex >> 8);
this.contents[this.contentsOffset++]= (byte)doubleValueIndex;
break;
case T_long:
int longValueIndex=
this.constantPool.literalIndex(fieldConstant.longValue());
this.contents[this.contentsOffset++]= (byte)(longValueIndex >> 8);
this.contents[this.contentsOffset++]= (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;
for (int i= 0, max= fieldDecls.length; 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;
}
} else {
this.contents[this.contentsOffset++]= (byte)(stringValueIndex >> 8);
this.contents[this.contentsOffset++]= (byte)stringValueIndex;
}
}
}
if (this.targetJDK < ClassFileConstants.JDK1_5 && fieldBinding.isSynthetic()) {
if (this.contentsOffset + 6 >= this.contents.length) {
resizeContents(6);
}
int syntheticAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
this.contents[this.contentsOffset++]= (byte)(syntheticAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)syntheticAttributeNameIndex;
// the length of a synthetic attribute is equals to 0
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
attributesNumber++;
}
if (fieldBinding.isDeprecated()) {
if (this.contentsOffset + 6 >= this.contents.length) {
resizeContents(6);
}
int deprecatedAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
this.contents[this.contentsOffset++]= (byte)(deprecatedAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)deprecatedAttributeNameIndex;
// the length of a deprecated attribute is equals to 0
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
attributesNumber++;
}
// add signature attribute
char[] genericSignature= fieldBinding.genericSignature();
if (genericSignature != null) {
// 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);
}
int signatureAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.SignatureName);
this.contents[this.contentsOffset++]= (byte)(signatureAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)signatureAttributeNameIndex;
// the length of a signature attribute is equals to 2
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 2;
int signatureIndex=
this.constantPool.literalIndex(genericSignature);
this.contents[this.contentsOffset++]= (byte)(signatureIndex >> 8);
this.contents[this.contentsOffset++]= (byte)signatureIndex;
attributesNumber++;
}
if (this.targetJDK >= ClassFileConstants.JDK1_4) {
FieldDeclaration fieldDeclaration= fieldBinding.sourceField();
if (fieldDeclaration != null) {
Annotation[] annotations= fieldDeclaration.annotations;
if (annotations != null) {
attributesNumber+= generateRuntimeAnnotations(annotations);
}
}
}
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
*
* @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)
*/
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());
}
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= generateMethodInfoAttribute(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(methodAttributeOffset, attributeNumber);
}
/**
* 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);
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.
*
* @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) {
// 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= generateMethodInfoAttribute(methodBinding);
// Code attribute
attributeNumber++;
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(methodAttributeOffset, attributeNumber);
}
/**
* 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.
*
* @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 attributeNumber= generateMethodInfoAttribute(methodBinding);
// Code attribute
attributeNumber++;
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(methodAttributeOffset, attributeNumber);
}
/**
* 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
*/
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++) {
generateMethodInfoHeader(defaultAbstractMethods[i]);
int methodAttributeOffset= this.contentsOffset;
int attributeNumber= generateMethodInfoAttribute(defaultAbstractMethods[i]);
completeMethodInfo(methodAttributeOffset, attributeNumber);
}
// add synthetic methods infos
SyntheticMethodBinding[] syntheticMethods= this.referenceBinding.syntheticMethods();
if (syntheticMethods != null) {
for (int i= 0, max= syntheticMethods.length; 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);
}
}
}
}
/**
* 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= generateMethodInfoAttribute(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
*
* @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= generateMethodInfoAttribute(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
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
*
* @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= generateMethodInfoAttribute(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;
}
/**
* 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= generateMethodInfoAttribute(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.
*
* @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= generateMethodInfoAttribute(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.
*
* @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= generateMethodInfoAttribute(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= generateMethodInfoAttribute(methodBinding);
// Code attribute
int codeAttributeOffset= this.contentsOffset;
attributeNumber++; // add code attribute
generateCodeAttributeHeader();
this.codeStream.init(this);
this.codeStream.generateSyntheticBodyForSwitchTable(methodBinding);
completeCodeAttributeForSyntheticMethod(
true,
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 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) {
// 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) {
this.codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(
this.codeStream.methodDeclaration);
}
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].count / 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.count;
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;
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 attributeNumber= 0;
// leave two bytes for the attribute_length
localContentsOffset+= 2;
if (localContentsOffset + 2 >= this.contents.length) {
resizeContents(2);
}
// first we handle the linenumber attribute
if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 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;
attributeNumber++;
}
}
// then we do the local variable attribute
if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) {
int numberOfEntries= 0;
int localVariableNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName);
final boolean methodDeclarationIsStatic= this.codeStream.methodDeclaration.isStatic();
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) {
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.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];
if (localVariable.declaration == null)
continue;
final TypeBinding localVariableTypeBinding= localVariable.type;
boolean isParameterizedType= localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable();
if (localVariable.initializationCount != 0 && isParameterizedType) {
if (genericLocalVariables == null) {
// we cannot have more than max locals
genericLocalVariables= new LocalVariableBinding[max];
}
genericLocalVariables[genericLocalVariablesCounter++]= localVariable;
}
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
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;
attributeNumber++;
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;
}
}
}
attributeNumber++;
}
}
if (addStackMaps) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(this.codeStream.methodDeclaration.binding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, false);
int numberOfFrames= frames.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)frames.get(0);
StackMapFrame prevFrame= null;
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
prevFrame= currentFrame;
currentFrame= (StackMapFrame)frames.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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(this.codeStream.methodDeclaration.binding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, false);
int numberOfFrames= frames.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)frames.get(0);
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
currentFrame= (StackMapFrame)frames.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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
this.contents[codeAttributeAttributeOffset++]= (byte)(attributeNumber >> 8);
this.contents[codeAttributeAttributeOffset]= (byte)attributeNumber;
// update the attribute length
int codeAttributeLength= localContentsOffset - (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;
this.contentsOffset= localContentsOffset;
}
/**
* 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) {
// 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].count / 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.count;
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 attributeNumber= 0;
// leave two bytes for the attribute_length
localContentsOffset+= 2;
if (localContentsOffset + 2 >= this.contents.length) {
resizeContents(2);
}
// first we handle the linenumber attribute
if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 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;
attributeNumber++;
}
}
// then we do the local variable attribute
if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) {
int numberOfEntries= 0;
// codeAttribute.addLocalVariableTableAttribute(this);
if ((this.codeStream.pcToSourceMap != null)
&& (this.codeStream.pcToSourceMapSize != 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;
int localVariableTableOffset= localContentsOffset;
localContentsOffset+= 6;
// leave space for attribute_length and local_variable_table_length
int nameIndex;
int descriptorIndex;
// 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];
if (localVariable.declaration == null)
continue;
final TypeBinding localVariableTypeBinding= localVariable.type;
boolean isParameterizedType= localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable();
if (localVariable.initializationCount != 0 && isParameterizedType) {
if (genericLocalVariables == null) {
// we cannot have more than max locals
genericLocalVariables= new LocalVariableBinding[max];
}
genericLocalVariables[genericLocalVariablesCounter++]= localVariable;
}
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
if (endPC == -1) {
localVariable.declaringScope.problemReporter().abortDueToInternalError(
Messages.bind(Messages.abort_invalidAttribute, new String(localVariable.name)),
(ASTNode)localVariable.declaringScope.methodScope().referenceContext);
}
if (localContentsOffset + 10 >= this.contents.length) {
resizeContents(10);
}
// now we can safely add the local entry
numberOfEntries++;
if (isParameterizedType) {
numberOfGenericEntries++;
}
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;
attributeNumber++;
if (genericLocalVariablesCounter != 0) {
// add the local variable type table attribute
// reserve enough space
int maxOfEntries= 8 + numberOfGenericEntries * 10;
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;
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;
}
}
}
attributeNumber++;
}
}
}
if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(null, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, true);
int numberOfFrames= frames.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)frames.get(0);
StackMapFrame prevFrame= null;
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
prevFrame= currentFrame;
currentFrame= (StackMapFrame)frames.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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(this.codeStream.methodDeclaration.binding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, false);
int numberOfFrames= frames.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)frames.get(0);
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
currentFrame= (StackMapFrame)frames.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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
// 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)(attributeNumber >> 8);
this.contents[codeAttributeAttributeOffset]= (byte)attributeNumber;
// update the attribute length
int codeAttributeLength= localContentsOffset - (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;
this.contentsOffset= localContentsOffset;
}
/**
* 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) {
// 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 attributeNumber= 0; // leave two bytes for the attribute_length
localContentsOffset+= 2; // first we handle the linenumber attribute
if (localContentsOffset + 2 >= this.contents.length) {
resizeContents(2);
}
// first we handle the linenumber attribute
if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) {
if (localContentsOffset + 20 >= this.contents.length) {
resizeContents(20);
}
/* 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
attributeNumber++;
}
// 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;
attributeNumber++;
}
if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(null, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, true);
int numberOfFrames= frames.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);
}
numberOfFrames= 0;
int numberOfFramesOffset= localContentsOffset;
localContentsOffset+= 2;
if (localContentsOffset + 2 >= this.contents.length) {
resizeContents(2);
}
StackMapFrame currentFrame= (StackMapFrame)frames.get(0);
StackMapFrame prevFrame= null;
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
prevFrame= currentFrame;
currentFrame= (StackMapFrame)frames.get(j);
// generate current frame
// need to find differences between the current frame and the previous frame
numberOfFrames++;
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;
}
}
}
}
}
}
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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(this.codeStream.methodDeclaration.binding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, false);
int numberOfFrames= frames.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)frames.get(0);
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
currentFrame= (StackMapFrame)frames.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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
// 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)(attributeNumber >> 8);
this.contents[codeAttributeAttributeOffset]= (byte)attributeNumber;
// update the attribute length
int codeAttributeLength= localContentsOffset - (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;
this.contentsOffset= localContentsOffset;
}
/**
*
*/
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 attributeNumber= 0; // leave two bytes for the attribute_length
localContentsOffset+= 2; // first we handle the linenumber attribute
if (localContentsOffset + 2 >= this.contents.length) {
resizeContents(2);
}
if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) {
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;
if (problemLine == 0) {
problemLine= Util.getLineNumber(binding.sourceStart(), startLineIndexes, 0, startLineIndexes.length - 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
attributeNumber++;
}
if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(binding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, false);
int numberOfFrames= frames.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);
}
numberOfFrames= 0;
int numberOfFramesOffset= localContentsOffset;
localContentsOffset+= 2;
if (localContentsOffset + 2 >= this.contents.length) {
resizeContents(2);
}
StackMapFrame currentFrame= (StackMapFrame)frames.get(0);
StackMapFrame prevFrame= null;
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
prevFrame= currentFrame;
currentFrame= (StackMapFrame)frames.get(j);
// generate current frame
// need to find differences between the current frame and the previous frame
numberOfFrames++;
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;
}
}
}
}
}
}
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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(this.codeStream.methodDeclaration.binding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, false);
int numberOfFrames= frames.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)frames.get(0);
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
currentFrame= (StackMapFrame)frames.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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
// 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)(attributeNumber >> 8);
this.contents[codeAttributeAttributeOffset]= (byte)attributeNumber;
// update the attribute length
int codeAttributeLength= localContentsOffset - (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;
this.contentsOffset= localContentsOffset;
}
/**
* 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 attributeNumber= 0; // leave two bytes for the attribute_length
localContentsOffset+= 2; // first we handle the linenumber attribute
if (localContentsOffset + 2 >= this.contents.length) {
resizeContents(2);
}
if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) {
if (localContentsOffset + 20 >= this.contents.length) {
resizeContents(20);
}
/* 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;
if (problemLine == 0) {
problemLine= Util.getLineNumber(binding.sourceStart(), startLineIndexes, 0, startLineIndexes.length - 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
attributeNumber++;
}
// then we do the local variable attribute
if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) {
// compute the resolved position for the arguments of the method
int argSize;
int numberOfEntries= 0;
// codeAttribute.addLocalVariableTableAttribute(this);
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;
int localVariableTableOffset= localContentsOffset;
localContentsOffset+= 6;
// leave space for attribute_length and local_variable_table_length
int descriptorIndex;
int nameIndex;
SourceTypeBinding declaringClassBinding= null;
final boolean methodDeclarationIsStatic= this.codeStream.methodDeclaration.isStatic();
if (!methodDeclarationIsStatic) {
numberOfEntries++;
if (localContentsOffset + 10 >= this.contents.length) {
resizeContents(10);
}
this.contents[localContentsOffset++]= 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.binding.declaringClass;
descriptorIndex=
this.constantPool.literalIndex(declaringClassBinding.signature());
this.contents[localContentsOffset++]= (byte)(descriptorIndex >> 8);
this.contents[localContentsOffset++]= (byte)descriptorIndex;
// the resolved position for this is always 0
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= 0;
}
// used to remember the local variable with a generic type
int genericLocalVariablesCounter= 0;
LocalVariableBinding[] genericLocalVariables= null;
int numberOfGenericEntries= 0;
if (binding.isConstructor()) {
ReferenceBinding declaringClass= binding.declaringClass;
if (declaringClass.isNestedType()) {
NestedTypeBinding methodDeclaringClass= (NestedTypeBinding)declaringClass;
argSize= methodDeclaringClass.getEnclosingInstancesSlotSize();
SyntheticArgumentBinding[] syntheticArguments;
if ((syntheticArguments= methodDeclaringClass.syntheticEnclosingInstances()) != null) {
for (int i= 0, max= syntheticArguments.length; i < max; i++) {
LocalVariableBinding localVariable= syntheticArguments[i];
final TypeBinding localVariableTypeBinding= localVariable.type;
if (localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable()) {
if (genericLocalVariables == null) {
// we cannot have more than max locals
genericLocalVariables= new LocalVariableBinding[max];
}
genericLocalVariables[genericLocalVariablesCounter++]= localVariable;
numberOfGenericEntries++;
}
if (localContentsOffset + 10 >= this.contents.length) {
resizeContents(10);
}
// now we can safely add the local entry
numberOfEntries++;
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= (byte)(code_length >> 8);
this.contents[localContentsOffset++]= (byte)code_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;
}
}
} else {
argSize= 1;
}
} else {
argSize= binding.isStatic() ? 0 : 1;
}
int genericArgumentsCounter= 0;
int[] genericArgumentsNameIndexes= null;
int[] genericArgumentsResolvedPositions= null;
TypeBinding[] genericArgumentsTypeBindings= null;
if (method.binding != null) {
TypeBinding[] parameters= method.binding.parameters;
Argument[] arguments= method.arguments;
if ((parameters != null) && (arguments != null)) {
for (int i= 0, max= parameters.length; i < max; i++) {
TypeBinding argumentBinding= parameters[i];
if (localContentsOffset + 10 >= this.contents.length) {
resizeContents(10);
}
// now we can safely add the local entry
numberOfEntries++;
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= (byte)(code_length >> 8);
this.contents[localContentsOffset++]= (byte)code_length;
nameIndex= this.constantPool.literalIndex(arguments[i].name);
this.contents[localContentsOffset++]= (byte)(nameIndex >> 8);
this.contents[localContentsOffset++]= (byte)nameIndex;
int resolvedPosition= argSize;
if (argumentBinding.isParameterizedType() || argumentBinding.isTypeVariable()) {
if (genericArgumentsCounter == 0) {
// we cannot have more than max locals
genericArgumentsNameIndexes= new int[max];
genericArgumentsResolvedPositions= new int[max];
genericArgumentsTypeBindings= new TypeBinding[max];
}
genericArgumentsNameIndexes[genericArgumentsCounter]= nameIndex;
genericArgumentsResolvedPositions[genericArgumentsCounter]= resolvedPosition;
genericArgumentsTypeBindings[genericArgumentsCounter++]= argumentBinding;
}
descriptorIndex= this.constantPool.literalIndex(argumentBinding.signature());
this.contents[localContentsOffset++]= (byte)(descriptorIndex >> 8);
this.contents[localContentsOffset++]= (byte)descriptorIndex;
switch (argumentBinding.id) {
case TypeIds.T_long:
case TypeIds.T_double:
argSize+= 2;
break;
default:
argSize++;
break;
}
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;
attributeNumber++;
final boolean currentInstanceIsGeneric=
!methodDeclarationIsStatic
&& declaringClassBinding != null
&& declaringClassBinding.typeVariables != Binding.NO_TYPE_VARIABLES;
if (genericLocalVariablesCounter != 0 || genericArgumentsCounter != 0 || currentInstanceIsGeneric) {
// add the local variable type table attribute
numberOfEntries= numberOfGenericEntries + genericArgumentsCounter + (currentInstanceIsGeneric ? 1 : 0);
// reserve enough space
int maxOfEntries= 8 + numberOfEntries * 10;
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= numberOfEntries * 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)(numberOfEntries >> 8);
this.contents[localContentsOffset++]= (byte)numberOfEntries;
if (currentInstanceIsGeneric) {
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;
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];
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= (byte)(code_length >> 8);
this.contents[localContentsOffset++]= (byte)code_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;
}
for (int i= 0; i < genericArgumentsCounter; i++) {
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= (byte)(code_length >> 8);
this.contents[localContentsOffset++]= (byte)code_length;
nameIndex= genericArgumentsNameIndexes[i];
this.contents[localContentsOffset++]= (byte)(nameIndex >> 8);
this.contents[localContentsOffset++]= (byte)nameIndex;
descriptorIndex= this.constantPool.literalIndex(genericArgumentsTypeBindings[i].genericTypeSignature());
this.contents[localContentsOffset++]= (byte)(descriptorIndex >> 8);
this.contents[localContentsOffset++]= (byte)descriptorIndex;
int resolvedPosition= genericArgumentsResolvedPositions[i];
this.contents[localContentsOffset++]= (byte)(resolvedPosition >> 8);
this.contents[localContentsOffset++]= (byte)resolvedPosition;
}
attributeNumber++;
}
}
if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(binding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, false);
int numberOfFrames= frames.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);
}
numberOfFrames= 0;
int numberOfFramesOffset= localContentsOffset;
localContentsOffset+= 2;
if (localContentsOffset + 2 >= this.contents.length) {
resizeContents(2);
}
StackMapFrame currentFrame= (StackMapFrame)frames.get(0);
StackMapFrame prevFrame= null;
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
prevFrame= currentFrame;
currentFrame= (StackMapFrame)frames.get(j);
// generate current frame
// need to find differences between the current frame and the previous frame
numberOfFrames++;
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;
}
}
}
}
}
}
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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(this.codeStream.methodDeclaration.binding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, false);
int numberOfFrames= frames.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)frames.get(0);
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
currentFrame= (StackMapFrame)frames.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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
// 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)(attributeNumber >> 8);
this.contents[codeAttributeAttributeOffset]= (byte)attributeNumber;
// update the attribute length
int codeAttributeLength= localContentsOffset - (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;
this.contentsOffset= localContentsOffset;
}
/**
* 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) {
// 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].count / 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.count;
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);
// 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;
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 attributeNumber= 0;
// leave two bytes for the attribute_length
localContentsOffset+= 2;
if (localContentsOffset + 2 >= this.contents.length) {
resizeContents(2);
}
// first we handle the linenumber attribute
if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) {
if (localContentsOffset + 12 >= this.contents.length) {
resizeContents(12);
}
int index= 0;
int lineNumberNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName);
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
// Seems like do would be better, but this preserves the existing behavior.
index= Util.getLineNumber(binding.sourceStart, startLineIndexes, 0, startLineIndexes.length - 1);
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= 0;
this.contents[localContentsOffset++]= (byte)(index >> 8);
this.contents[localContentsOffset++]= (byte)index;
// now we change the size of the line number attribute
this.contents[lineNumberTableOffset++]= 0;
this.contents[lineNumberTableOffset++]= 0;
this.contents[lineNumberTableOffset++]= 0;
this.contents[lineNumberTableOffset++]= 6;
this.contents[lineNumberTableOffset++]= 0;
this.contents[lineNumberTableOffset++]= 1;
attributeNumber++;
}
// then we do the local variable attribute
if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) {
int numberOfEntries= 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;
int localVariableTableOffset= localContentsOffset;
localContentsOffset+= 6;
// leave space for attribute_length and local_variable_table_length
int nameIndex;
int descriptorIndex;
// 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];
if (localVariable.declaration == null)
continue;
final TypeBinding localVariableTypeBinding= localVariable.type;
boolean isParameterizedType= localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable();
if (localVariable.initializationCount != 0 && isParameterizedType) {
if (genericLocalVariables == null) {
// we cannot have more than max locals
genericLocalVariables= new LocalVariableBinding[max];
}
genericLocalVariables[genericLocalVariablesCounter++]= localVariable;
}
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
if (endPC == -1) {
localVariable.declaringScope.problemReporter().abortDueToInternalError(
Messages.bind(Messages.abort_invalidAttribute, new String(localVariable.name)),
(ASTNode)localVariable.declaringScope.methodScope().referenceContext);
}
if (localContentsOffset + 10 > this.contents.length) {
resizeContents(10);
}
// now we can safely add the local entry
numberOfEntries++;
if (isParameterizedType) {
numberOfGenericEntries++;
}
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;
attributeNumber++;
if (genericLocalVariablesCounter != 0) {
// add the local variable type table attribute
int 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;
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;
}
}
}
attributeNumber++;
}
}
if (addStackMaps) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(binding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, false);
int numberOfFrames= frames.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)frames.get(0);
StackMapFrame prevFrame= null;
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
prevFrame= currentFrame;
currentFrame= (StackMapFrame)frames.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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
StackMapFrameCodeStream stackMapFrameCodeStream= (StackMapFrameCodeStream)this.codeStream;
stackMapFrameCodeStream.removeFramePosition(code_length);
if (stackMapFrameCodeStream.hasFramePositions()) {
ArrayList frames= new ArrayList();
traverse(this.codeStream.methodDeclaration.binding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, false);
int numberOfFrames= frames.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)frames.get(0);
for (int j= 1; j < numberOfFrames; j++) {
// select next frame
currentFrame= (StackMapFrame)frames.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;
attributeNumber++;
} else {
localContentsOffset= stackMapTableAttributeOffset;
}
}
}
}
// 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)(attributeNumber >> 8);
this.contents[codeAttributeAttributeOffset]= (byte)attributeNumber;
// update the attribute length
int codeAttributeLength= localContentsOffset - (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;
this.contentsOffset= localContentsOffset;
}
/**
* 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);
}
/**
* 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 attributeNumber <CODE>int</CODE>
*/
public void completeMethodInfo(
int methodAttributeOffset,
int attributeNumber) {
// update the number of attributes
this.contents[methodAttributeOffset++]= (byte)(attributeNumber >> 8);
this.contents[methodAttributeOffset]= (byte)attributeNumber;
}
/**
* 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;
}
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;
if (memberValuePairs != null) {
final int memberValuePairsLength= memberValuePairs.length;
this.contents[this.contentsOffset++]= (byte)(memberValuePairsLength >> 8);
this.contents[this.contentsOffset++]= (byte)memberValuePairsLength;
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= startingContentsOffset;
} else {
try {
generateElementValue(memberValuePair.value, methodBinding.returnType, startingContentsOffset);
} catch (ClassCastException e) {
this.contentsOffset= startingContentsOffset;
} catch (ShouldNotImplement e) {
this.contentsOffset= startingContentsOffset;
}
}
}
} 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 {
try {
generateElementValue(singleMemberAnnotation.memberValue, methodBinding.returnType, startingContentsOffset);
} catch (ClassCastException e) {
this.contentsOffset= startingContentsOffset;
} catch (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;
}
}
/**
* 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 void generateElementValue(
Expression defaultValue,
TypeBinding memberValuePairReturnType,
int attributeOffset) {
Constant constant= defaultValue.constant;
TypeBinding defaultValueBinding= defaultValue.resolvedType;
if (defaultValueBinding == null) {
this.contentsOffset= attributeOffset;
} else {
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);
}
}
}
/**
* @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;
}
}
/**
* 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 generateMethodInfoAttribute(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 attributeNumber= 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
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[this.contentsOffset++]= (byte)(exceptionNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)exceptionNameIndex;
// The attribute length = length * 2 + 2 in case of a exception attribute
int attributeLength= length * 2 + 2;
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;
this.contents[this.contentsOffset++]= (byte)(length >> 8);
this.contents[this.contentsOffset++]= (byte)length;
for (int i= 0; i < length; i++) {
int exceptionIndex= this.constantPool.literalIndexForType(thrownsExceptions[i]);
this.contents[this.contentsOffset++]= (byte)(exceptionIndex >> 8);
this.contents[this.contentsOffset++]= (byte)exceptionIndex;
}
attributeNumber++;
}
if (methodBinding.isDeprecated()) {
// Deprecated attribute
// Check that there is enough space to write the deprecated attribute
if (this.contentsOffset + 6 >= this.contents.length) {
resizeContents(6);
}
int deprecatedAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.DeprecatedName);
this.contents[this.contentsOffset++]= (byte)(deprecatedAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)deprecatedAttributeNameIndex;
// the length of a deprecated attribute is equals to 0
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
attributeNumber++;
}
if (this.targetJDK < ClassFileConstants.JDK1_5) {
if (methodBinding.isSynthetic()) {
// Synthetic attribute
// Check that there is enough space to write the deprecated attribute
if (this.contentsOffset + 6 >= this.contents.length) {
resizeContents(6);
}
int syntheticAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.SyntheticName);
this.contents[this.contentsOffset++]= (byte)(syntheticAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)syntheticAttributeNameIndex;
// the length of a synthetic attribute is equals to 0
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
attributeNumber++;
}
if (methodBinding.isVarargs()) {
/*
* handle of the target jsr14 for varargs in the source
* Varargs attribute
* Check that there is enough space to write the deprecated attribute
*/
if (this.contentsOffset + 6 >= this.contents.length) {
resizeContents(6);
}
int varargsAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.VarargsName);
this.contents[this.contentsOffset++]= (byte)(varargsAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)varargsAttributeNameIndex;
// the length of a varargs attribute is equals to 0
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
attributeNumber++;
}
}
// add signature attribute
char[] genericSignature= methodBinding.genericSignature();
if (genericSignature != null) {
// 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);
}
int signatureAttributeNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.SignatureName);
this.contents[this.contentsOffset++]= (byte)(signatureAttributeNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)signatureAttributeNameIndex;
// the length of a signature attribute is equals to 2
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 0;
this.contents[this.contentsOffset++]= 2;
int signatureIndex=
this.constantPool.literalIndex(genericSignature);
this.contents[this.contentsOffset++]= (byte)(signatureIndex >> 8);
this.contents[this.contentsOffset++]= (byte)signatureIndex;
attributeNumber++;
}
if (this.targetJDK >= ClassFileConstants.JDK1_4) {
AbstractMethodDeclaration methodDeclaration= methodBinding.sourceMethod();
if (methodDeclaration != null) {
Annotation[] annotations= methodDeclaration.annotations;
if (annotations != null) {
attributeNumber+= generateRuntimeAnnotations(annotations);
}
if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) {
Argument[] arguments= methodDeclaration.arguments;
if (arguments != null) {
attributeNumber+= generateRuntimeAnnotationsForParameters(arguments);
}
}
}
}
if ((methodBinding.tagBits & TagBits.HasMissingType) != 0) {
this.missingTypes= methodBinding.collectMissingTypes(this.missingTypes);
}
return attributeNumber;
}
public int generateMethodInfoAttribute(MethodBinding methodBinding, AnnotationMethodDeclaration declaration) {
int attributesNumber= generateMethodInfoAttribute(methodBinding);
int attributeOffset= this.contentsOffset;
if ((declaration.modifiers & ClassFileConstants.AccAnnotationDefault) != 0) {
// add an annotation default attribute
int annotationDefaultNameIndex=
this.constantPool.literalIndex(AttributeNamesConstants.AnnotationDefaultName);
this.contents[this.contentsOffset++]= (byte)(annotationDefaultNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)annotationDefaultNameIndex;
int attributeLengthOffset= this.contentsOffset;
this.contentsOffset+= 4;
if (this.contentsOffset + 4 >= this.contents.length) {
resizeContents(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 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.
*
* @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;
}
/**
* 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
*
* @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() {
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((TypeBinding)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;
}
}
/**
* @param annotations
* @return the number of attributes created while dumping the annotations in the .class file
*/
private int generateRuntimeAnnotations(final Annotation[] annotations) {
int attributesNumber= 0;
final int length= annotations.length;
int visibleAnnotationsCounter= 0;
int invisibleAnnotationsCounter= 0;
for (int i= 0; i < length; i++) {
Annotation annotation= annotations[i];
if (isRuntimeInvisible(annotation)) {
invisibleAnnotationsCounter++;
} else if (isRuntimeVisible(annotation)) {
visibleAnnotationsCounter++;
}
}
int annotationAttributeOffset= this.contentsOffset;
int constantPOffset= this.constantPool.currentOffset;
int constantPoolIndex= this.constantPool.currentIndex;
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= annotations[i];
if (isRuntimeInvisible(annotation)) {
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;
// reset the constant pool to its state before the clinit
this.constantPool.resetForAttributeName(AttributeNamesConstants.RuntimeInvisibleAnnotationsName, constantPoolIndex, constantPOffset);
}
}
annotationAttributeOffset= this.contentsOffset;
constantPOffset= this.constantPool.currentOffset;
constantPoolIndex= this.constantPool.currentIndex;
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= annotations[i];
if (isRuntimeVisible(annotation)) {
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;
this.constantPool.resetForAttributeName(AttributeNamesConstants.RuntimeVisibleAnnotationsName, constantPoolIndex, constantPOffset);
}
}
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= annotations[j];
if (isRuntimeInvisible(annotation)) {
annotationsCounters[i][INVISIBLE_INDEX]++;
invisibleParametersAnnotationsCounter++;
} else if (isRuntimeVisible(annotation)) {
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= annotations[j];
if (isRuntimeInvisible(annotation)) {
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= annotations[j];
if (isRuntimeVisible(annotation)) {
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;
}
/**
* 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.
*
* @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();
}
}
}
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.referenceBinding.methods().length + this.referenceBinding.fields().length;
this.header= new byte[INITIAL_HEADER_SIZE];
this.contents= new byte[members < 15 ? INITIAL_CONTENTS_SIZE : INITIAL_HEADER_SIZE];
}
public void initialize(SourceTypeBinding aType, ClassFile parentClassFile, boolean createProblemType) {
// 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);
// 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;
}
this.enclosingClassFile= parentClassFile;
// innerclasses get their names computed at code gen time
// now we continue to generate the bytes inside the contents array
this.contents[this.contentsOffset++]= (byte)(accessFlags >> 8);
this.contents[this.contentsOffset++]= (byte)accessFlags;
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 {
superclassNameIndex=
(aType.superclass == null ? 0 : this.constantPool.literalIndexForType(aType.superclass));
}
this.contents[this.contentsOffset++]= (byte)(superclassNameIndex >> 8);
this.contents[this.contentsOffset++]= (byte)superclassNameIndex;
ReferenceBinding[] superInterfacesBinding= aType.superInterfaces();
int interfacesCount= superInterfacesBinding.length;
this.contents[this.contentsOffset++]= (byte)(interfacesCount >> 8);
this.contents[this.contentsOffset++]= (byte)interfacesCount;
for (int i= 0; i < interfacesCount; i++) {
int interfaceIndex= this.constantPool.literalIndexForType(superInterfacesBinding[i]);
this.contents[this.contentsOffset++]= (byte)(interfaceIndex >> 8);
this.contents[this.contentsOffset++]= (byte)interfaceIndex;
}
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;
}
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) {
LocalVariableBinding localVariableBinding= new LocalVariableBinding("this".toCharArray(), methodBinding.declaringClass, 0, false); //$NON-NLS-1$
localVariableBinding.resolvedPosition= 0;
this.codeStream.record(localVariableBinding);
localVariableBinding.recordInitializationStartPC(0);
localVariableBinding.recordInitializationEndPC(codeLength);
frame.putLocal(resolvedPosition, new VerificationTypeInfo(
VerificationTypeInfo.ITEM_UNINITIALIZED_THIS,
methodBinding.declaringClass));
resolvedPosition++;
} else if (!methodBinding.isStatic()) {
LocalVariableBinding localVariableBinding= new LocalVariableBinding("this".toCharArray(), methodBinding.declaringClass, 0, false); //$NON-NLS-1$
localVariableBinding.resolvedPosition= 0;
this.codeStream.record(localVariableBinding);
localVariableBinding.recordInitializationStartPC(0);
localVariableBinding.recordInitializationEndPC(codeLength);
frame.putLocal(resolvedPosition, new VerificationTypeInfo(
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(
TypeIds.T_JavaLangString,
ConstantPool.JavaLangStringConstantPoolName));
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];
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;
}
}
}
}
private boolean isRuntimeInvisible(Annotation annotation) {
final TypeBinding annotationBinding= annotation.resolvedType;
if (annotationBinding == null) {
return false;
}
long metaTagBits= annotationBinding.getAnnotationTagBits(); // could be forward reference
if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
return true; // by default the retention is CLASS
return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationClassRetention;
}
private boolean isRuntimeVisible(Annotation annotation) {
final TypeBinding annotationBinding= annotation.resolvedType;
if (annotationBinding == null) {
return false;
}
long metaTagBits= annotationBinding.getAnnotationTagBits();
if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
return false; // by default the retention is CLASS
return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationRuntimeRetention;
}
/**
* 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) {
if (this.innerClassesBindings == null) {
this.innerClassesBindings= new HashSet(INNER_CLASSES_SIZE);
}
ReferenceBinding innerClass= (ReferenceBinding)binding;
this.innerClassesBindings.add(innerClass.erasure());
ReferenceBinding enclosingType= innerClass.enclosingType();
while (enclosingType != null
&& enclosingType.isNestedType()) {
this.innerClassesBindings.add(enclosingType.erasure());
enclosingType= enclosingType.enclosingType();
}
}
public void reset(SourceTypeBinding typeBinding) {
// the code stream is reinitialized for each method
final CompilerOptions options= typeBinding.scope.compilerOptions();
this.referenceBinding= typeBinding;
this.isNestedType= typeBinding.isNestedType();
this.targetJDK= options.targetJDK;
this.produceAttributes= options.produceDebugAttributes;
if (this.targetJDK >= ClassFileConstants.JDK1_6) {
this.produceAttributes|= ClassFileConstants.ATTR_STACK_MAP_TABLE;
} 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();
}
this.missingTypes= null;
this.visitedTypes= null;
}
/**
* 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 new IllegalArgumentException();
}
}
/**
* 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;
}
public void traverse(MethodBinding methodBinding, int maxLocals, byte[] bytecodes, int codeOffset, int codeLength, ArrayList frames, boolean isClinit) {
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 stack depth markers
int indexInStackDepthMarkers= 0;
StackDepthMarker[] stackDepthMarkers= stackMapFrameCodeStream.getStackDepthMarkers();
int stackDepthMarkersLength= stackDepthMarkers == null ? 0 : stackDepthMarkers.length;
boolean hasStackDepthMarkers= stackDepthMarkersLength != 0;
StackDepthMarker stackDepthMarker= null;
if (hasStackDepthMarkers) {
stackDepthMarker= stackDepthMarkers[0];
}
// set initial values for stack markers (used only in cldc mode)
int indexInStackMarkers= 0;
StackMarker[] stackMarkers= stackMapFrameCodeStream.getStackMarkers();
int stackMarkersLength= stackMarkers == null ? 0 : stackMarkers.length;
boolean hasStackMarkers= stackMarkersLength != 0;
StackMarker stackMarker= null;
if (hasStackMarkers) {
stackMarker= stackMarkers[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;
frames.add(frame.duplicate());
while (true) {
int currentPC= pc - codeOffset;
if (hasStackMarkers && stackMarker.pc == currentPC) {
VerificationTypeInfo[] infos= frame.stackItems;
VerificationTypeInfo[] tempInfos= new VerificationTypeInfo[frame.numberOfStackItems];
System.arraycopy(infos, 0, tempInfos, 0, frame.numberOfStackItems);
stackMarker.setInfos(tempInfos);
} else if (hasStackMarkers && stackMarker.destinationPC == currentPC) {
VerificationTypeInfo[] infos= stackMarker.infos;
frame.stackItems= infos;
frame.numberOfStackItems= infos.length;
indexInStackMarkers++;
if (indexInStackMarkers < stackMarkersLength) {
stackMarker= stackMarkers[indexInStackMarkers];
} else {
hasStackMarkers= false;
}
}
if (hasStackDepthMarkers && stackDepthMarker.pc == currentPC) {
TypeBinding typeBinding= stackDepthMarker.typeBinding;
if (typeBinding != null) {
if (stackDepthMarker.delta > 0) {
frame.addStackItem(new VerificationTypeInfo(typeBinding));
} else {
frame.stackItems[frame.numberOfStackItems - 1]= new VerificationTypeInfo(typeBinding);
}
} else {
frame.numberOfStackItems--;
}
indexInStackDepthMarkers++;
if (indexInStackDepthMarkers < stackDepthMarkersLength) {
stackDepthMarker= stackDepthMarkers[indexInStackDepthMarkers];
} else {
hasStackDepthMarkers= false;
}
}
if (hasExceptionMarkers && exceptionMarker.pc == currentPC) {
frame.numberOfStackItems= 0;
frame.addStackItem(new VerificationTypeInfo(0, VerificationTypeInfo.ITEM_OBJECT, exceptionMarker.constantPoolName));
indexInExceptionMarkers++;
if (indexInExceptionMarkers < exceptionsMarkersLength) {
exceptionMarker= exceptionMarkers[indexInExceptionMarkers];
} else {
hasExceptionMarkers= false;
}
}
if (currentFramePosition < currentPC) {
do {
indexInFramePositions++;
if (indexInFramePositions < framePositionsLength) {
currentFramePosition= framePositions[indexInFramePositions];
} else {
// no more frame to generate
return;
}
} while (currentFramePosition < currentPC);
}
if (currentFramePosition == currentPC) {
// need to build a new frame and create a stack map attribute entry
StackMapFrame currentFrame= frame.duplicate();
currentFrame.pc= currentPC;
// initialize locals
initializeLocals(isClinit ? true : methodBinding.isStatic(), currentPC, currentFrame);
// insert a new frame
frames.add(currentFrame);
indexInFramePositions++;
if (indexInFramePositions < framePositionsLength) {
currentFramePosition= framePositions[indexInFramePositions];
} else {
// no more frame to generate
return;
}
}
byte opcode= (byte)u1At(bytecodes, 0, pc);
switch (opcode) {
case Opcodes.OPC_nop:
pc++;
break;
case Opcodes.OPC_aconst_null:
frame.addStackItem(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(TypeBinding.INT);
pc++;
break;
case Opcodes.OPC_lconst_0:
case Opcodes.OPC_lconst_1:
frame.addStackItem(TypeBinding.LONG);
pc++;
break;
case Opcodes.OPC_fconst_0:
case Opcodes.OPC_fconst_1:
case Opcodes.OPC_fconst_2:
frame.addStackItem(TypeBinding.FLOAT);
pc++;
break;
case Opcodes.OPC_dconst_0:
case Opcodes.OPC_dconst_1:
frame.addStackItem(TypeBinding.DOUBLE);
pc++;
break;
case Opcodes.OPC_bipush:
frame.addStackItem(TypeBinding.BYTE);
pc+= 2;
break;
case Opcodes.OPC_sipush:
frame.addStackItem(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(
TypeIds.T_JavaLangString,
ConstantPool.JavaLangStringConstantPoolName));
break;
case ClassFileConstants.IntegerTag:
frame.addStackItem(TypeBinding.INT);
break;
case ClassFileConstants.FloatTag:
frame.addStackItem(TypeBinding.FLOAT);
break;
case ClassFileConstants.ClassTag:
frame.addStackItem(new VerificationTypeInfo(
TypeIds.T_JavaLangClass,
ConstantPool.JavaLangClassConstantPoolName));
}
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(
TypeIds.T_JavaLangString,
ConstantPool.JavaLangStringConstantPoolName));
break;
case ClassFileConstants.IntegerTag:
frame.addStackItem(TypeBinding.INT);
break;
case ClassFileConstants.FloatTag:
frame.addStackItem(TypeBinding.FLOAT);
break;
case ClassFileConstants.ClassTag:
frame.addStackItem(new VerificationTypeInfo(
TypeIds.T_JavaLangClass,
ConstantPool.JavaLangClassConstantPoolName));
}
pc+= 3;
break;
case Opcodes.OPC_ldc2_w:
index= u2At(bytecodes, 1, pc);
switch (u1At(poolContents, 0, constantPoolOffsets[index])) {
case ClassFileConstants.DoubleTag:
frame.addStackItem(TypeBinding.DOUBLE);
break;
case ClassFileConstants.LongTag:
frame.addStackItem(TypeBinding.LONG);
break;
}
pc+= 3;
break;
case Opcodes.OPC_iload:
frame.addStackItem(TypeBinding.INT);
pc+= 2;
break;
case Opcodes.OPC_lload:
frame.addStackItem(TypeBinding.LONG);
pc+= 2;
break;
case Opcodes.OPC_fload:
frame.addStackItem(TypeBinding.FLOAT);
pc+= 2;
break;
case Opcodes.OPC_dload:
frame.addStackItem(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(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(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(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(TypeBinding.DOUBLE);
pc++;
break;
case Opcodes.OPC_aload_0:
VerificationTypeInfo locals0= frame.locals[0];
// special case to handle uninitialized object
if (locals0 == null) {
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(TypeBinding.INT);
pc++;
break;
case Opcodes.OPC_laload:
frame.numberOfStackItems-= 2;
frame.addStackItem(TypeBinding.LONG);
pc++;
break;
case Opcodes.OPC_faload:
frame.numberOfStackItems-= 2;
frame.addStackItem(TypeBinding.FLOAT);
pc++;
break;
case Opcodes.OPC_daload:
frame.numberOfStackItems-= 2;
frame.addStackItem(TypeBinding.DOUBLE);
pc++;
break;
case Opcodes.OPC_aaload:
frame.numberOfStackItems--;
frame.replaceWithElementType();
pc++;
break;
case Opcodes.OPC_baload:
frame.numberOfStackItems-= 2;
frame.addStackItem(TypeBinding.BYTE);
pc++;
break;
case Opcodes.OPC_caload:
frame.numberOfStackItems-= 2;
frame.addStackItem(TypeBinding.CHAR);
pc++;
break;
case Opcodes.OPC_saload:
frame.numberOfStackItems-= 2;
frame.addStackItem(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(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--;
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;
pc+= 3;
break;
case Opcodes.OPC_goto:
pc+= 3;
break;
case Opcodes.OPC_tableswitch:
pc++;
while (((pc - codeOffset) & 0x03) != 0) {
pc++;
}
pc+= 4; // default
int low= i4At(bytecodes, 0, pc);
pc+= 4;
int high= i4At(bytecodes, 0, pc);
pc+= 4;
int length= high - low + 1;
pc+= (length * 4);
frame.numberOfStackItems--;
break;
case Opcodes.OPC_lookupswitch:
pc++;
while (((pc - codeOffset) & 0x03) != 0) {
pc++;
}
pc+= 4; // default
int npairs= (int)u4At(bytecodes, 0, pc);
pc+= (4 + npairs * 8);
frame.numberOfStackItems--;
break;
case Opcodes.OPC_ireturn:
case Opcodes.OPC_lreturn:
case Opcodes.OPC_freturn:
case Opcodes.OPC_dreturn:
case Opcodes.OPC_areturn:
frame.numberOfStackItems--;
pc++;
break;
case Opcodes.OPC_return:
pc++;
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]));
if (descriptor.length == 1) {
// base type
switch (descriptor[0]) {
case 'Z':
frame.addStackItem(TypeBinding.BOOLEAN);
break;
case 'B':
frame.addStackItem(TypeBinding.BYTE);
break;
case 'C':
frame.addStackItem(TypeBinding.CHAR);
break;
case 'D':
frame.addStackItem(TypeBinding.DOUBLE);
break;
case 'F':
frame.addStackItem(TypeBinding.FLOAT);
break;
case 'I':
frame.addStackItem(TypeBinding.INT);
break;
case 'J':
frame.addStackItem(TypeBinding.LONG);
break;
case 'S':
frame.addStackItem(TypeBinding.SHORT);
break;
}
} else if (descriptor[0] == '[') {
frame.addStackItem(new VerificationTypeInfo(0, descriptor));
} else {
frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(descriptor, 1, descriptor.length - 1)));
}
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--;
if (descriptor.length == 1) {
// base type
switch (descriptor[0]) {
case 'Z':
frame.addStackItem(TypeBinding.BOOLEAN);
break;
case 'B':
frame.addStackItem(TypeBinding.BYTE);
break;
case 'C':
frame.addStackItem(TypeBinding.CHAR);
break;
case 'D':
frame.addStackItem(TypeBinding.DOUBLE);
break;
case 'F':
frame.addStackItem(TypeBinding.FLOAT);
break;
case 'I':
frame.addStackItem(TypeBinding.INT);
break;
case 'J':
frame.addStackItem(TypeBinding.LONG);
break;
case 'S':
frame.addStackItem(TypeBinding.SHORT);
break;
}
} else if (descriptor[0] == '[') {
frame.addStackItem(new VerificationTypeInfo(0, descriptor));
} else {
frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(descriptor, 1, descriptor.length - 1)));
}
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);
if (returnType.length == 1) {
// base type
switch (returnType[0]) {
case 'Z':
frame.addStackItem(TypeBinding.BOOLEAN);
break;
case 'B':
frame.addStackItem(TypeBinding.BYTE);
break;
case 'C':
frame.addStackItem(TypeBinding.CHAR);
break;
case 'D':
frame.addStackItem(TypeBinding.DOUBLE);
break;
case 'F':
frame.addStackItem(TypeBinding.FLOAT);
break;
case 'I':
frame.addStackItem(TypeBinding.INT);
break;
case 'J':
frame.addStackItem(TypeBinding.LONG);
break;
case 'S':
frame.addStackItem(TypeBinding.SHORT);
break;
}
} else {
if (returnType[0] == '[') {
frame.addStackItem(new VerificationTypeInfo(0, returnType));
} else {
frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(returnType, 1, returnType.length - 1)));
}
}
pc+= 3;
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);
if (returnType.length == 1) {
// base type
switch (returnType[0]) {
case 'Z':
frame.addStackItem(TypeBinding.BOOLEAN);
break;
case 'B':
frame.addStackItem(TypeBinding.BYTE);
break;
case 'C':
frame.addStackItem(TypeBinding.CHAR);
break;
case 'D':
frame.addStackItem(TypeBinding.DOUBLE);
break;
case 'F':
frame.addStackItem(TypeBinding.FLOAT);
break;
case 'I':
frame.addStackItem(TypeBinding.INT);
break;
case 'J':
frame.addStackItem(TypeBinding.LONG);
break;
case 'S':
frame.addStackItem(TypeBinding.SHORT);
break;
}
} else {
if (returnType[0] == '[') {
frame.addStackItem(new VerificationTypeInfo(0, returnType));
} else {
frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(returnType, 1, returnType.length - 1)));
}
}
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);
if (returnType.length == 1) {
// base type
switch (returnType[0]) {
case 'Z':
frame.addStackItem(TypeBinding.BOOLEAN);
break;
case 'B':
frame.addStackItem(TypeBinding.BYTE);
break;
case 'C':
frame.addStackItem(TypeBinding.CHAR);
break;
case 'D':
frame.addStackItem(TypeBinding.DOUBLE);
break;
case 'F':
frame.addStackItem(TypeBinding.FLOAT);
break;
case 'I':
frame.addStackItem(TypeBinding.INT);
break;
case 'J':
frame.addStackItem(TypeBinding.LONG);
break;
case 'S':
frame.addStackItem(TypeBinding.SHORT);
break;
}
} else {
if (returnType[0] == '[') {
frame.addStackItem(new VerificationTypeInfo(0, returnType));
} else {
frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(returnType, 1, returnType.length - 1)));
}
}
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);
if (returnType.length == 1) {
// base type
switch (returnType[0]) {
case 'Z':
frame.addStackItem(TypeBinding.BOOLEAN);
break;
case 'B':
frame.addStackItem(TypeBinding.BYTE);
break;
case 'C':
frame.addStackItem(TypeBinding.CHAR);
break;
case 'D':
frame.addStackItem(TypeBinding.DOUBLE);
break;
case 'F':
frame.addStackItem(TypeBinding.FLOAT);
break;
case 'I':
frame.addStackItem(TypeBinding.INT);
break;
case 'J':
frame.addStackItem(TypeBinding.LONG);
break;
case 'S':
frame.addStackItem(TypeBinding.SHORT);
break;
}
} else {
if (returnType[0] == '[') {
frame.addStackItem(new VerificationTypeInfo(0, returnType));
} else {
frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(returnType, 1, returnType.length - 1)));
}
}
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]));
VerificationTypeInfo verificationTypeInfo= new VerificationTypeInfo(0, VerificationTypeInfo.ITEM_UNINITIALIZED, className);
verificationTypeInfo.offset= currentPC;
frame.addStackItem(verificationTypeInfo);
pc+= 3;
break;
case Opcodes.OPC_newarray:
char[] constantPoolName= null;
switch (u1At(bytecodes, 1, pc)) {
case ClassFileConstants.INT_ARRAY:
constantPoolName= new char[] { '[', 'I' };
break;
case ClassFileConstants.BYTE_ARRAY:
constantPoolName= new char[] { '[', 'B' };
break;
case ClassFileConstants.BOOLEAN_ARRAY:
constantPoolName= new char[] { '[', 'Z' };
break;
case ClassFileConstants.SHORT_ARRAY:
constantPoolName= new char[] { '[', 'S' };
break;
case ClassFileConstants.CHAR_ARRAY:
constantPoolName= new char[] { '[', 'C' };
break;
case ClassFileConstants.LONG_ARRAY:
constantPoolName= new char[] { '[', 'J' };
break;
case ClassFileConstants.FLOAT_ARRAY:
constantPoolName= new char[] { '[', 'F' };
break;
case ClassFileConstants.DOUBLE_ARRAY:
constantPoolName= new char[] { '[', 'D' };
break;
}
frame.stackItems[frame.numberOfStackItems - 1]= new VerificationTypeInfo(TypeIds.T_JavaLangObject, constantPoolName);
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]));
int classNameLength= className.length;
if (className[0] != '[') {
// this is a type name (class or interface). So we add appropriate '[', 'L' and ';'.
System.arraycopy(className, 0, (constantPoolName= new char[classNameLength + 3]), 2, classNameLength);
constantPoolName[0]= '[';
constantPoolName[1]= 'L';
constantPoolName[classNameLength + 2]= ';';
} else {
// if class name is already an array, we just need to add one dimension
System.arraycopy(className, 0, (constantPoolName= new char[classNameLength + 1]), 1, classNameLength);
constantPoolName[0]= '[';
}
frame.stackItems[frame.numberOfStackItems - 1]= new VerificationTypeInfo(0, constantPoolName);
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++;
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]));
frame.stackItems[frame.numberOfStackItems - 1]= new VerificationTypeInfo(0, className);
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(TypeBinding.INT);
break;
case Opcodes.OPC_fload:
frame.addStackItem(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(TypeBinding.LONG);
break;
case Opcodes.OPC_dload:
frame.addStackItem(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;
classNameLength= className.length;
constantPoolName= new char[classNameLength + dimensions];
for (int i= 0; i < dimensions; i++) {
constantPoolName[i]= '[';
}
System.arraycopy(className, 0, constantPoolName, dimensions, classNameLength);
frame.addStackItem(new VerificationTypeInfo(0, constantPoolName));
pc+= 4;
break;
case Opcodes.OPC_ifnull:
case Opcodes.OPC_ifnonnull:
frame.numberOfStackItems--;
pc+= 3;
break;
case Opcodes.OPC_goto_w:
pc+= 5;
break;
default: // should not occur
this.codeStream.methodDeclaration.scope.problemReporter().abortDueToInternalError(
Messages.bind(
Messages.abort_invalidOpcode,
new Object[] {
new Byte(opcode),
new Integer(pc),
new String(methodBinding.shortReadableName()),
}),
this.codeStream.methodDeclaration);
break;
}
if (pc >= (codeLength + codeOffset)) {
break;
}
}
}
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));
}
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;
}
}