]> source.dussan.org Git - aspectj.git/commitdiff
can add stackmap attributes with: -1.6 -Xset:generateStackMaps=true
authoraclement <aclement>
Wed, 17 Sep 2008 19:49:01 +0000 (19:49 +0000)
committeraclement <aclement>
Wed, 17 Sep 2008 19:49:01 +0000 (19:49 +0000)
weaver/.classpath
weaver/src/org/aspectj/weaver/World.java
weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java
weaver/src/org/aspectj/weaver/bcel/asm/AsmDetector.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/bcel/asm/StackMapAdder.java [new file with mode: 0644]

index 0ac3d80ff217935c9ca5c36086a9f3849b2c822a..adee2df9722232a63320973097a47247328f64df 100644 (file)
@@ -12,5 +12,6 @@
        <classpathentry kind="lib" path="/lib/commons/commons.jar" sourcepath="/lib/commons/commons-src.zip"/>
        <classpathentry kind="lib" path="/lib/bcel/bcel.jar" sourcepath="/lib/bcel/bcel-src.zip"/>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+       <classpathentry kind="lib" path="/lib/asm/asm-3.1.jar"/>
        <classpathentry kind="output" path="bin"/>
 </classpath>
index 265ccbc0880aadeab46fa32eb8c973ca174b128f..ea1253a0a4eec310a4e755b6717914bdc82b9733 100644 (file)
@@ -111,6 +111,7 @@ public abstract class World implements Dump.INode {
        // Xset'table options
        private boolean runMinimalMemory = false;
        private boolean shouldPipelineCompilation = true;
+       private boolean shouldGenerateStackMaps = false;
        protected boolean bcelRepositoryCaching = xsetBCEL_REPOSITORY_CACHING_DEFAULT.equalsIgnoreCase("true");
        private boolean fastMethodPacking = false;
        private boolean completeBinaryTypes = false;
@@ -758,6 +759,7 @@ public abstract class World implements Dump.INode {
        public final static String xsetDEBUG_BRIDGING = "debugBridging"; // default false
        public final static String xsetBCEL_REPOSITORY_CACHING = "bcelRepositoryCaching";
        public final static String xsetPIPELINE_COMPILATION = "pipelineCompilation";
+       public final static String xsetGENERATE_STACKMAPS = "generateStackMaps";
        public final static String xsetPIPELINE_COMPILATION_DEFAULT = "true";
        public final static String xsetCOMPLETE_BINARY_TYPES = "completeBinaryTypes";
        public final static String xsetCOMPLETE_BINARY_TYPES_DEFAULT = "false";
@@ -1144,6 +1146,9 @@ public abstract class World implements Dump.INode {
 
                                s = p.getProperty(xsetPIPELINE_COMPILATION, xsetPIPELINE_COMPILATION_DEFAULT);
                                shouldPipelineCompilation = s.equalsIgnoreCase("true");
+                               
+                               s = p.getProperty(xsetGENERATE_STACKMAPS, "false");
+                               shouldGenerateStackMaps = s.equalsIgnoreCase("true");
 
                                s = p.getProperty(xsetCOMPLETE_BINARY_TYPES, xsetCOMPLETE_BINARY_TYPES_DEFAULT);
                                completeBinaryTypes = s.equalsIgnoreCase("true");
@@ -1183,7 +1188,12 @@ public abstract class World implements Dump.INode {
                ensureAdvancedConfigurationProcessed();
                return shouldPipelineCompilation;
        }
-
+       
+       public boolean shouldGenerateStackMaps() {
+               ensureAdvancedConfigurationProcessed();
+               return shouldGenerateStackMaps;
+       }
+       
        public void setIncrementalCompileCouldFollow(boolean b) {
                incrementalCompileCouldFollow = b;
        }
index 253e50e15dbbd90b11c6cf6bfecf03f53c7517f6..b70f7db94c85aba394f5a053adb51f0c421b2d95 100644 (file)
@@ -65,6 +65,8 @@ import org.aspectj.weaver.WeaverStateInfo;
 import org.aspectj.weaver.World;
 import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
 import org.aspectj.weaver.UnresolvedType.TypeKind;
+import org.aspectj.weaver.bcel.asm.AsmDetector;
+import org.aspectj.weaver.bcel.asm.StackMapAdder;
 
 /**
  * Lazy lazy lazy. We don't unpack the underlying class unless necessary. Things like new methods and annotations accumulate in here
@@ -79,23 +81,23 @@ public final class LazyClassGen {
 
        int highestLineNumber = 0; // ---- JSR 45 info
 
-       private final SortedMap /* <String, InlinedSourceFileInfo> */inlinedFiles = new TreeMap();
+       private SortedMap /* <String, InlinedSourceFileInfo> */inlinedFiles = new TreeMap();
 
        private boolean regenerateGenericSignatureAttribute = false;
 
        private BcelObjectType myType; // XXX is not set for types we create
        private ClassGen myGen;
-       private final ConstantPool cp;
-       private final World world;
-       private final String packageName = null;
-
-       private final List /* BcelField */fields = new ArrayList();
-       private final List /* LazyMethodGen */methodGens = new ArrayList();
-       private final List /* LazyClassGen */classGens = new ArrayList();
-       private final List /* AnnotationGen */annotations = new ArrayList();
+       private ConstantPool cp;
+       private World world;
+       private String packageName = null;
+
+       private List /* BcelField */fields = new ArrayList();
+       private List /* LazyMethodGen */methodGens = new ArrayList();
+       private List /* LazyClassGen */classGens = new ArrayList();
+       private List /* AnnotationGen */annotations = new ArrayList();
        private int childCounter = 0;
 
-       private final InstructionFactory fact;
+       private InstructionFactory fact;
 
        private boolean isSerializable = false;
        private boolean hasSerialVersionUIDField = false;
@@ -613,10 +615,10 @@ public final class LazyClassGen {
                writeBack(world);
                byte[] wovenClassFileData = myGen.getJavaClass().getBytes();
                // if is java 6 class file
-               // if (myGen.getMajor()>=Constants.MAJOR_1_6 && AsmDetector.isAsmAround) {
-               // wovenClassFileData = StackMapAdder.addStackMaps(wovenClassFileData);
-               // }
-
+               if (myGen.getMajor()>=Constants.MAJOR_1_6 && world.shouldGenerateStackMaps() && AsmDetector.isAsmAround) {
+                       wovenClassFileData = StackMapAdder.addStackMaps(world,wovenClassFileData);
+               }
+               
                WeaverStateInfo wsi = myType.getWeaverState();// getOrCreateWeaverStateInfo();
                if (wsi != null && wsi.isReweavable()) { // && !reweavableDataInserted
                        // reweavableDataInserted = true;
diff --git a/weaver/src/org/aspectj/weaver/bcel/asm/AsmDetector.java b/weaver/src/org/aspectj/weaver/bcel/asm/AsmDetector.java
new file mode 100644 (file)
index 0000000..415e38e
--- /dev/null
@@ -0,0 +1,26 @@
+package org.aspectj.weaver.bcel.asm;
+
+import java.lang.reflect.Method;
+
+/**
+ * Determines if a version of asm is around that will enable us to add
+ * stack map attributes to classes that we produce.
+ * 
+ * @author Andy Clement
+ */
+public class AsmDetector {
+
+       public static boolean isAsmAround;
+       
+       static {
+               try {
+                       Class reader = Class.forName("org.objectweb.asm.ClassReader");
+                       Class visitor = Class.forName("org.objectweb.asm.ClassVisitor");
+                       Method m = reader.getMethod("accept",new Class[]{visitor,Integer.TYPE});
+                       isAsmAround = m!=null;
+               } catch (Exception e ) {
+                       isAsmAround = false;
+               }
+               // System.out.println(isAsmAround?"ASM detected":"No ASM found");
+       }
+}
diff --git a/weaver/src/org/aspectj/weaver/bcel/asm/StackMapAdder.java b/weaver/src/org/aspectj/weaver/bcel/asm/StackMapAdder.java
new file mode 100644 (file)
index 0000000..96d6a88
--- /dev/null
@@ -0,0 +1,63 @@
+package org.aspectj.weaver.bcel.asm;
+
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+/**
+ * Uses asm to add the stack map attribute to methods in a class.  The class is passed in as pure byte data
+ * and then a reader/writer process it.  The writer is wired into the world so that types can be resolved
+ * and getCommonSuperClass() can be implemented without class loading using the context class loader.
+ * 
+ * @author Andy Clement
+ */
+public class StackMapAdder {
+
+       public static byte[] addStackMaps(World world, byte[] data) {
+               try {
+                       ClassReader cr = new ClassReader(data);
+                       ClassWriter cw = new AspectJConnectClassWriter(world);
+                       cr.accept(cw,0);
+                       return  cw.toByteArray();
+               } catch (Throwable t) {
+                       System.err.println("AspectJ Internal Error: unable to add stackmap attributes. "+t.getMessage());
+                       AsmDetector.isAsmAround=false;
+                       return data;
+               }
+       }
+       
+       private static class AspectJConnectClassWriter extends ClassWriter {
+               private World world;
+
+               public AspectJConnectClassWriter(World w) {
+                       super(ClassWriter.COMPUTE_FRAMES);
+                       this.world = w;
+               }
+
+               // Implementation of getCommonSuperClass() that avoids Class.forName()
+               protected String getCommonSuperClass(final String type1, final String type2) {
+                         
+                 ResolvedType resolvedType1 = world.resolve(UnresolvedType.forName(type1.replace('/','.')));
+                 ResolvedType resolvedType2 = world.resolve(UnresolvedType.forName(type2.replace('/','.')));
+                 
+                 if (resolvedType1.isAssignableFrom(resolvedType2)) {
+                         return type1;
+                 }
+                 
+                 if (resolvedType2.isAssignableFrom(resolvedType1)) {
+                         return type2;
+                 }
+                 
+                 if (resolvedType1.isInterface() || resolvedType2.isInterface()) {
+                         return "java/lang/Object";
+                 } else {
+                         do {
+                                 resolvedType1 = resolvedType1.getSuperclass();
+                         } while (!resolvedType1.isAssignableFrom(resolvedType2));
+                         return resolvedType1.getName().replace('.','/');
+                 }
+           }
+       }
+}