]> source.dussan.org Git - aspectj.git/commitdiff
76030 - cflow optimizations. Part 1 fix - use counters rather than stacks when we...
authoraclement <aclement>
Mon, 11 Oct 2004 18:39:06 +0000 (18:39 +0000)
committeraclement <aclement>
Mon, 11 Oct 2004 18:39:06 +0000 (18:39 +0000)
17 files changed:
lib/test/aspectjrt.jar
runtime/src/org/aspectj/runtime/internal/CFlowCounter.java [new file with mode: 0644]
runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadCounter.java [new file with mode: 0644]
runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadCounterImpl11.java [new file with mode: 0644]
runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactory.java
runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl.java
runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl11.java
tests/cflow/CounterTest01.java [new file with mode: 0644]
tests/src/org/aspectj/systemtest/ajc121/Ajc121Tests.java
tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml
weaver/src/org/aspectj/weaver/NameMangler.java
weaver/src/org/aspectj/weaver/World.java
weaver/src/org/aspectj/weaver/bcel/BcelCflowCounterFieldAdder.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
weaver/src/org/aspectj/weaver/bcel/BcelWorld.java
weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java
weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java

index c4febb32373845a205bbc185c5bc6d22258cdca2..1e52a637314b5fff6038c7fb74ec869fbf3c4620 100644 (file)
Binary files a/lib/test/aspectjrt.jar and b/lib/test/aspectjrt.jar differ
diff --git a/runtime/src/org/aspectj/runtime/internal/CFlowCounter.java b/runtime/src/org/aspectj/runtime/internal/CFlowCounter.java
new file mode 100644 (file)
index 0000000..e48f678
--- /dev/null
@@ -0,0 +1,75 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation
+ * 
+ * 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 implementation 
+ * ******************************************************************/
+
+
+package org.aspectj.runtime.internal;
+
+import org.aspectj.runtime.internal.cflowstack.ThreadCounter;
+import org.aspectj.runtime.internal.cflowstack.ThreadStackFactory;
+import org.aspectj.runtime.internal.cflowstack.ThreadStackFactoryImpl;
+import org.aspectj.runtime.internal.cflowstack.ThreadStackFactoryImpl11;
+
+
+public class CFlowCounter {
+       
+       private static ThreadStackFactory tsFactory;
+       private ThreadCounter flowHeightHandler;
+
+       static {
+               selectFactoryForVMVersion();
+       }
+       
+       public CFlowCounter() {
+               flowHeightHandler = tsFactory.getNewThreadCounter();
+       }
+    
+    public void inc() {
+       flowHeightHandler.inc();
+    }
+
+    public void dec() {
+       flowHeightHandler.dec();
+    }
+    
+    public boolean isValid() {
+       return flowHeightHandler.isNotZero();
+    }
+
+
+       private static ThreadStackFactory getThreadLocalStackFactory()      { return new ThreadStackFactoryImpl(); }
+       private static ThreadStackFactory getThreadLocalStackFactoryFor11() { return new ThreadStackFactoryImpl11(); }
+    
+       private static void selectFactoryForVMVersion() {
+               String override = System.getProperty("aspectj.runtime.cflowstack.usethreadlocal","unspecified");
+               boolean useThreadLocalImplementation = false;
+               if (override.equals("unspecified")) {
+                       String v = System.getProperty("java.class.version","0.0");
+                       // Java 1.2 is version 46.0 and above
+                       useThreadLocalImplementation = (v.compareTo("46.0") >= 0);
+               } else {
+                       useThreadLocalImplementation = override.equals("yes") || override.equals("true");
+               }
+               // System.err.println("Trying to use thread local implementation? "+useThreadLocalImplementation);
+               if (useThreadLocalImplementation) {
+                       tsFactory = getThreadLocalStackFactory();
+               } else {
+                       tsFactory = getThreadLocalStackFactoryFor11();
+               }
+       }
+       
+       //  For debug ...
+       public static String getThreadStackFactoryClassName() {
+               return tsFactory.getClass().getName();
+       }
+
+}
diff --git a/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadCounter.java b/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadCounter.java
new file mode 100644 (file)
index 0000000..96f136e
--- /dev/null
@@ -0,0 +1,21 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation
+ * 
+ * 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 implementation 
+ * ******************************************************************/
+
+package org.aspectj.runtime.internal.cflowstack;
+
+
+public interface ThreadCounter {
+         public void          inc();
+         public void          dec();
+         public boolean isNotZero();
+}
\ No newline at end of file
diff --git a/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadCounterImpl11.java b/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadCounterImpl11.java
new file mode 100644 (file)
index 0000000..997f5fe
--- /dev/null
@@ -0,0 +1,74 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation
+ * 
+ * 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 implementation 
+ *                                        Copied from bits of original CFlowStack
+ * ******************************************************************/
+package org.aspectj.runtime.internal.cflowstack;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+public class ThreadCounterImpl11 implements ThreadCounter {
+       private Hashtable counters = new Hashtable();
+       private Thread cached_thread;
+       private Counter cached_counter;
+       
+       private int change_count = 0;
+       private static final int COLLECT_AT = 20000;
+       private static final int MIN_COLLECT_AT = 100; 
+       
+       static class Counter {
+               protected int value = 0;
+       }
+
+       private synchronized Counter getThreadCounter() {
+               if (Thread.currentThread() != cached_thread) {
+                       cached_thread = Thread.currentThread();
+                       cached_counter = (Counter)counters.get(cached_thread);
+                       if (cached_counter == null) {
+                               cached_counter = new Counter();
+                               counters.put(cached_thread, cached_counter);
+                       }
+                       change_count++;
+                       // Collect more often if there are many threads, but not *too* often
+                       int size = Math.max(1, counters.size()); // should be >1 b/c always live threads, but...
+                       if (change_count > Math.max(MIN_COLLECT_AT, COLLECT_AT/size)) {
+                               List dead_stacks = new ArrayList();
+                               for (Enumeration e = counters.keys(); e.hasMoreElements(); ) {
+                                       Thread t = (Thread)e.nextElement();
+                                       if (!t.isAlive()) dead_stacks.add(t);
+                               }
+                               for (Iterator e = dead_stacks.iterator(); e.hasNext(); ) {
+                                       Thread t = (Thread)e.next();
+                                       counters.remove(t);
+                               }
+                               change_count = 0;
+                       }
+               }
+               return cached_counter;
+       }
+
+       public void inc() {
+               getThreadCounter().value++;
+       }
+
+       public void dec() {
+               getThreadCounter().value--;
+       }
+
+       public boolean isNotZero() {
+               return getThreadCounter().value!=0;
+       }
+
+}
index d382acbc80ce57e88835d68e44cde1b8b09d66bf..b79b63a98e22bc65a6d1f67612336cd9f5eecc21 100644 (file)
@@ -15,5 +15,6 @@ package org.aspectj.runtime.internal.cflowstack;
 public interface ThreadStackFactory {
        
   public ThreadStack getNewThreadStack();  
+  public ThreadCounter getNewThreadCounter();
   
 }
