singrdk/base/Kernel/Bartok/GCs/WriteBarrier.cs

581 lines
25 KiB
C#

/*******************************************************************/
/* 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. */
/*******************************************************************/
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
namespace System.GCs
{
using Microsoft.Bartok.Runtime;
using System.Runtime.CompilerServices;
using System.Threading;
[CCtorIsRunDuringStartup]
internal abstract unsafe class WriteBarrier
{
[TrustedNonNull]
private static WriteBarrier installedWriteBarrier;
[TrustedNonNull]
private static CopyFieldsVisitor copyFieldsVisitor;
[TrustedNonNull]
private static ZeroFieldsVisitor zeroFieldsVisitor;
[PreInitRefCounts]
internal static void Initialize()
{
switch (GC.wbType) {
#if !SINGULARITY || MARK_SWEEP_COLLECTOR
case WBType.noWB: {
EmptyWriteBarrier.Initialize();
installedWriteBarrier = EmptyWriteBarrier.instance;
break;
}
#endif
#if !SINGULARITY || SEMISPACE_COLLECTOR || SLIDING_COLLECTOR || ADAPTIVE_COPYING_COLLECTOR
case WBType.Generational: {
GenerationalWriteBarrier.Initialize();
installedWriteBarrier = GenerationalWriteBarrier.instance;
break;
}
#endif
#if !SINGULARITY || CONCURRENT_MS_COLLECTOR
case WBType.CMS: {
WriteBarrierCMS.Initialize();
installedWriteBarrier = WriteBarrierCMS.instance;
break;
}
#endif
#if !SINGULARITY || ATOMIC_RC_COLLECTOR
case WBType.ARC: {
AtomicRCWriteBarrier.Initialize();
installedWriteBarrier = AtomicRCWriteBarrier.instance;
break;
}
#endif
#if !SINGULARITY || SEMISPACE_COLLECTOR || SLIDING_COLLECTOR || ADAPTIVE_COPYING_COLLECTOR
case WBType.AllCards: {
AllCardsWriteBarrier.Initialize();
installedWriteBarrier = AllCardsWriteBarrier.instance;
break;
}
#endif
default: {
VTable.NotReached("Unknown write barrier type: "+GC.wbType);
break;
}
}
// copyFieldsVisitor = new CopyFieldsVisitor();
WriteBarrier.copyFieldsVisitor = (CopyFieldsVisitor)
BootstrapMemory.Allocate(typeof(CopyFieldsVisitor));
// zeroFieldsVisitor = new ZeroFieldsVisitor();
WriteBarrier.zeroFieldsVisitor = (ZeroFieldsVisitor)
BootstrapMemory.Allocate(typeof(ZeroFieldsVisitor));
}
[Inline]
protected virtual void StoreIndirectImpl(UIntPtr *location,
Object value)
{
this.WriteReferenceImpl(location, value);
}
[Inline]
protected virtual void StoreIndirectImpl(ref Object reference,
Object value)
{
this.WriteReferenceImpl(ref reference, value);
}
[Inline]
protected virtual void StoreObjectFieldImpl(Object obj,
UIntPtr fieldOffset,
Object value)
{
UIntPtr *fieldPtr = (UIntPtr *)
(Magic.addressOf(obj) + fieldOffset);
this.WriteReferenceImpl(fieldPtr, value);
}
[Inline]
protected virtual void StoreStructFieldImpl(UIntPtr structPtr,
UIntPtr fieldOffset,
Object value)
{
UIntPtr *fieldPtr = (UIntPtr *) (structPtr + fieldOffset);
this.WriteReferenceImpl(fieldPtr, value);
}
[Inline]
protected virtual void StoreVectorElementImpl(Array vector,
int index,
int arrayElementSize,
UIntPtr fieldOffset,
Object value)
{
UIntPtr *fieldPtr =
IndexedFieldPtr(vector, index, arrayElementSize, fieldOffset);
this.WriteReferenceImpl(fieldPtr, value);
}
[Inline]
protected virtual void StoreArrayElementImpl(Array array,
int index,
int arrayElementSize,
UIntPtr fieldOffset,
Object value)
{
UIntPtr *fieldPtr =
IndexedFieldPtr(array, index, arrayElementSize, fieldOffset);
this.WriteReferenceImpl(fieldPtr, value);
}
[Inline]
protected virtual void StoreStaticFieldImpl(ref Object staticField,
Object value)
{
this.WriteReferenceImpl(ref staticField, value);
}
protected abstract void CopyStructImpl(VTable vtable,
UIntPtr srcPtr,
UIntPtr dstPtr);
protected abstract Object AtomicSwapImpl(ref Object reference,
Object value);
protected abstract Object AtomicCompareAndSwapImpl(ref Object reference,
Object newValue,
Object comparand);
protected abstract void CloneImpl(Object srcObject, Object dstObject);
protected void WriteReferenceImpl(ref Object reference, Object value)
{
this.WriteReferenceImpl(Magic.toPointer(ref reference), value);
}
protected abstract void WriteReferenceImpl(UIntPtr *location,
Object value);
// 'offset' is not relative to the lower bound, but is a count
// of elements from the first element in the array.
protected abstract void ArrayZeroImpl(Array array,
int offset,
int length);
// 'offset' is not relative to the lower bound, but is a count
// of elements from the first element in the array.
protected abstract void ArrayCopyImpl(Array srcArray, int srcOffset,
Array dstArray, int dstOffset,
int length);
[Inline]
protected static UIntPtr IndexedDataPtr(Array array) {
return (UIntPtr) (Magic.addressOf(array) +
(array.vtable.baseLength-(uint)PreHeader.Size));
}
[Inline]
protected static UIntPtr *IndexedFieldPtr(Array obj,
int index,
int arrayElementSize,
UIntPtr fieldOffset)
{
UIntPtr dataPtr = IndexedDataPtr(obj);
UIntPtr *fieldPtr = (UIntPtr *)
(dataPtr + index * arrayElementSize + fieldOffset);
return fieldPtr;
}
[Inline]
protected void CopyStructNoBarrier(VTable vtable,
UIntPtr srcPtr,
UIntPtr dstPtr)
{
int preHeaderSize = PreHeader.Size;
int postHeaderSize = PostHeader.Size;
int structSize = ((int) ObjectLayout.ObjectSize(vtable) -
(preHeaderSize + postHeaderSize));
Buffer.MoveMemory((byte *) dstPtr, (byte *) srcPtr, structSize);
}
[Inline]
protected void CopyStructWithBarrier(VTable vtable,
UIntPtr srcPtr,
UIntPtr dstPtr)
{
copyFieldsVisitor.VisitReferenceFields(vtable, srcPtr, dstPtr);
}
[Inline]
protected Object AtomicSwapNoBarrier(ref Object reference,
Object value)
{
UIntPtr resultAddr =
Interlocked.Exchange(Magic.toPointer(ref reference),
Magic.addressOf(value));
return Magic.fromAddress(resultAddr);
}
[Inline]
protected Object AtomicCompareAndSwapNoBarrier(ref Object reference,
Object newValue,
Object comparand)
{
UIntPtr resultAddr =
Interlocked.CompareExchange(Magic.toPointer(ref reference),
Magic.addressOf(newValue),
Magic.addressOf(comparand));
return Magic.fromAddress(resultAddr);
}
[Inline]
protected void CloneNoBarrier(Object srcObject,
Object dstObject)
{
UIntPtr objectSize = System.GCs.ObjectLayout.Sizeof(srcObject);
int preHeaderSize = PreHeader.Size;
int postHeaderSize = PostHeader.Size;
// We don't copy any of the header fields.
Util.MemCopy(Magic.addressOf(dstObject) + postHeaderSize,
Magic.addressOf(srcObject) + postHeaderSize,
objectSize - preHeaderSize - postHeaderSize);
}
[Inline]
protected void CloneWithBarrier(Object srcObject,
Object dstObject)
{
copyFieldsVisitor.VisitReferenceFields(srcObject, dstObject);
}
// 'offset' is not relative to the lower bound, but is a count
// of elements from the first element in the array.
[Inline]
protected void ArrayZeroNoBarrier(Array array, int offset,
int length)
{
UIntPtr dataPtr = IndexedDataPtr(array);
int elementSize = array.vtable.arrayElementSize;
Buffer.ZeroMemory((byte *)dataPtr + offset * elementSize,
length * elementSize);
}
// 'offset' is not relative to the lower bound, but is a count
// of elements from the first element in the array.
[Inline]
protected void ArrayZeroWithBarrier(Array array, int offset,
int length)
{
UIntPtr dataPtr = IndexedDataPtr(array);
int elementSize = array.vtable.arrayElementSize;
UIntPtr startAddr = dataPtr + offset * elementSize;
zeroFieldsVisitor.VisitReferenceFields(array.vtable,
startAddr, length);
}
// 'offset' is not relative to the lower bound, but is a count
// of elements from the first element in the array.
[Inline]
protected void ArrayCopyNoBarrier(Array srcArray, int srcOffset,
Array dstArray, int dstOffset,
int length)
{
UIntPtr srcDataAddr = IndexedDataPtr(srcArray);
UIntPtr dstDataAddr = IndexedDataPtr(dstArray);
int elementSize = srcArray.vtable.arrayElementSize;
VTable.Assert(elementSize ==
dstArray.vtable.arrayElementSize);
Buffer.MoveMemory((byte *) (dstDataAddr + dstOffset * elementSize),
(byte *) (srcDataAddr + srcOffset * elementSize),
length * elementSize);
}
// 'offset' is not relative to the lower bound, but is a count
// of elements from the first element in the array.
[Inline]
protected void ArrayCopyWithBarrier(Array srcArray, int srcOffset,
Array dstArray, int dstOffset,
int length)
{
UIntPtr srcDataAddr = IndexedDataPtr(srcArray);
UIntPtr dstDataAddr = IndexedDataPtr(dstArray);
int elementSize = srcArray.vtable.arrayElementSize;
VTable.Assert(elementSize == dstArray.vtable.arrayElementSize);
UIntPtr srcStartAddr = srcDataAddr + srcOffset * elementSize;
UIntPtr dstStartAddr = dstDataAddr + dstOffset * elementSize;
copyFieldsVisitor.VisitReferenceFields(srcArray.vtable,
srcStartAddr,
dstStartAddr,
length);
}
[Inline]
internal static void StoreIndirect(UIntPtr *location, Object value)
{
installedWriteBarrier.StoreIndirectImpl(location, value);
}
[RequiredByBartok]
[Inline]
internal static void StoreIndirect(ref Object reference,
Object value)
{
installedWriteBarrier.StoreIndirectImpl(ref reference, value);
}
[RequiredByBartok]
[Inline]
internal static void StoreObjectField(Object obj,
UIntPtr fieldOffset,
Object value)
{
installedWriteBarrier.StoreObjectFieldImpl(obj,
fieldOffset,
value);
}
[RequiredByBartok]
[Inline]
internal static void StoreStructField(UIntPtr structPtr,
UIntPtr fieldOffset,
Object value)
{
installedWriteBarrier.StoreStructFieldImpl(structPtr,
fieldOffset,
value);
}
[RequiredByBartok]
[Inline]
internal static void StoreVectorElement(Array vector,
int index,
int arrayElementSize,
UIntPtr fieldOffset,
Object value)
{
installedWriteBarrier.StoreVectorElementImpl(vector,
index,
arrayElementSize,
fieldOffset,
value);
}
[RequiredByBartok]
[Inline]
internal static void StoreArrayElement(Array array,
int index,
int arrayElementSize,
UIntPtr fieldOffset,
Object value)
{
installedWriteBarrier.StoreArrayElementImpl(array,
index,
arrayElementSize,
fieldOffset,
value);
}
[RequiredByBartok]
[Inline]
internal static void StoreStaticField(ref Object staticField,
Object value)
{
installedWriteBarrier.StoreStaticFieldImpl(ref staticField, value);
}
[Inline]
internal static void CopyStruct(VTable vtable,
UIntPtr srcPtr,
UIntPtr dstPtr)
{
installedWriteBarrier.CopyStructImpl(vtable, srcPtr, dstPtr);
}
[RequiredByBartok]
[Inline]
internal static Object AtomicSwap(ref Object reference,
Object value)
{
return installedWriteBarrier.AtomicSwapImpl(ref reference, value);
}
[RequiredByBartok]
[Inline]
internal static Object AtomicCompareAndSwap(ref Object reference,
Object newValue,
Object comparand)
{
return
installedWriteBarrier.AtomicCompareAndSwapImpl(ref reference,
newValue,
comparand);
}
[Inline]
internal static void Clone(Object srcObject, Object dstObject)
{
installedWriteBarrier.CloneImpl(srcObject, dstObject);
}
// 'offset' is not relative to the lower bound, but is a count
// of elements from the first element in the array.
[Inline]
internal static void ArrayZero(Array array, int offset, int length)
{
installedWriteBarrier.ArrayZeroImpl(array, offset, length);
}
// 'offset' is not relative to the lower bound, but is a count
// of elements from the first element in the array.
[Inline]
internal static void ArrayCopy(Array srcArray, int srcOffset,
Array dstArray, int dstOffset,
int length)
{
installedWriteBarrier.ArrayCopyImpl(srcArray, srcOffset,
dstArray, dstOffset,
length);
}
[Inline]
internal static void WriteReference(UIntPtr *location, Object value)
{
installedWriteBarrier.WriteReferenceImpl(location, value);
}
private class CopyFieldsVisitor : OffsetReferenceVisitor
{
// Struct copy
internal void VisitReferenceFields(VTable vtable,
UIntPtr srcPtr,
UIntPtr dstPtr)
{
int postHeaderSize = PostHeader.Size;
ObjectDescriptor objDesc =
new ObjectDescriptor(vtable,
srcPtr - postHeaderSize,
dstPtr - postHeaderSize,
(UIntPtr) postHeaderSize);
UIntPtr ignore = VisitReferenceFieldsTemplate(ref objDesc);
int preHeaderSize = PreHeader.Size;
UIntPtr limitSize =
ObjectLayout.ObjectSize(vtable) - preHeaderSize;
UIntPtr previouslyDone = objDesc.extra;
UIntPtr tailSize = limitSize - previouslyDone;
if (tailSize > UIntPtr.Zero) {
Util.MemCopy(objDesc.secondBase + previouslyDone,
objDesc.objectBase + previouslyDone,
tailSize);
}
}
internal void VisitReferenceFields(Object srcObject,
Object dstObject)
{
int postHeaderSize = PostHeader.Size;
ObjectDescriptor objDesc =
new ObjectDescriptor(srcObject.vtable,
Magic.addressOf(srcObject),
Magic.addressOf(dstObject),
(UIntPtr) postHeaderSize);
UIntPtr objectSize = VisitReferenceFieldsTemplate(ref objDesc);
int preHeaderSize = PreHeader.Size;
UIntPtr limitSize = objectSize - preHeaderSize;
UIntPtr previouslyDone = objDesc.extra;
UIntPtr tailSize = limitSize - previouslyDone;
if (tailSize > UIntPtr.Zero) {
Util.MemCopy(objDesc.secondBase + previouslyDone,
objDesc.objectBase + previouslyDone,
tailSize);
}
}
// Partial array copy
internal void VisitReferenceFields(VTable vtable,
UIntPtr srcElementPtr,
UIntPtr dstElementPtr,
int length)
{
ObjectDescriptor objDesc =
new ObjectDescriptor(vtable, srcElementPtr, dstElementPtr);
VisitReferenceFieldsTemplate(ref objDesc, length);
UIntPtr srcLimitAddr =
srcElementPtr + length * vtable.arrayElementSize;
UIntPtr previouslyDone = objDesc.objectBase + objDesc.extra;
UIntPtr tailSize = srcLimitAddr - previouslyDone;
if (tailSize > UIntPtr.Zero) {
Util.MemCopy(objDesc.secondBase + objDesc.extra,
previouslyDone, tailSize);
}
}
internal override void FieldOffset(UIntPtr offset,
ref ObjectDescriptor objDesc)
{
UIntPtr previouslyDone = objDesc.extra;
objDesc.extra = offset + UIntPtr.Size;
UIntPtr norefSize = offset - previouslyDone;
if (norefSize > UIntPtr.Zero) {
Util.MemCopy(objDesc.secondBase + previouslyDone,
objDesc.objectBase + previouslyDone,
norefSize);
}
UIntPtr *srcAddr = (UIntPtr *) (objDesc.objectBase + offset);
UIntPtr *dstAddr = (UIntPtr *) (objDesc.secondBase + offset);
Object fieldValue = Magic.fromAddress(*srcAddr);
WriteBarrier.WriteReference(dstAddr, fieldValue);
}
}
private class ZeroFieldsVisitor : OffsetReferenceVisitor
{
internal void VisitReferenceFields(VTable vtable,
UIntPtr elementAddr,
int length)
{
int postHeaderSize = PostHeader.Size;
ObjectDescriptor objDesc =
new ObjectDescriptor(vtable, elementAddr);
VisitReferenceFieldsTemplate(ref objDesc, length);
UIntPtr limitAddr =
elementAddr + length * vtable.arrayElementSize;
UIntPtr previouslyDone = objDesc.objectBase + objDesc.extra;
UIntPtr tailSize = limitAddr - previouslyDone;
if (tailSize > UIntPtr.Zero) {
Buffer.ZeroMemory((byte *) previouslyDone, tailSize);
}
}
internal override void FieldOffset(UIntPtr offset,
ref ObjectDescriptor objDesc)
{
int postHeaderSize = PostHeader.Size;
UIntPtr previouslyDone = objDesc.extra;
objDesc.extra = offset + UIntPtr.Size;
UIntPtr norefSize = offset - previouslyDone;
if (norefSize > UIntPtr.Zero) {
Util.MemClear(objDesc.objectBase + previouslyDone,
norefSize);
}
UIntPtr *fieldAddr = (UIntPtr *) (objDesc.objectBase + offset);
WriteBarrier.WriteReference(fieldAddr, null);
}
}
}
}