Search in sources :

Example 31 with MethodInfo

use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.

the class Transformer method addMethodForInstrumentation.

/**
 * Adds a method to a class that re can redefine when the class is reloaded
 */
private void addMethodForInstrumentation(ClassFile file) {
    try {
        MethodInfo m = new MethodInfo(file.getConstPool(), Constants.ADDED_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
        m.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.SYNTHETIC);
        Bytecode b = new Bytecode(file.getConstPool(), 5, 3);
        if (BuiltinClassData.skipInstrumentation(file.getSuperclass())) {
            b.addNew(NoSuchMethodError.class.getName());
            b.add(Opcode.DUP);
            b.addInvokespecial(NoSuchMethodError.class.getName(), "<init>", "()V");
            b.add(Opcode.ATHROW);
        } else {
            // delegate to the parent class
            b.add(Bytecode.ALOAD_0);
            b.add(Bytecode.ILOAD_1);
            b.add(Bytecode.ALOAD_2);
            b.addInvokespecial(file.getSuperclass(), Constants.ADDED_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
            b.add(Bytecode.ARETURN);
        }
        CodeAttribute ca = b.toCodeAttribute();
        m.setCodeAttribute(ca);
        file.addMethod(m);
    } catch (DuplicateMemberException e) {
    // e.printStackTrace();
    }
    try {
        MethodInfo m = new MethodInfo(file.getConstPool(), Constants.ADDED_STATIC_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
        m.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC | AccessFlag.SYNTHETIC);
        Bytecode b = new Bytecode(file.getConstPool(), 5, 3);
        b.addNew(NoSuchMethodError.class.getName());
        b.add(Opcode.DUP);
        b.addInvokespecial(NoSuchMethodError.class.getName(), "<init>", "()V");
        b.add(Opcode.ATHROW);
        CodeAttribute ca = b.toCodeAttribute();
        m.setCodeAttribute(ca);
        file.addMethod(m);
    } catch (DuplicateMemberException e) {
    // e.printStackTrace();
    }
}
Also used : DuplicateMemberException(javassist.bytecode.DuplicateMemberException) CodeAttribute(javassist.bytecode.CodeAttribute) MethodInfo(javassist.bytecode.MethodInfo) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode)

Example 32 with MethodInfo

use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.

the class AnnotationDataStore method createParameterAnnotationsProxy.

