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());
}
}
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);
}
}
}
}
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;
}
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);
}
}
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;
}
Aggregations