singrdk/base/Imported/Bartok/runtime/shared/System/VTable.cs

2252 lines
84 KiB
C#
Raw Permalink 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. */
/*******************************************************************/
#define OLD_FAST_TESTS
#if MARKSWEEPCOLLECTOR
#define ALLOW_BOOT_ARGLIST
#endif
namespace System {
using Microsoft.Bartok.Runtime;
#if SINGULARITY_KERNEL
using Microsoft.Singularity;
#elif SINGULARITY_PROCESS
using Microsoft.Singularity;
using Microsoft.Singularity.V1.Services;
#endif
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System;
internal sealed class MutableInt32 {
public MutableInt32(int x) { this.val = x; }
public int Value { get { return this.val; } set { this.val = value; } }
private int val;
}
[RequiredByBartok]
internal struct InterfaceInfo {
[RequiredByBartok]
internal System.RuntimeType type;
[RequiredByBartok]
internal IntPtr offset;
}
[StructLayout(LayoutKind.Sequential)]
[CCtorIsRunDuringStartup]
[NoLoggingForUndo]
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[AccessedByRuntime("Referenced from brt{main,exn}.cpp and brtasm.asm")]
2008-03-05 09:52:00 -05:00
internal sealed class VTable {
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly VTable depth1;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[RequiredByBartok]
public readonly VTable depth2;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[RequiredByBartok]
public readonly VTable depth3;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[RequiredByBartok]
public readonly VTable depth4;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[RequiredByBartok]
public readonly VTable depth5;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[RequiredByBartok]
public readonly VTable depth6;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public VTable posCache;
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public int depth;
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly StructuralType arrayOf;
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly VTable arrayElementClass;
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly int arrayElementSize;
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly InterfaceInfo[] interfaces;
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly uint baseLength;
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly uint baseAlignment;
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly UIntPtr pointerTrackingMask;
2008-11-17 18:29:00 -05:00
[RequiredByBartok]
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly StructuralType structuralView;
[AccessedByRuntime("Referenced from C++")]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly RuntimeType vtableType;
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly int marshalSize;
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly VTable vectorClass;
[AccessedByRuntime("Type information available to runtime.")]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public readonly bool isAcyclicRefType;
// one less than size, which must be a power of two
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
internal static int tryAllCheckMask = 2047;
#if SINGULARITY_KERNEL
private static bool multiThreaded;
#endif
internal class ClassConstructorLock
{
}
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public static readonly ClassConstructorLock cctorLock = new ClassConstructorLock();
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public static int[] handle_counts = new int[4];
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public static bool runtimeInitialized = false;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public static System.Collections.Hashtable interfaceOffsetTable;
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
public static bool callTraceInProgress;
2008-11-17 18:29:00 -05:00
#if ARM
// TODO: ARM isn't supported by the BartokLinker yet, so this
// function won't be correctly generated.
[StackBound(252)]
[RequiredByBartok]
private static void Initialize() {
}
#else
2008-03-05 09:52:00 -05:00
// This method is generated by Bartok.
// It calls all the auto init class constructors.
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(252)]
[RequiredByBartok]
private static extern void Initialize();
2008-11-17 18:29:00 -05:00
#endif
2008-03-05 09:52:00 -05:00
// NB: This is called from Kernel.Main() before the VTable.cctor.
// It calls all the manual init class constructors then
// call Initialize() above to call the auto init class constructors.
[AccessedByRuntime("called from brtmain.cpp")]
[NoStackLinkCheck]
static public void Initialize(RuntimeType mainType)
{
initializeGC();
#if !SINGULARITY
if (useLinkedStack) {
System.GCs.StackManager.Initialize();
}
#endif // !SINGULARITY
// The remaining cctors may allocate memory normally
2008-11-17 18:29:00 -05:00
#if !SINGULARITY
InitializeLimitedType(typeof(Microsoft.Win32.Win32Native));
#endif
2008-03-05 09:52:00 -05:00
InitializeLimitedType(typeof(System.Delegate));
InitializeLimitedType(typeof(System.MultiUseWord));
InitializeLimitedType(typeof(System.WeakReference));
InitializeLimitedType(typeof(System.GCs.Verifier));
InitializeLimitedType(typeof(System.Collections.Hashtable));
Thread.FinishInitializeThread();
// Make transition to full thread-ready GC.
// We can't start any other threads until this code runs.
System.GC.FinishInitializeThread();
#if !SINGULARITY
InitializeLimitedType(typeof(System.IO.Stream));
InitializeLimitedType(typeof(System.Reflection.Missing));
InitializeLimitedType(typeof(System.RuntimeType));
InitializeLimitedType(typeof(System.Environment));
#endif
#if SINGULARITY
InitializeLimitedType(typeof(System.DateTime));
InitializeLimitedType(typeof(System.TimeSpan));
InitializeLimitedType(typeof(System.SchedulerTime));
#endif
InitializeLimitedType(typeof(System.Type));
InitializeLimitedType(typeof(System.String));
InitializeLimitedType(typeof(System.BitConverter));
InitializeLimitedType(typeof(System.Math));
InitializeLimitedType(typeof(System.VTable));
#if !VC
InitializeLimitedType(typeof(System.TryAllManager));
InitializeLimitedType(typeof(System.TryAllCounters));
#endif
VTable.runtimeInitialized = true;
VTable.Initialize();
#if !SINGULARITY
GC.EnableHeap();
if(mainType != null) {
initType(mainType);
}
#endif
}
#if SINGULARITY_KERNEL
static public void InitializeForMultipleThread()
{
multiThreaded = true;
}
#endif
#if (REFERENCE_COUNTING_GC || DEFERRED_REFERENCE_COUNTING_GC)
[NoInline]
#endif // REFERENCE_COUNTING_GC
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
private static void initializeGC() {
// Create the heap management data structures
System.GC.ConstructHeap();
// The following cctors may only allocate using BootstrapMemory
InitializeLimitedType(typeof(System.Threading.Thread));
InitializeLimitedType(typeof(System.GC));
InitializeLimitedType(typeof(System.Finalizer));
System.GCs.BootstrapMemory.Truncate();
}
[RequiredByBartok]
private static bool useLinkedStack;
[System.Diagnostics.Conditional("DEBUG")]
static unsafe void StartupChecks() {
VTable v = ((RuntimeType)typeof(System.VTable)).classVtable;
Assert(v.depth == (Constants.TypeTestDisplayObjectOffset + 1),
"Depth of VTable's VTable is wrong, so either the hierarchy " +
"has changed or the compiler and runtime differ over the " +
"size of the display so the depth offset is wrong");
fixed(int * p = &v.depth) {
UIntPtr up = (UIntPtr) p;
UIntPtr upBase = Magic.addressOf(v);
int diff = ((int) (up - upBase)) / UIntPtr.Size;
#if (REFERENCE_COUNTING_GC || DEFERRED_REFERENCE_COUNTING_GC)
Assert(diff == Constants.TypeTestDisplaySize + 3,
"Number of display fields does not match constant");
#else // REFERENCE_COUNTING_GC
Assert(diff == Constants.TypeTestDisplaySize + 2,
"Number of display fields does not match constant");
#endif
}
}
static unsafe VTable() {
StartupChecks();
// Ensure that the monitors have been allocated, so that we don't
// try to allocate them just as we are running out of memory
Monitor.Enter(VTable.cctorLock);
Monitor.Exit(VTable.cctorLock);
}
internal static void checkNonNull(object obj) {
if (obj == null) {
throw new NullReferenceException();
}
}
[Inline]
[RequiredByBartok]
internal static void checkUnbox(object obj, int structuralType) {
if (structuralType != (int) obj.vtable.structuralView) {
#if SINGULARITY
Tracing.Log(Tracing.Debug, "checkUnbox failed: Obj={0:x8} st={1}",
Magic.addressOf(obj),
unchecked((uint)structuralType));
#endif
throwNewClassCastException();
}
}
2008-11-17 18:29:00 -05:00
#if (REFERENCE_COUNTING_GC || DEFERRED_REFERENCE_COUNTING_GC)
// The CheckVectorStore opcode returns a value to model a
// dependency with respect to StoreVectorElement.
// CheckVectorStore gets lowered to a call to checkArrayStore.
// If the call is subsequently inlined, the type checker may
// complain, due to effects like t := Id<ArraySafetyCheck>().
//
// The bug shows up in release builds with the RC collector,
// when the RCCollectorOptInlineRCUpdates stage-control is
// also turned on.
//
// Attaching [NoInline] to checkArrayStore is a temporary
// solution to get around this bug.
[NoInline]
#endif // REFERENCE_COUNTING_GC
2008-03-05 09:52:00 -05:00
[RequiredByBartok]
internal static void checkArrayStore(object obj1,object obj2) {
Assert(obj1.vtable.vtableType.IsArray);
// can't put an object into a primitive array, but we can probably
// guarantee that this is never called on a primitive type array
VTable obj1VT = obj1.vtable;
VTable obj1ElemVT = obj1VT.arrayElementClass;
RuntimeType obj1ElemTy = obj1ElemVT.vtableType;
// typeof is too slow right now...
//if(obj1ElemTy == typeof(Object)) {
// return;
//}
Deny(obj1ElemTy.IsPrimitive);
if(obj2 == null) {
return;
}
RuntimeType obj2Ty = obj2.vtable.vtableType;
if(! isValidAssignment(obj1ElemTy, obj2Ty)) {
#if SINGULARITY
Tracing.Log(Tracing.Debug,
"checkArrayStore failed: obj1={0:x8} obj2={1:x8} obj1ElemTy={2:x8} obj2Ty={3:x8}",
Magic.addressOf(obj1),
Magic.addressOf(obj2),
Magic.addressOf(obj1ElemTy),
Magic.addressOf(obj2Ty));
#endif
throwNewArrayTypeMismatchException();
}
}
[RequiredByBartok]
internal static void checkArrayElementAddress(RuntimeType ty,
object obj) {
if(ty != obj.vtable.vtableType) {
throwNewArrayTypeMismatchException();
#if SINGULARITY
Tracing.Log(Tracing.Debug,
"checkArrayElementAddress failed: ty={0:x8} obj={1:x8}",
Magic.addressOf(ty),
Magic.addressOf(obj));
#endif
}
}
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
private static bool isValidAssignmentArray(RuntimeType ty,
RuntimeType objTy) {
Assert((ty.IsVector && objTy.IsVector) ||
(ty.IsRectangleArray && objTy.IsRectangleArray),
"incompatible arrays");
Assert(ty.classVtable.arrayOf == objTy.classVtable.arrayOf,
"!= arrayOfs");
VTable tyVT = ty.classVtable;
VTable tyElementVT = tyVT.arrayElementClass;
Assert(tyElementVT != null, "array has null arrayElementClass");
RuntimeType tyElementType = tyElementVT.vtableType;
RuntimeType objElementType =
objTy.classVtable.arrayElementClass.vtableType;
// struct
if(tyVT.arrayOf == StructuralType.Struct) {
return tyElementType == objElementType;
}
// primitives and enums -- this allows int[], E1[], and E2[]
// to cast either way (assuming E1 and E2 are based on int)
if(tyVT.arrayOf != StructuralType.Reference) {
return true;
}
// reference
return isValidAssignment(tyElementType, objElementType);
}
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
internal static bool isValidAssignment(RuntimeType ty,RuntimeType objTy) {
return (ty == objTy) || isValidAssignmentMedium(ty, objTy);
}
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
internal static bool isValidAssignmentMedium(RuntimeType ty,
RuntimeType objTy)
{
RuntimeType testType = objTy;
do {
testType = testType.baseType;
if (ty == testType) {
return true;
}
} while (testType != null);
return isValidAssignmentSlow(ty, objTy);
}
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
private static bool isValidAssignmentSlow(RuntimeType ty,
RuntimeType objTy)
{
Assert(ty != null, "isValidAssignment null dst type");
Assert(objTy != null, "isValidAssignment null src type");
if(ty.classVtable.arrayOf != StructuralType.None) {
// ty is an Array
if(ty.classVtable.arrayOf == objTy.classVtable.arrayOf) {
if(ty.IsVector) {
if (objTy.IsVector) {
return isValidAssignmentArray(ty, objTy);
}
} else {
Assert(ty.IsRectangleArray, "not rectangle array");
if(!objTy.IsVector && ty.rank == objTy.rank) {
return isValidAssignmentArray(ty, objTy);
}
}
}
} else if ((ty.attributes & TypeAttributes.ClassSemanticsMask) ==
TypeAttributes.Interface) {
// ty is an Interface
System.RuntimeType[] interfaces = objTy.interfaces;
if(interfaces != null) {
int numInterfaces = interfaces.Length;
for(int i=0; i<numInterfaces; ++i) {
if(interfaces[i] == ty) {
return true;
}
}
}
}
return false;
}
[RequiredByBartok]
internal static Object isInstanceOf(RuntimeType ty,object obj) {
if(obj == null) {
return null;
}
RuntimeType objTy = obj.vtable.vtableType;
if(isValidAssignment(ty, objTy)) {
return obj;
} else {
return null;
}
}
// null ok
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
internal static void checkClassCast(RuntimeType ty,object obj) {
if(obj != null && !isValidAssignment(ty, obj.vtable.vtableType)) {
#if SINGULARITY
Tracing.Log(Tracing.Debug,
"checkClassCast failed: ty={0:x8} obj={1:x8}",
Magic.addressOf(ty),
Magic.addressOf(obj));
#endif
throwNewClassCastException();
}
}
// "Simple" means that we must be testing against a type that is in our
// display. Deep classes, interfaces, and arrays of interfaces are not
// simple. "Exact" means that we do not accept subtypes. This is
// common if we are testing against a sealed type since it will have no
// subtypes.
#if OLD_FAST_TESTS
// The boolean parameters should always be inlined constants -- it is here
// so that the callers here in VTable can be partially evaluated at
// compile-time.
[Inline]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
internal unsafe static bool newIsValidAssignment(VTable vtarget,
VTable vobj,
int vtargetDepth,
bool alwaysExact,
bool alwaysSimple) {
Assert((int)vtarget.depth == vtargetDepth);
Assert(vtargetDepth > 0);
if(alwaysExact) {
return vobj == vtarget;
}
UIntPtr * p = (UIntPtr *) Magic.addressOf(vobj);
#if (REFERENCE_COUNTING_GC || DEFERRED_REFERENCE_COUNTING_GC)
if(alwaysSimple ||
(vtargetDepth < Constants.TypeTestDisplayPosCache)) {
return p[vtargetDepth+1] == Magic.addressOf(vtarget);
}
#else // REFERENCE_COUNTING_GC
if(alwaysSimple ||
(vtargetDepth < Constants.TypeTestDisplayPosCache)) {
return p[vtargetDepth] == Magic.addressOf(vtarget);
}
#endif
#if (REFERENCE_COUNTING_GC || DEFERRED_REFERENCE_COUNTING_GC)
if(p[vtargetDepth+1] == Magic.addressOf(vtarget)) {
return true;
}
#else // REFERENCE_COUNTING_GC
if(p[vtargetDepth] == Magic.addressOf(vtarget)) {
return true;
}
#endif
if(isValidAssignment(vtarget.vtableType, vobj.vtableType)) {
vobj.posCache = vtarget;
return true;
}
return false;
}
[Inline]
private static Object newIsInstanceOf(VTable v,
Object obj,
int vtargetDepth,
bool mayBeNull,
bool mustBeExact,
bool alwaysSimple) {
if(mayBeNull && obj == null) {
return null;
}
VTable objVtable = obj.vtable;
if(newIsValidAssignment(v, objVtable, vtargetDepth, mustBeExact,
alwaysSimple)) {
return obj;
} else {
return null;
}
}
[Inline]
[RequiredByBartok]
internal static Object newIsInstanceOfNonNullExact(VTable v,
Object obj,
int vtargetDepth) {
return newIsInstanceOf(v, obj, vtargetDepth, false, true, true);
}
[Inline]
[RequiredByBartok]
internal static Object newIsInstanceOfExact(VTable v,
Object obj,
int vtargetDepth) {
return newIsInstanceOf(v, obj, vtargetDepth, true, true, true);
}
[Inline]
[RequiredByBartok]
internal static Object newIsInstanceOfNonNullSimple(VTable v,
Object obj,
int vtargetDepth) {
return newIsInstanceOf(v, obj, vtargetDepth, false, false, true);
}
[Inline]
[RequiredByBartok]
internal static Object newIsInstanceOfSimple(VTable v,
Object obj,
int vtargetDepth) {
return newIsInstanceOf(v, obj, vtargetDepth, true, false, true);
}
[Inline]
[RequiredByBartok]
internal static Object newIsInstanceOfNonNullComplex(VTable v,
Object obj,
int vtargetDepth) {
return newIsInstanceOf(v, obj, vtargetDepth, false, false, false);
}
[Inline]
[RequiredByBartok]
internal static Object newIsInstanceOfComplex(VTable v,
Object obj,
int vtargetDepth) {
return newIsInstanceOf(v, obj, vtargetDepth, true, false, false);
}
[Inline]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
internal static void newCheckClassCast(VTable v,
object obj,
int vtargetDepth,
bool mayBeNull,
bool mustBeExact,
bool alwaysSimple) {
if(mayBeNull && obj == null) {
return;
}
if(!newIsValidAssignment(v, obj.vtable, vtargetDepth, mustBeExact,
alwaysSimple)) {
#if SINGULARITY
Tracing.Log(Tracing.Debug,
"newCheckClassCast failed: v={0:x8} obj={1:x8} vtd={2} mbn={3} as={4}",
Magic.addressOf(v),
Magic.addressOf(obj),
unchecked((uint)vtargetDepth),
unchecked((uint)(mayBeNull ? 1 : 0)),
unchecked((uint)(alwaysSimple ? 1 : 0)));
#endif
throwNewClassCastException();
}
}
[Inline]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
[RequiredByBartok]
internal static void newCheckClassCastNonNullExact(VTable v,
object obj,
int vtargetDepth) {
newCheckClassCast(v, obj, vtargetDepth, false, true, true);
}
[Inline]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
[RequiredByBartok]
internal static void newCheckClassCastExact(VTable v,
object obj,
int vtargetDepth) {
newCheckClassCast(v, obj, vtargetDepth, true, true, true);
}
[Inline]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
[RequiredByBartok]
internal static void newCheckClassCastNonNullSimple(VTable v,
object obj,
int vtargetDepth) {
newCheckClassCast(v, obj, vtargetDepth, false, false, true);
}
[Inline]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
[RequiredByBartok]
internal static void newCheckClassCastSimple(VTable v,
object obj,
int vtargetDepth) {
newCheckClassCast(v, obj, vtargetDepth, true, false, true);
}
[Inline]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
[RequiredByBartok]
internal static void newCheckClassCastNonNullComplex(VTable v,
object obj,
int vtargetDepth)
{
newCheckClassCast(v, obj, vtargetDepth, false, false, false);
}
[Inline]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
[RequiredByBartok]
internal static void newCheckClassCastComplex(VTable v,
object obj,
int vtargetDepth) {
newCheckClassCast(v, obj, vtargetDepth, true, false, false);
}
#else
[Inline]
private unsafe static bool checkDisplay(VTable vtarget,
VTable vobj,
int vtargetDepth) {
UIntPtr * p = (UIntPtr *) Magic.addressOf(vobj);
Assert((int)vtarget.depth == vtargetDepth);
Assert(vtargetDepth > 0);
#if (REFERENCE_COUNTING_GC || DEFERRED_REFERENCE_COUNTING_GC)
return p[vtargetDepth+1] == Magic.addressOf(vtarget);
#else // REFERENCE_COUNTING_GC
return p[vtargetDepth] == Magic.addressOf(vtarget);
#endif
}
[Inline]
[RequiredByBartok]
internal static Object newIsInstanceOfNonNullSimple(VTable v,
Object obj,
int vtargetDepth) {
return checkDisplay(v, obj.vtable, vtargetDepth)
? obj : null;
}
[Inline]
internal static Object newIsInstanceOfSimple(VTable v,
Object obj,
int vtargetDepth) {
if(obj == null) {
return null;
}
return newIsInstanceOfNonNullSimple(v, obj, vtargetDepth);
}
[NoInline]
internal static Object newIsInstanceOfHelp(VTable v,
Object obj) {
int vtargetDepth = v.depth;
if(vtargetDepth < Constants.TypeTestDisplayPosCache) {
return null;
}
VTable vobj = obj.vtable;
if(isValidAssignment(v.vtableType, vobj.vtableType)) {
v.posCache = vobj;
return obj;
}
return null;
}
[Inline]
[RequiredByBartok]
internal static Object newIsInstanceOfNonNullComplex(VTable v,
Object obj,
int vtargetDepth) {
return checkDisplay(v, obj.vtable, vtargetDepth)
? obj : newIsInstanceOfHelp(v, obj);
}
[Inline]
internal static Object newIsInstanceOfComplex(VTable v,
Object obj,
int vtargetDepth) {
if(obj == null) {
return null;
}
return newIsInstanceOfNonNullComplex(v, obj, vtargetDepth);
}
[Inline]
[RequiredByBartok]
internal static void newCheckClassCastNonNullSimple(VTable v,
object obj,
int vtargetDepth) {
if(!checkDisplay(v, obj.vtable, vtargetDepth)) {
#if SINGULARITY
Tracing.Log(Tracing.Debug,
"newCheckClassCastNonNullSimple failed: v={0:x8} obj={1:x8} vtd={2}",
Magic.addressOf(v),
Magic.addressOf(obj),
unchecked((uint)vtargetDepth));
#endif
throwNewClassCastException();
}
}
[Inline]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
[RequiredByBartok]
internal static void newCheckClassCastSimple(VTable v,
object obj,
int vtargetDepth) {
if(obj == null) {
return;
}
newCheckClassCastNonNullSimple(v, obj, vtargetDepth);
}
[NoInline]
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
internal static void newCheckClassCastHelp(VTable v,
VTable vobj) {
int vtargetDepth = v.depth;
if(vtargetDepth == Constants.TypeTestDisplayPosCache
&& isValidAssignment(v.vtableType, vobj.vtableType)) {
v.posCache = vobj;
return;
}
#if SINGULARITY
Tracing.Log(Tracing.Debug,
"newCheckClassCastHelp failed: v={0:x8} vobj={1:x8}",
Magic.addressOf(v),
Magic.addressOf(vobj));
#endif
throwNewClassCastException();
}
[Inline]
[RequiredByBartok]
internal static void newCheckClassCastNonNullComplex(VTable v,
object obj,
int vtargetDepth) {
VTable vobj = obj.vtable;
if(!checkDisplay(v, vobj, vtargetDepth)) {
newCheckClassCastHelp(v, vobj);
}
}
[Inline]
[RequiredByBartok]
internal static void newCheckClassCastComplex(VTable v,
object obj,
int vtargetDepth) {
if(obj == null) {
return;
}
newCheckClassCastNonNullComplex(v, obj, vtargetDepth);
}
/*
[NoInline]
internal static void newCheckArrayStoreHelp(VTable v,
VTable vobj) {
int vtargetDepth = v.depth;
if(vtargetDepth == Constants.TypeTestDisplayPosCache
&& isValidAssignment(v.vtableType, vobj.vtableType)) {
v.posCache = vobj;
return;
}
throwNewArrayTypeMismatchException();
}
[NoInline]
internal static void newCheckArrayStore(object obj1,object obj2) {
Assert(obj1.vtable.vtableType.IsArray);
if(obj2 == null) {
return;
}
// can't put an object into a primitive array, but we can probably
// guarantee that this is never called on a primitive type array
VTable obj1ElemTy = obj1.vtable.arrayElementClass;
VTable obj2Ty = obj2.vtable;
Deny(obj1ElemTy.vtableType.IsPrimitive);
if(checkDisplay(obj1ElemTy, obj2Ty, obj1ElemTy.depth)) {
return;
}
newCheckArrayStoreHelp(obj1ElemTy, obj2Ty);
}
*/
#endif // OLD_FAST_TESTS
[NoInline]
internal static bool shouldDoCallTrace() {
return VTable.runtimeInitialized && !VTable.callTraceInProgress;
}
[NoInline]
internal static void callTrace(Object o) {
if(o == null) {
VTable.DebugPrint("null");
return;
}
VTable.callTraceInProgress = true;
try {
VTable.DebugPrint(o.ToString());
} catch(Exception) {
VTable.DebugPrint("exn");
}
VTable.callTraceInProgress = false;
}
// Bartok intrinsics
[Intrinsic]
internal static extern ulong mulUIntUIntToULong(uint x, uint y);
internal static extern bool BuildC2Mods
{
[Intrinsic]
get;
}
[System.Diagnostics.Conditional("DEBUG")]
[NoInline]
private static void initTypePrint(RuntimeType ty, String s)
{
if (VTable.enableDebugPrint) {
#if ALLOW_BOOT_ARGLIST
DebugPrint("initType({0}.{1}): {2}\n",
__arglist(ty.Namespace, ty.Name, s));
#endif
}
}
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
internal static void InitializeLimitedType(Type t)
{
2008-11-17 18:29:00 -05:00
InitializeLimitedType(Magic.toRuntimeType(t));
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
[NoBarriers]
2008-03-05 09:52:00 -05:00
[PreInitRefCounts]
private static void InitializeLimitedType(RuntimeType ty)
{
#if SINGULARITY_KERNEL
Tracing.Log(Tracing.Debug, "InitializeLimitedType({0}.{1}",
ty.Namespace, ty.Name);
//DebugStub.WriteLine("InitializeLimitedType({0}.{1})",
//__arglist(ty.Namespace, ty.Name));
#endif
// Null check is needed because Bartok can remove static type
// constructors and we don't have a good framework for removing the
// static initialization of those types (particularly in
// VTable.Initialize).
if(ty.cctor != UIntPtr.Zero) {
Magic.calli(ty.cctor);
}
ty.cctorState = TypeInitState.Completed;
}
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 legitimate rationale. A bug exists in the database for all
// intractable violations, listing each one including this one. This violation
// is somewhat intractable because initType requires a link check and yet it
// is potentially called from stack linking code that cannot tolerate any
// linking.
//
// We need to rethink the .NET model for implicit lazy class initialization,
// since it is hard to reason about the failure points.
//
// Bug 436
[NoStackLinkCheckTransCut]
2008-03-05 09:52:00 -05:00
[RequiredByBartok]
2008-11-17 18:29:00 -05:00
[CalledRarely]
2008-03-05 09:52:00 -05:00
internal static void initType(RuntimeType ty) {
// Abort early if the type has already been initialized.
if (ty.cctorState == TypeInitState.Completed) {
return;
}
// Or if it doesn't have a class constructor.
if (ty.cctor == UIntPtr.Zero) {
ty.cctorState = TypeInitState.Completed;
return;
}
#if SINGULARITY_KERNEL
if (!multiThreaded) {
//DebugStub.WriteLine("initType({0}.{1}) - singlethreaded",
//__arglist(ty.Namespace, ty.Name));
switch(ty.cctorState) {
case TypeInitState.Ready:
initTypePrint(ty, "ready");
ty.cctorState = TypeInitState.Running;
try {
initTypePrint(ty, "running");
Magic.calli(ty.cctor);
} catch (Exception e) {
initTypePrint(ty, "failed");
// Wrap the type initializer exception
// appropriately and save it for future calls.
ty.cctorState = TypeInitState.Failed;
Exception exn
= new TypeInitializationException(ty.FullName, e);
ty.cctorException = exn;
throw exn;
}
initTypePrint(ty, "complete");
ty.cctorState = TypeInitState.Completed;
return;
case TypeInitState.Failed:
initTypePrint(ty, "previous failure");
throw ty.cctorException;
case TypeInitState.Completed:
initTypePrint(ty, "already completed");
return;
default:
initTypePrint(ty, "selfloop or finished");
if (ty.cctorState == TypeInitState.Failed) {
initTypePrint(ty, "clash finished - failed");
throw ty.cctorException;
}
return;
}
}
//DebugStub.WriteLine("initType({0}.{1}) - multithreaded",
//__arglist(ty.Namespace, ty.Name));
#endif
// Get global lock - must have to read/write any thread/type
// wait dependencies. Also used for some things that possibly
// should be shifted to the type locks.
// BUGBUG: The local lock used below is the RuntimeType object. We
// can't use VTable since interfaces do not currently have VTable
// objects. But RuntimeType is exposed to users and thus this is
// incorrect.
Monitor.Enter(VTable.cctorLock);
switch(ty.cctorState) {
case TypeInitState.Ready:{
initTypePrint(ty, "ready");
// Record that this thread is running this type initializer.
Thread t = Thread.CurrentThread;
ty.cctorThread = t;
ty.cctorState = TypeInitState.Running;
// Get local lock - must have to actually run an initializer
// and thus also to check if one is done. We are done setting
// global state and ready to run the local (type) initializer;
// therefore we can dump the global lock now as well.
lock (ty) { // .classVtable) {
Monitor.Exit(VTable.cctorLock);
// we don't need to start with "initialize base and
// all interfaces" because the compiler explicitly
// add calls to the base and interfaces ..ctor in
// current type's ..cctor.
// Run the type initializer, if it exists.
if (ty.cctor != UIntPtr.Zero) {
try {
initTypePrint(ty, "running");
Magic.calli(ty.cctor);
} catch(Exception e) {
initTypePrint(ty, "failed");
// Wrap the type initializer exception
// appropriately and save it for future calls.
ty.cctorState = TypeInitState.Failed;
ty.cctorThread = null;
Exception exn = new TypeInitializationException
(ty.FullName, e);
ty.cctorException = exn;
throw exn;
}
}
initTypePrint(ty, "complete");
ty.cctorState = TypeInitState.Completed;
ty.cctorThread = null;
}
return;
}
case TypeInitState.Running:{
initTypePrint(ty, "clash");
// Try to grab the local lock. This seems somewhat confusing
// to me but I'll follow the CLR code for now (see
// VM\class.cpp:EEClass::DoRunClassInit()). It is important
// to do the TryEnter() as we need to detect circular
// dependencies.
Thread runningThread = ty.cctorThread;
bool gotIt = Monitor.TryEnter(ty); // .classVtable);
if (gotIt) {
initTypePrint(ty, "selfloop or finished");
// If we succeed in getting the lock, then either the
// class finished between the switch statement and here
// (setting complete/fail does not require the global
// lock...) or this thread is attempting circular
// initialization. In the former we need to check for
// success/failure; in the latter we just return to
// prevent deadlock (state will still be Running and thus
// not Failed).
Monitor.Exit(ty); // .classVtable);
Monitor.Exit(VTable.cctorLock);
if (ty.cctorState == TypeInitState.Failed) {
initTypePrint(ty, "clash finished - failed");
throw ty.cctorException;
}
return;
} else {
initTypePrint(ty, "blocked by another thread");
// Check and see if blocking this thread to wait for the
// type to complete initialization will cause a deadlock.
// To do this, see which thread is initializing the type
// and then follow the blocking threads. This thread
// can not be at any of the intermediate (next blocking
// thread is non-null) points as by definition they are
// blocked and can't have reached here.
Thread currentThread = Thread.CurrentThread;
Thread blockingThread = runningThread;
VTable.Assert(blockingThread != null);
while(blockingThread.blockingCctorThread != null) {
blockingThread = blockingThread.blockingCctorThread;
}
if(currentThread == blockingThread) {
// Circular dependency. Give up on "finished
// initialization" guaranties and just return.
initTypePrint(ty, "circular");
Monitor.Exit(VTable.cctorLock);
return;
}
// Set us as blocked by this type, release the global
// lock, and wait for the type to complete initialization.
// REVIEW: I have concerns about the lack of lock around
// setting the block to null. Come back to this!
currentThread.blockingCctorThread = runningThread;
Monitor.Exit(VTable.cctorLock);
lock (ty) {} // .classVtable) {}
currentThread.blockingCctorThread = null;
// The type has finished initialization. As above, the
// two possible cases are Completed and Failed.
if(ty.cctorState == TypeInitState.Failed) {
throw ty.cctorException;
}
return;
}
}
case TypeInitState.Failed:
initTypePrint(ty, "previous failure");
Monitor.Exit(VTable.cctorLock);
throw ty.cctorException;
case TypeInitState.Completed:
initTypePrint(ty, "already completed");
Monitor.Exit(VTable.cctorLock);
return;
}
}
2008-11-17 18:29:00 -05:00
[NoStackLinkCheckTransCut]
2008-03-05 09:52:00 -05:00
[NoInline]
internal static void throwNewClassCastException() {
throw new InvalidCastException();
}
[NoInline]
internal static void throwNewArgumentOutOfRangeException() {
throw new ArgumentOutOfRangeException();
}
2008-11-17 18:29:00 -05:00
// Rationale for cutting the fact that no stack probes are permitted in this
// tree of calls:
//
// Without this, then trees of code that cannot probe (like the stack link and
// unlink code itself) cannot use arrays. This is too high a burden. Instead,
// we change it to the *unchecked* requirement that this code cannot attempt to
// over-index an array. There is a bug that captures the fact that we cannot
// check this behavior.
//
// Bug 436
[NoStackLinkCheckTransCut]
2008-03-05 09:52:00 -05:00
[NoInline]
[RequiredByBartok]
internal static void throwNewIndexOutOfRangeException() {
throw new IndexOutOfRangeException();
}
[NoInline]
[RequiredByBartok]
internal static void throwNewStringIndexOutOfRangeException() {
throw new ArgumentOutOfRangeException();
}
[NoInline]
internal static void throwNewArrayTypeMismatchException() {
throw new ArrayTypeMismatchException();
}
2008-11-17 18:29:00 -05:00
// Rationale for cutting the fact that no stack probes are permitted in this
// tree of calls:
//
// Without this, then trees of code that cannot probe (like the stack link and
// unlink code itself) cannot use arrays. This is too high a burden. Instead,
// we change it to the *unchecked* requirement that this code cannot attempt to
// over-index an array. There is a bug that captures the fact that we cannot
// check this behavior.
//
// Bug 436
[NoStackLinkCheckTransCut]
2008-03-05 09:52:00 -05:00
[NoInline]
[AccessedByRuntime("referenced from halasm.asm")]
internal static void throwNewOverflowException() {
2008-11-17 18:29:00 -05:00
#if DEBUG && SINGULARITY
DebugStub.WriteLine("Overflow exception");
DebugStub.Break();
#endif
2008-03-05 09:52:00 -05:00
throw new OverflowException();
}
2008-11-17 18:29:00 -05:00
// Rationale for cutting the fact that no stack probes are permitted in this
// tree of calls:
//
// Without this, then trees of code that cannot probe (like the stack link and
// unlink code itself) cannot use arrays. This is too high a burden. Instead,
// we change it to the *unchecked* requirement that this code cannot attempt to
// over-index an array. There is a bug that captures the fact that we cannot
// check this behavior.
//
// Bug 436
[NoStackLinkCheckTransCut]
2008-03-05 09:52:00 -05:00
[NoInline]
[RequiredByBartok]
internal static void throwNewDivideByZeroException() {
throw new DivideByZeroException();
}
2008-11-17 18:29:00 -05:00
[NoStackLinkCheckTransCut]
2008-03-05 09:52:00 -05:00
[NoInline]
[RequiredByBartok]
internal static void throwNewArithmeticException() {
throw new ArithmeticException();
}
[System.Diagnostics.Conditional("DEBUG")]
2008-11-17 18:29:00 -05:00
// Rationale for cutting the fact that no stack probes are permitted in this
// tree of calls:
//
// This is DEBUG-only code. It is reachable from every interface call, which
// means we would have to effectively prevent usage of interface calls when
// stack probes are transitively forbidden. This is a needless burden for
// DEBUG-only code.
[NoStackLinkCheckTransCut]
[StackLinkCheck]
2008-03-05 09:52:00 -05:00
private static void profileInterfaceOffset(VTable v, RuntimeType ty,
int index) {
// REVIEW: Counts could be off in a multithreaded setting, but these
// are just debug counts and if extra hashtables are allocated or
// increments are missed it's not that big of a deal.
// index ignored
if(VTable.runtimeInitialized && VTable.enableDumpInterface) {
if(VTable.interfaceOffsetTable == null) {
VTable.interfaceOffsetTable =
new System.Collections.Hashtable();
}
System.Collections.Hashtable h = (System.Collections.Hashtable)
VTable.interfaceOffsetTable[v];
if(h == null) {
VTable.interfaceOffsetTable[v] = h =
new System.Collections.Hashtable();
}
MutableInt32 m = (MutableInt32) h[ty];
if(m == null) {
h[ty] = new MutableInt32(1);
} else {
m.Value++;
}
}
}
[DisableBoundsChecks]
[RequiredByBartok]
internal static IntPtr interfaceOffset(VTable v,RuntimeType ty) {
InterfaceInfo[] interfaces = v.interfaces;
VTable.Assert(interfaces != null);
int numInterfaces = interfaces.Length;
int i;
for(i=0; i<numInterfaces; ++i) {
if(interfaces[i].type == ty) {
break;
}
}
profileInterfaceOffset(v, ty, i);
VTable.Assert(i != numInterfaces);
return interfaces[i].offset;
}
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(24)]
[RequiredByBartok]
internal static extern int doubleToInt(double d);
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(28)]
[RequiredByBartok]
internal static extern long doubleToLong(double d);
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(20)]
[RequiredByBartok]
internal static extern int floatToInt(float f);
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(24)]
[RequiredByBartok]
internal static extern long floatToLong(float f);
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(24)]
[RequiredByBartok]
internal static extern int checkedDoubleToInt(double d);
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(28)]
[RequiredByBartok]
internal static extern long checkedDoubleToLong(double d);
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(20)]
[RequiredByBartok]
internal static extern int checkedFloatToInt(float f);
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(24)]
[RequiredByBartok]
internal static extern long checkedFloatToLong(float f);
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(12)]
[RequiredByBartok]
internal static extern float floatRem(float f1, float f2);
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(20)]
[RequiredByBartok]
internal static extern double doubleRem(double d1, double d2);
// mulSigned64Bit: signed 2's complement 64-bit multiplication with
// overflow checking.
//
// x,y and the result are represented in 2's complement. The
// following algorithm is used:
// Compute the sign of x*y.
// Compute |x| * |y| using unsigned arithmetic
// If the sign of the result is non-negative
// Check that x*y <= 2^(n-1)-1.
// If the sign of the result is negative,
// Check that x*y <= 2^(n-1).
// Convert back to 2's complement:
// 2^n - x*y
[RequiredByBartok]
static public long mulOverflowSigned64Bit(long x,long y) {
bool isPositive = true;
if (x < 0) {
x = -x;
isPositive = false;
}
if (y < 0) {
y = -y;
isPositive = !isPositive;
}
ulong result = mulOverflowUnsigned64Bit((ulong) x, (ulong) y);
if (isPositive) {
if (result <= 0x7FFFFFFFFFFFFFFF) {
return (long) result;
} else {
VTable.throwNewOverflowException();
return 0;
}
} else {
if (result <= 0x8000000000000000) {
return -((long) result);
} else {
VTable.throwNewOverflowException();
return 0;
}
}
}
[RequiredByBartok]
// unsigned 64-bit multiplication with overflow checking
static public ulong mulOverflowUnsigned64Bit(ulong x,ulong y) {
uint loX = (uint) x;
uint hiX = (uint) (x >> 32);
uint loY = (uint) y;
uint hiY = (uint) (y >> 32);
if (hiX > 0 && hiY > 0) {
VTable.throwNewOverflowException();
}
ulong result = mulUIntUIntToULong(loY, loX);
checked {
result = result + (((ulong) (loX * hiY)) << 32);
result = result + (((ulong) (loY * hiX)) << 32);
}
return result;
}
[RequiredByBartok]
// unsigned 64-bit multiplication with no overflow checking
static public ulong mulUnsigned64Bit(ulong x,ulong y) {
uint loX = (uint) x;
uint hiX = (uint) (x >> 32);
uint loY = (uint) y;
uint hiY = (uint) (y >> 32);
ulong result = mulUIntUIntToULong(loY, loX);
result = result + (((ulong) (loX * hiY)) << 32);
result = result + (((ulong) (loY * hiX)) << 32);
return result;
}
2008-11-17 18:29:00 -05:00
[RequiredByBartok]
static public ulong doubleToULong(double val) {
double two63 = 2147483648.0 * 4294967296.0;
ulong ret;
if (val < two63) {
ret = (ulong)doubleToLong(val);
} else {
// subtract 0x8000000000000000, do the convert then add
// it back again
ret = (ulong)doubleToLong(val - two63) + (0x8000000000000000L);
}
return ret;
}
[RequiredByBartok]
static public ulong checkedDoubleToULong(double val) {
double two64 = 4294967296.0 * 4294967296.0;
// Note that this expression also works properly for val = NaN case
if (val > -1.0 && val < two64) {
const double two63 = 2147483648.0 * 4294967296.0;
ulong ret;
if (val < two63) {
ret = (ulong)doubleToLong(val);
} else {
// subtract 0x8000000000000000, do the convert then add
// it back again
ret = (ulong)doubleToLong(val - two63) + (0x8000000000000000L);
}
return ret;
}
// throw
VTable.throwNewOverflowException();
return 0;
}
2008-03-05 09:52:00 -05:00
public const bool enableLibraryOptions = true;
internal static bool enableDebugPrint = false; /*true to log initType calls*/
2008-11-17 18:29:00 -05:00
internal static bool enableUserTiming = false;
2008-03-05 09:52:00 -05:00
internal static bool enableGCVerify = false;
internal static bool enableGCProfiling = false;
internal static bool enableGCTiming = false;
2008-11-17 18:29:00 -05:00
internal static bool enableFinalGCTiming = false;
2008-03-05 09:52:00 -05:00
internal static bool enableGCAccounting = false;
2008-11-17 18:29:00 -05:00
internal static bool enableGCAccurateHeapSize = false;
2008-03-05 09:52:00 -05:00
internal static bool enableDumpMemStats = false;
internal static bool enableDumpMultiUseWords = false;
internal static bool enableDumpInterface = false;
internal static bool enableDumpTryAllStats = false;
2008-11-17 18:29:00 -05:00
internal static int beforeUser;
internal static int afterUser;
2008-03-05 09:52:00 -05:00
[NoHeapAllocation]
public static bool EnableLibraryNotImplemented() {
return(false);
}
[NoHeapAllocation]
public static bool EnableLibraryAsserts() {
return(true);
}
[NoHeapAllocation]
public static void NotImplemented() {
failAssert("Not implemented.");
}
[NoHeapAllocation]
public static void NotImplemented(String msg) {
failAssert(/*"Not implemented: "+*/msg);
}
[System.Diagnostics.Conditional("DEBUG")]
[NoInline]
[NoHeapAllocation]
public static void NotReached() {
failAssert("Unreachable code reached.");
}
[System.Diagnostics.Conditional("DEBUG")]
[NoInline]
[NoHeapAllocation]
public static void NotReached(String msg) {
failAssert(/*"Unreachable code reached: "+*/msg);
}
[System.Diagnostics.Conditional("DEBUG")]
[NoInline]
[ManualRefCounts]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[NoStackLinkCheckTrans]
2008-03-05 09:52:00 -05:00
public static void Assert(bool expr) {
if (VTable.enableLibraryOptions && EnableLibraryAsserts() && !expr) {
failAssert(null);
}
}
[System.Diagnostics.Conditional("DEBUG")]
[NoInline]
[ManualRefCounts]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[NoStackLinkCheckTrans]
2008-03-05 09:52:00 -05:00
public static void Deny(bool expr) {
if (VTable.enableLibraryOptions && EnableLibraryAsserts() && expr) {
failAssert(null);
}
}
[System.Diagnostics.Conditional("DEBUG")]
[NoInline]
[NoHeapAllocation]
public static void AssertForRedundant(bool expr) {
if (!expr) {
failAssert(null);
}
}
[System.Diagnostics.Conditional("DEBUG")]
[NoInline]
[NoHeapAllocation]
public static void DenyForRedundant(bool expr) {
AssertForRedundant(!expr);
}
[System.Diagnostics.Conditional("DEBUG")]
[NoInline]
[ManualRefCounts]
[NoHeapAllocation]
public static void Assert(bool expr, String s) {
if (VTable.enableLibraryOptions && EnableLibraryAsserts() && !expr) {
failAssert(s);
}
}
[System.Diagnostics.Conditional("DEBUG")]
[NoInline]
[NoHeapAllocation]
public static void Deny(bool expr, String s) {
if (VTable.enableLibraryOptions && EnableLibraryAsserts() && expr) {
failAssert(s);
}
}
2008-11-17 18:29:00 -05:00
// Rationale for cutting the fact that no stack probes are permitted in this
// tree of calls:
//
// * Asserts are debug only.
// * When an assert fails, a future stack overflow is not our biggest problem.
// * We want the ability to freely assert in trees that forbid stack probes.
[NoStackLinkCheckTransCut]
2008-03-05 09:52:00 -05:00
[ManualRefCounts]
[NoHeapAllocation]
private static void failAssert(String s) {
#if SINGULARITY
if (s != null) {
Tracing.Log(Tracing.Notice, "Assertion failed: {0}\n", s);
} else {
Tracing.Log(Tracing.Notice, "Assertion failed\n");
}
#endif
// DebugPrintSpinLock();
// DebugPrint(Thread.currentThread().toString());
if (s != null) {
DebugPrint("Assertion failed: {0}\n", __arglist(s));
}
else {
DebugPrint("Assertion failed.\n");
}
// Thread.DebugDumpThreadAnchorTable(0);
DebugBreak();
// DebugPrintSpinUnlock();
}
#if SINGULARITY_KERNEL || SINGULARITY_PROCESS
// Note confusion: This DebugPrint is an unconditional output to stderr,
// not something that only prints in BRT debug modes.
[RequiredByBartok]
[NoHeapAllocation]
static public void DebugPrint(String v)
{
DebugStub.Print(v);
}
[NoHeapAllocation]
static public void DebugPrint(String v, __arglist)
{
DebugStub.Print(v, new ArgIterator(__arglist));
}
[NoHeapAllocation]
static public void DebugPrint(String v, ArgIterator args)
{
DebugStub.Print(v, args);
}
[RequiredByBartok]
static public void DebugPrint(int v)
{
DebugStub.Print("{0}", __arglist(v));
}
[RequiredByBartok]
static public void DebugPrint(long v)
{
DebugStub.Print("{0}", __arglist(v));
}
[NoHeapAllocation]
static public void DebugBreak()
{
DebugStub.Break();
}
#else // not SINGULARITY
// Note confusion: This DebugPrint is an unconditional output to stderr,
// not something that only prints in BRT debug modes.
[RequiredByBartok]
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(312)]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static public extern void DebugPrint(String v);
[MethodImpl(MethodImplOptions.InternalCall)]
//[StackBound(610)]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static private unsafe extern void DebugPrintHelper(char *p_str, int length);
const int DEBUG_MESSAGE_BUFFER_SIZE = 4095;
[NoHeapAllocation]
static public unsafe void DebugPrint(String v, ArgIterator args)
{
char *memBuffer = stackalloc char[DEBUG_MESSAGE_BUFFER_SIZE+1];
// note that we save 1 for the null character
int stringLength = String.LimitedFormatTo(v, args, memBuffer, DEBUG_MESSAGE_BUFFER_SIZE);
VTable.Assert(stringLength <= DEBUG_MESSAGE_BUFFER_SIZE, "String.LimitedFormatTo returned an impossibly large stringLength");
// null terminate the string
DebugPrintHelper(memBuffer, stringLength);
}
[NoHeapAllocation]
static public void DebugPrint(String v, __arglist)
{
DebugPrint(v, new ArgIterator(__arglist));
}
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(610)]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static public extern void DebugPrint(byte v);
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(610)]
[RequiredByBartok]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static public extern void DebugPrint(int v);
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(618)]
[RequiredByBartok]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static public extern void DebugPrint(long v);
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(618)]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static public extern void DebugPrint(ulong v);
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(618)]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static public extern void DebugPrint(int v, int width);
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(626)]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static public extern void DebugPrint(long v, int width);
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static public extern void DebugPrint(ulong v, int width);
[NoHeapAllocation]
static public void DebugPrint(bool b)
{
if (b) {
DebugPrint("true");
}
else {
DebugPrint("false");
}
}
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(638)]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static public extern void DebugDump(object o);
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(638)]
[NoHeapAllocation]
2008-11-17 18:29:00 -05:00
[GCAnnotation(GCOption.NOGC)]
2008-03-05 09:52:00 -05:00
static public extern void DebugBreak();
#endif
[AccessedByRuntime("referenced from halexn.cpp")]
[NoHeapAllocation]
static public bool IsExceptionHandler(Type t,Exception e) {
Type s = e.vtable.vtableType;
// check whether s is a subtype of t
do {
if (s==t) {
return true;
}
s = s.BaseType;
} while (s != null);
return false;
}
#if SINGULARITY
static public String[] ParseArgs(String[] args)
#else
[AccessedByRuntime("referenced from brtmain.cpp")]
static public String[] ParseArgs()
#endif
{
#if !SINGULARITY
String[] args = System.Environment.GetCommandLineArgs();
#endif
int i=0;
2008-11-17 18:29:00 -05:00
#if !SINGULARITY_KERNEL
2008-03-05 09:52:00 -05:00
++i; // dump program name argument
2008-11-17 18:29:00 -05:00
#endif
2008-03-05 09:52:00 -05:00
for( ; i<args.Length; ++i) {
String arg = args[i];
if(!arg.StartsWith("--brt")) {
break;
}
if(arg == "--brt-debug") {
VTable.enableDebugPrint = true;
continue;
}
2008-11-17 18:29:00 -05:00
#if !SINGULARITY
if(arg == "--brt-one-cpu") {
Thread.SetOneCPU();
continue;
}
#endif
if(arg == "--brt-user-timing") {
VTable.enableUserTiming = true;
beforeUser = Environment.TickCount;
continue;
}
if(arg == "--brt-stw-retrace") {
GC.enableSTWRetrace = true;
continue;
}
2008-03-05 09:52:00 -05:00
if(arg == "--brt-gc-verify") {
VTable.enableGCVerify = true;
continue;
}
if(arg == "--brt-gc-profiling") {
VTable.enableGCProfiling = true;
continue;
}
if(arg == "--brt-gc-timing") {
VTable.enableGCTiming = true;
continue;
}
2008-11-17 18:29:00 -05:00
if(arg == "--brt-final-gc-timing") {
VTable.enableFinalGCTiming = true;
continue;
}
2008-03-05 09:52:00 -05:00
if(arg == "--brt-gc-accounting") {
VTable.enableGCAccounting = true;
continue;
}
2008-11-17 18:29:00 -05:00
if(arg == "--brt-gc-heapsize") {
VTable.enableGCAccurateHeapSize = true;
2008-03-05 09:52:00 -05:00
continue;
}
if(arg == "--brt-dump-memstats") {
VTable.enableDumpMemStats = true;
continue;
}
if(arg == "--brt-dump-muw") {
VTable.enableDumpMultiUseWords = true;
continue;
}
if(arg == "--brt-dump-interface") {
VTable.enableDumpInterface = true;
continue;
}
if(arg == "--brt-tryallchecksize") {
++i;
if(i==args.Length) {
DebugPrint
("--brt-tryallchecksize requires argument\r\n");
DebugBreak();
}
try {
int tryAllSize = Int32.Parse(args[i]);
// check that it's a power of two
VTable.Assert
((tryAllSize > 0)
&& (((tryAllSize - 1) & tryAllSize) == 0),
"--brt-tryallchecksize must be a power of two");
VTable.tryAllCheckMask = tryAllSize - 1;
} catch(FormatException) {
DebugPrint
("--brt-tryallchecksize requires argument\r\n");
DebugBreak();
}
continue;
}
if(arg == "--brt-dump-tryallstats") {
VTable.enableDumpTryAllStats = true;
continue;
}
if(arg == "--brt-countgc-trigger") {
#if !SINGULARITY || ADAPTIVE_COPYING_COLLECTOR || SEMISPACE_COLLECTOR
switch(GC.gcType) {
case GCType.AdaptiveCopyingCollector:
case GCType.SemispaceCollector: {
++i;
if(i==args.Length) {
DebugPrint("--brt-countgc-trigger requires argument\r\n");
DebugBreak();
}
try {
short countGCTrigger = Int16.Parse(args[i]);
if(countGCTrigger == -1) {
countGCTrigger = Int16.MaxValue;
}
2008-11-17 18:29:00 -05:00
GCs.GenerationalGCData.gcFrequencyTable
[(int)GCs.GenerationalGCData.MIN_GENERATION] = countGCTrigger;
2008-03-05 09:52:00 -05:00
} catch(FormatException) {
DebugPrint("--brt-countgc-trigger requires argument\r\n");
DebugBreak();
}
break;
}
}
#endif
continue; // argument loop
}
if(arg == "--brt-promotegc-trigger") {
#if !SINGULARITY || ADAPTIVE_COPYING_COLLECTOR || SEMISPACE_COLLECTOR
switch(GC.gcType) {
case GCType.AdaptiveCopyingCollector:
case GCType.SemispaceCollector: {
++i;
if(i==args.Length) {
DebugPrint("--brt-promotegc-trigger requires argument\r\n");
DebugBreak();
}
try {
long promotedGCTrigger = Int64.Parse(args[i]);
if(promotedGCTrigger == -1L) {
promotedGCTrigger = Int64.MaxValue;
}
2008-11-17 18:29:00 -05:00
GCs.GenerationalGCData.gcPromotedLimitTable
[(int)GCs.GenerationalGCData.MIN_GENERATION] = (UIntPtr) promotedGCTrigger;
2008-03-05 09:52:00 -05:00
} catch(FormatException) {
DebugPrint
("--brt-promotegc-trigger requires argument\r\n");
DebugBreak();
}
break;
}
}
#endif
continue; // argument loop
}
if(arg == "--brt-nurserysize") {
#if !SINGULARITY || ADAPTIVE_COPYING_COLLECTOR || SEMISPACE_COLLECTOR
switch(GC.gcType) {
case GCType.AdaptiveCopyingCollector:
case GCType.SemispaceCollector: {
++i;
if(i==args.Length) {
DebugPrint
("--brt-nurserysize requires argument\r\n");
DebugBreak();
}
try {
2008-11-17 18:29:00 -05:00
GCs.GenerationalGCData.nurserySize = (UIntPtr)
2008-03-05 09:52:00 -05:00
UInt64.Parse(args[i]);
} catch(FormatException) {
DebugPrint("--brt-nurserysize-trigger requires argument\r\n");
DebugBreak();
}
break;
}
}
#endif
continue; // argument loop
}
2008-11-17 18:29:00 -05:00
if(arg == "--brt-maxheapsizekb") {
Assert(GC.HeapSizeConfigurable,
"not compiled with /heapsizeconfigurable");
++i;
if(i==args.Length) {
DebugPrint
("--brt-maxheapsizekb requires argument\r\n");
DebugBreak();
}
try {
int maxheapsizekb = Int32.Parse(args[i]);
GC.MaxHeapPages =
maxheapsizekb >>
(GCs.PageTable.PageBits-10);
} catch(FormatException) {
DebugPrint("--brt-maxheapsizekb requires argument\r\n");
DebugBreak();
}
continue; // argument loop
}
2008-03-05 09:52:00 -05:00
/*
if(arg == "--brt-ssbsize") {
++i;
if(i==args.Length) {
DebugPrint
("--brt-ssbsize requires argument\r\n");
DebugBreak();
}
try {
SequentialStoreBuffer.??? = Int32.Parse(args[i]);
} catch(FormatException) {
DebugPrint
("--brt-ssbsize requires argument\r\n");
DebugBreak();
}
continue;
}
*/
if(arg == "--brt-gctrace-filter") {
++i;
if(i==args.Length) {
DebugPrint
("--brt-gctrace-filter requires argument\r\n");
DebugBreak();
}
try {
System.GCs.Trace.filter = (UIntPtr)
UInt64.Parse(args[i], System.Globalization.NumberStyles.AllowHexSpecifier);
} catch(FormatException) {
DebugPrint
("--brt-gctrace-filter requires a hex argument\r\n");
DebugBreak();
}
continue;
}
if(arg == "--brt-gctrace-filter-range") {
i += 2;
if(i >= args.Length) {
DebugPrint
("--brt-gctrace-filter-range requires two hex arguments\r\n");
DebugBreak();
}
try {
System.GCs.Trace.filterLow = (UIntPtr)
UInt64.Parse(args[i-1], System.Globalization.NumberStyles.AllowHexSpecifier);
System.GCs.Trace.filterHigh = (UIntPtr)
UInt64.Parse(args[i], System.Globalization.NumberStyles.AllowHexSpecifier);
} catch(FormatException) {
DebugPrint
("--brt-gctrace-filter-range requires two hex arguments\r\n");
DebugBreak();
}
continue;
}
if(arg == "--brt-gctrace-filter-area") {
++i;
if(i >= args.Length) {
DebugPrint
("--brt-gctrace-filter-area requires hex argument\r\n");
DebugBreak();
}
try {
System.GCs.Trace.filterArea = (System.GCs.Trace.Area)
Int32.Parse(args[i], System.Globalization.NumberStyles.AllowHexSpecifier);
} catch(FormatException) {
DebugPrint
("--brt-gctrace-filter-area requires hex argument\r\n");
DebugBreak();
}
continue;
}
DebugPrint("Unrecognized BRT option: {0}\n", __arglist(arg));
DebugBreak();
}
2008-11-17 18:29:00 -05:00
if(VTable.enableGCAccounting) {
GCs.MemoryAccounting.Initialize(GC.gcType);
}
int mainArgsLength = args.Length - i;
VTable.Assert(mainArgsLength >= 0,
"negative number of args to Main");
String[] mainArgs = new String[mainArgsLength];
2008-03-05 09:52:00 -05:00
for(int j=0; i<args.Length; ++i, ++j) {
mainArgs[j] = args[i];
}
return mainArgs;
}
// This method is modified by Bartok.
// It calls profiling dump functions.
[RequiredByBartok]
[NoInline]
private static void Shutdown() {}
// REVIEW: We need to make sure that this is called for all exit modes.
// Right now we have normal exit, exception exit, and Environment.Exit,
// but we probably want an OS hook. Also, nothing important to
// shutdown happens here anyway.
#if SINGULARITY
private static int hasShutdownStarted = 0;
#endif
2008-11-17 18:29:00 -05:00
#if !SINGULARITY
[AccessedByRuntime("Referenced from brtmain.cpp")]
#endif
2008-03-05 09:52:00 -05:00
static public void Shutdown(int exitCode) {
2008-11-17 18:29:00 -05:00
if (fDebug) {
VTable.DebugPrint("shutdown called with exitCode = ");
VTable.DebugPrint(exitCode);
VTable.DebugPrint("\n");
}
if (VTable.enableUserTiming) {
int afterUser = Environment.TickCount;
VTable.DebugPrint("wall-clock time spent in user code = ");
VTable.DebugPrint(afterUser-beforeUser);
VTable.DebugPrint("\n");
}
GC.Shutdown();
2008-03-05 09:52:00 -05:00
#if SINGULARITY_KERNEL
if (Interlocked.CompareExchange(ref hasShutdownStarted, 1, 0) != 0) {
return;
}
Kernel.Shutdown(exitCode);
#elif SINGULARITY_PROCESS
if (Interlocked.CompareExchange(ref hasShutdownStarted, 1, 0) != 0) {
return;
}
Finalizer.Shutdown();
#else
if(Interlocked.CompareExchange(ref Environment.hasShutdownStarted,
1, 0) != 0) {
return;
}
Finalizer.Shutdown();
#endif
VTable.Shutdown();
if(VTable.enableDumpMultiUseWords) {
MultiUseWord.DumpTables();
}
if(VTable.enableDumpInterface) {
if(VTable.interfaceOffsetTable != null) {
foreach(System.Collections.DictionaryEntry d
in VTable.interfaceOffsetTable) {
VTable v = (VTable) d.Key;
foreach(System.Collections.DictionaryEntry d2
in (System.Collections.Hashtable) d.Value) {
RuntimeType ty = (RuntimeType) d2.Key;
MutableInt32 m = (MutableInt32) d2.Value;
int num = m.Value;
IntPtr index = interfaceOffset(v, ty);
DebugPrint("{0} - {1}: {2}\n",
__arglist(v.vtableType.FullName,
ty.FullName,
num));
}
}
}
}
#if !VC
if(VTable.enableDumpTryAllStats) {
TryAllCounters.DumpRegisteredCounters();
}
#endif
int size = handle_counts.Length;
if(size > 4) {
for(int i = 0; i < size; i++) {
if(handle_counts[i] == 0) {
continue;
}
DebugPrint("{0:d3}: {1}\n", __arglist(i, handle_counts[i]));
}
}
GC.DestructHeap();
}
[AccessedByRuntime("referenced from halexn.cpp")]
static public void TerminateByException(Exception e) {
RuntimeType rt = (RuntimeType)e.GetType();
DebugPrint("\n");
DebugPrint("Unhandled Exception ({0}.{1}):\n",
__arglist(rt.Namespace, rt.Name));
DebugPrint(" {0}\n", __arglist(e.Message));
try {
DebugPrint(" {0}\n", __arglist(e.ToString()));
} catch(Exception) {
try {
DebugPrint("\n Exception.ToString() failed.\n");
} catch (Exception) {
}
} finally {
Shutdown(-2);
}
DebugBreak();
}
static public void DumpException(Exception e) {
RuntimeType rt = (RuntimeType)e.GetType();
DebugPrint("Handled Exception ({0}.{1}):\n",
__arglist(rt.Namespace, rt.Name));
DebugPrint(" {0}\n", __arglist(e.Message));
try {
DebugPrint(" {0}\n", __arglist(e.ToString()));
} catch(Exception) {
try {
DebugPrint(" Exception.ToString() failed.\n");
} catch (Exception) {
}
} finally {
}
}
[RequiredByBartok]
public static void init(object obj) {
}
2008-11-17 18:29:00 -05:00
private static bool fDebug { get { return false; } }
2008-03-05 09:52:00 -05:00
}
}