private static Class<?> createParameterAnnotationsProxy(ClassLoader loader, ParameterAnnotationsAttribute annotations, int paramCount) {
    String proxyName = ProxyDefinitionStore.getProxyName();
    ClassFile proxy = new ClassFile(false, proxyName, "java.lang.Object");
    proxy.setAccessFlags(AccessFlag.PUBLIC);
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < paramCount; ++i) {
        sb.append("I");
    }
    MethodInfo method = new MethodInfo(proxy.getConstPool(), PROXY_METHOD_NAME, "(" + sb.toString() + ")V");
    Bytecode b = new Bytecode(proxy.getConstPool());
    b.add(Opcode.RETURN);
    method.setAccessFlags(AccessFlag.PUBLIC);
    method.setCodeAttribute(b.toCodeAttribute());
    method.getCodeAttribute().setMaxLocals(paramCount + 1);
    AttributeInfo an = annotations.copy(proxy.getConstPool(), Collections.EMPTY_MAP);
    method.addAttribute(an);
    try {
        proxy.addMethod(method);
        method.getCodeAttribute().computeMaxStack();
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(bytes);
        try {
            proxy.write(dos);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        ProxyDefinitionStore.saveProxyDefinition(loader, proxyName, bytes.toByteArray());
        return loader.loadClass(proxyName);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : AttributeInfo(javassist.bytecode.AttributeInfo) ClassFile(javassist.bytecode.ClassFile) DataOutputStream(java.io.DataOutputStream) MethodInfo(javassist.bytecode.MethodInfo) Bytecode(javassist.bytecode.Bytecode) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) IOException(java.io.IOException)

Example 33 with MethodInfo

use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.

the class ReflectionFieldAccessManipulator method transformClass.

public boolean transformClass(ClassFile file, ClassLoader loader, boolean modifiableClass, final Set<MethodInfo> modifiedMethods) {
    Map<Integer, RewriteData> methodCallLocations = new HashMap<>();
    Map<RewriteData, Integer> newClassPoolLocations = new HashMap<>();
    Integer fieldAccessLocation = null;
    // first we need to scan the constant pool looking for
    // CONSTANT_method_info_ref structures
    ConstPool pool = file.getConstPool();
    for (int i = 1; i < pool.getSize(); ++i) {
        // we have a method call
        if (pool.getTag(i) == ConstPool.CONST_Methodref || pool.getTag(i) == ConstPool.CONST_InterfaceMethodref) {
            String className, methodName;
            if (pool.getTag(i) == ConstPool.CONST_Methodref) {
                className = pool.getMethodrefClassName(i);
                methodName = pool.getMethodrefName(i);
            } else {
                className = pool.getInterfaceMethodrefClassName(i);
                methodName = pool.getInterfaceMethodrefName(i);
            }
            if (className.equals(Field.class.getName())) {
                RewriteData data = manipulationData.get(methodName);
                if (data != null) {
                    // store the location in the const pool of the method ref
                    methodCallLocations.put(i, data);
                    // method in the const pool
                    if (!newClassPoolLocations.containsKey(data)) {
                        if (fieldAccessLocation == null) {
                            fieldAccessLocation = pool.addClassInfo("org.fakereplace.reflection.FieldReflection");
                        }
                        int newNameAndType = pool.addNameAndTypeInfo(data.getMethodName(), data.getNewMethodDescriptor());
                        newClassPoolLocations.put(data, newNameAndType);
                    }
                }
            }
        }
    }
    // through the methods and replace instances of the call
    if (fieldAccessLocation != null) {
        List<MethodInfo> methods = file.getMethods();
        for (MethodInfo m : methods) {
            try {
                // ignore abstract methods
                if (m.getCodeAttribute() == null) {
                    continue;
                }
                CodeIterator it = m.getCodeAttribute().iterator();
                while (it.hasNext()) {
                    // loop through the bytecode
                    int index = it.next();
                    int op = it.byteAt(index);
                    // if the bytecode is a method invocation
                    if (op == CodeIterator.INVOKEVIRTUAL || op == CodeIterator.INVOKESTATIC || op == CodeIterator.INVOKEINTERFACE) {
                        int val = it.s16bitAt(index + 1);
                        // replacing
                        if (methodCallLocations.containsKey(val)) {
                            RewriteData data = methodCallLocations.get(val);
                            Bytecode b = new Bytecode(file.getConstPool());
                            prepareForIsFakeFieldCall(b, data);
                            b.addInvokestatic(fieldAccessLocation, "isFakeField", "(Ljava/lang/reflect/Field;)Z");
                            b.add(Opcode.IFEQ);
                            JumpMarker performRealCall = JumpUtils.addJumpInstruction(b);
                            // now perform the fake call
                            b.addInvokestatic(fieldAccessLocation, data.getMethodName(), data.getNewMethodDescriptor());
                            b.add(Opcode.GOTO);
                            JumpMarker finish = JumpUtils.addJumpInstruction(b);
                            performRealCall.mark();
                            b.addInvokevirtual(Field.class.getName(), data.getMethodName(), data.getMethodDescriptor());
                            finish.mark();
                            it.writeByte(CodeIterator.NOP, index);
                            it.writeByte(CodeIterator.NOP, index + 1);
                            it.writeByte(CodeIterator.NOP, index + 2);
                            if (op == CodeIterator.INVOKEINTERFACE) {
                                // INVOKEINTERFACE has some extra parameters
                                it.writeByte(CodeIterator.NOP, index + 3);
                                it.writeByte(CodeIterator.NOP, index + 4);
                            }
                            it.insertEx(b.get());
                            modifiedMethods.add(m);
                        }
                    }
                }
            } catch (Exception e) {
                log.error("Bad byte code transforming " + file.getName() + "." + m.getName(), e);
            }
        }
        return true;
    } else {
        return false;
    }
}
Also used : ConstPool(javassist.bytecode.ConstPool) JumpMarker(org.fakereplace.util.JumpMarker) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) Field(java.lang.reflect.Field) CodeIterator(javassist.bytecode.CodeIterator) MethodInfo(javassist.bytecode.MethodInfo) Bytecode(javassist.bytecode.Bytecode)

Example 34 with MethodInfo

use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.

the class ReflectionMethodAccessManipulator method transformClass.