index d39b7fcb634f2c4567d71835186477c3045e5649..98ca2f4b5997594bcd9108272115dff0f1487fb0 100644 (file)
@@ -28,5 +28,27 @@ public class ThreadStackFactoryImpl implements ThreadStackFactory {
        public ThreadStack getNewThreadStack() {
                return new ThreadStackImpl();
        }
+       
+       private static class ThreadCounterImpl extends ThreadLocal implements ThreadCounter {
+               
+               public Object initialValue() {
+                 return new Counter();
+               }
+               public Counter getThreadCounter() {
+                       return (Counter)get();
+               }
+               
+               public void inc() { getThreadCounter().value++; }
+               public void dec() { getThreadCounter().value--; }
+               public boolean isNotZero() { return getThreadCounter().value!= 0; }
+               
+               static class Counter {
+                 protected int value = 0;
+               }
+       }
+       
+       public ThreadCounter getNewThreadCounter() {
+               return new ThreadCounterImpl();
+       }
 
 }
index 350a68109ee70db2dfd5dee2901ca98361343796..f4d2a22301babbae86f11ce7a180064e6c97515c 100644 (file)
@@ -18,5 +18,9 @@ public class ThreadStackFactoryImpl11 implements ThreadStackFactory {
        public ThreadStack getNewThreadStack() {
                return new ThreadStackImpl11();
        }
+       
+       public ThreadCounter getNewThreadCounter() {
+               return new ThreadCounterImpl11();
+       }
 
 }
