]> source.dussan.org Git - aspectj.git/commitdiff
Added JSR45 attribute
authorehilsdal <ehilsdal>
Mon, 17 Nov 2003 10:45:33 +0000 (10:45 +0000)
committerehilsdal <ehilsdal>
Mon, 17 Nov 2003 10:45:33 +0000 (10:45 +0000)
weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java
weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java
weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java
weaver/src/org/aspectj/weaver/bcel/Utility.java

index 6d45e96dba0dfa25f01b0e88d8ab1b85ee340d3d..0ffdfc6be4c3f05b2aa3c3ea2d059f04f179a8c4 100644 (file)
@@ -1189,8 +1189,8 @@ public class BcelShadow extends Shadow {
                                return exitInstructions;
                        }
                });
-
-
+               
+               
                range.insert(entryInstructions, Range.InsideBefore);
        }
     
@@ -1325,10 +1325,20 @@ public class BcelShadow extends Shadow {
                                                parameterTypes,
                                                new String[0],
                                                getEnclosingClass());
+               String donorFileName = adviceMethod.getEnclosingClass().getInternalFileName();
+               String recipientFileName = getEnclosingClass().getInternalFileName();
+//             System.err.println("donor " + donorFileName);
+//             System.err.println("recip " + recipientFileName);
+               if (! donorFileName.equals(recipientFileName)) {
+                       localAdviceMethod.fromFilename = donorFileName;
+                       getEnclosingClass().addInlinedSourceFileInfo(
+                               donorFileName,
+                               adviceMethod.highestLineNumber);
+               }
     
                getEnclosingClass().addMethodGen(localAdviceMethod);
                
-               
                // create a map that will move all slots in advice method forward by extraParamOffset
                // in order to make room for the new proceed-required arguments that are added at
                // the beginning of the parameter list
@@ -1341,6 +1351,8 @@ public class BcelShadow extends Shadow {
                localAdviceMethod.getBody().insert(
                        BcelClassWeaver.genInlineInstructions(adviceMethod, 
                                        localAdviceMethod, varMap, fact, true));
+
+
                                        
                localAdviceMethod.setMaxLocals(nVars);
                                        
index 3a83bf2c418c2fd9a970bd2dd38bd26af4298097..97f26c9161bd84cbe5217c32d7a18f333f1cddae 100644 (file)
@@ -523,19 +523,18 @@ public class BcelWeaver implements IWeaver {
        private void dump(UnwovenClassFile classFile, LazyClassGen clazz) throws IOException {
                if (zipOutputStream != null) {
                        String mainClassName = classFile.getJavaClass().getClassName();
-                       
                        writeZipEntry(getEntryName(mainClassName),
-                                                       clazz.getJavaClass().getBytes());
-                       if (!clazz.getChildClasses().isEmpty()) {
-                               for (Iterator i = clazz.getChildClasses().iterator(); i.hasNext();) {
+                                                       clazz.getJavaClass(world).getBytes());
+                       if (!clazz.getChildClasses(world).isEmpty()) {
+                               for (Iterator i = clazz.getChildClasses(world).iterator(); i.hasNext();) {
                                        UnwovenClassFile.ChildClass c = (UnwovenClassFile.ChildClass) i.next();
                                        writeZipEntry(getEntryName(mainClassName + "$" + c.name), c.bytes);
                                }
                        }
                } else {
                        classFile.writeWovenBytes(
-                               clazz.getJavaClass().getBytes(), 
-                               clazz.getChildClasses()
+                               clazz.getJavaClass(world).getBytes(), 
+                               clazz.getChildClasses(world)
                        );
                }
        }
index b21460186eb438bc9d65866e5944dd83ddd430ec..49d231e3eee7aab0f06e1b8fb692bd5a39d9269b 100644 (file)
@@ -25,11 +25,16 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
 
 import org.apache.bcel.Constants;
+import org.apache.bcel.classfile.Attribute;
+import org.apache.bcel.classfile.ConstantUtf8;
 import org.apache.bcel.classfile.Field;
 import org.apache.bcel.classfile.JavaClass;
 import org.apache.bcel.classfile.Method;
+import org.apache.bcel.classfile.Unknown;
 import org.apache.bcel.generic.ClassGen;
 import org.apache.bcel.generic.ConstantPoolGen;
 import org.apache.bcel.generic.FieldGen;
@@ -41,6 +46,7 @@ import org.apache.bcel.generic.ObjectType;
 import org.apache.bcel.generic.PUSH;
 import org.apache.bcel.generic.RETURN;
 import org.apache.bcel.generic.Type;
+import org.aspectj.bridge.IMessage;
 import org.aspectj.util.CollectionUtil;
 import org.aspectj.weaver.AjAttribute;
 import org.aspectj.weaver.BCException;
@@ -51,7 +57,120 @@ import org.aspectj.weaver.TypeX;
 import org.aspectj.weaver.WeaverStateInfo;
 
 public final class LazyClassGen {
+       
+       // ---- JSR 45 info
+       int highestLineNumber = 0;
+       
+       private SortedMap /* <String, InlinedSourceFileInfo> */ inlinedFiles = new TreeMap();
+       
+       static class InlinedSourceFileInfo {
+               int highestLineNumber;
+               int offset;     // calculated
+               
+               InlinedSourceFileInfo(int highestLineNumber) {
+                       this.highestLineNumber = highestLineNumber;
+               }
+       }       
+       
+       void addInlinedSourceFileInfo(String fullpath, int highestLineNumber) {
+               Object o = inlinedFiles.get(fullpath);
+               if (o != null) {
+                       InlinedSourceFileInfo info = (InlinedSourceFileInfo) o;
+                       if (info.highestLineNumber < highestLineNumber) {
+                               info.highestLineNumber = highestLineNumber;
+                       }
+               } else {
+                       inlinedFiles.put(fullpath, new InlinedSourceFileInfo(highestLineNumber));
+               }
+       }
+       
+       void calculateSourceDebugExtensionOffsets() {
+               int i = roundUpToHundreds(highestLineNumber);
+               for (Iterator iter = inlinedFiles.values().iterator(); iter.hasNext();) {
+                       InlinedSourceFileInfo element = (InlinedSourceFileInfo) iter.next();
+                       element.offset = i;
+                       i = roundUpToHundreds(i + element.highestLineNumber);
+               }
+       }
 
+       private static int roundUpToHundreds(int i) {
+               return ((i / 100) + 1) * 100;
+       }
+       
+       int getSourceDebugExtensionOffset(String fullpath) {
+               return ((InlinedSourceFileInfo) inlinedFiles.get(fullpath)).offset;
+       }
+       
+       private Unknown getSourceDebugExtensionAttribute() {
+               int nameIndex = constantPoolGen.addUtf8("SourceDebugExtension");
+               String data = getSourceDebugExtensionString();
+               System.err.println(data);
+               byte[] bytes = Utility.stringToUTF(data);
+               int length = bytes.length;
+
+               return new Unknown(nameIndex, length, bytes, constantPoolGen.getConstantPool());                
+       }       
+
+//     private LazyClassGen() {}
+//     public static void main(String[] args) {
+//             LazyClassGen m = new LazyClassGen();
+//             m.highestLineNumber = 37;
+//             m.inlinedFiles.put("boo/baz/foo.java", new InlinedSourceFileInfo( 83));
+//             m.inlinedFiles.put("boo/barz/foo.java", new InlinedSourceFileInfo(292));
+//             m.inlinedFiles.put("boo/baz/moo.java", new InlinedSourceFileInfo(128)); 
+//             m.calculateSourceDebugExtensionOffsets();
+//             System.err.println(m.getSourceDebugExtensionString());                  
+//     }
+       
+       // For the entire pathname, we're using package names.  This is probably wrong.
+       private String getSourceDebugExtensionString() {
+               StringBuffer out = new StringBuffer();
+               String myFileName = getFileName();
+               // header section
+               out.append("SMAP\n");
+               out.append(myFileName);
+               out.append("\nAspectJ\n");
+               // stratum section
+               out.append("*S AspectJ\n");
+               // file section
+               out.append("*F\n");
+               out.append("1 ");
+               out.append(myFileName);
+               out.append("\n");
+               int i = 2;
+               for (Iterator iter = inlinedFiles.keySet().iterator(); iter.hasNext();) {
+                       String element = (String) iter.next(); 
+                       int ii = element.lastIndexOf('/');
+                       if (ii == -1) {
+                               out.append(i++); out.append(' '); 
+                               out.append(element); out.append('\n');                          
+                       } else {
+                               out.append("+ "); out.append(i++); out.append(' '); 
+                               out.append(element.substring(ii+1)); out.append('\n');
+                               out.append(element); out.append('\n');                                                  
+                       }
+               }
+               // emit line section
+               out.append("*L\n");
+               out.append("1#1,");
+               out.append(highestLineNumber);
+               out.append(":1,1\n");
+               i = 2;  
+               for (Iterator iter = inlinedFiles.values().iterator(); iter.hasNext();) {
+                       InlinedSourceFileInfo element = (InlinedSourceFileInfo) iter.next();
+                       out.append("1#"); 
+                       out.append(i++); out.append(',');
+                       out.append(element.highestLineNumber); out.append(":");
+                       out.append(element.offset + 1); out.append(",1\n");
+               }       
+               // end section
+               out.append("*E\n");
+               // and finish up...
+               return out.toString();
+       }
+       
+       // ---- end JSR45-related stuff
+       
     /** Emit disassembled class and newline to out */
     public static void disassemble(String path, String name, PrintStream out) 
         throws IOException {
@@ -123,6 +242,17 @@ public final class LazyClassGen {
 
     }
 
+       public String getInternalFileName() {
+               String str = getInternalClassName();
+               int index = str.lastIndexOf('/');
+               if (index == -1) {
+                       return getFileName(); 
+               } else {
+                       return str.substring(0, index + 1) + getFileName();
+               }       
+       }
+
+
     public File getPackagePath(File root) {
         String str = getInternalClassName();
         int index = str.lastIndexOf('/');
@@ -143,6 +273,7 @@ public final class LazyClassGen {
     public void addMethodGen(LazyMethodGen gen) {
         //assert gen.getClassName() == super.getClassName();
         methodGens.add(gen);
+        if (highestLineNumber < gen.highestLineNumber) highestLineNumber = gen.highestLineNumber;
     }
 
     public List getMethodGens() {
@@ -150,7 +281,7 @@ public final class LazyClassGen {
 
     }
 
-    private void writeBack() {
+    private void writeBack(BcelWorld world) {
        if (myType != null && myType.getWeaverState() != null) {
                        myGen.addAttribute(BcelAttributes.bcelAttribute(
                                new AjAttribute.WeaverState(myType.getWeaverState()), 
@@ -161,16 +292,42 @@ public final class LazyClassGen {
        
         int len = methodGens.size();
         myGen.setMethods(new Method[0]);
+        
+        calculateSourceDebugExtensionOffsets();
         for (int i = 0; i < len; i++) {
             LazyMethodGen gen = (LazyMethodGen) methodGens.get(i);
             // we skip empty clinits
             if (isEmptyClinit(gen)) continue;
             myGen.addMethod(gen.getMethod());
         }
+               if (inlinedFiles.size() != 0) {
+                       if (hasSourceDebugExtensionAttribute(myGen)) {
+                               world.showMessage(
+                                       IMessage.WARNING,
+                                       "overwriting JSR45 information for "
+                                               + getFileName()
+                                               + " (compiler limitation)",
+                                       null,
+                                       null);
+                       }
+                       myGen.addAttribute(getSourceDebugExtensionAttribute());
+               }
     }
 
-    public JavaClass getJavaClass() {
-        writeBack();
+       private static boolean hasSourceDebugExtensionAttribute(ClassGen gen) {
+               ConstantPoolGen pool = gen.getConstantPool();
+               Attribute[] attrs = gen.getAttributes();
+               for (int i = 0; i < attrs.length; i++) {
+                       if ("SourceDebugExtension"
+                               .equals(((ConstantUtf8) pool.getConstant(attrs[i].getNameIndex())).getBytes())) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+    public JavaClass getJavaClass(BcelWorld world) {
+        writeBack(world);
         return myGen.getJavaClass();
     }
 
@@ -197,12 +354,12 @@ public final class LazyClassGen {
     }
 
 
-       public List getChildClasses() {
+       public List getChildClasses(BcelWorld world) {
                if (classGens.isEmpty()) return Collections.EMPTY_LIST;
                List ret = new ArrayList();
                for (Iterator i = classGens.iterator(); i.hasNext();) {
                        LazyClassGen clazz = (LazyClassGen) i.next();
-                       byte[] bytes = clazz.getJavaClass().getBytes();
+                       byte[] bytes = clazz.getJavaClass(world).getBytes();
                        String name = clazz.getName();
                        int index = name.lastIndexOf('$');
                        // XXX this could be bad, check use of dollar signs.
index a6dcb0cc6addcea3beccb46738a205146eb2bee3..c0b1251437c020837b61a95b48df4113ea99c525 100644 (file)
@@ -83,6 +83,14 @@ public final class LazyMethodGen {
     private final Attribute[]     attributes;
     /* private */ final LazyClassGen    enclosingClass;   
     private final BcelMethod      memberView;
+    int highestLineNumber = 0;
+
+       /** This is nonnull if this method is the result of an "inlining".  We currently
+        * copy methods into other classes for around advice.  We add this field so
+        * we can get JSR45 information correct.  If/when we do _actual_ inlining, 
+        * we'll need to subtype LineNumberTag to have external line numbers.
+        */
+       String fromFilename = null;
 
     private int             maxLocals; 
     
@@ -220,8 +228,7 @@ public final class LazyMethodGen {
                                return ih;
                        }
                }
-       }    
-
+       }
 
     private void unpackLineNumbers(MethodGen gen) {
         LineNumberTag lr = null;
@@ -233,7 +240,9 @@ public final class LazyMethodGen {
                     if (targeter instanceof LineNumberGen) {
                         LineNumberGen lng = (LineNumberGen) targeter;
                         lng.updateTarget(ih, null);
-                        lr = new LineNumberTag(lng.getSourceLine());
+                        int lineNumber = lng.getSourceLine();
+                        if (highestLineNumber < lineNumber) highestLineNumber = lineNumber;
+                        lr = new LineNumberTag(lineNumber);
                     }
                 }
             }
@@ -830,13 +839,17 @@ public final class LazyMethodGen {
                 // now deal with line numbers 
                 // and store up info for local variables
                 InstructionTargeter[] targeters = ih.getTargeters();
+                               int lineNumberOffset =
+                                       (fromFilename == null)
+                                               ? 0
+                                               : getEnclosingClass().getSourceDebugExtensionOffset(fromFilename);
                 if (targeters != null) {
                     for (int k = targeters.length - 1; k >= 0; k--) {
                         InstructionTargeter targeter = targeters[k];
                         if (targeter instanceof LineNumberTag) {
                             int line = ((LineNumberTag)targeter).getLineNumber();
                             if (line != currLine) {
-                                gen.addLineNumber(jh, line);
+                                gen.addLineNumber(jh, line + lineNumberOffset);
                                 currLine = line;
                             }
                         } else if (targeter instanceof LocalVariableTag) {
index 16527dcc38cb30e073b39e39e2b471663b5d676f..2ddfe8506e04a29ea74adfb35ac83008e91dbfde 100644 (file)
@@ -14,6 +14,8 @@
 package org.aspectj.weaver.bcel;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
 import java.io.IOException;
 import java.lang.reflect.Modifier;
 
@@ -152,6 +154,17 @@ public class Utility {
             Type.getArgumentTypes(newMethod.getSignature()),
             kind);
        }
+       
+       public static byte[] stringToUTF(String s) {
+               try {
+                       ByteArrayOutputStream out0 = new ByteArrayOutputStream();
+                       DataOutputStream out1 = new DataOutputStream(out0);
+                       out1.writeUTF(s);
+                       return out0.toByteArray();
+               } catch (IOException e) {
+                       throw new RuntimeException("sanity check");
+               }
+       }
 
     public static Instruction createInstanceof(InstructionFactory fact, ReferenceType t) {
                int cpoolEntry =