--- /dev/null
+/* *******************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/* *******************************************************************
+ * 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
--- /dev/null
+/* *******************************************************************
+ * 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;
+ }
+
+}
public interface ThreadStackFactory {
public ThreadStack getNewThreadStack();
+ public ThreadCounter getNewThreadCounter();
}
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();
+ }
}
public ThreadStack getNewThreadStack() {
return new ThreadStackImpl11();
}
+
+ public ThreadCounter getNewThreadCounter() {
+ return new ThreadCounterImpl11();
+ }
}
--- /dev/null
+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();
+ }
+
+}
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
<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
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";
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()));
+ }
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);
--- /dev/null
+/*******************************************************************************
+ * 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());
+ }
+
+}
}
- 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;
} 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));
+ }
}
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
Type.VOID,
new Type[] {
}, Constants.INVOKEVIRTUAL));
+ }
return exitInstructions;
}
});
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
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++) {
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 {
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);
}
}
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) {
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");