use of org.objectweb.asm.Type in project buck by facebook.
the class FirstOrderHelper method addDependencies.
private ImmutableSet<String> addDependencies(Iterable<ClassNode> allClasses) {
for (ClassNode classNode : allClasses) {
FirstOrderVisitorContext context = new FirstOrderVisitorContext();
classNode.accept(context.classVisitor);
FirstOrderTypeInfo info = context.builder.build();
knownTypes.put(info.type, info);
}
for (Type type : scenarioTypes) {
addFirstOrderTypes(type);
}
return resultBuilder.build();
}
use of org.objectweb.asm.Type in project android_frameworks_base by ParanoidAndroid.
the class DelegateMethodAdapter2 method generateDelegateCode.
/**
* Generates the new code for the method.
* <p/>
* For native methods, this must be invoked directly by {@link DelegateClassAdapter}
* (since they have no code to visit).
* <p/>
* Otherwise for non-native methods the {@link DelegateClassAdapter} simply needs to
* return this instance of {@link DelegateMethodAdapter2} and let the normal visitor pattern
* invoke it as part of the {@link ClassReader#accept(ClassVisitor, int)} workflow and then
* this method will be invoked from {@link MethodVisitor#visitEnd()}.
*/
public void generateDelegateCode() {
/*
* The goal is to generate a call to a static delegate method.
* If this method is non-static, the first parameter will be 'this'.
* All the parameters must be passed and then the eventual return type returned.
*
* Example, let's say we have a method such as
* public void myMethod(int a, Object b, ArrayList<String> c) { ... }
*
* We'll want to create a body that calls a delegate method like this:
* TheClass_Delegate.myMethod(this, a, b, c);
*
* If the method is non-static and the class name is an inner class (e.g. has $ in its
* last segment), we want to push the 'this' of the outer class first:
* OuterClass_InnerClass_Delegate.myMethod(
* OuterClass.this,
* OuterClass$InnerClass.this,
* a, b, c);
*
* Only one level of inner class is supported right now, for simplicity and because
* we don't need more.
*
* The generated class name is the current class name with "_Delegate" appended to it.
* One thing to realize is that we don't care about generics -- since generic types
* are erased at build time, they have no influence on the method name being called.
*/
// Add our annotation
AnnotationVisitor aw = mDelWriter.visitAnnotation(Type.getObjectType(Type.getInternalName(LayoutlibDelegate.class)).toString(), // visible at runtime
true);
if (aw != null) {
aw.visitEnd();
}
mDelWriter.visitCode();
if (mDelegateLineNumber != null) {
Object[] p = mDelegateLineNumber;
mDelWriter.visitLineNumber((Integer) p[0], (Label) p[1]);
}
ArrayList<Type> paramTypes = new ArrayList<Type>();
String delegateClassName = mClassName + DELEGATE_SUFFIX;
boolean pushedArg0 = false;
int maxStack = 0;
// Check if the last segment of the class name has inner an class.
// Right now we only support one level of inner classes.
Type outerType = null;
int slash = mClassName.lastIndexOf('/');
int dol = mClassName.lastIndexOf('$');
if (dol != -1 && dol > slash && dol == mClassName.indexOf('$')) {
String outerClass = mClassName.substring(0, dol);
outerType = Type.getObjectType(outerClass);
// Change a delegate class name to "com/foo/Outer_Inner_Delegate"
delegateClassName = delegateClassName.replace('$', '_');
}
// by the 'this' of any outer class, if any.
if (!mIsStatic) {
if (outerType != null) {
// The first-level inner class has a package-protected member called 'this$0'
// that points to the outer class.
// Push this.getField("this$0") on the call stack.
// var 0 = this
mDelWriter.visitVarInsn(Opcodes.ALOAD, 0);
mDelWriter.visitFieldInsn(Opcodes.GETFIELD, // class where the field is defined
mClassName, // field name
"this$0", // type of the field
outerType.getDescriptor());
maxStack++;
paramTypes.add(outerType);
}
// Push "this" for the instance method, which is always ALOAD 0
mDelWriter.visitVarInsn(Opcodes.ALOAD, 0);
maxStack++;
pushedArg0 = true;
paramTypes.add(Type.getObjectType(mClassName));
}
// Push all other arguments. Start at arg 1 if we already pushed 'this' above.
Type[] argTypes = Type.getArgumentTypes(mDesc);
int maxLocals = pushedArg0 ? 1 : 0;
for (Type t : argTypes) {
int size = t.getSize();
mDelWriter.visitVarInsn(t.getOpcode(Opcodes.ILOAD), maxLocals);
maxLocals += size;
maxStack += size;
paramTypes.add(t);
}
// Construct the descriptor of the delegate based on the parameters
// we pushed on the call stack. The return type remains unchanged.
String desc = Type.getMethodDescriptor(Type.getReturnType(mDesc), paramTypes.toArray(new Type[paramTypes.size()]));
// Invoke the static delegate
mDelWriter.visitMethodInsn(Opcodes.INVOKESTATIC, delegateClassName, mMethodName, desc);
Type returnType = Type.getReturnType(mDesc);
mDelWriter.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
mDelWriter.visitMaxs(maxStack, maxLocals);
mDelWriter.visitEnd();
// For debugging now. Maybe we should collect these and store them in
// a text file for helping create the delegates. We could also compare
// the text file to a golden and break the build on unsupported changes
// or regressions. Even better we could fancy-print something that looks
// like the expected Java method declaration.
mLog.debug("Delegate: %1$s # %2$s %3$s", delegateClassName, mMethodName, desc);
}
use of org.objectweb.asm.Type in project android_frameworks_base by ParanoidAndroid.
the class TransformClassAdapter method visitMethod.
/* Visits a method. */
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (mDeleteReturns != null) {
Type t = Type.getReturnType(desc);
if (t.getSort() == Type.OBJECT) {
String returnType = t.getInternalName();
if (returnType != null) {
if (mDeleteReturns.contains(returnType)) {
return null;
}
}
}
}
String methodSignature = mClassName.replace('/', '.') + "#" + name;
// change access to public
if (Main.sOptions.generatePublicAccess) {
access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE);
access |= Opcodes.ACC_PUBLIC;
}
// remove final
access = access & ~Opcodes.ACC_FINAL;
// and don't try to stub interfaces nor abstract non-native methods.
if (!mIsInterface && ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) != Opcodes.ACC_ABSTRACT) && (mStubAll || (access & Opcodes.ACC_NATIVE) != 0) || mStubMethods.contains(methodSignature)) {
boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
// remove abstract, final and native
access = access & ~(Opcodes.ACC_ABSTRACT | Opcodes.ACC_FINAL | Opcodes.ACC_NATIVE);
String invokeSignature = methodSignature + desc;
mLog.debug(" Stub: %s (%s)", invokeSignature, isNative ? "native" : "");
MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
return new StubMethodAdapter(mw, name, returnType(desc), invokeSignature, isStatic, isNative);
} else {
mLog.debug(" Keep: %s %s", name, desc);
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
use of org.objectweb.asm.Type in project MinecraftForge by MinecraftForge.
the class EventSubscriptionTransformer method buildEvents.
private boolean buildEvents(ClassNode classNode) throws Exception {
// Yes, this recursively loads classes until we get this base class. THIS IS NOT A ISSUE. Coremods should handle re-entry just fine.
// If they do not this a COREMOD issue NOT a Forge/LaunchWrapper issue.
Class<?> parent = this.getClass().getClassLoader().loadClass(classNode.superName.replace('/', '.'));
if (!Event.class.isAssignableFrom(parent)) {
return false;
}
//Class<?> listenerListClazz = Class.forName("net.minecraftforge.fml.common.eventhandler.ListenerList", false, getClass().getClassLoader());
Type tList = Type.getType("Lnet/minecraftforge/fml/common/eventhandler/ListenerList;");
boolean edited = false;
boolean hasSetup = false;
boolean hasGetListenerList = false;
boolean hasDefaultCtr = false;
boolean hasCancelable = false;
boolean hasResult = false;
String voidDesc = Type.getMethodDescriptor(VOID_TYPE);
String boolDesc = Type.getMethodDescriptor(BOOLEAN_TYPE);
String listDesc = tList.getDescriptor();
String listDescM = Type.getMethodDescriptor(tList);
for (MethodNode method : classNode.methods) {
if (method.name.equals("setup") && method.desc.equals(voidDesc) && (method.access & ACC_PROTECTED) == ACC_PROTECTED)
hasSetup = true;
if ((method.access & ACC_PUBLIC) == ACC_PUBLIC) {
if (method.name.equals("getListenerList") && method.desc.equals(listDescM))
hasGetListenerList = true;
if (method.name.equals("isCancelable") && method.desc.equals(boolDesc))
hasCancelable = true;
if (method.name.equals("hasResult") && method.desc.equals(boolDesc))
hasResult = true;
}
if (method.name.equals("<init>") && method.desc.equals(voidDesc))
hasDefaultCtr = true;
}
if (classNode.visibleAnnotations != null) {
for (AnnotationNode node : classNode.visibleAnnotations) {
if (!hasResult && node.desc.equals("Lnet/minecraftforge/fml/common/eventhandler/Event$HasResult;")) {
/* Add:
* public boolean hasResult()
* {
* return true;
* }
*/
MethodNode method = new MethodNode(ACC_PUBLIC, "hasResult", boolDesc, null, null);
method.instructions.add(new InsnNode(ICONST_1));
method.instructions.add(new InsnNode(IRETURN));
classNode.methods.add(method);
edited = true;
} else if (!hasCancelable && node.desc.equals("Lnet/minecraftforge/fml/common/eventhandler/Cancelable;")) {
/* Add:
* public boolean isCancelable()
* {
* return true;
* }
*/
MethodNode method = new MethodNode(ACC_PUBLIC, "isCancelable", boolDesc, null, null);
method.instructions.add(new InsnNode(ICONST_1));
method.instructions.add(new InsnNode(IRETURN));
classNode.methods.add(method);
edited = true;
}
}
}
if (hasSetup) {
if (!hasGetListenerList)
throw new RuntimeException("Event class defines setup() but does not define getListenerList! " + classNode.name);
else
return edited;
}
Type tSuper = Type.getType(classNode.superName);
//Add private static ListenerList LISTENER_LIST
classNode.fields.add(new FieldNode(ACC_PRIVATE | ACC_STATIC, "LISTENER_LIST", listDesc, null, null));
/*Add:
* public <init>()
* {
* super();
* }
*/
if (!hasDefaultCtr) {
MethodNode method = new MethodNode(ACC_PUBLIC, "<init>", voidDesc, null, null);
method.instructions.add(new VarInsnNode(ALOAD, 0));
method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "<init>", voidDesc, false));
method.instructions.add(new InsnNode(RETURN));
classNode.methods.add(method);
}
/*Add:
* protected void setup()
* {
* super.setup();
* if (LISTENER_LIST != NULL)
* {
* return;
* }
* LISTENER_LIST = new ListenerList(super.getListenerList());
* }
*/
MethodNode method = new MethodNode(ACC_PROTECTED, "setup", voidDesc, null, null);
method.instructions.add(new VarInsnNode(ALOAD, 0));
method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "setup", voidDesc, false));
method.instructions.add(new FieldInsnNode(GETSTATIC, classNode.name, "LISTENER_LIST", listDesc));
LabelNode initListener = new LabelNode();
method.instructions.add(new JumpInsnNode(IFNULL, initListener));
method.instructions.add(new InsnNode(RETURN));
method.instructions.add(initListener);
method.instructions.add(new FrameNode(F_SAME, 0, null, 0, null));
method.instructions.add(new TypeInsnNode(NEW, tList.getInternalName()));
method.instructions.add(new InsnNode(DUP));
method.instructions.add(new VarInsnNode(ALOAD, 0));
method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "getListenerList", listDescM, false));
method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tList.getInternalName(), "<init>", getMethodDescriptor(VOID_TYPE, tList), false));
method.instructions.add(new FieldInsnNode(PUTSTATIC, classNode.name, "LISTENER_LIST", listDesc));
method.instructions.add(new InsnNode(RETURN));
classNode.methods.add(method);
/*Add:
* public ListenerList getListenerList()
* {
* return this.LISTENER_LIST;
* }
*/
method = new MethodNode(ACC_PUBLIC, "getListenerList", listDescM, null, null);
method.instructions.add(new FieldInsnNode(GETSTATIC, classNode.name, "LISTENER_LIST", listDesc));
method.instructions.add(new InsnNode(ARETURN));
classNode.methods.add(method);
return true;
}
use of org.objectweb.asm.Type in project hudson-2.x by hudson.
the class SubClassGenerator method generate.
public <T> Class<? extends T> generate(Class<T> base, String name) {
//?
ClassWriter cw = new ClassWriter(false, false);
cw.visit(49, ACC_PUBLIC, name.replace('.', '/'), null, Type.getInternalName(base), null);
for (Constructor c : base.getDeclaredConstructors()) {
Class[] et = c.getExceptionTypes();
String[] exceptions = new String[et.length];
for (int i = 0; i < et.length; i++) exceptions[i] = Type.getInternalName(et[i]);
String methodDescriptor = getMethodDescriptor(c);
MethodVisitor m = cw.visitMethod(c.getModifiers(), "<init>", methodDescriptor, null, exceptions);
m.visitCode();
int index = 1;
m.visitVarInsn(ALOAD, 0);
for (Class param : c.getParameterTypes()) {
Type t = Type.getType(param);
m.visitVarInsn(t.getOpcode(ILOAD), index);
index += t.getSize();
}
m.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(base), "<init>", methodDescriptor);
m.visitInsn(RETURN);
m.visitMaxs(index, index);
m.visitEnd();
}
cw.visitEnd();
byte[] image = cw.toByteArray();
Class<? extends T> c = defineClass(name, image, 0, image.length).asSubclass(base);
Hudson h = Hudson.getInstance();
if (// null only during tests.
h != null)
// can't change the field type as it breaks binary compatibility
((UberClassLoader) h.pluginManager.uberClassLoader).addNamedClass(name, c);
return c;
}
Aggregations