Skip to content

[wasm][R2R] Give the hidden generic context its own token in Wasm signature strings #134716

Description

@lewing

Description

The Wasm signature string (see "Wasm Signature String Encoding" in docs/design/coreclr/botr/readytorun-format.md) has no distinct token for the hidden generic context. WasmLowering.GetSignature emits it as the pointer char (i on wasm32, l on wasm64), which is indistinguishable from an explicit pointer-sized argument. The VM's GetSignatureKey (src/coreclr/vm/wasm/helpers.cpp) does the same when building thunk lookup keys.

Signature-keyed thunks (WasmR2RToInterpreterThunkNode, WasmInterpreterToR2RThunkNode, WasmImportThunk) only have the signature string, so they can recognize the generic context only by position: when the async continuation a immediately follows it. That is WasmLowering.HasGenericContextBeforeAsync, and the special casing built on it in WasmThunkArgLayout and RaiseSignature (including the roundtrip a<ctx> → <ctx>a swap). Without an async continuation this doesn't matter: the hidden-argument slot and the first argument slot are the same, so the layout is identical.

This positional inference is what let the generic context and async continuation get swapped in the first place (#133953, #134660, #133627, fixed in #134676). It was called out in review as a likely source of future bugs.

Proposal

Add a dedicated signature token for the hidden generic context and use it everywhere the semantic signature string is produced or parsed:

  • WasmLowering.GetSignature emits the token when LoweringFlags.HasGenericContextArg is set. The Wasm function type is unchanged (still one pointer-sized param).
  • WasmLowering.RaiseSignature parses it. This removes the roundtrip swap and HasGenericContextBeforeAsync.
  • WasmThunkArgLayout models the generic context as the hidden instantiation argument (methodRequiresInstArg) whenever the token is present, async or not.
  • The VM's GetSignatureKey emits the same token in its semantic (non-Wasm-calling-convention) key, so string lookups for the R2R↔interpreter thunks keep matching.
  • The portable call-helper tokenizer (InteropSignature / InterpToNativeGenerator) and readytorun-format.md learn the token.

Considerations

  • The thunk key strings change on both the crossgen2 and VM sides, so they must change together. Images compiled by an older crossgen2 would register keys that the newer runtime no longer looks up.
  • Signatures that differ only in having a generic context versus an explicit pointer argument would no longer share a thunk. This is a small image-size cost.
  • The structural V keys used by virtual dispatch thunks are unaffected.

Follow-up to #134676.

Note

This issue was drafted with GitHub Copilot.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    arch-wasmWebAssembly architecturearea-ReadyToRununtriagedNew issue has not been triaged by the area owner

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions