Search in sources :

Example 16 with Bytecode

use of javassist.bytecode.Bytecode 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 17 with Bytecode

use of javassist.bytecode.Bytecode 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 18 with Bytecode

use of javassist.bytecode.Bytecode 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 19 with Bytecode

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

the class ConstructorInvocationManipulator method transformClass.

public boolean transformClass(ClassFile file, ClassLoader loader, boolean modifiableClass, final Set<MethodInfo> modifiedMethods) {
    Map<String, Set<ConstructorRewriteData>> constructorRewrites = new HashMap<>(data.getManipulationData(loader));
    Map<Integer, ConstructorRewriteData> methodCallLocations = 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) {
            boolean handled = false;
            String className = pool.getMethodrefClassName(i);
            String methodDesc = pool.getMethodrefType(i);
            String methodName = pool.getMethodrefName(i);
            if (methodName.equals("<init>")) {
                if (constructorRewrites.containsKey(className)) {
                    for (ConstructorRewriteData data : constructorRewrites.get(className)) {
                        if (methodDesc.equals(data.getMethodDesc())) {
                            // store the location in the const pool of the method ref
                            methodCallLocations.put(i, data);
                            // we have found a method call
                            // now lets replace it
                            handled = true;
                            break;
                        }
                    }
                }
                if (!handled && Fakereplace.isClassReplaceable(className, loader)) {
                    // may be an added field
                    // if the field does not actually exist yet we just assume it is about to come into existence
                    // and rewrite it anyway
                    BaseClassData data = ClassDataStore.instance().getBaseClassData(loader, className);
                    if (data != null) {
                        MethodData method = data.getMethodOrConstructor("<init>", methodDesc);
                        if (method == null) {
                            // this is a new method
                            // lets deal with it
                            int methodNo = MethodIdentifierStore.instance().getMethodNumber("<init>", methodDesc);
                            methodCallLocations.put(i, new ConstructorRewriteData(className, methodDesc, methodNo, loader));
                        }
                    }
                }
            }
        }
    }
    // through the methods and replace instances of the call
    if (!methodCallLocations.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.INVOKESPECIAL) {
                        int val = it.s16bitAt(index + 1);
                        // replacing
                        if (methodCallLocations.containsKey(val)) {
                            ConstructorRewriteData data = methodCallLocations.get(val);
                            // so we currently have all the arguments sitting on the
                            // stack, and we need to jigger them into
                            // an array and then call our method. First thing to do
                            // is scribble over the existing
                            // instructions:
                            it.writeByte(CodeIterator.NOP, index);
                            it.writeByte(CodeIterator.NOP, index + 1);
                            it.writeByte(CodeIterator.NOP, index + 2);
                            Bytecode bc = new Bytecode(file.getConstPool());
                            ManipulationUtils.pushParametersIntoArray(bc, data.getMethodDesc());
                            // so now our stack looks like unconstructed instance : array
                            // we need unconstructed instance : int : array : null
                            bc.addIconst(data.getMethodNo());
                            bc.add(Opcode.SWAP);
                            bc.add(Opcode.ACONST_NULL);
                            bc.addInvokespecial(data.getClazz(), "<init>", Constants.ADDED_CONSTRUCTOR_DESCRIPTOR);
                            // and we have our bytecode
                            it.insert(bc.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) Set(java.util.Set) HashMap(java.util.HashMap) BaseClassData(org.fakereplace.data.BaseClassData) CodeIterator(javassist.bytecode.CodeIterator) MethodData(org.fakereplace.data.MethodData) MethodInfo(javassist.bytecode.MethodInfo) Bytecode(javassist.bytecode.Bytecode)

Example 20 with Bytecode

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

the class FakeMethodCallManipulator method handleFakeMethodCall.

private void handleFakeMethodCall(ClassFile file, Set<MethodInfo> modifiedMethods, MethodInfo m, CodeIterator it, int index, int op, Data data) throws BadBytecode {
    // NOP out the whole thing
    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);
    }
    // now we write some bytecode to invoke it directly
    final boolean staticMethod = data.getType() == Type.STATIC;
    Bytecode byteCode = new Bytecode(file.getConstPool());
    // stick the method number in the const pool then load it onto the
    // stack
    ManipulationUtils.pushParametersIntoArray(byteCode, data.getMethodDesc());
    int scind = file.getConstPool().addIntegerInfo(data.getMethodNumber());
    byteCode.addLdc(scind);
    byteCode.add(Opcode.SWAP);
    // invoke the added method
    if (staticMethod) {
        byteCode.addInvokestatic(data.getClassName(), Constants.ADDED_STATIC_METHOD_NAME, "(I[Ljava/lang/Object;)Ljava/lang/Object;");
    } else if (data.getType() == Type.INTERFACE) {
        byteCode.addInvokeinterface(data.getClassName(), Constants.ADDED_METHOD_NAME, "(I[Ljava/lang/Object;)Ljava/lang/Object;", 3);
    } else {
        byteCode.addInvokevirtual(data.getClassName(), Constants.ADDED_METHOD_NAME, "(I[Ljava/lang/Object;)Ljava/lang/Object;");
    }
    // cast it to the appropriate type and return it
    String returnType = DescriptorUtils.getReturnType(data.getMethodDesc());
    if (returnType.length() == 1 && !returnType.equals("V")) {
        Boxing.unbox(byteCode, returnType.charAt(0));
    } else if (returnType.equals("V")) {
        byteCode.add(Opcode.POP);
    } else {
        byteCode.addCheckcast(returnType.substring(1, returnType.length() - 1));
    }
    it.insertEx(byteCode.get());
    modifiedMethods.add(m);
}
Also used : BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode)

Aggregations

Bytecode (javassist.bytecode.Bytecode)36 MethodInfo (javassist.bytecode.MethodInfo)28 BadBytecode (javassist.bytecode.BadBytecode)24 CodeIterator (javassist.bytecode.CodeIterator)15 CodeAttribute (javassist.bytecode.CodeAttribute)11 ConstPool (javassist.bytecode.ConstPool)11 DuplicateMemberException (javassist.bytecode.DuplicateMemberException)8 IOException (java.io.IOException)6 List (java.util.List)6 ClassFile (javassist.bytecode.ClassFile)5 ByteArrayOutputStream (java.io.ByteArrayOutputStream)4 DataOutputStream (java.io.DataOutputStream)4 IllegalClassFormatException (java.lang.instrument.IllegalClassFormatException)4 Method (java.lang.reflect.Method)4 HashSet (java.util.HashSet)4 NotFoundException (javassist.NotFoundException)4 JumpMarker (org.fakereplace.util.JumpMarker)4 HashMap (java.util.HashMap)3 Set (java.util.Set)3 CannotCompileException (javassist.CannotCompileException)3