singrdk/base/Imported/Bartok/runtime/shared/GCs/AbortingCoCoBarrier.cs

499 lines
17 KiB
C#

//
// 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; } }
}
}