下面列出了org.objectweb.asm.Type#BYTE 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Get the source code name for the specified type
*
* @param type Type to generate a friendly name for
* @param box True to return the equivalent boxing type for primitives
* @param fullyQualified fully-qualify class names
* @return String representation of the specified type, eg "int" for an
* integer primitive or "String" for java.lang.String
*/
public static String getTypeName(Type type, boolean box, boolean fullyQualified) {
if (type == null) {
return "{null?}";
}
switch (type.getSort()) {
case Type.VOID: return box ? "Void" : "void";
case Type.BOOLEAN: return box ? "Boolean" : "boolean";
case Type.CHAR: return box ? "Character" : "char";
case Type.BYTE: return box ? "Byte" : "byte";
case Type.SHORT: return box ? "Short" : "short";
case Type.INT: return box ? "Integer" : "int";
case Type.FLOAT: return box ? "Float" : "float";
case Type.LONG: return box ? "Long" : "long";
case Type.DOUBLE: return box ? "Double" : "double";
case Type.ARRAY: return SignaturePrinter.getTypeName(type.getElementType(), box, fullyQualified) + SignaturePrinter.arraySuffix(type);
case Type.OBJECT:
String typeName = type.getClassName();
if (!fullyQualified) {
typeName = typeName.substring(typeName.lastIndexOf('.') + 1);
}
return typeName;
default:
return "Object";
}
}
Type getBoxedType(final Type type) {
switch (type.getSort()) {
case Type.BYTE:
return BYTE_TYPE;
case Type.BOOLEAN:
return BOOLEAN_TYPE;
case Type.SHORT:
return SHORT_TYPE;
case Type.CHAR:
return CHARACTER_TYPE;
case Type.INT:
return INTEGER_TYPE;
case Type.FLOAT:
return FLOAT_TYPE;
case Type.LONG:
return LONG_TYPE;
case Type.DOUBLE:
return DOUBLE_TYPE;
}
return type;
}
public static int getReturnOpcode(Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return Opcodes.IRETURN;
case Type.FLOAT:
return Opcodes.FRETURN;
case Type.LONG:
return Opcodes.LRETURN;
case Type.DOUBLE:
return Opcodes.DRETURN;
case Type.ARRAY:
case Type.OBJECT:
return Opcodes.ARETURN;
case Type.VOID:
return Opcodes.RETURN;
default:
throw new AssertionError("Unknown type sort: " + type.getClassName());
}
}
public static int getVarOpcode(Type type, boolean store) {
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return store ? Opcodes.ISTORE : Opcodes.ILOAD;
case Type.FLOAT:
return store ? Opcodes.FSTORE : Opcodes.FLOAD;
case Type.LONG:
return store ? Opcodes.LSTORE : Opcodes.LLOAD;
case Type.DOUBLE:
return store ? Opcodes.DSTORE : Opcodes.DLOAD;
case Type.ARRAY:
case Type.OBJECT:
return store ? Opcodes.ASTORE : Opcodes.ALOAD;
default:
throw new AssertionError("Unknown type: " + type.getClassName());
}
}
public static int NEWARRAY(Type type) {
switch (type.getSort()) {
case Type.BYTE:
return Constants.T_BYTE;
case Type.CHAR:
return Constants.T_CHAR;
case Type.DOUBLE:
return Constants.T_DOUBLE;
case Type.FLOAT:
return Constants.T_FLOAT;
case Type.INT:
return Constants.T_INT;
case Type.LONG:
return Constants.T_LONG;
case Type.SHORT:
return Constants.T_SHORT;
case Type.BOOLEAN:
return Constants.T_BOOLEAN;
default:
return -1; // error
}
}
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack.
*/
public void push(final Type value) {
if (value == null) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else {
switch (value.getSort()) {
case Type.BOOLEAN:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.CHAR:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.BYTE:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.SHORT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.INT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.FLOAT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.LONG:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.DOUBLE:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", CLASS_DESCRIPTOR);
break;
default:
mv.visitLdcInsn(value);
}
}
}
@Override
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
boolean isArray = type.getSort() == Type.ARRAY;
if (isArray) {
switch (type.getElementType().getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
return new BasicValue(type);
default:
break;
}
}
BasicValue value = super.newValue(type);
if (BasicValue.REFERENCE_VALUE.equals(value)) {
if (isArray) {
value = newValue(type.getElementType());
StringBuilder descriptor = new StringBuilder();
for (int i = 0; i < type.getDimensions(); ++i) {
descriptor.append('[');
}
descriptor.append(value.getType().getDescriptor());
value = new BasicValue(Type.getType(descriptor.toString()));
} else {
value = new BasicValue(type);
}
}
return value;
}
@Override
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
switch (type.getSort()) {
case Type.VOID:
return null;
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return BasicValue.INT_VALUE;
case Type.FLOAT:
return BasicValue.FLOAT_VALUE;
case Type.LONG:
return BasicValue.LONG_VALUE;
case Type.DOUBLE:
return BasicValue.DOUBLE_VALUE;
case Type.ARRAY:
case Type.OBJECT:
return BasicValue.REFERENCE_VALUE;
default:
throw new Error("Internal error");
}
}
/**
* Generates the instructions to unbox the top stack value. This value is replaced by its unboxed
* equivalent on top of the stack.
*
* @param type the type of the top stack value.
*/
public void unbox(final Type type) {
Type boxedType = NUMBER_TYPE;
Method unboxMethod;
switch (type.getSort()) {
case Type.VOID:
return;
case Type.CHAR:
boxedType = CHARACTER_TYPE;
unboxMethod = CHAR_VALUE;
break;
case Type.BOOLEAN:
boxedType = BOOLEAN_TYPE;
unboxMethod = BOOLEAN_VALUE;
break;
case Type.DOUBLE:
unboxMethod = DOUBLE_VALUE;
break;
case Type.FLOAT:
unboxMethod = FLOAT_VALUE;
break;
case Type.LONG:
unboxMethod = LONG_VALUE;
break;
case Type.INT:
case Type.SHORT:
case Type.BYTE:
unboxMethod = INT_VALUE;
break;
default:
unboxMethod = null;
break;
}
if (unboxMethod == null) {
checkCast(type);
} else {
checkCast(boxedType);
invokeVirtual(boxedType, unboxMethod);
}
}
@Override
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
switch (type.getSort()) {
case Type.VOID:
return null;
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return BasicValue.INT_VALUE;
case Type.FLOAT:
return BasicValue.FLOAT_VALUE;
case Type.LONG:
return BasicValue.LONG_VALUE;
case Type.DOUBLE:
return BasicValue.DOUBLE_VALUE;
case Type.ARRAY:
case Type.OBJECT:
return BasicValue.REFERENCE_VALUE;
default:
throw new AssertionError();
}
}
@Override
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
boolean isArray = type.getSort() == Type.ARRAY;
if (isArray) {
switch (type.getElementType().getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
return new BasicValue(type);
default:
break;
}
}
BasicValue value = super.newValue(type);
if (BasicValue.REFERENCE_VALUE.equals(value)) {
if (isArray) {
value = newValue(type.getElementType());
StringBuilder descriptor = new StringBuilder();
for (int i = 0; i < type.getDimensions(); ++i) {
descriptor.append('[');
}
descriptor.append(value.getType().getDescriptor());
value = new BasicValue(Type.getType(descriptor.toString()));
} else {
value = new BasicValue(type);
}
}
return value;
}
private static Class<?> getType(Type type) throws ClassNotFoundException {
switch (type.getSort()) {
case Type.VOID:
return void.class;
case Type.BOOLEAN:
return boolean.class;
case Type.CHAR:
return char.class;
case Type.BYTE:
return byte.class;
case Type.SHORT:
return short.class;
case Type.INT:
return int.class;
case Type.FLOAT:
return float.class;
case Type.LONG:
return long.class;
case Type.DOUBLE:
return double.class;
case Type.ARRAY:
return Util.getArrayClass(getType(type.getElementType()),
type.getDimensions());
default:
return Class.forName(type.getClassName(), false, null);
}
}
/**
* Returns whether a given instruction can be used to push argument of {@code type} on stack.
*/
private /* static */ boolean isPushForType(AbstractInsnNode insn, Type type) {
int opcode = insn.getOpcode();
if (opcode == type.getOpcode(Opcodes.ILOAD)) {
return true;
}
// b/62060793: AsyncAwait rewrites bytecode to convert java methods into state machine with
// support of lambdas. Constant zero values are pushed on stack for all yet uninitialized
// local variables. And SIPUSH instruction is used to advance an internal state of a state
// machine.
switch (type.getSort()) {
case Type.BOOLEAN:
return opcode == Opcodes.ICONST_0 || opcode == Opcodes.ICONST_1;
case Type.BYTE:
case Type.CHAR:
case Type.SHORT:
case Type.INT:
return opcode == Opcodes.SIPUSH
|| opcode == Opcodes.ICONST_0
|| opcode == Opcodes.ICONST_1
|| opcode == Opcodes.ICONST_2
|| opcode == Opcodes.ICONST_3
|| opcode == Opcodes.ICONST_4
|| opcode == Opcodes.ICONST_5
|| opcode == Opcodes.ICONST_M1;
case Type.LONG:
return opcode == Opcodes.LCONST_0 || opcode == Opcodes.LCONST_1;
case Type.FLOAT:
return opcode == Opcodes.FCONST_0
|| opcode == Opcodes.FCONST_1
|| opcode == Opcodes.FCONST_2;
case Type.DOUBLE:
return opcode == Opcodes.DCONST_0 || opcode == Opcodes.DCONST_1;
case Type.OBJECT:
case Type.ARRAY:
return opcode == Opcodes.ACONST_NULL;
default:
// Support for BIPUSH and LDC* opcodes is not implemented as there is no known use case.
return false;
}
}
/**
* Constructs a new {@link AnalyzerAdapter}.
*
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* @param owner the owner's class name.
* @param access the method's access flags (see {@link Opcodes}).
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
* @param methodVisitor the method visitor to which this adapter delegates calls. May be {@literal
* null}.
*/
protected AnalyzerAdapter(
final int api,
final String owner,
final int access,
final String name,
final String descriptor,
final MethodVisitor methodVisitor) {
super(api, methodVisitor);
this.owner = owner;
locals = new ArrayList<Object>();
stack = new ArrayList<Object>();
uninitializedTypes = new HashMap<Object, Object>();
if ((access & Opcodes.ACC_STATIC) == 0) {
if ("<init>".equals(name)) {
locals.add(Opcodes.UNINITIALIZED_THIS);
} else {
locals.add(owner);
}
}
for (Type argumentType : Type.getArgumentTypes(descriptor)) {
switch (argumentType.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
locals.add(Opcodes.INTEGER);
break;
case Type.FLOAT:
locals.add(Opcodes.FLOAT);
break;
case Type.LONG:
locals.add(Opcodes.LONG);
locals.add(Opcodes.TOP);
break;
case Type.DOUBLE:
locals.add(Opcodes.DOUBLE);
locals.add(Opcodes.TOP);
break;
case Type.ARRAY:
locals.add(argumentType.getDescriptor());
break;
case Type.OBJECT:
locals.add(argumentType.getInternalName());
break;
default:
throw new AssertionError();
}
}
maxLocals = locals.size();
}
/**
* Constructs a new {@link AnalyzerAdapter}.
*
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* @param owner the owner's class name.
* @param access the method's access flags (see {@link Opcodes}).
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
* @param methodVisitor the method visitor to which this adapter delegates calls. May be {@literal
* null}.
*/
protected AnalyzerAdapter(
final int api,
final String owner,
final int access,
final String name,
final String descriptor,
final MethodVisitor methodVisitor) {
super(api, methodVisitor);
this.owner = owner;
locals = new ArrayList<>();
stack = new ArrayList<>();
uninitializedTypes = new HashMap<>();
if ((access & Opcodes.ACC_STATIC) == 0) {
if ("<init>".equals(name)) {
locals.add(Opcodes.UNINITIALIZED_THIS);
} else {
locals.add(owner);
}
}
for (Type argumentType : Type.getArgumentTypes(descriptor)) {
switch (argumentType.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
locals.add(Opcodes.INTEGER);
break;
case Type.FLOAT:
locals.add(Opcodes.FLOAT);
break;
case Type.LONG:
locals.add(Opcodes.LONG);
locals.add(Opcodes.TOP);
break;
case Type.DOUBLE:
locals.add(Opcodes.DOUBLE);
locals.add(Opcodes.TOP);
break;
case Type.ARRAY:
locals.add(argumentType.getDescriptor());
break;
case Type.OBJECT:
locals.add(argumentType.getInternalName());
break;
default:
throw new AssertionError();
}
}
maxLocals = locals.size();
}
public static void addValueReadInsn(MethodVisitor mv, String desc, String methodNamePrefix) {
Type t;
if (desc.startsWith("(")) {
t = Type.getReturnType(desc);
} else {
t = Type.getType(desc);
}
switch (t.getSort()) {
case Type.DOUBLE:
mv.visitInsn(DUP2);
mv.visitMethodInsn(
INVOKESTATIC, Config.instance.analysisClass, methodNamePrefix + "double", "(D)V", false);
break;
case Type.LONG:
mv.visitInsn(DUP2);
mv.visitMethodInsn(
INVOKESTATIC, Config.instance.analysisClass, methodNamePrefix + "long", "(J)V", false);
break;
case Type.ARRAY:
mv.visitInsn(DUP);
mv.visitMethodInsn(
INVOKESTATIC,
Config.instance.analysisClass,
methodNamePrefix + "Object",
"(Ljava/lang/Object;)V", false);
break;
case Type.BOOLEAN:
mv.visitInsn(DUP);
mv.visitMethodInsn(
INVOKESTATIC, Config.instance.analysisClass, methodNamePrefix + "boolean", "(Z)V", false);
break;
case Type.BYTE:
mv.visitInsn(DUP);
mv.visitMethodInsn(
INVOKESTATIC, Config.instance.analysisClass, methodNamePrefix + "byte", "(B)V", false);
break;
case Type.CHAR:
mv.visitInsn(DUP);
mv.visitMethodInsn(
INVOKESTATIC, Config.instance.analysisClass, methodNamePrefix + "char", "(C)V", false);
break;
case Type.FLOAT:
mv.visitInsn(DUP);
mv.visitMethodInsn(
INVOKESTATIC, Config.instance.analysisClass, methodNamePrefix + "float", "(F)V", false);
break;
case Type.INT:
mv.visitInsn(DUP);
mv.visitMethodInsn(
INVOKESTATIC, Config.instance.analysisClass, methodNamePrefix + "int", "(I)V", false);
break;
case Type.OBJECT:
mv.visitInsn(DUP);
mv.visitMethodInsn(
INVOKESTATIC,
Config.instance.analysisClass,
methodNamePrefix + "Object",
"(Ljava/lang/Object;)V", false);
break;
case Type.SHORT:
mv.visitInsn(DUP);
mv.visitMethodInsn(
INVOKESTATIC, Config.instance.analysisClass, methodNamePrefix + "short", "(S)V", false);
break;
case Type.VOID:
mv.visitMethodInsn(
INVOKESTATIC, Config.instance.analysisClass, methodNamePrefix + "void", "()V", false);
break;
default:
System.err.println("Unknown field or method descriptor " + desc);
System.exit(1);
}
}
/**
* Create the types of local variables at the very beginning of the method with the information of
* the declaring class and the method descriptor.
*/
private static ArrayList<InferredType> createInitialLocalVariableTypes(
int access, String ownerClass, String methodName, String methodDescriptor) {
ArrayList<InferredType> types = new ArrayList<>();
if (!isStatic(access)) {
// Instance method, and this is the receiver
types.add(InferredType.create(convertToDescriptor(ownerClass)));
}
Type[] argumentTypes = Type.getArgumentTypes(methodDescriptor);
for (Type argumentType : argumentTypes) {
switch (argumentType.getSort()) {
case Type.BOOLEAN:
case Type.BYTE:
case Type.CHAR:
case Type.SHORT:
case Type.INT:
types.add(InferredType.INT);
break;
case Type.FLOAT:
types.add(InferredType.FLOAT);
break;
case Type.LONG:
types.add(InferredType.LONG);
types.add(InferredType.TOP);
break;
case Type.DOUBLE:
types.add(InferredType.DOUBLE);
types.add(InferredType.TOP);
break;
case Type.ARRAY:
case Type.OBJECT:
types.add(InferredType.create(argumentType.getDescriptor()));
break;
default:
throw new RuntimeException(
"Unhandled argument type: "
+ argumentType
+ " in "
+ ownerClass
+ "."
+ methodName
+ methodDescriptor);
}
}
return types;
}
static private void insertSetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields,
Type primitiveType) {
int maxStack = 6;
int maxLocals = 4; // See correction below for LLOAD and DLOAD
final String setterMethodName;
final String typeNameInternal = primitiveType.getDescriptor();
final int loadValueInstruction;
switch (primitiveType.getSort()) {
case Type.BOOLEAN:
setterMethodName = "setBoolean";
loadValueInstruction = ILOAD;
break;
case Type.BYTE:
setterMethodName = "setByte";
loadValueInstruction = ILOAD;
break;
case Type.CHAR:
setterMethodName = "setChar";
loadValueInstruction = ILOAD;
break;
case Type.SHORT:
setterMethodName = "setShort";
loadValueInstruction = ILOAD;
break;
case Type.INT:
setterMethodName = "setInt";
loadValueInstruction = ILOAD;
break;
case Type.FLOAT:
setterMethodName = "setFloat";
loadValueInstruction = FLOAD;
break;
case Type.LONG:
setterMethodName = "setLong";
loadValueInstruction = LLOAD;
maxLocals++; // (LLOAD and DLOAD actually load two slots)
break;
case Type.DOUBLE:
setterMethodName = "setDouble";
loadValueInstruction = DLOAD;
maxLocals++; // (LLOAD and DLOAD actually load two slots)
break;
default:
setterMethodName = "set";
loadValueInstruction = ALOAD;
break;
}
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, setterMethodName, "(Ljava/lang/Object;I" + typeNameInternal + ")V", null,
null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()];
Label labelForInvalidTypes = new Label();
boolean hasAnyBadTypeLabel = false;
for (int i = 0, n = labels.length; i < n; i++) {
if (Type.getType(fields.get(i).getType()).equals(primitiveType))
labels[i] = new Label();
else {
labels[i] = labelForInvalidTypes;
hasAnyBadTypeLabel = true;
}
}
Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
for (int i = 0, n = labels.length; i < n; i++) {
if (!labels[i].equals(labelForInvalidTypes)) {
Field field = fields.get(i);
mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitVarInsn(loadValueInstruction, 3);
mv.visitFieldInsn(PUTFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
typeNameInternal);
mv.visitInsn(RETURN);
}
}
// Rest of fields: different type
if (hasAnyBadTypeLabel) {
mv.visitLabel(labelForInvalidTypes);
mv.visitFrame(F_SAME, 0, null, 0, null);
insertThrowExceptionForFieldType(mv, primitiveType.getClassName());
}
// Default: field not found
mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null);
}
mv = insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(maxStack, maxLocals);
mv.visitEnd();
}
static private void insertGetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields,
Type primitiveType) {
int maxStack = 6;
final String getterMethodName;
final String typeNameInternal = primitiveType.getDescriptor();
final int returnValueInstruction;
switch (primitiveType.getSort()) {
case Type.BOOLEAN:
getterMethodName = "getBoolean";
returnValueInstruction = IRETURN;
break;
case Type.BYTE:
getterMethodName = "getByte";
returnValueInstruction = IRETURN;
break;
case Type.CHAR:
getterMethodName = "getChar";
returnValueInstruction = IRETURN;
break;
case Type.SHORT:
getterMethodName = "getShort";
returnValueInstruction = IRETURN;
break;
case Type.INT:
getterMethodName = "getInt";
returnValueInstruction = IRETURN;
break;
case Type.FLOAT:
getterMethodName = "getFloat";
returnValueInstruction = FRETURN;
break;
case Type.LONG:
getterMethodName = "getLong";
returnValueInstruction = LRETURN;
break;
case Type.DOUBLE:
getterMethodName = "getDouble";
returnValueInstruction = DRETURN;
break;
default:
getterMethodName = "get";
returnValueInstruction = ARETURN;
break;
}
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, getterMethodName, "(Ljava/lang/Object;I)" + typeNameInternal, null, null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()];
Label labelForInvalidTypes = new Label();
boolean hasAnyBadTypeLabel = false;
for (int i = 0, n = labels.length; i < n; i++) {
if (Type.getType(fields.get(i).getType()).equals(primitiveType))
labels[i] = new Label();
else {
labels[i] = labelForInvalidTypes;
hasAnyBadTypeLabel = true;
}
}
Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
for (int i = 0, n = labels.length; i < n; i++) {
Field field = fields.get(i);
if (!labels[i].equals(labelForInvalidTypes)) {
mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitFieldInsn(GETFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
typeNameInternal);
mv.visitInsn(returnValueInstruction);
}
}
// Rest of fields: different type
if (hasAnyBadTypeLabel) {
mv.visitLabel(labelForInvalidTypes);
mv.visitFrame(F_SAME, 0, null, 0, null);
insertThrowExceptionForFieldType(mv, primitiveType.getClassName());
}
// Default: field not found
mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null);
}
mv = insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(maxStack, 3);
mv.visitEnd();
}
static private void insertGetObject (ClassWriter cw, String classNameInternal, ArrayList<Field> fields) {
int maxStack = 6;
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;I)Ljava/lang/Object;", null, null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()];
for (int i = 0, n = labels.length; i < n; i++)
labels[i] = new Label();
Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
for (int i = 0, n = labels.length; i < n; i++) {
Field field = fields.get(i);
mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitFieldInsn(GETFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
Type.getDescriptor(field.getType()));
Type fieldType = Type.getType(field.getType());
switch (fieldType.getSort()) {
case Type.BOOLEAN:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
break;
case Type.BYTE:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
break;
case Type.CHAR:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
break;
case Type.SHORT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
break;
case Type.INT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
break;
case Type.FLOAT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
break;
case Type.LONG:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
break;
case Type.DOUBLE:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
break;
}
mv.visitInsn(ARETURN);
}
mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null);
}
insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(maxStack, 3);
mv.visitEnd();
}