public boolean transformClass(ClassFile file, ClassLoader loader, boolean modifiableClass, final Set<MethodInfo> modifiedMethods) {
    Set<Integer> methodCallLocations = new HashSet<>();
    Integer newCallLocation = null;
    Integer methodReflectionLocation = null;
    // first we need to scan the constant pool looking for
    // CONSTANT_method_info_ref structures
    ConstPool pool = file.getConstPool();
    for (int i = 1; i < pool.getSize(); ++i) {
        // we have a method call
        if (pool.getTag(i) == ConstPool.CONST_Methodref) {
            String className = pool.getMethodrefClassName(i);
            String methodName = pool.getMethodrefName(i);
            if (className.equals(Method.class.getName())) {
                if (methodName.equals("invoke")) {
                    // store the location in the const pool of the method ref
                    methodCallLocations.add(i);
                    // method in the const pool
                    if (newCallLocation == null) {
                        methodReflectionLocation = pool.addClassInfo("org.fakereplace.reflection.MethodReflection");
                        newCallLocation = pool.addNameAndTypeInfo(METHOD_NAME, REPLACED_METHOD_DESCRIPTOR);
                    }
                }
            }
        }
    }
    // through the methods and replace instances of the call
    if (newCallLocation != null) {
        List<MethodInfo> methods = file.getMethods();
        for (MethodInfo m : methods) {
            try {
                // ignore abstract methods
                if (m.getCodeAttribute() == null) {
                    continue;
                }
                CodeIterator it = m.getCodeAttribute().iterator();
                while (it.hasNext()) {
                    // loop through the bytecode
                    int index = it.next();
                    int op = it.byteAt(index);
                    // if the bytecode is a method invocation
                    if (op == CodeIterator.INVOKEVIRTUAL) {
                        int val = it.s16bitAt(index + 1);
                        // replacing
                        if (methodCallLocations.contains(val)) {
                            Bytecode b = new Bytecode(file.getConstPool());
                            // our stack looks like Method, instance,params
                            // we need Method, instance, params , Method
                            b.add(Opcode.DUP_X2);
                            b.add(Opcode.POP);
                            b.add(Opcode.DUP_X2);
                            b.add(Opcode.POP);
                            b.add(Opcode.DUP_X2);
                            b.addInvokestatic(methodReflectionLocation, "fakeCallRequired", "(Ljava/lang/reflect/Method;)Z");
                            b.add(Opcode.IFEQ);
                            JumpMarker performRealCall = JumpUtils.addJumpInstruction(b);
                            // now perform the fake call
                            b.addInvokestatic(methodReflectionLocation, "invoke", REPLACED_METHOD_DESCRIPTOR);
                            b.add(Opcode.GOTO);
                            JumpMarker finish = JumpUtils.addJumpInstruction(b);
                            performRealCall.mark();
                            b.addInvokevirtual(Method.class.getName(), METHOD_NAME, METHOD_DESCRIPTOR);
                            finish.mark();
                            it.writeByte(CodeIterator.NOP, index);
                            it.writeByte(CodeIterator.NOP, index + 1);
                            it.writeByte(CodeIterator.NOP, index + 2);
                            it.insertEx(b.get());
                            modifiedMethods.add(m);
                        }
                    }
                }
            } catch (Exception e) {
                log.error("Bad byte code transforming " + file.getName(), e);
            }
        }
        return true;
    } else {
        return false;
    }
}
Also used : ConstPool(javassist.bytecode.ConstPool) JumpMarker(org.fakereplace.util.JumpMarker) Method(java.lang.reflect.Method) CodeIterator(javassist.bytecode.CodeIterator) MethodInfo(javassist.bytecode.MethodInfo) Bytecode(javassist.bytecode.Bytecode) HashSet(java.util.HashSet)

Example 35 with MethodInfo

use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.

the class VirtualToStaticManipulator method transformClass.

