]> source.dussan.org Git - aspectj.git/commitdiff
Fix for Bug 36430: Xreweavable support
authoraclement <aclement>
Tue, 24 Feb 2004 13:43:56 +0000 (13:43 +0000)
committeraclement <aclement>
Tue, 24 Feb 2004 13:43:56 +0000 (13:43 +0000)
33 files changed:
ajde/testdata/ReweavableTest/CalculatePI.java [new file with mode: 0644]
ajde/testdata/ReweavableTest/Logger.aj [new file with mode: 0644]
ajde/testdata/ReweavableTest/NonReweavable1.lst [new file with mode: 0644]
ajde/testdata/ReweavableTest/Reweavable1.lst [new file with mode: 0644]
ajde/testdata/ReweavableTest/Reweavable2.lst [new file with mode: 0644]
ajde/testdata/ReweavableTest/ReweavableCompress1.lst [new file with mode: 0644]
ajde/testdata/ReweavableTest/Second.lst [new file with mode: 0644]
ajde/testdata/ReweavableTest/SecondAspect.aj [new file with mode: 0644]
ajde/testdata/ReweavableTest/TJP1.lst [new file with mode: 0644]
ajde/testdata/ReweavableTest/TJP2.lst [new file with mode: 0644]
ajde/testdata/ReweavableTest/ThirdAspect.aj [new file with mode: 0644]
ajde/testdata/ReweavableTest/tjp/Demo.java [new file with mode: 0644]
ajde/testdata/ReweavableTest/tjp/GetInfo.java [new file with mode: 0644]
ajde/testsrc/org/aspectj/ajde/AjdeTests.java
ajde/testsrc/org/aspectj/ajde/ReweavableTestCase.java [new file with mode: 0644]
docs/devGuideDB/ajc.xml
org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/messages.properties
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java
taskdefs/src/org/aspectj/tools/ant/taskdefs/AjcTask.java
testing/src/org/aspectj/testing/harness/bridge/CompilerRun.java
weaver/src/org/aspectj/weaver/Advice.java
weaver/src/org/aspectj/weaver/CrosscuttingMembers.java
weaver/src/org/aspectj/weaver/CrosscuttingMembersSet.java
weaver/src/org/aspectj/weaver/Shadow.java
weaver/src/org/aspectj/weaver/WeaverStateInfo.java
weaver/src/org/aspectj/weaver/bcel/BcelCflowStackFieldAdder.java
weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java
weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java
weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java
weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java
weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java

