Skip to content

Add getWasmTypeSymbol API to JIT-EE interface#123958

Open
Copilot wants to merge 12 commits intomainfrom
copilot/add-new-api-to-clr-jit-ee
Open

Add getWasmTypeSymbol API to JIT-EE interface#123958
Copilot wants to merge 12 commits intomainfrom
copilot/add-new-api-to-clr-jit-ee

Conversation

Copy link
Contributor

Copilot AI commented Feb 3, 2026

Description

Adds CORINFO_WASM_TYPE_SYMBOL_HANDLE getWasmTypeSymbol(CorInfoType* types) to the JIT-EE interface with full cross-layer plumbing.

Changes

New API surface:

  • Introduces CORINFO_WASM_TYPE_SYMBOL_HANDLE handle type
  • Parameter: CorInfoType* array pointer
  • Returns handle to WASM type symbol

Core interface (5 files):

  • Handle typedef in corinfo.h
  • Virtual method in ICorStaticInfo
  • Stub in CorInfoImpl.csNotImplementedException
  • CEEInfo implementation in jitinterface.cppUNREACHABLE()
  • ThunkInput.txt signature + thunk codegen

SuperPMI instrumentation (5 files):

  • LWM entry using DWORDLONG, DWORDLONG mapping
  • Packet 235 in methodcontext enum
  • rec/dmp/rep trio in methodcontext.{h,cpp}
  • MyICJI replay hook
  • interceptor_ICJI recording hook

Auto-generated (7 files):

  • Thunk wrappers, name tables, impl stubs

17 files total, 141 insertions. Functional implementation deferred via placeholder markers.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI assigned Copilot and kg Feb 3, 2026
Copilot AI changed the title [WIP] Add getWasmTypeSymbol API to CLR JIT-EE interface Add getWasmTypeSymbol API to JIT-EE interface Feb 3, 2026
Copilot AI requested a review from kg February 3, 2026 19:27
Copilot finished work on behalf of kg February 3, 2026 19:27
@kg
Copy link
Member

kg commented Feb 3, 2026

@SingleAccretion, I tried having copilot implement your proposed JIT-EE API. Looking at it now, I'm thinking we may want to explicitly pass a count arg after the types arg instead of making it implicit with a null terminator, what do you think? Should we have it accept a SIG_INFO instead of passing a count and type pointers? Were you thinking something else?

@SingleAccretion
Copy link
Contributor

SingleAccretion commented Feb 3, 2026

I'm thinking we may want to explicitly pass a count arg after the types arg instead of making it implicit with a null terminator

Yes, that is a good pattern for such APIs (note CorInfoType[] - of course, in C you have to lower that to pointer + length).

typedef struct CORINFO_JUST_MY_CODE_HANDLE_*CORINFO_JUST_MY_CODE_HANDLE;
typedef struct CORINFO_PROFILING_STRUCT_* CORINFO_PROFILING_HANDLE; // a handle guaranteed to be unique per process
typedef struct CORINFO_GENERIC_STRUCT_* CORINFO_GENERIC_HANDLE; // a generic handle (could be any of the above)
typedef struct CORINFO_WASM_TYPE_SYMBOL_STRUCT_* CORINFO_WASM_TYPE_SYMBOL_HANDLE; // a handle for WASM type symbols
Copy link
Member

Choose a reason for hiding this comment

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

What do we plan to use CORINFO_WASM_TYPE_SYMBOL_HANDLE for?

Copy link
Member

Choose a reason for hiding this comment

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

I'm partially speculating here but I think the idea is that these handles represent entries in the Wasm module's types table. In Wasm one of the first tables is the types table that maps signatures (i.e. (int, int) -> int) to indices, and then all function definitions and indirect calls refer to those signatures by index.
I'm guessing R2R needs to build up a table of these, and this API will be passing it the raw signature and getting back a handle that will eventually go in that table.

Copy link
Contributor

Choose a reason for hiding this comment

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

