protected UnresolvedType[] bindingParameterTypes;
protected List/*Lint.Kind*/ suppressedLintKinds = null; // based on annotations on this advice
+
+ ISourceLocation lastReportedMonitorExitJoinpointLocation = null;
public static Advice makeCflowEntry(World world, Pointcut entry, boolean isBelow, Member stackField, int nFreeVars, List innerCflowEntries, ResolvedType inAspect){
Advice ret = world.createAdviceMunger(isBelow ? AdviceKind.CflowBelowEntry : AdviceKind.CflowEntry,
return false;
}
}
+ if (shadow.getKind()==Shadow.SynchronizationLock ||
+ shadow.getKind()==Shadow.SynchronizationUnlock) {
+ if (kind==AdviceKind.Around
+// Don't work, see comments in SynchronizationTests
+// && attribute.getProceedCallSignatures()!=null
+// && attribute.getProceedCallSignatures().length!=0
+ ) {
+ world.showMessage(IMessage.WARNING,
+ WeaverMessages.format(WeaverMessages.NO_AROUND_ON_SYNCHRONIZATION),
+ getSourceLocation(), shadow.getSourceLocation());
+ return false;
+ }
+ }
if (hasExtraParameter() && kind == AdviceKind.AfterReturning) {
package org.aspectj.weaver;
import java.io.DataInputStream;
+import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
return (getKind()==ConstructorCall && signature.getDeclaringType().isArray());
}
+ public boolean isShadowForMonitor() {
+ return (getKind()==SynchronizationLock || getKind()==SynchronizationUnlock);
+ }
+
// will return the right length array of ints depending on how many dimensions the array has
public ResolvedType[] getArgumentTypesForArrayConstructionShadow() {
String s = signature.getDeclaringType().getSignature();
if (isShadowForArrayConstructionJoinpoint()) {
return getArgumentTypesForArrayConstructionShadow();
}
+ if (isShadowForMonitor()) {
+ return UnresolvedType.ARRAY_WITH_JUST_OBJECT;
+ }
if (getKind() == FieldSet) return new UnresolvedType[] { getResolvedSignature().getGenericReturnType() };
return getResolvedSignature().getGenericParameterTypes();
}
public UnresolvedType getReturnType() {
- if (kind == ConstructorCall) return getSignature().getDeclaringType();
- else if (kind == FieldSet) return ResolvedType.VOID;
+ if (kind == ConstructorCall) return getSignature().getDeclaringType();
+ else if (kind == FieldSet) return ResolvedType.VOID;
+ else if (kind == SynchronizationLock || kind==SynchronizationUnlock) return ResolvedType.VOID;
return getResolvedSignature().getGenericReturnType();
}
public static final Kind AdviceExecution = new Kind(JoinPoint.ADVICE_EXECUTION, 9, false);
public static final Kind Initialization = new Kind(JoinPoint.INITIALIZATION, 10, false);
public static final Kind ExceptionHandler = new Kind(JoinPoint.EXCEPTION_HANDLER, 11, true);
+ public static final Kind SynchronizationLock = new Kind(JoinPoint.SYNCHRONIZATION_LOCK, 12, true);
+ public static final Kind SynchronizationUnlock= new Kind(JoinPoint.SYNCHRONIZATION_UNLOCK, 13, true);
// Bits here are 1<<(Kind.getKey()) - and unfortunately keys didn't start at zero so bits here start at 2
public static final int MethodCallBit = 0x002;
public static final int AdviceExecutionBit = 0x200;
public static final int InitializationBit = 0x400;
public static final int ExceptionHandlerBit = 0x800;
+ public static final int SynchronizationLockBit =0x1000;
+ public static final int SynchronizationUnlockBit=0x2000;
- public static final int MAX_SHADOW_KIND = 11;
+ public static final int MAX_SHADOW_KIND = 13;
public static final Kind[] SHADOW_KINDS = new Kind[] {
MethodCall, ConstructorCall, MethodExecution, ConstructorExecution,
FieldGet, FieldSet, StaticInitialization, PreInitialization,
- AdviceExecution, Initialization, ExceptionHandler,
+ AdviceExecution, Initialization, ExceptionHandler,SynchronizationLock,SynchronizationUnlock
};
public static final int ALL_SHADOW_KINDS_BITS;
public static final int NO_SHADOW_KINDS_BITS;
static {
- ALL_SHADOW_KINDS_BITS = 0xffe;
- NO_SHADOW_KINDS_BITS = 0x000;
+ ALL_SHADOW_KINDS_BITS = 0x3ffe;
+ NO_SHADOW_KINDS_BITS = 0x0000;
}
/**
}
private final static int neverHasTargetFlag=
- ConstructorCallBit | ExceptionHandlerBit | PreInitializationBit | StaticInitializationBit;
+ ConstructorCallBit | ExceptionHandlerBit | PreInitializationBit | StaticInitializationBit | SynchronizationLockBit | SynchronizationUnlockBit;
public boolean neverHasTarget() {
return (bit&neverHasTargetFlag)!=0;
}
case 9: return AdviceExecution;
case 10: return Initialization;
case 11: return ExceptionHandler;
+ case 12: return SynchronizationLock;
+ case 13: return SynchronizationUnlock;
}
throw new BCException("unknown kind: " + key);
}
aKind.equals(AdviceKind.Around) ||
aKind.equals(AdviceKind.Softener))) return;
+ // synchronized blocks are implemented with multiple monitor_exit instructions in the bytecode
+ // (one for normal exit from the method, one for abnormal exit), we only want to tell the user
+ // once we have advised the end of the sync block, even though under the covers we will have
+ // woven both exit points
+ if (this.kind==Shadow.SynchronizationUnlock) {
+ if (advice.lastReportedMonitorExitJoinpointLocation==null) {
+ // this is the first time through, let's continue...
+ advice.lastReportedMonitorExitJoinpointLocation = getSourceLocation();
+ } else {
+ if (areTheSame(getSourceLocation(),advice.lastReportedMonitorExitJoinpointLocation)) {
+ // Don't report it again!
+ advice.lastReportedMonitorExitJoinpointLocation=null;
+ return;
+ }
+ // hmmm, this means some kind of nesting is going on, urgh
+ advice.lastReportedMonitorExitJoinpointLocation=getSourceLocation();
+ }
+ }
+
String description = advice.getKind().toString();
String advisedType = this.getEnclosingType().getName();
String advisingType= advice.getConcreteAspect().getName();
}
+ private boolean areTheSame(ISourceLocation locA, ISourceLocation locB) {
+ if (locA==null) return locB==null;
+ if (locB==null) return false;
+ if (locA.getLine()!=locB.getLine()) return false;
+ File fA = locA.getSourceFile();
+ File fB = locA.getSourceFile();
+ if (fA==null) return fB==null;
+ if (fB==null) return false;
+ return fA.getName().equals(fB.getName());
+ }
+
public IRelationship.Kind determineRelKind(ShadowMunger munger) {
AdviceKind ak = ((Advice)munger).getKind();
if (ak.getKey()==AdviceKind.Before.getKey())
private String targetAspectjRuntimeLevel = Constants.RUNTIME_LEVEL_DEFAULT;
/** Flags for the new joinpoints that are 'optional' */
- private boolean optionalJoinpoint_ArrayConstruction = false; // Command line flag: "arrayconstruction"
+ private boolean optionalJoinpoint_ArrayConstruction = false; // Command line flag: "-Xjoinpoints:arrayconstruction"
+ private boolean optionalJoinpoint_Synchronization = false; // Command line flag: "-Xjoinpoints:synchronization"
private boolean addSerialVerUID = false;
private Properties extraConfiguration = null;
private boolean checkedAdvancedConfiguration=false;
+ private boolean synchronizationPointcutsInUse = false;
// Xset'table options
private boolean fastDelegateSupportEnabled = isASMAround;
private boolean runMinimalMemory = false;
public void setOptionalJoinpoints(String jps) {
if (jps==null) return;
- if (jps.indexOf("arrayconstruction")!=-1) {
- optionalJoinpoint_ArrayConstruction = true;
- }
+ if (jps.indexOf("arrayconstruction")!=-1) optionalJoinpoint_ArrayConstruction = true;
+ if (jps.indexOf("trivial")!=-1) optionalJoinpoint_Trivial = true;
+ if (jps.indexOf("synchronization")!=-1) optionalJoinpoint_Synchronization = true;
}
public boolean isJoinpointArrayConstructionEnabled() {
return optionalJoinpoint_ArrayConstruction;
}
+ public boolean isJoinpointSynchronizationEnabled() {
+ return optionalJoinpoint_Synchronization;
+ }
public String getTargetAspectjRuntimeLevel() {
return targetAspectjRuntimeLevel;
public void setIncrementalCompileCouldFollow(boolean b) {incrementalCompileCouldFollow = b;}
public boolean couldIncrementalCompileFollow() {return incrementalCompileCouldFollow;}
+ public void setSynchronizationPointcutsInUse() {synchronizationPointcutsInUse =true;}
+ public boolean areSynchronizationPointcutsInUse() {return synchronizationPointcutsInUse;}
}
retargetAllBranches(arrayInstruction, r.getStart());
return s;
}
+
+ public static BcelShadow makeMonitorEnter(BcelWorld world,LazyMethodGen enclosingMethod,InstructionHandle monitorInstruction,BcelShadow enclosingShadow) {
+ final InstructionList body = enclosingMethod.getBody();
+ Member sig = world.makeJoinPointSignatureForMonitorEnter(enclosingMethod.getEnclosingClass(),monitorInstruction);
+ BcelShadow s = new BcelShadow(world,SynchronizationLock,sig,enclosingMethod,enclosingShadow);
+ ShadowRange r = new ShadowRange(body);
+ r.associateWithShadow(s);
+ r.associateWithTargets(
+ Range.genStart(body, monitorInstruction),
+ Range.genEnd(body, monitorInstruction));
+ retargetAllBranches(monitorInstruction, r.getStart());
+ return s;
+ }
+
+ public static BcelShadow makeMonitorExit(BcelWorld world,LazyMethodGen enclosingMethod,InstructionHandle monitorInstruction,BcelShadow enclosingShadow) {
+ final InstructionList body = enclosingMethod.getBody();
+ Member sig = world.makeJoinPointSignatureForMonitorExit(enclosingMethod.getEnclosingClass(),monitorInstruction);
+ BcelShadow s = new BcelShadow(world,SynchronizationUnlock,sig,enclosingMethod,enclosingShadow);
+ ShadowRange r = new ShadowRange(body);
+ r.associateWithShadow(s);
+ r.associateWithTargets(
+ Range.genStart(body, monitorInstruction),
+ Range.genEnd(body, monitorInstruction));
+ retargetAllBranches(monitorInstruction, r.getStart());
+ return s;
+ }
// see pr77166
// public static BcelShadow makeArrayLoadCall(
public String getActualTargetType() {
return actualInstructionTargetType;
}
-}
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2006 IBM
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - initial API and implementation
+ *******************************************************************************/
+package org.aspectj.weaver.bcel;
+
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.MessageUtil;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.patterns.AndPointcut;
+import org.aspectj.weaver.patterns.IdentityPointcutVisitor;
+import org.aspectj.weaver.patterns.KindedPointcut;
+import org.aspectj.weaver.patterns.NotPointcut;
+import org.aspectj.weaver.patterns.OrPointcut;
+import org.aspectj.weaver.patterns.Pointcut;
+
+/**
+ * Walks a pointcut and determines if the synchronization related designators have been
+ * used: lock() or unlock()
+ */
+public class PoliceExtensionUse extends IdentityPointcutVisitor {
+
+ private boolean synchronizationDesignatorEncountered;
+ private World world;
+ private Pointcut p;
+
+ public PoliceExtensionUse(World w,Pointcut p) {
+ this.world = w;
+ this.p = p;
+ this.synchronizationDesignatorEncountered = false;
+ }
+
+ public boolean synchronizationDesignatorEncountered() {
+ return synchronizationDesignatorEncountered;
+ }
+
+ public Object visit(KindedPointcut node, Object data) {
+ if (world==null) return super.visit(node,data); // error scenario can sometimes lead to this LazyClassGen.toLongString()
+ if (node.getKind()==Shadow.SynchronizationLock ||
+ node.getKind()==Shadow.SynchronizationUnlock)
+ synchronizationDesignatorEncountered=true;
+ // Check it!
+ if (!world.isJoinpointSynchronizationEnabled()) {
+ if (node.getKind()==Shadow.SynchronizationLock) {
+ IMessage m = MessageUtil.warn("lock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization",
+ p.getSourceLocation());
+ world.getMessageHandler().handleMessage(m);
+ } else if (node.getKind()==Shadow.SynchronizationUnlock) {
+ IMessage m = MessageUtil.warn("unlock() pointcut designator cannot be used without the option -Xjoinpoints:synchronization",
+ p.getSourceLocation());
+ world.getMessageHandler().handleMessage(m);
+ }
+ }
+ if (node.getKind()==Shadow.MethodExecution) {
+ if (!world.isJoinpointTrivialEnabled() &&
+ node.getSignature().getModifiers().concernedWithTriviality()) {
+ IMessage m = MessageUtil.warn("Use of 'trivial' modifier in the execution() pointcut is not allowed without the option -Xjoinpoints:trivial",
+ p.getSourceLocation());
+ world.getMessageHandler().handleMessage(m);
+ }
+ }
+ return super.visit(node, data);
+ }
+
+ public Object visit(AndPointcut node, Object data) {
+ node.getLeft().accept(this, data);
+ node.getRight().accept(this, data);
+ return node;
+ }
+
+ public Object visit(NotPointcut node, Object data) {
+ node.getNegatedPointcut().accept(this, data);
+ return node;
+ }
+
+ public Object visit(OrPointcut node, Object data) {
+ node.getLeft().accept(this, data);
+ node.getRight().accept(this, data);
+ return node;
+ }
+
+}
\ No newline at end of file
protected FuzzyBoolean matchInternal(Shadow shadow) {
if (shadow.getKind() != kind) return FuzzyBoolean.NO;
+ if (shadow.getKind() == Shadow.SynchronizationLock && kind == Shadow.SynchronizationLock) return FuzzyBoolean.YES;
+ if (shadow.getKind() == Shadow.SynchronizationUnlock && kind == Shadow.SynchronizationUnlock) return FuzzyBoolean.YES;
+
if (!signature.matches(shadow.getMatchingSignature(), shadow.getIWorld(),this.kind == Shadow.MethodCall)){
if(kind == Shadow.MethodCall) {
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.VersionedDataInputStream;
+import org.aspectj.weaver.World;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.bcel.PoliceExtensionUse;
/**
* The lifecycle of Pointcuts is modeled by Pointcut.State. It has three things:
}
+ public void check(ISourceContext ctx,World world) {
+ PoliceExtensionUse pointcutPolice = new PoliceExtensionUse(world,this);
+ this.accept(pointcutPolice, null);
+ if (pointcutPolice.synchronizationDesignatorEncountered())
+ world.setSynchronizationPointcutsInUse();
+ }
+
//public void prepare(Shadow shadow) {}