// // 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 abstract class LowAbortCoCoBarrier: CoCoBarrier { // note that this the mixinConditional // for CoCo [MixinConditional("LowAbortCoCo")] [Mixin(typeof(PreHeader))] internal struct CoCoPreHeader { internal MultiUseWord muw; internal UIntPtr CoCoWord; } [MixinConditional("LowAbortCoCo")] [Mixin(typeof(Object))] internal class CoCoObject: System.Object { internal new CoCoPreHeader preHeader; } internal static CoCoObject MixinObject(Object o) { return (CoCoObject)o; } [NoBarriers] internal static new void Initialize() { CoCoBarrier.Initialize(); } internal override void InitLateStub() { CoCoWordOffset = (UIntPtr)Magic.toPointer(ref MixinObject(interlock).preHeader.CoCoWord) - Magic.addressOf(interlock); } // shifts 1 left by size bytes. if size is 4, returns 0. [Inline] internal static int Shlb1(UIntPtr size) { int halfAmount=(int)(uint)size*4; return 1<>(int)(uint)(lowOffset*8))&(ulong)UIntPtr.MaxValue); } // These methods are for reading. When we read, we want to // reassemble words into a ulong. The words and the ulong may not // be aligned. Thus, for each word, we want to be able to // mask off the part of the word that belongs to the ulong, and then // shift it into position. It turns out that there are only // two cases (covered ShiftMask and UnShiftMask). It is never // necessary to take an arbitrary part of a word and shift it to // an arbitrary part of the resulting ulong. // Mask off the first size bytes of the word and then shift it up // to lowOffset. [Inline] internal static ulong ShiftMask(UIntPtr value, UIntPtr lowOffset, UIntPtr size) { return ((ulong)(value&(UIntPtr)(uint)(Shlb1(size)-1)))<<(int)(uint)(lowOffset*8); } // take size bytes above lowOffset and shift them all the way // down. [Inline] internal static ulong UnShiftMask(UIntPtr value, UIntPtr lowOffset, UIntPtr size) { return (ulong)((value>>(int)(uint)(lowOffset*8))&(UIntPtr)(uint)(Shlb1(size)-1)); } [NoBarriers] [TrustedNonNull] internal static LowAbortCoCoBarrier laInstance; internal void InitEarly() { instance = laInstance = this; } internal LowAbortCoCoBarrier() { } [NoBarriers] internal override bool ObjectIsNotCopied(Object o) { return MixinObject(o).preHeader.CoCoWord==0; } [NoInline] [CalledRarely] internal static UIntPtr PinSlow(UIntPtr address) { return laInstance.DoPin(address, Pinner.Barrier); } [Inline] protected override UIntPtr PinImpl(UIntPtr address, int mask) { if (AllowPinFastPath(mask)) { return address; } else { return PinSlow(address); } } internal static bool EqImpl(UIntPtr a, UIntPtr b, bool isObject) { return a == b || (isObject && forwarding && ToSpaceBeforeReadyImpl(Magic.fromAddress(a)) == ToSpaceBeforeReadyImpl(Magic.fromAddress(b))); } [NoBarriers] [NoInline] [CalledRarely] internal static bool EqImplSlow(Object a, Object b) { return ToSpaceBeforeReadyImpl(a) == ToSpaceBeforeReadyImpl(b); } [NoBarriers] [Inline] protected override bool EqImpl(Object a, Object b, int mask) { // why this works: either a==b or not. if not, then // this trivially works. if a==b, then either the object // that a and b refer to is forwarded, is going to be // forwarded while this runs, or it isn't forwarded. if // it isn't, a, b, ToSpace(a) and ToSpace(b) will all // trivially give the same address. if it is forwarded // right now, then forcing forwarding on both pointers // guarantees correctness. if it will be forwarded as // this runs, ToSpace(a) == ToSpace(b) may fail (one may // observe forwarding while the other doesn't), but // a == b will be correct. if ((mask & BarrierMask.PathSpec.UseMask)!=0) { if (StrictlyAllowFastPath(mask)) { return a==b; } else { return a == b || EqImplSlow(a, b); } } else { return a == b || (forwarding && EqImplSlow(a, b)); } } [AssertDevirtualize] protected abstract UIntPtr ReadWordSlow(Object o, UIntPtr offset); [NoInline] [CalledRarely] internal static UIntPtr ReadWordSlow(Object o, void *ptr) { UIntPtr offset = (UIntPtr)ptr-Magic.addressOf(o); if (fVerbose && DebugThread) { VTable.DebugPrint("o = "); VTable.DebugPrint((ulong)Magic.addressOf(o)); VTable.DebugPrint(", ptr = "); VTable.DebugPrint((ulong)ptr); VTable.DebugPrint(", offset = "); VTable.DebugPrint((ulong)offset); VTable.DebugPrint("\n"); } return laInstance.ReadWordSlow(o, offset); } [NoInline] [CalledRarely] internal static Object ReadObjImplSlow(Object o, UIntPtr *ptr) { return ToSpaceAsObj(ReadWordSlow(o, ptr)); } [Inline] protected override Object ReadObjImpl(Object o, UIntPtr *ptr, int mask) { if (AllowFastPath(mask)) { return Magic.fromAddress(*ptr); } else { return ReadObjImplSlow(o, ptr); } } [Inline] internal static ulong LoadSlow(Object o, UIntPtr offset, UIntPtr size) { UIntPtr maxLowOff=(UIntPtr)sizeof(UIntPtr); UIntPtr lowMask=maxLowOff-1; UIntPtr lowOff=offset&lowMask; offset&=~lowMask; if (lowOff+size>maxLowOff*2) { return UnShiftMask(laInstance.ReadWordSlow(o, offset), lowOff, maxLowOff-lowOff) | ShiftMask(laInstance.ReadWordSlow(o, offset+maxLowOff), maxLowOff-lowOff, UIntPtr.MaxValue) | ShiftMask(laInstance.ReadWordSlow(o, offset+maxLowOff*2), maxLowOff*2-lowOff, lowOff+size-maxLowOff); } else if (lowOff+size>maxLowOff) { return UnShiftMask(laInstance.ReadWordSlow(o, offset), lowOff, maxLowOff-lowOff) | ShiftMask(laInstance.ReadWordSlow(o, offset+maxLowOff), maxLowOff-lowOff, lowOff+size-maxLowOff); } else { return UnShiftMask(laInstance.ReadWordSlow(o, offset), lowOff, size); } } [NoInline] [CalledRarely] internal static ulong LoadSlow(Object o, UIntPtr offset, int size) { return LoadSlow(o, offset, (UIntPtr)size); } [NoInline] [CalledRarely] internal static ulong LoadSlow(Object o, void *ptr, int size) { return LoadSlow(o, (UIntPtr)ptr-Magic.addressOf(o), (UIntPtr)size); } [NoInline] [CalledRarely] internal static float ReadSlow(Object o, float *ptr) { return IntToFloatBits((uint)LoadSlow(o, ptr, 4)); } [Inline] protected override float ReadImpl(Object o, float *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(o, ptr); } } [NoInline] [CalledRarely] internal static double ReadSlow(Object o, double *ptr) { return LongToDoubleBits(LoadSlow(o, ptr, 8)); } [Inline] protected override double ReadImpl(Object o, double *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(o, ptr); } } [NoInline] [CalledRarely] internal static byte ReadSlow(Object o, byte *ptr) { return (byte)LoadSlow(o, ptr, 1); } [Inline] protected override byte ReadImpl(Object o, byte *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(o, ptr); } } [NoInline] [CalledRarely] internal static ushort ReadSlow(Object o, ushort *ptr) { return (ushort)LoadSlow(o, ptr, 2); } [Inline] protected override ushort ReadImpl(Object o, ushort *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(o, ptr); } } [NoInline] [CalledRarely] internal static uint ReadSlow(Object o, uint *ptr) { return (uint)LoadSlow(o, ptr, 4); } [Inline] protected override uint ReadImpl(Object o, uint *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(o, ptr); } } [NoInline] [CalledRarely] internal static ulong ReadSlow(Object o, ulong *ptr) { return (ulong)LoadSlow(o, ptr, 8); } [Inline] protected override ulong ReadImpl(Object o, ulong *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(o, ptr); } } [NoInline] [CalledRarely] internal static UIntPtr ReadSlow(Object o, UIntPtr *ptr) { return (UIntPtr)LoadSlow(o, ptr, sizeof(UIntPtr)); } [Inline] protected override UIntPtr ReadImpl(Object o, UIntPtr *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(o, ptr); } } [NoInline] [CalledRarely] internal static ulong LoadSlow(void *ptr, int size) { UIntPtr baseAddr = FindObjectForPreInteriorPtr((UIntPtr)ptr); if (baseAddr == UIntPtr.Zero) { switch (size) { case 1: return (ulong)*(byte*)ptr; case 2: return (ulong)*(ushort*)ptr; case 4: return (ulong)*(uint*)ptr; case 8: return *(ulong*)ptr; default: VTable.NotReached(); return 0; } } else { return LoadSlow(Magic.fromAddress(baseAddr), ptr, size); } } [NoInline] [CalledRarely] internal static Object ReadObjSlow(UIntPtr *ptr) { return ToSpaceAsObj((UIntPtr)LoadSlow(ptr, sizeof(UIntPtr))); } [Inline] protected override Object ReadObjImpl(UIntPtr *ptr, int mask) { if (AllowFastPath(mask)) { return Magic.fromAddress(*ptr); } else { return ReadObjSlow(ptr); } } [NoInline] [CalledRarely] internal static float ReadSlow(float *ptr) { return IntToFloatBits((uint)LoadSlow(ptr, 4)); } [Inline] protected override float ReadImpl(float *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(ptr); } } [NoInline] [CalledRarely] internal static double ReadSlow(double *ptr) { return LongToDoubleBits((ulong)LoadSlow(ptr, 8)); } [Inline] protected override double ReadImpl(double *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(ptr); } } [NoInline] [CalledRarely] internal static byte ReadSlow(byte *ptr) { return (byte)LoadSlow(ptr, 1); } [Inline] protected override byte ReadImpl(byte *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(ptr); } } [NoInline] [CalledRarely] internal static ushort ReadSlow(ushort *ptr) { return (ushort)LoadSlow(ptr, 2); } [Inline] protected override ushort ReadImpl(ushort *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(ptr); } } [NoInline] [CalledRarely] internal static uint ReadSlow(uint *ptr) { return (uint)LoadSlow(ptr, 4); } [Inline] protected override uint ReadImpl(uint *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(ptr); } } [NoInline] [CalledRarely] internal static ulong ReadSlow(ulong *ptr) { return (ulong)LoadSlow(ptr, 8); } [Inline] protected override ulong ReadImpl(ulong *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(ptr); } } [NoInline] [CalledRarely] internal static UIntPtr ReadSlow(UIntPtr *ptr) { return (UIntPtr)LoadSlow(ptr, sizeof(UIntPtr)); } [Inline] protected override UIntPtr ReadImpl(UIntPtr *ptr, int mask) { if (AllowIdleFastPath(mask)) { return *ptr; } else { return ReadSlow(ptr); } } [Inline] protected override Object ReadImplByRef(ref Object loc, int mask) { return ReadObjImpl(Magic.toPointer(ref loc), mask); } [Inline] protected override float ReadImplByRef(ref float loc, int mask) { return ReadImpl((float*)Magic.toPointer(ref loc), mask); } [Inline] protected override double ReadImplByRef(ref double loc, int mask) { return ReadImpl((double*)Magic.toPointer(ref loc), mask); } [Inline] protected override byte ReadImplByRef(ref byte loc, int mask) { return ReadImpl((byte*)Magic.toPointer(ref loc), mask); } [Inline] protected override ushort ReadImplByRef(ref ushort loc, int mask) { return ReadImpl((ushort*)Magic.toPointer(ref loc), mask); } [Inline] protected override uint ReadImplByRef(ref uint loc, int mask) { return ReadImpl((uint*)Magic.toPointer(ref loc), mask); } [Inline] protected override ulong ReadImplByRef(ref ulong loc, int mask) { return ReadImpl((ulong*)Magic.toPointer(ref loc), mask); } [Inline] protected override UIntPtr ReadImplByRef(ref UIntPtr loc, int mask) { return ReadImpl((UIntPtr*)Magic.toPointer(ref loc), mask); } // this method is expected to invoke the target barrier [AssertDevirtualize] protected abstract void WriteWordSlow(Object o, UIntPtr offset, UIntPtr mask, UIntPtr shiftedValue, bool isObject); [NoInline] [CalledRarely] internal static void WriteWordSlow(Object o, UIntPtr offset, UIntPtr mask, UIntPtr shiftedValue) { laInstance.WriteWordSlow(o, offset, mask, shiftedValue, false); } [NoInline] [CalledRarely] internal static void WriteWordSlowObj(Object o, UIntPtr *ptr, UIntPtr value) { laInstance.WriteWordSlow(o, (UIntPtr)ptr-Magic.addressOf(o), UIntPtr.MaxValue, value, true); } [NoInline] [CalledRarely] internal static void WriteWordSlowObj(Object o, UIntPtr *ptr, Object value) { UIntPtr valueBits=Magic.addressOf(value); SourceBarrierWithForward(valueBits); WriteWordSlowObj(o, ptr, valueBits); } [ForceInline] protected override void WriteImpl(Object o, UIntPtr *ptr, Object value, int mask) { if (AllowFastPath(mask)) { UIntPtr valueBits=Magic.addressOf(value); TargetAndSourceBarrierNoForward(ptr, valueBits); *ptr = valueBits; } else { WriteWordSlowObj(o, ptr, value); } } [NoInline] [CalledRarely] internal static void StoreSlow(Object o, void *ptr, UIntPtr size, ulong value) { UIntPtr offset=(UIntPtr)ptr-Magic.addressOf(o); if (fVerbose && DebugThread) { VTable.DebugPrint("Doing a StoreSlow on "); VTable.DebugPrint((ulong)Magic.addressOf(o)); VTable.DebugPrint(" + "); VTable.DebugPrint((ulong)offset); VTable.DebugPrint(" the value "); VTable.DebugPrint(value); VTable.DebugPrint(" of size "); VTable.DebugPrint((ulong)size); VTable.DebugPrint("\n"); } UIntPtr maxLowOff=(UIntPtr)sizeof(UIntPtr); UIntPtr lowMask=maxLowOff-1; UIntPtr lowOff=offset&lowMask; offset&=~lowMask; if (lowOff+size>maxLowOff*2) { WriteWordSlow(o, offset, MakeMask(lowOff, maxLowOff-lowOff), Shift(value, lowOff)); WriteWordSlow(o, offset+maxLowOff, UIntPtr.MaxValue, UnShift(value, maxLowOff-lowOff)); WriteWordSlow(o, offset+maxLowOff*2, MakeMask(0, lowOff+size-maxLowOff), UnShift(value, maxLowOff*2-lowOff)); } else if (lowOff+size>maxLowOff) { WriteWordSlow(o, offset, MakeMask(lowOff, maxLowOff-lowOff), Shift(value, lowOff)); WriteWordSlow(o, offset+maxLowOff, MakeMask(0, lowOff+size-maxLowOff), UnShift(value, maxLowOff-lowOff)); } else { WriteWordSlow(o, offset, MakeMask(lowOff, size), Shift(value, lowOff)); } } [NoInline] [CalledRarely] internal static void StoreSlow(Object o, void *ptr, int size, ulong value) { StoreSlow(o, ptr, (UIntPtr)size, value); } [NoInline] [CalledRarely] internal static void WriteSlow(Object o, float *ptr, float value) { StoreSlow(o, ptr, 4, FloatToIntBits(value)); } [Inline] protected override void WriteImpl(Object o, float *ptr, float value, int mask) { if (AllowIdleFastPath(mask)) { *ptr = value; } else { WriteSlow(o, ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(Object o, double *ptr, double value) { StoreSlow(o, ptr, 8, DoubleToLongBits(value)); } [Inline] protected override void WriteImpl(Object o, double *ptr, double value, int mask) { if (AllowIdleFastPath(mask)) { *ptr = value; } else { WriteSlow(o, ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(Object o, byte *ptr, byte value) { StoreSlow(o, ptr, 1, value); } [Inline] protected override void WriteImpl(Object o, byte *ptr, byte value, int mask) { if (AllowIdleFastPath(mask)) { *ptr = value; } else { WriteSlow(o, ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(Object o, ushort *ptr, ushort value) { StoreSlow(o, ptr, 2, value); } [Inline] protected override void WriteImpl(Object o, ushort *ptr, ushort value, int mask) { if (AllowIdleFastPath(mask)) { *ptr = value; } else { WriteSlow(o, ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(Object o, uint *ptr, uint value) { StoreSlow(o, ptr, 4, value); } [Inline] protected override void WriteImpl(Object o, uint *ptr, uint value, int mask) { if (AllowIdleFastPath(mask)) { *ptr = value; } else { WriteSlow(o, ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(Object o, ulong *ptr, ulong value) { StoreSlow(o, ptr, 8, value); } [Inline] protected override void WriteImpl(Object o, ulong *ptr, ulong value, int mask) { if (AllowIdleFastPath(mask)) { *ptr = value; } else { WriteSlow(o, ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(Object o, UIntPtr *ptr, UIntPtr value) { StoreSlow(o, ptr, sizeof(UIntPtr), (ulong)value); } [Inline] protected override void WriteImpl(Object o, UIntPtr *ptr, UIntPtr value, int mask) { if (AllowIdleFastPath(mask)) { *ptr = value; } else { WriteSlow(o, ptr, value); } } [NoInline] [CalledRarely] internal static void WriteWordSlowObj(UIntPtr *ptr, Object value) { UIntPtr valueBits=Magic.addressOf(value); SourceBarrierWithForward(valueBits); UIntPtr baseAddr = FindObjectForPreInteriorPtr((UIntPtr)ptr); if (baseAddr == UIntPtr.Zero) { TargetBarrierWithForward(*ptr); *ptr=valueBits; } else { WriteWordSlowObj(Magic.fromAddress(baseAddr), ptr, valueBits); } } [ForceInline] protected override void WriteImpl(UIntPtr *ptr, Object value, int mask) { if (AllowFastPath(mask)) { UIntPtr valueBits=Magic.addressOf(value); TargetAndSourceBarrierNoForward(ptr, valueBits); *ptr=valueBits; } else { WriteWordSlowObj(ptr, value); } } internal static void StoreSlow(void *ptr, int size, ulong value) { UIntPtr baseAddr = FindObjectForPreInteriorPtr((UIntPtr)ptr); if (baseAddr == UIntPtr.Zero) { switch (size) { case 1: *(byte*)ptr=(byte)value; break; case 2: *(ushort*)ptr=(ushort)value; break; case 4: *(uint*)ptr=(uint)value; break; case 8: *(ulong*)ptr=value; break; default: VTable.NotReached(); break; } } else { StoreSlow(Magic.fromAddress(baseAddr), ptr, size, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(float *ptr, float value) { StoreSlow(ptr, 4, FloatToIntBits(value)); } [Inline] protected override void WriteImpl(float *ptr, float value, int mask) { if (AllowIdleFastPath(mask)) { *ptr=value; } else { WriteSlow(ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(double *ptr, double value) { StoreSlow(ptr, 8, DoubleToLongBits(value)); } [Inline] protected override void WriteImpl(double *ptr, double value, int mask) { if (AllowIdleFastPath(mask)) { *ptr=value; } else { WriteSlow(ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(byte *ptr, byte value) { StoreSlow(ptr, 1, value); } [Inline] protected override void WriteImpl(byte *ptr, byte value, int mask) { if (AllowIdleFastPath(mask)) { *ptr=value; } else { WriteSlow(ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(ushort *ptr, ushort value) { StoreSlow(ptr, 2, value); } [Inline] protected override void WriteImpl(ushort *ptr, ushort value, int mask) { if (AllowIdleFastPath(mask)) { *ptr=value; } else { WriteSlow(ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(uint *ptr, uint value) { StoreSlow(ptr, 4, value); } [Inline] protected override void WriteImpl(uint *ptr, uint value, int mask) { if (AllowIdleFastPath(mask)) { *ptr=value; } else { WriteSlow(ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(ulong *ptr, ulong value) { StoreSlow(ptr, 8, value); } [Inline] protected override void WriteImpl(ulong *ptr, ulong value, int mask) { if (AllowIdleFastPath(mask)) { *ptr=value; } else { WriteSlow(ptr, value); } } [NoInline] [CalledRarely] internal static void WriteSlow(UIntPtr *ptr, UIntPtr value) { StoreSlow(ptr, sizeof(UIntPtr), (ulong)value); } [Inline] protected override void WriteImpl(UIntPtr *ptr, UIntPtr value, int mask) { if (AllowIdleFastPath(mask)) { *ptr=value; } else { WriteSlow(ptr, value); } } [ForceInline] protected override void WriteImplByRef(ref Object loc, Object value, int mask) { WriteImpl(Magic.toPointer(ref loc), value, mask); } [Inline] protected override void WriteImplByRef(ref byte loc, byte value, int mask) { WriteImpl(Magic.toPointer(ref loc), value, mask); } [Inline] protected override void WriteImplByRef(ref ushort loc, ushort value, int mask) { WriteImpl(Magic.toPointer(ref loc), value, mask); } [Inline] protected override void WriteImplByRef(ref uint loc, uint value, int mask) { WriteImpl(Magic.toPointer(ref loc), value, mask); } [Inline] protected override void WriteImplByRef(ref ulong loc, ulong value, int mask) { WriteImpl(Magic.toPointer(ref loc), value, mask); } [Inline] protected override void WriteImplByRef(ref UIntPtr loc, UIntPtr value, int mask) { WriteImpl(Magic.toPointer(ref loc), value, mask); } [Inline] protected override void WriteImplByRef(ref float loc, float value, int mask) { WriteImpl(Magic.toPointer(ref loc), value, mask); } [Inline] protected override void WriteImplByRef(ref double loc, double value, int mask) { WriteImpl(Magic.toPointer(ref loc), value, mask); } // this method is NOT expected to invoke either the source or // target barrier. [AssertDevirtualize] protected abstract bool WeakCASWordSlow(Object o, UIntPtr offset, UIntPtr mask, UIntPtr shiftedValue, UIntPtr shiftedComparand, bool isObject); // returns the shifted result. does not guarantee the correctness // of the result for anything but the bits in the mask. [NoInline] [CalledRarely] static UIntPtr StrongCASWordSlow(Object o, UIntPtr offset, UIntPtr mask, UIntPtr shiftedValue, UIntPtr shiftedComparand, bool isObject) { if (fVerbose && DebugThread) { VTable.DebugPrint("StrongCASWordSlow: o = "); VTable.DebugPrint((ulong)Magic.addressOf(o)); VTable.DebugPrint(", offset = "); VTable.DebugPrint((ulong)offset); VTable.DebugPrint(", mask = "); VTable.DebugPrint((ulong)mask); VTable.DebugPrint(", shiftedValue = "); VTable.DebugPrint((ulong)shiftedValue); VTable.DebugPrint(", shiftedComparand = "); VTable.DebugPrint((ulong)shiftedComparand); VTable.DebugPrint("\n"); } for (;;) { UIntPtr oldVal=laInstance.ReadWordSlow(o, offset); if (fVerbose && DebugThread) { VTable.DebugPrint("StrongCASWordSlow: oldVal = "); VTable.DebugPrint((ulong)oldVal); VTable.DebugPrint("\n"); } if (!EqImpl(oldVal&mask, shiftedComparand&mask, isObject) || laInstance.WeakCASWordSlow(o, offset, mask, shiftedValue, oldVal, isObject)) { return oldVal; } } } [NoInline] [CalledRarely] static UIntPtr StrongXCHGWordSlow(Object o, UIntPtr offset, UIntPtr mask, UIntPtr shiftedValue, bool isObject) { for (;;) { UIntPtr oldVal=laInstance.ReadWordSlow(o, offset); if (laInstance.WeakCASWordSlow(o, offset, mask, shiftedValue, oldVal, isObject)) { return oldVal; } } } [AssertDevirtualize] protected abstract bool WeakCASArbitrarySlow(Object o, UIntPtr offset, UIntPtr size, ulong value, ulong comparand); [NoInline] [CalledRarely] static ulong StrongCASArbitrarySlow(Object o, UIntPtr offset, UIntPtr size, ulong value, ulong comparand) { for (;;) { ulong oldVal=LoadSlow(o, offset, size); if (oldVal!=comparand) { if (laInstance.WeakCASArbitrarySlow(o, offset, size, oldVal, oldVal)) { return oldVal; } } else if (laInstance.WeakCASArbitrarySlow(o, offset, size, value, comparand)) { return oldVal; } } } [NoInline] [CalledRarely] static ulong StrongXCHGArbitrarySlow(Object o, UIntPtr offset, UIntPtr size, ulong value) { for (;;) { ulong oldVal=LoadSlow(o, offset, size); if (laInstance.WeakCASArbitrarySlow(o, offset, size, value, oldVal)) { return oldVal; } } } [NoInline] [CalledRarely] internal static UIntPtr AtomicCompareAndSwapObjSlow(UIntPtr *ptr, UIntPtr newValueBits, UIntPtr comparandBits) { if (fCount) { numAtomics++; } UIntPtr result; UIntPtr addr=(UIntPtr)ptr; UIntPtr baseAddr=baseAddr = FindObjectForPreInteriorPtr(addr); if (baseAddr == UIntPtr.Zero) { TargetBarrierWithForward(*ptr); result= Interlocked.CompareExchange(ptr, newValueBits, comparandBits); } else { Object o=Magic.fromAddress(baseAddr); TargetBarrierWithForward(laInstance.ReadWordSlow(o, addr-baseAddr)); result=StrongCASWordSlow(o, addr-baseAddr, UIntPtr.MaxValue, newValueBits, comparandBits, true /* isObject */); } return result; } [Inline] protected override Object AtomicCompareAndSwapImpl(ref Object reference, Object newValue, Object comparand, int mask) { UIntPtr newValueBits = Magic.addressOf(newValue); UIntPtr comparandBits = Magic.addressOf(comparand); SourceBarrierWithForward(newValueBits); UIntPtr result; UIntPtr *ptr=Magic.toPointer(ref reference); if (AllowFastPath(mask)) { TargetBarrierNoForward(*ptr); result= Interlocked.CompareExchange(ptr, newValueBits, comparandBits); } else { result=AtomicCompareAndSwapObjSlow(ptr, newValueBits, comparandBits); } if (StrictlyAllowFastPath(mask)) { return Magic.fromAddress(result); } else { return ToSpaceAsObj(result); } } [NoInline] [CalledRarely] internal static UIntPtr AtomicSwapObjSlow(UIntPtr *ptr, UIntPtr newValueBits) { if (fCount) { numAtomics++; } UIntPtr result; UIntPtr addr=(UIntPtr)ptr; UIntPtr baseAddr = FindObjectForPreInteriorPtr(addr); if (baseAddr == UIntPtr.Zero) { TargetBarrierWithForward(*ptr); result= Interlocked.Exchange(ptr, newValueBits); } else { Object o=Magic.fromAddress(baseAddr); TargetBarrierWithForward(laInstance.ReadWordSlow(o, addr-baseAddr)); result=StrongXCHGWordSlow(o, addr-baseAddr, UIntPtr.MaxValue, newValueBits, true); } return result; } [Inline] protected override Object AtomicSwapImpl(ref Object reference, Object newValue, int mask) { UIntPtr newValueBits=Magic.addressOf(newValue); SourceBarrierWithForward(newValueBits); UIntPtr result; UIntPtr *ptr=Magic.toPointer(ref reference); if (AllowFastPath(mask)) { TargetBarrierNoForward(*ptr); result= Interlocked.Exchange(ptr, newValueBits); } else { result=AtomicSwapObjSlow(ptr, newValueBits); } if (StrictlyAllowFastPath(mask)) { return Magic.fromAddress(result); } else { return ToSpaceAsObj(result); } } static ulong StrongCASSlow(Object o, UIntPtr offset, UIntPtr size, ulong value, ulong comparand) { if (fVerbose && DebugThread) { VTable.DebugPrint("StrongCASSlow: offset = "); VTable.DebugPrint((ulong)offset); VTable.DebugPrint(", size = "); VTable.DebugPrint((ulong)size); VTable.DebugPrint("\n"); } UIntPtr maxLowOff=(UIntPtr)sizeof(UIntPtr); UIntPtr lowMask=maxLowOff-1; UIntPtr lowOff=offset&lowMask; offset&=~lowMask; if (lowOff+size>maxLowOff) { if (fVerbose && DebugThread) { VTable.DebugPrint("StrongCASSlow: WEIRD! we're using arbitrary-slow CAS.\n"); } return StrongCASArbitrarySlow(o, offset, size, value, comparand); } else { return UnShiftMask(StrongCASWordSlow(o, offset, MakeMask(lowOff, size), Shift(value, lowOff), Shift(comparand, lowOff), false /* not isObject */), lowOff, size); } } static ulong StrongCASSlow(Object o, UIntPtr offset, int size, ulong value, ulong comparand) { return StrongCASSlow(o, offset, (UIntPtr)size, value, comparand); } static ulong StrongXCHGSlow(Object o, UIntPtr offset, UIntPtr size, ulong value) { UIntPtr maxLowOff=(UIntPtr)sizeof(UIntPtr); UIntPtr lowMask=maxLowOff-1; UIntPtr lowOff=offset&lowMask; offset&=~lowMask; if (lowOff+size>maxLowOff) { return StrongXCHGArbitrarySlow(o, offset, size, value); } else { return UnShiftMask(StrongXCHGWordSlow(o, offset, MakeMask(lowOff, size), Shift(value, lowOff), false /* not object */), lowOff, size); } } static ulong StrongXCHGSlow(Object o, UIntPtr offset, int size, ulong value) { return StrongXCHGSlow(o, offset, (UIntPtr)size, value); } [NoInline] [CalledRarely] internal static int AtomicCompareAndSwapSlow(int *ptr, int value, int comparand) { if (fCount) { numAtomics++; } UIntPtr addr=(UIntPtr)ptr; UIntPtr baseAddr = FindObjectForPreInteriorPtr(addr); if (baseAddr == UIntPtr.Zero) { return Interlocked.CompareExchange(ptr, value, comparand); } else { return (int)StrongCASSlow(Magic.fromAddress(baseAddr), addr-baseAddr, 4, (ulong)value, (ulong)comparand); } } [Inline] protected override int AtomicCompareAndSwapImpl(ref int reference, int value, int comparand, int mask) { int *ptr=Magic.toPointer(ref reference); if (AllowIdleFastPath(mask)) { return Interlocked.CompareExchange(ptr, value, comparand); } else { return AtomicCompareAndSwapSlow(ptr, value, comparand); } } [NoInline] [CalledRarely] internal static int AtomicSwapSlow(int *ptr, int value) { if (fCount) { numAtomics++; } UIntPtr addr=(UIntPtr)ptr; UIntPtr baseAddr = FindObjectForPreInteriorPtr(addr); if (baseAddr == UIntPtr.Zero) { return Interlocked.Exchange(ptr, value); } else { return (int)StrongXCHGSlow(Magic.fromAddress(baseAddr), addr-baseAddr, 4, (ulong)value); } } [Inline] protected override int AtomicSwapImpl(ref int reference, int value, int mask) { int *ptr=Magic.toPointer(ref reference); if (AllowIdleFastPath(mask)) { return Interlocked.Exchange(ptr, value); } else { return AtomicSwapSlow(ptr, value); } } [NoInline] [CalledRarely] internal static long AtomicCompareAndSwapSlow(long *ptr, long value, long comparand) { if (fCount) { numAtomics++; } UIntPtr addr=(UIntPtr)ptr; UIntPtr baseAddr = FindObjectForPreInteriorPtr(addr); if (baseAddr == UIntPtr.Zero) { return Interlocked.CompareExchange(ptr, value, comparand); } else { return (long)StrongCASSlow(Magic.fromAddress(baseAddr), addr-baseAddr, 8, (ulong)value, (ulong)comparand); } } [Inline] protected override long AtomicCompareAndSwapImpl(ref long reference, long value, long comparand, int mask) { long *ptr=Magic.toPointer(ref reference); UIntPtr addr=(UIntPtr)ptr; if (AllowIdleFastPath(mask)) { return Interlocked.CompareExchange(ptr, value, comparand); } else { return AtomicCompareAndSwapSlow(ptr, value, comparand); } } [NoInline] [CalledRarely] internal static UIntPtr AtomicCompareAndSwapSlow(UIntPtr *ptr, UIntPtr value, UIntPtr comparand) { if (fCount) { numAtomics++; } UIntPtr addr=(UIntPtr)ptr; UIntPtr baseAddr = FindObjectForPreInteriorPtr(addr); if (baseAddr == UIntPtr.Zero) { return Interlocked.CompareExchange(ptr, value, comparand); } else { return (UIntPtr)StrongCASSlow(Magic.fromAddress(baseAddr), addr-baseAddr, UIntPtr.Size, (ulong)value, (ulong)comparand); } } [Inline] protected override UIntPtr AtomicCompareAndSwapImpl(ref UIntPtr reference, UIntPtr value, UIntPtr comparand, int mask) { UIntPtr *ptr=Magic.toPointer(ref reference); if (AllowIdleFastPath(mask)) { return Interlocked.CompareExchange(ptr, value, comparand); } else { return AtomicCompareAndSwapSlow(ptr, value, comparand); } } [NoInline] [CalledRarely] internal static UIntPtr AtomicSwapSlow(UIntPtr *ptr, UIntPtr value) { if (fCount) { numAtomics++; } UIntPtr addr=(UIntPtr)ptr; UIntPtr baseAddr = FindObjectForPreInteriorPtr(addr); if (baseAddr == UIntPtr.Zero) { return Interlocked.Exchange(ptr, value); } else { return (UIntPtr)StrongXCHGSlow(Magic.fromAddress(baseAddr), addr-baseAddr, UIntPtr.Size, (ulong)value); } } [Inline] protected override UIntPtr AtomicSwapImpl(ref UIntPtr reference, UIntPtr value, int mask) { if (fCount) { numAtomics++; } UIntPtr *ptr=Magic.toPointer(ref reference); if (AllowIdleFastPath(mask)) { return Interlocked.Exchange(ptr, value); } else { return AtomicSwapSlow(ptr, value); } } protected override void CopyStructImpl(Object srcObj, Object dstObj, VTable vtable, UIntPtr srcPtr, UIntPtr dstPtr) { if (allowFastPath) { if (NeedsTargetBarrier) { PreWriteStruct(vtable, dstPtr); } CopyStructNoBarrier(vtable, srcPtr, dstPtr); } else { if (fCount) { numSlowCopyStructs++; } CopyStructWithSlowBarrier(srcObj, dstObj, vtable, srcPtr-Magic.addressOf(srcObj), dstPtr-Magic.addressOf(dstObj)); } } protected override void CloneImpl(Object srcObject, Object dstObject) { if (allowFastPath) { // we're cloning, so nothing of note in the destination /* if (false && NeedsTargetBarrier) { PreWriteObject(dstObject); } */ CloneNoBarrier(srcObject, dstObject); } else { if (fCount) { numSlowClones++; } CloneWithSlowBarrier(srcObject, dstObject); } } protected override void ArrayZeroImpl(Array array, int offset, int length) { if (allowFastPath) { if (NeedsTargetBarrier) { PreWriteArray(array, offset, length); } ArrayZeroNoBarrier(array, offset, length); } else { if (fCount) { numSlowArrayZeroes++; } ArrayZeroWithSlowBarrier(array, offset, length); } } protected override void ArrayCopyImpl(Array srcArray, int srcOffset, Array dstArray, int dstOffset, int length) { if (allowFastPath) { if (NeedsTargetBarrier) { PreWriteArray(dstArray, dstOffset, length); } ArrayCopyNoBarrier(srcArray, srcOffset, dstArray, dstOffset, length); } else { if (fCount) { numSlowArrayCopies++; } ArrayCopyWithSlowBarrier(srcArray, srcOffset, dstArray, dstOffset, length); } } [NoInline] [CalledRarely] static void StoreStaticFieldSlow(ref Object staticField, Object value) { UIntPtr *staticFieldAddr=(UIntPtr*)Magic.toPointer(ref staticField); TargetBarrierWithForward(*staticFieldAddr); UIntPtr valueAddr=Magic.addressOf(value); SourceBarrierWithForward(valueAddr); // NOTE: we don't have to forward value because before the // static data is scanned (and forwarded), we'll already have // instituted the to-space invariant. *staticFieldAddr = valueAddr; } [ForceInline] protected override void StoreStaticFieldImpl(ref Object staticField, Object value, int mask) { if (AllowFastPath(mask)) { UIntPtr *staticFieldAddr=(UIntPtr*)Magic.toPointer(ref staticField); UIntPtr valueAddr=Magic.addressOf(value); TargetAndSourceBarrierNoForward(staticFieldAddr, valueAddr); // NOTE: we don't have to forward value because before the // static data is scanned (and forwarded), we'll already have // instituted the to-space invariant. *staticFieldAddr = valueAddr; } else { StoreStaticFieldSlow(ref staticField, value); } } [NoInline] [CalledRarely] static Object LoadStaticFieldSlow(ref Object staticField) { return ToSpaceAsObj(staticField); } [Inline] [NoBarriers] protected override Object LoadStaticFieldImpl(ref Object staticField, int mask) { if (AllowFastPath(mask)) { return staticField; } else { return LoadStaticFieldSlow(ref staticField); } } internal override void PinningEnabledHook() { } internal override bool PinOffsetPointers { [Inline] get { return false; } } } }