From 133302d00c198727f0c19e999d84892f2d0eebbc Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Fri, 6 Feb 2026 09:11:46 -0800 Subject: [PATCH 1/3] [Wasm RyuJit] Ind write barriers, direct helper calls, more * implement codegen for write barrier helper calls * support direct calls to helpers * decorate call targets with their symbolic names in dumps/disasm --- src/coreclr/jit/codegencommon.cpp | 7 +++++++ src/coreclr/jit/codegenwasm.cpp | 20 +++++++++----------- src/coreclr/jit/emitwasm.cpp | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 176f5c23805992..b7620a2d8e41e3 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -2519,6 +2519,7 @@ bool CodeGenInterface::genUseOptimizedWriteBarriers(GenTreeStoreInd* store) return false; #endif } +#endif // !TARGET_WASM //---------------------------------------------------------------------- // genWriteBarrierHelperForWriteBarrierForm: Given a write barrier form @@ -2555,6 +2556,8 @@ CorInfoHelpFunc CodeGenInterface::genWriteBarrierHelperForWriteBarrierForm(GCInf } } +#if !defined(TARGET_WASM) + // ----------------------------------------------------------------------------- // genGetGSCookieTempRegs: // Get a mask of registers to use for the GS cookie check generated in a @@ -2603,6 +2606,8 @@ regMaskTP CodeGenInterface::genGetGSCookieTempRegs(bool tailCall) #endif } +#endif // !defined(TARGET_WASM) + //---------------------------------------------------------------------- // genGCWriteBarrier: Generate a write barrier for a node. // @@ -2688,6 +2693,8 @@ void CodeGen::genGCWriteBarrier(GenTreeStoreInd* store, GCInfo::WriteBarrierForm EA_PTRSIZE); // retSize } +#ifndef TARGET_WASM + /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 1e5786ecec0135..1f9087e1445b06 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -1375,18 +1375,18 @@ void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree) GenTree* data = tree->Data(); GenTree* addr = tree->Addr(); + // We must consume the operands in the proper execution order, + // so that liveness is updated appropriately. + genConsumeAddress(addr); + genConsumeRegs(data); + GCInfo::WriteBarrierForm writeBarrierForm = gcInfo.gcIsWriteBarrierCandidate(tree); if (writeBarrierForm != GCInfo::WBF_NoBarrier) { - NYI_WASM("write barriers in StoreInd"); + genGCWriteBarrier(tree, writeBarrierForm); } else // A normal store, not a WriteBarrier store { - // We must consume the operands in the proper execution order, - // so that liveness is updated appropriately. - genConsumeAddress(addr); - genConsumeRegs(data); - var_types type = tree->TypeGet(); instruction ins = ins_Store(type); @@ -1498,13 +1498,11 @@ void CodeGen::genCallInstruction(GenTreeCall* call) if (call->IsHelperCall()) { - NYI_WASM("Call helper statically without indirection cell"); + assert(!call->IsFastTailCall()); CorInfoHelpFunc helperNum = m_compiler->eeGetHelperNum(params.methHnd); noway_assert(helperNum != CORINFO_HELP_UNDEF); - - CORINFO_CONST_LOOKUP helperLookup = m_compiler->compGetHelperFtn(helperNum); - params.addr = helperLookup.addr; - assert(helperLookup.accessType == IAT_VALUE); + genEmitHelperCall(helperNum, 0, EA_UNKNOWN); + return; } else { diff --git a/src/coreclr/jit/emitwasm.cpp b/src/coreclr/jit/emitwasm.cpp index ccb84d2481fac1..38abbd8d07fef7 100644 --- a/src/coreclr/jit/emitwasm.cpp +++ b/src/coreclr/jit/emitwasm.cpp @@ -693,6 +693,20 @@ void emitter::emitDispIns( } }; + auto dispTargetOfCallIfAny = [this, id]() { + if (m_debugInfoSize > 0) + { + const void* const methodToken = (const void*)id->idDebugOnlyInfo()->idMemCookie; + if (methodToken != nullptr) + { + printf(" ;; "); + const char* const methodName = + m_compiler->eeGetMethodFullName((CORINFO_METHOD_HANDLE)id->idDebugOnlyInfo()->idMemCookie); + printf("%s", methodName); + } + } + }; + // The reference for the following style of display is wasm-objdump output. // switch (fmt) @@ -707,6 +721,7 @@ void emitter::emitDispIns( cnsval_ssize_t imm = emitGetInsSC(id); printf(" %llu", (uint64_t)imm); dispJumpTargetIfAny(); + dispTargetOfCallIfAny(); } break; @@ -714,6 +729,7 @@ void emitter::emitDispIns( { cnsval_ssize_t imm = emitGetInsSC(id); printf(" %llu 0", (uint64_t)imm); + dispTargetOfCallIfAny(); } break; From 8fdef96fa6f55b0c0272d19c06d67f57e86e4a00 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Sat, 7 Feb 2026 07:32:26 -0800 Subject: [PATCH 2/3] simplify direct helper invocation --- src/coreclr/jit/codegenwasm.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 1f9087e1445b06..e3949bd31dfdd3 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -1501,8 +1501,9 @@ void CodeGen::genCallInstruction(GenTreeCall* call) assert(!call->IsFastTailCall()); CorInfoHelpFunc helperNum = m_compiler->eeGetHelperNum(params.methHnd); noway_assert(helperNum != CORINFO_HELP_UNDEF); - genEmitHelperCall(helperNum, 0, EA_UNKNOWN); - return; + CORINFO_CONST_LOOKUP helperLookup = m_compiler->compGetHelperFtn(helperNum); + assert(helperLookup.accessType == IAT_VALUE); + params.addr = helperLookup.addr; } else { From 6491465adcaaec23aa74df5086be2908f6a0e57d Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Sat, 7 Feb 2026 08:52:22 -0800 Subject: [PATCH 3/3] use emitDispCommentForHandle --- src/coreclr/jit/emit.cpp | 4 +++- src/coreclr/jit/emitwasm.cpp | 18 ++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index f18a72849d9714..a86f845c30b0d1 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -4525,8 +4525,10 @@ void emitter::emitRecomputeIGoffsets() // void emitter::emitDispCommentForHandle(size_t handle, size_t cookie, GenTreeFlags flag) const { -#ifdef TARGET_XARCH +#if defined(TARGET_XARCH) const char* commentPrefix = " ;"; +#elif defined(TARGET_WASM) + const char* commentPrefix = " ;;"; #else const char* commentPrefix = " //"; #endif diff --git a/src/coreclr/jit/emitwasm.cpp b/src/coreclr/jit/emitwasm.cpp index 38abbd8d07fef7..7c136e416b6105 100644 --- a/src/coreclr/jit/emitwasm.cpp +++ b/src/coreclr/jit/emitwasm.cpp @@ -175,6 +175,7 @@ void emitter::emitIns_Call(const EmitCallParams& params) { INDEBUG(id->idDebugOnlyInfo()->idCallSig = params.sigInfo); id->idDebugOnlyInfo()->idMemCookie = (size_t)params.methHnd; // method token + id->idDebugOnlyInfo()->idFlags = GTF_ICON_METHOD_HDL; } dispIns(id); @@ -685,7 +686,7 @@ void emitter::emitDispIns( BasicBlock* const targetBlock = id->idDebugOnlyInfo()->idTargetBlock; if (targetBlock != nullptr) { - printf(" ;; "); + printf(" ;;"); insGroup* const targetGroup = (insGroup*)emitCodeGetCookie(targetBlock); assert(targetGroup != nullptr); emitPrintLabel(targetGroup); @@ -693,17 +694,10 @@ void emitter::emitDispIns( } }; - auto dispTargetOfCallIfAny = [this, id]() { + auto dispHandleIfAny = [this, id]() { if (m_debugInfoSize > 0) { - const void* const methodToken = (const void*)id->idDebugOnlyInfo()->idMemCookie; - if (methodToken != nullptr) - { - printf(" ;; "); - const char* const methodName = - m_compiler->eeGetMethodFullName((CORINFO_METHOD_HANDLE)id->idDebugOnlyInfo()->idMemCookie); - printf("%s", methodName); - } + emitDispCommentForHandle(id->idDebugOnlyInfo()->idMemCookie, 0, id->idDebugOnlyInfo()->idFlags); } }; @@ -721,7 +715,7 @@ void emitter::emitDispIns( cnsval_ssize_t imm = emitGetInsSC(id); printf(" %llu", (uint64_t)imm); dispJumpTargetIfAny(); - dispTargetOfCallIfAny(); + dispHandleIfAny(); } break; @@ -729,7 +723,7 @@ void emitter::emitDispIns( { cnsval_ssize_t imm = emitGetInsSC(id); printf(" %llu 0", (uint64_t)imm); - dispTargetOfCallIfAny(); + dispHandleIfAny(); } break;