/*
* Copyright (C) 2014, United States Government, as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All rights reserved.
*
* The Java Pathfinder core (jpf-core) platform is licensed under the
* Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package gov.nasa.jpf.jvm;
import java.io.File;
import gov.nasa.jpf.JPFException;
import gov.nasa.jpf.util.BailOut;
import gov.nasa.jpf.util.BinaryClassSource;
import gov.nasa.jpf.vm.ClassParseException;
/**
* class to read and dissect Java classfile contents (as specified by the Java VM
* spec http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#16628
*/
public class ClassFile extends BinaryClassSource {
public static final int CONSTANT_UTF8 = 1;
public static final int CONSTANT_INTEGER = 3;
public static final int CONSTANT_FLOAT = 4;
public static final int CONSTANT_LONG = 5;
public static final int CONSTANT_DOUBLE = 6;
public static final int CONSTANT_CLASS = 7;
public static final int CONSTANT_STRING = 8;
public static final int FIELD_REF = 9;
public static final int METHOD_REF = 10;
public static final int INTERFACE_METHOD_REF = 11;
public static final int NAME_AND_TYPE = 12;
public static final int METHOD_HANDLE = 15;
public static final int METHOD_TYPE = 16;
public static final int INVOKE_DYNAMIC = 18;
public static final int REF_GETFIELD = 1;
public static final int REF_GETSTATIC = 2;
public static final int REF_PUTFIELD = 3;
public static final int REF_PUTSTATIC = 4;
public static final int REF_INVOKEVIRTUAL = 5;
public static final int REF_INVOKESTATIC = 6;
public static final int REF_INVOKESPECIAL = 7;
public static final int REF_NEW_INVOKESPECIAL = 8;
public static final int REF_INVOKEINTERFACE = 9;
// used to store types in cpValue[]
public static enum CpInfo {
Unused_0, // 0
ConstantUtf8, // 1
Unused_2, // 2
ConstantInteger, // 3
ConstantFloat, // 4
ConstantLong, // 5
ConstantDouble, // 6
ConstantClass, // 7
ConstantString, // 8
FieldRef, // 9
MethodRef, // 10
InterfaceMethodRef, // 11
NameAndType, // 12
Unused_13,
Unused_14,
MethodHandle, // 15
MethodType, // 16
Unused_17,
InvokeDynamic // 18
}
// <2do> this is going away
String requestedTypeName; // the type name that caused this classfile to be loaded
// the const pool
int[] cpPos; // cpPos[i] holds data start index for cp_entry i (0 is unused)
Object[] cpValue; // cpValue[i] hold the String/Integer/Float/Double associated with corresponding cp_entries
//--- ctors
public ClassFile (byte[] data, int offset){
super(data,offset);
}
public ClassFile (byte[] data){
super(data,0);
}
public ClassFile (String typeName, byte[] data){
super(data,0);
this.requestedTypeName = typeName;
}
public ClassFile (String typeName, byte[] data, int offset){
super(data, offset);
this.requestedTypeName = typeName;
}
public ClassFile (File file) throws ClassParseException {
super(file);
}
public ClassFile (String pathName) throws ClassParseException {
super( new File(pathName));
}
/**
* set classfile data. This is mainly provided to allow
* on-the-fly classfile instrumentation with 3rd party libraries
*
* BEWARE - like getData(), this method can cause parsing to fail if the
* provided data does not conform to the VM specs. In particular, this
* method should ONLY be called before executing parse(ClassFileReader) and
* will otherwise throw a JPFException
*/
public void setData(byte[] newData){
if (cpPos != null){
throw new JPFException("concurrent modification of ClassFile data");
}
data = newData;
}
/**
* return the typename this classfile gets loaded for
* <2do> this is going away
*/
public String getRequestedTypeName(){
return requestedTypeName;
}
//--- general attributes
public static final String SYNTHETIC_ATTR = "Synthetic";
public static final String DEPRECATED_ATTR = "Deprecated";
public static final String SIGNATURE_ATTR = "Signature";
public static final String RUNTIME_INVISIBLE_ANNOTATIONS_ATTR = "RuntimeInvisibleAnnotations";
public static final String RUNTIME_VISIBLE_ANNOTATIONS_ATTR = "RuntimeVisibleAnnotations";
public static final String RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR = "RuntimeVisibleTypeAnnotations";
//--- standard field attributes
public static final String CONST_VALUE_ATTR = "ConstantValue";
protected final static String[] stdFieldAttrs = {
CONST_VALUE_ATTR, SYNTHETIC_ATTR, DEPRECATED_ATTR, SIGNATURE_ATTR,
RUNTIME_INVISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR };
//--- standard method attributes
public static final String CODE_ATTR = "Code";
public static final String EXCEPTIONS_ATTR = "Exceptions";
public static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS_ATTR = "RuntimeInvisibleParameterAnnotations";
public static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS_ATTR = "RuntimeVisibleParameterAnnotations";
public static final String ANNOTATIONDEFAULT_ATTR = "AnnotationDefault";
protected final static String[] stdMethodAttrs = {
CODE_ATTR, EXCEPTIONS_ATTR, SYNTHETIC_ATTR, DEPRECATED_ATTR, SIGNATURE_ATTR,
RUNTIME_INVISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_ANNOTATIONS_ATTR,
RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS_ATTR,
RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS_ATTR,
RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR,
ANNOTATIONDEFAULT_ATTR
};
//--- standard code attributes
public static final String LINE_NUMBER_TABLE_ATTR = "LineNumberTable";
public static final String LOCAL_VAR_TABLE_ATTR = "LocalVariableTable";
protected final static String[] stdCodeAttrs = { LINE_NUMBER_TABLE_ATTR, LOCAL_VAR_TABLE_ATTR, RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR };
//--- standard class attributes
public static final String SOURCE_FILE_ATTR = "SourceFile";
public static final String INNER_CLASSES_ATTR = "InnerClasses";
public static final String ENCLOSING_METHOD_ATTR = "EnclosingMethod";
public static final String BOOTSTRAP_METHOD_ATTR = "BootstrapMethods";
protected final static String[] stdClassAttrs = {
SOURCE_FILE_ATTR, DEPRECATED_ATTR, INNER_CLASSES_ATTR, DEPRECATED_ATTR, SIGNATURE_ATTR,
RUNTIME_INVISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR,
ENCLOSING_METHOD_ATTR, BOOTSTRAP_METHOD_ATTR };
protected String internStdAttrName(int cpIdx, String name, String[] stdNames){
for (int i=0; i<stdNames.length; i++){
if (stdNames[i] == name) return name;
}
for (int i=0; i<stdNames.length; i++){
String stdName = stdNames[i];
if (stdName.equals(name)){
cpValue[cpIdx] = stdName;
return stdName;
}
}
return name;
}
//--- constpool access
//--- the primitive info cpValue
public String utf8At(int utf8InfoIdx){
//assert data[cpPos[utf8InfoIdx]] == 1 : "not a utf8_info tag";
return (String) cpValue[utf8InfoIdx];
}
public int intAt(int intInfoIdx){
//assert data[cpPos[intInfoIdx]] == 3 : "not a int_info tag";
return (Integer) cpValue[intInfoIdx];
}
public float floatAt(int floatInfoIdx){
//assert data[cpPos[floatInfoIdx]] == 4 : "not a float_info tag";
return (Float) cpValue[floatInfoIdx];
}
public long longAt(int longInfoIdx){
//assert data[cpPos[longInfoIdx]] == 5 : "not a long_info tag";
return (Long) cpValue[longInfoIdx];
}
public double doubleAt(int doubleInfoIdx){
//assert data[cpPos[doubleInfoIdx]] == 6 : "not a double_info tag";
return (Double) cpValue[doubleInfoIdx];
}
//--- those two are delegated but resolved
public String classNameAt(int classInfoIdx){
//assert data[cpPos[classInfoIdx]] == 7 : "not a Class_info tag";
return (String) cpValue[classInfoIdx];
}
public String stringAt(int stringInfoIdx){
//assert data[cpPos[stringInfoIdx]] == 8 : "not a String_info tag";
return (String) cpValue[stringInfoIdx];
}
//--- composite infos
// the generic ones (if we don't care what kind of reference type this is)
public String refClassNameAt(int cpIdx){
return (String) cpValue[ u2(cpPos[cpIdx]+1)];
}
public String refNameAt(int cpIdx){
return utf8At( u2( cpPos[ u2(cpPos[cpIdx]+3)]+1));
}
public String refDescriptorAt(int cpIdx){
return utf8At( u2( cpPos[ u2(cpPos[cpIdx]+3)]+3));
}
public int mhRefTypeAt (int methodHandleInfoIdx){
return u1(cpPos[methodHandleInfoIdx]+1);
}
public int mhMethodRefIndexAt (int methodHandleInfoIdx){
return u2(cpPos[methodHandleInfoIdx]+2);
}
// those could check ref types
public String fieldClassNameAt(int fieldRefInfoIdx){
//assert data[cpPos[fieldRefInfoIdx]] == 9 : "not a Fieldref_info tag";
return (String) cpValue[ u2(cpPos[fieldRefInfoIdx]+1)];
}
public String fieldNameAt(int fieldRefInfoIdx){
return utf8At( u2( cpPos[ u2(cpPos[fieldRefInfoIdx]+3)]+1));
}
public String fieldDescriptorAt(int fieldRefInfoIdx){
return utf8At( u2( cpPos[ u2(cpPos[fieldRefInfoIdx]+3)]+3));
}
public String methodClassNameAt(int methodRefInfoIdx){
return (String) cpValue[ u2(cpPos[methodRefInfoIdx]+1)];
}
public String methodNameAt(int methodRefInfoIdx){
return utf8At( u2( cpPos[ u2(cpPos[methodRefInfoIdx]+3)]+1));
}
public String methodDescriptorAt(int methodRefInfoIdx){
return utf8At( u2( cpPos[ u2(cpPos[methodRefInfoIdx]+3)]+3));
}
public String methodTypeDescriptorAt (int methodTypeInfoIdx){
return utf8At( u2(cpPos[methodTypeInfoIdx]+1));
}
public String interfaceMethodClassNameAt(int ifcMethodRefInfoIdx){
return (String) cpValue[ u2(cpPos[ifcMethodRefInfoIdx]+1)];
}
public String interfaceMethodNameAt(int ifcMethodRefInfoIdx){
return utf8At( u2( cpPos[ u2(cpPos[ifcMethodRefInfoIdx]+3)]+1));
}
public String interfaceMethodDescriptorAt(int ifcMethodRefInfoIdx){
return utf8At( u2( cpPos[ u2(cpPos[ifcMethodRefInfoIdx]+3)]+3));
}
public int bootstrapMethodIndex (int cpInvokeDynamicIndex){
return u2(cpPos[cpInvokeDynamicIndex]+1);
}
public String samMethodNameAt(int cpInvokeDynamicIndex) {
return utf8At( u2( cpPos[ u2(cpPos[cpInvokeDynamicIndex]+3)]+1));
}
public String callSiteDescriptor(int cpInvokeDynamicIndex) {
return utf8At( u2( cpPos[ u2(cpPos[cpInvokeDynamicIndex]+3)]+3));
}
public String getRefTypeName (int refCode){
switch (refCode){
case REF_GETFIELD: return "getfield";
case REF_GETSTATIC: return "getstatic";
case REF_PUTFIELD: return "putfield";
case REF_PUTSTATIC: return "putstatic";
case REF_INVOKEVIRTUAL: return "invokevirtual";
case REF_INVOKESTATIC: return "invokestatic";
case REF_INVOKESPECIAL: return "invokespecial";
case REF_NEW_INVOKESPECIAL: return "new-invokespecial";
case REF_INVOKEINTERFACE: return "invokeinterface";
default:
return "<unknown>";
}
}
public String getTypeName (int typeCode){
switch(typeCode){
case 4: return "boolean";
case 5: return "char";
case 6: return "float";
case 7: return "double";
case 8: return "byte";
case 9: return "short";
case 10: return "int";
case 11: return "long";
default:
return "<unknown>";
}
}
@Override
public int getPos(){
return pos;
}
public int getPc(){
return pc;
}
//--- traverse/analyze the const pool (this is rather exotic)
public int getNumberOfCpEntries(){
return cpValue.length;
}
public Object getCpValue (int i){
return cpValue[i];
}
public int getCpTag (int i){
return data[cpPos[i]];
}
/**
* the result can be used as input for u2(dataIndex)
*
* NOTE - this returns -1 for the dreaded unused extra entries associated
* with ConstantDouble and ConstantLong
*/
public int getDataPosOfCpEntry (int i){
return cpPos[i];
}
//--- standard attributes
public Object getConstValueAttribute(int dataPos){
int cpIdx = u2(dataPos);
Object v = cpValue[cpIdx];
return v;
}
public String getSourceFileAttribute(int dataPos){
// SourceFile_attribute { u2 attr_name_idx; u4 attr_length; u2 sourcefile_idx<utf8>; }
int cpIdx = u2(dataPos + 6);
Object v = cpValue[cpIdx];
return (String)v;
}
//--- low level readers
public final int u1(int dataIdx){
return data[dataIdx] & 0xff;
}
public final int u2(int dataIdx){
return ((data[dataIdx]&0xff) << 8) | (data[dataIdx+1]&0xff);
}
public final int i1(int dataIdx) {
return data[dataIdx++];
}
public final int i2(int dataIdx) {
int idx = dataIdx;
return (data[idx++] << 8) | (data[idx]&0xff);
}
public final int readU2(){
int idx = pos;
pos += 2;
return ((data[idx++]&0xff) << 8) | (data[idx]&0xff);
}
public final int readI2() {
int idx = pos;
pos += 2;
return (data[idx++] << 8) | (data[idx]&0xff);
}
public final int readI4(){
int idx = pos;
pos += 4;
byte[] data = this.data;
return (data[idx++] <<24) | ((data[idx++]&0xff) << 16) | ((data[idx++]&0xff) << 8) | (data[idx]&0xff);
}
//--- reader notifications
private void setClass(ClassFileReader reader, String clsName, String superClsName, int flags, int cpCount) throws ClassParseException {
int p = pos;
reader.setClass( this, clsName, superClsName, flags, cpCount);
pos = p;
}
private void setInterfaceCount(ClassFileReader reader, int ifcCount){
int p = pos;
reader.setInterfaceCount( this, ifcCount);
pos = p;
}
private void setInterface(ClassFileReader reader, int ifcIndex, String ifcName){
int p = pos;
reader.setInterface( this, ifcIndex, ifcName);
pos = p;
}
private void setInterfacesDone(ClassFileReader reader){
int p = pos;
reader.setInterfacesDone( this);
pos = p;
}
private void setFieldCount(ClassFileReader reader, int fieldCount){
int p = pos;
reader.setFieldCount( this, fieldCount);
pos = p;
}
private void setField(ClassFileReader reader, int fieldIndex, int accessFlags, String name, String descriptor){
int p = pos;
reader.setField( this, fieldIndex, accessFlags, name, descriptor);
pos = p;
}
private void setFieldAttributeCount(ClassFileReader reader, int fieldIndex, int attrCount){
int p = pos;
reader.setFieldAttributeCount( this, fieldIndex, attrCount);
pos = p;
}
private void setFieldAttribute(ClassFileReader reader, int fieldIndex, int attrIndex, String name, int attrLength){
int p = pos + attrLength;
reader.setFieldAttribute( this, fieldIndex, attrIndex, name, attrLength);
pos = p;
}
private void setFieldAttributesDone(ClassFileReader reader, int fieldIndex){
int p = pos;
reader.setFieldAttributesDone( this, fieldIndex);
pos = p;
}
private void setFieldDone(ClassFileReader reader, int fieldIndex){
int p = pos;
reader.setFieldDone( this, fieldIndex);
pos = p;
}
private void setFieldsDone(ClassFileReader reader){
int p = pos;
reader.setFieldsDone( this);
pos = p;
}
private void setConstantValue(ClassFileReader reader, Object tag, Object value){
int p = pos;
reader.setConstantValue( this, tag, value);
pos = p;
}
private void setMethodCount(ClassFileReader reader, int methodCount){
int p = pos;
reader.setMethodCount( this, methodCount);
pos = p;
}
private void setMethod(ClassFileReader reader, int methodIndex, int accessFlags, String name, String descriptor){
int p = pos;
reader.setMethod( this, methodIndex, accessFlags, name, descriptor);
pos = p;
}
private void setMethodAttributeCount(ClassFileReader reader, int methodIndex, int attrCount){
int p = pos;
reader.setMethodAttributeCount( this, methodIndex, attrCount);
pos = p;
}
private void setMethodAttribute(ClassFileReader reader, int methodIndex, int attrIndex, String name, int attrLength){
int p = pos + attrLength;
reader.setMethodAttribute( this, methodIndex, attrIndex, name, attrLength);
pos = p;
}
private void setMethodAttributesDone(ClassFileReader reader, int methodIndex){
int p = pos;
reader.setMethodAttributesDone( this, methodIndex);
pos = p;
}
private void setMethodDone(ClassFileReader reader, int methodIndex){
int p = pos;
reader.setMethodDone( this, methodIndex);
pos = p;
}
private void setMethodsDone(ClassFileReader reader){
int p = pos;
reader.setMethodsDone( this);
pos = p;
}
private void setExceptionCount(ClassFileReader reader, Object tag, int exceptionCount){
int p = pos;
reader.setExceptionCount( this, tag, exceptionCount);
pos = p;
}
private void setExceptionsDone(ClassFileReader reader, Object tag){
int p = pos;
reader.setExceptionsDone( this, tag);
pos = p;
}
private void setException(ClassFileReader reader, Object tag, int exceptionIndex, String exceptionType){
int p = pos;
reader.setException( this, tag, exceptionIndex, exceptionType);
pos = p;
}
private void setCode(ClassFileReader reader, Object tag, int maxStack, int maxLocals, int codeLength){
int p = pos + codeLength;
reader.setCode( this, tag, maxStack, maxLocals, codeLength);
pos = p;
}
private void setExceptionTableCount(ClassFileReader reader, Object tag, int exceptionTableCount){
int p = pos;
reader.setExceptionHandlerTableCount( this, tag, exceptionTableCount);
pos = p;
}
private void setExceptionTableEntry(ClassFileReader reader, Object tag, int exceptionIndex,
int startPc, int endPc, int handlerPc, String catchType){
int p = pos;
reader.setExceptionHandler( this, tag, exceptionIndex, startPc, endPc, handlerPc, catchType);
pos = p;
}
private void setExceptionTableDone(ClassFileReader reader, Object tag){
int p = pos;
reader.setExceptionHandlerTableDone( this, tag);
pos = p;
}
private void setCodeAttributeCount(ClassFileReader reader, Object tag, int attrCount){
int p = pos;
reader.setCodeAttributeCount( this, tag, attrCount);
pos = p;
}
private void setCodeAttribute(ClassFileReader reader, Object tag, int attrIndex, String name, int attrLength){
int p = pos + attrLength;
reader.setCodeAttribute( this, tag, attrIndex, name, attrLength);
pos = p;
}
private void setCodeAttributesDone(ClassFileReader reader, Object tag){
int p = pos;
reader.setCodeAttributesDone( this, tag);
pos = p;
}
private void setLineNumberTableCount(ClassFileReader reader, Object tag, int lineNumberCount){
int p = pos;
reader.setLineNumberTableCount( this, tag, lineNumberCount);
pos = p;
}
private void setLineNumber(ClassFileReader reader, Object tag, int lineIndex, int lineNumber, int startPc){
int p = pos;
reader.setLineNumber( this, tag, lineIndex, lineNumber, startPc);
pos = p;
}
private void setLineNumberTableDone(ClassFileReader reader, Object tag){
int p = pos;
reader.setLineNumberTableDone( this, tag);
pos = p;
}
private void setLocalVarTableCount(ClassFileReader reader, Object tag, int localVarCount){
int p = pos;
reader.setLocalVarTableCount( this, tag, localVarCount);
pos = p;
}
private void setLocalVar(ClassFileReader reader, Object tag, int localVarIndex, String varName, String descriptor,
int scopeStartPc, int scopeEndPc, int slotIndex){
int p = pos;
reader.setLocalVar( this, tag, localVarIndex, varName, descriptor, scopeStartPc, scopeEndPc, slotIndex);
pos = p;
}
private void setLocalVarTableDone(ClassFileReader reader, Object tag){
int p = pos;
reader.setLocalVarTableDone( this, tag);
pos = p;
}
private void setClassAttributeCount(ClassFileReader reader, int attrCount){
int p = pos;
reader.setClassAttributeCount( this, attrCount);
pos = p;
}
private void setClassAttribute(ClassFileReader reader, int attrIndex, String name, int attrLength){
int p = pos + attrLength;
reader.setClassAttribute( this, attrIndex, name, attrLength);
pos = p;
}
private void setClassAttributesDone(ClassFileReader reader){
int p = pos;
reader.setClassAttributesDone(this);
pos = p;
}
private void setSourceFile(ClassFileReader reader, Object tag, String pathName){
int p = pos;
reader.setSourceFile( this, tag, pathName);
pos = p;
}
private void setBootstrapMethodCount (ClassFileReader reader, Object tag, int bootstrapMethodCount){
int p = pos;
reader.setBootstrapMethodCount( this, tag, bootstrapMethodCount);
pos = p;
}
private void setBootstrapMethod (ClassFileReader reader, Object tag, int idx,
int refKind, String cls, String mth, String descriptor, int[] cpArgs){
int p = pos;
reader.setBootstrapMethod( this, tag, idx, refKind, cls, mth, descriptor, cpArgs);
pos = p;
}
private void setBootstrapMethodsDone (ClassFileReader reader, Object tag){
int p = pos;
reader.setBootstrapMethodsDone( this, tag);
pos = p;
}
private void setInnerClassCount(ClassFileReader reader, Object tag, int innerClsCount){
int p = pos;
reader.setInnerClassCount( this, tag, innerClsCount);
pos = p;
}
private void setInnerClass(ClassFileReader reader, Object tag, int innerClsIndex, String outerName, String innerName,
String innerSimpleName, int accessFlags){
int p = pos;
reader.setInnerClass( this, tag, innerClsIndex, outerName, innerName, innerSimpleName, accessFlags);
pos = p;
}
private void setEnclosingMethod(ClassFileReader reader, Object tag, String enclosingClass, String enclosedMethod, String descriptor){
int p = pos;
reader.setEnclosingMethod( this, tag, enclosingClass, enclosedMethod, descriptor);
pos = p;
}
private void setInnerClassesDone(ClassFileReader reader, Object tag){
int p = pos;
reader.setInnerClassesDone(this, tag);
pos = p;
}
private void setAnnotationCount(ClassFileReader reader, Object tag, int annotationCount){
int p = pos;
reader.setAnnotationCount( this, tag, annotationCount);
pos = p;
}
private void setAnnotation(ClassFileReader reader, Object tag, int annotationIndex, String annotationType){
int p = pos;
reader.setAnnotation( this, tag, annotationIndex, annotationType);
pos = p;
}
private void setAnnotationsDone(ClassFileReader reader, Object tag){
int p = pos;
reader.setAnnotationsDone(this, tag);
pos = p;
}
private void setTypeAnnotationCount(ClassFileReader reader, Object tag, int annotationCount){
int p = pos;
reader.setTypeAnnotationCount( this, tag, annotationCount);
pos = p;
}
private void setTypeAnnotationsDone(ClassFileReader reader, Object tag){
int p = pos;
reader.setTypeAnnotationsDone(this, tag);
pos = p;
}
private void setAnnotationValueCount(ClassFileReader reader, Object tag, int annotationIndex, int nValuePairs){
int p = pos;
reader.setAnnotationValueCount( this, tag, annotationIndex, nValuePairs);
pos = p;
}
private void setPrimitiveAnnotationValue(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex,
String elementName, int arrayIndex, Object val){
int p = pos;
reader.setPrimitiveAnnotationValue( this, tag, annotationIndex, valueIndex, elementName, arrayIndex, val);
pos = p;
}
private void setStringAnnotationValue(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex,
String elementName, int arrayIndex, String s){
int p = pos;
reader.setStringAnnotationValue( this, tag, annotationIndex, valueIndex, elementName, arrayIndex, s);
pos = p;
}
private void setClassAnnotationValue(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex,
String elementName, int arrayIndex, String typeName){
int p = pos;
reader.setClassAnnotationValue( this, tag, annotationIndex, valueIndex, elementName, arrayIndex, typeName);
pos = p;
}
private void setEnumAnnotationValue(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex,
String elementName, int arrayIndex, String enumType, String enumValue){
int p = pos;
reader.setEnumAnnotationValue( this, tag, annotationIndex, valueIndex, elementName, arrayIndex, enumType, enumValue);
pos = p;
}
private void setAnnotationValueElementCount(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex,
String elementName, int elementCount){
int p = pos;
reader.setAnnotationValueElementCount(this, tag, annotationIndex, valueIndex, elementName, elementCount);
pos = p;
}
private void setAnnotationValueElementsDone(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex,
String elementName){
int p = pos;
reader.setAnnotationValueElementsDone(this, tag, annotationIndex, valueIndex, elementName);
pos = p;
}
public void setAnnotationValuesDone(ClassFileReader reader, Object tag, int annotationIndex){
int p = pos;
reader.setAnnotationValuesDone(this, tag, annotationIndex);
pos = p;
}
private void setParameterCount(ClassFileReader reader, Object tag, int parameterCount){
int p = pos;
reader.setParameterCount(this, tag, parameterCount);
pos = p;
}
private void setParameterAnnotationCount(ClassFileReader reader, Object tag, int paramIndex, int annotationCount){
int p = pos;
reader.setParameterAnnotationCount(this, tag, paramIndex, annotationCount);
pos = p;
}
private void setParameterAnnotation(ClassFileReader reader, Object tag, int annotationIndex, String annotationType){
int p = pos;
reader.setParameterAnnotation( this, tag, annotationIndex, annotationType);
pos = p;
}
private void setParameterAnnotationsDone(ClassFileReader reader, Object tag, int paramIndex){
int p = pos;
reader.setParameterAnnotationsDone(this, tag, paramIndex);
pos = p;
}
private void setParametersDone(ClassFileReader reader, Object tag){
int p = pos;
reader.setParametersDone(this, tag);
pos = p;
}
public void setSignature(ClassFileReader reader, Object tag, String signature){
int p = pos;
reader.setSignature(this, tag, signature);
pos = p;
}
//--- parsing
/**
* this is the main parsing routine that uses the ClassFileReader interface
* to tell clients about the classfile contents
*
* ClassFile structure: http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#74353
* u4 magic; // 0xcafebabe
* u2 minor_version;
* u2 major_version;
*
* u2 constant_pool_count;
* cp_entry constant_pool[constant_pool_count-1];
* u2 access_flags;
*
* u2 this_class;
* u2 super_class;
*
* u2 interfaces_count;
* u2 interfaces[interfaces_count];
*
* u2 fields_count;
* field_info fields[fields_count];
*
* u2 methods_count;
* method_info methods[methods_count];
*
* u2 attributes_count;
* attribute_info attributes[attributes_count];
*/
public void parse( ClassFileReader reader) throws ClassParseException {
int cpIdx;
try {
// yeah, cafebabe
int magic = readI4();
if (magic != 0xCAFEBABE) {
error("wrong magic: " + Integer.toHexString(magic));
}
// we don't do much with the version numbers yet
int minor = readU2();
int major = readU2();
// get the const pool
int cpCount = readU2();
cpPos = new int[cpCount];
cpValue = new Object[cpCount];
parseCp(cpCount);
// the class essentials
int accessFlags = readU2();
cpIdx = readU2();
String clsName = (String) cpValue[cpIdx];
cpIdx = readU2();
String superClsName = (String) cpValue[cpIdx];
setClass(reader, clsName, superClsName, accessFlags, cpCount);
// interfaces
int ifcCount = readU2();
parseInterfaces(reader, ifcCount);
// fields
int fieldCount = readU2();
parseFields(reader, fieldCount);
// methods
int methodCount = readU2();
parseMethods(reader, methodCount);
// class attributes
int classAttrCount = readU2();
parseClassAttributes(reader, classAttrCount);
} catch (BailOut x){
// nothing, just a control exception to shortcut the classfile parsing
}
}
//--- constpool parsing
public static String readModifiedUTF8String( byte[] data, int pos, int len) throws ClassParseException {
int n = 0; // the number of chars in buf
char[] buf = new char[len]; // it can't be more, but it can be less chars
// \u0001 - \u007f : single byte chars: 0xxxxxxx
// \u0000 and \u0080 - \u07ff : double byte chars: 110xxxxx, 10xxxxxx
// \u0800 - \uffff : tripple byte chars: 1110xxxx, 10xxxxxx, 10xxxxxx
int max = pos+len;
for (int i=pos; i<max; i++){
int c = data[i] & 0xff;
if ((c & 0x80) == 0){ // single byte char 0xxxxxxx
buf[n++] = (char)c;
} else {
if ((c & 0x40) != 0){ // 11xxxxxx
// for the sake of efficiency, we don't check for the trailing zero bit in the marker,
// we just mask it out
if ((c & 0x20) == 0) { // 110xxxxx - double byte char
buf[n++] = (char) (((c & 0x1f) << 6) | (data[++i] & 0x3f));
} else { // 1110xxxx - tripple byte char
buf[n++] = (char) (((c & 0x0f) << 12) | ((data[++i] & 0x3f) << 6) | (data[++i] & 0x3f));
}
} else {
throw new ClassParseException("malformed modified UTF-8 input: ");
}
}
}
return new String(buf, 0, n);
}
// the protected methods are called automatically, the public parse..Attr() methods
// are called optionally from the corresponding ClassFileReader.set..Attribute() method.
// Note that these calls have to provide the ClassFileReader as an argument because
// we might actually switch to another reader (e.g. MethodInfos for parseCodeAttr)
protected void parseCp(int cpCount) throws ClassParseException {
int j = pos;
byte[] data = this.data;
int[] dataIdx = this.cpPos;
Object[] values = this.cpValue;
//--- first pass: store data index values and convert non-delegating constant values
// cp_entry[0] is traditionally unused
for (int i=1; i<cpCount; i++) {
switch (data[j]){
case 0:
error("illegal constpool tag");
case CONSTANT_UTF8: // utf8_info { u1 tag; u2 length; u1 bytes[length]; }
dataIdx[i] = j++;
int len = ((data[j++]&0xff) <<8) | (data[j++]&0xff);
String s = readModifiedUTF8String( data, j, len);
values[i] = s;
j += len;
break;
case 2:
error("illegal constpool tag");
case CONSTANT_INTEGER: // Integer_info { u1 tag; u4 bytes; }
dataIdx[i] = j++;
int iVal = (data[j++]&0xff)<<24 | (data[j++]&0xff)<<16 | (data[j++]&0xff)<<8 | (data[j++]&0xff);
values[i] = new Integer(iVal);
break;
case CONSTANT_FLOAT: // Float_info { u1 tag; u4 bytes; }
dataIdx[i] = j++;
int iBits = (data[j++]&0xff)<<24 | (data[j++]&0xff)<<16 | (data[j++]&0xff)<<8 | (data[j++]&0xff);
float fVal = Float.intBitsToFloat(iBits);
values[i] = new Float(fVal);
break;
case CONSTANT_LONG: // Long_info { u1 tag; u4 high_bytes; u4 low_bytes; }
dataIdx[i] = j++;
long lVal = (data[j++]&0xffL)<<56 | (data[j++]&0xffL)<<48 | (data[j++]&0xffL)<<40 | (data[j++]&0xffL)<<32
| (data[j++]&0xffL)<<24 | (data[j++]&0xffL)<<16 | (data[j++]&0xffL)<<8 | (data[j++]&0xffL);
values[i] = new Long(lVal);
dataIdx[++i] = -1; // 8 byte cpValue occupy 2 index slots
break;
case CONSTANT_DOUBLE: // Double_info { u1 tag; u4 high_bytes; u4 low_bytes; }
dataIdx[i] = j++;
long lBits = (data[j++]&0xffL)<<56 | (data[j++]&0xffL)<<48 | (data[j++]&0xffL)<<40 | (data[j++]&0xffL)<<32
| (data[j++]&0xffL)<<24 | (data[j++]&0xffL)<<16 | (data[j++]&0xffL)<<8 | (data[j++]&0xffL);
double dVal = Double.longBitsToDouble(lBits);
values[i] = new Double(dVal);
dataIdx[++i] = -1; // 8 byte cpValue occupy 2 index slots
break;
case CONSTANT_CLASS: // Class_info { u1 tag; u2 name_index<utf8>; }
dataIdx[i] = j;
values[i] = CpInfo.ConstantClass;
j += 3;
break;
case CONSTANT_STRING: // String_info { u1 tag; u2 string_index<utf8>; }
dataIdx[i] = j;
values[i] = CpInfo.ConstantString;
j += 3;
break;
case FIELD_REF: // Fieldref_info { u1 tag; u2 class_index; u2 name_and_type_index; }
dataIdx[i] = j;
values[i] = CpInfo.FieldRef;
j += 5;
break;
case METHOD_REF: // Methodref_info { u1 tag; u2 class_index; u2 name_and_type_index; }
dataIdx[i] = j;
values[i] = CpInfo.MethodRef;
j += 5;
break;
case INTERFACE_METHOD_REF: // InterfaceMethodref_info { u1 tag; u2 class_index; u2 name_and_type_index; }
dataIdx[i] = j;
values[i] = CpInfo.InterfaceMethodRef;
j += 5;
break;
case NAME_AND_TYPE: // NameAndType_info { u1 tag; u2 name_index<utf8>; u2 descriptor_index<utf8>; }
dataIdx[i] = j;
values[i] = CpInfo.NameAndType;
j += 5;
break;
//--- the Java 8 ones
case METHOD_HANDLE: // MethodHandle_info { u1 tag; u1 reference_kind; u2 reference_index<mthref>; }
dataIdx[i] = j;
values[i] = CpInfo.MethodHandle;
j += 4;
break;
case METHOD_TYPE: // MethodType_info { u1 tag; u2 descriptor_index<utf8>; }
dataIdx[i] = j;
values[i] = CpInfo.MethodType;
j += 3;
break;
case INVOKE_DYNAMIC: // InvokeDynamic_info { u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index; }
dataIdx[i] = j;
values[i] = CpInfo.InvokeDynamic;
j += 5;
break;
default:
error("illegal constpool tag: " + data[j]);
}
}
pos = j;
//--- second pass: store values of delegating constant values
for (int i=1; i<cpCount; i++){
Object v = cpValue[i];
// we store string and class constants as their utf8 string values
if (v == CpInfo.ConstantClass || v == CpInfo.ConstantString){
cpValue[i] = cpValue[u2(cpPos[i]+1)];
}
}
}
protected void parseInterfaces(ClassFileReader reader, int ifcCount){
setInterfaceCount(reader, ifcCount);
for (int i=0; i<ifcCount; i++){
int cpIdx = readU2();
setInterface(reader, i, classNameAt(cpIdx));
}
setInterfacesDone(reader);
}
//--- fields
protected void parseFields(ClassFileReader reader, int fieldCount) {
setFieldCount(reader, fieldCount);
for (int i=0; i<fieldCount; i++){
int accessFlags = readU2();
int cpIdx = readU2();
String name = utf8At(cpIdx);
cpIdx = readU2();
String descriptor = utf8At(cpIdx);
setField(reader, i, accessFlags, name, descriptor);
int attrCount = readU2();
parseFieldAttributes(reader, i, attrCount);
setFieldDone(reader, i);
}
setFieldsDone(reader);
}
protected void parseFieldAttributes(ClassFileReader reader, int fieldIdx, int attrCount){
setFieldAttributeCount(reader, fieldIdx, attrCount);
for (int i=0; i<attrCount; i++){
int cpIdx = readU2();
String name = utf8At(cpIdx);
name = internStdAttrName(cpIdx, name, stdFieldAttrs);
int attrLength = readI4(); // actually U4, but we don't support 2GB attributes
setFieldAttribute(reader, fieldIdx, i, name, attrLength);
}
setFieldAttributesDone(reader, fieldIdx);
}
/**
* optionally called by reader to obtain a ConstantValue field attribute
*
* ConstantValue {u2 attrName<utf8>; u4 attrLength; u2 constIndex<class|string|int|float|long|double> }
*
* pos is at constIndex
*/
public void parseConstValueAttr(ClassFileReader reader, Object tag){
int cpIdx = readU2();
setConstantValue(reader, tag, cpValue[cpIdx]);
}
//--- methods
protected void parseMethods(ClassFileReader reader, int methodCount) {
setMethodCount(reader, methodCount);
for (int i=0; i<methodCount; i++){
int accessFlags = readU2();
int cpIdx = readU2();
String name = utf8At(cpIdx);
cpIdx = readU2();
String descriptor = utf8At(cpIdx);
setMethod(reader, i, accessFlags, name, descriptor);
int attrCount = readU2();
parseMethodAttributes(reader, i, attrCount);
setMethodDone(reader, i);
}
setMethodsDone(reader);
}
protected void parseMethodAttributes(ClassFileReader reader, int methodIdx, int attrCount){
setMethodAttributeCount(reader, methodIdx, attrCount);
for (int i=0; i<attrCount; i++){
int cpIdx = readU2();
String name = utf8At(cpIdx);
name = internStdAttrName(cpIdx, name, stdMethodAttrs);
int attrLength = readI4(); // actually U4, but we don't support 2GB attributes
setMethodAttribute(reader, methodIdx, i, name, attrLength);
}
setMethodAttributesDone(reader, methodIdx);
}
public void parseExceptionAttr (ClassFileReader reader, Object tag){
int exceptionCount = readU2();
setExceptionCount(reader, tag, exceptionCount);
for (int i=0; i<exceptionCount; i++){
int cpIdx = readU2();
String exceptionType = classNameAt(cpIdx);
setException(reader, tag, i, exceptionType);
}
setExceptionsDone(reader, tag);
}
/**
* (optionally) called by reader from within the setMethodAttribute() notification
* This means we have recursive notification since this is a variable length
* attribute that has variable length attributes
*
* Code_attribute { u2 attr_name_index<utf8>; u4 attr_length;
* u2 max_stack; u2 max_locals;
* u4 code_length; u1 code[code_length];
* u2 exception_table_length;
* { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type<class_entry>;
* } exception_table[exception_table_length];
* u2 attributes_count;
* attribute_info attributes[attributes_count]; }
*
* pos is at max_stack
*/
public void parseCodeAttr (ClassFileReader reader, Object tag){
int maxStack = readU2();
int maxLocals = readU2();
int codeLength = readI4(); // no code length > 2GB supported
int codeStartPos = pos;
setCode(reader, tag, maxStack, maxLocals, codeLength);
int exceptionCount = readU2();
setExceptionTableCount(reader, tag, exceptionCount);
for (int i = 0; i < exceptionCount; i++) {
int startPc = readU2();
int endPc = readU2();
int handlerPc = readU2();
int cpIdx = readU2();
String catchType = (String) cpValue[cpIdx]; // a Constant_class
setExceptionTableEntry(reader, tag, i, startPc, endPc, handlerPc, catchType);
}
setExceptionTableDone(reader, tag);
int attrCount = readU2();
parseCodeAttrAttributes(reader, tag, attrCount);
}
protected void parseCodeAttrAttributes(ClassFileReader reader, Object tag, int attrCount){
setCodeAttributeCount(reader, tag, attrCount);
for (int i=0; i<attrCount; i++){
int cpIdx = readU2();
String name = utf8At(cpIdx);
name = internStdAttrName(cpIdx, name, stdCodeAttrs);
int attrLength = readI4(); // actually U4, but we don't support 2GB attributes
setCodeAttribute(reader, tag, i, name, attrLength);
}
setCodeAttributesDone(reader, tag);
}
/**
* optionally called from ClassFileReader.setCodeAttribute() to parse LineNumberTables
* LineNumberTable { u2 attrName; u4 attrLength;
* u2 lineCount;
* { u2 startPc; u2 lineNumber; } [lineCount] };
* pos is at lineCount
*/
public void parseLineNumberTableAttr(ClassFileReader reader, Object tag){
int lineCount = readU2();
setLineNumberTableCount(reader, tag, lineCount);
for (int i=0; i<lineCount; i++){
int startPc = readU2();
int lineNumber = readU2();
setLineNumber(reader, tag, i, lineNumber, startPc);
}
setLineNumberTableDone(reader, tag);
}
/**
* optionally called from ClassFileReader.setCodeAttribute() to parse LocalVarTables
* LocalVarTableTable { u2 attrName; u4 attrLength;
* u2 localVarCount;
* { u2 startPc; u2 lineNumber; } [lineCount] };
* pos is at localVarCount
*/
public void parseLocalVarTableAttr(ClassFileReader reader, Object tag){
int localVarCount = readU2();
setLocalVarTableCount(reader, tag, localVarCount);
for (int i=0; i<localVarCount; i++){
int startPc = readU2();
int length = readU2();
int cpIdx = readU2();
String varName = (String) cpValue[cpIdx];
cpIdx = readU2();
String descriptor = (String) cpValue[cpIdx];
int slotIndex = readU2();
setLocalVar(reader, tag, i, varName, descriptor, startPc, startPc+length-1, slotIndex );
}
setLocalVarTableDone(reader, tag);
}
//--- class
protected void parseClassAttributes(ClassFileReader reader, int attrCount){
setClassAttributeCount(reader, attrCount);
for (int i=0; i<attrCount; i++){
int cpIdx = readU2();
String name = utf8At(cpIdx);
name = internStdAttrName(cpIdx, name, stdClassAttrs);
int attrLength = readI4(); // actually U4, but we don't support 2GB attributes
setClassAttribute(reader, i, name, attrLength);
}
setClassAttributesDone(reader);
}
/**
* (optionally) called by ClassFileReader from within setClassAttribute() notification
*
* InnerClass { u2 nameIdx<utf8>; u4 length; u2 sourceFile<utf8>; }
*/
public void parseSourceFileAttr(ClassFileReader reader, Object tag){
int cpIdx = readU2();
String pathName = utf8At(cpIdx);
setSourceFile(reader, tag, pathName);
}
/**
* (optionally) called by ClassFileReader from within setClassAttribute() notification
*
* InnerClass {
* u2 nameIdx<utf8>;
* u4 length;
* u2 classCount;
* { u2 innerCls<cls>;
* u2 outerCls<cls>;
* u2 innerName<utf8>;
* u2 innerAccessFlags;
* } classes[classCount] }
* }
*
* pos is at classCount
*/
public void parseInnerClassesAttr(ClassFileReader reader, Object tag){
int innerClsCount = readU2();
setInnerClassCount(reader, tag, innerClsCount);
for (int i = 0; i < innerClsCount; i++) {
int cpIdx = readU2();
String innerClsName = (cpIdx != 0) ? (String) cpValue[cpIdx] : null;
cpIdx = readU2();
String outerClsName = (cpIdx != 0) ? (String) cpValue[cpIdx] : null;
cpIdx = readU2();
String innerSimpleName = (cpIdx != 0) ? (String) cpValue[cpIdx] : null;
int accessFlags = readU2();
setInnerClass(reader, tag, i, outerClsName, innerClsName, innerSimpleName, accessFlags);
}
setInnerClassesDone(reader, tag);
}
/**
* EnclosingMethod_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 class_index -> Class_info { u1 tag; u2 name_index->utf8 }
* u2 method_index -> NameAndType_info { u1 tag; u2 name_index->utf8; u2 descriptor_index->utf8 }
* }
*/
public void parseEnclosingMethodAttr(ClassFileReader reader, Object tag){
String enclosedMethod = null;
String descriptor = null;
int cpIdx = readU2(); // start of Class_info
String enclosingClass = nameAt(cpIdx);
cpIdx = readU2(); // start of NameAndType_info
// check if this is inside a method - we also get EnclosingMethod_infos for
// classes that are not immediately enclosed
if (cpIdx != 0){
enclosedMethod = nameAt(cpIdx);
descriptor = descriptorAt(cpIdx);
}
setEnclosingMethod(reader, tag, enclosingClass, enclosedMethod, descriptor);
}
/**
* BootstrapMethods_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 num_bootstrap_methods;
* { u2 bootstrap_method_ref; -> MethodHandle
* u2 num_bootstrap_arguments;
* u2 bootstrap_arguments[num_bootstrap_arguments];
* } bootstrap_methods[num_bootstrap_methods];
* }
*
* pos is at num_bootstrap_methods
*/
public void parseBootstrapMethodAttr (ClassFileReader reader, Object tag){
int nBootstrapMethods = readU2();
setBootstrapMethodCount(reader, tag, nBootstrapMethods);
for (int i=0; i<nBootstrapMethods; i++){
int cpMhIdx = readU2();
int nArgs = readU2();
int[] bmArgs = new int[nArgs];
for (int j=0; j<nArgs; j++){
bmArgs[j] = readU2();
}
// kind of this method handle
int refKind = mhRefTypeAt(cpMhIdx);
// CONSTANT_Methodref_info structure
int mrefIdx = mhMethodRefIndexAt(cpMhIdx);
String clsName = methodClassNameAt(mrefIdx);
String mthName = methodNameAt(mrefIdx);
String descriptor = methodDescriptorAt(mrefIdx);
setBootstrapMethod(reader, tag, i, refKind, clsName, mthName, descriptor, bmArgs);
}
setBootstrapMethodsDone( reader, tag);
}
String nameAt(int nameTypeInfoIdx) {
return utf8At(u2(cpPos[nameTypeInfoIdx] + 1));
}
String descriptorAt (int nameTypeInfoIdx){
return utf8At( u2( cpPos[nameTypeInfoIdx]+3));
}
// those are as per http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf
/*
* element_value {
* u1 tag;
* union {
* u2 const_value_index;
* { u2 type_name_index; u2 const_name_index; } enum_const_value;
* u2 class_info_index;
* annotation annotation_value;
* { u2 num_values; element_value values[num_values]; } array_value;
* } value;
* }
* valid tags are primitve type codes B,C,D,F,I,J,S,Z
* plus: 's'=String, 'e'=enum, 'c'=class, '@'=annotation, '['=array
*/
void parseAnnotationValue(ClassFileReader reader, Object tag, int annotationIndex, int valueIndex, String elementName, int arrayIndex){
int cpIdx;
Object val;
int t = readUByte();
switch (t){
case 'Z':
// booleans have to be treated differently since there is no CONSTANT_Boolean, i.e. values are
// stored as CONSTANT_Integer in the constpool, i.e. the cpValue doesn't have the right type
cpIdx = readU2();
val = cpValue[cpIdx];
val = Boolean.valueOf((Integer)val == 1);
setPrimitiveAnnotationValue(reader, tag, annotationIndex, valueIndex, elementName, arrayIndex, val);
break;
case 'B':
cpIdx = readU2();
val = cpValue[cpIdx];
val = Byte.valueOf(((Integer)val).byteValue());
setPrimitiveAnnotationValue(reader, tag, annotationIndex, valueIndex, elementName, arrayIndex, val);
break;
case 'C':
cpIdx = readU2();
val = cpValue[cpIdx];
val = Character.valueOf((char)((Integer)val).shortValue());
setPrimitiveAnnotationValue(reader, tag, annotationIndex, valueIndex, elementName, arrayIndex, val);
break;
case 'S':
cpIdx = readU2();
val = cpValue[cpIdx];
val = Short.valueOf(((Integer)val).shortValue());
setPrimitiveAnnotationValue(reader, tag, annotationIndex, valueIndex, elementName, arrayIndex, val);
break;
case 'I':
case 'F':
case 'D':
case 'J':
cpIdx = readU2();
val = cpValue[cpIdx];
setPrimitiveAnnotationValue(reader, tag, annotationIndex, valueIndex, elementName, arrayIndex, val);
break;
case 's':
cpIdx = readU2();
String s = (String) cpValue[cpIdx];
setStringAnnotationValue(reader, tag, annotationIndex, valueIndex, elementName, arrayIndex, s);
break;
case 'e':
cpIdx = readU2();
String enumTypeName = (String)cpValue[cpIdx];
cpIdx = readU2();
String enumConstName = (String)cpValue[cpIdx];
setEnumAnnotationValue(reader, tag, annotationIndex, valueIndex, elementName, arrayIndex, enumTypeName, enumConstName);
break;
case 'c':
cpIdx = readU2();
String className = (String)cpValue[cpIdx];
setClassAnnotationValue(reader, tag, annotationIndex, valueIndex, elementName, arrayIndex, className);
break;
case '@':
parseAnnotation(reader, tag, 0, false); // getting recursive here
break;
case '[':
int arrayLen = readU2();
setAnnotationValueElementCount(reader, tag, annotationIndex, valueIndex, elementName, arrayLen);
for (int i=0; i<arrayLen; i++){
parseAnnotationValue(reader, tag, annotationIndex, valueIndex, elementName, i);
}
setAnnotationValueElementsDone(reader, tag, annotationIndex, valueIndex, elementName);
break;
}
}
/*
* annotation {
* u2 type_index;
* u2 num_element_value_pairs;
* {
* u2 element_name_index;
* element_value value;
* } element_value_pairs[num_element_value_pairs]
* }
*/
void parseAnnotation (ClassFileReader reader, Object tag, int annotationIndex, boolean isParameterAnnotation){
int cpIdx = readU2();
String annotationType = (String)cpValue[cpIdx];
if (isParameterAnnotation){
setParameterAnnotation(reader, tag, annotationIndex, annotationType);
} else {
setAnnotation(reader, tag, annotationIndex, annotationType);
}
parseAnnotationValues(reader, tag, annotationIndex);
}
void parseAnnotationValues (ClassFileReader reader, Object tag, int annotationIndex){
int nValuePairs = readU2();
setAnnotationValueCount(reader, tag, annotationIndex, nValuePairs);
for (int i=0; i<nValuePairs; i++){
int cpIdx = readU2();
String elementName = (String)cpValue[cpIdx];
parseAnnotationValue(reader, tag, annotationIndex, i, elementName, -1);
}
setAnnotationValuesDone(reader, tag, annotationIndex);
}
/*
* class, field, method annotation attributes (only one per target)
*
* Runtime[In]VisibleAnnotations_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 num_annotations; << pos
* annotation annotations[num_annotations];
* }
*/
public void parseAnnotationsAttr (ClassFileReader reader, Object tag){
int numAnnotations = readU2();
setAnnotationCount(reader, tag, numAnnotations);
for (int i=0; i<numAnnotations; i++){
parseAnnotation(reader, tag, i, false);
}
setAnnotationsDone(reader, tag);
}
// JSR 308 type annotation target types
public static final int CLASS_TYPE_PARAMETER = 0x00;
public static final int METHOD_TYPE_PARAMETER = 0x01;
public static final int CLASS_EXTENDS = 0x10;
public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11;
public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12;
public static final int FIELD = 0x13;
public static final int METHOD_RETURN = 0x14;
public static final int METHOD_RECEIVER = 0x15;
public static final int METHOD_FORMAL_PARAMETER = 0x16;
public static final int THROWS = 0x17;
public static final int LOCAL_VARIABLE = 0x40;
public static final int RESOURCE_VARIABLE = 0x41;
public static final int EXCEPTION_PARAMETER = 0x42;
public static final int INSTANCEOF = 0x43;
public static final int NEW = 0x44;
public static final int CONSTRUCTOR_REFERENCE = 0x45;
public static final int METHOD_REFERENCE = 0x46;
public static final int CAST = 0x47;
public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4a;
public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4b;
public static String getTargetTypeName (int targetType){
switch (targetType){
case CLASS_TYPE_PARAMETER: return "class type parameter";
case METHOD_TYPE_PARAMETER: return "method type parameter";
case CLASS_EXTENDS: return "super class";
case CLASS_TYPE_PARAMETER_BOUND: return "class type parameter bound";
case METHOD_TYPE_PARAMETER_BOUND: return "method type parameter bound";
case FIELD: return "field";
case METHOD_RETURN: return "method return";
case METHOD_RECEIVER: return "method receiver";
case METHOD_FORMAL_PARAMETER: return "method formal parameter";
case THROWS: return "throws";
case LOCAL_VARIABLE: return "local variable";
case RESOURCE_VARIABLE: return "resource variable";
case EXCEPTION_PARAMETER: return "exception parameter";
case INSTANCEOF: return "instanceof";
case NEW: return "new";
case CONSTRUCTOR_REFERENCE: return "ctor reference";
case METHOD_REFERENCE: return "method reference";
case CAST: return "case";
case METHOD_INVOCATION_TYPE_ARGUMENT: return "method invocation type argument";
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: return "ctor reference type argument";
case METHOD_REFERENCE_TYPE_ARGUMENT: return "method reference type argument";
default:
return "<unknown target type 0x" + Integer.toHexString(targetType);
}
}
public static String getTypePathEncoding (short[] typePath){
if (typePath == null){
return "()";
}
StringBuffer sb = new StringBuffer();
for (int i=0; i<typePath.length;i++){
int e = typePath[i];
sb.append('(');
sb.append( Integer.toString((e>>8) & 0xff));
sb.append( Integer.toString(e & 0xff));
sb.append(')');
}
return sb.toString();
}
public static String getScopeEncoding (long[] scopeEntries){
StringBuffer sb = new StringBuffer();
for (int i=0; i<scopeEntries.length;i++){
long e = scopeEntries[i];
int slotIndex = (int)(e & 0xffff);
int length = (int)((e >> 16) & 0xffff);
int startPc = (int)((e >> 32) & 0xffff);
if (i>0){
sb.append(',');
}
sb.append('[');
sb.append( Integer.toString(startPc));
sb.append("..");
sb.append( Integer.toString(startPc + length-1));
sb.append("]#");
sb.append(slotIndex);
}
return sb.toString();
}
// JSR 308 type annotation, which adds 3 fields to the old annotation structure
//
// type_annotation {
// u1 target_type; // targeted program element (sec 3.2)
// union { // ?? this is probably packed - variable size unions make no sense
// type_parameter_target;
// supertype_target;
// type_parameter_bound_target;
// empty_target;
// method_formal_parameter_target;
// throws_target;
// localvar_target;
// catch_target;
// offset_target;
// type_argument_target;
// } target_info; // targeted program element (sec 3.3)
//
// type_path target_path; // encoding of annotation position in compound type (array, generic, etc., sec 3.4)
//
// // standard annotation fields
// u2 type_index; // the annotation type
// u2 num_element_value_pairs;
// {
// u2 element_name_index;
// element_value value;
// } element_value_pairs[num_element_value_pairs];
// }
//
// struct type_path {
// u1 path_length;
// type_path_entry path[path_length];
// }
//
// struct type_path_entry {
// u1 type_path_kind;
// // 0: deeper in array type
// // 1: deeper in nested type
// // 2: bound of wildcard typearg
// // 3: type argument of parameterized type
// u1 type_argument_index;
// // 0, if type_path_kind == 0,1,2
// // 0-based index of type arg in parameterized type if type_path_kind i== 3
// }
int getTargetInfoSize (int targetType){
int len = 3; // max static length are xx_TYPE_ARGUMENTs
if (targetType == LOCAL_VARIABLE || targetType == RESOURCE_VARIABLE){
len = Math.max( len, u2(pos) * 6); // three u2 values per entry
}
return len;
}
int getTypePathSize (short[] typePath){
int typePathSize = 1;
if (typePath != null) {
typePathSize += typePath.length * 2;
}
return typePathSize;
}
short[] readTypePath (){
short[] typePath = null;
int pathLength = readUByte();
if (pathLength > 0){
typePath = new short[pathLength];
for (int i=0; i<pathLength; i++){
int pathKind = (short)readUByte();
int argIdx = (short)readUByte();
typePath[i]= (short)((pathKind << 8) | argIdx);
}
}
return typePath;
}
String readAnnotationType (){
int cpIdx = readU2();
String annotationType = (String)cpValue[cpIdx];
return annotationType;
}
void setTypeAnnotation (ClassFileReader reader, Object tag, int annotationIndex) {
int targetType = readUByte();
switch (targetType){
case CLASS_TYPE_PARAMETER:
case METHOD_TYPE_PARAMETER: {
// type_parameter_target { u1 type_parameter_index; }
int typeParamIdx = readUByte();
reader.setTypeParameterAnnotation( this, tag, annotationIndex, targetType, typeParamIdx, readTypePath(), readAnnotationType());
break;
}
case CLASS_EXTENDS: {
// supertype_target { u2 supertype_index; }
int superTypeIdx = readU2();
reader.setSuperTypeAnnotation( this, tag, annotationIndex, targetType, superTypeIdx, readTypePath(), readAnnotationType());
break;
}
case CLASS_TYPE_PARAMETER_BOUND:
case METHOD_TYPE_PARAMETER_BOUND: {
// type_parameter_bound_target { u1 type_parameter_index; u1 bound_index; }
int typeParamIdx = readUByte();
int boundIdx = readUByte();
reader.setTypeParameterBoundAnnotation(this, tag, annotationIndex, targetType, typeParamIdx, boundIdx, readTypePath(), readAnnotationType());
break;
}
case METHOD_RETURN:
case METHOD_RECEIVER:
case FIELD:
// empty_target {}
reader.setTypeAnnotation( this, tag, annotationIndex, targetType, readTypePath(), readAnnotationType());
break;
case METHOD_FORMAL_PARAMETER: {
// method_formal_parameter_target { u1 method_formal_parameter_index; }
int formalParamIdx = readUByte();
reader.setFormalParameterAnnotation( this, tag, annotationIndex, targetType, formalParamIdx, readTypePath(), readAnnotationType());
break;
}
case THROWS: {
// throws_target { u2 throws_type_index; }
int throwsTypeIdx = readU2();
reader.setThrowsAnnotation( this, tag, annotationIndex, targetType, throwsTypeIdx, readTypePath(), readAnnotationType());
break;
}
case LOCAL_VARIABLE:
case RESOURCE_VARIABLE: {
// this can't just refer to a LocalVarInfo since those depend on debug compile options
//
// localvar_target {
// u2 table_length; // number of entries, not bytes
// {
// u2 start_pc;
// u2 length; // bytecode offset length
// u2 index; // local var idx
// } table[table_length];
// }
int tableLength = readU2();
long[] scopeEntries = new long[tableLength];
for (int i=0; i<tableLength; i++){
int startPc = readU2();
int length = readU2();
int slotIdx = readU2();
scopeEntries[i] = ((long)startPc << 32) | ((long)length << 16) | slotIdx;
}
reader.setVariableAnnotation( this, tag, annotationIndex, targetType, scopeEntries, readTypePath(), readAnnotationType());
break;
}
case EXCEPTION_PARAMETER: {
// catch_target { u2 exception_table_index; }
int exceptionIdx = readU2();
reader.setExceptionParameterAnnotation( this, tag, annotationIndex, targetType, exceptionIdx, readTypePath(), readAnnotationType());
break;
}
case INSTANCEOF:
case METHOD_REFERENCE:
case CONSTRUCTOR_REFERENCE:
case NEW: {
// offset_target { u2 offset; } // insn offset within bytecode
int offset = readU2();
reader.setBytecodeAnnotation(this, tag, annotationIndex, targetType, offset, readTypePath(), readAnnotationType());
break;
}
case CAST:
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT: {
// type_argument_target {
// u2 offset;
// u1 type_argument_index;
// }
int offset = readU2();
int typeArgIdx = readUByte();
reader.setBytecodeTypeParameterAnnotation(this, tag, annotationIndex, targetType, offset, typeArgIdx, readTypePath(), readAnnotationType());
break;
}
default:
// <2do - report this to the reader
throw new RuntimeException("unknown type annotation target: 0x" + Integer.toHexString(targetType));
}
}
void parseTypeAnnotation (ClassFileReader reader, Object tag, int annotationIndex) {
// this does the respective setXTypeAnnotation() reader callback
//dumpData(pos, 16);
setTypeAnnotation(reader, tag, annotationIndex);
// now set the annotation value pairs
parseAnnotationValues( reader, tag, annotationIndex);
}
/*
* Runtime[In]VisibleTypeAnnotations_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u2 num_annotations;
* type_annotation annotations[num_annotations];
* }
*/
public void parseTypeAnnotationsAttr (ClassFileReader reader, Object tag) {
int numAnnotations = readU2();
setTypeAnnotationCount(reader, tag, numAnnotations);
for (int i=0; i<numAnnotations; i++){
parseTypeAnnotation(reader, tag, i);
}
setTypeAnnotationsDone(reader, tag);
}
/*
* RuntimeInvisibleParameterAnnotations_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* u1 num_parameters; << pos
* {
* u2 num_annotations;
* annotation annotations[num_annotations];
* } parameter_annotations[num_parameters];
* }
*/
public void parseParameterAnnotationsAttr(ClassFileReader reader, Object tag){
int numParameters = readUByte();
setParameterCount(reader, tag, numParameters);
for (int i=0; i<numParameters; i++){
int numAnnotations = readU2();
setParameterAnnotationCount(reader, tag, i, numAnnotations);
for (int j=0; j<numAnnotations; j++){
parseAnnotation(reader, tag, j, true);
}
setParameterAnnotationsDone(reader, tag, i);
}
setParametersDone(reader, tag);
}
/**
* Signature_attribute {
* u2 attribute_name_index;
* u4 attr-length;
* u2 signature-index << pos
* }
*/
public void parseSignatureAttr(ClassFileReader reader, Object tag){
int cpIdx = readU2();
setSignature(reader, tag, utf8At(cpIdx));
}
/**
* AnnotationDefault_attribute {
* u2 attribute_name_index;
* u4 attribute_length;
* element_value default_value; << pos
* }
*/
public void parseAnnotationDefaultAttr(ClassFileReader reader, Object tag){
parseAnnotationValue(reader, tag, -1, -1, null, -1);
}
// EnclosingMethod_attribute {
// u2 attribute_name_index;
// u4 attribute_length;
// u2 class_index
// u2 method_index;
// }
// LocalVariableTypeTable_attribute { // Code attr
// u2 attribute_name_index;
// u4 attribute_length;
// u2 local_variable_type_table_length;
// {
// u2 start_pc;
// u2 length;
// u2 name_index;
// u2 signature_index;
// u2 index;
// } local_variable_type_table[local_variable_type_table_length];
// }
public void parseBytecode(JVMByteCodeReader reader, Object tag, int codeLength){
int localVarIndex;
int cpIdx;
int constVal;
int offset;
int defaultOffset;
boolean isWide = false; // modifier for Xload,Xstore,ret and iinc
int startPos = pos;
int endPos = pos+codeLength;
int nextPos;
while (pos < endPos){
pc = pos - startPos;
int opcode = readUByte();
switch (opcode){
case 0: // nop
reader.nop();
break;
case 1: // aconst_null
reader.aconst_null();
break;
case 2: // iconst_m1
reader.iconst_m1();
break;
case 3: // iconst_0
reader.iconst_0();
break;
case 4: // iconst_1
reader.iconst_1();
break;
case 5: // iconst_2
reader.iconst_2();
break;
case 6: // iconst_3
reader.iconst_3();
break;
case 7: // iconst_4
reader.iconst_4();
break;
case 8: // iconst_5
reader.iconst_5();
break;
case 9: // lconst_0
reader.lconst_0();
break;
case 10: // lconst_1
reader.lconst_1();
break;
case 11: // fconst_0
reader.fconst_0();
break;
case 12: // fconst_1
reader.fconst_1();
break;
case 13: // fconst_2
reader.fconst_2();
break;
case 14: // dconst_0
reader.dconst_0();
break;
case 15: // dconst_1
reader.dconst_1();
break;
case 16: // bipush
constVal = readByte();
reader.bipush(constVal);
break;
case 17: // sipush
constVal = readI2();
reader.sipush(constVal);
break;
case 18: // ldc
cpIdx = readUByte();
reader.ldc_(cpIdx);
break;
case 19: // ldc_w
cpIdx = readU2();
reader.ldc_w_(cpIdx);
break;
case 20: // ldc2_w
cpIdx = readU2();
reader.ldc2_w(cpIdx);
break;
case 21: // iload
localVarIndex = isWide ? readU2() : readUByte();
reader.iload(localVarIndex);
break;
case 22: // lload
localVarIndex = isWide ? readU2() : readUByte();
reader.lload(localVarIndex);
break;
case 23: // fload
localVarIndex = isWide ? readU2() : readUByte();
reader.fload(localVarIndex);
break;
case 24: // dload
localVarIndex = isWide ? readU2() : readUByte();
reader.dload(localVarIndex);
break;
case 25: // aload
localVarIndex = isWide ? readU2() : readUByte();
reader.aload(localVarIndex);
break;
case 26: // iload_0
reader.iload_0();
break;
case 27: // iload_1
reader.iload_1();
break;
case 28: // iload_2
reader.iload_2();
break;
case 29: // iload_3
reader.iload_3();
break;
case 30: // lload_0
reader.lload_0();
break;
case 31: // lload_1
reader.lload_1();
break;
case 32: // lload_2
reader.lload_2();
break;
case 33: // lload_3
reader.lload_3();
break;
case 34: // fload_0
reader.fload_0();
break;
case 35: // fload_1
reader.fload_1();
break;
case 36: // fload_2
reader.fload_2();
break;
case 37: // fload_3
reader.fload_3();
break;
case 38: // dload_0
reader.dload_0();
break;
case 39: // dload_1
reader.dload_1();
break;
case 40: // dload_2
reader.dload_2();
break;
case 41: // dload_3
reader.dload_3();
break;
case 42: // aload_0
reader.aload_0();
break;
case 43: // aload_1
reader.aload_1();
break;
case 44: // aload_2
reader.aload_2();
break;
case 45: // aload_3
reader.aload_3();
break;
case 46: // iaload
reader.iaload();
break;
case 47: // laload
reader.laload();
break;
case 48: // faload
reader.faload();
break;
case 49: // daload
reader.daload();
break;
case 50: // aaload
reader.aaload();
break;
case 51: // baload
reader.baload();
break;
case 52: // caload
reader.caload();
break;
case 53: // saload
reader.saload();
break;
case 54: // istore
localVarIndex = isWide ? readU2() : readUByte();
reader.istore(localVarIndex);
break;
case 55: // lstore
localVarIndex = isWide ? readU2() : readUByte();
reader.lstore(localVarIndex);
break;
case 56: // fstore
localVarIndex = isWide ? readU2() : readUByte();
reader.fstore(localVarIndex);
break;
case 57: // dstore
localVarIndex = isWide ? readU2() : readUByte();
reader.dstore(localVarIndex);
break;
case 58: // astore
localVarIndex = isWide ? readU2() : readUByte();
reader.astore(localVarIndex);
break;
case 59: // istore_0
reader.istore_0();
break;
case 60: // istore_1
reader.istore_1();
break;
case 61: // istore_2
reader.istore_2();
break;
case 62: // istore_3
reader.istore_3();
break;
case 63: // lstore_0
reader.lstore_0();
break;
case 64: // lstore_1
reader.lstore_1();
break;
case 65: // lstore_2
reader.lstore_2();
break;
case 66: // lstore_3
reader.lstore_3();
break;
case 67: // fstore_0
reader.fstore_0();
break;
case 68: // fstore_1
reader.fstore_1();
break;
case 69: // fstore_2
reader.fstore_2();
break;
case 70: // fstore_3
reader.fstore_3();
break;
case 71: //dstore_0
reader.dstore_0();
break;
case 72: //dstore_1
reader.dstore_1();
break;
case 73: //dstore_2
reader.dstore_2();
break;
case 74: //dstore_3
reader.dstore_3();
break;
case 75: // astore_0
reader.astore_0();
break;
case 76: // astore_1
reader.astore_1();
break;
case 77: // astore_2
reader.astore_2();
break;
case 78: // astore_3
reader.astore_3();
break;
case 79: // iastore
reader.iastore();
break;
case 80: // lastore
reader.lastore();
break;
case 81: // fastore
reader.fastore();
break;
case 82: // dastore
reader.dastore();
break;
case 83: // aastore
reader.aastore();
break;
case 84: // bastore
reader.bastore();
break;
case 85: // castore
reader.castore();
break;
case 86: // sastore
reader.sastore();
break;
case 87: // pop
reader.pop();
break;
case 88: // pop2
reader.pop2();
break;
case 89: // dup
reader.dup();
break;
case 90: // dup_x1
reader.dup_x1();
break;
case 91: // dup_x2
reader.dup_x2();
break;
case 92: // dup2
reader.dup2();
break;
case 93: // dup2_x1
reader.dup2_x1();
break;
case 94: // dup2_x2
reader.dup2_x2();
break;
case 95: // swap
reader.swap();
break;
case 96: // iadd
reader.iadd();
break;
case 97: // ladd
reader.ladd();
break;
case 98: // fadd
reader.fadd();
break;
case 99: // dadd
reader.dadd();
break;
case 100: // isub
reader.isub();
break;
case 101: // lsub
reader.lsub();
break;
case 102: // fsub
reader.fsub();
break;
case 103: // dsub
reader.dsub();
break;
case 104: // imul
reader.imul();
break;
case 105: // lmul
reader.lmul();
break;
case 106: // fmul
reader.fmul();
break;
case 107: // dmul
reader.dmul();
break;
case 108: // idiv
reader.idiv();
break;
case 109: // ldiv
reader.ldiv();
break;
case 110: // fdiv
reader.fdiv();
break;
case 111: //ddiv
reader.ddiv();
break;
case 112: // irem
reader.irem();
break;
case 113: // lrem
reader.lrem();
break;
case 114: // frem
reader.frem();
break;
case 115: // drem
reader.drem();
break;
case 116: // ineg
reader.ineg();
break;
case 117: // lneg
reader.lneg();
break;
case 118: // fneg
reader.fneg();
break;
case 119: // dneg
reader.dneg();
break;
case 120: // ishl
reader.ishl();
break;
case 121: // lshl
reader.lshl();
break;
case 122: // ishr
reader.ishr();
break;
case 123: // lshr
reader.lshr();
break;
case 124: // iushr
reader.iushr();
break;
case 125: // lushr
reader.lushr();
break;
case 126: // iand
reader.iand();
break;
case 127: // land
reader.land();
break;
case 128: // ior
reader.ior();
break;
case 129: // lor
reader.lor();
break;
case 130: // ixor
reader.ixor();
break;
case 131: // lxor
reader.lxor();
break;
case 132: // iinc
if (isWide){
localVarIndex = readU2();
constVal = readI2();
} else {
localVarIndex = readUByte();
constVal = readByte();
}
reader.iinc(localVarIndex, constVal);
break;
case 133: // i2l
reader.i2l();
break;
case 134: // i2f
reader.i2f();
break;
case 135: // i2d
reader.i2d();
break;
case 136: // l2i
reader.l2i();
break;
case 137: // l2f
reader.l2f();
break;
case 138: // l2d
reader.l2d();
break;
case 139: // f2i
reader.f2i();
break;
case 140: // f2l
reader.f2l();
break;
case 141: // f2d
reader.f2d();
break;
case 142: // d2i
reader.d2i();
break;
case 143: // d2l
reader.d2l();
break;
case 144: // d2f
reader.d2f();
break;
case 145: // i2b
reader.i2b();
break;
case 146: // i2c
reader.i2c();
break;
case 147: // i2s
reader.i2s();
break;
case 148: // lcmp
reader.lcmp();
break;
case 149: // fcmpl
reader.fcmpl();
break;
case 150: // fcmpg
reader.fcmpg();
break;
case 151: // dcmpl
reader.dcmpl();
break;
case 152: // dcmpg
reader.dcmpg();
break;
case 153: // ifeq
offset = readI2();
reader.ifeq(offset);
break;
case 154: // ifne
offset = readI2();
reader.ifne(offset);
break;
case 155: // iflt
offset = readI2();
reader.iflt(offset);
break;
case 156: // ifge
offset = readI2();
reader.ifge(offset);
break;
case 157: // ifgt
offset = readI2();
reader.ifgt(offset);
break;
case 158: // ifle
offset = readI2();
reader.ifle(offset);
break;
case 159: // if_icmpeq
offset = readI2();
reader.if_icmpeq(offset);
break;
case 160: // if_icmpne
offset = readI2();
reader.if_icmpne(offset);
break;
case 161: // if_icmplt
offset = readI2();
reader.if_icmplt(offset);
break;
case 162: // if_icmpge
offset = readI2();
reader.if_icmpge(offset);
break;
case 163: // if_icmpgt
offset = readI2();
reader.if_icmpgt(offset);
break;
case 164: // if_icmple
offset = readI2();
reader.if_icmple(offset);
break;
case 165: // if_acmpeq
offset = readI2();
reader.if_acmpeq(offset);
break;
case 166: // if_acmpne
offset = readI2();
reader.if_acmpne(offset);
break;
case 167: // goto
offset = readI2();
reader.goto_(offset);
break;
case 168: // jsr
offset = readI2();
reader.jsr(offset);
break;
case 169: // ret
localVarIndex = isWide ? readU2() : readUByte();
reader.ret(localVarIndex);
break;
case 170: // tableswitch
pos = (((pc+4)>>2)<<2)+startPos; // skip over padding
defaultOffset = readI4();
int low = readI4();
int high = readI4();
int len = high-low+1;
nextPos = pos + len*4;
reader.tableswitch(defaultOffset, low, high);
pos = nextPos;
break;
case 171: // lookupswitch
pos = (((pc+4)>>2)<<2)+startPos; // skip over padding
defaultOffset = readI4();
int nPairs = readI4();
nextPos = pos + (nPairs*8);
reader.lookupswitch(defaultOffset, nPairs);
pos = nextPos;
break;
case 172: // ireturn
reader.ireturn();
break;
case 173: // lreturn
reader.lreturn();
break;
case 174: // freturn
reader.freturn();
break;
case 175: // dreturn
reader.dreturn();
break;
case 176: // areturn
reader.areturn();
break;
case 177: // return
reader.return_();
break;
case 178: // getstatic
cpIdx = readU2(); // CP index of fieldRef
reader.getstatic(cpIdx);
break;
case 179: // putstatic
cpIdx = readU2(); // CP index of fieldRef
reader.putstatic(cpIdx);
break;
case 180: // getfield
cpIdx = readU2(); // CP index of fieldRef
reader.getfield(cpIdx);
break;
case 181: // putfield
cpIdx = readU2(); // CP index of fieldRef
reader.putfield(cpIdx);
break;
case 182: // invokevirtual
cpIdx = readU2(); // CP index of methodRef
reader.invokevirtual(cpIdx);
break;
case 183: // invokespecial
cpIdx = readU2(); // CP index of methodRef
reader.invokespecial(cpIdx);
break;
case 184: // invokestatic
cpIdx = readU2(); // CP index of methodRef
reader.invokestatic(cpIdx);
break;
case 185: // invokeinterface
cpIdx = readU2(); // CP index of methodRef
int count = readUByte();
int zero = readUByte(); // must be 0
reader.invokeinterface(cpIdx, count, zero);
break;
case 186: // invokedynamic
cpIdx = readU2(); // CP index of bootstrap method
readUByte(); // 0
readUByte(); // 0
reader.invokedynamic(cpIdx);
break;
case 187: // new
cpIdx = readU2();
reader.new_(cpIdx);
break;
case 188: // newarray
int aType = readUByte();
reader.newarray(aType);
break;
case 189: // anewarray
cpIdx = readU2(); // CP index of component type
reader.anewarray(cpIdx);
break;
case 190: // arraylength
reader.arraylength();
break;
case 191: // athrow
reader.athrow();
break;
case 192: // checkcast
cpIdx = readU2(); // cast type cp index
reader.checkcast(cpIdx);
break;
case 193: // instanceof
cpIdx = readU2(); // check type cp index
reader.instanceof_(cpIdx);
break;
case 194: // monitorenter
reader.monitorenter();
break;
case 195: // monitorexit
reader.monitorexit();
break;
case 196: // wide
isWide = true;
// affects immediate operand width if next bytecode is:
// iload,fload,aload,lload,dload,
// istore,fstore,astore,lstore,dstore
// ret
reader.wide();
continue;
case 197: // multianewarray
cpIdx = readU2();
int dimensions = readUByte();
reader.multianewarray(cpIdx, dimensions);
break;
case 198: // ifnull
offset = readI2();
reader.ifnull(offset);
break;
case 199: // ifnonnull
offset = readI2();
reader.ifnonnull(offset);
break;
case 200: // goto_w
offset = readI4();
reader.goto_w(offset);
break;
case 201: // jsr_w
offset = readI4();
reader.jsr_w(offset);
break;
default:
reader.unknown(opcode);
}
isWide = false; // reset wide modifier
}
}
//--- those can only be called from within a JVMByteCodeReader.tableswitch() notification
public void parseTableSwitchEntries(JVMByteCodeReader reader, int low, int high){
for (int val=low; val<=high; val++){
int offset = readI4();
reader.tableswitchEntry(val, offset);
}
}
public int getTableSwitchOffset(int low, int high, int defaultOffset, int val){
if (val < low || val > high){
return defaultOffset;
}
int n = Math.abs(val - low);
pos += n*4;
int pcOffset = readI4();
return pcOffset;
}
//--- those can only be called from within a JVMByteCodeReader.lookupswitch() notification
public void parseLookupSwitchEntries(JVMByteCodeReader reader, int nEntries){
for (int i=0; i<nEntries; i++){
int value = readI4();
int offset = readI4();
reader.lookupswitchEntry(i, value, offset);
}
}
public int getLookupSwitchOffset(int nEntries, int defaultOffset, int val){
for (int i=0; i<nEntries; i++){
int match = readI4();
if (val > match){
pos +=4;
} else if (val == match) {
int offset = readI4();
return offset;
} else {
break;
}
}
return defaultOffset;
}
}