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