Commits

Shashank Bharadwaj  committed d900844

Update to use ASM4.
* This commit changes all classes under expose/generate/.. to be complient with ASM4
* I've also added some helper functions in Code.java to help with indy
* This changeset contains a change to CodeCompiler, this was required because it was incorrectly using the ASM APIs. Please read the comments in there for more info.

  • Participants
  • Parent commits f24fe48
  • Branches update-asm4

Comments (0)

Files changed (8)

File src/org/python/compiler/Code.java

 package org.python.compiler;
 
+
+import static org.python.util.CodegenUtils.sig;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles.Lookup;
 import java.util.BitSet;
 import java.util.Vector;
 
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Handle;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 
-class Code implements MethodVisitor, Opcodes {
+class Code extends MethodVisitor implements Opcodes {
     MethodVisitor mv;
     String sig;
     String locals[];
     //XXX: I'd really like to get sig and access out of here since MethodVistitor
     //     should already have this information.
     public Code(MethodVisitor mv, String sig, int access) {
+        super(ASM4);
         this.mv = mv;
         this.sig = sig;
         nlocals = -sigSize(sig, false);
         return mv.visitParameterAnnotation(arg0, arg1, arg2);
     }
 
-    public void visitTableSwitchInsn(int arg0, int arg1, Label arg2, Label[] arg3) {
+    public void visitTableSwitchInsn(int arg0, int arg1, Label arg2, Label... arg3) {
         mv.visitTableSwitchInsn(arg0, arg1, arg2, arg3);
     }
 
     public void setline(int line) {
         mv.visitLineNumber(line, new Label());
     }
+
+    @Override
+    public void visitInvokeDynamicInsn(String name, String descriptor, Handle bsmHandle, 
+                                       Object... bmsArgs) {
+        mv.visitInvokeDynamicInsn(name, descriptor, bsmHandle, bmsArgs);
+    }
+    
+    /**
+     * Convinience method to call {@link #visitInvokeDynamicInsn(String, String, MethodHandle, 
+     * Object...)} without having to create method handles. This method assumes that the 
+     * bootstrap method is a static one.
+     * 
+     * @param name name of the function to be invoked dyanmically
+     * @param descriptor method descriptor of the function to be invoked dyanmically
+     * @param bsmOwner owner class of the bootstrap method
+     * @param bsmName name of the bootstrap method
+     * @param bsmAccess how to invoke the bootstrap method. Usually one of
+     *        {@link Opcodes#MH_INVOKESTATIC}, or {@link Opcodes#MH_INVOKEVIRTUAL}. But it can be
+     *        other invokes too I guess. 
+     * @param bsmArgs list of arguments to be passed to bootstrap method
+     */
+    public void invokedynamic(String name, String descriptor, String bsmOwner, String bsmName,
+                              int bsmAccess, Object... bsmArgs) {
+        
+        String signature;
+        if (bsmArgs == null || bsmArgs.length == 0) {
+            signature = sig(CallSite.class, Lookup.class, String.class, 
+                            java.lang.invoke.MethodType.class); 
+        } else if (bsmArgs.length == 1) {
+            signature = sig(CallSite.class, Lookup.class, String.class, 
+                            java.lang.invoke.MethodType.class, Object.class);
+        } else {
+            signature = sig(CallSite.class, Lookup.class, String.class, 
+                            java.lang.invoke.MethodType.class, Object[].class);
+        }
+        
+        Handle bsmHandle = new Handle(bsmAccess, bsmOwner, bsmName, 
+                                                  signature);
+        visitInvokeDynamicInsn(name, descriptor, bsmHandle, bsmArgs);
+    }
+
 }

File src/org/python/compiler/CodeCompiler.java

 
         Object ret;
 
-        ExceptionHandler inFinally = new ExceptionHandler(node);
+        ExceptionHandler inFinally = initExceptionHandler(start, end, handlerStart, node);
 
         // Do protected suite
         exceptionHandlers.push(inFinally);
         code.astore(excLocal);
 
         code.label(start);
-        inFinally.exceptionStarts.addElement(start);
 
         ret = suite(node.getInternalBody());
 
         code.label(end);
-        inFinally.exceptionEnds.addElement(end);
         inFinally.bodyDone = true;
 
         exceptionHandlers.pop();
 
         code.freeLocal(excLocal);
 
-        inFinally.addExceptionHandlers(handlerStart);
         // According to any JVM verifiers, this code block might not return
         return null;
     }
         Label end = new Label();
         Label handler_start = new Label();
         Label handler_end = new Label();
-        ExceptionHandler handler = new ExceptionHandler();
-
+        
         code.label(start);
-        handler.exceptionStarts.addElement(start);
+        ExceptionHandler handler = initExceptionHandler(start, end, handler_start, null);
+        
         exceptionHandlers.push(handler);
         //Do suite
         Object exit = suite(node.getInternalBody());
         exceptionHandlers.pop();
         code.label(end);
-        handler.exceptionEnds.addElement(end);
 
         if (exit == null) {
             code.goto_(handler_end);
         }
 
         code.freeFinallyLocal(exc);
-        handler.addExceptionHandlers(handler_start);
+
         return null;
     }
 
         exceptionHandlers.push(normalExit);
 
         // try-catch block here
