1985 lines
74 KiB
C#
1985 lines
74 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.
|
||
|
//
|
||
|
|
||
|
#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]
|
||
|
internal sealed class VTable {
|
||
|
[RequiredByBartok]
|
||
|
public readonly VTable depth1;
|
||
|
[RequiredByBartok]
|
||
|
public readonly VTable depth2;
|
||
|
[RequiredByBartok]
|
||
|
public readonly VTable depth3;
|
||
|
[RequiredByBartok]
|
||
|
public readonly VTable depth4;
|
||
|
[RequiredByBartok]
|
||
|
public readonly VTable depth5;
|
||
|
[RequiredByBartok]
|
||
|
public readonly VTable depth6;
|
||
|
public VTable posCache;
|
||
|
[RequiredByBartok]
|
||
|
public int depth;
|
||
|
[RequiredByBartok]
|
||
|
public readonly StructuralType arrayOf;
|
||
|
[RequiredByBartok]
|
||
|
public readonly VTable arrayElementClass;
|
||
|
[RequiredByBartok]
|
||
|
public readonly int arrayElementSize;
|
||
|
[RequiredByBartok]
|
||
|
public readonly InterfaceInfo[] interfaces;
|
||
|
[RequiredByBartok]
|
||
|
public readonly uint baseLength;
|
||
|
[RequiredByBartok]
|
||
|
public readonly uint baseAlignment;
|
||
|
[RequiredByBartok]
|
||
|
public readonly UIntPtr pointerTrackingMask;
|
||
|
[AccessedByRuntime("Referenced from C++")]
|
||
|
public readonly StructuralType structuralView;
|
||
|
[AccessedByRuntime("Referenced from C++")]
|
||
|
public readonly RuntimeType vtableType;
|
||
|
[RequiredByBartok]
|
||
|
public readonly int marshalSize;
|
||
|
[RequiredByBartok]
|
||
|
public readonly VTable vectorClass;
|
||
|
[AccessedByRuntime("Type information available to runtime.")]
|
||
|
public readonly bool isAcyclicRefType;
|
||
|
|
||
|
// one less than size, which must be a power of two
|
||
|
internal static int tryAllCheckMask = 2047;
|
||
|
#if SINGULARITY_KERNEL
|
||
|
private static bool multiThreaded;
|
||
|
#endif
|
||
|
|
||
|
internal class ClassConstructorLock
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public static readonly ClassConstructorLock cctorLock = new ClassConstructorLock();
|
||
|
public static int[] handle_counts = new int[4];
|
||
|
public static bool runtimeInitialized = false;
|
||
|
public static System.Collections.Hashtable interfaceOffsetTable;
|
||
|
public static bool callTraceInProgress;
|
||
|
|
||
|
// 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();
|
||
|
|
||
|
// 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
|
||
|
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;
|
||
|
if(VTable.enableGCAccounting) {
|
||
|
GCs.MemoryAccounting.Initialize(GC.gcType);
|
||
|
}
|
||
|
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
|
||
|
[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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[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
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[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);
|
||
|
}
|
||
|
|
||
|
[PreInitRefCounts]
|
||
|
internal static bool isValidAssignment(RuntimeType ty,RuntimeType objTy) {
|
||
|
return (ty == objTy) || isValidAssignmentMedium(ty, objTy);
|
||
|
}
|
||
|
|
||
|
[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);
|
||
|
}
|
||
|
|
||
|
[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]
|
||
|
[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]
|
||
|
[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]
|
||
|
[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]
|
||
|
[PreInitRefCounts]
|
||
|
[RequiredByBartok]
|
||
|
internal static void newCheckClassCastNonNullExact(VTable v,
|
||
|
object obj,
|
||
|
int vtargetDepth) {
|
||
|
newCheckClassCast(v, obj, vtargetDepth, false, true, true);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[PreInitRefCounts]
|
||
|
[RequiredByBartok]
|
||
|
internal static void newCheckClassCastExact(VTable v,
|
||
|
object obj,
|
||
|
int vtargetDepth) {
|
||
|
newCheckClassCast(v, obj, vtargetDepth, true, true, true);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[PreInitRefCounts]
|
||
|
[RequiredByBartok]
|
||
|
internal static void newCheckClassCastNonNullSimple(VTable v,
|
||
|
object obj,
|
||
|
int vtargetDepth) {
|
||
|
newCheckClassCast(v, obj, vtargetDepth, false, false, true);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[PreInitRefCounts]
|
||
|
[RequiredByBartok]
|
||
|
internal static void newCheckClassCastSimple(VTable v,
|
||
|
object obj,
|
||
|
int vtargetDepth) {
|
||
|
newCheckClassCast(v, obj, vtargetDepth, true, false, true);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[PreInitRefCounts]
|
||
|
[RequiredByBartok]
|
||
|
internal static void newCheckClassCastNonNullComplex(VTable v,
|
||
|
object obj,
|
||
|
int vtargetDepth)
|
||
|
{
|
||
|
newCheckClassCast(v, obj, vtargetDepth, false, false, false);
|
||
|
}
|
||
|
|
||
|
[Inline]
|
||
|
[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]
|
||
|
[PreInitRefCounts]
|
||
|
[RequiredByBartok]
|
||
|
internal static void newCheckClassCastSimple(VTable v,
|
||
|
object obj,
|
||
|
int vtargetDepth) {
|
||
|
if(obj == null) {
|
||
|
return;
|
||
|
}
|
||
|
newCheckClassCastNonNullSimple(v, obj, vtargetDepth);
|
||
|
}
|
||
|
|
||
|
[NoInline]
|
||
|
[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
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[PreInitRefCounts]
|
||
|
internal static void InitializeLimitedType(Type t)
|
||
|
{
|
||
|
InitializeLimitedType((RuntimeType)t);
|
||
|
}
|
||
|
|
||
|
[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;
|
||
|
}
|
||
|
|
||
|
[StackLinkCheck]
|
||
|
[RequiredByBartok]
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[NoInline]
|
||
|
internal static void throwNewClassCastException() {
|
||
|
throw new InvalidCastException();
|
||
|
}
|
||
|
|
||
|
[NoInline]
|
||
|
internal static void throwNewArgumentOutOfRangeException() {
|
||
|
throw new ArgumentOutOfRangeException();
|
||
|
}
|
||
|
|
||
|
[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();
|
||
|
}
|
||
|
|
||
|
[NoInline]
|
||
|
[AccessedByRuntime("referenced from halasm.asm")]
|
||
|
internal static void throwNewOverflowException() {
|
||
|
throw new OverflowException();
|
||
|
}
|
||
|
|
||
|
[NoInline]
|
||
|
[RequiredByBartok]
|
||
|
internal static void throwNewDivideByZeroException() {
|
||
|
throw new DivideByZeroException();
|
||
|
}
|
||
|
|
||
|
[NoInline]
|
||
|
[RequiredByBartok]
|
||
|
internal static void throwNewArithmeticException() {
|
||
|
throw new ArithmeticException();
|
||
|
}
|
||
|
|
||
|
[System.Diagnostics.Conditional("DEBUG")]
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
public const bool enableLibraryOptions = true;
|
||
|
internal static bool enableDebugPrint = false; /*true to log initType calls*/
|
||
|
internal static bool enableGCVerify = false;
|
||
|
internal static bool enableGCProfiling = false;
|
||
|
internal static bool enableGCTiming = false;
|
||
|
internal static bool enableGCAccounting = false;
|
||
|
internal static bool enableGCWatermarks = false;
|
||
|
internal static bool enableDumpMemStats = false;
|
||
|
internal static bool enableDumpMultiUseWords = false;
|
||
|
internal static bool enableDumpInterface = false;
|
||
|
internal static bool enableDumpTryAllStats = false;
|
||
|
|
||
|
[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]
|
||
|
public static void Assert(bool expr) {
|
||
|
if (VTable.enableLibraryOptions && EnableLibraryAsserts() && !expr) {
|
||
|
failAssert(null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[System.Diagnostics.Conditional("DEBUG")]
|
||
|
[NoInline]
|
||
|
[ManualRefCounts]
|
||
|
[NoHeapAllocation]
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[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]
|
||
|
static public extern void DebugPrint(String v);
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
//[StackBound(610)]
|
||
|
[NoHeapAllocation]
|
||
|
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]
|
||
|
static public extern void DebugPrint(byte v);
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(610)]
|
||
|
[RequiredByBartok]
|
||
|
[NoHeapAllocation]
|
||
|
static public extern void DebugPrint(int v);
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(618)]
|
||
|
[RequiredByBartok]
|
||
|
[NoHeapAllocation]
|
||
|
static public extern void DebugPrint(long v);
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(618)]
|
||
|
[NoHeapAllocation]
|
||
|
static public extern void DebugPrint(ulong v);
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(618)]
|
||
|
[NoHeapAllocation]
|
||
|
static public extern void DebugPrint(int v, int width);
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(626)]
|
||
|
[NoHeapAllocation]
|
||
|
static public extern void DebugPrint(long v, int width);
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[NoHeapAllocation]
|
||
|
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]
|
||
|
static public extern void DebugDump(object o);
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||
|
[StackBound(638)]
|
||
|
[NoHeapAllocation]
|
||
|
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;
|
||
|
|
||
|
++i; // dump program name argument
|
||
|
|
||
|
for( ; i<args.Length; ++i) {
|
||
|
String arg = args[i];
|
||
|
if(!arg.StartsWith("--brt")) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(arg == "--brt-debug") {
|
||
|
VTable.enableDebugPrint = true;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
if(arg == "--brt-gc-accounting") {
|
||
|
VTable.enableGCAccounting = true;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(arg == "--brt-gc-watermarks") {
|
||
|
VTable.enableGCWatermarks = true;
|
||
|
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;
|
||
|
}
|
||
|
GCs.GenerationalCollector.gcFrequencyTable
|
||
|
[(int)GCs.GenerationalCollector.MIN_GENERATION] = countGCTrigger;
|
||
|
} 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;
|
||
|
}
|
||
|
GCs.GenerationalCollector.gcPromotedLimitTable
|
||
|
[(int)GCs.GenerationalCollector.MIN_GENERATION] = (UIntPtr) promotedGCTrigger;
|
||
|
} 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 {
|
||
|
GCs.GenerationalCollector.nurserySize = (UIntPtr)
|
||
|
UInt64.Parse(args[i]);
|
||
|
} catch(FormatException) {
|
||
|
DebugPrint("--brt-nurserysize-trigger requires argument\r\n");
|
||
|
DebugBreak();
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
continue; // argument loop
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
String[] mainArgs = new String[args.Length - i];
|
||
|
|
||
|
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
|
||
|
|
||
|
static public void Shutdown(int exitCode) {
|
||
|
#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) {
|
||
|
}
|
||
|
}
|
||
|
}
|