Annotation parsing (Java 8)

This commit is contained in:
Stiver 2014-03-04 17:00:10 +01:00
parent 4f879b36b4
commit c9c426ded7
8 changed files with 288 additions and 10 deletions

View File

@ -135,6 +135,19 @@ public interface CodeConstants {
public final static int CONSTANT_MethodType = 16; public final static int CONSTANT_MethodType = 16;
public final static int CONSTANT_InvokeDynamic = 18; public final static int CONSTANT_InvokeDynamic = 18;
// ----------------------------------------------------------------------
// MethodHandle reference_kind values
// ----------------------------------------------------------------------
public final static int CONSTANT_MethodHandle_REF_getField = 1;
public final static int CONSTANT_MethodHandle_REF_getStatic = 2;
public final static int CONSTANT_MethodHandle_REF_putField = 3;
public final static int CONSTANT_MethodHandle_REF_putStatic = 4;
public final static int CONSTANT_MethodHandle_REF_invokeVirtual = 5;
public final static int CONSTANT_MethodHandle_REF_invokeStatic = 6;
public final static int CONSTANT_MethodHandle_REF_invokeSpecial = 7;
public final static int CONSTANT_MethodHandle_REF_newInvokeSpecial = 8;
public final static int CONSTANT_MethodHandle_REF_invokeInterface = 9;
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// VM OPCODES // VM OPCODES

View File

@ -0,0 +1,188 @@
package de.fernflower.struct.attr;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import de.fernflower.modules.decompiler.exps.AnnotationExprent;
import de.fernflower.struct.consts.ConstantPool;
public class StructAnnotationTypeAttribute extends StructGeneralAttribute {
public static final int ANNOTATION_TARGET_TYPE_GENERIC_CLASS = 0x00;
public static final int ANNOTATION_TARGET_TYPE_GENERIC_METHOD = 0x01;
public static final int ANNOTATION_TARGET_TYPE_EXTENDS_IMPLEMENTS = 0x10;
public static final int ANNOTATION_TARGET_TYPE_GENERIC_CLASS_BOUND = 0x11;
public static final int ANNOTATION_TARGET_TYPE_GENERIC_METHOD_BOUND = 0x12;
public static final int ANNOTATION_TARGET_TYPE_FIELD = 0x13;
public static final int ANNOTATION_TARGET_TYPE_RETURN = 0x14;
public static final int ANNOTATION_TARGET_TYPE_RECEIVER = 0x15;
public static final int ANNOTATION_TARGET_TYPE_FORMAL = 0x16;
public static final int ANNOTATION_TARGET_TYPE_THROWS = 0x17;
public static final int ANNOTATION_TARGET_TYPE_LOCAL_VARIABLE = 0x40;
public static final int ANNOTATION_TARGET_TYPE_RESOURCE_VARIABLE = 0x41;
public static final int ANNOTATION_TARGET_TYPE_EXCEPTION = 0x42;
public static final int ANNOTATION_TARGET_TYPE_INSTANCEOF = 0x43;
public static final int ANNOTATION_TARGET_TYPE_NEW = 0x44;
public static final int ANNOTATION_TARGET_TYPE_DOUBLECOLON_NEW = 0x45;
public static final int ANNOTATION_TARGET_TYPE_DOUBLECOLON_ID = 0x46;
public static final int ANNOTATION_TARGET_TYPE_CAST = 0x47;
public static final int ANNOTATION_TARGET_TYPE_INVOKATION_CONSTRUCTOR = 0x48;
public static final int ANNOTATION_TARGET_TYPE_INVOKATION_METHOD = 0x49;
public static final int ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_NEW = 0x4A;
public static final int ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_ID = 0x4B;
public static final int ANNOTATION_TARGET_UNION_TYPE_PARAMETER = 1;
public static final int ANNOTATION_TARGET_UNION_SUPERTYPE = 2;
public static final int ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND = 3;
public static final int ANNOTATION_TARGET_UNION_EMPTY = 4;
public static final int ANNOTATION_TARGET_UNION_FORMAL_PARAMETER = 5;
public static final int ANNOTATION_TARGET_UNION_THROWS = 6;
public static final int ANNOTATION_TARGET_UNION_LOCALVAR = 7;
public static final int ANNOTATION_TARGET_UNION_CATCH = 8;
public static final int ANNOTATION_TARGET_UNION_OFFSET = 9;
public static final int ANNOTATION_TARGET_UNION_TYPE_ARGUMENT = 10;
List<AnnotationLocation> locations = new ArrayList<AnnotationLocation>();
List<AnnotationExprent> annotations = new ArrayList<AnnotationExprent>();
public void initContent(ConstantPool pool) {
super.initContent(pool);
DataInputStream data = new DataInputStream(new ByteArrayInputStream(info));
try {
int ann_number = data.readUnsignedByte();
for(int i = 0; i < ann_number; i++) {
locations.add(parseAnnotationLocation(data));
annotations.add(StructAnnotationAttribute.parseAnnotation(data, pool));
}
} catch(IOException ex) {
throw new RuntimeException(ex);
}
}
public AnnotationLocation parseAnnotationLocation(DataInputStream data) throws IOException {
AnnotationLocation ann_location = new AnnotationLocation();
// target type
ann_location.target_type = data.readUnsignedByte();
// target union
switch(ann_location.target_type) {
case ANNOTATION_TARGET_TYPE_GENERIC_CLASS:
case ANNOTATION_TARGET_TYPE_GENERIC_METHOD:
ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_PARAMETER;
break;
case ANNOTATION_TARGET_TYPE_EXTENDS_IMPLEMENTS:
ann_location.target_union = ANNOTATION_TARGET_UNION_SUPERTYPE;
break;
case ANNOTATION_TARGET_TYPE_GENERIC_CLASS_BOUND:
case ANNOTATION_TARGET_TYPE_GENERIC_METHOD_BOUND:
ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND;
break;
case ANNOTATION_TARGET_TYPE_FIELD:
case ANNOTATION_TARGET_TYPE_RETURN:
case ANNOTATION_TARGET_TYPE_RECEIVER:
ann_location.target_union = ANNOTATION_TARGET_UNION_EMPTY;
break;
case ANNOTATION_TARGET_TYPE_FORMAL:
ann_location.target_union = ANNOTATION_TARGET_UNION_FORMAL_PARAMETER;
break;
case ANNOTATION_TARGET_TYPE_THROWS:
ann_location.target_union = ANNOTATION_TARGET_UNION_THROWS;
break;
case ANNOTATION_TARGET_TYPE_LOCAL_VARIABLE:
case ANNOTATION_TARGET_TYPE_RESOURCE_VARIABLE:
ann_location.target_union = ANNOTATION_TARGET_UNION_LOCALVAR;
break;
case ANNOTATION_TARGET_TYPE_EXCEPTION:
ann_location.target_union = ANNOTATION_TARGET_UNION_CATCH;
break;
case ANNOTATION_TARGET_TYPE_INSTANCEOF:
case ANNOTATION_TARGET_TYPE_NEW:
case ANNOTATION_TARGET_TYPE_DOUBLECOLON_NEW:
case ANNOTATION_TARGET_TYPE_DOUBLECOLON_ID:
ann_location.target_union = ANNOTATION_TARGET_UNION_OFFSET;
break;
case ANNOTATION_TARGET_TYPE_CAST:
case ANNOTATION_TARGET_TYPE_INVOKATION_CONSTRUCTOR:
case ANNOTATION_TARGET_TYPE_INVOKATION_METHOD:
case ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_NEW:
case ANNOTATION_TARGET_TYPE_GENERIC_DOUBLECOLON_ID:
ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_ARGUMENT;
break;
default:
throw new RuntimeException("Unknown target type in a type annotation!");
}
// target union data
switch(ann_location.target_union) {
case ANNOTATION_TARGET_UNION_TYPE_PARAMETER:
case ANNOTATION_TARGET_UNION_FORMAL_PARAMETER:
ann_location.data = new int[] {data.readUnsignedByte()};
break;
case ANNOTATION_TARGET_UNION_SUPERTYPE:
case ANNOTATION_TARGET_UNION_THROWS:
case ANNOTATION_TARGET_UNION_CATCH:
case ANNOTATION_TARGET_UNION_OFFSET:
ann_location.data = new int[] {data.readUnsignedShort()};
break;
case ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND:
ann_location.data = new int[] {data.readUnsignedByte(), data.readUnsignedByte()};
break;
case ANNOTATION_TARGET_UNION_EMPTY:
break;
case ANNOTATION_TARGET_UNION_LOCALVAR:
int table_length = data.readUnsignedShort();
ann_location.data = new int[table_length * 3 + 1];
ann_location.data[0] = table_length;
for(int i = 0; i < table_length; ++i) {
ann_location.data[3 * i + 1] = data.readUnsignedShort();
ann_location.data[3 * i + 2] = data.readUnsignedShort();
ann_location.data[3 * i + 3] = data.readUnsignedShort();
}
break;
case ANNOTATION_TARGET_UNION_TYPE_ARGUMENT:
ann_location.data = new int[] {data.readUnsignedShort(), data.readUnsignedByte()};
}
// target path
int path_length = data.readUnsignedByte();
ann_location.target_path_kind = new int[path_length];
ann_location.target_argument_index = new int[path_length];
for(int i = 0; i < path_length; ++i) {
ann_location.target_path_kind[i] = data.readUnsignedByte();
ann_location.target_argument_index[i] = data.readUnsignedByte();
}
return ann_location;
}
private static class AnnotationLocation {
public int target_type;
public int target_union;
public int[] data;
public int[] target_path_kind;
public int[] target_argument_index;
}
}

View File

@ -0,0 +1,50 @@
package de.fernflower.struct.attr;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import de.fernflower.struct.consts.ConstantPool;
import de.fernflower.struct.consts.LinkConstant;
import de.fernflower.struct.consts.PooledConstant;
public class StructBootstrapMethodsAttribute extends StructGeneralAttribute {
private List<LinkConstant> method_refs = new ArrayList<LinkConstant>();
private List<List<PooledConstant>> method_arguments = new ArrayList<List<PooledConstant>>();
public void initContent(ConstantPool pool) {
name = ATTRIBUTE_BOOTSTRAP_METHODS;
try {
DataInputStream data = new DataInputStream(new ByteArrayInputStream(info, 0, info.length));
int method_number = data.readUnsignedShort();
for(int i = 0; i < method_number; ++i) {
int bootstrap_method_ref = data.readUnsignedShort();
int num_bootstrap_arguments = data.readUnsignedShort();
List<PooledConstant> list_arguments = new ArrayList<PooledConstant>();
for(int j = 0; j < num_bootstrap_arguments; ++j) {
int bootstrap_argument_ref = data.readUnsignedShort();
list_arguments.add(pool.getConstant(bootstrap_argument_ref));
}
method_refs.add(pool.getLinkConstant(bootstrap_method_ref));
method_arguments.add(list_arguments);
}
} catch(IOException ex) {
throw new RuntimeException(ex);
}
}
}

View File

@ -39,8 +39,11 @@ public class StructGeneralAttribute {
public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations";
public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations"; public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations";
public static final String ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations";
public static final String ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations";
public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable";
public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue"; public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue";
public static final String ATTRIBUTE_BOOTSTRAP_METHODS = "BootstrapMethods";
@ -92,8 +95,13 @@ public class StructGeneralAttribute {
} else if(ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attrname) || } else if(ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attrname) ||
ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attrname)) { ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attrname)) {
attr = new StructAnnotationParameterAttribute(); attr = new StructAnnotationParameterAttribute();
} else if(ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attrname) ||
ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attrname)) {
attr = new StructAnnotationTypeAttribute();
} else if(ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname)) { } else if(ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname)) {
attr = new StructLocalVariableTableAttribute(); attr = new StructLocalVariableTableAttribute();
} else if(ATTRIBUTE_BOOTSTRAP_METHODS.equals(attrname)) {
attr = new StructBootstrapMethodsAttribute();
} else { } else {
// unsupported attribute // unsupported attribute
return null; return null;

View File

@ -90,6 +90,7 @@ public class ConstantPool {
case CodeConstants.CONSTANT_Methodref: case CodeConstants.CONSTANT_Methodref:
case CodeConstants.CONSTANT_InterfaceMethodref: case CodeConstants.CONSTANT_InterfaceMethodref:
case CodeConstants.CONSTANT_NameAndType: case CodeConstants.CONSTANT_NameAndType:
case CodeConstants.CONSTANT_InvokeDynamic:
pool.add(new LinkConstant(tag, in.readUnsignedShort(), in.readUnsignedShort())); pool.add(new LinkConstant(tag, in.readUnsignedShort(), in.readUnsignedShort()));
if(tag == CodeConstants.CONSTANT_NameAndType) { if(tag == CodeConstants.CONSTANT_NameAndType) {
pass[i] = 1; pass[i] = 1;
@ -101,9 +102,6 @@ public class ConstantPool {
pool.add(new LinkConstant(tag, in.readUnsignedByte(), in.readUnsignedShort())); pool.add(new LinkConstant(tag, in.readUnsignedByte(), in.readUnsignedShort()));
pass[i] = 3; pass[i] = 3;
break; break;
case CodeConstants.CONSTANT_InvokeDynamic:
pool.add(new LinkConstant(tag, in.readUnsignedShort(), in.readUnsignedShort()));
pass[i] = 2;
} }
} }
@ -151,6 +149,7 @@ public class ConstantPool {
case CodeConstants.CONSTANT_Methodref: case CodeConstants.CONSTANT_Methodref:
case CodeConstants.CONSTANT_InterfaceMethodref: case CodeConstants.CONSTANT_InterfaceMethodref:
case CodeConstants.CONSTANT_NameAndType: case CodeConstants.CONSTANT_NameAndType:
case CodeConstants.CONSTANT_InvokeDynamic:
in.skip(4); in.skip(4);
break; break;
case CodeConstants.CONSTANT_Long: case CodeConstants.CONSTANT_Long:
@ -160,7 +159,11 @@ public class ConstantPool {
break; break;
case CodeConstants.CONSTANT_Class: case CodeConstants.CONSTANT_Class:
case CodeConstants.CONSTANT_String: case CodeConstants.CONSTANT_String:
case CodeConstants.CONSTANT_MethodType:
in.skip(2); in.skip(2);
break;
case CodeConstants.CONSTANT_MethodHandle:
in.skip(3);
} }
} }
} }

