335 lines
15 KiB
C#
335 lines
15 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;
|
||
|
|
||
|
internal abstract class ReferenceVisitor {
|
||
|
|
||
|
internal struct ObjectDescriptor {
|
||
|
[ManualRefCounts]
|
||
|
[Inline]
|
||
|
internal ObjectDescriptor(VTable vtable, UIntPtr objectBase) :
|
||
|
this(vtable, objectBase, UIntPtr.Zero, UIntPtr.Zero)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
[ManualRefCounts]
|
||
|
[Inline]
|
||
|
internal ObjectDescriptor(VTable vtable, UIntPtr objectBase,
|
||
|
UIntPtr secondBase) :
|
||
|
this(vtable, objectBase, secondBase, UIntPtr.Zero)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
[ManualRefCounts]
|
||
|
[Inline]
|
||
|
internal ObjectDescriptor(VTable vtable,
|
||
|
UIntPtr objectBase,
|
||
|
UIntPtr secondBase,
|
||
|
UIntPtr extra)
|
||
|
{
|
||
|
this.vtable = vtable;
|
||
|
this.objectBase = objectBase;
|
||
|
this.secondBase = secondBase;
|
||
|
this.extra = extra;
|
||
|
}
|
||
|
|
||
|
internal new VTable vtable;
|
||
|
internal UIntPtr objectBase;
|
||
|
internal UIntPtr secondBase;
|
||
|
internal UIntPtr extra;
|
||
|
}
|
||
|
|
||
|
[ManualRefCounts]
|
||
|
internal virtual UIntPtr VisitReferenceFields(Object obj)
|
||
|
{
|
||
|
return this.VisitReferenceFields(Magic.addressOf(obj),
|
||
|
obj.vtable);
|
||
|
}
|
||
|
|
||
|
internal abstract UIntPtr VisitReferenceFields(UIntPtr objectBase,
|
||
|
VTable vtable);
|
||
|
|
||
|
[Inline]
|
||
|
protected abstract unsafe
|
||
|
void Filter(UIntPtr *location, ref ObjectDescriptor objDesc);
|
||
|
|
||
|
[ManualRefCounts]
|
||
|
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;
|
||
|
this.VisitReferenceFieldsTemplate(ref objDesc);
|
||
|
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;
|
||
|
this.VisitReferenceFieldsTemplate(ref objDesc);
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
[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++) {
|
||
|
this.VisitReferenceFieldsTemplate(ref objDesc);
|
||
|
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");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
internal abstract class NonNullReferenceVisitor : ReferenceVisitor
|
||
|
{
|
||
|
|
||
|
internal unsafe abstract void Visit(UIntPtr *location);
|
||
|
|
||
|
#region HELP_DEVIRT
|
||
|
// This method simply forces the compiler to generate a copy
|
||
|
// of VisitReferenceFieldsTemplate in this class.
|
||
|
[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.
|
||
|
[ManualRefCounts]
|
||
|
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)
|
||
|
{
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|