anchor.diff:                  // Note that the transaction will at most hold one
                   // lock at a time.
                   //Monitor.Enter e
  -                let enterWorked = e.Lock.EnterWrite(e)
  -                try
  -                    // if the element is already outOfDate we
  -                    // do not traverse the graph further.
  -                    if e.OutOfDate then
  -                        outputCount := 0
  -                        e.AllInputsProcessed(x)
  -
  -                    else
  +
  +                if e.Lock.IsOutdatedCaller(e) then
  +                    e.AllInputsProcessed(x)
  +
  +                else
  +                    let enterWorked = e.Lock.EnterWrite(e)
  +                    try
  +                        // if the element is already outOfDate we
  +                        // do not traverse the graph further.
  +                        if e.OutOfDate then
  +                            outputCount := 0
  +                            e.AllInputsProcessed(x)
  +
  +                        else
                           
   
  -                        // if the object's level has changed since it
  -                        // was added to the queue we re-enqueue it with the new level
  -                        // Note that this may of course cause runtime overhead and
  -                        // might even change the asymptotic runtime behaviour of the entire
  -                        // system in the worst case but we opted for this approach since
  -                        // it is relatively simple to implement.
  -                        if currentLevel <> e.Level then
  -                            q.Enqueue e
  -                            outputCount := 0
  -                        else
  -                            if causes.TryRemove(e, &myCauses.contents) then
  -                                !myCauses |> Seq.iter (fun i -> e.InputChanged(x,i))
  -
  -                            // however if the level is consistent we may proceed
  -                            // by marking the object as outOfDate
  -                            e.OutOfDate <- true
  -                            e.AllInputsProcessed(x)
  -                            markCount := !markCount + 1
  -                
  -                            try 
  -                                // here mark and the callbacks are allowed to evaluate
  -                                // the adaptive object but must expect any call to AddOutput to 
  -                                // raise a LevelChangedException whenever a level has been changed
  -                                if e.Mark() then
  -                                    // if everything succeeded we return all current outputs
  -                                    // which will cause them to be enqueued 
  -                                    outputs <- e.Outputs.Consume(outputCount)
  -
  -                                else
  -                                    // if Mark told us not to continue we're done here
  -                                    outputCount := 0
  -
  -                            with LevelChangedException(obj, objLevel, distance) ->
  -                                // if the level was changed either by a callback
  -                                // or Mark we re-enqueue the object with the new level and
  -                                // mark it upToDate again (since it would otherwise not be processed again)
  -                                e.Level <- max e.Level (objLevel + distance)
  -                                e.OutOfDate <- false
  -
  -                                levelChangeCount := !levelChangeCount + 1
  -
  +                            // if the object's level has changed since it
  +                            // was added to the queue we re-enqueue it with the new level
  +                            // Note that this may of course cause runtime overhead and
  +                            // might even change the asymptotic runtime behaviour of the entire
  +                            // system in the worst case but we opted for this approach since
  +                            // it is relatively simple to implement.
  +                            if currentLevel <> e.Level then
                                   q.Enqueue e
                                   outputCount := 0
  +                            else
  +                                if causes.TryRemove(e, &myCauses.contents) then
  +                                    !myCauses |> Seq.iter (fun i -> e.InputChanged(x,i))
  +
  +                                // however if the level is consistent we may proceed
  +                                // by marking the object as outOfDate
  +                                e.OutOfDate <- true
  +                                e.AllInputsProcessed(x)
  +                                markCount := !markCount + 1
                   
  -                finally 
  -                    if enterWorked then
  -                        e.Lock.ExitWrite(e)
  -                    //Monitor.Exit e
  -
  -                // finally we enqueue all returned outputs
  -                for i in 0..!outputCount - 1 do
  -                    let o = outputs.[i]
  -                    o.InputChanged(x,e)
  -                    x.Enqueue o
  +                                try 
  +                                    // here mark and the callbacks are allowed to evaluate
  +                                    // the adaptive object but must expect any call to AddOutput to 
  +                                    // raise a LevelChangedException whenever a level has been changed
  +                                    if e.Mark() then
  +                                        // if everything succeeded we return all current outputs
  +                                        // which will cause them to be enqueued 
  +                                        outputs <- e.Outputs.Consume(outputCount)
  +
  +                                    else
  +                                        // if Mark told us not to continue we're done here
  +                                        outputCount := 0
  +
  +                                with LevelChangedException(obj, objLevel, distance) ->
  +                                    // if the level was changed either by a callback
  +                                    // or Mark we re-enqueue the object with the new level and
  +                                    // mark it upToDate again (since it would otherwise not be processed again)
  +                                    e.Level <- max e.Level (objLevel + distance)
  +                                    e.OutOfDate <- false
  +
  +                                    levelChangeCount := !levelChangeCount + 1
  +
  +                                    q.Enqueue e
  +                                    outputCount := 0
  +                
  +                    finally 
  +                        if enterWorked then
  +                            e.Lock.ExitWrite(e)
  +                        //Monitor.Exit e
  +
  +                    // finally we enqueue all returned outputs
  +                    for i in 0..!outputCount - 1 do
  +                        let o = outputs.[i]
  +                        o.InputChanged(x,e)
  +                        x.Enqueue o
   
                   contained.Remove e |> ignore
                   current <- null
  
positive.code:         enter 0
          true
  
      member x.ExitWrite(o : obj) = 
          Monitor.Exit o
  
  /// <summary>
  
negative.code:                 else []
  
              let mutable res = Unchecked.defaultof<_>
              this.Lock.EnterRead this
              let mutable good = false // evaluate works without exception?
  
              depth := !depth + 1
  