diff --git a/ajde/testdata/ReweavableTest/CalculatePI.java b/ajde/testdata/ReweavableTest/CalculatePI.java
new file mode 100644 (file)
index 0000000..84ae085
--- /dev/null
@@ -0,0 +1,26 @@
+import java.util.Random;
+
+public class CalculatePI {
+       
+       static Random r = new Random();
+       static double piApproximation = 1.0f;
+       static int repetitions = 500000;
+       static int iteration = 0;
+       static double inSquare = 0;
+       static double inCircle = 0;
+               
+       public static void main(String[] args) {
+         for (iteration = 0;iteration<repetitions;iteration++) approximate();
+         piApproximation = (inCircle/inSquare)*4.0f;
+         System.out.println("After "+repetitions+" iterations, pi is estimated to be "+piApproximation);
+       }
+       
+       public static void approximate() {
+               double x = r.nextDouble();
+               double y = r.nextDouble();
+               inSquare++;
+               if (x*x + y*y < 1) {inCircle++;}
+       }
+
+       
+}
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/Logger.aj b/ajde/testdata/ReweavableTest/Logger.aj
new file mode 100644 (file)
index 0000000..b41c884
--- /dev/null
@@ -0,0 +1,11 @@
+\r
+\r
+public aspect Logger {\r
+  \r
+  after(): call(* approximate(..)) {\r
+       if (CalculatePI.iteration%10000==0) \r
+         System.out.println("Approximation is now:"+\r
+           (CalculatePI.inCircle/CalculatePI.inSquare)*4.0f);\r
+  }\r
+  \r
+}
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/NonReweavable1.lst b/ajde/testdata/ReweavableTest/NonReweavable1.lst
new file mode 100644 (file)
index 0000000..c40df5e
--- /dev/null
@@ -0,0 +1,4 @@
+CalculatePI.java\r
+Logger.aj\r
+-verbose\r
+-noExit
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/Reweavable1.lst b/ajde/testdata/ReweavableTest/Reweavable1.lst
new file mode 100644 (file)
index 0000000..43c6b24
--- /dev/null
@@ -0,0 +1,5 @@
+CalculatePI.java\r
+Logger.aj\r
+-Xreweavable\r
+-verbose\r
+-noExit
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/Reweavable2.lst b/ajde/testdata/ReweavableTest/Reweavable2.lst
new file mode 100644 (file)
index 0000000..6f0b9d7
--- /dev/null
@@ -0,0 +1,4 @@
+SecondAspect.aj\r
+-Xreweavable\r
+-verbose\r
+-noExit
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/ReweavableCompress1.lst b/ajde/testdata/ReweavableTest/ReweavableCompress1.lst
new file mode 100644 (file)
index 0000000..af8fc60
--- /dev/null
@@ -0,0 +1,5 @@
+CalculatePI.java\r
+Logger.aj\r
+-Xreweavable:compress\r
+-verbose\r
+-noExit
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/Second.lst b/ajde/testdata/ReweavableTest/Second.lst
new file mode 100644 (file)
index 0000000..9a33441
--- /dev/null
@@ -0,0 +1,3 @@
+Logger.aj\r
+-Xreweavable\r
+-verbose
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/SecondAspect.aj b/ajde/testdata/ReweavableTest/SecondAspect.aj
new file mode 100644 (file)
index 0000000..413f496
--- /dev/null
@@ -0,0 +1,5 @@
+\r
+public aspect SecondAspect {\r
+\r
+  declare parents: Logger implements java.io.Serializable;\r
+}
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/TJP1.lst b/ajde/testdata/ReweavableTest/TJP1.lst
new file mode 100644 (file)
index 0000000..f686a5e
--- /dev/null
@@ -0,0 +1,5 @@
+tjp/Demo.java\r
+tjp/GetInfo.java\r
+-Xreweavable\r
+-verbose\r
+-noExit
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/TJP2.lst b/ajde/testdata/ReweavableTest/TJP2.lst
new file mode 100644 (file)
index 0000000..27e2216
--- /dev/null
@@ -0,0 +1,3 @@
+-Xreweavable\r
+-verbose\r
+-noExit
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/ThirdAspect.aj b/ajde/testdata/ReweavableTest/ThirdAspect.aj
new file mode 100644 (file)
index 0000000..c6c6b1a
--- /dev/null
@@ -0,0 +1,5 @@
+\r
+public aspect ThirdAspect {\r
+\r
+       int CalculatePI.x;\r
+}
\ No newline at end of file
diff --git a/ajde/testdata/ReweavableTest/tjp/Demo.java b/ajde/testdata/ReweavableTest/tjp/Demo.java
new file mode 100644 (file)
index 0000000..c4a4f05
--- /dev/null
@@ -0,0 +1,38 @@
+
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+*/
+package tjp;
+
+public class Demo {
+       static Demo d;
+
+       public static void main(String[] args){
+               new Demo().go();
+       }
+
+       void go(){
+               d = new Demo();
+               d.foo(1,d);
+               System.out.println(d.bar(new Integer(3)));
+       }
+
+       void foo(int i, Object o){
+               System.out.println("Demo.foo(" + i + ", " + o + ")\n");
+       }
+
+       String bar (Integer j){
+               System.out.println("Demo.bar(" + j + ")\n");
+               return "Demo.bar(" + j  + ")";
+       }
+}
diff --git a/ajde/testdata/ReweavableTest/tjp/GetInfo.java b/ajde/testdata/ReweavableTest/tjp/GetInfo.java
new file mode 100644 (file)
index 0000000..458acb5
--- /dev/null
@@ -0,0 +1,50 @@
+
+/*
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+*/
+
+package tjp;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.reflect.CodeSignature;
+
+aspect GetInfo {
+
+   static final void println(String s){ System.out.println(s); }
+
+   pointcut goCut(): cflow(this(Demo) && execution(void go()));
+
+   pointcut demoExecs(): within(Demo) && execution(* *(..));
+
+   Object around(): demoExecs() && !execution(* go()) && goCut() {
+         println("Intercepted message: " +
+                 thisJoinPointStaticPart.getSignature().getName());
+         println("in class: " +
+                 thisJoinPointStaticPart.getSignature().getDeclaringType().getName());
+         printParameters(thisJoinPoint);
+         println("Running original method: \n" );
+         Object result = proceed();
+         println("  result: " + result );
+         return result;
+   }
+
+   static private void printParameters(JoinPoint jp) {
+         println("Arguments: " );
+         Object[] args = jp.getArgs();
+         String[] names = ((CodeSignature)jp.getSignature()).getParameterNames();
+         Class[] types = ((CodeSignature)jp.getSignature()).getParameterTypes();
+         for (int i = 0; i < args.length; i++) {
+                println("  "  + i + ". " + names[i] +
+                        " : " +            types[i].getName() +
+                        " = " +            args[i]);
+         }
+   }
+}
index 22905ca8fb6c7566d39021de01cf0e160d3a2b1d..06ead0b2cae5148d827fb2eb3e02aabb18848c0e 100644 (file)
@@ -31,6 +31,7 @@ public class AjdeTests extends TestCase {
                suite.addTestSuite(AsmDeclarationsTest.class);
                suite.addTestSuite(AsmRelationshipsTest.class);
                suite.addTestSuite(InpathTestcase.class);
+               suite.addTestSuite(ReweavableTestCase.class);
                suite.addTestSuite(ResourceCopyTestCase.class);
                suite.addTestSuite(ModelPerformanceTest.class);
                suite.addTestSuite(SavedModelConsistencyTest. class);
diff --git a/ajde/testsrc/org/aspectj/ajde/ReweavableTestCase.java b/ajde/testsrc/org/aspectj/ajde/ReweavableTestCase.java
new file mode 100644 (file)
index 0000000..4f9608d
--- /dev/null
@@ -0,0 +1,426 @@
+/* *******************************************************************
+ * Copyright (c) 2004 Contributors.
+ * All rights reserved. 
+ * This program and the accompanying materials are made available 
+ * under the terms of the Common Public License v1.0 
+ * which accompanies this distribution and is available at 
+ * http://www.eclipse.org/legal/cpl-v10.html 
+ *  
+ * Contributors: 
+ *    Andy Clement     Initial version
+ * ******************************************************************/
+
+package org.aspectj.ajde;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.aspectj.ajde.internal.CompilerAdapter;
+import org.aspectj.ajde.ui.UserPreferencesAdapter;
+import org.aspectj.ajde.ui.internal.AjcBuildOptions;
+import org.aspectj.ajdt.internal.core.builder.AjBuildConfig;
+import org.aspectj.bridge.MessageHandler;
+import org.aspectj.util.FileUtil;
+
+public class ReweavableTestCase extends AjdeTestCase {
+
+       private MessageHandler messageHandler;
+       private NullIdeProperties projectProperties;
+       private AjcBuildOptions buildOptions;
+       private UserPreferencesAdapter preferencesAdapter = null;
+       private CompilerAdapter compilerAdapter;
+       private static final String configFile = 
+               AjdeTests.TESTDATA_PATH + "/examples/figures-coverage/all.lst";
+       public static final String PROJECT_DIR = "ReweavableTest";
+
+       private AjBuildConfig buildConfig = null;
+       public static final String binDir = "bin";
+
+       public static final String indir1Name = "indir1";
+       public static final String indir2Name = "indir2";
+       public static final String injarName  = "injar.jar";
+       public static final String outjarName = "/bin/output.jar";
+
+
+       public static int nonreweavesize_CalculatePI;
+       public static int nonreweavesize_Logger;
+       public static int reweavablesize_CalculatePI;
+       public static int reweavablesize_Logger;
+                       
+       /**
+        * Constructor for JarResourceCopyTestCase.
+        * @param arg0
+        */
+       public ReweavableTestCase(String arg0) {
+               super(arg0);
+       }
+
+
+
+       /*
+        * Ensure the output directpry in clean
+        */
+       protected void setUp() throws Exception {
+               super.setUp(PROJECT_DIR);
+               FileUtil.deleteContents(openFile(binDir));
+       }
+
+
+       /**
+        * Aim: Check we haven't damaged 'normal compilation' when not supplying -Xreweavable.  Also determines
+        *      baseline sizes for the compiled class files for later comparison.
+        * 
+        * Inputs to the compiler:
+        *   NonReweavable1.lst
+        *   -> CalculatePI.java
+        *   -> Logger.aj
+        *   -> -verbose
+        *   -> -noExit
+        * 
+        * Expected result = Compile successful, the types will not be reweavable and the weaver
+        *                   should not report it is running in reweavable mode.
+        */
+       public void testNonReweavableCompile() {
+               System.out.println("testNonReweavableCompile: Building with NonReweavable1.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("NonReweavable1.lst").getAbsolutePath(),new BPM(),false);
+       
+               assertFalse("Did not expect to find a message about the weaver operating in reweavable mode",
+                 checkFor("weaver operating in reweavable mode"));
+
+               File fCalc = openFile("bin/CalculatePI.class");
+               File fLog = openFile("bin/Logger.class");
+               assertTrue("bin/CalculatePI.class should exist?!?",fCalc.exists());
+               assertTrue("bin/Logger.class should exist?!?",fLog.exists());
+               System.out.println("CalculatePI.class is of size: "+fCalc.length());
+               System.out.println("Logger.class is of size: "+fLog.length());
+               System.out.println("\n\n\n");
+               nonreweavesize_CalculatePI = (int)fCalc.length();
+               nonreweavesize_Logger = (int)fLog.length();
+       }
+
+
+       /**
+        * Aim: Basic call to -Xreweavable.  Weaver should report it is in reweavable mode and the
+        *      classes produced should be much larger than normal classes (those produced in the first
+        *      test).
+        * 
+        * Inputs to the compiler:
+        *   Reweavable1.lst
+        *   -> CalculatePI.java
+        *   -> Logger.aj
+        *   -> -Xreweavable
+        *   -> -verbose
+        *   -> -noExit
+        * 
+        * Expected result = Compile successful, the types will be reweavable and the weaver
+        *                   should report it is running in reweavable mode.  The files produced
+        *                               should be larger than those created during the last test.
+        */
+       public void testReweavableCompile() {
+               System.out.println("testReweavableCompile: Building with Reweavable1.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("Reweavable1.lst").getAbsolutePath(),new BPM(),false);
+       
+               assertTrue("Expected a message about operating in reweavable mode, but didn't get one",
+                 checkFor("weaver operating in reweavable mode"));
+                 
+               File fCalc = openFile("bin/CalculatePI.class");
+               File fLog = openFile("bin/Logger.class");
+               assertTrue("bin/CalculatePI.class should exist?!?",fCalc.exists());
+               assertTrue("bin/Logger.class should exist?!?",fLog.exists());
+               System.out.println("CalculatePI.class is of size: "+fCalc.length());
+               System.out.println("Logger.class is of size: "+fLog.length());
+               assertTrue("Reweavable version should be larger than non-reweavable version of CalculatePI",
+                 fCalc.length()>nonreweavesize_CalculatePI);
+               assertTrue("Reweavable version should be larger than non-reweavable version of Logger",
+                 fLog.length()>nonreweavesize_Logger);
+
+               reweavablesize_CalculatePI = (int)fCalc.length();
+               reweavablesize_Logger = (int)fLog.length();
+               
+               System.out.println("\n\n\n");
+       }
+       
+       
+       /**
+        * Aim: Use the optional ':compress' modifier on -Xreweavable.  This causes some of the meta-data
+        *      for use in reweaving to be compressed.  It should succeed and produce class files smaller
+        *      than straight -Xreweavable but larger than without specifying -Xreweavable.
+        * 
+        * Inputs to the compiler:
+        *   ReweavableCompress1.lst
+        *   -> CalculatePI.java
+        *   -> Logger.aj
+        *   -> -Xreweavable:compress
+        *   -> -verbose
+        *   -> -noExit
+        * 
+        * Expected result = Compile successful, the types will be reweavable and the weaver
+        *                   should report it is running in reweavable mode.  The files created should
+        *                                       have a size between the non-reweavable versions and the reweavable (without
+        *                                       compression) versions.
+        */
+       public void testReweavableCompressCompile() {
+               System.out.println("testReweavableCompressCompile: Building with ReweavableCompress1.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("ReweavableCompress1.lst").getAbsolutePath(),new BPM(),false);
+       
+               assertTrue("Expected a message about operating in reweavable mode, but didn't get one",
+                 checkFor("weaver operating in reweavable mode"));
+                 
+               File fCalc = openFile("bin/CalculatePI.class");
+               File fLog = openFile("bin/Logger.class");
+               assertTrue("bin/CalculatePI.class should exist?!?",fCalc.exists());
+               assertTrue("bin/Logger.class should exist?!?",fLog.exists());
+               System.out.println("CalculatePI.class is of size: "+fCalc.length());
+               System.out.println("Logger.class is of size: "+fLog.length());
+               assertTrue("Reweavable version should be larger than non-reweavable version of CalculatePI",
+                 fCalc.length()>nonreweavesize_CalculatePI);
+               assertTrue("Reweavable version should be larger than non-reweavable version of Logger",
+                 fLog.length()>nonreweavesize_Logger);
+               
+               assertTrue("Reweavable (with compression) version should be smaller than reweavable (without compression) version of CalculatePI",
+                 fCalc.length()<reweavablesize_CalculatePI);
+               assertTrue("Reweavable (with compression) version should be smaller than reweavable (without compression) version of Logger",
+                 fLog.length()<reweavablesize_Logger);  
+                
+               System.out.println("\n\n\n");
+       }
+       
+       
+       /**
+        * Aim: The tests above have determined that reweaving appears to be behaving in terms of the .class
+        *      files it is creating.  Now lets actually attempt a reweave.  For this, we build two files
+        *      as reweavable and then build a single file whilst specifying an inpath that contains the
+        *      .class files from the first compile.  This should succeed.
+        * 
+        * Inputs to the first compile:
+        *   Reweavable1.lst
+        *   -> CalculatePI.java
+        *   -> Logger.aj
+        *   -> -Xreweavable
+        *   -> -verbose
+        *   -> -noExit
+        * 
+        * Input to the second compile:
+        *   Reweavable2.lst
+        *   -> SecondAspect.aj
+        *   -> -Xreweavable
+        *   -> -verbose
+        *   -> -noExit
+        *   -inpath bin\.
+        * 
+        * Expected result = Both compiles will succeed.
+        */
+       public void testReweavableSimpleCompile() {
+               System.out.println("testReweavableSimpleCompile: Building with Reweavable1.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("Reweavable1.lst").getAbsolutePath(),new BPM(),false);
+       
+               assertTrue("Expected a message about operating in reweavable mode, but didn't get one",
+                 checkFor("weaver operating in reweavable mode"));
+                 
+                 
+               System.out.println("\ntestReweavableSimpleCompile: Building with Reweavable2.lst");
+               Set paths = new HashSet();
+               paths.add(openFile(binDir));
+               ideManager.getProjectProperties().setInpath(paths);
+               compilerAdapter.compile((String) openFile("Reweavable2.lst").getAbsolutePath(),new BPM(),false);
+
+
+               String expMessage ="successfully verified type Logger exists";
+               assertTrue("Expected message '"+expMessage+"' but did not find it",
+                 checkFor(expMessage));
+                 
+               File fCalc = openFile("bin/CalculatePI.class");
+               File fLog = openFile("bin/Logger.class");
+               File fSec = openFile("bin/SecondAspect.class");
+               assertTrue("bin/CalculatePI.class should exist?!?",fCalc.exists());
+               assertTrue("bin/Logger.class should exist?!?",fLog.exists());
+               assertTrue("bin/SecondAspect.class should exist?!?",fSec.exists());
+                
+               System.out.println("\n\n\n");
+       }
+       
+       
+       /**
+        * Aim: Based on the test above, if we delete Logger.class between the first and second compiles
+        *      the second compile should fail because there is not enough information to reweave CalculatePI
+        * 
+        * Inputs to the first compile:
+        *   Reweavable1.lst
+        *   -> CalculatePI.java
+        *   -> Logger.aj
+        *   -> -Xreweavable
+        *   -> -verbose
+        *   -> -noExit
+        * 
+        * Input to the second compile:
+        *   Reweavable2.lst
+        *   -> SecondAspect.aj
+        *   -> -Xreweavable
+        *   -> -verbose
+        *   -> -noExit
+        *   -inpath bin\.
+        * 
+        * Expected result = Second compile will fail - reporting that Logger is missing (it 'touched' in the first compile CalculatePI)
+        */
+       public void testForReweavableSimpleErrorCompile() {
+               System.out.println("testForReweavableSimpleErrorCompile: Building with Reweavable2.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("Reweavable1.lst").getAbsolutePath(),new BPM(),false);
+       
+               assertTrue("Expected a message about operating in reweavable mode, but didn't get one",
+                 checkFor("weaver operating in reweavable mode"));
+                 
+                 
+               assertTrue("Could not delete bin/Logger.class??",openFile("bin/Logger.class").delete());
+
+
+               System.out.println("\ntestForReweavableSimpleErrorCompile: Building with Reweavable2.lst");
+               Set paths = new HashSet();
+               paths.add(openFile(binDir));
+               ideManager.getProjectProperties().setInpath(paths);
+               compilerAdapter.compile((String) openFile("Reweavable2.lst").getAbsolutePath(),new BPM(),false);
+
+
+               String expMessage ="type Logger is needed by reweavable type CalculatePI";
+               assertTrue("Expected message '"+expMessage+"' but did not find it",
+                 checkFor(expMessage));
+                 
+               File fCalc = openFile("bin/CalculatePI.class");
+               File fLog = openFile("bin/Logger.class");
+               File fSec = openFile("bin/SecondAspect.class");
+               assertTrue("bin/CalculatePI.class should exist!",fCalc.exists());
+               assertTrue("bin/Logger.class should not exist!",!fLog.exists());
+               assertTrue("bin/SecondAspect.class should not exist!",fSec.exists());
+                
+               System.out.println("\n\n\n");
+       }
+       
+       
+       /**
+        * Aim: Based on the test above, if we delete Logger.class between the first and second compiles
+        *      the second compile should fail because there is not enough information to reweave CalculatePI
+        * 
+        * Inputs to the first compile:
+        *   TJP1.lst
+        *   -> tjp/Demo.java
+        *   -> tjp/GetInfo.java
+        *   -> -Xreweavable
+        *   -> -verbose
+        *   -> -noExit
+        * 
+        * Now, delete bin\tjp\GetInfo.class and do a compile with:
+        *   TJP2.lst
+        *   -> -Xreweavable
+        *   -> -verbose
+        *   -> -noExit
+        *   -inpath bin\.
+        * 
+        * Expected result = Second compile will fail - reporting that tjp.GetInfo is missing (it 'touched' in the first compile tjp.Demo)
+        */
+       public void testErrorScenario2Compile() {
+               System.out.println("testErrorScenario2: Building with TJP1.lst");
+               compilerAdapter = new CompilerAdapter();
+               compilerAdapter.showInfoMessages(true);
+               compilerAdapter.compile((String) openFile("TJP1.lst").getAbsolutePath(),new BPM(),false);
+       
+               assertTrue("Expected a message about operating in reweavable mode, but didn't get one",
+                 checkFor("weaver operating in reweavable mode"));
+                 
+                 
+               assertTrue("Could not delete bin/tjp/GetInfo.class??",openFile("bin/tjp/GetInfo.class").delete());
+
+
+               System.out.println("\ntestErrorScenario2: Building with TJP2.lst");
+               Set paths = new HashSet();
+               paths.add(openFile(binDir));
+               ideManager.getProjectProperties().setInpath(paths);
+               compilerAdapter.compile((String) openFile("TJP2.lst").getAbsolutePath(),new BPM(),false);
+
+
+               String expMessage ="type tjp.GetInfo is needed by reweavable type tjp.Demo";
+               assertTrue("Expected message '"+expMessage+"' but did not find it",
+                 checkFor(expMessage));
+                 
+               File fDemo = openFile("bin/tjp/Demo.class");
+               File fGetInfo = openFile("bin/tjp/GetInfo.class");
+               assertTrue("bin/tjp/Demo.class should exist!",fDemo.exists());
+               assertTrue("bin/tjp/GetInfo.class should not exist!",!fGetInfo.exists());
+                
+               System.out.println("\n\n\n");
+       }
+       
+       public void testWorkingScenario2Compile() {
+                       System.out.println("testWorkingScenario2: Building with TJP1.lst");
+                       compilerAdapter = new CompilerAdapter();
+                       compilerAdapter.showInfoMessages(true);
+                       compilerAdapter.compile((String) openFile("TJP1.lst").getAbsolutePath(),new BPM(),false);
+       
+                       assertTrue("Expected a message about operating in reweavable mode, but didn't get one",
+                         checkFor("weaver operating in reweavable mode"));
+                 
+               
+                       System.out.println("\ntestWorkingScenario2: Building with TJP2.lst");
+                       Set paths = new HashSet();
+                       paths.add(openFile(binDir));
+                       ideManager.getProjectProperties().setInpath(paths);
+                       compilerAdapter.compile((String) openFile("TJP2.lst").getAbsolutePath(),new BPM(),false);
+
+
+                       String expMessage ="successfully verified type tjp.GetInfo exists";
+                       assertTrue("Expected message '"+expMessage+"' but did not find it",
+                         checkFor(expMessage));
+                 
+                       File fGetInfo = openFile("bin/tjp/GetInfo.class");
+                       File fDemo = openFile("bin/tjp/Demo.class");
+                       assertTrue("bin/tjp/GetInfo.class should exist!",fGetInfo.exists());
+                       assertTrue("bin/tjp/Demo.class should not exist!",fDemo.exists());
+                       
+                       System.out.println("\n\n\n");
+               }
+       
+
+       private class BPM implements BuildProgressMonitor {
+               public void start(String configFile) {}
+
+                               public void setProgressText(String text) {}
+
+                               public void setProgressBarVal(int newVal) {     }
+
+                               public void incrementProgressBarVal() {}
+
+                               public void setProgressBarMax(int maxVal) {     }
+
+                               public int getProgressBarMax() {
+                                       return 0;
+                               }
+
+                               public void finish() {}
+               
+       }
+       
+
+
+       
+       private boolean checkFor(String what) {
+               List ll = ideManager.getCompilationSourceLineTasks();
+               for (Iterator iter = ll.iterator(); iter.hasNext();) {
+                       Object element = (Object) iter.next();
+                       if (element.toString().indexOf(what)!=-1) return true;
+               }
+               return false;
+       }
+       
+
+}
index afe218887ee32d660420bc734eb0dc45f9c6f112..0bfcbb769d79da501d83ce5771014120e91b9e54 100644 (file)
         for input using -injars.
         </para></listitem>
       </varlistentry>
+      
+      <varlistentry>
+        <term>-Xreweavable[:compress]</term>
+        <listitem><para>(Experimental) runs weaver in reweavable mode which causes
+        it to create woven classes that can be rewoven, subject to the restriction that
+        on attempting a reweave all the types that advised the woven type must be accessible.
+        </para></listitem>
+      </varlistentry>
 
       <varlistentry>
         <term>-XnoInline</term>
index cf6174746edf74c09584b1ea9014ef9fdb0c66e0..6132b74d0dc3217eb671e9b99266d0114989615c 100644 (file)
@@ -444,6 +444,11 @@ public class BuildArgParser extends Main {
                                buildConfig.setXserializableAspects(true);
                        } else if (arg.equals("-XlazyTjp")) {
                                buildConfig.setXlazyTjp(true);
+            } else if (arg.startsWith("-Xreweavable")) {
+               buildConfig.setXreweavable(true);
+               if (arg.endsWith(":compress")) {
+                       buildConfig.setXreweavableCompressClasses(true);
+               }
                        } else if (arg.equals("-XnoInline")) {
                                buildConfig.setXnoInline(true);
                        } else if (arg.equals("-Xlintfile")) { 
index ac2113113cb0b11b6d694d283c7fbd866803b29e..27b3cb7ae4719e17fd38309dafe15782833575ad 100644 (file)
@@ -115,7 +115,7 @@ Standard Eclipse compiler options:\n\
 \    -showversion       print compiler version and continue\n
 
 ## options not documented above (per ..ajdt.ajc.BuildArgParser.java):
-# -XincrementalFile, -XnoWeave, -XserializableAspects, -XnoInline
+# -XincrementalFile, -XnoWeave, -XserializableAspects, -XnoInline, -Xreweavable[:compress]
 
 ###############################################################################
 # Copyright (c) 2000, 2004 IBM Corporation and others.
index ad182a589233ba601f57cc13638438abef610978..f9c2571db1016753bfd2116869e78d29e4f075a2 100644 (file)
@@ -56,6 +56,8 @@ public class AjBuildConfig { // XXX needs bootclasspath?
        private boolean XserializableAspects = false;
        private boolean XlazyTjp = false;
        private boolean XnoInline = false;
+       private boolean Xreweavable = false;
+       private boolean XreweavableCompressClasses = false;
        private String lintMode = AJLINT_DEFAULT;
        private File lintSpecFile = null;
     
@@ -214,6 +216,10 @@ public class AjBuildConfig { // XXX needs bootclasspath?
        public void setInJars(List sourceJars) {
                this.inJars = sourceJars;
        }
+       
+       public void setInPath(List dirsOrJars) {
+               inPath = dirsOrJars;
+       }
 
        public List getSourceRoots() {
                return sourceRoots;
@@ -462,4 +468,20 @@ public class AjBuildConfig { // XXX needs bootclasspath?
                XlazyTjp = b;
        }
 
+       public void setXreweavable(boolean b) {
+               Xreweavable = true;
+       }
+       
+       public boolean isXreweavable() {
+               return Xreweavable;
+       }
+       
+       public void setXreweavableCompressClasses(boolean b) {
+               XreweavableCompressClasses = true;
+       }
+       
+       public boolean getXreweavableCompressClasses() {
+               return XreweavableCompressClasses;
+       }
+
 }
index d0a79ca3c1adf8d21f8b2a37417adfb2a571b5b0..efa48254829251471056f8535989578796768a87 100644 (file)
@@ -226,6 +226,9 @@ public class AjBuildManager {
        //                      bcelWeaver.addResource(resource, buildConfig.getOutputDir());
                        }
                }
+               
+               bcelWeaver.setReweavableMode(buildConfig.isXreweavable(),buildConfig.getXreweavableCompressClasses());
+
                //check for org.aspectj.runtime.JoinPoint
                bcelWorld.resolve("org.aspectj.lang.JoinPoint");
        }
index 0bf34a24ebb303edacc7aa144e88374686cfc51c..10f7c42dc4867bc60f9bfe4a305bb13b7da68c41 100644 (file)
@@ -454,6 +454,10 @@ public class AjcTask extends MatchingTask {
     public void setXNoweave(boolean noweave) {  
         cmd.addFlag("-XnoWeave", noweave);
     }
+    
+    public void setXReweavable(boolean reweavable) {
+       cmd.addFlag("-Xreweavable",reweavable);
+    }
 
     public void setNowarn(boolean nowarn) {  
         cmd.addFlag("-nowarn", nowarn);
@@ -1699,6 +1703,8 @@ public class AjcTask extends MatchingTask {
                 setXlintfile(new File(in.next()));
             } else if ("-Xnoweave".equals(flag)) {
                 setXNoweave(true);
+                       } else if ("-Xreweavable".equals(flag)) {
+                               setXReweavable(true);
             } else if (flag.startsWith("@")) {
                 File file = new File(flag.substring(1));
                 if (file.canRead()) {
index efa60f1c1d05867d1906866ced8d955563284792..084c17c7a4b22c1f9bbec723f65fb409b1547b1d 100644 (file)
@@ -1645,6 +1645,7 @@ public class CompilerRun implements IAjcRun {
                                     "1.5" }}),
                         factory.create("XnoInline"),
                         factory.create("XnoWeave"),
+                        factory.create("Xreweavable"),
                         factory.create("XserializableAspects")
                     };
                     
index b25df052c0288d891f6bc0840da82165fe873922..4e76e2e28f814be0d850d87d91e13ae6e3bd3aeb 100644 (file)
@@ -37,12 +37,13 @@ public abstract class Advice extends ShadowMunger {
     
     protected TypePattern exceptionType; // just for Softener kind
 
-    public static Advice makeCflowEntry(World world, Pointcut entry, boolean isBelow, Member stackField, int nFreeVars, List innerCflowEntries{
+    public static Advice makeCflowEntry(World world, Pointcut entry, boolean isBelow, Member stackField, int nFreeVars, List innerCflowEntries, ResolvedTypeX inAspect){
        Advice ret = world.concreteAdvice(isBelow ? AdviceKind.CflowBelowEntry : AdviceKind.CflowEntry,
              entry, stackField, 0, entry);
              //0);
        ret.innerCflowEntries = innerCflowEntries;
        ret.nFreeVars = nFreeVars;
+       ret.concreteAspect = inAspect;
        return ret;
     }
 
@@ -66,12 +67,13 @@ public abstract class Advice extends ShadowMunger {
        return ret;
     }
     
-    public static Advice makeSoftener(World world, Pointcut entry, TypePattern exceptionType) {
+    public static Advice makeSoftener(World world, Pointcut entry, TypePattern exceptionType,ResolvedTypeX inAspect) {
        Advice ret = world.concreteAdvice(AdviceKind.Softener,
              entry, null, 0, entry);  
   
        ret.exceptionType = exceptionType;
-       //System.out.println("made ret: " + ret + " with " + exceptionType);
+       ret.concreteAspect = inAspect;
+       // System.out.println("made ret: " + ret + " with " + exceptionType);
        return ret;
     }
        
index b5311a9ec5a1e4f66fcc64ba9d56455941539623..0992fef8961cc9f57e9c180e833c74330150f3b3 100644 (file)
@@ -110,7 +110,7 @@ public class CrosscuttingMembers {
                        DeclareSoft d = (DeclareSoft)declare;
                        Pointcut concretePointcut = d.getPointcut().concretize(inAspect, 0);
                        declareSofts.add(new DeclareSoft(d.getException(), concretePointcut));
-                       ShadowMunger m = Advice.makeSoftener(world, concretePointcut, d.getException());
+                       ShadowMunger m = Advice.makeSoftener(world, concretePointcut, d.getException(),inAspect);
                        addConcreteShadowMunger(m);
                } else {
                        throw new RuntimeException("unimplemented");
index 2dcae923c141d7ef373f8a0459797f99d84391a4..4a359d69a880f7212903224f8958b09261a80c9f 100644 (file)
@@ -15,10 +15,14 @@ package org.aspectj.weaver;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import org.aspectj.weaver.bcel.BcelTypeMunger;
+import org.aspectj.weaver.patterns.DeclareParents;
 
 /**
  * This holds on to all CrosscuttingMembers for a world.  It handles 
@@ -144,5 +148,21 @@ public class CrosscuttingMembersSet {
                        declareDominates = ret;
                }
                return declareDominates;
-       }       
+       }
+
+
+       public ResolvedTypeX findAspectDeclaringParents(DeclareParents p) {
+               Set result = new HashSet();
+               Set keys = this.members.keySet();
+               for (Iterator iter = keys.iterator(); iter.hasNext();) {
+                       ResolvedTypeX element = (ResolvedTypeX) iter.next();
+                       for (Iterator i = ((CrosscuttingMembers)members.get(element)).getDeclareParents().iterator(); i.hasNext(); ) {
+                               DeclareParents dp = (DeclareParents)i.next();
+                               return element;
+                       }
+               }
+               return null;
+       }
+
+       
 }
index ade65de83689f0150d336b6d42b08ce78ea30986..266c8b4db7b74c50f231eb9c006dfd5adb62b699 100644 (file)
@@ -39,6 +39,7 @@ public abstract class Shadow {
        protected final Shadow enclosingShadow;
     protected List mungers = new ArrayList(1);
 
+
        // ----
     protected Shadow(Kind kind, Member signature, Shadow enclosingShadow) {
         this.kind = kind;
@@ -49,7 +50,11 @@ public abstract class Shadow {
        // ----
 
     public abstract World getIWorld();
-    
+
+       public List /*ShadowMunger*/ getMungers() {
+               return mungers;
+       }
+           
     /**
      * could this(*) pcd ever match
      */
index a2e78ed014f5a30d159d5ac5221ecdc96341c6eb..127bb3ee9fe42e994f25bacb1acb6173ee3c2322 100644 (file)
@@ -17,36 +17,87 @@ import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
 
 import org.aspectj.bridge.IMessage;
 import org.aspectj.weaver.bcel.BcelTypeMunger;
 
+
+/**
+ * WeaverStateInfo represents how a type was processed.  It is used by the weaver to determine how a type 
+ * was previously treated and whether reweaving is allowed.
+ * The format in the data stream is:
+ * 
+ * Byte:  Kind.  UNTOUCHED|WOVEN|EXTENDED - If extended it can have two extra bits set 'REWEAVABLE' and 'REWEAVABLE_COMPRESSION_BIT'
+ * Short: typeMungerCount - how many type mungers have affected this type
+ * <TypeX & ResolvedTypeMunger>: The type mungers themselves
+ * If we are reweavable then we also have:
+ * Short: Number of aspects that touched this type in some way when it was previously woven
+ * <String> The fully qualified name of each type
+ * Int: Length of class file data (i.e. the unwovenclassfile)
+ * Byte[]: The class file data, compressed if REWEAVABLE_COMPRESSION_BIT set.
+ */
+
+
 public class WeaverStateInfo {
        private List/*Entry*/ typeMungers;
        private boolean oldStyle;
        
+       
+       
+       private boolean reweavable;
+       private boolean reweavableCompressedMode;     // If true, unwovenClassFile is compressed on write and uncompressed on read
+       private Set /*String*/ aspectsAffectingType;  // These must exist in the world for reweaving to be valid
+       private byte[] unwovenClassFile;                          // Original 'untouched' class file
+       private static boolean reweavableDefault = false;
+       private static boolean reweavableCompressedModeDefault = false;
+       
        public WeaverStateInfo() {
-               this(new ArrayList(), false);
+               this(new ArrayList(), false,reweavableDefault,reweavableCompressedModeDefault);
        }
        
-       private WeaverStateInfo(List typeMungers, boolean oldStyle) {
+       private WeaverStateInfo(List typeMungers, boolean oldStyle,boolean reweavableMode,boolean reweavableCompressedMode) {
                this.typeMungers = typeMungers;
-               this.oldStyle = oldStyle;
+               this.oldStyle    = oldStyle;
+               this.reweavable  = reweavableMode;
+               this.reweavableCompressedMode = reweavableCompressedMode;
+               this.aspectsAffectingType= new HashSet();
+               this.unwovenClassFile = null;
+       }
+       
+       public static void setReweavableModeDefaults(boolean mode, boolean compress) {
+               reweavableDefault = mode;
+               reweavableCompressedModeDefault = compress;
        }
        
        private static final int UNTOUCHED=0, WOVEN=2, EXTENDED=3;
        
+       // Use 'bits' for these capabilities - only valid in EXTENDED mode
+       private static final byte REWEAVABLE_BIT             = 1<<4;
+       private static final byte REWEAVABLE_COMPRESSION_BIT = 1<<5;
+       
        public static final WeaverStateInfo read(DataInputStream s, ISourceContext context) throws IOException {
                byte b = s.readByte();
                
+               boolean isReweavable = ((b&REWEAVABLE_BIT)!=0);
+               if (isReweavable) b=(byte) (b-REWEAVABLE_BIT);
+
+               boolean isReweavableCompressed = ((b&REWEAVABLE_COMPRESSION_BIT)!=0);
+               if (isReweavableCompressed) b=(byte) (b-REWEAVABLE_COMPRESSION_BIT);
+
                switch(b) {
                        case UNTOUCHED:
                                throw new RuntimeException("unexpected UNWOVEN");
                        case WOVEN: 
-                               return new WeaverStateInfo(Collections.EMPTY_LIST, true);
+                               return new WeaverStateInfo(Collections.EMPTY_LIST, true,isReweavable,isReweavableCompressed);
                        case EXTENDED:
                                int n = s.readShort();
                                List l = new ArrayList();
@@ -56,11 +107,15 @@ public class WeaverStateInfo {
                                                ResolvedTypeMunger.read(s, context);
                                        l.add(new Entry(aspectType, typeMunger));
                                }
-                               return new WeaverStateInfo(l, false);
+                           WeaverStateInfo wsi = new WeaverStateInfo(l,false,isReweavable,isReweavableCompressed);
+                           readAnyReweavableData(wsi,s);
+                               return wsi;
                } 
                throw new RuntimeException("bad WeaverState.Kind: " + b);
        }
        
+       
+       
        private static class Entry {
                public TypeX aspectType;
                public ResolvedTypeMunger typeMunger;
@@ -77,7 +132,10 @@ public class WeaverStateInfo {
        public void write(DataOutputStream s) throws IOException {
                if (oldStyle) throw new RuntimeException("shouldn't be writing this");
                
-               s.writeByte(EXTENDED);
+               byte weaverStateInfoKind = EXTENDED;
+               if (reweavable) weaverStateInfoKind |= REWEAVABLE_BIT;
+               if (reweavableCompressedMode) weaverStateInfoKind |= REWEAVABLE_COMPRESSION_BIT;
+               s.writeByte(weaverStateInfoKind);
                int n = typeMungers.size();
                s.writeShort(n);
                for (int i=0; i < n; i++) {
@@ -85,6 +143,7 @@ public class WeaverStateInfo {
                        e.aspectType.write(s);
                        e.typeMunger.write(s);
                }
+               writeAnyReweavableData(this,s);
        }
 
        public void addConcreteMunger(ConcreteTypeMunger munger) {
@@ -117,4 +176,101 @@ public class WeaverStateInfo {
        public boolean isOldStyle() {
                return oldStyle;
        }
+
+       public byte[] getUnwovenClassFileData() {
+               return unwovenClassFile;
+       }
+
+       public void setUnwovenClassFileData(byte[] data) {
+               unwovenClassFile = data;
+       }
+
+       public boolean isReweavable() {
+               return reweavable;
+       }
+       
+       public void setReweavable(boolean rw,boolean compressData) {
+               reweavable = rw;
+               reweavableCompressedMode = compressData;
+       }
+       
+       public void addAspectsAffectingType(Collection /*String*/ aspects) {
+               aspectsAffectingType.addAll(aspects);
+       }
+       public void addAspectAffectingType(String aspectType) {
+               aspectsAffectingType.add(aspectType);
+       }
+       public Set /*String*/ getAspectsAffectingType() {
+               return this.aspectsAffectingType;
+       }
+
+
+    ////
+    
+       private static void readAnyReweavableData(WeaverStateInfo wsi,DataInputStream s) throws IOException {
+
+               if (wsi.isReweavable()) {               
+                       // Load list of aspects that need to exist in the world for reweaving to be 'legal'
+                       int numberAspectsAffectingType = s.readShort();
+                       for (int i=0; i < numberAspectsAffectingType; i++) {wsi.addAspectAffectingType(s.readUTF());} 
+                       
+                       int unwovenClassFileSize = s.readInt();
+                       byte[] classData = null;                                        
+                       // The data might or might not be compressed:
+                       if (!wsi.reweavableCompressedMode) {
+                               // Read it straight in
+                               classData = new byte[unwovenClassFileSize];
+                               int bytesread = s.read(classData);
+                               if (bytesread!=unwovenClassFileSize) 
+                                 throw new IOException("ERROR whilst reading reweavable data, expected "+
+                                                       unwovenClassFileSize+" bytes, only found "+bytesread);
+                       } else {
+                               // Decompress it
+                               classData = new byte[unwovenClassFileSize];
+                                               
+                               ZipInputStream zis = new ZipInputStream(s);
+                               ZipEntry zen = zis.getNextEntry();
+                               int current = 0; 
+                               int bytesToGo=unwovenClassFileSize;
+                               while (bytesToGo>0) {
+                                       int amount = zis.read(classData,current,bytesToGo);
+                                       current+=amount;
+                                       bytesToGo-=amount;
+                               }
+                               zis.closeEntry();
+                               if (bytesToGo!=0) 
+                                 throw new IOException("ERROR whilst reading compressed reweavable data, expected "+
+                                                       unwovenClassFileSize+" bytes, only found "+current);
+                       }
+                       wsi.setUnwovenClassFileData(classData);
+               }
+       }
+
+
+
+       private static void writeAnyReweavableData(WeaverStateInfo wsi,DataOutputStream s) throws IOException {
+               if (wsi.isReweavable()) {
+                       // Write out list of aspects that must exist next time we try and weave this class
+                       s.writeShort(wsi.aspectsAffectingType.size());
+                       if (wsi.aspectsAffectingType.size()>0) {
+                               for (Iterator iter = wsi.aspectsAffectingType.iterator(); iter.hasNext();) {
+                                       String type = (String) iter.next();
+                                       s.writeUTF(type);       
+                               }
+                       }
+                       byte[] data = wsi.unwovenClassFile;
+                       s.writeInt(data.length);
+                       // Do we need to compress the data?
+                       if (!wsi.reweavableCompressedMode) {
+                               s.write(wsi.unwovenClassFile);
+                       } else {
+                               ZipOutputStream zos = new ZipOutputStream(s);
+                               ZipEntry ze = new ZipEntry("data");
+                               zos.putNextEntry(ze);
+                               zos.write(wsi.unwovenClassFile,0,wsi.unwovenClassFile.length);
+                               zos.closeEntry();
+                       }
+               }
+       }
+
 }
index bd0f31f0c0f8e06f0dd27a11c63480f4ac9c9b1a..0de033913ecf59e59b68c6fa58749ba541fed4ef 100644 (file)
@@ -28,7 +28,7 @@ import org.aspectj.weaver.ResolvedTypeX;
 public class BcelCflowStackFieldAdder extends BcelTypeMunger {
        private ResolvedMember cflowStackField;
        public BcelCflowStackFieldAdder(ResolvedMember cflowStackField) {
-               super(null, null);
+               super(null,(ResolvedTypeX)cflowStackField.getDeclaringType());
                this.cflowStackField = cflowStackField;
        }
 
index d67d4eb87b8c16c9a9ad6142c2c80803eaf4f774..514e922625f5ed6cd7f07f58febf7ec744546b30 100644 (file)
@@ -62,6 +62,7 @@ import org.aspectj.weaver.ResolvedMember;
 import org.aspectj.weaver.ResolvedTypeX;
 import org.aspectj.weaver.Shadow;
 import org.aspectj.weaver.ShadowMunger;
+import org.aspectj.weaver.WeaverStateInfo;
 import org.aspectj.weaver.Shadow.Kind;
 import org.aspectj.weaver.patterns.FastMatchInfo;
 
@@ -97,6 +98,11 @@ class BcelClassWeaver implements IClassWeaver {
     private final List        addedLazyMethodGens           = new ArrayList();
     private final Set         addedDispatchTargets          = new HashSet();
     
+
+       // Static setting across BcelClassWeavers
+       private static boolean inReweavableMode = false;
+       private static boolean compressReweavableAttributes = false;
+    
     
     private        List addedSuperInitializersAsList = null; // List<IfaceInitList>
     private final Map  addedSuperInitializers = new HashMap(); // Interface -> IfaceInitList
@@ -279,12 +285,17 @@ class BcelClassWeaver implements IClassWeaver {
     // ----
     
     public boolean weave() {
-        if (clazz.isWoven()) {
+               
+        if (clazz.isWoven() && !clazz.isReweavable()) {
                world.showMessage(IMessage.ERROR, 
-                               "class \'" + clazz.getType().getName() + "\' is already woven",
+                               "class \'" + clazz.getType().getName() + "\' is already woven and has not been built with -Xreweavable",
                                ty.getSourceLocation(), null);
                return false;
         }
+       
+
+        Set aspectsAffectingType = null;
+        if (inReweavableMode) aspectsAffectingType = new HashSet();
         
         boolean isChanged = false;
         
@@ -300,7 +311,11 @@ class BcelClassWeaver implements IClassWeaver {
                        continue;
                }
                BcelTypeMunger munger = (BcelTypeMunger)o;
-               isChanged |= munger.munge(this);
+               boolean typeMungerAffectedType = munger.munge(this);
+               if (typeMungerAffectedType) {
+                       isChanged = true;
+                       if (inReweavableMode) aspectsAffectingType.add(munger.getAspectType().getName());
+               }
         }
         
         // XXX do major sort of stuff
@@ -327,7 +342,12 @@ class BcelClassWeaver implements IClassWeaver {
             LazyMethodGen mg = (LazyMethodGen)i.next();
             //mg.getBody();
                        if (! mg.hasBody()) continue;
-            isChanged |= match(mg);
+                       boolean shadowMungerMatched = match(mg);
+                       if (shadowMungerMatched) {
+                               // For matching mungers, add their declaring aspects to the list that affected this type
+                               if (inReweavableMode) aspectsAffectingType.addAll(findAspectsForMungers(mg));
+              isChanged = true;
+                       }
         }
         if (! isChanged) return false;
         
@@ -352,9 +372,36 @@ class BcelClassWeaver implements IClassWeaver {
                        weaveInAddedMethods();
         }
         
+        if (inReweavableMode) {
+               WeaverStateInfo wsi = clazz.getOrCreateWeaverStateInfo();
+               wsi.addAspectsAffectingType(aspectsAffectingType);
+               wsi.setUnwovenClassFileData(ty.getJavaClass().getBytes());
+               wsi.setReweavable(true,compressReweavableAttributes);
+        } else {
+               clazz.getOrCreateWeaverStateInfo().setReweavable(false,false);
+        }
+        
         return isChanged;
     }
 
+       private Set findAspectsForMungers(LazyMethodGen mg) {
+               Set aspectsAffectingType = new HashSet();
+               for (Iterator iter = mg.matchedShadows.iterator(); iter.hasNext();) {
+                       BcelShadow aShadow = (BcelShadow) iter.next();  
+                       // Mungers in effect on that shadow
+                       for (Iterator iter2 = aShadow.getMungers().iterator();iter2.hasNext();) {
+                               ShadowMunger aMunger = (ShadowMunger) iter2.next();
+                               if (aMunger instanceof BcelAdvice) {
+                                       BcelAdvice bAdvice = (BcelAdvice)aMunger;
+                                       aspectsAffectingType.add(bAdvice.getConcreteAspect().getName());
+                               } else {
+                               // It is a 'Checker' - we don't need to remember aspects that only contributed Checkers...
+                               }               
+                       }
+               }
+               return aspectsAffectingType;
+       }
+
 
        private void inlineSelfConstructors(List methodGens) {
                for (Iterator i = methodGens.iterator(); i.hasNext();) {
@@ -1095,5 +1142,11 @@ class BcelClassWeaver implements IClassWeaver {
        public BcelWorld getWorld() {
                return world;
        }
+       
+       // Called by the BcelWeaver to let us know all BcelClassWeavers need to collect reweavable info
+       public static void setReweavableMode(boolean mode,boolean compress) {
+               inReweavableMode = mode;
+               compressReweavableAttributes = compress;
+       }
 
 }
index a055f92a4bcc8983c9468f342ce2702f4d8e801f..1c8a44c0cb79ec0077f218b76d3f958d1efaf348 100644 (file)
@@ -85,6 +85,13 @@ public class BcelObjectType extends ResolvedTypeX.ConcreteName {
         unpackAspectAttributes();
     }
     
+    
+    // repeat initialization
+    public void setJavaClass(JavaClass newclass) {
+       this.javaClass = newclass;
+       resetState();
+    }
+    
     public int getModifiers() {
         return javaClass.getAccessFlags();
     }
index 7dea8184ba9ac2139a8224eaa3034dbc8fbffaa4..12d7518d66f868d606c0f7da9851f9336fcea262 100644 (file)
@@ -29,12 +29,14 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
 
 import org.apache.bcel.classfile.ClassParser;
 import org.apache.bcel.classfile.JavaClass;
+import org.aspectj.bridge.AbortException;
 import org.aspectj.bridge.IMessage;
 import org.aspectj.bridge.IProgressListener;
 import org.aspectj.util.FileUtil;
@@ -46,6 +48,7 @@ import org.aspectj.weaver.ResolvedTypeMunger;
 import org.aspectj.weaver.ResolvedTypeX;
 import org.aspectj.weaver.ShadowMunger;
 import org.aspectj.weaver.TypeX;
+import org.aspectj.weaver.WeaverStateInfo;
 import org.aspectj.weaver.patterns.DeclareParents;
 import org.aspectj.weaver.patterns.FastMatchInfo;
 
@@ -55,7 +58,10 @@ public class BcelWeaver implements IWeaver {
     private IProgressListener progressListener = null;
     private double progressMade;
     private double progressPerClassFile;
-
+    
+    private boolean inReweavableMode = false;
+    private boolean compressReweavableAttributes = false;
+    
     public BcelWeaver(BcelWorld world) {
         super();
         this.world = world;
@@ -354,12 +360,47 @@ public class BcelWeaver implements IWeaver {
        
        //System.err.println("typeMungers: " + typeMungerList);
        
+
+               if (inReweavableMode)
+                       world.showMessage(IMessage.INFO, "weaver operating in reweavable mode.  Need to verify any required types exist.", null, null);
+               
+       
+       Set alreadyConfirmedOK = new HashSet();
                // clear all state from files we'll be reweaving
         for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
             UnwovenClassFile classFile = (UnwovenClassFile)i.next();
                String className = classFile.getClassName();
             BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
-            classType.resetState();
+
+                       
+            // If the class is marked reweavable, check any aspects around when it was built are in this world
+                       WeaverStateInfo wsi = classType.getWeaverState();               
+                       if (wsi!=null && wsi.isReweavable()) { // Check all necessary types are around!
+                               world.showMessage(IMessage.INFO,"processing reweavable type "+className+": "+classType.getSourceLocation().getSourceFile(),null,null);
+                       Set aspectsPreviouslyInWorld = wsi.getAspectsAffectingType();
+                               if (aspectsPreviouslyInWorld!=null) {
+                                       for (Iterator iter = aspectsPreviouslyInWorld.iterator(); iter.hasNext();) {
+                                               String requiredTypeName = (String) iter.next();
+                                               if (!alreadyConfirmedOK.contains(requiredTypeName)) {
+                                                       ResolvedTypeX rtx = world.resolve(TypeX.forName(requiredTypeName),true);
+                                                       boolean exists = rtx!=ResolvedTypeX.MISSING;
+                                                       if (!exists) {
+                                                               world.showMessage(IMessage.ERROR, "type " + requiredTypeName + 
+                                                                       " is needed by reweavable type " + className,
+                                                                       classType.getSourceLocation(), null);
+                                                       } else {
+                                                               if (!world.getMessageHandler().isIgnoring(IMessage.INFO))
+                                                                 world.showMessage(IMessage.INFO,"successfully verified type "+requiredTypeName+
+                                    " exists.  Originates from "+rtx.getSourceLocation().getSourceFile(),null,null);
+                                                               alreadyConfirmedOK.add(requiredTypeName);
+                                                       }
+                                               }               
+                                       }
+                               }
+                               classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData()));
+                       } else {
+               classType.resetState();
+                       }
         }
        
        
@@ -431,7 +472,7 @@ public class BcelWeaver implements IWeaver {
                                        
                                        classType.addParent(newParent);
                                        ResolvedTypeMunger newParentMunger = new NewParentTypeMunger(newParent);
-                                       onType.addInterTypeMunger(new BcelTypeMunger(newParentMunger, null));
+                                       onType.addInterTypeMunger(new BcelTypeMunger(newParentMunger, xcutSet.findAspectDeclaringParents(p)));
                                }
                        }
                }
@@ -462,6 +503,7 @@ public class BcelWeaver implements IWeaver {
                
                return ret;
        }
+
        
        private LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType, boolean dump) throws IOException {             
                if (classType.isSynthetic()) {
@@ -574,4 +616,11 @@ public class BcelWeaver implements IWeaver {
                this.progressPerClassFile = progressPerClassFile;
        }
 
+       public void setReweavableMode(boolean mode,boolean compress) {
+               inReweavableMode = mode;
+               compressReweavableAttributes = compress;
+               WeaverStateInfo.setReweavableModeDefaults(mode,compress);
+               BcelClassWeaver.setReweavableMode(mode,compress);
+       }
+
 }
index 6a37aee39717e75a9ca240fbaa4aea83f5a64c8a..c003201716d9ce6e84f8c65f81a04fe690324b08 100644 (file)
@@ -25,6 +25,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
@@ -470,6 +471,16 @@ public final class LazyClassGen {
                return myType.getWeaverState() != null;
        }
        
+       public boolean isReweavable() {
+               if (myType.getWeaverState()==null) return false;
+               return myType.getWeaverState().isReweavable();
+       }
+       
+       public Set getAspectsAffectingType() {
+               if (myType.getWeaverState()==null) return null;
+               return myType.getWeaverState().getAspectsAffectingType();
+       }
+       
        public WeaverStateInfo getOrCreateWeaverStateInfo() {
                WeaverStateInfo ret = myType.getWeaverState();
                if (ret != null) return ret;
index 6aa5f7fc3e011f6f2b2f66ad93b8b13baeea393b..4c00603e945575645fb29ff0abba31eb85fb94c1 100644 (file)
@@ -161,7 +161,7 @@ public class CflowPointcut extends Pointcut {
                //XXX and then that info above needs to be mapped down here to help with
                //XXX getting the exposed state right
                concreteAspect.crosscuttingMembers.addConcreteShadowMunger(
-                               Advice.makeCflowEntry(world, concreteEntry, isBelow, cflowField, freeVars.length, innerCflowEntries));
+                               Advice.makeCflowEntry(world, concreteEntry, isBelow, cflowField, freeVars.length, innerCflowEntries,inAspect));
                
                concreteAspect.crosscuttingMembers.addTypeMunger(
                        world.makeCflowStackFieldAdder(cflowField));