Skip to content

[EnC] Switch to lazy MethodDesc creation for methods/fields added to existing generic instantiations #127851

@kotlarmilos

Description

@kotlarmilos

Background

When EnC adds a new method or field to a generic type, EEClass::AddMethod (and EEClass::AddField) eagerly walk every loaded assembly's m_AvailableParamTypes hash to find each existing instantiation of the modified type and attach the new MethodDesc/FieldDesc to it. This eager walk has two problems:

  1. Pre-existing race. Even with m_AvailableTypesLock held throughout the iteration, another thread can begin building a new instantiation, read the EEClass method list before the EnC apply mutates it, and publish the resulting MethodTable after the EnC walk completes. That instantiation is silently missing the new method/field. Holding the lock longer narrows the window but does not close it.

  2. Lock-level / reentrancy. EEClass::AddMethod for a generic method routes through InstantiatedMethodDesc::SetupGenericMethodDefinition, which itself takes CrstAvailableParamTypes to publish the new method's TypeVarTypeDesc into Module.m_GenericParamToDescMap. If the inner acquire targets a different loader module's lock instance, the lock-level ordering check fires in checked builds and would deadlock in release.

Proposed fix

Switch from eager attachment to lazy attachment, matching how the type loader handles other generic-instantiation lookups today.

  1. Drop the per-instantiation walk in EEClass::AddMethod (vm/class.cpp lines ~692-755) and EEClass::AddField (vm/class.cpp lines ~380-422). The new MethodDesc/FieldDesc is only added to the canonical/generic EEClass.

  2. Lazily create the per-instantiation MethodDesc in MethodTable::GetParallelMethodDescForEnC (vm/methodtable.cpp line ~7878). When the iterator-based search returns no match on the instantiation MT but the canonical MT has a matching EnC-added MD, create the per-instantiation MD on demand via EEClass::AddMethodDesc and append it to the chain. Same treatment for fields via the analogous lookup path.

  3. Resolve the contract mismatch. GetParallelMethodDescForEnC is currently declared NOTHROW; GC_NOTRIGGER; MODE_ANY. EEClass::AddMethodDesc is THROWS; GC_NOTRIGGER; MODE_COOPERATIVE and allocates from LoaderHeap. Two options: relax the contracts on GetParallelMethodDesc and audit the ~16 call sites, or introduce a separate EnsureParallelMethodDesc API that callers invoke from safe contexts before the cheap lookup.

  4. Add concurrency control to prevent two threads from racing to lazily create the same per-instantiation MD.

  5. Apply symmetrically to fields so the EnC AddField path follows the same model.

Reference: #127755

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions