From f1ad9e6c3550df1679ca5a79729ffd129d55f02d Mon Sep 17 00:00:00 2001 From: aclement Date: Thu, 8 Jun 2006 08:38:43 +0000 Subject: [PATCH] synchronization joinpoints: code dump... --- weaver/src/org/aspectj/weaver/Advice.java | 15 ++++ weaver/src/org/aspectj/weaver/Shadow.java | 59 ++++++++++-- weaver/src/org/aspectj/weaver/World.java | 15 +++- .../org/aspectj/weaver/bcel/BcelShadow.java | 28 +++++- .../weaver/bcel/PoliceExtensionUse.java | 89 +++++++++++++++++++ .../weaver/patterns/KindedPointcut.java | 3 + .../org/aspectj/weaver/patterns/Pointcut.java | 9 ++ 7 files changed, 206 insertions(+), 12 deletions(-) create mode 100644 weaver/src/org/aspectj/weaver/bcel/PoliceExtensionUse.java diff --git a/weaver/src/org/aspectj/weaver/Advice.java b/weaver/src/org/aspectj/weaver/Advice.java index d8d8f3b7c..959ce3a18 100644 --- a/weaver/src/org/aspectj/weaver/Advice.java +++ b/weaver/src/org/aspectj/weaver/Advice.java @@ -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) { diff --git a/weaver/src/org/aspectj/weaver/Shadow.java b/weaver/src/org/aspectj/weaver/Shadow.java index 6207516a3..0db4ac5a4 100644 --- a/weaver/src/org/aspectj/weaver/Shadow.java +++ b/weaver/src/org/aspectj/weaver/Shadow.java @@ -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()) diff --git a/weaver/src/org/aspectj/weaver/World.java b/weaver/src/org/aspectj/weaver/World.java index c4a1faf10..8aacc20ee 100644 --- a/weaver/src/org/aspectj/weaver/World.java +++ b/weaver/src/org/aspectj/weaver/World.java @@ -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;} } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java index 98a11f39b..db7650560 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java @@ -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; } -} +} \ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/bcel/PoliceExtensionUse.java b/weaver/src/org/aspectj/weaver/bcel/PoliceExtensionUse.java new file mode 100644 index 000000000..186333ca0 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/PoliceExtensionUse.java @@ -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; + } + +} \ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java b/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java index ef4f3e60a..cc2064742 100644 --- a/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java @@ -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) { diff --git a/weaver/src/org/aspectj/weaver/patterns/Pointcut.java b/weaver/src/org/aspectj/weaver/patterns/Pointcut.java index b0b97bc48..a4af8a495 100644 --- a/weaver/src/org/aspectj/weaver/patterns/Pointcut.java +++ b/weaver/src/org/aspectj/weaver/patterns/Pointcut.java @@ -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) {} -- 2.39.5