use of org.objectweb.asm.tree.MethodNode in project atlas by alibaba.
the class TBIncrementalChangeVisitor method addDispatchMethod.
/**
* To each class, add the dispatch method called by the original code that acts as a trampoline to
* invoke the changed methods.
* <p>
* Pseudo code:
* <code>
* Object access$dispatch(String name, object[] args) {
* if (name.equals(
* "firstMethod.(L$type;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;")) {
* return firstMethod(($type)arg[0], (String)arg[1], arg[2]);
* }
* if (name.equals("secondMethod.(L$type;Ljava/lang/String;I;)V")) {
* secondMethod(($type)arg[0], (String)arg[1], (int)arg[2]);
* return;
* }
* ...
* StringBuilder $local1 = new StringBuilder();
* $local1.append("Method not found ");
* $local1.append(name);
* $local1.append(" in " + visitedClassName +
* "$dispatch implementation, restart the application");
* throw new $package/InstantReloadException($local1.toString());
* }
* </code>
*/
private void addDispatchMethod() {
int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_VARARGS;
Method m = new Method("ipc$dispatch", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;");
MethodVisitor visitor = super.visitMethod(access, m.getName(), m.getDescriptor(), null, null);
final GeneratorAdapter mv = new GeneratorAdapter(access, m, visitor);
if (TRACING_ENABLED) {
mv.push("Redirecting ");
mv.loadArg(0);
trace(mv, 2);
}
List<MethodNode> allMethods = new ArrayList<>();
// if invoked which should never happen.
if (!instantRunDisabled) {
// noinspection unchecked
allMethods.addAll(classNode.methods);
allMethods.addAll(addedMethods);
}
final Map<String, MethodNode> methods = new HashMap<>();
for (MethodNode methodNode : allMethods) {
if (methodNode.name.equals("<clinit>") || methodNode.name.equals("<init>")) {
continue;
}
if (!isAccessCompatibleWithInstantRun(methodNode.access)) {
continue;
}
methods.put(methodNode.name + "." + methodNode.desc, methodNode);
}
new StringSwitch() {
@Override
void visitString() {
mv.visitVarInsn(Opcodes.ALOAD, 1);
}
@Override
void visitCase(String methodName) {
MethodNode methodNode = methods.get(methodName);
String name = methodNode.name;
boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) != 0;
String newDesc = computeOverrideMethodDesc(methodNode.desc, isStatic);
if (TRACING_ENABLED) {
trace(mv, "M: " + name + " P:" + newDesc);
}
Type[] args = Type.getArgumentTypes(newDesc);
int argc = 0;
for (Type t : args) {
mv.visitVarInsn(Opcodes.ALOAD, 2);
mv.push(argc);
mv.visitInsn(Opcodes.AALOAD);
ByteCodeUtils.unbox(mv, t);
argc++;
}
mv.visitMethodInsn(Opcodes.INVOKESTATIC, visitedClassName + OVERRIDE_SUFFIX, isStatic ? computeOverrideMethodName(name, methodNode.desc) : name, newDesc, false);
Type ret = Type.getReturnType(methodNode.desc);
if (ret.getSort() == Type.VOID) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else {
mv.box(ret);
}
mv.visitInsn(Opcodes.ARETURN);
}
@Override
void visitDefault() {
writeMissingMessageWithHash(mv, visitedClassName);
}
}.visit(mv, methods.keySet());
mv.visitMaxs(0, 0);
mv.visitEnd();
super.visitEnd();
}
use of org.objectweb.asm.tree.MethodNode in project atlas by alibaba.
the class TBIncrementalSupportVisitor method createDispatchingThis.
/**
* Inserts a trampoline to this class so that the updated methods can make calls to
* constructors.
*
* <p>
* Pseudo code for this trampoline:
* <code>
* ClassName(Object[] args, Marker unused) {
* String name = (String) args[0];
* if (name.equals(
* "java/lang/ClassName.(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;")) {
* this((String)arg[1], arg[2]);
* return
* }
* if (name.equals("SuperClassName.(Ljava/lang/String;I)V")) {
* super((String)arg[1], (int)arg[2]);
* return;
* }
* ...
* StringBuilder $local1 = new StringBuilder();
* $local1.append("Method not found ");
* $local1.append(name);
* $local1.append(" in " $classType $super implementation");
* throw new $package/InstantReloadException($local1.toString());
* }
* </code>
*/
private void createDispatchingThis() {
// Gather all methods from itself and its superclasses to generate a giant constructor
// implementation.
// This will work fine as long as we don't support adding constructors to classes.
final Map<String, MethodNode> uniqueMethods = new HashMap<>();
addAllNewConstructors(uniqueMethods, classNode, true);
for (ClassNode parentNode : parentNodes) {
addAllNewConstructors(uniqueMethods, parentNode, false);
}
int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC;
Method m = new Method(ByteCodeUtils.CONSTRUCTOR, ALI_DISPATCHING_THIS_SIGNATURE);
MethodVisitor visitor = super.visitMethod(0, m.getName(), m.getDescriptor(), null, null);
final GeneratorAdapter mv = new GeneratorAdapter(access, m, visitor);
mv.visitCode();
// Mark this code as redirection code
Label label = new Label();
mv.visitLineNumber(0, label);
// Get and store the constructor canonical name.
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.push(1);
mv.visitInsn(Opcodes.AALOAD);
mv.unbox(Type.getType("Ljava/lang/String;"));
final int constructorCanonicalName = mv.newLocal(Type.getType("Ljava/lang/String;"));
mv.storeLocal(constructorCanonicalName);
new StringSwitch() {
@Override
void visitString() {
mv.loadLocal(constructorCanonicalName);
}
@Override
void visitCase(String canonicalName) {
MethodNode methodNode = uniqueMethods.get(canonicalName);
String owner = canonicalName.split("\\.")[0];
// Parse method arguments and
mv.visitVarInsn(Opcodes.ALOAD, 0);
Type[] args = Type.getArgumentTypes(methodNode.desc);
int argc = 1;
for (Type t : args) {
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.push(argc + 1);
mv.visitInsn(Opcodes.AALOAD);
ByteCodeUtils.unbox(mv, t);
argc++;
}
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, ByteCodeUtils.CONSTRUCTOR, methodNode.desc, false);
mv.visitInsn(Opcodes.RETURN);
}
@Override
void visitDefault() {
// mv.visitInsn(Opcodes.RETURN);
writeMissingMessageWithHash(mv, visitedClassName);
}
@Override
void visit(GeneratorAdapter mv, Set<String> strings) {
super.visit(mv, strings);
}
}.visit(mv, uniqueMethods.keySet());
mv.visitMaxs(1, 3);
mv.visitEnd();
}
use of org.objectweb.asm.tree.MethodNode in project robolectric by robolectric.
the class ClassInstrumentor method addSetToSparseArray.
// See https://github.com/robolectric/robolectric/issues/6840
// Adds Set(int, object) to android.util.SparseArray.
private void addSetToSparseArray(MutableClass mutableClass) {
for (MethodNode method : mutableClass.getMethods()) {
if ("set".equals(method.name)) {
return;
}
}
MethodNode setFunction = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, "set", "(ILjava/lang/Object;)V", "(ITE;)V", null);
RobolectricGeneratorAdapter generator = new RobolectricGeneratorAdapter(setFunction);
generator.loadThis();
generator.loadArg(0);
generator.loadArg(1);
generator.invokeVirtual(mutableClass.classType, new Method("put", "(ILjava/lang/Object;)V"));
generator.returnValue();
mutableClass.addMethod(setFunction);
}
use of org.objectweb.asm.tree.MethodNode in project robolectric by robolectric.
the class ClassInstrumentor method addNoArgsConstructor.
private static void addNoArgsConstructor(MutableClass mutableClass) {
if (!mutableClass.foundMethods.contains("<init>()V")) {
MethodNode defaultConstructor = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, "<init>", "()V", "()V", null);
RobolectricGeneratorAdapter generator = new RobolectricGeneratorAdapter(defaultConstructor);
generator.loadThis();
generator.visitMethodInsn(Opcodes.INVOKESPECIAL, mutableClass.classNode.superName, "<init>", "()V", false);
generator.loadThis();
generator.invokeVirtual(mutableClass.classType, new Method(ROBO_INIT_METHOD_NAME, "()V"));
generator.returnValue();
mutableClass.addMethod(defaultConstructor);
}
}
use of org.objectweb.asm.tree.MethodNode in project robolectric by robolectric.
the class ClassInstrumentor method addRoboInitMethod.
/**
* Generates code like this:
*
* <pre>
* protected void $$robo$init() {
* if (__robo_data__ == null) {
* __robo_data__ = RobolectricInternals.initializing(this);
* }
* }
* </pre>
*/
private void addRoboInitMethod(MutableClass mutableClass) {
MethodNode initMethodNode = new MethodNode(Opcodes.ACC_PROTECTED | Opcodes.ACC_SYNTHETIC, ROBO_INIT_METHOD_NAME, "()V", null, null);
RobolectricGeneratorAdapter generator = new RobolectricGeneratorAdapter(initMethodNode);
Label alreadyInitialized = new Label();
// this
generator.loadThis();
generator.getField(mutableClass.classType, ShadowConstants.CLASS_HANDLER_DATA_FIELD_NAME, // contents of __robo_data__
OBJECT_TYPE);
generator.ifNonNull(alreadyInitialized);
// this
generator.loadThis();
// this, this
generator.loadThis();
writeCallToInitializing(mutableClass, generator);
// this, __robo_data__
generator.putField(mutableClass.classType, ShadowConstants.CLASS_HANDLER_DATA_FIELD_NAME, OBJECT_TYPE);
generator.mark(alreadyInitialized);
generator.returnValue();
mutableClass.addMethod(initMethodNode);
}
Aggregations