diff --git a/tests/cflow/CounterTest01.java b/tests/cflow/CounterTest01.java
new file mode 100644 (file)
index 0000000..1578ea0
--- /dev/null
@@ -0,0 +1,68 @@
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class CounterTest01 {
+
+       public static void main(String []argv) {
+               new CounterTest01().sayMessage();
+               int ctrs = ReflectionHelper.howManyCflowCounterFields(Cflow1.aspectOf());
+               if (ctrs!=2) {
+                       throw new RuntimeException("Should be two cflow counters, but found: "+ctrs);
+               }
+               int stacks = ReflectionHelper.howManyCflowStackFields(Cflow1.aspectOf());
+               if (stacks!=1) {
+                       throw new RuntimeException("Should be one cflow stacks, but found: "+stacks);
+               }
+       }
+       
+       public void sayMessage() {
+               print("Hello ");
+               print("World\n");
+       }
+       
+       public void print(String msg) {
+               System.out.print(msg);
+       }
+}
+
+aspect Cflow1 {
+       before(): execution(* print(..)) && cflow(execution(* main(..))) {
+               // Managed by a CflowCounter
+       }
+       
+       before(): execution(* print(..)) && cflow(execution(* main(..))) {
+               // Managed by a CflowCounter
+       }
+       
+       before(Object o): execution(* print(..)) && cflow(execution(* main(..)) && target(o)) {
+               // Managed by a CflowStack - since state is exposed
+       }
+}
+
+class ReflectionHelper {
+  public static List getCflowfields(Object o,boolean includeCounters,boolean includeStacks) {
+       List res = new ArrayList();
+       Class clazz = o.getClass();
+       Field[] fs = clazz.getDeclaredFields();
+       for (int i = 0; i < fs.length; i++) {
+               Field f = fs[i];
+               if ((f.getType().getName().endsWith("CFlowCounter") && includeCounters) ||
+                       (f.getType().getName().endsWith("CFlowStack") && includeStacks)) {
+                       res.add(f.getType().getName()+":"+f.getName());
+               }
+       }
+       return res;
+  }
+  
+  public static int howManyCflowCounterFields(Object o) {
+    return getCflowfields(o,true,false).size();
+  }
+  
+  public static int howManyCflowStackFields(Object o) {
+    return getCflowfields(o,false,true).size();
+  }
+  
+}
index 02242409048a6f1de94cd05be8a183b13415f969..82574a3393086c9df24e5fcec769366f7093f879 100644 (file)
@@ -313,5 +313,9 @@ public class Ajc121Tests extends org.aspectj.testing.XMLBasedAjcTestCase {
   public void test058_npeOnTJPerror() {
     runTest("NPE on thisJoinPoint mistake");
   }
+  
+  public void test059_cflowOptimization_counters() {
+       runTest("Optimization of cflow - counters");
+  }
 
 }
\ No newline at end of file
index 5c76906a38e7f809bb3ec74bdf2bff5fdcbabf8f..2d443d55ca3567993dfa89512e6af90caf92d03b 100644 (file)
         <compile files="TjpMistake.java">
                <message kind="error" line="22"/>
         </compile>
