aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/test/aspectjrt.jarbin35991 -> 41305 bytes
-rw-r--r--runtime/src/org/aspectj/runtime/internal/CFlowCounter.java75
-rw-r--r--runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadCounter.java21
-rw-r--r--runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadCounterImpl11.java74
-rw-r--r--runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactory.java1
-rw-r--r--runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl.java22
-rw-r--r--runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl11.java4
-rw-r--r--tests/cflow/CounterTest01.java68
-rw-r--r--tests/src/org/aspectj/systemtest/ajc121/Ajc121Tests.java4
-rw-r--r--tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml8
-rw-r--r--weaver/src/org/aspectj/weaver/NameMangler.java5
-rw-r--r--weaver/src/org/aspectj/weaver/World.java4
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/BcelCflowCounterFieldAdder.java89
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/BcelShadow.java66
-rw-r--r--weaver/src/org/aspectj/weaver/bcel/BcelWorld.java4
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java80
-rw-r--r--weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java40
17 files changed, 497 insertions, 68 deletions
diff --git a/lib/test/aspectjrt.jar b/lib/test/aspectjrt.jar
index c4febb323..1e52a6373 100644
--- a/lib/test/aspectjrt.jar
+++ b/lib/test/aspectjrt.jar
Binary files 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
index 000000000..e48f67864
--- /dev/null
+++ b/runtime/src/org/aspectj/runtime/internal/CFlowCounter.java
@@ -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
index 000000000..96f136ec3
--- /dev/null
+++ b/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadCounter.java
@@ -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
index 000000000..997f5fed3
--- /dev/null
+++ b/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadCounterImpl11.java
@@ -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;
+ }
+
+}
diff --git a/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactory.java b/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactory.java
index d382acbc8..b79b63a98 100644
--- a/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactory.java
+++ b/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactory.java
@@ -15,5 +15,6 @@ package org.aspectj.runtime.internal.cflowstack;
public interface ThreadStackFactory {
public ThreadStack getNewThreadStack();
+ public ThreadCounter getNewThreadCounter();
}
diff --git a/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl.java b/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl.java
index d39b7fcb6..98ca2f4b5 100644
--- a/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl.java
+++ b/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl.java
@@ -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();
+ }
}
diff --git a/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl11.java b/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl11.java
index 350a68109..f4d2a2230 100644
--- a/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl11.java
+++ b/runtime/src/org/aspectj/runtime/internal/cflowstack/ThreadStackFactoryImpl11.java
@@ -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
index 000000000..1578ea0f8
--- /dev/null
+++ b/tests/cflow/CounterTest01.java
@@ -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();
+ }
+
+}
diff --git a/tests/src/org/aspectj/systemtest/ajc121/Ajc121Tests.java b/tests/src/org/aspectj/systemtest/ajc121/Ajc121Tests.java
index 022424090..82574a339 100644
--- a/tests/src/org/aspectj/systemtest/ajc121/Ajc121Tests.java
+++ b/tests/src/org/aspectj/systemtest/ajc121/Ajc121Tests.java
@@ -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
diff --git a/tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml b/tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml
index 5c76906a3..2d443d55c 100644
--- a/tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml
+++ b/tests/src/org/aspectj/systemtest/ajc121/ajc121-tests.xml
@@ -464,4 +464,12 @@
<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
diff --git a/weaver/src/org/aspectj/weaver/NameMangler.java b/weaver/src/org/aspectj/weaver/NameMangler.java
index e73973541..6d49a45fb 100644
--- a/weaver/src/org/aspectj/weaver/NameMangler.java
+++ b/weaver/src/org/aspectj/weaver/NameMangler.java
@@ -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()));
+ }
diff --git a/weaver/src/org/aspectj/weaver/World.java b/weaver/src/org/aspectj/weaver/World.java
index f72a3c5ac..74a083053 100644
--- a/weaver/src/org/aspectj/weaver/World.java
+++ b/weaver/src/org/aspectj/weaver/World.java
@@ -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
index 000000000..5c6a44d96
--- /dev/null
+++ b/weaver/src/org/aspectj/weaver/bcel/BcelCflowCounterFieldAdder.java
@@ -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());
+ }
+
+}
diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
index 2d15f0989..cbabd9e1c 100644
--- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
+++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
@@ -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;
}
});
diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java
index e2c7e0225..b77d546fb 100644
--- a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java
+++ b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java
@@ -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
diff --git a/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java b/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java
index 1db5bb695..adbb5839d 100644
--- a/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java
@@ -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);
}
}
diff --git a/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java
index df2c76bba..e02d6f7d2 100644
--- a/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java
+++ b/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java
@@ -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");