public static bool HasCctor(RuntimeTypeHandle typeHandle) { return(RuntimeImports.RhHasCctor(CreateEETypePtr(typeHandle))); }
public static IntPtr RuntimeHandleAllocRefCounted(object value) { return(RuntimeImports.RhHandleAlloc(value, (GCHandleType)RefCountedHandleType)); }
public static void RuntimeHandleFree(IntPtr handle) { RuntimeImports.RhHandleFree(handle); }
public static bool RuntimeRegisterGcCalloutForGCEnd(IntPtr pCalloutMethod) { return(RuntimeImports.RhRegisterGcCallout(RuntimeImports.GcRestrictedCalloutKind.EndCollection, pCalloutMethod)); }
public static bool RuntimeRegisterRefCountedHandleCallback(IntPtr pCalloutMethod, RuntimeTypeHandle pTypeFilter) { return(RuntimeImports.RhRegisterRefCountedHandleCallback(pCalloutMethod, pTypeFilter.ToEETypePtr())); }
// Block until the next finalization pass is complete. public static void WaitForPendingFinalizers() { RuntimeImports.RhWaitForPendingFinalizers(Thread.ReentrantWaitsEnabled); }
public static long GetAllocatedBytesForCurrentThread() { return(RuntimeImports.RhGetAllocatedBytesForCurrentThread()); }
public static RuntimeTypeHandle GetNullableType(RuntimeTypeHandle nullableType) { EETypePtr theT = RuntimeImports.RhGetNullableType(nullableType.ToEETypePtr()); return(new RuntimeTypeHandle(theT)); }
// if functionPointer points at an import or unboxing stub, find the target of the stub public static IntPtr GetCodeTarget(IntPtr functionPointer) { return(RuntimeImports.RhGetCodeTarget(functionPointer)); }
public static bool IsAssignable(Object srcObject, RuntimeTypeHandle dstType) { EETypePtr srcEEType = srcObject.EETypePtr; return(RuntimeImports.AreTypesAssignable(srcEEType, dstType.ToEETypePtr())); }
//============================================================================================== // Nullable<> support //============================================================================================== public static bool IsNullable(RuntimeTypeHandle declaringTypeHandle) { return(RuntimeImports.RhIsNullable(declaringTypeHandle.ToEETypePtr())); }
public static bool IsGenericTypeDefinition(RuntimeTypeHandle typeHandle) { return(RuntimeImports.RhGetEETypeClassification(CreateEETypePtr(typeHandle)) == RuntimeImports.RhEETypeClassification.GenericTypeDefinition); }
public static bool IsUnmanagedPointerType(RuntimeTypeHandle typeHandle) { return(RuntimeImports.RhGetEETypeClassification(CreateEETypePtr(typeHandle)) == RuntimeImports.RhEETypeClassification.UnmanagedPointer); }
public static IntPtr ResolveDispatch(object instance, RuntimeTypeHandle interfaceType, int slot) { return(RuntimeImports.RhResolveDispatch(instance, CreateEETypePtr(interfaceType), checked ((ushort)slot))); }
/// <summary> /// Returns the status of a registered notification about whether a blocking garbage collection /// is imminent. May wait indefinitely for a full collection. /// </summary> /// <returns>The status of a registered full GC notification</returns> public static GCNotificationStatus WaitForFullGCApproach() { return((GCNotificationStatus)RuntimeImports.RhWaitForFullGCApproach(-1)); }
public static int GetCorElementType(RuntimeTypeHandle type) { return((int)RuntimeImports.RhGetCorElementType(type.ToEETypePtr())); }
/// <summary> /// Returns the status of a registered notification about whether a blocking garbage collection /// has completed. May wait indefinitely for a full collection. /// </summary> /// <returns>The status of a registered full GC notification</returns> public static GCNotificationStatus WaitForFullGCComplete() { return((GCNotificationStatus)RuntimeImports.RhWaitForFullGCComplete(-1)); }
// Move memory which may be on the heap which may have object references in it. // In general, a memcpy on the heap is unsafe, but this is able to perform the // correct write barrier such that the GC is not incorrectly impacted. public unsafe static void BulkMoveWithWriteBarrier(IntPtr dmem, IntPtr smem, int size) { RuntimeImports.RhBulkMoveWithWriteBarrier((byte *)dmem.ToPointer(), (byte *)smem.ToPointer(), size); }
/// <summary> /// New AddMemoryPressure implementation (used by RCW and the CLRServicesImpl class) /// 1. Less sensitive than the original implementation (start budget 3 MB) /// 2. Focuses more on newly added memory pressure /// 3. Budget adjusted by effectiveness of last 3 triggered GC (add / remove ratio, max 10x) /// 4. Budget maxed with 30% of current managed GC size /// 5. If Gen2 GC is happening naturally, ignore past pressure /// /// Here's a brief description of the ideal algorithm for Add/Remove memory pressure: /// Do a GC when (HeapStart is less than X * MemPressureGrowth) where /// - HeapStart is GC Heap size after doing the last GC /// - MemPressureGrowth is the net of Add and Remove since the last GC /// - X is proportional to our guess of the ummanaged memory death rate per GC interval, /// and would be calculated based on historic data using standard exponential approximation: /// Xnew = UMDeath/UMTotal * 0.5 + Xprev /// </summary> /// <param name="bytesAllocated"></param> public static void AddMemoryPressure(long bytesAllocated) { if (bytesAllocated <= 0) { throw new ArgumentOutOfRangeException(nameof(bytesAllocated), SR.ArgumentOutOfRange_NeedPosNum); } #if !BIT64 if (bytesAllocated > int.MaxValue) { throw new ArgumentOutOfRangeException(nameof(bytesAllocated), SR.ArgumentOutOfRange_MustBeNonNegInt32); } #endif CheckCollectionCount(); uint p = s_iteration % PressureCount; long newMemValue = InterlockedAddMemoryPressure(ref s_addPressure[p], bytesAllocated); Debug.Assert(PressureCount == 4, "GC.AddMemoryPressure contains unrolled loops which depend on the PressureCount"); if (newMemValue >= MinGCMemoryPressureBudget) { long add = s_addPressure[0] + s_addPressure[1] + s_addPressure[2] + s_addPressure[3] - s_addPressure[p]; long rem = s_removePressure[0] + s_removePressure[1] + s_removePressure[2] + s_removePressure[3] - s_removePressure[p]; long budget = MinGCMemoryPressureBudget; if (s_iteration >= PressureCount) // wait until we have enough data points { // Adjust according to effectiveness of GC // Scale budget according to past m_addPressure / m_remPressure ratio if (add >= rem * MaxGCMemoryPressureRatio) { budget = MinGCMemoryPressureBudget * MaxGCMemoryPressureRatio; } else if (add > rem) { Debug.Assert(rem != 0); // Avoid overflow by calculating addPressure / remPressure as fixed point (1 = 1024) budget = (add * 1024 / rem) * budget / 1024; } } // If still over budget, check current managed heap size if (newMemValue >= budget) { long heapOver3 = RuntimeImports.RhGetCurrentObjSize() / 3; if (budget < heapOver3) //Max { budget = heapOver3; } if (newMemValue >= budget) { // last check - if we would exceed 20% of GC "duty cycle", do not trigger GC at this time if ((RuntimeImports.RhGetGCNow() - RuntimeImports.RhGetLastGCStartTime(2)) > (RuntimeImports.RhGetLastGCDuration(2) * 5)) { RuntimeImports.RhCollect(2, InternalGCCollectionMode.NonBlocking); CheckCollectionCount(); } } } } }
public static IntPtr GetUniversalTransitionThunk() { return(RuntimeImports.RhGetUniversalTransitionThunk()); }
public static bool AreTypesAssignable(RuntimeTypeHandle sourceType, RuntimeTypeHandle targetType) { return(RuntimeImports.AreTypesAssignable(sourceType.ToEETypePtr(), targetType.ToEETypePtr())); }
public static void CallDescrWorker(IntPtr callDescr) { RuntimeImports.RhCallDescrWorker(callDescr); }
public static bool RuntimeRegisterGcCalloutForAfterMarkPhase(IntPtr pCalloutMethod) { return(RuntimeImports.RhRegisterGcCallout(RuntimeImports.GcRestrictedCalloutKind.AfterMarkPhase, pCalloutMethod)); }
internal static IntPtr IDynamicCastableGetInterfaceImplementation(object instance, MethodTable *interfaceType, ushort slot) { RuntimeImports.RhpFallbackFailFast(); return(default);
public static void RuntimeUnregisterRefCountedHandleCallback(IntPtr pCalloutMethod, RuntimeTypeHandle pTypeFilter) { RuntimeImports.RhUnregisterRefCountedHandleCallback(pCalloutMethod, pTypeFilter.ToEETypePtr()); }
private static void SerializeExceptionsForDump(Exception currentException, IntPtr exceptionCCWPtr, LowLevelList <byte[]> serializedExceptions) { const uint NoInnerExceptionValue = 0xFFFFFFFF; // Approximate upper size limit for the serialized exceptions (but we'll always serialize currentException) // If we hit the limit, because we serialize in arbitrary order, there may be missing InnerExceptions or nested exceptions. const int MaxBufferSize = 20000; int nExceptions; RuntimeImports.RhGetExceptionsForCurrentThread(null, out nExceptions); Exception[] curThreadExceptions = new Exception[nExceptions]; RuntimeImports.RhGetExceptionsForCurrentThread(curThreadExceptions, out nExceptions); LowLevelList <Exception> exceptions = new LowLevelList <Exception>(curThreadExceptions); LowLevelList <Exception> nonThrownInnerExceptions = new LowLevelList <Exception>(); uint currentThreadId = (uint)Environment.CurrentNativeThreadId; // Reset nesting levels for exceptions on this thread that might not be currently in flight foreach (KeyValuePair <Exception, ExceptionData> item in s_exceptionDataTable) { ExceptionData exceptionData = item.Value; if (exceptionData.ExceptionMetadata.ThreadId == currentThreadId) { exceptionData.ExceptionMetadata.NestingLevel = -1; } } // Find all inner exceptions, even if they're not currently being handled for (int i = 0; i < exceptions.Count; i++) { if (exceptions[i].InnerException != null && !exceptions.Contains(exceptions[i].InnerException)) { exceptions.Add(exceptions[i].InnerException); nonThrownInnerExceptions.Add(exceptions[i].InnerException); } } int currentNestingLevel = curThreadExceptions.Length - 1; // Make sure we serialize currentException if (!exceptions.Contains(currentException)) { // When this happens, currentException is probably passed to this function through System.Environment.FailFast(), we // would want to treat as if this exception is last thrown in the current thread. exceptions.Insert(0, currentException); currentNestingLevel++; } // Populate exception data for all exceptions interesting to this thread. // Whether or not there was previously data for that object, it might have changed. for (int i = 0; i < exceptions.Count; i++) { ExceptionData exceptionData = s_exceptionDataTable.GetOrCreateValue(exceptions[i]); exceptionData.ExceptionMetadata.ExceptionId = (uint)System.Threading.Interlocked.Increment(ref s_currentExceptionId); if (exceptionData.ExceptionMetadata.ExceptionId == NoInnerExceptionValue) { exceptionData.ExceptionMetadata.ExceptionId = (uint)System.Threading.Interlocked.Increment(ref s_currentExceptionId); } exceptionData.ExceptionMetadata.ThreadId = currentThreadId; // Only include nesting information for exceptions that were thrown on this thread if (!nonThrownInnerExceptions.Contains(exceptions[i])) { exceptionData.ExceptionMetadata.NestingLevel = currentNestingLevel; currentNestingLevel--; } else { exceptionData.ExceptionMetadata.NestingLevel = -1; } // Only match the CCW pointer up to the current exception if (object.ReferenceEquals(exceptions[i], currentException)) { exceptionData.ExceptionMetadata.ExceptionCCWPtr = exceptionCCWPtr; } byte[] serializedEx = exceptions[i].SerializeForDump(); exceptionData.SerializedExceptionData = serializedEx; } // Populate inner exception ids now that we have all of them in the table for (int i = 0; i < exceptions.Count; i++) { ExceptionData exceptionData; if (!s_exceptionDataTable.TryGetValue(exceptions[i], out exceptionData)) { // This shouldn't happen, but we can't meaningfully throw here continue; } if (exceptions[i].InnerException != null) { ExceptionData innerExceptionData; if (s_exceptionDataTable.TryGetValue(exceptions[i].InnerException, out innerExceptionData)) { exceptionData.ExceptionMetadata.InnerExceptionId = innerExceptionData.ExceptionMetadata.ExceptionId; } } else { exceptionData.ExceptionMetadata.InnerExceptionId = NoInnerExceptionValue; } } int totalSerializedExceptionSize = 0; // Make sure we include the current exception, regardless of buffer size ExceptionData currentExceptionData = null; if (s_exceptionDataTable.TryGetValue(currentException, out currentExceptionData)) { byte[] serializedExceptionData = currentExceptionData.Serialize(); serializedExceptions.Add(serializedExceptionData); totalSerializedExceptionSize = serializedExceptionData.Length; } checked { foreach (KeyValuePair <Exception, ExceptionData> item in s_exceptionDataTable) { ExceptionData exceptionData = item.Value; // Already serialized currentException if (currentExceptionData != null && exceptionData.ExceptionMetadata.ExceptionId == currentExceptionData.ExceptionMetadata.ExceptionId) { continue; } byte[] serializedExceptionData = exceptionData.Serialize(); if (totalSerializedExceptionSize + serializedExceptionData.Length >= MaxBufferSize) { break; } serializedExceptions.Add(serializedExceptionData); totalSerializedExceptionSize += serializedExceptionData.Length; } } }
public static void RuntimeHandleSet(IntPtr handle, object value) { RuntimeImports.RhHandleSet(handle, value); }
// Garbage collect all generations. public static void Collect() { //-1 says to GC all generations. RuntimeImports.RhCollect(-1, InternalGCCollectionMode.Blocking); }
public static IntPtr RuntimeHandleAllocDependent(object primary, object secondary) { return(RuntimeImports.RhHandleAllocDependent(primary, secondary)); }
public static bool IsDynamicType(RuntimeTypeHandle typeHandle) { return(RuntimeImports.RhIsDynamicType(CreateEETypePtr(typeHandle))); }