View File

@ -19,6 +19,7 @@ import java.io.IOException;
/* /*
* NameAndType, FieldRef, MethodRef, InterfaceMethodref * NameAndType, FieldRef, MethodRef, InterfaceMethodref
* InvokeDynamic, MethodHandle
*/ */
public class LinkConstant extends PooledConstant { public class LinkConstant extends PooledConstant {
@ -39,7 +40,7 @@ public class LinkConstant extends PooledConstant {
public boolean isVoid = false;; public boolean isVoid = false;;
public boolean returnCategory2 = false;; public boolean returnCategory2 = false;
// ***************************************************************************** // *****************************************************************************
@ -71,8 +72,17 @@ public class LinkConstant extends PooledConstant {
if(type == CONSTANT_NameAndType) { if(type == CONSTANT_NameAndType) {
elementname = pool.getPrimitiveConstant(index1).getString(); elementname = pool.getPrimitiveConstant(index1).getString();
descriptor = pool.getPrimitiveConstant(index2).getString(); descriptor = pool.getPrimitiveConstant(index2).getString();
} else if(type == CONSTANT_MethodHandle) {
LinkConstant ref_info = pool.getLinkConstant(index2);
classname = ref_info.classname;
elementname = ref_info.elementname;
descriptor = ref_info.descriptor;
} else { } else {
if(type != CONSTANT_InvokeDynamic) {
classname = pool.getPrimitiveConstant(index1).getString(); classname = pool.getPrimitiveConstant(index1).getString();
}
LinkConstant nametype = pool.getLinkConstant(index2); LinkConstant nametype = pool.getLinkConstant(index2);
elementname = nametype.elementname; elementname = nametype.elementname;
@ -84,7 +94,11 @@ public class LinkConstant extends PooledConstant {
public void writeToStream(DataOutputStream out) throws IOException { public void writeToStream(DataOutputStream out) throws IOException {
out.writeByte(type); out.writeByte(type);
if(type == CONSTANT_MethodHandle) {
out.writeByte(index1);
} else {
out.writeShort(index1); out.writeShort(index1);
}
out.writeShort(index2); out.writeShort(index2);
} }
@ -117,7 +131,7 @@ public class LinkConstant extends PooledConstant {
private void initConstant() { private void initConstant() {
if(type == CONSTANT_Methodref || type == CONSTANT_InterfaceMethodref) { if(type == CONSTANT_Methodref || type == CONSTANT_InterfaceMethodref || type == CONSTANT_InvokeDynamic || type == CONSTANT_MethodHandle) {
resolveDescriptor(descriptor); resolveDescriptor(descriptor);
} else if(type == CONSTANT_Fieldref) { } else if(type == CONSTANT_Fieldref) {
returnCategory2 = ("D".equals(descriptor) || "J".equals(descriptor)); returnCategory2 = ("D".equals(descriptor) || "J".equals(descriptor));

View File

@ -17,6 +17,8 @@ package de.fernflower.struct.consts;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import de.fernflower.code.CodeConstants;
/* /*
* Integer, Long, Float, Double, String, Class, UTF8 * Integer, Long, Float, Double, String, Class, UTF8
*/ */
@ -75,7 +77,7 @@ public class PrimitiveConstant extends PooledConstant {
public void resolveConstant(ConstantPool pool) { public void resolveConstant(ConstantPool pool) {
if(type == CONSTANT_Class || type == CONSTANT_String) { if(type == CONSTANT_Class || type == CONSTANT_String || type == CONSTANT_MethodType) {
value = pool.getPrimitiveConstant(index).getString(); value = pool.getPrimitiveConstant(index).getString();
initConstant(); initConstant();
} }
@ -100,7 +102,7 @@ public class PrimitiveConstant extends PooledConstant {
case CONSTANT_Utf8: case CONSTANT_Utf8:
out.writeUTF(getString()); out.writeUTF(getString());
break; break;
default: // CONSTANT_Class or CONSTANT_String default: // CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType
out.writeShort(index); out.writeShort(index);
} }
} }