Skip to content

Conversation

@davidwrighton
Copy link
Member

@davidwrighton davidwrighton commented May 19, 2025

Use the barrier approach to make this safe. Adding an address dependency got into lots of details around possibly needing an entire new stub type, and several paths through this code already depend on the concept of having a barrier here. To support modifying the stubs without inserting lots of magic number, rework how stubs are identified to just do a complete compare of the entire assembly stub in a way which will be easily to generalize to the cDAC.

In addition, make changes to make the FixupPrecode path safe from the same memory ordering concerns. Since the FixupPrecode always goes through a specified entrypoint, we can slide the barrier into only the slow path as long as we ensure that the Target field written with a VolatileStore after the MethodDesc and PrecodeFixupThunk fields are set. To ensure that the barrier on the writer side has happened before with hit the barrier on the reader, we ensure that the Target field is initialized into an infinite loop before the code associated with the FixupPrecode is mapped into the process.

Fixes #113810

Also, this is now only enabled for scenarios where it is required. (Mac Catalyst and iOS).

… stream of assembly data instead of the current approach.
…e DAC. cDAC isn't done yet, but it should be simpler than the confusion that is today's implementation.
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

@davidwrighton
Copy link
Member Author

/azp list

@azure-pipelines
Copy link

CI/CD Pipelines for this repository:

@davidwrighton
Copy link
Member Author

/azp run runtime-diagnostics

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@davidwrighton davidwrighton marked this pull request as ready for review May 21, 2025 21:49
Copilot AI review requested due to automatic review settings May 21, 2025 21:49
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for dynamic helper stub precodes (version 3) by switching to a full-byte-pattern comparison approach and integrates it into both the managed contracts and native runtime metadata.

  • Introduces PrecodeStubs_3_Impl with ReadBytesAndCompare for stub/fixup detection and updates the factory to return version 3.
  • Extends PrecodeMachineDescriptor (native) with full stub/fixup byte arrays and ignore masks, and initializes them in CDacPlatformMetadata.
  • Updates allocation and detection in precode.h/.cpp, VM startup, DAC tables, and ARM64 thunk templates to use the new patterns.

Reviewed Changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
PrecodeStubs_3.cs New v3 contract API using full-byte comparisons
PrecodeStubs_2.cs, PrecodeStubs_1.cs Ensure v2/v1 chaining still works
PrecodeStubsFactory.cs Register version 3 in factory switch
readytoruninfo.cpp, loaderallocator.hpp Switch dynamic helper allocation to AllocStub()
precode.h, precode.cpp Remove magic offsets, add Is*ByASM_DAC, use full-byte compare
cdacplatformmetadata.{hpp,cpp}, dacvars.h, datadescriptor.h Add new DAC fields & initialization for byte-pattern data
arm64 thunktemplates.* Insert memory-barrier (dmb ishld) for stubs
contracts.jsonc Bump PrecodeStubs contract version to 3
dactable.cpp, enummem.cpp Include new platform metadata header
clrfeatures.cmake Enable FEATURE_STUBPRECODE_DYNAMIC_HELPERS on AMD64/ARM64
PrecodeStubs.md Document v3 byte-pattern approach

@max-charlamb
Copy link
Member

/azp run runtime-diagnostics

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jkotas
Copy link
Member

jkotas commented May 21, 2025

Any numbers for the worst-case perf regressions that we expect to get from this change?

@LuckyXu-HF
Copy link
Contributor

LuckyXu-HF commented Jul 4, 2025

cc @LuckyXu-HF, @shushanhf for LA64.

Thank you very much and sorry for late reply, based on the latest commit:9c17ab8f7 the LA64 CoreRoot and libraries tests looks good:

Release-CoreRoot-SPC-PE32+-pri1: Total: 14967 ; Passed: 14912 ; Failed: 0 ; Skipped: 55 ; Time: 2306.321s ; PassRate: 100%
Debug-CoreRoot-SPC-PE32+-pri1: Total: 14967 ; Passed: 14912 ; Failed: 0 ; Skipped: 55 ; Time: 18435.866s ; PassRate: 100%
Release-libs.tests-SPC-PE32+: TestDirList:258 ; Total: 701594 ; Passed: 699950 ; Errors: 0 ; Failed: 0 ; Skipped: 1644 ; Time: 4238.85s ; PassRate: 100%

@jkotas
Copy link
Member

jkotas commented Jul 4, 2025

@max-charlamb Could you please review the new Precode data contract and the cDac related changes?

@max-charlamb max-charlamb force-pushed the enable_FEATURE_STUBPRECODE_DYNAMIC_HELPERS_again branch from dc2f322 to 71b3876 Compare July 7, 2025 18:29
Copy link
Member

@max-charlamb max-charlamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cDAC changes look good to me.

Currently the runtime-diagnostics pipeline isn't verifying the cDAC correctly. #117100 will fix the issue, in the mean-team I put up a test PR to run these changes with my fixes #117382

Copy link
Member

@max-charlamb max-charlamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#117382 passed runtime-diagnostics

lgtm from a cDAC perspective

@davidwrighton

This comment was marked as outdated.

@risc-vv
Copy link

risc-vv commented Jul 8, 2025