-        ExceptionHandler handler = new ExceptionHandler();
+		ExceptionHandler handler = initExceptionHandler(label_body_start, label_body_end, label_catch, null);
+		
         exceptionHandlers.push(handler);
-        handler.exceptionStarts.addElement(label_body_start);
 
         // VAR = value  # Only if "as VAR" is present
         code.label(label_body_start);
         exceptionHandlers.pop();
         exceptionHandlers.pop();
         code.label(label_body_end);
-        handler.exceptionEnds.addElement(label_body_end);
 
         // FINALLY if *not* non-local-goto
         if (blockResult == NoExit) {
         code.label(label_end);
         code.freeLocal(mgr_tmp);
 
-        handler.addExceptionHandlers(label_catch);
         return null;
     }
 
     }
 
     /**
+     * Creates a new ExceptionHandler and adds the appropriate start, end and 
+     * handler_start labels.
+     * 
+     * Initialize the {@link ExceptionHandler} correctly. This function should
+     * be called before any code for the body or the catch block are visited.
+     * To help with this, this function should be the only function that creates new
+     * ExceptionHandler.
+     * 
+     * @return a newly constructed and properly initialized ExceptionHandler
+     * @throws Exception
+     */
+	private ExceptionHandler initExceptionHandler(Label start, Label end, Label handler_start, PythonTree n) 
+			throws Exception {
+		ExceptionHandler handler = null;
+		if(n == null)
+			handler = new ExceptionHandler();
+		else
+			handler = new ExceptionHandler(n);
+        handler.exceptionStarts.addElement(start);
+        handler.exceptionEnds.addElement(end);
+        handler.addExceptionHandlers(handler_start);
+		return handler;
+	}
+
+
+    /**
      *  Data about a given exception range whether a try:finally: or a
      *  try:except:.  The finally needs to inline the finally block for
      *  each exit of the try: section, so we carry around that data for it.
 
         public void addExceptionHandlers(Label handlerStart) throws Exception {
             for (int i = 0; i < exceptionStarts.size(); ++i) {
-                Label start = exceptionStarts.elementAt(i);
-                Label end = exceptionEnds.elementAt(i);
-                //FIXME: not at all sure that getOffset() test is correct or necessary.
-                if (start.getOffset() != end.getOffset()) {
                     code.trycatch(
                             exceptionStarts.elementAt(i),
                             exceptionEnds.elementAt(i),
                             handlerStart,
                             p(Throwable.class));
-                }
             }
         }
 

File src/org/python/core/AnnotationReader.java

 
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.commons.EmptyVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
 
 /**
  * This class reads a classfile from a byte array and pulls out the value of the class annotation
  * cost too much, we will want to implement a special purpose ClassReader that only reads out the
  * APIVersion annotation I think.
  */