public boolean transformClass(ClassFile file, ClassLoader loader, boolean modifiableClass, final Set<MethodInfo> modifiedMethods) {
    final Map<String, Set<Data>> virtualToStaticMethod = data.getManipulationData(loader);
    final Map<Integer, Data> methodCallLocations = new HashMap<>();
    final Map<Data, Integer> newClassPoolLocations = new HashMap<>();
    final Map<Data, Integer> newCallLocations = new HashMap<>();
    // first we need to scan the constant pool looking for
    // CONSTANT_method_info_ref structures
    ConstPool pool = file.getConstPool();
    for (int i = 1; i < pool.getSize(); ++i) {
        // we have a method call
        if (pool.getTag(i) == ConstPool.CONST_Methodref || pool.getTag(i) == ConstPool.CONST_InterfaceMethodref) {
            String className, methodDesc, methodName;
            if (pool.getTag(i) == ConstPool.CONST_Methodref) {
                className = pool.getMethodrefClassName(i);
                methodDesc = pool.getMethodrefType(i);
                methodName = pool.getMethodrefName(i);
            } else {
                className = pool.getInterfaceMethodrefClassName(i);
                methodDesc = pool.getInterfaceMethodrefType(i);
                methodName = pool.getInterfaceMethodrefName(i);
            }
            if (virtualToStaticMethod.containsKey(className)) {
                for (Data data : virtualToStaticMethod.get(className)) {
                    if (methodName.equals(data.getMethodName()) && methodDesc.equals(data.getMethodDesc())) {
                        // store the location in the const pool of the method ref
                        methodCallLocations.put(i, data);
                        // method in the const pool
                        if (!newClassPoolLocations.containsKey(data)) {
                            // we have not added the new class reference or
                            // the new call location to the class pool yet
                            int newCpLoc;
                            if (data.getNewClass() != null) {
                                newCpLoc = pool.addClassInfo(data.getNewClass());
                            } else {
                                newCpLoc = pool.addClassInfo(file.getName());
                            }
                            newClassPoolLocations.put(data, newCpLoc);
                            int newNameAndType = pool.addNameAndTypeInfo(data.getNewMethodName(), data.getNewStaticMethodDesc());
                            newCallLocations.put(data, pool.addMethodrefInfo(newCpLoc, newNameAndType));
                        }
                        break;
                    }
                }
            }
        }
    }
    // through the methods and replace instances of the call
    if (!newClassPoolLocations.isEmpty()) {
        List<MethodInfo> methods = file.getMethods();
        for (MethodInfo m : methods) {
            try {
                // ignore abstract methods
                if (m.getCodeAttribute() == null) {
                    continue;
                }
                CodeIterator it = m.getCodeAttribute().iterator();
                while (it.hasNext()) {
                    // loop through the bytecode
                    int index = it.next();
                    int op = it.byteAt(index);
                    // if the bytecode is a method invocation
                    if (op == CodeIterator.INVOKEVIRTUAL || op == CodeIterator.INVOKESTATIC || op == CodeIterator.INVOKEINTERFACE || op == CodeIterator.INVOKESPECIAL) {
                        int val = it.s16bitAt(index + 1);
                        // replacing
                        if (methodCallLocations.containsKey(val)) {
                            Data data = methodCallLocations.get(val);
                            // change the call to an invokestatic
                            it.writeByte(CodeIterator.INVOKESTATIC, index);
                            // change the method that is being called
                            it.write16bit(newCallLocations.get(data), index + 1);
                            if (op == CodeIterator.INVOKEINTERFACE) {
                                // INVOKEINTERFACE has some extra parameters
                                it.writeByte(CodeIterator.NOP, index + 3);
                                it.writeByte(CodeIterator.NOP, index + 4);
                            }
                            modifiedMethods.add(m);
                        }
                    }
                }
            } catch (Exception e) {
                log.error("Bad byte code transforming " + file.getName(), e);
                e.printStackTrace();
            }
        }
        return true;
    } else {
        return false;
    }
}
Also used : ConstPool(javassist.bytecode.ConstPool) Set(java.util.Set) HashMap(java.util.HashMap) CodeIterator(javassist.bytecode.CodeIterator) MethodInfo(javassist.bytecode.MethodInfo)

Aggregations

MethodInfo (javassist.bytecode.MethodInfo)54 Bytecode (javassist.bytecode.Bytecode)28 BadBytecode (javassist.bytecode.BadBytecode)19 CodeIterator (javassist.bytecode.CodeIterator)18 CodeAttribute (javassist.bytecode.CodeAttribute)17 ConstPool (javassist.bytecode.ConstPool)17 ClassFile (javassist.bytecode.ClassFile)12 LocalVariableAttribute (javassist.bytecode.LocalVariableAttribute)10 DuplicateMemberException (javassist.bytecode.DuplicateMemberException)9 List (java.util.List)7 ClassPool (javassist.ClassPool)7 ByteArrayOutputStream (java.io.ByteArrayOutputStream)6 DataOutputStream (java.io.DataOutputStream)6 IOException (java.io.IOException)6 CtMethod (javassist.CtMethod)6 HashMap (java.util.HashMap)5 HashSet (java.util.HashSet)5 Set (java.util.Set)5 AnnotationsAttribute (javassist.bytecode.AnnotationsAttribute)5 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)4