RISC-V Release-CLR-QEMU: 9080 / 9110 (99.67%)
=======================
      passed: 9080
      failed: 2
     skipped: 599
      killed: 28
------------------------
 TOTAL tests: 9709
VIRTUAL time: 36h 23min 3s 938ms
   REAL time: 37min 10s 621ms
=======================

report.xml, report.md, failures.xml, testclr_details.tar.zst

RISC-V Release-FX-VF2: 508987 / 510675 (99.67%)
=======================
      passed: 508987
      failed: 1677
     skipped: 39
      killed: 11
------------------------
 TOTAL tests: 510714
VIRTUAL time: 22h 28min 34s 778ms
   REAL time: 2h 16min 1s 530ms
=======================

report.xml, report.md, failures.xml, testclr_details.tar.zst

Build information and commands

GIT: f6142235a6c94e60e25302928d45840215fddefe
CI: 78e142fd33020d1c98d51294d2e82d7c5be9fbf2
REPO: dotnet/runtime
BRANCH: main
CONFIG: Release
LIB_CONFIG: Release

@davidwrighton davidwrighton dismissed sirntar’s stale review July 8, 2025 21:20

@sirntar isn't responding, and I believe I've addressed his feedback.

@risc-vv
Copy link

risc-vv commented Jul 8, 2025

RISC-V Release-CLR-QEMU: 9080 / 9110 (99.67%)
=======================
      passed: 9080
      failed: 2
     skipped: 599
      killed: 28
------------------------
 TOTAL tests: 9709
VIRTUAL time: 37h 19min 18s 388ms
   REAL time: 38min 6s 756ms
=======================

report.xml, report.md, failures.xml, testclr_details.tar.zst

RISC-V Release-CLR-VF2: 9081 / 9111 (99.67%)
=======================
      passed: 9081
      failed: 2
     skipped: 599
      killed: 28
------------------------
 TOTAL tests: 9710
VIRTUAL time: 11h 25min 38s 955ms
   REAL time: 46min 17s 413ms
=======================

report.xml, report.md, failures.xml, testclr_details.tar.zst

RISC-V Release-FX-QEMU: 275736 / 276816 (99.61%)
=======================
      passed: 275736
      failed: 1072
     skipped: 39
      killed: 8
------------------------
 TOTAL tests: 276855
VIRTUAL time: 32h 41min 34s 837ms
   REAL time: 1h 11min 21s 708ms
=======================

report.xml, report.md, failures.xml, testclr_details.tar.zst

RISC-V Release-FX-VF2: 307712 / 309349 (99.47%)
=======================
      passed: 307712
      failed: 1628
     skipped: 39
      killed: 9
------------------------
 TOTAL tests: 309388
VIRTUAL time: 21h 0min 16s 735ms
   REAL time: 2h 19min 42s 51ms
=======================

report.xml, report.md, failures.xml, testclr_details.tar.zst

Build information and commands

GIT: 854fd3e1895e651671d9e8de7110b445d19e4514
CI: 78e142fd33020d1c98d51294d2e82d7c5be9fbf2
REPO: dotnet/runtime
BRANCH: main
CONFIG: Release
LIB_CONFIG: Release

Copy link
Member

@sirntar sirntar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
@davidwrighton sorry for delay, I was waiting for the tests to finish to see if there would be any more problems

@risc-vv
Copy link

risc-vv commented Jul 9, 2025

0689a0b is being scheduled for building and testing

GIT: 0689a0b0bcef9d8803fa076ae82aedf6a86a9013
REPO: dotnet/runtime
BRANCH: main

@davidwrighton
Copy link
Member Author

@EgorBot -arm

using System;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

namespace PInvokeBenchmark
{
    public class PInvokeBenchmarks
    {
        // Define a delegate type for our managed function
        private delegate int ManagedDelegate(bool value);
        
        // Define a matching function pointer type for unmanaged calls
        private unsafe delegate int UnmanagedDelegate(bool value);
        
        // The managed implementation
        private static int ManagedImplementation(bool value)
        {
            return value ? 42 : 0;
        }
        
        // Our instance of the delegate
        private readonly ManagedDelegate _managedDelegate;
        
        // Marshaled function pointer
        private readonly unsafe delegate* unmanaged<bool, int> _nativeFunctionPointer;
        
        // Delegate wrapping the marshaled function pointer
        private readonly unsafe delegate* unmanaged<bool, int> _unmanagedDelegate;

        // P/Invoke declaration for the native method
        [DllImport(@"C:\temp\pinvokeBench\NativeDll\NativeDll.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern int Method(bool value);


        public unsafe PInvokeBenchmarks()
        {
            // Create the managed delegate
            _managedDelegate = ManagedImplementation;

            // Marshal it to a native function pointer
            _nativeFunctionPointer = (delegate* unmanaged<bool, int>)Marshal.GetFunctionPointerForDelegate(_managedDelegate);

        }

        [Benchmark]
        public unsafe int MarshaledDelegateCall()
        {
            return _nativeFunctionPointer(true);
        }
    }
}

@davidwrighton davidwrighton merged commit 4c4f282 into dotnet:main Jul 9, 2025
98 of 101 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Aug 9, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Intermittent test crash on linux arm64 caused by FEATURE_STUBPRECODE_DYNAMIC_HELPERS

9 participants