Search in sources :

Example 26 with Bytecode

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

the class MethodReplacementTransformer method generateBoxedConditionalCodeBlock.

/**
 * This method will take a method body and add it to an added method local
 * the bytecode is inserted inside a conditional that will only run the code
 * if the method number is correct variables are removed from the parameter
 * array and unboxed if nessesary the return value is boxed if nessesary
 * <p>
 * Much of this work is handled by helper classes
 */
private static void generateBoxedConditionalCodeBlock(int methodNumber, MethodInfo mInfo, ConstPool methodConstPool, CodeAttribute addedMethod, boolean staticMethod, boolean constructor) throws BadBytecode {
    // we need to insert a conditional
    Bytecode bc = new Bytecode(mInfo.getConstPool());
    CodeAttribute ca = (CodeAttribute) mInfo.getCodeAttribute().copy(mInfo.getConstPool(), Collections.emptyMap());
    if (staticMethod) {
        bc.addOpcode(Opcode.ILOAD_0);
    } else {
        bc.addOpcode(Opcode.ILOAD_1);
    }
    int methodCountIndex = methodConstPool.addIntegerInfo(methodNumber);
    bc.addLdc(methodCountIndex);
    bc.addOpcode(Opcode.IF_ICMPNE);
    // now we need to fix local variables and unbox parameters etc
    int addedCodeLength = mangleParameters(staticMethod, constructor, ca, mInfo.getDescriptor());
    int newMax = ca.getMaxLocals() + 2;
    if (constructor) {
        // for the extra
        newMax++;
    }
    if (newMax > addedMethod.getMaxLocals()) {
        addedMethod.setMaxLocals(newMax);
    }
    // later
    int offset = ca.getCodeLength();
    // offset is +3, 2 for the branch offset after the IF_ICMPNE and 1 to
    // take it past the end of the code
    // add the branch offset
    ManipulationUtils.add16bit(bc, offset + 3);
    // now we need to insert our generated conditional at the start of the
    // new method
    CodeIterator newInfo = ca.iterator();
    newInfo.insert(bc.get());
    // now insert the new method code at the beginning of the static method
    // code attribute
    addedMethod.iterator().insert(ca.getCode());
    // update the exception table
    int exOffset = bc.length() + addedCodeLength;
    for (int i = 0; i < mInfo.getCodeAttribute().getExceptionTable().size(); ++i) {
        int start = mInfo.getCodeAttribute().getExceptionTable().startPc(i) + exOffset;
        int end = mInfo.getCodeAttribute().getExceptionTable().endPc(i) + exOffset;
        int handler = mInfo.getCodeAttribute().getExceptionTable().handlerPc(i) + exOffset;
        int type = mInfo.getCodeAttribute().getExceptionTable().catchType(i);
        addedMethod.getExceptionTable().add(start, end, handler, type);
    }
    // rewriteFakeMethod makes sure that the return type is properly boxed
    if (!constructor) {
        rewriteFakeMethod(addedMethod.iterator(), mInfo.getDescriptor());
    }
}
Also used : CodeAttribute(javassist.bytecode.CodeAttribute) CodeIterator(javassist.bytecode.CodeIterator) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode)

Example 27 with Bytecode

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

the class MethodReplacementTransformer method rewriteFakeMethod.

private static void rewriteFakeMethod(CodeIterator methodBody, String methodDescriptor) {
    String ret = DescriptorUtils.getReturnType(methodDescriptor);
    // so it does not need to be boxed
    if (ret.length() != 1) {
        return;
    }
    // void methods are special
    if (ret.equals("V")) {
        while (methodBody.hasNext()) {
            try {
                int index = methodBody.next();
                int opcode = methodBody.byteAt(index);
                // to return a null value
                if (opcode == Opcode.RETURN) {
                    Bytecode code = new Bytecode(methodBody.get().getConstPool());
                    methodBody.writeByte(Opcode.ARETURN, index);
                    code.add(Opcode.ACONST_NULL);
                    methodBody.insertAt(index, code.get());
                }
            } catch (BadBytecode e) {
                throw new RuntimeException(e);
            }
        }
    } else {
        while (methodBody.hasNext()) {
            try {
                int index = methodBody.next();
                int opcode = methodBody.byteAt(index);
                switch(opcode) {
                    case Opcode.IRETURN:
                    case Opcode.LRETURN:
                    case Opcode.DRETURN:
                    case Opcode.FRETURN:
                        // write a NOP over the old return instruction
                        // insert the boxing code to get an object on the stack
                        methodBody.writeByte(Opcode.ARETURN, index);
                        Bytecode b = new Bytecode(methodBody.get().getConstPool());
                        Boxing.box(b, ret.charAt(0));
                        methodBody.insertAt(index, b.get());
                }
            } catch (BadBytecode e) {
                throw new RuntimeException(e);
            }
        }
    }
}
Also used : BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode) BadBytecode(javassist.bytecode.BadBytecode)

Example 28 with Bytecode

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

the class MethodReplacementTransformer method createRemovedMethod.

