/** Returns the reference/primitive class to store the */ private static String findReferenceDesc(String desc) { Type type = Type.getType(desc); switch (type.getSort()) { case Type.ARRAY: return "Lorg/multiverse/transactional/refs/BasicRef;"; case Type.BOOLEAN: return "Lorg/multiverse/transactional/refs/BooleanRef;"; case Type.BYTE: return "Lorg/multiverse/transactional/refs/ByteRef;"; case Type.CHAR: return "Lorg/multiverse/transactional/refs/CharRef;"; case Type.DOUBLE: return "Lorg/multiverse/transactional/refs/DoubleRef;"; case Type.FLOAT: return "Lorg/multiverse/transactional/refs/FloatRef;"; case Type.INT: return "Lorg/multiverse/transactional/refs/IntRef;"; case Type.LONG: return "Lorg/multiverse/transactional/refs/LongRef;"; case Type.SHORT: return "Lorg/multiverse/transactional/refs/ShortRef;"; case Type.OBJECT: return "Lorg/multiverse/transactional/refs/BasicRef;"; default: throw new IllegalStateException("Unhandeled sort: " + type.getSort()); } }
private Type getMirrorType(final Type type) { int numDimensions = 0; final Type basicType; if (type.getSort() == Type.ARRAY) { numDimensions = type.getDimensions(); basicType = type.getElementType(); } else { basicType = type; } if (basicType.getSort() != Type.OBJECT) { return type; } final Mirror mirror = getMirror(basicType.getInternalName()); if (mirror.isClassMirror()) { final StringBuilder name = new StringBuilder(); for (int i = 0; i < numDimensions; ++i) { name.append('['); } name.append('L').append(mirror.getTranslatedName()).append(';'); return Type.getType(name.toString()); } return type; }
public boolean isTypeImmutable(String desc) { Type type = Type.getType(desc); if (IMMUTABLE_TYPE_SORTS.contains(type.getSort())) { return true; } if (type.getSort() != Type.OBJECT) { return false; } if (Sets.union(EXTERNAL_IMMUTABLE_CLASSES, immutableClasses).contains(type.getInternalName())) { return true; } return false; }
/** * Insert the necessary methods to unbox a primitive type (if the given type is a primitive). * * @param mv The method visitor * @param type The type to unbox */ public static void visitUnboxingMethod(MethodVisitor mv, Type type) { if (type.getSort() == Type.BOOLEAN) { mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); } else if (type.getSort() == Type.INT) { mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); } else if (type.getSort() == Type.BYTE) { mv.visitTypeInsn(CHECKCAST, "java/lang/Byte"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); } else if (type.getSort() == Type.SHORT) { mv.visitTypeInsn(CHECKCAST, "java/lang/Short"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false); } else if (type.getSort() == Type.LONG) { mv.visitTypeInsn(CHECKCAST, "java/lang/Long"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); } else if (type.getSort() == Type.FLOAT) { mv.visitTypeInsn(CHECKCAST, "java/lang/Float"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); } else if (type.getSort() == Type.DOUBLE) { mv.visitTypeInsn(CHECKCAST, "java/lang/Double"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); } else if (type.getSort() == Type.CHAR) { mv.visitTypeInsn(CHECKCAST, "java/lang/Character"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false); } else { mv.visitTypeInsn(CHECKCAST, type.getInternalName()); } }
private String getDescriptor(Type type) { if (type.getSort() == Type.OBJECT) { String name = type.getInternalName(); int index = name.lastIndexOf('/'); return name.substring(index + 1); } if (type.getSort() == Type.ARRAY) { StringBuilder sb = new StringBuilder(getDescriptor(type.getElementType())); for (int dim = type.getDimensions(); dim > 0; --dim) { sb.append("[]"); } return sb.toString(); } return type.getClassName(); }
private boolean classIsDefinitelyMutable(ClassNode klass) { if (superClassIsDefinitelyMutable(klass.superName)) { log.add("Mutable parent: " + klass.name + " < " + klass.superName); return true; } for (FieldNode field : klass.fields) { if ((field.access & Opcodes.ACC_STATIC) != 0) { continue; } if ((field.access & Opcodes.ACC_FINAL) == 0) { log.add("Non-final field: " + klass.name + "#" + field.name + ":" + field.desc); return true; } if (field.name.contains("$")) { // Generated fields are assumed to be effectively immutable. // This could, in principle, miss an issue like a static reference to a // seemingly-immutable inner class object that maintains a hidden reference // to its mutable outer object, but that seems unlikely. continue; } Type type = Type.getType(field.desc); if (IMMUTABLE_TYPE_SORTS.contains(type.getSort())) { continue; } if (type.getSort() != Type.OBJECT) { log.add("Odd sort: " + klass.name + "#" + field.name + ":" + field.desc); return true; } if (allClasses.keySet().contains(type.getInternalName())) { if (classesWithMutableDescendents.contains(type.getInternalName())) { log.add("Internal mutable field: " + klass.name + "#" + field.name + ":" + field.desc); return true; } } else { if (!EXTERNAL_IMMUTABLE_CLASSES.contains(type.getInternalName())) { log.add("External mutable field: " + klass.name + "#" + field.name + ":" + field.desc); return true; } } } return false; }
/** * Creates a new local variable of the given type. * * @param type the type of the local variable to be created. * @return the identifier of the newly created local variable. */ public int newLocal(final Type type) { Object t; switch (type.getSort()) { case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: case Type.INT: t = Opcodes.INTEGER; break; case Type.FLOAT: t = Opcodes.FLOAT; break; case Type.LONG: t = Opcodes.LONG; break; case Type.DOUBLE: t = Opcodes.DOUBLE; break; case Type.ARRAY: t = type.getDescriptor(); break; // case Type.OBJECT: default: t = type.getInternalName(); break; } int local = newLocalMapping(type); setLocalType(local, type); setFrameLocal(local, t); return local; }
public static Class<?> getClassForType(Type type) { checkArgNotNull(type, "type"); switch (type.getSort()) { case Type.BOOLEAN: return boolean.class; case Type.BYTE: return byte.class; case Type.CHAR: return char.class; case Type.DOUBLE: return double.class; case Type.FLOAT: return float.class; case Type.INT: return int.class; case Type.LONG: return long.class; case Type.SHORT: return short.class; case Type.VOID: return void.class; case Type.OBJECT: case Type.ARRAY: return getClassForInternalName(type.getInternalName()); } throw new IllegalStateException(); // should be unreachable }
/** * Emits code boxing value of basic type. * * @param mv output method visitor * @param type input data type (must be basic type!) */ public void emitAutoboxing(SpyMethodVisitor mv, Type type) { switch (type.getSort()) { case Type.INT: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); break; case Type.LONG: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); break; case Type.FLOAT: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); break; case Type.DOUBLE: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); break; case Type.SHORT: mv.visitInsn(I2S); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;"); break; case Type.BYTE: mv.visitInsn(I2B); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;"); break; case Type.BOOLEAN: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); break; case Type.CHAR: mv.visitMethodInsn( INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); break; } }
/** * Pushes the default value for the given type onto the stack (ie. 0 for scalars, null for refs). */ public void pushDefaultValue(Type aType) { switch (aType.getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.CHAR: case Type.SHORT: case Type.INT: pushInt(0); break; case Type.FLOAT: pushFloat(0); break; case Type.LONG: pushLong(0); break; case Type.DOUBLE: pushDouble(0); break; case Type.OBJECT: case Type.ARRAY: ACONST_NULL(); break; case Type.VOID: break; default: throw new RuntimeException("Not handled: " + aType); } }
private Expression pushDefaultValue(Type type) { switch (type.getSort()) { case BOOLEAN: return value(false); case CHAR: return value((char) 0); case BYTE: return value((byte) 0); case SHORT: return value((short) 0); case INT: return value(0); case Type.LONG: return value(0L); case Type.FLOAT: return value(0f); case Type.DOUBLE: return value(0d); case ARRAY: case OBJECT: return nullRef(type); default: throw new IllegalArgumentException(); } }
private ClassMetadata getClassMetadata( ClassMetadataResolver resolver, Type type, boolean ignoreArray) { if (type.getSort() == Type.ARRAY) { return resolver.resolve( type.getElementType().getClassName(), ignoreArray ? 0 : type.getDimensions()); } else { return resolver.resolve(type.getClassName(), 0); } }
private void addType(Type t) { switch (t.getSort()) { case Type.ARRAY: addType(t.getElementType()); break; case Type.OBJECT: addName(t.getInternalName()); break; } }
private void addType(final Type t) { switch (t.getSort()) { case Type.ARRAY: addType(t.getElementType()); break; case Type.OBJECT: addName(t.getClassName().replace('.', '/')); break; } }
/** * Inspects the given type recursively and add it as outgoing reference if necessary * * @param type Referenced type */ private void inspectType(Type type) { switch (type.getSort()) { case Type.ARRAY: inspectType(type.getElementType()); break; case Type.OBJECT: String typeName = refactor(type.getClassName()); checkReference(typeName); break; } }
/** * Fetches return value or thrown exception. If return value is of basic type, it is automatically * boxed. * * @param mv output method visitor * @param type return data type * @return number of JVM stack slots emitted code consumes */ public int emitFetchRetVal(SpyMethodVisitor mv, Type type) { if (Type.VOID == type.getSort()) { mv.visitInsn(ACONST_NULL); return 1; } mv.visitInsn(DUP); emitAutoboxing(mv, type); mv.visitVarInsn(ASTORE, mv.getRetValProbeSlot()); return type.getSize(); }
private void addType(final Type type) { switch (type.getSort()) { case Type.ARRAY: addType(type.getElementType()); break; case Type.OBJECT: addPackage(type.getInternalName()); break; case Type.METHOD: addMethodTypes(type.getDescriptor()); break; } }
void addType(final Type t) { switch (t.getSort()) { case Type.ARRAY: addType(t.getElementType()); break; case Type.OBJECT: addName(t.getInternalName()); break; case Type.METHOD: addMethodDesc(t.getDescriptor()); break; } }
private static boolean appendTypeName(StringBuilder tpl, Type type, String sourceClass) { switch (type.getSort()) { case Type.BOOLEAN: tpl.append("boolean"); return false; case Type.CHAR: tpl.append("char"); return false; case Type.BYTE: tpl.append("byte"); return false; case Type.SHORT: tpl.append("short"); return false; case Type.INT: tpl.append("int"); return false; case Type.FLOAT: tpl.append("float"); return false; case Type.LONG: tpl.append("long"); return false; case Type.DOUBLE: tpl.append("double"); return false; case Type.ARRAY: EventProxy.appendTypeName(tpl, type.getElementType(), sourceClass); return true; case Type.OBJECT: String typeName = type.getClassName(); typeName = typeName.substring(typeName.lastIndexOf('.') + 1); tpl.append(typeName); if (typeName.endsWith("ReturnEventInfo")) tpl.append('<').append(sourceClass).append(", ?>"); else if (typeName.endsWith("EventInfo")) tpl.append('<').append(sourceClass).append('>'); return false; } tpl.append("Object"); return false; }
public JavaType convertAsmType(org.objectweb.asm.Type asmType) { JavaType result; switch (asmType.getSort()) { case org.objectweb.asm.Type.OBJECT: result = getClassSymbol(asmType.getInternalName()).type; break; case org.objectweb.asm.Type.BYTE: result = symbols.byteType; break; case org.objectweb.asm.Type.CHAR: result = symbols.charType; break; case org.objectweb.asm.Type.SHORT: result = symbols.shortType; break; case org.objectweb.asm.Type.INT: result = symbols.intType; break; case org.objectweb.asm.Type.LONG: result = symbols.longType; break; case org.objectweb.asm.Type.FLOAT: result = symbols.floatType; break; case org.objectweb.asm.Type.DOUBLE: result = symbols.doubleType; break; case org.objectweb.asm.Type.BOOLEAN: result = symbols.booleanType; break; case org.objectweb.asm.Type.ARRAY: result = new ArrayJavaType(convertAsmType(asmType.getElementType()), symbols.arrayClass); break; case org.objectweb.asm.Type.VOID: result = symbols.voidType; break; default: throw new IllegalArgumentException(asmType.toString()); } return result; }
/** * Insert the necessary methods to box a primitive type (if the given type is a primitive object). * * @param mv The method visitor * @param type The type to unbox */ public static void visitBoxingMethod(MethodVisitor mv, Type type) { if (type.getSort() == Type.BOOLEAN) { mv.visitMethodInsn( INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); } else if (type.getSort() == Type.INT) { mv.visitMethodInsn( INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); } else if (type.getSort() == Type.BYTE) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); } else if (type.getSort() == Type.SHORT) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); } else if (type.getSort() == Type.LONG) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); } else if (type.getSort() == Type.FLOAT) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); } else if (type.getSort() == Type.DOUBLE) { mv.visitMethodInsn( INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); } else if (type.getSort() == Type.CHAR) { mv.visitMethodInsn( INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); } }
public static int getLoadingOpcode(Type argType) { checkArgNotNull(argType, "argType"); switch (argType.getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.CHAR: case Type.SHORT: case Type.INT: return Opcodes.ILOAD; case Type.DOUBLE: return Opcodes.DLOAD; case Type.FLOAT: return Opcodes.FLOAD; case Type.LONG: return Opcodes.LLOAD; case Type.OBJECT: case Type.ARRAY: return Opcodes.ALOAD; default: throw new IllegalStateException(); } }
private static 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); if (!Modifier.isStatic(field.getModifiers())) { mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, classNameInternal); } mv.visitFieldInsn( Modifier.isStatic(field.getModifiers()) ? GETSTATIC : GETFIELD, classNameInternal, 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(); }
private InsnList fixInstructions(MethodNode originalMethod, CloneMap cloneMap) { InsnList instructions = new InsnList(); for (int k = 0; k < originalMethod.instructions.size(); k++) { AbstractInsnNode originalInsn = originalMethod.instructions.get(k); switch (originalInsn.getOpcode()) { // the put on the field granular field is transformed to a fieldref.set case PUTFIELD: { FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn; ClassMetadata ownerMetadata = metadataRepository.loadClassMetadata(classLoader, fieldInsn.owner); FieldMetadata fieldMetadata = ownerMetadata.getFieldMetadata(fieldInsn.name); Type originalFieldType = Type.getType(fieldMetadata.getDesc()); if (fieldMetadata.hasFieldGranularity()) { boolean fieldIsCategory2 = isCategory2(fieldMetadata.getDesc()); if (fieldIsCategory2) { // value(category2), owner,.. instructions.add(new InsnNode(DUP2_X1)); // [value(category2), owner, value(category2),...] instructions.add(new InsnNode(POP2)); // [owner, value(category2), ...] } else { // [value(category1), owner, instructions.add(new InsnNode(SWAP)); // [owner, value(category1),.. } String referenceDesc = findReferenceDesc(fieldMetadata.getDesc()); String referenceName = Type.getType(referenceDesc).getInternalName(); instructions.add( new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc)); if (fieldIsCategory2) { // [owner, value(category2),.. instructions.add(new InsnNode(DUP_X2)); // [owner, value(category2), owner instructions.add(new InsnNode(POP)); // [value(category2), owner } else { // [owner, value(category1) instructions.add(new InsnNode(SWAP)); // [value(category1), owner.. } // call the set if (originalFieldType.getSort() == Type.ARRAY || originalFieldType.getSort() == Type.OBJECT) { String objectDesc = Type.getDescriptor(Object.class); MethodInsnNode methodInsn = new MethodInsnNode( INVOKEVIRTUAL, referenceName, "set", format("(%s)%s", objectDesc, objectDesc)); instructions.add(methodInsn); } else { MethodInsnNode methodInsn = new MethodInsnNode( INVOKEVIRTUAL, referenceName, "set", format("(%s)%s", fieldMetadata.getDesc(), fieldMetadata.getDesc())); instructions.add(methodInsn); } // pop the unused return value of the set. if (fieldIsCategory2) { instructions.add(new InsnNode(POP2)); } else { instructions.add(new InsnNode(POP)); } } else { instructions.add(originalInsn.clone(cloneMap)); } } break; // the get on the field granular field is transformed to a fieldref.get case GETFIELD: { FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn; FieldMetadata fieldMetadata = metadataRepository .loadClassMetadata(classLoader, fieldInsn.owner) .getFieldMetadata(fieldInsn.name); if (!fieldMetadata.hasFieldGranularity()) { // if it is not getter on a field granular field instructions.add(originalInsn.clone(cloneMap)); } else { // it is a getter on a field granular field. String referenceDesc = findReferenceDesc(fieldMetadata.getDesc()); String referenceName = Type.getType(referenceDesc).getInternalName(); // place the fieldref on the stack. instructions.add( new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc)); Type originalFieldType = Type.getType(fieldMetadata.getDesc()); if (originalFieldType.getSort() == Type.ARRAY || originalFieldType.getSort() == Type.OBJECT) { instructions.add( new MethodInsnNode( INVOKEVIRTUAL, referenceName, "get", format("()%s", getDescriptor(Object.class)))); if (!originalFieldType.equals(Type.getType(Object.class))) { instructions.add( new TypeInsnNode(CHECKCAST, originalFieldType.getInternalName())); } } else { instructions.add( new MethodInsnNode( INVOKEVIRTUAL, referenceName, "get", format("()%s", fieldMetadata.getDesc()))); } } } break; default: instructions.add(originalInsn.clone(cloneMap)); break; } } return instructions; }
/* * (non-Javadoc) * * @see org.objectweb.asm.MethodAdapter#visitLdcInsn(java.lang.Object) */ @Override public void visitLdcInsn(Object cst) { if (cst == null) { this.visitInsn(ACONST_NULL); } else if (cst instanceof Integer) { int value = (Integer) cst; if (value >= -1 && value <= 5) { super.visitInsn(ICONST_0 + value); } else if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) { super.visitIntInsn(BIPUSH, value); } else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) { super.visitIntInsn(SIPUSH, value); } else { super.visitLdcInsn(cst); } } else if (cst instanceof Long) { long value = (Long) cst; if (value == 0L || value == 1L) { super.visitInsn(LCONST_0 + ((int) value)); } else { super.visitLdcInsn(cst); } } else if (cst instanceof Float) { float value = (Float) cst; if (value == 0.0F) { super.visitInsn(FCONST_0); } else if (value == 1.0F) { super.visitInsn(FCONST_1); } else if (value == 2.0F) { super.visitInsn(FCONST_2); } else { super.visitLdcInsn(cst); } } else if (cst instanceof Double) { double value = (Double) cst; if (value == 0.0D) { super.visitInsn(DCONST_0); } else if (value == 1.0D) { super.visitInsn(DCONST_1); } else { super.visitLdcInsn(cst); } } else if (cst instanceof Type) { Type t = (Type) cst; switch (t.getSort()) { case Type.BOOLEAN: super.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;"); break; case Type.BYTE: super.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;"); break; case Type.CHAR: super.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;"); break; case Type.DOUBLE: super.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;"); break; case Type.FLOAT: super.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;"); break; case Type.INT: super.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); break; case Type.LONG: super.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;"); break; case Type.SHORT: super.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;"); break; default: super.visitLdcInsn(cst); } } else { super.visitLdcInsn(cst); } }
private static void insertSetObject( ClassWriter cw, String classNameInternal, ArrayList<Field> fields) { int maxStack = 6; MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "set", "(Ljava/lang/Object;ILjava/lang/Object;)V", 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); Type fieldType = Type.getType(field.getType()); mv.visitLabel(labels[i]); mv.visitFrame(F_SAME, 0, null, 0, null); if (!Modifier.isStatic(field.getModifiers())) { mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, classNameInternal); } mv.visitVarInsn(ALOAD, 3); switch (fieldType.getSort()) { case Type.BOOLEAN: mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z"); break; case Type.BYTE: mv.visitTypeInsn(CHECKCAST, "java/lang/Byte"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B"); break; case Type.CHAR: mv.visitTypeInsn(CHECKCAST, "java/lang/Character"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); break; case Type.SHORT: mv.visitTypeInsn(CHECKCAST, "java/lang/Short"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S"); break; case Type.INT: mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I"); break; case Type.FLOAT: mv.visitTypeInsn(CHECKCAST, "java/lang/Float"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F"); break; case Type.LONG: mv.visitTypeInsn(CHECKCAST, "java/lang/Long"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J"); break; case Type.DOUBLE: mv.visitTypeInsn(CHECKCAST, "java/lang/Double"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D"); break; case Type.ARRAY: mv.visitTypeInsn(CHECKCAST, fieldType.getDescriptor()); break; case Type.OBJECT: mv.visitTypeInsn(CHECKCAST, fieldType.getInternalName()); break; } mv.visitFieldInsn( Modifier.isStatic(field.getModifiers()) ? PUTSTATIC : PUTFIELD, classNameInternal, field.getName(), fieldType.getDescriptor()); mv.visitInsn(RETURN); } mv.visitLabel(defaultLabel); mv.visitFrame(F_SAME, 0, null, 0, null); } mv = insertThrowExceptionForFieldNotFound(mv); mv.visitMaxs(maxStack, 4); mv.visitEnd(); }
private static 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); if (!Modifier.isStatic(field.getModifiers())) { mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, classNameInternal); } mv.visitFieldInsn( Modifier.isStatic(field.getModifiers()) ? GETSTATIC : GETFIELD, classNameInternal, 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(); }
private GaMethod toMethod( ClassLoader loader, Class<?> clazz, String methodName, String methodDesc) throws ClassNotFoundException, NoSuchMethodException { final org.objectweb.asm.Type asmType = org.objectweb.asm.Type.getMethodType(methodDesc); // to arg types final Class<?>[] argsClasses = new Class<?>[asmType.getArgumentTypes().length]; for (int index = 0; index < argsClasses.length; index++) { // asm class descriptor to jvm class final Class<?> argumentClass; final Type argumentAsmType = asmType.getArgumentTypes()[index]; switch (argumentAsmType.getSort()) { case Type.BOOLEAN: { argumentClass = boolean.class; break; } case Type.CHAR: { argumentClass = char.class; break; } case Type.BYTE: { argumentClass = byte.class; break; } case Type.SHORT: { argumentClass = short.class; break; } case Type.INT: { argumentClass = int.class; break; } case Type.FLOAT: { argumentClass = float.class; break; } case Type.LONG: { argumentClass = long.class; break; } case Type.DOUBLE: { argumentClass = double.class; break; } case Type.ARRAY: { argumentClass = toClass(loader, argumentAsmType.getInternalName()); break; } case Type.VOID: { argumentClass = void.class; break; } case Type.OBJECT: case Type.METHOD: default: { argumentClass = toClass(loader, argumentAsmType.getClassName()); break; } } argsClasses[index] = argumentClass; } // to method or constructor if (GaCheckUtils.isEquals(methodName, "<init>")) { return GaMethod.newInit(toConstructor(clazz, argsClasses)); } else { return GaMethod.newMethod(toMethod(clazz, methodName, argsClasses)); } }