Skip to content

[wasm][coreclr] Cache calli cookies#127016

Open
radekdoulik wants to merge 8 commits intodotnet:mainfrom
radekdoulik:pe-cookie-cache
Open

[wasm][coreclr] Cache calli cookies#127016
radekdoulik wants to merge 8 commits intodotnet:mainfrom
radekdoulik:pe-cookie-cache

Conversation

@radekdoulik
Copy link
Copy Markdown
Member

@radekdoulik radekdoulik commented Apr 16, 2026

Avoid repeated expensive calls to get calli cookie by caching it

Checked in HelloWorld

CalliCookie cache: 18 hits, 17 misses, 35 total (51.4% hit rate)

Avoid repeated expensive calls to get calli cookie by caching it
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

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

Copy link
Copy Markdown
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 reduces overhead in the WASM interpreter call path by caching the computed calli cookie on the MethodDesc, avoiding repeated (and potentially expensive) cookie computation for repeated invocations of the same managed method.

Changes:

  • Cache and reuse a per-MethodDesc calli cookie in InvokeManagedMethod on WASM.
  • Extend MethodDescCodeData (portable entrypoints + interpreter builds) to store a CalliCookie.
  • Add MethodDesc::{GetCalliCookie, SetCalliCookie} APIs to manage the cached value thread-safely.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/coreclr/vm/wasm/helpers.cpp Uses MethodDesc-cached cookie to avoid repeated GetCookieForCalliSig calls.
src/coreclr/vm/method.hpp Adds CalliCookie storage in MethodDescCodeData and declares accessor APIs under the relevant feature flags.
src/coreclr/vm/method.cpp Implements thread-safe cookie get/set using EnsureCodeDataExists + interlocked/volatile operations.

Comment thread src/coreclr/vm/wasm/helpers.cpp
Comment thread src/coreclr/vm/wasm/helpers.cpp
Comment thread src/coreclr/vm/method.cpp Outdated
…Cookie typedef

- Define InterpreterCalliCookie typedef: function pointer on WASM,
  CallStubHeader* on non-WASM (Jan's feedback)
- Unify SetCalliCookie/GetCalliCookie API, removing the separate
  SetCallStub/GetCallStub and FEATURE_PORTABLE_ENTRYPOINTS branching
  in MethodDesc
- Cache calli cookie on targetMethod in the WASM calli path in
  interpexec.cpp (Jan's feedback)
- Re-read cookie after SetCalliCookie in wasm/helpers.cpp to use
  the race-winning value (Aaron's feedback)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 26, 2026 20:29
Copy link
Copy Markdown
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

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

Comment thread src/coreclr/vm/wasm/helpers.cpp
Comment thread src/coreclr/vm/jitinterface.cpp Outdated
Comment thread src/coreclr/vm/interpexec.cpp Outdated
Comment thread src/coreclr/vm/interpexec.cpp Outdated
Copilot AI review requested due to automatic review settings April 27, 2026 13:09
Copy link
Copy Markdown
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

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/coreclr/vm/wasm/helpers.cpp:435

  • CalliStubParam::cookie is now typed as InterpreterCalliCookie, but these calls still cast the cookie to void(*)(PCODE, int8_t*, int8_t*). If InterpreterCalliCookie already has that signature in wasm builds, you can invoke it directly without the cast (and it avoids extra reliance on function-pointer casts).
void InvokeCalliStub(CalliStubParam* pParam)
{
    _ASSERTE(pParam->ftn != (PCODE)NULL);
    _ASSERTE(pParam->cookie != NULL);

    // WASM-TODO: Reconcile calling conventions for managed calli.
    PCODE actualFtn = (PCODE)PortableEntryPoint::GetActualCode(pParam->ftn);
    ((void(*)(PCODE, int8_t*, int8_t*))pParam->cookie)(actualFtn, pParam->pArgs, pParam->pRet);
}

void InvokeUnmanagedCalli(PCODE ftn, InterpreterCalliCookie cookie, int8_t *pArgs, int8_t *pRet)
{
    _ASSERTE(ftn != (PCODE)NULL);
    _ASSERTE(cookie != NULL);
    ((void(*)(PCODE, int8_t*, int8_t*))cookie)(ftn, pArgs, pRet);
}

Comment thread src/coreclr/vm/method.hpp
Comment thread src/coreclr/vm/interpexec.cpp
Comment thread src/coreclr/vm/method.cpp
Comment thread src/coreclr/vm/method.hpp Outdated
Comment thread src/coreclr/vm/jitinterface.cpp Outdated
Comment thread src/coreclr/vm/wasm/helpers.cpp Outdated
Copilot AI review requested due to automatic review settings April 27, 2026 18:57
Copy link
Copy Markdown
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

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (3)

src/coreclr/vm/method.hpp:272

  • MethodDescCodeData stores the cached cookie as void*, but the accessor/mutator APIs are typed as InterpreterCalliCookie (which is a function pointer on WASM). This forces repeated casts between function pointers and void* and can trip toolchain warnings / UB concerns. Consider storing the field as InterpreterCalliCookie (or a union/std::atomic<InterpreterCalliCookie>-style storage) so SetCalliCookie/GetCalliCookie don’t need object-pointer casts on portable-entrypoint builds.
#endif // FEATURE_INTERPRETER
#if defined(_DEBUG) && defined(ALLOW_SXS_JIT)
    PatchpointInfo *AltJitPatchpointInfo;
#endif // _DEBUG && ALLOW_SXS_JIT

src/coreclr/vm/method.cpp:290

  • SetCalliCookie currently casts InterpreterCalliCookie to void* for the interlocked CAS. On WASM InterpreterCalliCookie is a function pointer, and function-pointer <-> void* casts are non-standard and may be rejected/warned under some toolchains (especially with -Werror). If possible, make m_codeData->CalliCookie be typed as InterpreterCalliCookie so the CAS can operate on the correctly-typed field without these casts.
    IfFailRet(EnsureCodeDataExists(NULL));

    _ASSERTE(m_codeData != NULL);
    VolatileStoreWithoutBarrier(&m_codeData->AltJitPatchpointInfo, pInfo);
    return S_OK;
}

src/coreclr/vm/wasm/helpers.cpp:598

  • StringToWasmSigThunkHash stores values as void*, but LookupThunk now uses an InterpreterCalliCookie local and passes its address to Lookup via (void**)&thunk. This relies on type-punning a function-pointer object as void* storage. A safer pattern here would be to look up into a void* temp and then cast the returned value to InterpreterCalliCookie for the return.
}

extern "C" void RhpInterfaceDispatch8()
{
    PORTABILITY_ASSERT("RhpInterfaceDispatch8 is not implemented on wasm");

Comment on lines 133 to 141
void InvokeManagedMethod(ManagedMethodParam *pParam);

#ifdef FEATURE_INTERPRETER
struct CalliStubParam
{
PCODE ftn;
void* cookie;
InterpreterCalliCookie cookie;
int8_t *pArgs;
int8_t *pRet;
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

CalliStubParam.cookie is now InterpreterCalliCookie, but interpexec.h doesn’t define that typedef or include the header that does (it relies on build/PCH include order). This makes the header non self-contained and can break compilation for any TU that includes interpexec.h without pulling in method.hpp first. Consider including the defining header here or moving the typedef to a header that interpexec.h already depends on under FEATURE_INTERPRETER.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-VM-coreclr

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants