]> source.dussan.org Git - aspectj.git/commitdiff
synchronization joinpoints: code dump...
authoraclement <aclement>
Thu, 8 Jun 2006 08:38:43 +0000 (08:38 +0000)
committeraclement <aclement>
Thu, 8 Jun 2006 08:38:43 +0000 (08:38 +0000)
weaver/src/org/aspectj/weaver/Advice.java
weaver/src/org/aspectj/weaver/Shadow.java
weaver/src/org/aspectj/weaver/World.java
weaver/src/org/aspectj/weaver/bcel/BcelShadow.java
weaver/src/org/aspectj/weaver/bcel/PoliceExtensionUse.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java
weaver/src/org/aspectj/weaver/patterns/Pointcut.java

index d8d8f3b7c8851193dd77d3aa250c46ce5134e0a2..959ce3a187562cdbef6f03729c68af91ea0753c6 100644 (file)
@@ -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) {
index 6207516a3576d443e683ed4a9bed06d6cc4d6042..0db4ac5a477b6dbc5bb10e4ba56a2d4f98007200 100644 (file)
@@ -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())
index c4a1faf1004a54ce98f49afb165e5e9139deca18..8aacc20ee9dd2b7854416ff64a8ecf82b181785e 100644 (file)
@@ -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;}
 }
index 98a11f39b53d620d4356883ea545460d0983e071..db76505607401ed2913bf2d833fb5d7d34ee33fa 100644 (file)
@@ -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 (file)
index 0000000..186333c
--- /dev/null
@@ -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
index ef4f3e60a9b3fc152dd96dfe239fcd8f3d3ffe92..cc2064742e4aafa955e8586cc003b0f92a166af9 100644 (file)
@@ -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) {
index b0b97bc482c40467b533ad1482d05008c8240d87..a4af8a495253266e29bcd21cbf5fc914d4c644ba 100644 (file)
@@ -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) {}