diff options
17 files changed, 497 insertions, 68 deletions
diff --git a/lib/test/aspectjrt.jar b/lib/test/aspectjrt.jar Binary files differindex c4febb323..1e52a6373 100644 --- a/lib/test/aspectjrt.jar +++ b/lib/test/aspectjrt.jar 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"); |