It is the handle type for an ISymbolNode which would represent the signature array (it is a new kind of symbol, and we'll have a few others as well, e. g. for globals). It's not strictly necessary, we could get away with CORINFO_GENERIC_HANDLE. But it seems like a good thing to make the API a bit more typed for clarity.

Copy link
Member

Choose a reason for hiding this comment

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

we could get away with CORINFO_GENERIC_HANDLE

CORINFO_GENERIC_HANDLE is used for type system things like MethodDescs or TypeDescs that are not ISymbolNode.

globals

We have these today. We use void* for most of them since they are raw addresses that just get embedded into the code . For example, CORINFO_CONST_LOOKUP.addr is ISymbolNode used for globals.

Is the idea that we would use CORINFO_WASM_TYPE_SYMBOL_HANDLE for e.g. addresses of globals as well? If yes, how are we going to reconcile that with void* used for these today?

Copy link
Contributor

Choose a reason for hiding this comment

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

CORINFO_GENERIC_HANDLE is used for type system things like MethodDescs or TypeDescs that are not ISymbolNode

It is not consistent. CORINFO_GENERIC_HANDLE handle field in CORINFO_CONST_LOOKUP is a runtime (symbol) handle. I agree it would not be ideal to perpetuate this overloading.

Is the idea that we would use CORINFO_WASM_TYPE_SYMBOL_HANDLE for e.g. addresses of globals as well? If yes, how are we going to reconcile that with void* used for these today?

Do note that I meant "WASM globals". So for example, we will have an API like: <some handle type> getStackPointerGlobal that would return some WasmGlobalNode("__stack_pointer") : ISymbolNode. It wouldn't make sense for this API to return CORINFO_CONST_LOOKUP like for data/code symbols, since globals can't be accessed indirectly / don't have an address. <some handle type> here could indeed be just void*; consistency with the current proposal for signature/type symbols would have it as CORINFO_WASM_GLOBAL_SYMBOL_HANDLE. So these types would be fully orthogonal to what's used currently for code/data symbols.

@kg
Copy link
Member

kg commented Feb 3, 2026

Is it fine to land this without an implementation? Or do I need to implement the API before it's ready for review? cc @AndyAyersMS

@AndyAyersMS
Copy link
Member

Is it fine to land this without an implementation? Or do I need to implement the API before it's ready for review? cc @AndyAyersMS

How sure are you about the API shape? Usually when I do something like this, I like to plumb through some of the implementation to build confidence that I have the right shape.

@SingleAccretion
Copy link
Contributor

API shape

One thing we may think about is future-proofing the API for vectors. We don't have a CorInfoType for vectors, so it may be a good idea to add an enum like we already have with WasmValueType for just the WASM types.

@kg
Copy link
Member

kg commented Feb 4, 2026

API shape

One thing we may think about is future-proofing the API for vectors. We don't have a CorInfoType for vectors, so it may be a good idea to add an enum like we already have with WasmValueType for just the WASM types.

Yeah, I was thinking about vectors and wondering what the best solution is for those. Could we pass an array of CLASS_HANDLEs instead and then crossgen/the EE is responsible for figuring out the calling convention for things like singleton structs?

@SingleAccretion
Copy link
Contributor

Class handles have the same problem as things like CORINFO_SIG_INFO - they're 'hard to come by'. In the Jit, we only have handles for "non-primitive structs". I. e. the opposite of what we want for this API.

@kg
Copy link
Member

kg commented Feb 4, 2026

I'm working on adding a new derived type of ObjectNode for a wasm type signature and making R2R create one and return a handle for it.

@jkotas
Copy link
Member

jkotas commented Feb 4, 2026

One thing we may think about is future-proofing the API for vectors. We don't have a CorInfoType for vectors, so it may be a good idea to add an enum like we already have with WasmValueType for just the WASM types.

Should this just take the encoded wasm signature of the type (using wasm encoding)? It would save us from problems with encoding the type one way and then re-encoding it in a different way on the other side.

@SingleAccretion
Copy link
Contributor

Should this just take the encoded wasm signature of the type (using wasm encoding)? It would save us from problems with encoding the type one way and then re-encoding it in a different way on the other side.

It could be a blob of bytes. I am not sure it would be a big saving in terms of coupling since we need to produce signatures in the managed compiler as well, straight from a MethodDesc, and that computation must match what the Jit would produce for the same method. We could use binary-encoded signatures for both, but using a more "expanded" exchange type seems more natural.

@jkotas
Copy link
Member

jkotas commented Feb 4, 2026

we need to produce signatures in the managed compiler as well, straight from a MethodDesc

Where do we need to do that?

@SingleAccretion
Copy link
Contributor

SingleAccretion commented Feb 4, 2026

Where do we need to do that?

There are two main places:

  1. Each defined function has a type. Currently we produce them in the object writer. This is not hard to fix if we wanted to move this responsibility to the Jit (it would produce a type signature for each compiled method body).
  2. Undefined imported functions. In the R2R context we will probably have few if any, but in the more general NAOT case you can import random RuntimeImportMethodNodes with managed signatures. You can't really drive this from the Jit side unless you accept needing to, when producing a reloc to a direct call, also in some way "associate" that direct callee with a signature.

There are also probably going to be cases with hand-emitted WASM where we will need to produce hand-crafted signatures that correspond in some fashion to their managed callees, which at that point may be yet to be compiled. This can be solved by delaying the signature realization and assuming the callee is going to be a part of the current compilation, and we will be able to retrieve the Jit-produced signature at object writing time. That's more complexity, however.

@kg
Copy link
Member

kg commented Feb 4, 2026

OK, I plumbed things through at a basic level and verified that the Wasm emitter can get a handle back from the JIT-EE API for a zero-length list of types. Is there more I should do here?

Copilot AI and others added 3 commits February 5, 2026 13:25
Co-authored-by: kg <198130+kg@users.noreply.github.com>
Co-authored-by: kg <198130+kg@users.noreply.github.com>
Update generated files

Fix typo

Checkpoint

Checkpoint

Introduce CorInfoWasmType

Exercise new JIT-EE API in emitter

Address PR feedback

Checkpoint

Fix build

Move type section

Address PR feedback

Move WasmTypeNode.cs next to WasmEmitter.cs
@kg kg force-pushed the copilot/add-new-api-to-clr-jit-ee branch from 0654329 to fbc5ad3 Compare February 5, 2026 21:37
@kg kg marked this pull request as ready for review February 5, 2026 22:05
@kg kg requested a review from MichalStrehovsky as a code owner February 5, 2026 22:05
Copilot AI review requested due to automatic review settings February 5, 2026 22:05
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 a new JIT-EE interface API getWasmTypeSymbol to enable the WebAssembly JIT compiler to obtain type symbol handles for native WASM types. The implementation provides complete cross-layer plumbing from the JIT through the execution engine and AOT compiler, with SuperPMI instrumentation for testing and replay. The actual functional implementation is deferred with placeholder stubs (UNREACHABLE(), NotImplementedException, etc.), making this a pure infrastructure change.

Changes:

  • Introduces CORINFO_WASM_TYPE_SYMBOL_HANDLE handle type and CorInfoWasmType enum to the JIT-EE interface
  • Implements full plumbing through CEEInfo, managed AOT compiler (RyuJit/ReadyToRun), and SuperPMI infrastructure
  • Adds WasmTypeNode to represent WASM type symbols in the AOT dependency graph and updates ObjectNodeSection to include WasmTypeSection

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/coreclr/inc/corinfo.h Defines CORINFO_WASM_TYPE_SYMBOL_HANDLE and CorInfoWasmType enum; adds virtual method to ICorDynamicInfo
src/coreclr/inc/jiteeversionguid.h Updates JIT-EE version GUID to reflect interface change
src/coreclr/inc/icorjitinfoimpl_generated.h Auto-generated: adds method declaration
src/coreclr/jit/ICorJitInfo_names_generated.h Auto-generated: adds API name to enum
src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp Auto-generated: adds wrapper implementation
src/coreclr/jit/emitwasm.cpp Exercises new API during indirect call emission (temporary usage)
src/coreclr/vm/jitinterface.cpp Implements CEEInfo::getWasmTypeSymbol with UNREACHABLE() stub
src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt Adds type mappings and function signature for thunk generation
src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs Defines managed equivalents of handle struct and enum
src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs Auto-generated: adds callback and managed-to-native wrapper
src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_Wasm/WasmTypeNode.cs New file: ObjectNode representing WASM type symbols
src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs Adds WasmTypeSection constant for object file output
src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs Updates to use centralized WasmTypeSection constant; whitespace cleanup
src/coreclr/tools/aot/jitinterface/jitinterface_generated.h Auto-generated: adds callback function pointer
src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Implements stub throwing NotImplementedException
src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs Implements functional version creating WasmTypeNode
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs Adds WasmTypeNodeKey and factory method for WasmTypeNode creation
src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj Adds WasmTypeNode.cs to project
src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h Declares rec/dmp/rep methods and adds Packet_GetWasmTypeSymbol (235)
src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp Implements recording, dump, and replay logic
src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h Adds GetWasmTypeSymbol LightWeightMap entry
src/coreclr/tools/superpmi/superpmi-shared/agnostic.h Defines Agnostic_GetWasmTypeSymbol struct
src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp Implements MyICJI replay hook
src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp Implements recording interceptor
src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp Auto-generated: adds passthrough
src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp Auto-generated: adds counting passthrough

kg and others added 3 commits February 6, 2026 08:42
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…sm/WasmTypeNode.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@kg
Copy link
Member

kg commented Feb 6, 2026

@dotnet/jit-contrib I think this is ready for review now. The plan is to immediately work on further changes to the object writer and R2R after this (together with Adam) to start wiring up relocations that use these new type symbol nodes to emit type indices into our output.

Copy link
Contributor

@SingleAccretion SingleAccretion left a comment

Choose a reason for hiding this comment

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

LGTM with minor comments.

Co-authored-by: Jan Kotas <jkotas@microsoft.com>

private CORINFO_WASM_TYPE_SYMBOL_STRUCT_* getWasmTypeSymbol(CorInfoWasmType* types, nuint typesSize)
{
throw new NotImplementedException();
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the implementation eventually going to do here? Will it look similar to the R2R implementation?

Copy link
Contributor

Choose a reason for hiding this comment

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

It will be identical (and moved back to CorInfoImpl.cs). The reason it is somewhat difficult to start this way is due to the NodeFactory implementation not being shared (which is not ideal).

Copy link
Member

Choose a reason for hiding this comment

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

similar to the R2R implementation

Exactly same as R2R implementation?

Copy link
Contributor

@adamperlin adamperlin left a comment

Choose a reason for hiding this comment

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

I think this looks good to me, though I can't comment on all of the pieces here. I can follow up here with some work to re-use the WasmValueType definitions in CG2 for the new WasmTypeNode as well as updating the ObjectWriter to use the new node.

…foImpl.ReadyToRun.cs

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants