From a9928aafc2f0333ca7cc1ac0cbd46f916c58829b Mon Sep 17 00:00:00 2001 From: ehilsdal Date: Mon, 17 Nov 2003 10:45:33 +0000 Subject: [PATCH] Added JSR45 attribute --- .../org/aspectj/weaver/bcel/BcelShadow.java | 18 +- .../org/aspectj/weaver/bcel/BcelWeaver.java | 11 +- .../org/aspectj/weaver/bcel/LazyClassGen.java | 167 +++++++++++++++++- .../aspectj/weaver/bcel/LazyMethodGen.java | 21 ++- .../src/org/aspectj/weaver/bcel/Utility.java | 13 ++ 5 files changed, 212 insertions(+), 18 deletions(-) diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java index 6d45e96db..0ffdfc6be 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java @@ -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); diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java index 3a83bf2c4..97f26c916 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java @@ -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) ); } } diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java index b21460186..49d231e3e 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java @@ -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 /* */ 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. diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java index a6dcb0cc6..c0b125143 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java @@ -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) { diff --git a/weaver/src/org/aspectj/weaver/bcel/Utility.java b/weaver/src/org/aspectj/weaver/bcel/Utility.java index 16527dcc3..2ddfe8506 100644 --- a/weaver/src/org/aspectj/weaver/bcel/Utility.java +++ b/weaver/src/org/aspectj/weaver/bcel/Utility.java @@ -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 = -- 2.39.5