+    </ajc-test>
+
+       <ajc-test 
+       dir="cflow" 
+       pr="76030"
+               title="Optimization of cflow - counters">
+        <compile files="CounterTest01.java"/>
+               <run class="CounterTest01"/>
     </ajc-test>
\ No newline at end of file
index e73973541027d8c3852829fa5de1378e1175fcf2..6d49a45fbf11eaaf7a66a6835d78f8f805b413d5 100644 (file)
@@ -25,6 +25,8 @@ public class NameMangler {
        
        
        public static final String CFLOW_STACK_TYPE = "org.aspectj.runtime.internal.CFlowStack";
+       public static final String CFLOW_COUNTER_TYPE="org.aspectj.runtime.internal.CFlowCounter";
+       
        public static final String SOFT_EXCEPTION_TYPE = "org.aspectj.lang.SoftException";
 
        public static final String PERSINGLETON_FIELD_NAME =  PREFIX + "perSingletonInstance";
@@ -294,6 +296,9 @@ public class NameMangler {
        public static String cflowStack(CrosscuttingMembers xcut) {
                return makeName("cflowStack", Integer.toHexString(xcut.getCflowEntries().size()));
        }
+       public static String cflowCounter(CrosscuttingMembers xcut) {
+               return makeName("cflowCounter",Integer.toHexString(xcut.getCflowEntries().size()));
+       }
 
 
 
index f72a3c5ac5e903b10b2f9a192abd5b9266a66719..74a08305374505a62b4b191e0e625c9e5a102911 100644 (file)
@@ -276,6 +276,10 @@ public abstract class World implements Dump.INode {
        public ConcreteTypeMunger makeCflowStackFieldAdder(ResolvedMember cflowField) {
                throw new RuntimeException("unimplemented");
        }
+       
+       public ConcreteTypeMunger makeCflowCounterFieldAdder(ResolvedMember cflowField) {
+               throw new RuntimeException("unimplemented");
+       }
 
     public abstract ConcreteTypeMunger concreteTypeMunger(ResolvedTypeMunger munger, ResolvedTypeX aspectType);
 
diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelCflowCounterFieldAdder.java b/weaver/src/org/aspectj/weaver/bcel/BcelCflowCounterFieldAdder.java
new file mode 100644 (file)
index 0000000..5c6a44d
--- /dev/null
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * 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:
+ *     IBM Corporation - initial API and implementation
+ *      (Andy Clement)
+ *******************************************************************************/
+
+package org.aspectj.weaver.bcel;
+
+import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.classfile.Field;
+import org.aspectj.apache.bcel.generic.FieldGen;
+import org.aspectj.apache.bcel.generic.InstructionFactory;
+import org.aspectj.apache.bcel.generic.InstructionList;
+import org.aspectj.apache.bcel.generic.ObjectType;
+import org.aspectj.apache.bcel.generic.Type;
+import org.aspectj.weaver.Member;
+import org.aspectj.weaver.NameMangler;
+import org.aspectj.weaver.ResolvedMember;
+import org.aspectj.weaver.ResolvedTypeX;
+
+/**
+ * This type munger will modify a given class (see the munge() method) to include
+ * a field representing a CflowCounter object.
+ */
+public class BcelCflowCounterFieldAdder extends BcelTypeMunger {
+       private ResolvedMember cflowCounterField;
+       
+       public BcelCflowCounterFieldAdder(ResolvedMember cflowCounterField) {
+               super(null,(ResolvedTypeX)cflowCounterField.getDeclaringType());
+               this.cflowCounterField = cflowCounterField;
+       }
+
+       public boolean munge(BcelClassWeaver weaver) {
+               LazyClassGen gen = weaver.getLazyClassGen();
+               
+               // Only munge one type!
+               if (!gen.getType().equals(cflowCounterField.getDeclaringType())) return false;
+
+               // Create the field declaration.
+               // Something like: "public static final CflowCounter ajc$cflowCounter$0;"
+               Field f = new FieldGen(cflowCounterField.getModifiers(),
+                   BcelWorld.makeBcelType(cflowCounterField.getReturnType()),
+                   cflowCounterField.getName(),
+               gen.getConstantPoolGen()).getField();
+               
+       gen.addField(f,getSourceLocation());
+
+       // Modify the ajc$preClinit() method to initialize it.
+       // Something like: "ajc$cflowCounter$0 = new CflowCounter();"
+               LazyMethodGen clinit = gen.getAjcPreClinit(); //StaticInitializer();
+               InstructionList setup = new InstructionList();
+               InstructionFactory fact = gen.getFactory();
+
+               setup.append(fact.createNew(new ObjectType(NameMangler.CFLOW_COUNTER_TYPE)));
+               setup.append(InstructionFactory.createDup(1));
+               setup.append(fact.createInvoke(
+                       NameMangler.CFLOW_COUNTER_TYPE, 
+                       "<init>", 
+                       Type.VOID, 
+                       new Type[0], 
+                       Constants.INVOKESPECIAL));
+
+
+               setup.append(Utility.createSet(fact, cflowCounterField));
+               clinit.getBody().insert(setup);
+
+               return true;
+       }
+
+
+       public ResolvedMember getMatchingSyntheticMember(Member member) {
+               return null;
+       }
+
+       public ResolvedMember getSignature() {
+               return cflowCounterField;
+       }
+
+       public boolean matches(ResolvedTypeX onType) {
+               return onType.equals(cflowCounterField.getDeclaringType());
+       }
+
+}
index 2d15f09893a7d6d618280eb0b025016579183400..cbabd9e1c0c3f1f7fc4c475cb19b2b8e6f2a33ac 100644 (file)
@@ -1415,7 +1415,7 @@ public class BcelShadow extends Shadow {
        }
     
        
-       public void weaveCflowEntry(final BcelAdvice munger, final Member cflowStackField) {
+       public void weaveCflowEntry(final BcelAdvice munger, final Member cflowField) {
                final boolean isPer = munger.getKind() == AdviceKind.PerCflowBelowEntry || 
                                                                munger.getKind() == AdviceKind.PerCflowEntry;
                
@@ -1446,30 +1446,40 @@ public class BcelShadow extends Shadow {
                        } else {
                                BcelVar[] cflowStateVars = munger.getExposedStateAsBcelVars();
        
-                               BcelVar arrayVar = genTempVar(TypeX.OBJECTARRAY);
+                               if (cflowStateVars.length == 0) {
+                                       // This should be getting managed by a counter - lets make sure.
+                                       if (!cflowField.getType().getName().endsWith("CFlowCounter")) 
+                                               throw new RuntimeException("Oncorrectly attempting counter operation on stacked cflow");
+                                       entrySuccessInstructions.append(
+                                               Utility.createGet(fact, cflowField));
+                                       //arrayVar.appendLoad(entrySuccessInstructions, fact);
+                                       entrySuccessInstructions.append(fact.createInvoke(NameMangler.CFLOW_COUNTER_TYPE,"inc",Type.VOID,new Type[] { },Constants.INVOKEVIRTUAL));
+                               } else {
+                                   BcelVar arrayVar = genTempVar(TypeX.OBJECTARRAY);
        
-                       int alen = cflowStateVars.length;
-                       entrySuccessInstructions.append(Utility.createConstant(fact, alen));
-                               entrySuccessInstructions.append(
-                                       (Instruction) fact.createNewArray(Type.OBJECT, (short) 1));
-                       arrayVar.appendStore(entrySuccessInstructions, fact);
+                                   int alen = cflowStateVars.length;
+                                   entrySuccessInstructions.append(Utility.createConstant(fact, alen));
+                                   entrySuccessInstructions.append(
+                                               (Instruction) fact.createNewArray(Type.OBJECT, (short) 1));
+                                   arrayVar.appendStore(entrySuccessInstructions, fact);
                 
-                               for (int i = 0; i < alen; i++) {
-                                       arrayVar.appendConvertableArrayStore(
-                                               entrySuccessInstructions,
-                                               fact,
-                                               i,
-                                               cflowStateVars[i]);
-                               }               
+                                   for (int i = 0; i < alen; i++) {
+                                       arrayVar.appendConvertableArrayStore(
+                                                       entrySuccessInstructions,
+                                                               fact,
+                                                               i,
+                                                               cflowStateVars[i]);
+                                   }           
        
-                       entrySuccessInstructions.append(
-                               Utility.createGet(fact, cflowStackField));
-                               arrayVar.appendLoad(entrySuccessInstructions, fact);
+                                   entrySuccessInstructions.append(
+                                               Utility.createGet(fact, cflowField));
+                                   arrayVar.appendLoad(entrySuccessInstructions, fact);
 
-                       entrySuccessInstructions.append(
-                               fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "push", Type.VOID, 
+                                   entrySuccessInstructions.append(
+                                               fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "push", Type.VOID, 
                                                        new Type[] { objectArrayType }, 
-                                                       Constants.INVOKEVIRTUAL));
+                                               Constants.INVOKEVIRTUAL));
+                               }
                        }
 
                        
@@ -1496,7 +1506,20 @@ public class BcelShadow extends Shadow {
                                                        Constants.IFEQ,
                                                        ifNoAdvice));
                                }
-                               exitInstructions.append(Utility.createGet(fact, cflowStackField));
+                               exitInstructions.append(Utility.createGet(fact, cflowField));
+                               if (munger.getKind() != AdviceKind.PerCflowEntry &&
+                                       munger.getKind() != AdviceKind.PerCflowBelowEntry &&
+                                       munger.getExposedStateAsBcelVars().length==0) {
+                                       exitInstructions
+                                       .append(
+                                               fact
+                                               .createInvoke(
+                                                       NameMangler.CFLOW_COUNTER_TYPE,
+                                                       "dec",
+                                                       Type.VOID,
+                                                       new Type[] {
+                               }, Constants.INVOKEVIRTUAL));
+                               } else {
                                exitInstructions
                                        .append(
                                                fact
@@ -1506,6 +1529,7 @@ public class BcelShadow extends Shadow {
                                                        Type.VOID,
                                                        new Type[] {
                                }, Constants.INVOKEVIRTUAL));
+                               }
                                return exitInstructions;
                        }
                });
