@@ -43,6 +43,8 @@ public abstract class Advice extends ShadowMunger { | |||
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, | |||
@@ -115,6 +117,19 @@ public abstract class Advice extends ShadowMunger { | |||
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) { |
@@ -14,6 +14,7 @@ | |||
package org.aspectj.weaver; | |||
import java.io.DataInputStream; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
@@ -146,6 +147,10 @@ public abstract class Shadow { | |||
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(); | |||
@@ -165,6 +170,9 @@ public abstract class Shadow { | |||
if (isShadowForArrayConstructionJoinpoint()) { | |||
return getArgumentTypesForArrayConstructionShadow(); | |||
} | |||
if (isShadowForMonitor()) { | |||
return UnresolvedType.ARRAY_WITH_JUST_OBJECT; | |||
} | |||
if (getKind() == FieldSet) return new UnresolvedType[] { getResolvedSignature().getGenericReturnType() }; | |||
return getResolvedSignature().getGenericParameterTypes(); | |||
} | |||
@@ -236,8 +244,9 @@ public abstract class Shadow { | |||
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(); | |||
} | |||
@@ -257,6 +266,8 @@ public abstract class Shadow { | |||
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; | |||
@@ -270,20 +281,22 @@ public abstract class Shadow { | |||
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; | |||
} | |||
/** | |||
@@ -363,7 +376,7 @@ public abstract class Shadow { | |||
} | |||
private final static int neverHasTargetFlag= | |||
ConstructorCallBit | ExceptionHandlerBit | PreInitializationBit | StaticInitializationBit; | |||
ConstructorCallBit | ExceptionHandlerBit | PreInitializationBit | StaticInitializationBit | SynchronizationLockBit | SynchronizationUnlockBit; | |||
public boolean neverHasTarget() { | |||
return (bit&neverHasTargetFlag)!=0; | |||
} | |||
@@ -395,6 +408,8 @@ public abstract class Shadow { | |||
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); | |||
} | |||
@@ -577,6 +592,25 @@ public abstract class Shadow { | |||
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(); | |||
@@ -604,6 +638,17 @@ public abstract class Shadow { | |||
} | |||
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()) |
@@ -96,13 +96,15 @@ public abstract class World implements Dump.INode { | |||
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; | |||
@@ -762,14 +764,17 @@ public abstract class World implements Dump.INode { | |||
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; | |||
@@ -1162,4 +1167,6 @@ public abstract class World implements Dump.INode { | |||
public void setIncrementalCompileCouldFollow(boolean b) {incrementalCompileCouldFollow = b;} | |||
public boolean couldIncrementalCompileFollow() {return incrementalCompileCouldFollow;} | |||
public void setSynchronizationPointcutsInUse() {synchronizationPointcutsInUse =true;} | |||
public boolean areSynchronizationPointcutsInUse() {return synchronizationPointcutsInUse;} | |||
} |
@@ -814,6 +814,32 @@ public class BcelShadow extends Shadow { | |||
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( | |||
@@ -3295,4 +3321,4 @@ public class BcelShadow extends Shadow { | |||
public String getActualTargetType() { | |||
return actualInstructionTargetType; | |||
} | |||
} | |||
} |
@@ -0,0 +1,89 @@ | |||
/******************************************************************************* | |||
* 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; | |||
} | |||
} |
@@ -100,6 +100,9 @@ public class KindedPointcut extends Pointcut { | |||
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) { |
@@ -29,8 +29,10 @@ import org.aspectj.weaver.ResolvedType; | |||
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: | |||
@@ -310,6 +312,13 @@ public abstract class Pointcut extends PatternNode { | |||
} | |||
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) {} | |||