private static MethodInfo createRemovedMethod(ClassFile file, MethodData md, Class<?> oldClass, Set<MethodData> methodsToRemove) {
    if (md.getMethodName().equals("<clinit>")) {
        // if the static constructor is removed it gets added later on
        return null;
    // in the process
    }
    // load up the existing method object
    MethodInfo m = new MethodInfo(file.getConstPool(), md.getMethodName(), md.getDescriptor());
    m.setAccessFlags(md.getAccessFlags());
    // put the old annotations on the class
    if (md.getMethodName().equals("<init>")) {
        Constructor<?> meth;
        try {
            meth = md.getConstructor(oldClass);
        } catch (Exception e) {
            throw new RuntimeException("Error accessing existing constructor via reflection in not found", e);
        }
        m.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), meth));
    } else {
        Method meth;
        try {
            meth = md.getMethod(oldClass);
        } catch (Exception e) {
            throw new RuntimeException("Error accessing existing method via reflection in not found", e);
        }
        m.addAttribute(AnnotationReplacer.duplicateAnnotationsAttribute(file.getConstPool(), meth));
    }
    Bytecode b = new Bytecode(file.getConstPool(), 5, 3);
    b.addNew("java.lang.NoSuchMethodError");
    b.add(Opcode.DUP);
    b.addInvokespecial("java.lang.NoSuchMethodError", "<init>", "()V");
    b.add(Bytecode.ATHROW);
    CodeAttribute ca = b.toCodeAttribute();
    m.setCodeAttribute(ca);
    try {
        ca.computeMaxStack();
        file.addMethod(m);
    } catch (DuplicateMemberException e) {
        logger.error("Duplicate error", e);
    } catch (BadBytecode e) {
        logger.error("Bad bytecode", e);
    }
    methodsToRemove.add(md);
    return m;
}
Also used : DuplicateMemberException(javassist.bytecode.DuplicateMemberException) CodeAttribute(javassist.bytecode.CodeAttribute) MethodInfo(javassist.bytecode.MethodInfo) BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode) Method(java.lang.reflect.Method) DuplicateMemberException(javassist.bytecode.DuplicateMemberException) IllegalClassFormatException(java.lang.instrument.IllegalClassFormatException) IOException(java.io.IOException) BadBytecode(javassist.bytecode.BadBytecode)

Example 29 with Bytecode

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

the class MethodReplacementTransformer method mangleParameters.

/**
 * Takes method parameters out of an array and puts them into local variables in the correct location. Also
 * deals with unboxing if necessary
 *
 * @return the length of the added code
 */
private static int mangleParameters(boolean staticMethod, boolean constructor, CodeAttribute attribute, String methodSigniture) {
    try {
        int offset = 0;
        String[] data = DescriptorUtils.descriptorStringToParameterArray(methodSigniture);
        if (!staticMethod) {
            // non static methods have a this pointer as the first argument
            // which should not be mangled
            offset = 1;
        }
        // insert two new local variables, these are the fake method parameters
        attribute.insertLocalVar(offset, 1);
        attribute.insertLocalVar(offset, 1);
        if (constructor) {
            // constructors have an extra one
            attribute.insertLocalVar(offset, 1);
        }
        Bytecode code = new Bytecode(attribute.getConstPool());
        int varpos = offset + 2;
        if (constructor) {
            varpos++;
        }
        for (int i = 0; i < data.length; ++i) {
            // push the parameter array onto the stack
            if (staticMethod) {
                code.add(Opcode.ALOAD_1);
            } else {
                code.add(Opcode.ALOAD_2);
            }
            int index = attribute.getConstPool().addIntegerInfo(i);
            code.addLdc(index);
            code.add(Opcode.AALOAD);
            // what happens next depends on the type
            switch(data[i].charAt(0)) {
                case 'L':
                    // add a checkcast substring is to get rid of the L
                    code.addCheckcast(data[i].substring(1));
                    // now stick it into its proper local variable
                    code.addAstore(varpos);
                    varpos++;
                    break;
                case '[':
                    code.addCheckcast(data[i]);
                    // now stick it into its proper local variable
                    code.addAstore(varpos);
                    varpos++;
                    break;
                case 'I':
                    // integer, we need to unbox it
                    Boxing.unboxInt(code);
                    code.addIstore(varpos);
                    varpos++;
                    break;
                case 'S':
                    // short, we need to unbox it
                    Boxing.unboxShort(code);
                    code.addIstore(varpos);
                    varpos++;
                    break;
                case 'B':
                    // short, we need to unbox it
                    Boxing.unboxByte(code);
                    code.addIstore(varpos);
                    varpos++;
                    break;
                case 'J':
                    // long, we need to unbox it
                    Boxing.unboxLong(code);
                    code.addLstore(varpos);
                    varpos = varpos + 2;
                    break;
                case 'F':
                    Boxing.unboxFloat(code);
                    code.addFstore(varpos);
                    varpos++;
                    break;
                case 'D':
                    Boxing.unboxDouble(code);
                    code.addDstore(varpos);
                    varpos++;
                    break;
                case 'C':
                    Boxing.unboxChar(code);
                    code.addIstore(varpos);
                    varpos++;
                    break;
                case 'Z':
                    Boxing.unboxBoolean(code);
                    code.addIstore(varpos);
                    varpos++;
                    break;
            }
        }
        attribute.iterator().insert(0, code.get());
        return code.length();
    } catch (BadBytecode e) {
        throw new RuntimeException(e);
    }
}
Also used : BadBytecode(javassist.bytecode.BadBytecode) Bytecode(javassist.bytecode.Bytecode) BadBytecode(javassist.bytecode.BadBytecode)

Example 30 with Bytecode

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

the class PrintLn method println.

public static Bytecode println(ConstPool cp, String message) {
    Bytecode proxyBytecode = new Bytecode(cp);
    proxyBytecode.addGetstatic("java/lang/System", "out", "Ljava/io/PrintStream;");
    proxyBytecode.addLdc(message);
    proxyBytecode.addInvokevirtual("java.io.PrintStream", "println", "(Ljava/lang/String;)V");
    return proxyBytecode;
}
Also used : 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