-public class AnnotationReader extends EmptyVisitor {
+public class AnnotationReader extends ClassVisitor {
 
     private boolean nextVisitIsVersion = false;
     private boolean nextVisitIsMTime = false;
      * @throws IOException - if the classfile is malformed.
      */
     public AnnotationReader(byte[] data) throws IOException {
+        super(Opcodes.ASM4);
         ClassReader r;
         try {
             r = new ClassReader(data);
         }
         r.accept(this, 0);
     }
-
+    
+    @Override
     public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
         nextVisitIsVersion = desc.equals("Lorg/python/compiler/APIVersion;");
         nextVisitIsMTime = desc.equals("Lorg/python/compiler/MTime;");
-        return this;
+        return super.visitAnnotation(desc, visible);
     }
 
     public void visit(String name, Object value) {

File src/org/python/expose/generate/ExposedFieldFinder.java

 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.Attribute;
 import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Opcodes;
 
-public abstract class ExposedFieldFinder implements FieldVisitor, PyTypes {
+public abstract class ExposedFieldFinder extends FieldVisitor implements PyTypes {
 
     private String fieldName;
 
     private String doc;
 
     public ExposedFieldFinder(String name, FieldVisitor delegate) {
+        super(Opcodes.ASM4, delegate);
         fieldName = name;
         this.delegate = delegate;
     }

File src/org/python/expose/generate/ExposedMethodFinder.java

 
 import org.python.expose.MethodType;
 import org.objectweb.asm.AnnotationVisitor;
-import org.objectweb.asm.MethodAdapter;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
  * annotation is visited, calls handleResult with the exposer constructed with that annotation. Only
  * one of the handleResult methods will be called, if any.
  */
-public abstract class ExposedMethodFinder extends MethodAdapter implements PyTypes, Opcodes {
+public abstract class ExposedMethodFinder extends MethodVisitor implements PyTypes, Opcodes {
 
     private Exposer newExp;
 
                                String desc,
                                String[] exceptions,
                                MethodVisitor delegate) {
-        super(delegate);
+        super(Opcodes.ASM4, delegate);
         this.typeName = typeName;
         this.onType = onType;
         this.access = access;
 
     class ExposedMethodVisitor extends RestrictiveAnnotationVisitor {
 
+        public ExposedMethodVisitor() {
+            super();
+        }
+
         @Override
         public void visit(String name, Object value) {
             if (name.equals("doc")) {

File src/org/python/expose/generate/ExposedTypeProcessor.java

 
 import org.python.expose.ExposedType;
 import org.objectweb.asm.AnnotationVisitor;
-import org.objectweb.asm.ClassAdapter;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.MethodAdapter;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
     /**
      * The actual visitor that runs over the bytecode and figures out what to expose.
      */
-    private final class TypeProcessor extends ClassAdapter {
+    private final class TypeProcessor extends ClassVisitor {
 
         private Type baseType = OBJECT;
 
         private boolean generatedStaticBlock;
 
         private TypeProcessor(ClassVisitor cv) {
-            super(cv);
+            super(Opcodes.ASM4, cv);
         }
 
         @Override
                                                                            desc,
                                                                            signature,
                                                                            exceptions);
-                return new MethodAdapter(passthroughVisitor) {
+                return new MethodVisitor(Opcodes.ASM4, passthroughVisitor) {
 
                     @Override
                     public void visitCode() {

File src/org/python/expose/generate/Exposer.java

         for (int i = 0; i < interfaces.length; i++) {
             interfaces[i] = interfacesImplemented[i].getInternalName();
         }
-        cv.visit(V1_5,
+        cv.visit(V1_7,
                  ACC_PUBLIC,
                  getInternalName(),
                  null,

File src/org/python/expose/generate/RestrictiveAnnotationVisitor.java

 package org.python.expose.generate;
 
 import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Opcodes;
 
 /**
  * An Annotation visitor that throws an IllegalArgumentException if it visits anything other than
  * visitEnd. Should be subclasses by something interested in only certain events.
  */
-public class RestrictiveAnnotationVisitor implements AnnotationVisitor {
+public class RestrictiveAnnotationVisitor extends AnnotationVisitor {
+
+    public RestrictiveAnnotationVisitor(int arg0) {
+        super(arg0);
+    }
+
+    public RestrictiveAnnotationVisitor() {
+        this(Opcodes.ASM4);
+    }
 
     public AnnotationVisitor visitAnnotation(String name, String desc) {
         throw new IllegalArgumentException("Unknown annotation field '" + name + "'");