blob: d063e15f714d850c66c15afe3cfa9db3ecf13afc [file] [log] [blame]
package com.android.tools.layoutlib.create;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
public class DelegateToNativeAdapter extends ClassVisitor {
private final Log mLog;
private final ClassWriter mDelegateWriter;
private final String mDelegateName;
private final String mClassName;
private final Set<String> mDelegateMethods;
public DelegateToNativeAdapter(Log logger, ClassVisitor cv, String className,
Map<String, ClassWriter> delegates, Set<String> delegateMethods) {
super(Main.ASM_VERSION, cv);
mLog = logger;
mDelegateWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
mClassName = className;
mDelegateName = (className + "_NativeDelegate").replace('$', '_');
mDelegateMethods = delegateMethods;
delegates.put(mDelegateName, mDelegateWriter);
}
@Override
public void visit(int version, int access, String name, String signature, String superName,
String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
mDelegateWriter.visit(version, Opcodes.ACC_PUBLIC, mDelegateName, null, "java/lang/Object",
null);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
String[] exceptions) {
boolean isStaticMethod = (access & Opcodes.ACC_STATIC) != 0;
boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
if (isNative) {
mDelegateWriter.visitMethod(access, name + "_Original", desc, signature, exceptions);
generateDelegateMethod(name, desc, signature, exceptions);
if (mDelegateMethods == null || !mDelegateMethods.contains(name)) {
// Remove native flag
access = access & ~Opcodes.ACC_NATIVE;
MethodVisitor mwDelegate =
super.visitMethod(access, name, desc, signature, exceptions);
DelegateMethodAdapter a =
new DelegateMethodAdapter(mLog, null, mwDelegate, mClassName, mDelegateName,
name, desc, isStaticMethod, false);
// A native has no code to visit, so we need to generate it directly.
a.generateDelegateCode();
return mwDelegate;
}
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
private void generateDelegateMethod(String name, String desc, String signature,
String[] exceptions) {
MethodVisitor delegateVisitor =
mDelegateWriter.visitMethod(Opcodes.ACC_STATIC, name, desc,
signature,
exceptions);
AnnotationVisitor aw = delegateVisitor.visitAnnotation(
Type.getObjectType(Type.getInternalName(LayoutlibDelegate.class)).toString(),
true); // visible at runtime
if (aw != null) {
aw.visitEnd();
}
delegateVisitor.visitCode();
int maxStack = 0;
int maxLocals = 0;
Type[] argTypes = Type.getArgumentTypes(desc);
for (Type t : argTypes) {
int size = t.getSize();
delegateVisitor.visitVarInsn(t.getOpcode(Opcodes.ILOAD), maxLocals);
maxLocals += size;
maxStack += size;
}
delegateVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, mDelegateName,
name + "_Original", desc, false);
Type returnType = Type.getReturnType(desc);
delegateVisitor.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
delegateVisitor.visitMaxs(maxStack, maxLocals);
delegateVisitor.visitEnd();
}
}