use of javassist.bytecode.MethodInfo in project fakereplace by fakereplace.
the class Transformer method addMethodForInstrumentation.
/**
* Adds a method to a class that re can redefine when the class is reloaded
*/
private void addMethodForInstrumentation(ClassFile file) {
try {
MethodInfo m = new MethodInfo(file.getConstPool(), Constants.ADDED_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
m.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.SYNTHETIC);
Bytecode b = new Bytecode(file.getConstPool(), 5, 3);
if (BuiltinClassData.skipInstrumentation(file.getSuperclass())) {
b.addNew(NoSuchMethodError.class.getName());
b.add(Opcode.DUP);
b.addInvokespecial(NoSuchMethodError.class.getName(), "<init>", "()V");
b.add(Opcode.ATHROW);
} else {
// delegate to the parent class
b.add(Bytecode.ALOAD_0);
b.add(Bytecode.ILOAD_1);
b.add(Bytecode.ALOAD_2);
b.addInvokespecial(file.getSuperclass(), Constants.ADDED_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
b.add(Bytecode.ARETURN);
}
CodeAttribute ca = b.toCodeAttribute();
m.setCodeAttribute(ca);
file.addMethod(m);
} catch (DuplicateMemberException e) {
// e.printStackTrace();
}
try {
MethodInfo m = new MethodInfo(file.getConstPool(), Constants.ADDED_STATIC_METHOD_NAME, Constants.ADDED_METHOD_DESCRIPTOR);
m.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC | AccessFlag.SYNTHETIC);
Bytecode b = new Bytecode(file.getConstPool(), 5, 3);
b.addNew(NoSuchMethodError.class.getName());
b.add(Opcode.DUP);
b.addInvokespecial(NoSuchMethodError.class.getName(), "<init>", "()V");
b.add(Opcode.ATHROW);
CodeAttribute ca = b.toCodeAttribute();
m.setCodeAttribute(ca);
file.addMethod(m);
} catch (DuplicateMemberException e) {
// e.printStackTrace();
}
}
use of javassist.bytecode.MethodInfo 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.MethodInfo 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.MethodInfo 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.MethodInfo in project fakereplace by fakereplace.
the class VirtualToStaticManipulator method transformClass.
public boolean transformClass(ClassFile file, ClassLoader loader, boolean modifiableClass, final Set<MethodInfo> modifiedMethods) {
final Map<String, Set<Data>> virtualToStaticMethod = data.getManipulationData(loader);
final Map<Integer, Data> methodCallLocations = new HashMap<>();
final Map<Data, Integer> newClassPoolLocations = new HashMap<>();
final Map<Data, Integer> newCallLocations = 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 || pool.getTag(i) == ConstPool.CONST_InterfaceMethodref) {
String className, methodDesc, methodName;
if (pool.getTag(i) == ConstPool.CONST_Methodref) {
className = pool.getMethodrefClassName(i);
methodDesc = pool.getMethodrefType(i);
methodName = pool.getMethodrefName(i);
} else {
className = pool.getInterfaceMethodrefClassName(i);
methodDesc = pool.getInterfaceMethodrefType(i);
methodName = pool.getInterfaceMethodrefName(i);
}
if (virtualToStaticMethod.containsKey(className)) {
for (Data data : virtualToStaticMethod.get(className)) {
if (methodName.equals(data.getMethodName()) && methodDesc.equals(data.getMethodDesc())) {
// store the location in the const pool of the method ref
methodCallLocations.put(i, data);
// method in the const pool
if (!newClassPoolLocations.containsKey(data)) {
// we have not added the new class reference or
// the new call location to the class pool yet
int newCpLoc;
if (data.getNewClass() != null) {
newCpLoc = pool.addClassInfo(data.getNewClass());
} else {
newCpLoc = pool.addClassInfo(file.getName());
}
newClassPoolLocations.put(data, newCpLoc);
int newNameAndType = pool.addNameAndTypeInfo(data.getNewMethodName(), data.getNewStaticMethodDesc());
newCallLocations.put(data, pool.addMethodrefInfo(newCpLoc, newNameAndType));
}
break;
}
}
}
}
}
// through the methods and replace instances of the call
if (!newClassPoolLocations.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.INVOKEVIRTUAL || op == CodeIterator.INVOKESTATIC || op == CodeIterator.INVOKEINTERFACE || op == CodeIterator.INVOKESPECIAL) {
int val = it.s16bitAt(index + 1);
// replacing
if (methodCallLocations.containsKey(val)) {
Data data = methodCallLocations.get(val);
// change the call to an invokestatic
it.writeByte(CodeIterator.INVOKESTATIC, index);
// change the method that is being called
it.write16bit(newCallLocations.get(data), index + 1);
if (op == CodeIterator.INVOKEINTERFACE) {
// INVOKEINTERFACE has some extra parameters
it.writeByte(CodeIterator.NOP, index + 3);
it.writeByte(CodeIterator.NOP, index + 4);
}
modifiedMethods.add(m);
}
}
}
} catch (Exception e) {
log.error("Bad byte code transforming " + file.getName(), e);
e.printStackTrace();
}
}
return true;
} else {
return false;
}
}
Aggregations