use of org.fakereplace.util.JumpMarker 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 org.fakereplace.util.JumpMarker 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 org.fakereplace.util.JumpMarker in project fakereplace by fakereplace.
the class ReflectionConstructorAccessManipulator method transformClass.
public boolean transformClass(ClassFile file, ClassLoader loader, boolean modifiableClass, final Set<MethodInfo> modifiedMethods) {
Set<Integer> methodCallLocations = new HashSet<>();
Integer constructorReflectionLocation = 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(Constructor.class.getName())) {
if (methodName.equals(METHOD_NAME)) {
// store the location in the const pool of the method ref
methodCallLocations.add(i);
// method in the const pool
if (constructorReflectionLocation == null) {
constructorReflectionLocation = pool.addClassInfo(ConstructorReflection.class.getName());
}
}
}
}
}
// through the methods and replace instances of the call
if (constructorReflectionLocation != 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 Constructor,params
// we need Constructor, params, Constructor
b.add(Opcode.SWAP);
b.add(Opcode.DUP_X1);
b.addInvokestatic(constructorReflectionLocation, "fakeCallRequired", "(Ljava/lang/reflect/Constructor;)Z");
b.add(Opcode.IFEQ);
JumpMarker performRealCall = JumpUtils.addJumpInstruction(b);
// now perform the fake call
b.addInvokestatic(constructorReflectionLocation, METHOD_NAME, REPLACED_METHOD_DESCRIPTOR);
b.add(Opcode.GOTO);
JumpMarker finish = JumpUtils.addJumpInstruction(b);
performRealCall.mark();
b.addInvokevirtual(Constructor.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 org.fakereplace.util.JumpMarker in project fakereplace by fakereplace.
the class ClassLoaderInstrumentation method redefineClassLoader.
/**
* This method instruments class loaders so that they can load our helper
* classes.
*/
@SuppressWarnings("unchecked")
public static boolean redefineClassLoader(ClassFile classFile, Set<MethodInfo> modifiedMethods) throws BadBytecode {
boolean modified = false;
for (MethodInfo method : (List<MethodInfo>) classFile.getMethods()) {
if (Modifier.isStatic(method.getAccessFlags())) {
continue;
}
if (method.getName().equals("loadClass") && (method.getDescriptor().equals("(Ljava/lang/String;)Ljava/lang/Class;") || method.getDescriptor().equals("(Ljava/lang/String;Z)Ljava/lang/Class;"))) {
modifiedMethods.add(method);
modified = true;
if (method.getCodeAttribute().getMaxLocals() < 4) {
method.getCodeAttribute().setMaxLocals(4);
}
// now we instrument the loadClass
// if the system requests a class from the generated class package
// then
// we check to see if it is already loaded.
// if not we try and get the class definition from GlobalData
// we do not need to delegate as GlobalData will only
// return the data to the correct classloader.
// if the data is not null then we define the class, link
// it if requested and return it.
final CodeIterator iterator = method.getCodeAttribute().iterator();
final Bytecode b = new Bytecode(classFile.getConstPool());
b.addAload(1);
b.addAload(0);
b.addInvokestatic(ClassLookupManager.class.getName(), "getClassData", "(Ljava/lang/String;Ljava/lang/Object;)[B");
b.add(Opcode.DUP);
b.add(Opcode.IFNULL);
JumpMarker jumpEnd = JumpUtils.addJumpInstruction(b);
// now we need to do the findLoadedClasses thing
b.addAload(0);
b.addAload(1);
b.addInvokevirtual("java.lang.ClassLoader", "findLoadedClass", "(Ljava/lang/String;)Ljava/lang/Class;");
b.add(Opcode.DUP);
b.add(Opcode.IFNULL);
JumpMarker notFound = JumpUtils.addJumpInstruction(b);
b.add(Opcode.ARETURN);
notFound.mark();
b.add(Opcode.POP);
b.addAstore(3);
b.addAload(0);
b.addAload(1);
b.addAload(3);
b.addIconst(0);
b.addAload(3);
b.add(Opcode.ARRAYLENGTH);
b.addInvokevirtual("java.lang.ClassLoader", "defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
if (method.getDescriptor().equals("Ljava/lang/String;Z)Ljava/lang/Class;")) {
b.addIload(2);
} else {
b.addIconst(0);
}
b.add(Opcode.IFEQ);
final JumpMarker linkJumpEnd = JumpUtils.addJumpInstruction(b);
b.add(Opcode.DUP);
b.addAload(0);
b.add(Opcode.SWAP);
b.addInvokevirtual("java.lang.ClassLoader", "resolveClass", "(Ljava/lang/Class;)V");
linkJumpEnd.mark();
b.add(Opcode.ARETURN);
jumpEnd.mark();
b.add(Opcode.POP);
if (!classFile.getName().startsWith("java.") && !classFile.getName().startsWith("com.sun") && !classFile.getName().startsWith("sun") && !classFile.getName().startsWith("jdk.internal")) {
// now we need to check if this is a fakereplace class
// and if so always delegate to the appropriate loader
b.addAload(1);
b.addLdc("org.fakereplace");
b.addInvokevirtual(String.class.getName(), "startsWith", "(Ljava/lang/String;)Z");
b.add(Opcode.IFEQ);
JumpMarker notFakereplace = JumpUtils.addJumpInstruction(b);
// so this is a fakereplace class, delegate to the system loader
b.addInvokestatic(ClassLoader.class.getName(), "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
b.addAload(1);
b.addInvokevirtual(ClassLoader.class.getName(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
b.add(Opcode.ARETURN);
notFakereplace.mark();
}
iterator.insert(b.get());
method.getCodeAttribute().computeMaxStack();
}
}
return modified;
}
Aggregations