index e2c7e02253f861049f77c55450a99992c427350f..b77d546fbc8e303f6bf93ff364639b1112176ff5 100644 (file)
@@ -357,6 +357,10 @@ public class BcelWorld extends World {
        public ConcreteTypeMunger makeCflowStackFieldAdder(ResolvedMember cflowField) {
                return new BcelCflowStackFieldAdder(cflowField);
        }
+       
+       public ConcreteTypeMunger makeCflowCounterFieldAdder(ResolvedMember cflowField) {
+               return new BcelCflowCounterFieldAdder(cflowField);
+       }
 
        public static BcelObjectType getBcelObjectType(ResolvedTypeX concreteAspect) {
                //XXX need error checking
index 1db5bb695bb3e15a69b0b745e2db8693fb33fa95..adbb5839de1fc25879f77940244d7dd3f2e6d3f1 100644 (file)
@@ -127,15 +127,16 @@ public class CflowPointcut extends Pointcut {
                throw new RuntimeException("unimplemented");
        }
        
-       
        public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
+
+               // Enforce rule about which designators are supported in declare
                if (isDeclare(bindings.getEnclosingAdvice())) {
-                       // Enforce rule about which designators are supported in declare
                        inAspect.getWorld().showMessage(IMessage.ERROR,
                                        WeaverMessages.format(WeaverMessages.CFLOW_IN_DECLARE,isBelow?"below":""),
                                        bindings.getEnclosingAdvice().getSourceLocation(), null);
                        return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
                }
+               
                //make this remap from formal positions to arrayIndices
                IntMap entryBindings = new IntMap();
                for (int i=0, len=freeVars.length; i < len; i++) {
@@ -155,7 +156,9 @@ public class CflowPointcut extends Pointcut {
                CrosscuttingMembers xcut = concreteAspect.crosscuttingMembers;          
                Collection previousCflowEntries = xcut.getCflowEntries();
                
+               
                entryBindings.pushEnclosingDefinition(CFLOW_MARKER);
+               // This block concretizes the pointcut within the cflow pointcut
                try {
                        concreteEntry = entry.concretize(inAspect, entryBindings);
                } finally {
@@ -164,42 +167,55 @@ public class CflowPointcut extends Pointcut {
 
                List innerCflowEntries = new ArrayList(xcut.getCflowEntries());
                innerCflowEntries.removeAll(previousCflowEntries);
-
                
-               ResolvedMember cflowField = new ResolvedMember(
-                       Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
-                                       NameMangler.cflowStack(xcut), 
-                                       TypeX.forName(NameMangler.CFLOW_STACK_TYPE).getSignature());
-               //System.out.println("adding field to: " + inAspect + " field " + cflowField);
-                                       
-               // add field and initializer to inAspect
-               //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,inAspect));
+               if (freeVars.length == 0) { // No state, so don't use a stack, use a counter.
+                 ResolvedMember cflowField = new ResolvedMember(Member.FIELD,concreteAspect,Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
+                               NameMangler.cflowCounter(xcut),TypeX.forName(NameMangler.CFLOW_COUNTER_TYPE).getSignature());
+                 
+                 // Create type munger to add field to the aspect
+                 concreteAspect.crosscuttingMembers.addTypeMunger(world.makeCflowCounterFieldAdder(cflowField));
+                 
+                 // Create shadow munger to push stuff onto the stack
+                 concreteAspect.crosscuttingMembers.addConcreteShadowMunger(
+                               Advice.makeCflowEntry(world,concreteEntry,isBelow,cflowField,freeVars.length,innerCflowEntries,inAspect));
+                 return new ConcreteCflowPointcut(cflowField, null,true);
+               } else {
                
-               concreteAspect.crosscuttingMembers.addTypeMunger(
-                       world.makeCflowStackFieldAdder(cflowField));
+                       List slots = new ArrayList();
+                       for (int i=0, len=freeVars.length; i < len; i++) {
+                               int freeVar = freeVars[i];
+                               
+                               // we don't need to keep state that isn't actually exposed to advice
+                               //??? this means that we will store some state that we won't actually use, optimize this later
+                               if (!bindings.hasKey(freeVar)) continue; 
+                               
+                               int formalIndex = bindings.get(freeVar);
+                               ResolvedTypeX formalType =
+                                       bindings.getAdviceSignature().getParameterTypes()[formalIndex].resolve(world);
+                               
+                               ConcreteCflowPointcut.Slot slot = 
+                                       new ConcreteCflowPointcut.Slot(formalIndex, formalType, i);
+                               slots.add(slot);
+                       }
                        
+                       ResolvedMember cflowField = new ResolvedMember(
+                               Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
+                                               NameMangler.cflowStack(xcut), 
+                                               TypeX.forName(NameMangler.CFLOW_STACK_TYPE).getSignature());
+                       //System.out.println("adding field to: " + inAspect + " field " + cflowField);
+                                               
+                       // add field and initializer to inAspect
+                       //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,inAspect));
                        
-               List slots = new ArrayList();
-               for (int i=0, len=freeVars.length; i < len; i++) {
-                       int freeVar = freeVars[i];
-                       
-                       // we don't need to keep state that isn't actually exposed to advice
-                       //??? this means that we will store some state that we won't actually use, optimize this later
-                       if (!bindings.hasKey(freeVar)) continue; 
-                       
-                       int formalIndex = bindings.get(freeVar);
-                       ResolvedTypeX formalType =
-                               bindings.getAdviceSignature().getParameterTypes()[formalIndex].resolve(world);
-                       
-                       ConcreteCflowPointcut.Slot slot = 
-                               new ConcreteCflowPointcut.Slot(formalIndex, formalType, i);
-                       slots.add(slot);
+                       concreteAspect.crosscuttingMembers.addTypeMunger(
+                               world.makeCflowStackFieldAdder(cflowField));
+
+                       return new ConcreteCflowPointcut(cflowField, slots,false);
                }
                
-               return new ConcreteCflowPointcut(cflowField, slots);
        }
 
 }
index df2c76bbaf4f55b2a62e7931a08c653bfa739b73..e02d6f7d2f06b62b035c380d5ba1332b0498402a 100644 (file)
@@ -31,13 +31,15 @@ import org.aspectj.weaver.bcel.BcelCflowAccessVar;
 
 
 public class ConcreteCflowPointcut extends Pointcut {
-       private Member cflowStackField;
+       private Member cflowField;
        List/*Slot*/ slots; // exposed for testing
-
+    boolean usesCounter;
        
-       public ConcreteCflowPointcut(Member cflowStackField, List slots) {
-               this.cflowStackField = cflowStackField;
-               this.slots = slots;
+    // Can either use a counter or a stack to implement cflow.
+       public ConcreteCflowPointcut(Member cflowField, List slots,boolean usesCounter) {
+               this.cflowField  = cflowField;
+               this.slots       = slots;
+               this.usesCounter = usesCounter;
        }
     
     public FuzzyBoolean fastMatch(FastMatchInfo type) {
@@ -65,32 +67,40 @@ public class ConcreteCflowPointcut extends Pointcut {
        public boolean equals(Object other) {
                if (!(other instanceof ConcreteCflowPointcut)) return false;
                ConcreteCflowPointcut o = (ConcreteCflowPointcut)other;
-               return o.cflowStackField.equals(this.cflowStackField);
+               return o.cflowField.equals(this.cflowField);
        }
     public int hashCode() {
         int result = 17;
-        result = 37*result + cflowStackField.hashCode();
+        result = 37*result + cflowField.hashCode();
         return result;
     }
        public String toString() {
-               return "concretecflow(" + cflowStackField + ")";
+               return "concretecflow(" + cflowField + ")";
        }
 
        public Test findResidue(Shadow shadow, ExposedState state) {
                //System.out.println("find residue: " + this);
-               for (Iterator i = slots.iterator(); i.hasNext();) {
-                       Slot slot = (Slot) i.next();
-                       //System.out.println("slot: " + slot.formalIndex);
-                       state.set(slot.formalIndex, 
-                               new BcelCflowAccessVar(slot.formalType, cflowStackField, slot.arrayIndex));
+               if (usesCounter) {
+                       return Test.makeFieldGetCall(cflowField, cflowCounterIsValidMethod, Expr.NONE);
+               } else {
+                 if (slots != null) { // null for cflows managed by counters
+                   for (Iterator i = slots.iterator(); i.hasNext();) {
+                         Slot slot = (Slot) i.next();
+                         //System.out.println("slot: " + slot.formalIndex);
+                         state.set(slot.formalIndex, 
+                               new BcelCflowAccessVar(slot.formalType, cflowField, slot.arrayIndex));
+                   }
+                 }
+                 return Test.makeFieldGetCall(cflowField, cflowStackIsValidMethod, Expr.NONE);
                }
-               
-               return Test.makeFieldGetCall(cflowStackField, cflowStackIsValidMethod, Expr.NONE);
        }
        
        private static final Member cflowStackIsValidMethod = 
                Member.method(TypeX.forName(NameMangler.CFLOW_STACK_TYPE), 0, "isValid", "()Z");
 
+       private static final Member cflowCounterIsValidMethod = 
+               Member.method(TypeX.forName(NameMangler.CFLOW_COUNTER_TYPE), 0, "isValid", "()Z");
+
        
        public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
                throw new RuntimeException("unimplemented");