Skip to content

Replace MethodDescCallSite instances with UnmanagedCallersOnlyAttribute pattern #123864

@AaronRobinsonMSFT

Description

@AaronRobinsonMSFT

This issue tracks the work to replace MethodDescCallSite / CallDescrWorker infrastructure with more efficient UnmanagedCallersOnly reverse P/Invoke calls for invoking managed code from native code.

Benefits

  • Significantly reduced overhead for VM-to-managed calls
  • Uses existing reverse P/Invoke infrastructure instead of the expensive CallDescrWorker mechanism
  • Better alignment with modern interop patterns

Pattern

The conversion pattern involves:

  1. Adding [UnmanagedCallersOnly] wrappers to managed methods with an Exception* out-parameter
  2. Using the UnmanagedCallersOnlyCaller template class in C++ to invoke these methods
  3. Updating metasig.h and corelib.h with appropriate signatures

Notes

  • The UnmanagedCallersOnlyCaller template class is defined in callhelpers.h and can be used to invoke the target.
  • WASM builds require regenerating callhelpers-reverse.cpp when adding new UCO methods.

Example PR to follow: #123832

Exception Propagation Helper

Before converting call sites that rely on exception propagation semantics (that is, Main(), finalizer, thread entrypoints`, we need to implement a helper function akin to:

internal static bool PropagateExceptionToNativeCode(Exception e)
{
    // Stack has an assembly's EntryPoint as the last frame in the stack
    if (...)
        return false;

    // Stack has no further managed frames above
    if (...)
        return false;

    return true;
}

This helper will determine whether an exception should be returned via the out-parameter (to be re-thrown by the caller) or left to propagate naturally through the UnmanagedCallersOnly boundary.


Conversion Tasks

Priority 1: Cross-Platform, Simple Conversions

These are straightforward conversions on code paths that run on all platforms.

AppDomain / Assembly Loading (appdomain.cpp) - #123967

  • METHOD__ASSEMBLYLOADCONTEXT__ON_ASSEMBLY_LOAD in AppDomain::RaiseAssemblyLoadEvent
  • METHOD__ASSEMBLYLOADCONTEXT__ON_TYPE_RESOLVE in AppDomain::RaiseTypeResolveEventThrowing
  • METHOD__ASSEMBLYLOADCONTEXT__ON_RESOURCE_RESOLVE in AppDomain::RaiseResourceResolveEvent
  • METHOD__ASSEMBLYLOADCONTEXT__ON_ASSEMBLY_RESOLVE in AppDomain::RaiseAssemblyResolveEvent
  • METHOD__ASSEMBLYLOADCONTEXT__RESOLVE in AppDomain::BindAssemblySpec
  • METHOD__ASSEMBLYLOADCONTEXT__RESOLVESATELLITEASSEMBLY in AppDomain::BindSatelliteResourceByResourceRoots
  • METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUSINGEVENT in AppDomain::RaiseLoadFileEvent

Loader Allocator (loaderallocator.cpp)

  • METHOD__LOADERALLOCATOR__CTOR in LoaderAllocator::Init

Custom Marshaler (custommarshalerinfo.cpp)

  • GetCustomMarshaler method lookup in CustomMarshalerInfo::CustomMarshalerInfo

Dynamic Methods / Resolver (dynamicmethod.cpp)

  • METHOD__RESOLVER__GET_JIT_CONTEXT in LCGMethodResolver::GetJitContext
  • METHOD__RESOLVER__GET_CODE_INFO in LCGMethodResolver::GetCodeInfo
  • METHOD__RESOLVER__GET_LOCALS_SIGNATURE in LCGMethodResolver::GetLocalSig
  • METHOD__RESOLVER__GET_STRING_LITERAL in LCGMethodResolver::GetStringLiteral

Interop Utilities (interoputil.cpp)

  • METHOD__CULTURE_INFO__INT_CTOR in GetCultureInfoForLCID
  • METHOD__COLORMARSHALER__CONVERT_TO_MANAGED in ConvertOleColorToSystemColor
  • METHOD__COLORMARSHALER__CONVERT_TO_NATIVE in ConvertSystemColorToOleColor

Threads / Culture (threads.cpp)

  • METHOD__CULTURE_INFO__GET_CURRENT_CULTURE / METHOD__CULTURE_INFO__GET_CURRENT_UI_CULTURE in Thread::GetCultureInfo
  • METHOD__CULTURE_INFO__SET_CURRENT_CULTURE / METHOD__CULTURE_INFO__SET_CURRENT_UI_CULTURE in Thread::SetCultureInfo

Event Sources (corhost.cpp)

  • METHOD__EVENT_SOURCE__INITIALIZE_DEFAULT_EVENT_SOURCES in CorHost2::CreateAppDomain

Diagnostics (ds-rt-coreclr.h)

  • METHOD__STARTUP_HOOK_PROVIDER__CALL_STARTUP_HOOK in ds_rt_apply_startup_hook

Priority 2: Cross-Platform, Exception Handling

Exception Construction (clrex.cpp)

  • Exception constructor in EEException::CreateThrowable
  • Exception constructor in EEMessageException::CreateThrowable
  • Exception constructor in EEResourceException::CreateThrowable

Exception Construction (excep.cpp)

  • METHOD__RUNTIME_WRAPPED_EXCEPTION__OBJ_CTOR in WrapThrowableInRuntimeWrappedException
  • Various exception constructors in CreateTypeInitializationExceptionObject

Exception Utilities (excep.cpp)

  • METHOD__OBJECT__TO_STRING in GetExceptionMessage
  • METHOD__EXCEPTION__INTERNAL_PRESERVE_STACK_TRACE in RaiseTheExceptionInternalOnly
  • METHOD__ENVIRONMENT__GET_RESOURCE_STRING_LOCAL in GetResourceStringFromManaged
  • Event args constructor in ExceptionNotifications::DeliverExceptionNotification

Exception Info Retrieval (comutilnative.cpp)

  • METHOD__EXCEPTION__GET_MESSAGE in ExceptionNative::GetMessageFromException
  • METHOD__EXCEPTION__GET_CLASS_NAME in ExceptionNative::GetMessageFromException
  • METHOD__EXCEPTION__GET_SOURCE in ExceptionNative::GetSource
  • METHOD__EXCEPTION__GET_HELP_CONTEXT in ExceptionNative::GetHelpContext

Priority 3: Cross-Platform, Entry Points (Complex)

These are entry points or thread-related and require careful consideration.

Application Entry Points (assembly.cpp)

  • Thread start / Main entry point in RunMainInternal
  • METHOD__ASYNC_HELPERS__HANDLE_ASYNC_ENTRYPOINT in RunMainInternal
  • METHOD__ASYNC_HELPERS__HANDLE_ASYNC_ENTRYPOINT_VOID in RunMainInternal
  • METHOD__STARTUP_HOOK_PROVIDER__MANAGED_STARTUP in Assembly::ExecuteMainMethod

Process Lifecycle (appdomain.cpp)

  • METHOD__APPCONTEXT__ON_UNHANDLED_EXCEPTION in AppDomain::RaiseUnhandledExceptionEvent
  • METHOD__APPCONTEXT__ON_PROCESS_EXIT in AppDomain::RaiseExitProcessEvent

Invoke / Reflection (invokeutil.cpp)

  • Constructor invocation in InvokeUtil::CreateObject
  • Constructor invocation in InvokeUtil::CreateValueType

Custom Attributes (customattribute.cpp)

  • Custom attribute constructor in COMCustomAttribute::CreateCaObject

Host Callbacks (corhost.cpp)

  • Method invocation in CorHost2::ExecuteAssembly

Func Eval (funceval.cpp)

  • FuncEvalWrapper() and DoNormalFuncEval()

Priority 4: Platform-Specific (ObjC - macOS/iOS)

ObjC Interop (interoplibinterface_objc.cpp)

  • METHOD__OBJCMARSHAL__AVAILABLEUNHANDLEDEXCEPTIONPROPAGATION in ObjCMarshalNative::GetPropagatingExceptionCallback

Priority 5: Windows-Only (COM Interop)

These files are only compiled on Windows and are lowest priority.

COM Connection Points (comconnectionpoints.cpp)

  • Delegate constructor in ConnectionPoint::Advise
  • Provider method in ConnectionPoint::Advise

Standard Interfaces (stdinterfaces.cpp)

  • CanRead property getter in IDispatchExInfo::GetIDsOfNames
  • CanWrite property getter in IDispatchExInfo::GetIDsOfNames

CLR to COM Calls (clrtocomcall.cpp)

  • METHOD__COM_OBJECT__GET_EVENT_PROVIDER in ComPlusMethodFrame::DoSlowPathComPlusCall
  • Event provider method in ComPlusMethodFrame::DoSlowPathComPlusCall
  • METHOD__CLASS__FORWARD_CALL_TO_INVOKE in CLRToCOMLateBoundWorker

COM Callable Wrapper (comcallablewrapper.cpp)

  • Custom ICustomQueryInterface::GetInterface in ComCallWrapper::CallICustomQueryInterface

Custom Marshaler (custommarshalerinfo.cpp)

  • METHOD__STUBHELPERS__GET_IENUMERATOR_TO_ENUM_VARIANT_MARSHALER in CustomMarshalerInfo::GetIEnumeratorToEnumVariantMarshaler

Runtime Callable Wrapper (runtimecallablewrapper.cpp)

  • METHOD__LICENSE_INTEROP_PROXY__CREATE in LicenseInteropHelper::GetCurrentContextInfo
  • METHOD__LICENSE_INTEROP_PROXY__GETCURRENTCONTEXTINFO in LicenseInteropHelper::GetCurrentContextInfo
  • METHOD__LICENSE_INTEROP_PROXY__SAVEKEYINCURRENTCONTEXT in LicenseInteropHelper::SaveKeyInCurrentContext
  • Delegate method invocation in COMToCLRWorkerBody

OLE Variant (olevariant.cpp)

  • METHOD__VARIANT__CAST_VARIANT in OleVariant::MarshalOleVariantForObject
  • METHOD__VARIANT__CONVERT_VARIANT_TO_OBJECT in OleVariant::MarshalObjectForOleVariant
  • METHOD__VARIANT__CONVERT_OBJECT_TO_VARIANT in OleVariant::MarshalOleVariantForObject

Dispatch Info (dispatchinfo.cpp) - ~30 call sites

Various reflection-based calls in:

  • DispatchMemberInfo::GetParamInfo - parameter name retrieval
  • DispatchMemberInfo::SetUpMethodMarshalerInfo - method handle retrieval
  • DispatchMemberInfo::GetMemberInfoValue - property getters
  • DispatchMemberInfo::SetMemberInfoValue - property setters
  • DispatchExInfo::InvokeMember - member invocation
  • DispatchExInfo::SynchWithManagedView - GetProperties, GetFields, GetMethods
  • DispatchInfo::GetExceptionDescription - exception property getter

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions