diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 65288617affdce..cd6b359c9f5d76 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -997,6 +997,7 @@ 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 +typedef struct CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_* CORINFO_WASM_GLOBAL_SYMBOL_HANDLE; // a handle for a WASM global symbol // what is actually passed on the varargs call typedef struct CORINFO_VarArgInfo * CORINFO_VARARGS_HANDLE; @@ -1839,6 +1840,19 @@ struct CORINFO_ASYNC_INFO CORINFO_METHOD_HANDLE finishSuspensionWithContinuationContextMethHnd; }; +// The well-known wasm globals that JIT-generated code references via +// WASM_GLOBAL_INDEX_LEB relocations. Each handle is the relocation target for the +// corresponding well-known global; the object writer resolves it to the final wasm global index. +struct CORINFO_WASM_WELLKNOWN_GLOBALS +{ + // Shadow stack pointer global (read at the root frame, then threaded through locals). + CORINFO_WASM_GLOBAL_SYMBOL_HANDLE stackPointer; + // Image base global (__memory_base), added to static data offsets. + CORINFO_WASM_GLOBAL_SYMBOL_HANDLE imageBase; + // Table base global (__table_base), added to funclet pointer offsets. + CORINFO_WASM_GLOBAL_SYMBOL_HANDLE tableBase; +}; + // Flags passed from JIT to runtime. enum CORINFO_GET_TAILCALL_HELPERS_FLAGS { @@ -3209,6 +3223,12 @@ class ICorStaticInfo virtual uint32_t getAddressAlignment( void* address ) = 0; + + // Get the well-known wasm global symbols (shadow stack pointer, image base, table base) + // that JIT-generated wasm code references via WASM_GLOBAL_INDEX_LEB relocations. + virtual void getWasmWellKnownGlobals( + CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut + ) = 0; }; /***************************************************************************** diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index fca6cdb5198cbc..6c0c39f71f0293 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -540,6 +540,9 @@ CorInfoWasmType getWasmLowering( uint32_t getAddressAlignment( void* address) override; +void getWasmWellKnownGlobals( + CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) override; + uint32_t getThreadTLSIndex( void** ppIndirection) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index b66d35a6d89981..e48e375315e0f5 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -37,11 +37,11 @@ #include -constexpr GUID JITEEVersionIdentifier = { /* 24c0b78a-9173-40cd-a6b3-e290fb3c0a22 */ - 0x24c0b78a, - 0x9173, - 0x40cd, - {0xa6, 0xb3, 0xe2, 0x90, 0xfb, 0x3c, 0x0a, 0x22} +constexpr GUID JITEEVersionIdentifier = { /* 65743063-e8fa-41d4-9496-c436974c00f5 */ + 0x65743063, + 0xe8fa, + 0x41d4, + {0x94, 0x96, 0xc4, 0x36, 0x97, 0x4c, 0x00, 0xf5} }; #endif // JIT_EE_VERSIONING_GUID_H diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 91ab585e857e8f..b3ccde2acebc8f 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -134,6 +134,7 @@ DEF_CLR_API(getSwiftLowering) DEF_CLR_API(getFpStructLowering) DEF_CLR_API(getWasmLowering) DEF_CLR_API(getAddressAlignment) +DEF_CLR_API(getWasmWellKnownGlobals) DEF_CLR_API(getThreadTLSIndex) DEF_CLR_API(getAddrOfCaptureThreadGlobal) DEF_CLR_API(getHelperFtn) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index b81544fa82cee6..3f40e71e6bbb26 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1279,6 +1279,14 @@ uint32_t WrapICorJitInfo::getAddressAlignment( return temp; } +void WrapICorJitInfo::getWasmWellKnownGlobals( + CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) +{ + API_ENTER(getWasmWellKnownGlobals); + wrapHnd->getWasmWellKnownGlobals(pWellKnownGlobalsOut); + API_LEAVE(getWasmWellKnownGlobals); +} + uint32_t WrapICorJitInfo::getThreadTLSIndex( void** ppIndirection) { diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 1c00c386259e20..d5860d5495ad66 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -13,8 +13,6 @@ #include "gcinfoencoder.h" static const int LINEAR_MEMORY_INDEX = 0; -// stackPointer is the 0th global in our generated Wasm modules -static const int STACK_POINTER_GLOBAL = 0; #ifdef TARGET_64BIT static const instruction INS_I_load = INS_i64_load; @@ -165,7 +163,8 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni if (!m_compiler->lvaGetDesc(m_compiler->lvaWasmSpArg)->lvIsParam) { initialSPLclIndex = spLclIndex; - GetEmitter()->emitIns_I(INS_global_get, EA_PTRSIZE, STACK_POINTER_GLOBAL); + GetEmitter()->emitIns_I(INS_global_get, EA_HANDLE_CNS_RELOC, + (cnsval_ssize_t)(size_t)m_compiler->eeGetWasmWellKnownGlobals()->stackPointer); GetEmitter()->emitIns_I(INS_local_set, EA_PTRSIZE, initialSPLclIndex); } else diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index b2acfa5e21f7db..7f733cd3e44006 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -9516,6 +9516,13 @@ class Compiler CORINFO_ASYNC_INFO* eeGetAsyncInfo(); +#if defined(TARGET_WASM) + CORINFO_WASM_WELLKNOWN_GLOBALS wasmWellKnownGlobals; + bool wasmWellKnownGlobalsInitialized = false; + + CORINFO_WASM_WELLKNOWN_GLOBALS* eeGetWasmWellKnownGlobals(); +#endif // defined(TARGET_WASM) + // Gets the offset of a SDArray's first element static unsigned eeGetArrayDataOffset(); diff --git a/src/coreclr/jit/ee_il_dll.hpp b/src/coreclr/jit/ee_il_dll.hpp index a64c9ad9698acb..9784b39b5b7157 100644 --- a/src/coreclr/jit/ee_il_dll.hpp +++ b/src/coreclr/jit/ee_il_dll.hpp @@ -187,6 +187,19 @@ inline CORINFO_ASYNC_INFO* Compiler::eeGetAsyncInfo() return &asyncInfo; } +#if defined(TARGET_WASM) +inline CORINFO_WASM_WELLKNOWN_GLOBALS* Compiler::eeGetWasmWellKnownGlobals() +{ + if (!wasmWellKnownGlobalsInitialized) + { + info.compCompHnd->getWasmWellKnownGlobals(&wasmWellKnownGlobals); + wasmWellKnownGlobalsInitialized = true; + } + + return &wasmWellKnownGlobals; +} +#endif // defined(TARGET_WASM) + /***************************************************************************** * * Convert the type returned from the VM to a var_type. diff --git a/src/coreclr/jit/emitfmtswasm.h b/src/coreclr/jit/emitfmtswasm.h index 0f052e198f2f07..2321cbb71ad883 100644 --- a/src/coreclr/jit/emitfmtswasm.h +++ b/src/coreclr/jit/emitfmtswasm.h @@ -33,6 +33,7 @@ IF_DEF(RAW_ULEB128, IS_NONE, NONE) // IF_DEF(CODE_SIZE, IS_NONE, NONE) IF_DEF(ULEB128, IS_NONE, NONE) // IF_DEF(FUNCIDX, IS_NONE, NONE) // +IF_DEF(GLOBALIDX, IS_NONE, NONE) // IF_DEF(SLEB128, IS_NONE, NONE) // IF_DEF(MEMADDR, IS_NONE, NONE) // IF_DEF(FUNCPTR, IS_NONE, NONE) // diff --git a/src/coreclr/jit/emitwasm.cpp b/src/coreclr/jit/emitwasm.cpp index d16867bc8ccc56..212fe17655c1e8 100644 --- a/src/coreclr/jit/emitwasm.cpp +++ b/src/coreclr/jit/emitwasm.cpp @@ -184,12 +184,12 @@ bool emitter::emitInsIsStore(instruction ins) //------------------------------------------------------------------------ // emitAddressConstant: Emit a memory address constant, like an indirection cell. -// This will automatically make use of relocations and the module base (__r2r_start). +// This will automatically make use of relocations and the module base (imageBase). void emitter::emitAddressConstant(void* address) { - // Load our module base from __r2r_start, then load our address constant, then sum them. - // FIXME-WASM: Make this a named constant or a reloc that crossgen2 fills in. - emitIns_I(INS_global_get, EA_4BYTE, 1 /* __r2r_start */); + // Load our module base from the image base global, then load our address constant, then sum them. + emitIns_I(INS_global_get, EA_HANDLE_CNS_RELOC, + (cnsval_ssize_t)(size_t)m_compiler->eeGetWasmWellKnownGlobals()->imageBase); emitIns_I(INS_i32_const_address, EA_SET_FLG(EA_PTRSIZE, EA_CNS_RELOC_FLG), (cnsval_ssize_t)address); emitIns(INS_i32_add); } @@ -197,7 +197,8 @@ void emitter::emitAddressConstant(void* address) void emitter::emitFuncletAddressConstant(cnsval_ssize_t funcletId) { // Load our table base, then load our funclet pointer offset, then sum them. - emitIns_I(INS_global_get, EA_4BYTE, 2 /* __table_start */); + emitIns_I(INS_global_get, EA_HANDLE_CNS_RELOC, + (cnsval_ssize_t)(size_t)m_compiler->eeGetWasmWellKnownGlobals()->tableBase); emitIns_I(INS_i32_const_funcletptr, EA_PTRSIZE, (cnsval_ssize_t)funcletId); emitIns(INS_i32_add); } @@ -670,6 +671,7 @@ unsigned emitter::instrDesc::idCodeSize() const } case IF_FUNCIDX: case IF_ULEB128: + case IF_GLOBALIDX: size += idIsCnsReloc() ? PADDED_RELOC_SIZE : SizeOfULEB128(emitGetInsSC(this)); break; case IF_MEMADDR: @@ -957,6 +959,12 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) dst += emitOutputConstant(dst, id, UNSIGNED, CorInfoReloc::WASM_FUNCTION_INDEX_LEB); break; } + case IF_GLOBALIDX: + { + dst += emitOutputOpcode(dst, ins); + dst += emitOutputConstant(dst, id, UNSIGNED, CorInfoReloc::WASM_GLOBAL_INDEX_LEB); + break; + } case IF_CALL_INDIRECT: { dst += emitOutputOpcode(dst, ins); @@ -1241,6 +1249,7 @@ void emitter::emitDispIns( case IF_RAW_ULEB128: case IF_ULEB128: case IF_FUNCIDX: + case IF_GLOBALIDX: { cnsval_ssize_t imm = emitGetInsSC(id); printf(" %llu", (uint64_t)imm); diff --git a/src/coreclr/jit/instrswasm.h b/src/coreclr/jit/instrswasm.h index 90e87b177e7cba..34c60c1517e518 100644 --- a/src/coreclr/jit/instrswasm.h +++ b/src/coreclr/jit/instrswasm.h @@ -56,25 +56,25 @@ INST(call_funclet, "call.funclet", 0, IF_FUNCLETIDX, 0x10) INST(drop, "drop", 0, IF_OPCODE, 0x1A) INST(try_table, "try_table", 0, IF_TRY_TABLE, 0x1F) -INST(local_get, "local.get", 0, IF_ULEB128, 0x20) -INST(local_set, "local.set", 0, IF_ULEB128, 0x21) -INST(local_tee, "local.tee", 0, IF_ULEB128, 0x22) -INST(global_get, "global.get", 0, IF_ULEB128, 0x23) -INST(global_set, "global.set", 0, IF_ULEB128, 0x24) -INST(i32_load, "i32.load", 0, IF_MEMARG, 0x28) -INST(i64_load, "i64.load", 0, IF_MEMARG, 0x29) -INST(f32_load, "f32.load", 0, IF_MEMARG, 0x2A) -INST(f64_load, "f64.load", 0, IF_MEMARG, 0x2B) -INST(i32_load8_s, "i32.load8_s", 0, IF_MEMARG, 0x2C) -INST(i32_load8_u, "i32.load8_u", 0, IF_MEMARG, 0x2D) -INST(i32_load16_s, "i32.load16_s", 0, IF_MEMARG, 0x2E) -INST(i32_load16_u, "i32.load16_u", 0, IF_MEMARG, 0x2F) -INST(i64_load8_s, "i64.load8_s", 0, IF_MEMARG, 0x30) -INST(i64_load8_u, "i64.load8_u", 0, IF_MEMARG, 0x31) -INST(i64_load16_s, "i64.load16_s", 0, IF_MEMARG, 0x32) -INST(i64_load16_u, "i64.load16_u", 0, IF_MEMARG, 0x33) -INST(i64_load32_s, "i64.load32_s", 0, IF_MEMARG, 0x34) -INST(i64_load32_u, "i64.load32_u", 0, IF_MEMARG, 0x35) +INST(local_get, "local.get", 0, IF_ULEB128, 0x20) +INST(local_set, "local.set", 0, IF_ULEB128, 0x21) +INST(local_tee, "local.tee", 0, IF_ULEB128, 0x22) +INST(global_get, "global.get", 0, IF_GLOBALIDX, 0x23) +INST(global_set, "global.set", 0, IF_GLOBALIDX, 0x24) +INST(i32_load, "i32.load", 0, IF_MEMARG, 0x28) +INST(i64_load, "i64.load", 0, IF_MEMARG, 0x29) +INST(f32_load, "f32.load", 0, IF_MEMARG, 0x2A) +INST(f64_load, "f64.load", 0, IF_MEMARG, 0x2B) +INST(i32_load8_s, "i32.load8_s", 0, IF_MEMARG, 0x2C) +INST(i32_load8_u, "i32.load8_u", 0, IF_MEMARG, 0x2D) +INST(i32_load16_s, "i32.load16_s", 0, IF_MEMARG, 0x2E) +INST(i32_load16_u, "i32.load16_u", 0, IF_MEMARG, 0x2F) +INST(i64_load8_s, "i64.load8_s", 0, IF_MEMARG, 0x30) +INST(i64_load8_u, "i64.load8_u", 0, IF_MEMARG, 0x31) +INST(i64_load16_s, "i64.load16_s", 0, IF_MEMARG, 0x32) +INST(i64_load16_u, "i64.load16_u", 0, IF_MEMARG, 0x33) +INST(i64_load32_s, "i64.load32_s", 0, IF_MEMARG, 0x34) +INST(i64_load32_u, "i64.load32_u", 0, IF_MEMARG, 0x35) INST(i32_store, "i32.store", 0, IF_MEMARG, 0x36) INST(i64_store, "i64.store", 0, IF_MEMARG, 0x37) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ExternSymbolNode.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ExternSymbolNode.cs similarity index 100% rename from src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ExternSymbolNode.cs rename to src/coreclr/tools/Common/Compiler/DependencyAnalysis/ExternSymbolNode.cs diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/NodeFactory.Wasm.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/NodeFactory.Wasm.cs new file mode 100644 index 00000000000000..6cb6190471d7b8 --- /dev/null +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/NodeFactory.Wasm.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Frozen; +using System.Threading; +using Internal.Text; + +namespace ILCompiler.DependencyAnalysis +{ + public partial class NodeFactory + { + // The well-known wasm globals are immutable relocation targets. They are created + // lazily on first access (only wasm targets ever request them) so non-wasm compilations don't + // pay the allocation. + private FrozenDictionary _wasmWellKnownGlobals; + + public WasmWellKnownGlobalSymbolNode GetWellKnownWasmGlobalSymbol(Utf8String symbolName) + { + FrozenDictionary globals = _wasmWellKnownGlobals; + if (globals is null) + { + globals = FrozenDictionary.Create([ + new(new(WasmWellKnownGlobalSymbolNode.StackPointerName), new WasmWellKnownGlobalSymbolNode(WasmWellKnownGlobalSymbolNode.StackPointerName)), + new(new(WasmWellKnownGlobalSymbolNode.ImageBaseName), new WasmWellKnownGlobalSymbolNode(WasmWellKnownGlobalSymbolNode.ImageBaseName)), + new(new(WasmWellKnownGlobalSymbolNode.TableBaseName), new WasmWellKnownGlobalSymbolNode(WasmWellKnownGlobalSymbolNode.TableBaseName)) + ]); + + globals = Interlocked.CompareExchange(ref _wasmWellKnownGlobals, globals, null) ?? globals; + } + + return globals[symbolName]; + } + } +} diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/WasmWellKnownGlobalSymbolNode.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/WasmWellKnownGlobalSymbolNode.cs new file mode 100644 index 00000000000000..26f70551b642de --- /dev/null +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/WasmWellKnownGlobalSymbolNode.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Internal.Text; + +namespace ILCompiler.DependencyAnalysis +{ + /// + /// Represents one of the well-known wasm globals referenced by JIT-generated code. + /// These are imported globals whose final index is assigned by the ObjectWriter / wasm linker. + /// crossgen2/R2R resolves it back to the fixed index defined in the WebCIL format, while a relocatable + /// NativeAOT object emits it as an undefined imported global for wasm-ld to resolve. + /// + public class WasmWellKnownGlobalSymbolNode(string symbolName) : ExternDataSymbolNode(new Utf8String(symbolName)) + { + public const string StackPointerName = "__stack_pointer"; + public const string ImageBaseName = "__memory_base"; + public const string TableBaseName = "__table_base"; + + public override int ClassCode => 0x79046cf9; + + protected override string GetName(NodeFactory factory) => $"WasmWellKnownGlobal {this.ToString()}"; + } +} diff --git a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs index 9f3dcd332202c5..d50888e0fdf309 100644 --- a/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs +++ b/src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs @@ -3,6 +3,7 @@ using System; using System.Buffers.Binary; +using System.Collections.Frozen; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -156,7 +157,7 @@ private WasmFuncType GetFuncletType(FuncletKind funcletKind, WasmValueType point _ => new WasmFuncType(new([pointerType, pointerType]), new([])), // (FP, SP) -> void }; } - + private void WriteSignatureIndexForFunction(MethodSignature managedSignature, WasmLowering.LoweringFlags flags, ISymbolNode node) { SectionWriter writer = GetOrCreateSection(WasmObjectNodeSection.FunctionSection); @@ -556,7 +557,7 @@ private int NextGlobalIndex() private Dictionary _definedGlobals = new(); // TODO-Wasm: In the future, we may want to consider representing Wasm globals in the dependency graph so that they - // can be referenced by other nodes and we can make effective use of them. + // can be referenced by other nodes and we can make effective use of them. private void WriteGlobal(SectionWriter writer, string name, WasmValueType valueType, WasmMutabilityType mutability, WasmInstructionGroup initExpr) { WasmGlobal global = new WasmGlobal( @@ -767,7 +768,7 @@ private protected override void EmitObjectFile(Stream outputFileStream) WasmDataSegment webcilContentsSegment = new WasmDataSegment(webcilStream, new Utf8String("webcilPayload"), WasmDataSectionType.Passive, null); - // Create combined data section and emit + // Create combined data section and emit WasmDataSection dataSection = new WasmDataSection([webcilSizeSegment, webcilContentsSegment], new Utf8String("data"), contentAlign: 4); dataSection.Emit(outputFileStream); #endif @@ -872,6 +873,26 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr throw new InvalidOperationException($"Unsupported relocation size for relocation: {reloc.Type}"); } + if (reloc.Type == RelocType.WASM_GLOBAL_INDEX_LEB) + { + // The JIT references the well-known wasm globals (stack pointer / image base / + // table base) via WASM_GLOBAL_INDEX_LEB relocations against the WasmWellKnownGlobalSymbolNode. + // For R2R these globals live at fixed indices supplied by the runtime loader, so we + // self-resolve them here to the global indices defined in the WebCIL specification. + if (!_globalSymbolNameToGlobalIndex.TryGetValue(reloc.SymbolName, out var globalIndex)) + { + throw new NotImplementedException($"Unexpected global symbol: {reloc.SymbolName}"); + } + + fixed (byte* pData = ReadRelocToDataSpan(reloc, relocScratchBuffer, sectionStart)) + { + Relocation.WriteValue(reloc.Type, pData, (int)globalIndex); + WriteRelocFromDataSpan(reloc, pData, sectionStart); + } + + continue; + } + SymbolDefinition definedSymbol = _definedSymbols[reloc.SymbolName]; // The virtual address of the relocation we are resolving @@ -950,7 +971,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr // i32.const // i32.add // i32.load 0 - // So, the relocated address value should always represent an offset relative to image base. + // So, the relocated address value should always represent an offset relative to image base. // This offset should ALWAYS be equal to the actual offset from image base at runtime, due to Webcil's // flag mapping if (symbolWebcilSection is null) @@ -966,7 +987,7 @@ private unsafe void ResolveRelocations(int sectionIndex, MemoryStream sectionStr // These relocs should be for cases of the form: // global.get $imageBase // i32.load - // So, the relocated address value should always represent an offset relative to image base. + // So, the relocated address value should always represent an offset relative to image base. // This offset should ALWAYS be equal to the actual offset from image base at runtime, due to Webcil's // flag mapping if (symbolWebcilSection is null) @@ -1041,6 +1062,12 @@ void WriteRelocFromDataSpan(SymbolicRelocation reloc, byte* pData, long sectionS new([]), new([])); + private static readonly FrozenDictionary _globalSymbolNameToGlobalIndex = FrozenDictionary.Create([ + new(new(WasmWellKnownGlobalSymbolNode.StackPointerName), StackPointerGlobalIndex), + new(new(WasmWellKnownGlobalSymbolNode.ImageBaseName), ImageBaseGlobalIndex), + new(new(WasmWellKnownGlobalSymbolNode.TableBaseName), TableBaseGlobalIndex) + ]); + private WasmImport[] CreateDefaultGlobalImports() { int rtlRestoreContextTagTypeIndex = RegisterSignature(RtlRestoreContextTagSignature); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 37badc2c91ed76..b25f8d0d683983 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3594,6 +3594,13 @@ private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut) pAsyncInfoOut.finishSuspensionWithContinuationContextMethHnd = ObjectToHandle(asyncHelpers.GetKnownMethod("FinishSuspensionWithContinuationContext"u8, null)); } + private void getWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pWellKnownGlobalsOut) + { + NodeFactory factory = _compilation.NodeFactory; + pWellKnownGlobalsOut.stackPointer = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)ObjectToHandle(factory.GetWellKnownWasmGlobalSymbol(new(WasmWellKnownGlobalSymbolNode.StackPointerName))); + pWellKnownGlobalsOut.imageBase = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)ObjectToHandle(factory.GetWellKnownWasmGlobalSymbol(new(WasmWellKnownGlobalSymbolNode.ImageBaseName))); + pWellKnownGlobalsOut.tableBase = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)ObjectToHandle(factory.GetWellKnownWasmGlobalSymbol(new(WasmWellKnownGlobalSymbolNode.TableBaseName))); + } private CORINFO_METHOD_STRUCT_* getAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) { instArg.lookupKind.needsRuntimeLookup = false; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 9566e1788240ae..ef00dcf0188b1b 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -150,6 +150,7 @@ static ICorJitInfoCallbacks() s_callbacks.getFpStructLowering = &_getFpStructLowering; s_callbacks.getWasmLowering = &_getWasmLowering; s_callbacks.getAddressAlignment = &_getAddressAlignment; + s_callbacks.getWasmWellKnownGlobals = &_getWasmWellKnownGlobals; s_callbacks.getThreadTLSIndex = &_getThreadTLSIndex; s_callbacks.getAddrOfCaptureThreadGlobal = &_getAddrOfCaptureThreadGlobal; s_callbacks.getHelperFtn = &_getHelperFtn; @@ -333,6 +334,7 @@ static ICorJitInfoCallbacks() public delegate* unmanaged getFpStructLowering; public delegate* unmanaged getWasmLowering; public delegate* unmanaged getAddressAlignment; + public delegate* unmanaged getWasmWellKnownGlobals; public delegate* unmanaged getThreadTLSIndex; public delegate* unmanaged getAddrOfCaptureThreadGlobal; public delegate* unmanaged getHelperFtn; @@ -2309,6 +2311,20 @@ private static uint _getAddressAlignment(IntPtr thisHandle, IntPtr* ppException, } } + [UnmanagedCallersOnly] + private static void _getWasmWellKnownGlobals(IntPtr thisHandle, IntPtr* ppException, CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) + { + var _this = GetThis(thisHandle); + try + { + _this.getWasmWellKnownGlobals(ref *pWellKnownGlobalsOut); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + [UnmanagedCallersOnly] private static uint _getThreadTLSIndex(IntPtr thisHandle, IntPtr* ppException, void** ppIndirection) { diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 0c843d13aa1a7f..2402eda54f0d59 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -64,6 +64,10 @@ public struct CORINFO_WASM_TYPE_SYMBOL_STRUCT_ { } + public struct CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_ + { + } + public struct CORINFO_JUST_MY_CODE_HANDLE_ { } @@ -970,6 +974,19 @@ public unsafe struct CORINFO_ASYNC_INFO public CORINFO_METHOD_STRUCT_* finishSuspensionWithContinuationContextMethHnd; } + // The well-known wasm globals referenced by JIT-generated code via + // WASM_GLOBAL_INDEX_LEB relocations. Each handle is the relocation target for the + // corresponding well-known global; the object writer resolves it to the final wasm global index. + public unsafe struct CORINFO_WASM_WELLKNOWN_GLOBALS + { + // Shadow stack pointer global (read at the root frame, then threaded through locals). + public CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_* stackPointer; + // Image base global (__memory_base), added to static data offsets. + public CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_* imageBase; + // Table base global (__table_base), added to funclet pointer offsets. + public CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_* tableBase; + } + // Flags passed from JIT to runtime. public enum CORINFO_GET_TAILCALL_HELPERS_FLAGS { diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 68a74186c816b9..8a6ab34f947c4b 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -84,6 +84,7 @@ CORINFO_RESOLVED_TOKEN*,ref CORINFO_RESOLVED_TOKEN CORINFO_RESOLVED_TOKEN_PTR,CORINFO_RESOLVED_TOKEN*,CORINFO_RESOLVED_TOKEN*,CORINFO_RESOLVED_TOKEN* CORINFO_EE_INFO*,ref CORINFO_EE_INFO CORINFO_ASYNC_INFO*,ref CORINFO_ASYNC_INFO +CORINFO_WASM_WELLKNOWN_GLOBALS*,ref CORINFO_WASM_WELLKNOWN_GLOBALS CORINFO_TAILCALL_HELPERS*,ref CORINFO_TAILCALL_HELPERS CORINFO_SWIFT_LOWERING*,ref CORINFO_SWIFT_LOWERING CORINFO_FPSTRUCT_LOWERING*,ref CORINFO_FPSTRUCT_LOWERING @@ -304,6 +305,7 @@ FUNCTIONS void getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering); CorInfoWasmType getWasmLowering(CORINFO_CLASS_HANDLE structHnd); uint32_t getAddressAlignment(void* address); + void getWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut); uint32_t getThreadTLSIndex(void **ppIndirection); int32_t * getAddrOfCaptureThreadGlobal(void **ppIndirection); void getHelperFtn (CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint, CORINFO_METHOD_HANDLE *pMethod); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index e42c5b8f0e0487..a1b2f8d86b6d66 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -306,6 +306,7 @@ + @@ -329,6 +330,8 @@ + + @@ -612,7 +615,6 @@ - diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs index aee0bc1e77cb30..258aae21977ec4 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs @@ -92,8 +92,31 @@ static void Validate(ReadyToRunReader reader) var webcilReader = Assert.IsType(reader.CompositeReader); Assert.True(webcilReader.IsWasmWrapped); Assert.Equal(WasmMachine.Wasm32, reader.Machine); - Assert.True(R2RAssert.GetAllMethods(reader).Exists(method => + + List methods = R2RAssert.GetAllMethods(reader); + Assert.True(methods.Exists(method => method.SignatureString.Contains("AddIntegers", StringComparison.Ordinal))); + // Reads static data, so the JIT materializes the image base via a well-known-global global.get. + Assert.True(methods.Exists(method => + method.SignatureString.Contains("SumStaticData", StringComparison.Ordinal))); + // Has a try/finally, so the JIT materializes the table base via a well-known-global global.get. + Assert.True(methods.Exists(method => + method.SignatureString.Contains("SumWithFinally", StringComparison.Ordinal))); + + // The wasm JIT references the ABI well-known globals via maximally padded WASM_GLOBAL_INDEX_LEB + // relocations that the R2R object writer must self-resolve back to the fixed global + // indices. Verify the emitted code contains a correctly self-resolved 'global.get' for the + // image base (1, materialized by static-data reads in SumStaticData) and the table base + // (2, materialized by the try/finally funclet path in SumWithFinally). Each pattern encodes + // the exact resolved index, so a regression in self-resolution changes it (or makes + // crossgen2 throw while emitting the method). The stack-pointer well-known global is passed to + // managed methods as a parameter in R2R, so it is not referenced via 'global.get' here. + const int ImageBaseGlobal = 1; + const int TableBaseGlobal = 2; + Assert.True(R2RAssert.WasmImageContainsWellKnownGlobalGet(webcilReader, ImageBaseGlobal), + "Expected a 'global.get' of the wasm image-base well-known global in the emitted code."); + Assert.True(R2RAssert.WasmImageContainsWellKnownGlobalGet(webcilReader, TableBaseGlobal), + "Expected a 'global.get' of the wasm table-base well-known global in the emitted code."); } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/Webcil/WasmWebcilModule.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/Webcil/WasmWebcilModule.cs index 209a61a56155ed..f0822dba5f8518 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/Webcil/WasmWebcilModule.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/Webcil/WasmWebcilModule.cs @@ -1,12 +1,49 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.CompilerServices; + namespace Webcil; public static class WasmWebcilModule { + private static readonly int[] s_primes = new int[] { 3, 5, 7, 11, 13 }; + private static int s_counter; + + [MethodImpl(MethodImplOptions.NoInlining)] public static int AddIntegers(int left, int right) { return left + right; } + + // Reads static data, which forces the JIT to materialize the imageBase address via a + // 'global.get' of the wasm imageBase well-known global. + public static int SumStaticData(int index) + { + s_counter += 1; + return AddIntegers(s_primes[index], s_counter); + } + + // An unoptimized try/finally makes the JIT emit a call to the 'finally' + // funclet (genCallFinally), which computes the funclet's address from the + // wasm table-base well-known global via a 'global.get'. Like the image + // base, that table-base global is referenced through a + // WASM_GLOBAL_INDEX_LEB relocation the R2R object writer must self-resolve + // back to the fixed table-base global index; if that resolution regresses, + // the emitted 'global.get' encoding changes (or crossgen2 throws while + // emitting this method). + [MethodImpl(MethodImplOptions.NoOptimization)] + public static int SumWithFinally(int index) + { + int total = 0; + try + { + total = s_primes[index]; + } + finally + { + s_counter++; + } + return total + s_counter; + } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs index 8a29c9de0bb128..bd009c5231527f 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs @@ -4,6 +4,7 @@ using System; using System.Buffers.Binary; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection.Metadata; @@ -35,6 +36,54 @@ public static List GetAllMethods(ReadyToRunReader reader) return methods; } + /// + /// Returns true if any WASM function body in the image contains a global.get of the + /// given ABI well-known-global index, emitted as a maximally padded 5-byte + /// WASM_GLOBAL_INDEX_LEB reference (the global.get opcode 0x23 followed + /// by the 5-byte padded ULEB128 of the index). + /// + /// + /// The wasm JIT references only the three ABI well-known globals (0 = stack pointer, 1 = image base, + /// 2 = table base) in this padded form; ordinary global.get instructions use the minimal + /// LEB128 encoding. The R2R object writer self-resolves the relocation in place, so after + /// compilation the padded slot holds the fixed index, e.g. image base -> + /// 23 81 80 80 80 00 and table base -> 23 82 80 80 80 00. This is a regression + /// smoke check for that self-resolution: it scans raw instruction bytes and does not decode + /// wasm instruction boundaries. + /// + public static bool WasmImageContainsWellKnownGlobalGet(WebcilImageReader reader, int wellKnownGlobalIndex) + { + // The well-known globals are 0/1/2, which all fit in a single ULEB128 payload byte. The padded + // encoding below only writes that single payload byte, so it is correct for indices <= 0x7F. + Debug.Assert((uint)wellKnownGlobalIndex <= 0x7F, + $"Only single-byte well-known-global indices are supported; got {wellKnownGlobalIndex}."); + + // global.get (0x23) followed by the 5-byte padded ULEB128 of wellKnownGlobalIndex. Padding sets + // the continuation bit on the first four bytes and clears the last, so a small index N + // encodes as (N | 0x80), 0x80, 0x80, 0x80, 0x00. + Span pattern = stackalloc byte[6]; + pattern[0] = 0x23; + pattern[1] = (byte)((wellKnownGlobalIndex & 0x7F) | 0x80); + pattern[2] = 0x80; + pattern[3] = 0x80; + pattern[4] = 0x80; + pattern[5] = 0x00; + + for (int functionIndex = 0; ; functionIndex++) + { + WebcilImageReader.WasmFunctionInfo? body = reader.GetWasmFunctionBody(functionIndex); + if (body is null) + break; + + ReadOnlySpan instructions = body.Value.Image.AsSpan().Slice( + body.Value.InstructionOffset, body.Value.InstructionLength); + if (instructions.IndexOf(pattern) >= 0) + return true; + } + + return false; + } + /// /// Returns true if the R2R image contains a manifest or MSIL assembly reference with the given name. /// diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index 34178500977b3c..4b3a4e84185974 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -73,7 +73,7 @@ public struct NodeFactoryOptimizationFlags // To make the code future compatible to the composite R2R story // do NOT attempt to pass and store _inputModule here - public sealed class NodeFactory + public sealed partial class NodeFactory { private bool _markingComplete; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index 2b73b12632740e..de7ef6ba591706 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -84,6 +84,7 @@ + @@ -107,6 +108,8 @@ + + diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index f544bfd4b6484e..3a0514e49ad2a7 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -141,6 +141,7 @@ struct JitInterfaceCallbacks void (* getFpStructLowering)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering); CorInfoWasmType (* getWasmLowering)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE structHnd); uint32_t (* getAddressAlignment)(void * thisHandle, CorInfoExceptionClass** ppException, void* address); + void (* getWasmWellKnownGlobals)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut); uint32_t (* getThreadTLSIndex)(void * thisHandle, CorInfoExceptionClass** ppException, void** ppIndirection); int32_t* (* getAddrOfCaptureThreadGlobal)(void * thisHandle, CorInfoExceptionClass** ppException, void** ppIndirection); void (* getHelperFtn)(void * thisHandle, CorInfoExceptionClass** ppException, CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint, CORINFO_METHOD_HANDLE* pMethod); @@ -1462,6 +1463,14 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual void getWasmWellKnownGlobals( + CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) +{ + CorInfoExceptionClass* pException = nullptr; + _callbacks->getWasmWellKnownGlobals(_thisHandle, &pException, pWellKnownGlobalsOut); + if (pException != nullptr) throw pException; +} + virtual uint32_t getThreadTLSIndex( void** ppIndirection) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 092a5db291773a..2c36e6500c75ac 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -241,6 +241,13 @@ struct Agnostic_CORINFO_ASYNC_INFO DWORDLONG finishSuspensionWithContinuationContextMethHnd; }; +struct Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS +{ + DWORDLONG stackPointer; + DWORDLONG imageBase; + DWORDLONG tableBase; +}; + struct Agnostic_GetAwaitReturnCallResult { DWORDLONG methodHnd; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index d46488982aa8fa..e44cf227fbd412 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -174,6 +174,7 @@ LWM(DoesFieldBelongToClass, DLDL, DWORD) DENSELWM(SigInstHandleMap, DWORDLONG) LWM(GetWasmTypeSymbol, Agnostic_GetWasmTypeSymbol, DWORDLONG) LWM(GetAddressAlignment, DWORDLONG, DWORD) +LWM(GetWasmWellKnownGlobals, DWORD, Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS) #undef LWM #undef DENSELWM diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 9d50ef78786dcd..db89aaed33f8a7 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4425,6 +4425,34 @@ void MethodContext::repGetAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfoOut) DEBUG_REP(dmpGetAsyncInfo(0, value)); } +void MethodContext::recGetWasmWellKnownGlobals(const CORINFO_WASM_WELLKNOWN_GLOBALS* pBaseGlobals) +{ + if (GetWasmWellKnownGlobals == nullptr) + GetWasmWellKnownGlobals = new LightWeightMap(); + + Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS value; + ZeroMemory(&value, sizeof(value)); + + value.stackPointer = CastHandle(pBaseGlobals->stackPointer); + value.imageBase = CastHandle(pBaseGlobals->imageBase); + value.tableBase = CastHandle(pBaseGlobals->tableBase); + + GetWasmWellKnownGlobals->Add(0, value); + DEBUG_REC(dmpGetWasmWellKnownGlobals(0, value)); +} +void MethodContext::dmpGetWasmWellKnownGlobals(DWORD key, const Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS& value) +{ + printf("GetWasmWellKnownGlobals key %u value stackPointer-%016" PRIX64 " imageBase-%016" PRIX64 " tableBase-%016" PRIX64, + key, value.stackPointer, value.imageBase, value.tableBase); +} +void MethodContext::repGetWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) +{ + Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS value = LookupByKeyOrMissNoMessage(GetWasmWellKnownGlobals, 0); + pWellKnownGlobalsOut->stackPointer = (CORINFO_WASM_GLOBAL_SYMBOL_HANDLE)value.stackPointer; + pWellKnownGlobalsOut->imageBase = (CORINFO_WASM_GLOBAL_SYMBOL_HANDLE)value.imageBase; + pWellKnownGlobalsOut->tableBase = (CORINFO_WASM_GLOBAL_SYMBOL_HANDLE)value.tableBase; + DEBUG_REP(dmpGetWasmWellKnownGlobals(0, value)); +} void MethodContext::recGetAwaitReturnCall(CORINFO_METHOD_HANDLE callerHnd, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_LOOKUP* instArg, CORINFO_METHOD_HANDLE methHnd) { if (GetAwaitReturnCall == nullptr) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 8d38ab29b240c4..5ca689f36ce384 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -563,6 +563,10 @@ class MethodContext void dmpGetAwaitReturnCall(DWORDLONG key, Agnostic_GetAwaitReturnCallResult& value); CORINFO_METHOD_HANDLE repGetAwaitReturnCall(CORINFO_METHOD_HANDLE callerHnd, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_LOOKUP* instArg); + void recGetWasmWellKnownGlobals(const CORINFO_WASM_WELLKNOWN_GLOBALS* pBaseGlobals); + void dmpGetWasmWellKnownGlobals(DWORD key, const Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS& value); + void repGetWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut); + void recGetGSCookie(GSCookie* pCookieVal, GSCookie** ppCookieVal); void dmpGetGSCookie(DWORD key, DLDL value); void repGetGSCookie(GSCookie* pCookieVal, GSCookie** ppCookieVal); @@ -1219,6 +1223,7 @@ enum mcPackets Packet_GetAsyncOtherVariant = 237, Packet_GetAwaitReturnCall = 238, Packet_GetAddressAlignment = 239, + Packet_GetWasmWellKnownGlobals = 240, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index a026e616aca6d9..9744fc70aaa470 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1382,6 +1382,12 @@ void interceptor_ICJI::getAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfo) mc->recGetAsyncInfo(pAsyncInfo); } +void interceptor_ICJI::getWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) +{ + mc->cr->AddCall("getWasmWellKnownGlobals"); + original_ICorJitInfo->getWasmWellKnownGlobals(pWellKnownGlobalsOut); + mc->recGetWasmWellKnownGlobals(pWellKnownGlobalsOut); +} CORINFO_METHOD_HANDLE interceptor_ICJI::getAwaitReturnCall(CORINFO_METHOD_HANDLE callerHandle, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_LOOKUP* instArg) { mc->cr->AddCall("getAwaitReturnCall"); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 8671f7c0b459fa..53166c4d1538d6 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1051,6 +1051,13 @@ uint32_t interceptor_ICJI::getAddressAlignment( return original_ICorJitInfo->getAddressAlignment(address); } +void interceptor_ICJI::getWasmWellKnownGlobals( + CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) +{ + mcs->AddCall("getWasmWellKnownGlobals"); + original_ICorJitInfo->getWasmWellKnownGlobals(pWellKnownGlobalsOut); +} + uint32_t interceptor_ICJI::getThreadTLSIndex( void** ppIndirection) { diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index c0ce45ed34f4c1..458287f1d32ac2 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -921,6 +921,12 @@ uint32_t interceptor_ICJI::getAddressAlignment( return original_ICorJitInfo->getAddressAlignment(address); } +void interceptor_ICJI::getWasmWellKnownGlobals( + CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) +{ + original_ICorJitInfo->getWasmWellKnownGlobals(pWellKnownGlobalsOut); +} + uint32_t interceptor_ICJI::getThreadTLSIndex( void** ppIndirection) { diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 6ba6066929752d..e71c1dd6071c4a 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1197,6 +1197,11 @@ void MyICJI::getAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfo) jitInstance->mc->repGetAsyncInfo(pAsyncInfo); } +void MyICJI::getWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) +{ + jitInstance->mc->cr->AddCall("getWasmWellKnownGlobals"); + jitInstance->mc->repGetWasmWellKnownGlobals(pWellKnownGlobalsOut); +} CORINFO_METHOD_HANDLE MyICJI::getAwaitReturnCall(CORINFO_METHOD_HANDLE callerHandle, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_LOOKUP* instArg) { jitInstance->mc->cr->AddCall("getAwaitReturnCall"); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 784edce5d72b78..fc8802a1ff863c 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10187,6 +10187,12 @@ CORINFO_WASM_TYPE_SYMBOL_HANDLE CEEInfo::getWasmTypeSymbol( UNREACHABLE_RET(); } +void CEEInfo::getWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) +{ + LIMITED_METHOD_CONTRACT; + UNREACHABLE(); +} + CORINFO_METHOD_HANDLE CEEInfo::getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) { CONTRACTL {