/* * This code is made available under version 3 of the * GNU GENERAL PUBLIC LICENSE. See the file LICENSE in this * distribution for details. * * Copyright 2008 Eric Bodden */ package ca.mcgill.sable.racer; import java.util.HashMap; import java.util.Map; import org.aspectbench.tm.runtime.internal.WeakKeyIdentityHashMap; import org.aspectj.lang.JoinPoint.StaticPart; import org.aspectj.lang.reflect.SourceLocation; /** * Main monitoring aspect. This aspect monitors field accesses and records lock sets per field. * * @author Eric Bodden */ public aspect Racer { public final static boolean LOGGING = !System.getProperty("RACER_LOGGING","false").equals("false"); /** * A mapping from a field owner to a field to a state. * This field is accessed by multiple threads but they all lock on * this field. */ private Map ownerToFieldToState = new WeakKeyIdentityHashMap(); /** restricts the scope of that aspect to avoid infinite recursion */ pointcut scope(): !within(ca.mcgill.sable..*) && !cflow(within(ca.mcgill.sable..*)); /** matches set-joinpoints of static fields */ pointcut staticFieldSet(): set(static * *) && maybeShared(); /** matches set-joinpoints of non-static fields exposing owner object of the field */ pointcut fieldSet(Object owner): set(!static * *) && target(owner) && maybeShared(); /** matches get-joinpoints of static fields */ pointcut staticFieldGet(): get(static * *) && maybeShared(); /** matches get-joinpoints of non-static fields exposing owner object of the field */ pointcut fieldGet(Object owner): get(!static * *) && target(owner) && maybeShared(); // ========= Advice to capture field accesses ========== /** * On every non-static field set... * @param owner the owner object of the field */ before(Object owner): fieldSet(owner) && scope() { String id = getId(thisJoinPointStaticPart); SourceLocation loc = location(thisJoinPointStaticPart); fieldSet(owner,id,loc); } /** * On every static field set... */ before(): staticFieldSet() && scope() { String id = getId(thisJoinPointStaticPart); Class owner = thisJoinPointStaticPart.getSignature().getDeclaringType(); SourceLocation loc = location(thisJoinPointStaticPart); fieldSet(owner,id,loc); } /** * On every non-static field get... * @param owner the owner object of the field */ before(Object owner): fieldGet(owner) && scope() { String id = getId(thisJoinPointStaticPart); SourceLocation loc = location(thisJoinPointStaticPart); fieldGet(owner,id,loc); } /** * On every static field get... */ before(): staticFieldGet() && scope() { String id = getId(thisJoinPointStaticPart); Class owner = thisJoinPointStaticPart.getSignature().getDeclaringType(); SourceLocation loc = location(thisJoinPointStaticPart); fieldGet(owner,id,loc); } private String getId(StaticPart sp) { return sp.getSignature().toLongString().intern(); } private SourceLocation location(StaticPart sp){ return sp.getSourceLocation(); } private void fieldSet(Object owner, String id, SourceLocation loc) { State currentState = getState(Thread.currentThread(),owner, id); State newState = currentState.onWrite(Thread.currentThread(),owner,id,loc); if(LOGGING) { System.err.println("WRITE: Moved state for field '"+id+ "' of object '"+owner+"' to from '"+currentState+ "' to '"+newState+"' ("+Thread.currentThread().getName()+")"); } putState(owner, id, newState); } private void fieldGet(Object owner, String id, SourceLocation loc) { State currentState = getState(Thread.currentThread(),owner, id); State newState = currentState.onRead(Thread.currentThread(),owner,id,loc); if(LOGGING) { System.err.println("READ: Moved state for field '"+id+ "' of object '"+owner+"' to from '"+currentState+ "' to '"+newState+"' ("+Thread.currentThread().getName()+")"); } putState(owner, id, newState); } private State getState(Thread t, Object owner, String id) { synchronized (ownerToFieldToState) { Map fieldToState = (Map)ownerToFieldToState.get(owner); if(fieldToState==null) { fieldToState = new HashMap(); ownerToFieldToState.put(owner,fieldToState); } State state = (State)fieldToState.get(id); if(state==null) { state = new VirginState(owner, id); fieldToState.put(id,state); } return state; } } private void putState(Object owner, String id, State newState) { synchronized (ownerToFieldToState) { Map fieldToState = (Map)ownerToFieldToState.get(owner); if(fieldToState==null) { fieldToState = new HashMap(); ownerToFieldToState.put(owner,fieldToState); } fieldToState.put(id,newState); } } }