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

453 lines
19 KiB
C#
Raw Normal View History

2008-11-17 18:29:00 -05:00
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
2008-03-05 09:52:00 -05:00
/*******************************************************************/
/* 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 System.Runtime.CompilerServices;
internal abstract class ReferenceVisitor {
internal struct ObjectDescriptor {
[ManualRefCounts]
[Inline]
internal ObjectDescriptor(VTable vtable, UIntPtr objectBase) :
2008-11-17 18:29:00 -05:00
this(vtable, objectBase, UIntPtr.Zero, UIntPtr.Zero,
null, null)
2008-03-05 09:52:00 -05:00
{
}
[ManualRefCounts]
[Inline]
internal ObjectDescriptor(VTable vtable, UIntPtr objectBase,
UIntPtr secondBase) :
2008-11-17 18:29:00 -05:00
this(vtable, objectBase, secondBase, UIntPtr.Zero, null, null)
2008-03-05 09:52:00 -05:00
{
}
[ManualRefCounts]
[Inline]
internal ObjectDescriptor(VTable vtable,
UIntPtr objectBase,
UIntPtr secondBase,
2008-11-17 18:29:00 -05:00
UIntPtr extra) :
this(vtable, objectBase, secondBase, extra, null, null)
{}
[ManualRefCounts]
[Inline]
internal ObjectDescriptor(VTable vtable,
UIntPtr objectBase,
UIntPtr secondBase,
UIntPtr extra,
Object realObjectBase,
Object realSecondBase)
2008-03-05 09:52:00 -05:00
{
this.vtable = vtable;
this.objectBase = objectBase;
this.secondBase = secondBase;
this.extra = extra;
2008-11-17 18:29:00 -05:00
this.realObjectBase = realObjectBase;
this.realSecondBase = realSecondBase;
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
// this struct is never in the heap, so the fields should
// be accessed the quick way. (and no, this struct isn't
// always accessed through a local var - it might be accessed
// via a managed pointer in the NoInline reference fields
// visitor methods.)
[NoBarriers]
2008-03-05 09:52:00 -05:00
internal new VTable vtable;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
internal UIntPtr objectBase;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
internal UIntPtr secondBase;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
internal UIntPtr extra;
2008-11-17 18:29:00 -05:00
[NoBarriers]
internal Object realObjectBase;
[NoBarriers]
internal Object realSecondBase;
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
// Rationale for cutting the fact that no stack probes are permitted in this
// tree of calls:
//
// There is no rationale. It is a bug which is tracked with all the cases that
// require fixing.
//
// Bug 436
[NoStackLinkCheckTransCut]
2008-03-05 09:52:00 -05:00
[ManualRefCounts]
2008-11-17 18:29:00 -05:00
[Inline]
2008-03-05 09:52:00 -05:00
internal virtual UIntPtr VisitReferenceFields(Object obj)
{
return this.VisitReferenceFields(Magic.addressOf(obj),
obj.vtable);
}
2008-11-17 18:29:00 -05:00
[Inline]
2008-03-05 09:52:00 -05:00
internal abstract UIntPtr VisitReferenceFields(UIntPtr objectBase,
VTable vtable);
[Inline]
protected abstract unsafe
void Filter(UIntPtr *location, ref ObjectDescriptor objDesc);
2008-11-17 18:29:00 -05:00
// Rationale for cutting the fact that no stack probes are permitted in this
// tree of calls:
//
// There is no rationale. This is a bug which has been filed. It is a temporary
// hack to break the recursion in this method. Recursion needs to open up an
// opportunity for stack probing. Eventually, perhaps this method can be
// rewritten to avoid the recursion.
//
// Bug 436
[NoStackLinkCheckTransCut]
2008-03-05 09:52:00 -05:00
[ManualRefCounts]
2008-11-17 18:29:00 -05:00
[NoInline]
protected unsafe
UIntPtr VisitReferenceFieldsTemplateNoInline(ref ObjectDescriptor objDesc)
{
return VisitReferenceFieldsTemplate(ref objDesc);
}
[ManualRefCounts]
[Inline]
2008-03-05 09:52:00 -05:00
protected unsafe
UIntPtr VisitReferenceFieldsTemplate(ref ObjectDescriptor objDesc)
{
UIntPtr pointerTracking = objDesc.vtable.pointerTrackingMask;
uint objectTag = (pointerTracking & 0xf);
UIntPtr size;
switch (objectTag) {
case ObjectLayout.SPARSE_TAG: {
UIntPtr *sparseObject = (UIntPtr *) objDesc.objectBase;
size = ObjectLayout.ObjectSize(objDesc.vtable);
pointerTracking >>= 4;
while (pointerTracking != 0) {
uint index = pointerTracking & 0xf;
pointerTracking >>= 4;
// The cast to int prevents C# from taking the
// index * sizeof(UIntPtr) to long:
UIntPtr *loc = sparseObject + (int) index;
this.Filter(loc, ref objDesc);
}
break;
}
case ObjectLayout.DENSE_TAG: {
// skip vtable
int postHeaderSize = PostHeader.Size;
UIntPtr *denseObject = (UIntPtr *)
(objDesc.objectBase + postHeaderSize);
size = ObjectLayout.ObjectSize(objDesc.vtable);
pointerTracking >>= 4;
while (pointerTracking != 0) {
if ((pointerTracking & ((UIntPtr)0x1)) != 0) {
this.Filter(denseObject, ref objDesc);
}
pointerTracking >>= 1;
denseObject++;
}
break;
}
case ObjectLayout.PTR_VECTOR_TAG: {
int postHeaderSize = PostHeader.Size;
uint length = *(uint*)(objDesc.objectBase + postHeaderSize);
size = ObjectLayout.ArraySize(objDesc.vtable, length);
int preHeaderSize = PreHeader.Size;
UIntPtr *elementAddress = (UIntPtr *)
(objDesc.objectBase + objDesc.vtable.baseLength -
preHeaderSize);
for (uint i = 0; i < length; i++, elementAddress++) {
this.Filter(elementAddress, ref objDesc);
}
break;
}
case ObjectLayout.OTHER_VECTOR_TAG: {
int postHeaderSize = PostHeader.Size;
uint length = *(uint*)(objDesc.objectBase + postHeaderSize);
size = ObjectLayout.ArraySize(objDesc.vtable, length);
if (objDesc.vtable.arrayOf == StructuralType.Struct) {
// pretend the struct is boxed and account for the
// presence of the vtable field
VTable elementVTable = objDesc.vtable.arrayElementClass;
UIntPtr elementMask = elementVTable.pointerTrackingMask;
// A structure with no references will have a SPARSE
// descriptor with no offset values.
if (elementMask != (UIntPtr) ObjectLayout.SPARSE_TAG) {
int preHeaderSize = PreHeader.Size;
UIntPtr elementAddress = (objDesc.objectBase +
objDesc.vtable.baseLength -
preHeaderSize -
postHeaderSize);
int elementSize = objDesc.vtable.arrayElementSize;
objDesc.vtable = elementVTable;
for (uint i = 0; i < length; i++) {
objDesc.objectBase = elementAddress;
2008-11-17 18:29:00 -05:00
this.VisitReferenceFieldsTemplateNoInline(ref objDesc);
2008-03-05 09:52:00 -05:00
elementAddress += elementSize;
}
}
}
break;
}
case ObjectLayout.PTR_ARRAY_TAG: {
int postHeaderSize = PostHeader.Size;
uint length = *(uint*)(objDesc.objectBase + postHeaderSize +
sizeof(uint));
size = ObjectLayout.ArraySize(objDesc.vtable, length);
int preHeaderSize = PreHeader.Size;
UIntPtr *elementAddress = (UIntPtr *)
(objDesc.objectBase + objDesc.vtable.baseLength -
preHeaderSize);
for (uint i = 0; i < length; i++, elementAddress++) {
this.Filter(elementAddress, ref objDesc);
}
break;
}
case ObjectLayout.OTHER_ARRAY_TAG: {
int postHeaderSize = PostHeader.Size;
uint length = *(uint*)(objDesc.objectBase + postHeaderSize +
sizeof(uint));
size = ObjectLayout.ArraySize(objDesc.vtable, length);
if (objDesc.vtable.arrayOf == StructuralType.Struct) {
// pretend the struct is boxed and account for the
// presence of the PostHeader
VTable elementVTable = objDesc.vtable.arrayElementClass;
UIntPtr elementMask = elementVTable.pointerTrackingMask;
// A structure with no references will have a SPARSE
// descriptor with no offset values.
if (elementMask != (UIntPtr) ObjectLayout.SPARSE_TAG) {
int preHeaderSize = PreHeader.Size;
int elementSize = objDesc.vtable.arrayElementSize;
UIntPtr elementAddress =
objDesc.objectBase + objDesc.vtable.baseLength -
preHeaderSize - postHeaderSize;
objDesc.vtable = elementVTable;
for (uint i = 0; i < length; i++) {
objDesc.objectBase = elementAddress;
2008-11-17 18:29:00 -05:00
this.VisitReferenceFieldsTemplateNoInline(ref objDesc);
2008-03-05 09:52:00 -05:00
elementAddress += elementSize;
}
}
}
break;
}
case ObjectLayout.STRING_TAG: {
int postHeaderSize = PostHeader.Size;
uint arrayLength =
*(uint*)(objDesc.objectBase + postHeaderSize);
size = ObjectLayout.StringSize(objDesc.vtable, arrayLength);
break;
}
default: {
// escape case
VTable.Assert((objectTag & 0x1) == 0,
"ReferenceVisitor: (objectTag & 0x1) == 0");
UIntPtr *largeObject = (UIntPtr *) objDesc.objectBase;
size = ObjectLayout.ObjectSize(objDesc.vtable);
int *pointerDescription = (int *) pointerTracking;
int count = *pointerDescription;
for (int i = 1; i <= count; i++) {
UIntPtr *loc = largeObject + *(pointerDescription+i);
this.Filter(loc, ref objDesc);
}
break;
}
}
return size;
}
2008-11-17 18:29:00 -05:00
// Rationale for cutting the fact that no stack probes are permitted in this
// tree of calls:
//
// There is no rationale. This is a bug which has been filed. It is a temporary
// hack to break the recursion in this method. Recursion needs to open up an
// opportunity for stack probing. Eventually, perhaps this method can be
// rewritten to avoid the recursion.
//
// Bug 436
[NoStackLinkCheckTransCut]
2008-03-05 09:52:00 -05:00
[ManualRefCounts]
protected unsafe
void VisitReferenceFieldsTemplate(ref ObjectDescriptor objDesc,
int count)
{
UIntPtr pointerTracking = objDesc.vtable.pointerTrackingMask;
uint objectTag = (pointerTracking & 0xf);
switch (objectTag) {
case ObjectLayout.PTR_VECTOR_TAG:
case ObjectLayout.PTR_ARRAY_TAG: {
UIntPtr *elementAddress = (UIntPtr *) objDesc.objectBase;
for (int i = 0; i < count; i++, elementAddress++) {
this.Filter(elementAddress, ref objDesc);
}
break;
}
case ObjectLayout.OTHER_VECTOR_TAG:
case ObjectLayout.OTHER_ARRAY_TAG: {
if (objDesc.vtable.arrayOf == StructuralType.Struct) {
// pretend the struct is boxed and account for the
// presence of the vtable field
VTable elementVTable = objDesc.vtable.arrayElementClass;
UIntPtr elementMask = elementVTable.pointerTrackingMask;
// A structure with no references will have a SPARSE
// descriptor with no offset values.
if (elementMask != (UIntPtr) ObjectLayout.SPARSE_TAG) {
int postHeaderSize = PostHeader.Size;
objDesc.objectBase -= postHeaderSize;
objDesc.secondBase -= postHeaderSize;
objDesc.extra += postHeaderSize;
int elementSize = objDesc.vtable.arrayElementSize;
objDesc.vtable = elementVTable;
for (int i = 0; i < count; i++) {
2008-11-17 18:29:00 -05:00
this.VisitReferenceFieldsTemplateNoInline(ref objDesc);
2008-03-05 09:52:00 -05:00
objDesc.objectBase += elementSize;
objDesc.secondBase += elementSize;
objDesc.extra -= elementSize;
}
objDesc.objectBase += postHeaderSize;
objDesc.secondBase += postHeaderSize;
objDesc.extra -= postHeaderSize;
}
}
break;
}
default: {
throw new Exception("Indexing non-indexed type");
}
}
}
}
2008-11-17 18:29:00 -05:00
internal abstract class DirectReferenceVisitor : ReferenceVisitor
2008-03-05 09:52:00 -05:00
{
2008-11-17 18:29:00 -05:00
[Inline]
internal abstract unsafe void Visit(UIntPtr *location);
}
// This visitor should be used in concurrent settings.
internal abstract class MutableReferenceVisitor : DirectReferenceVisitor
{
2008-03-05 09:52:00 -05:00
#region HELP_DEVIRT
2008-11-17 18:29:00 -05:00
// TODO: Evaluate the performance impact of these [Inline] annotations,
// which appeared as part of the CoCo code dump.
2008-03-05 09:52:00 -05:00
// This method simply forces the compiler to generate a copy
// of VisitReferenceFieldsTemplate in this class.
2008-11-17 18:29:00 -05:00
[Inline]
2008-03-05 09:52:00 -05:00
[ManualRefCounts]
internal override UIntPtr VisitReferenceFields(Object obj)
{
return this.VisitReferenceFields(Magic.addressOf(obj),
obj.vtable);
}
// This method simply forces the compiler to generate a copy
// of VisitReferenceFieldsTemplate in this class.
2008-11-17 18:29:00 -05:00
[Inline]
2008-03-05 09:52:00 -05:00
[ManualRefCounts]
2008-11-17 18:29:00 -05:00
internal override UIntPtr VisitReferenceFields(UIntPtr objectBase,
VTable vtable)
{
ObjectDescriptor objDesc =
new ObjectDescriptor(vtable, objectBase);
return VisitReferenceFieldsTemplate(ref objDesc);
}
#endregion
[Inline]
protected override unsafe
void Filter(UIntPtr *location, ref ObjectDescriptor objDesc)
{
this.Visit(location);
}
}
// This visitor should only be used in situations where the
// reference fields are known to not be modified by other threads
// while the visitor is traversing the object.
internal abstract class NonNullReferenceVisitor : DirectReferenceVisitor
{
#region HELP_DEVIRT
// This method simply forces the compiler to generate a copy
// of VisitReferenceFieldsTemplate in this class.
[ManualRefCounts]
[Inline]
internal override UIntPtr VisitReferenceFields(Object obj)
{
return this.VisitReferenceFields(Magic.addressOf(obj),
obj.vtable);
}
// This method simply forces the compiler to generate a copy
// of VisitReferenceFieldsTemplate in this class.
[ManualRefCounts]
[Inline]
internal override UIntPtr VisitReferenceFields(UIntPtr objectBase,
VTable vtable)
2008-03-05 09:52:00 -05:00
{
ObjectDescriptor objDesc =
new ObjectDescriptor(vtable, objectBase);
return VisitReferenceFieldsTemplate(ref objDesc);
}
#endregion
[Inline]
protected override unsafe
void Filter(UIntPtr *location, ref ObjectDescriptor objDesc)
{
if (*location != UIntPtr.Zero) {
this.Visit(location);
}
}
}
internal abstract class OffsetReferenceVisitor : ReferenceVisitor
{
internal abstract void FieldOffset(UIntPtr offset,
ref ObjectDescriptor objDesc);
#region HELP_DEVIRT
// This method simply forces the compiler to generate a copy
// of VisitReferenceFieldsTemplate in this class.
[ManualRefCounts]
internal override sealed
UIntPtr VisitReferenceFields(UIntPtr objectBase, VTable vtable)
{
ObjectDescriptor objDesc =
new ObjectDescriptor(vtable, objectBase);
return VisitReferenceFieldsTemplate(ref objDesc);
}
#endregion
[Inline]
protected override unsafe sealed
void Filter(UIntPtr *location, ref ObjectDescriptor objDesc)
{
UIntPtr offset = ((UIntPtr) location) - objDesc.objectBase;
this.FieldOffset(offset, ref objDesc);
}
}
}