Mercurial > hg > Members > kono > jpf-core
view src/main/gov/nasa/jpf/jvm/ClassFile.java @ 28:7be90179bb3b
Provided support for double colon operator used for lamabda expressions. Fixed a bug related to generating names for funcation object classes (by supporting double colon operator, a new stragety needed to generate unique names for function objects. To achive that the bootstrap ids are incorporated into names). Finally modified the method that retrieves the SAM from functional interfaces.
author | nastaran <nastaran.shafiei@gmail.com> |
---|---|
date | Thu, 25 Jun 2015 13:20:50 -0700 |
parents | 61d41facf527 |
children |
line wrap: on
line source
/* * 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 gov.nasa.jpf.jvm.JVMByteCodeReader; import gov.nasa.jpf.vm.ClassParseException; import gov.nasa.jpf.JPFException; import gov.nasa.jpf.util.BailOut; import gov.nasa.jpf.util.BinaryClassSource; import java.io.File; /** * 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; } }