// // Copyright (c) Microsoft Corporation. All rights reserved. // /*******************************************************************/ /* WARNING */ /* This file should be identical in the Bartok and Singularity */ /* depots. Master copy resides in Bartok Depot. Changes should be */ /* made to Bartok Depot and propagated to Singularity Depot. */ /*******************************************************************/ namespace System.GCs { using Microsoft.Bartok.Runtime; using Microsoft.Bartok.Options; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; internal unsafe class AbortingCoCoBarrier: CoCoBarrier { [MixinConditional("AbortingCoCo")] [Mixin(typeof(PreHeader))] internal struct CoCoPreHeader { internal MultiUseWord muw; [SelfPoint] [NoBarriers] internal UIntPtr CoCoWord; } [MixinConditional("AbortingCoCo")] [Mixin(typeof(Object))] internal class CoCoObject: System.Object { internal new CoCoPreHeader preHeader; } internal static CoCoObject MixinObject(Object o) { return (CoCoObject)o; } internal static Thread mainThread; internal override void InitLateStub() { CoCoWordOffset = (UIntPtr)Magic.toPointer(ref MixinObject(interlock).preHeader.CoCoWord) - Magic.addressOf(interlock); mainThread = Thread.CurrentThread; } internal AbortingCoCoBarrier() { } internal static new AbortingCoCoBarrier instance; [NoBarriers] internal static new void Initialize() { CoCoBarrier.instance = AbortingCoCoBarrier.instance = (AbortingCoCoBarrier) BootstrapMemory.Allocate(typeof(AbortingCoCoBarrier)); } /////////////////////////// forwarding word states // the CoCoWord contains the forwarding pointer, plus one bit: // // Copying: // This is the lowest-order bit. If it is zero, then the object is // not currently being copied. This is the default state. If it // is one, it means that copying activity is on-going with this // object as the source. To write to the object, the copying bit // must first be cleared by the mutator. // // If the object gets forwarded (i.e. the forwarding pointer is not // a self-pointer), the copying bit gets locked in with // a value of 0 (indicating not-copying). Note // that it is illegal to set the copying bit to 1 // if the forwarding pointer is not a self-pointer. [ForceInline] internal static UIntPtr ForwardPtr(UIntPtr CoCoWord) { return CoCoWord&~(UIntPtr)3; } [ForceInline] internal static bool IsCopying(UIntPtr CoCoWord) { return (CoCoWord&(UIntPtr)1) != 0; } [ForceInline] [NoBarriers] internal static bool IsForwarded(UIntPtr CoCoWord, Object o) { return ForwardPtr(CoCoWord) != Magic.addressOf(o); } [ForceInline] internal static UIntPtr WithForwardPtr(UIntPtr CoCoWord, UIntPtr forward) { return (CoCoWord&(UIntPtr)1)|forward; } [ForceInline] internal static UIntPtr WithForward(UIntPtr forward) { return forward; } [ForceInline] [NoBarriers] internal static UIntPtr WithNoForward(Object o, bool copying) { return WithCopying(Magic.addressOf(o),copying); } [ForceInline] internal static UIntPtr WithNoForwardCopying(Object o) { return WithNoForward(o,true); } [ForceInline] internal static UIntPtr WithNoForwardNotCopying(Object o) { return WithNoForward(o,false); } [ForceInline] internal static UIntPtr WithCopying(UIntPtr CoCoWord, bool copying) { if (copying) { return CoCoWord|(UIntPtr)1; } else { return CoCoWord&~(UIntPtr)1; } } /////////////////////////// overriding CoCo and Barrier functionality [NoBarriers] internal override bool ObjectIsNotCopied(Object o) { // BUGBUG: get rid of this method. it is meaninless. return true; } [NoBarriers] [Inline] internal override bool IsInToSpace(UIntPtr ptr) { Object o = Magic.fromAddress(ptr); return !IsForwarded(MixinObject(o).preHeader.CoCoWord,o); } [NoBarriers] [Inline] internal override UIntPtr ToSpaceImplBeforeReadyNonNull(Object o) { return ForwardPtr(MixinObject(o).preHeader.CoCoWord); } [ForceInline] [NoBarriers] protected override void InitObjectImpl(Object o,VTable vtable) { MyInitObject(o, vtable); } [ForceInline] [NoBarriers] internal static new void BootstrapInitObjectImpl(Object o, VTable vtable) { MyInitObject(o, vtable); } [ForceInline] [NoBarriers] private static void MyInitObject(Object o, VTable vtable) { MixinObject(o).preHeader.CoCoWord = WithNoForwardNotCopying(o); o.vtable = vtable; } [Inline] internal override UIntPtr DoPin(UIntPtr address, Pinner pinner) { UIntPtr baseAddr=FindObjectForInteriorPtr(address); Object o=Magic.fromAddress(baseAddr); UIntPtr offset=address-baseAddr; o=Pin(o,pinner); return Magic.addressOf(o)+offset; } [NoBarriers] [Inline] internal override UIntPtr ToSpaceImplNonNull(Object o) { return ForwardPtr(MixinObject(o).preHeader.CoCoWord); } [ForceInline] [NoBarriers] protected override Object ForwardImpl(Object o,int mask) { if ((mask & BarrierMask.Forward.Nullable)!=0 && o == null) { return null; } else { UIntPtr CoCoWord = MixinObject(o).preHeader.CoCoWord; if ((mask & BarrierMask.Forward.Writable)!=0 && IsCopying(CoCoWord)) { return ForwardWritableSlow(o); } else { return Magic.fromAddress(ForwardPtr(CoCoWord)); } } } [NoInline] [CalledRarely] internal static Object ForwardWritableSlow(Object o) { return Pin(o,Pinner.Barrier); } [NoBarriers] internal static bool EqImpl(Object a,Object b) { return a == b || (ToSpaceBeforeReadyImpl(a) == ToSpaceBeforeReadyImpl(b)); } [NoBarriers] [Inline] protected override bool EqImpl(Object a,Object b, int mask) { return EqImpl(a,b); } [NoBarriers] internal static Object Pin(Object o, Pinner pinner) { if (fAbortVerboseDebug) { VTable.DebugPrint("Aborter: requested pinning on "); VTable.DebugPrint((ulong)Magic.addressOf(o)); VTable.DebugPrint(" in thread "); VTable.DebugPrint((ulong)Magic.addressOf(Thread.CurrentThread)); VTable.DebugPrint(" with pinner = "); VTable.DebugPrint((int)pinner); VTable.DebugPrint("\n"); } UIntPtr oldCoCoWord= CAS(ref MixinObject(o).preHeader.CoCoWord, WithNoForwardNotCopying(o), WithNoForwardCopying(o)); if (!IsForwarded(oldCoCoWord,o)) { // the object is not forwarded - nothing further to do. // (we know that it must now be aborted, since if it // was, then that couldn't have changed; and if it wasn't, // then our CAS would have succeeded.) if (fAbortVerboseDebug && IsCopying(oldCoCoWord)) { VTable.DebugPrint("Aborter: aborted copying on "); VTable.DebugPrint((ulong)Magic.addressOf(o)); VTable.DebugPrint(" in thread "); VTable.DebugPrint((ulong)Magic.addressOf(Thread.CurrentThread)); VTable.DebugPrint("\n"); } if (fBreakOnAbort && Thread.CurrentThread!=mainThread && pinner == Pinner.Barrier) { VTable.DebugBreak(); } return o; } else { VTable.Assert(pinner == Pinner.Barrier, "Encountered a forwarded object in a pin "+ "request that did not originate from the "+ "barrier"); if (fAbortVerboseDebug) { VTable.DebugPrint("Aborter: encountered forwarded object "+ "at "); VTable.DebugPrint((ulong)Magic.addressOf(o)); VTable.DebugPrint(" in thread "); VTable.DebugPrint((ulong)Magic.addressOf(Thread.CurrentThread)); VTable.DebugPrint("\n"); } return Magic.fromAddress(ForwardPtr(oldCoCoWord)); } } [AssertDevirtualize] [ForceInline] [NoBarriers] protected override Object AtomicSwapImpl(ref Object reference, Object value, int mask) { TargetWithForwardAndSourceNoForwardBarrier(ref reference,value); return Interlocked.Exchange(ref reference,value); } [AssertDevirtualize] [ForceInline] [NoBarriers] protected override Object AtomicCompareAndSwapImpl(ref Object reference, Object newValue, Object comparand, int mask) { TargetWithForwardAndSourceNoForwardBarrier(ref reference,newValue); for (;;) { Object oldValue = reference; Object myNewValue; if (EqImpl(oldValue, comparand)) { myNewValue = newValue; } else { myNewValue = oldValue; } if (Interlocked.CompareExchange(ref reference, myNewValue, oldValue) == oldValue) { return oldValue; } } } [ForceInline] [NoBarriers] protected override void WriteImpl(UIntPtr *location, Object value, int mask) { UIntPtr valueBits=Magic.addressOf(value); TargetWithForwardAndSourceNoForwardBarrier(location,valueBits); *location=valueBits; } [ForceInline] [NoBarriers] protected override void WriteImplByRef(ref Object location, Object value, int mask) { TargetWithForwardAndSourceNoForwardBarrier(ref location,value); location=value; } class TagNode { internal Object from; internal Object to; internal TagNode next; } static TagNode tagHead; static ulong nTagged; internal override bool AnyTaggedForCopying { get { return tagHead!=null; } } internal override bool TagObjectForCopy(Object from, Object to, out UIntPtr spaceOverhead) { TagNode tn=new TagNode(); spaceOverhead=ObjectLayout.Sizeof(tn); tn.next=tagHead; tn.from=from; tn.to=to; tagHead=tn; nTagged++; return true; } [NoBarriers] internal override void PinningEnabledHook() { if (fAbortDebug) { VTable.DebugPrint("Aborter: un-aborting "); VTable.DebugPrint(nTagged); VTable.DebugPrint(" objects.\n"); } for (TagNode n=tagHead; n!=null; n=n.next) { if (fAbortVerboseDebug) { VTable.DebugPrint("Aborter: un-aborting "); VTable.DebugPrint((ulong)Magic.addressOf(n.from)); VTable.DebugPrint("\n"); } UIntPtr oldCoCoWord= CAS(ref MixinObject(n.from).preHeader.CoCoWord, WithNoForwardCopying(n.from), WithNoForwardNotCopying(n.from)); VTable.Assert(!IsCopying(oldCoCoWord)); VTable.Assert(!IsForwarded(oldCoCoWord,n.from)); } if (fAbortDebug) { VTable.DebugPrint("Aborter: un-aborted "); VTable.DebugPrint(nTagged); VTable.DebugPrint(" objects.\n"); } } internal override bool NeedsPrepPhase { get { return false; } } internal override bool PinOffsetPointers { [Inline] get { return true; } } [NoBarriers] internal override ulong Copy() { ulong cnt=0; TagNode myTagHead=tagHead; ulong myNTagged=nTagged; tagHead=null; nTagged=0; if (fAbortDebug) { VTable.DebugPrint("Aborter: copying "); VTable.DebugPrint(myNTagged); VTable.DebugPrint(" objects.\n"); } // first do all of the copying for (TagNode n=myTagHead; n!=null; n=n.next) { Util.MemCopy(Magic.addressOf(n.to)-PreHeader.Size, Magic.addressOf(n.from)-PreHeader.Size, ObjectLayout.Sizeof(n.from)); // fix the forwarding word in the to-space object (without // this it'll point at from-space) MixinObject(n.to).preHeader.CoCoWord=WithNoForwardNotCopying(n.to); } if (fAbortDebug) { VTable.DebugPrint("Aborter: copied "); VTable.DebugPrint(myNTagged); VTable.DebugPrint(" objects.\n"); } // now attempt to forward all objects. for (TagNode n=myTagHead; n!=null; n=n.next) { UIntPtr oldCoCoWord= CAS(ref MixinObject(n.from).preHeader.CoCoWord, WithForward(Magic.addressOf(n.to)), WithNoForwardCopying(n.from)); VTable.Assert(!IsForwarded(MixinObject(n.to).preHeader.CoCoWord, n.to)); if (oldCoCoWord == WithNoForwardCopying(n.from)) { // copy successful cnt++; } } if (fAbortDebug) { VTable.DebugPrint("Aborter: forwarded "); VTable.DebugPrint(cnt); VTable.DebugPrint(" objects.\n"); } return cnt; } private static bool fAbortDebug { get { return false; } } private static bool fAbortVerboseDebug { get { return false; } } private static bool fBreakOnAbort { get { return false; } } } }