diff --git a/src/coreclr/gcinfo/CMakeLists.txt b/src/coreclr/gcinfo/CMakeLists.txt index a652648f32a689..05521608a09a73 100644 --- a/src/coreclr/gcinfo/CMakeLists.txt +++ b/src/coreclr/gcinfo/CMakeLists.txt @@ -66,6 +66,7 @@ endif() if (CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_AMD64) create_gcinfo_lib(TARGET gcinfo_universal_arm64 OS universal ARCH arm64) create_gcinfo_lib(TARGET gcinfo_unix_x64 OS unix ARCH x64) + create_gcinfo_lib(TARGET gcinfo_universal_wasm OS universal ARCH wasm) if (CLR_CMAKE_BUILD_COMMUNITY_ALTJITS EQUAL 1) create_gcinfo_lib(TARGET gcinfo_unix_loongarch64 OS unix ARCH loongarch64) create_gcinfo_lib(TARGET gcinfo_unix_riscv64 OS unix ARCH riscv64) diff --git a/src/coreclr/gcinfo/gcinfoencoder.cpp b/src/coreclr/gcinfo/gcinfoencoder.cpp index e877fb534cb163..2a0636e11dbb7e 100644 --- a/src/coreclr/gcinfo/gcinfoencoder.cpp +++ b/src/coreclr/gcinfo/gcinfoencoder.cpp @@ -2634,10 +2634,8 @@ int BitStreamWriter::EncodeVarLengthSigned( SSIZE_T n, UINT32 base ) } } -#ifndef TARGET_WASM // Instantiate the encoder so other files can use it template class TGcInfoEncoder; -#endif // !TARGET_WASM #ifdef FEATURE_INTERPRETER template class TGcInfoEncoder; diff --git a/src/coreclr/inc/gcinfotypes.h b/src/coreclr/inc/gcinfotypes.h index dc56c94477db0e..68aa15eae549df 100644 --- a/src/coreclr/inc/gcinfotypes.h +++ b/src/coreclr/inc/gcinfotypes.h @@ -909,13 +909,60 @@ struct X86GcInfoEncoding { static const bool HAS_FIXED_STACK_PARAMETER_SCRATCH_AREA = true; }; -#elif defined(TARGET_WASM) +#elif defined(TARGET_WASM) && !defined(TARGET_64BIT) #ifndef TARGET_POINTER_SIZE #define TARGET_POINTER_SIZE 4 // equal to sizeof(void*) and the managed pointer size in bytes for this target #endif -#define TargetGcInfoEncoding InterpreterGcInfoEncoding +#define TargetGcInfoEncoding Wasm32GcInfoEncoding + +struct Wasm32GcInfoEncoding { + static const uint32_t NUM_NORM_CODE_OFFSETS_PER_CHUNK = (64); + static const uint32_t NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 = (6); + static inline constexpr int32_t NORMALIZE_STACK_SLOT (int32_t x) { return (x); } + static inline constexpr int32_t DENORMALIZE_STACK_SLOT (int32_t x) { return (x); } + static inline constexpr uint32_t NORMALIZE_CODE_LENGTH (uint32_t x) { return (x); } + static inline constexpr uint32_t DENORMALIZE_CODE_LENGTH (uint32_t x) { return (x); } + static inline constexpr uint32_t NORMALIZE_STACK_BASE_REGISTER (uint32_t x) { return (x); } + static inline constexpr uint32_t DENORMALIZE_STACK_BASE_REGISTER (uint32_t x) { return (x); } + static inline constexpr uint32_t NORMALIZE_SIZE_OF_STACK_AREA (uint32_t x) { return (x); } + static inline constexpr uint32_t DENORMALIZE_SIZE_OF_STACK_AREA (uint32_t x) { return (x); } + static const bool CODE_OFFSETS_NEED_NORMALIZATION = false; + static inline constexpr uint32_t NORMALIZE_CODE_OFFSET (uint32_t x) { return (x); } + static inline constexpr uint32_t DENORMALIZE_CODE_OFFSET (uint32_t x) { return (x); } + + static const int PSP_SYM_STACK_SLOT_ENCBASE = 6; + static const int GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE = 6; + static const int SECURITY_OBJECT_STACK_SLOT_ENCBASE = 6; + static const int GS_COOKIE_STACK_SLOT_ENCBASE = 6; + static const int CODE_LENGTH_ENCBASE = 6; + static const int SIZE_OF_RETURN_KIND_IN_SLIM_HEADER = 2; + static const int SIZE_OF_RETURN_KIND_IN_FAT_HEADER = 2; + static const int STACK_BASE_REGISTER_ENCBASE = 3; + static const int SIZE_OF_STACK_AREA_ENCBASE = 6; + static const int SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE = 3; + static const int REVERSE_PINVOKE_FRAME_ENCBASE = 6; + static const int NUM_REGISTERS_ENCBASE = 3; + static const int NUM_STACK_SLOTS_ENCBASE = 5; + static const int NUM_UNTRACKED_SLOTS_ENCBASE = 5; + static const int NORM_PROLOG_SIZE_ENCBASE = 4; + static const int NORM_EPILOG_SIZE_ENCBASE = 3; + static const int NORM_CODE_OFFSET_DELTA_ENCBASE = 3; + static const int INTERRUPTIBLE_RANGE_DELTA1_ENCBASE = 5; + static const int INTERRUPTIBLE_RANGE_DELTA2_ENCBASE = 5; + static const int REGISTER_ENCBASE = 3; + static const int REGISTER_DELTA_ENCBASE = REGISTER_ENCBASE; + static const int STACK_SLOT_ENCBASE = 6; + static const int STACK_SLOT_DELTA_ENCBASE = 4; + static const int NUM_SAFE_POINTS_ENCBASE = 4; + static const int NUM_INTERRUPTIBLE_RANGES_ENCBASE = 1; + static const int NUM_EH_CLAUSES_ENCBASE = 2; + static const int POINTER_SIZE_ENCBASE = 3; + static const int LIVESTATE_RLE_RUN_ENCBASE = 2; + static const int LIVESTATE_RLE_SKIP_ENCBASE = 4; + static const bool HAS_FIXED_STACK_PARAMETER_SCRATCH_AREA = false; +}; #else // No target defined diff --git a/src/coreclr/jit/CMakeLists.txt b/src/coreclr/jit/CMakeLists.txt index e7e69887486830..fd88b263fd5946 100644 --- a/src/coreclr/jit/CMakeLists.txt +++ b/src/coreclr/jit/CMakeLists.txt @@ -23,7 +23,7 @@ function(create_standalone_jit) if(TARGETDETAILS_OS STREQUAL "unix_osx" OR TARGETDETAILS_OS STREQUAL "unix_anyos") set(JIT_ARCH_LINK_LIBRARIES gcinfo_unix_${TARGETDETAILS_ARCH}) - elseif(NOT ${TARGETDETAILS_ARCH} MATCHES "wasm") + else() set(JIT_ARCH_LINK_LIBRARIES gcinfo_${TARGETDETAILS_OS}_${TARGETDETAILS_ARCH}) endif() @@ -292,6 +292,8 @@ set( JIT_RISCV64_SOURCES ) set( JIT_WASM_SOURCES + gcdecode.cpp + gcencode.cpp codegenwasm.cpp emitwasm.cpp fgwasm.cpp diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index d7dc1e38aedfd6..9da4c8a1e9286a 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -854,7 +854,9 @@ bool CodeGen::genIsSameLocalVar(GenTree* op1, GenTree* op2) // inline void CodeGenInterface::genUpdateRegLife(const LclVarDsc* varDsc, bool isBorn, bool isDying DEBUGARG(GenTree* tree)) { -#if EMIT_GENERATE_GCINFO // The regset being updated here is only needed for codegen-level GCness tracking +#if EMIT_GENERATE_GCINFO && !defined(TARGET_WASM) + // The regset being updated here is only needed for codegen-level GCness tracking, + // and Wasm does not have registers regMaskTP regMask = genGetRegMask(varDsc); #ifdef DEBUG @@ -884,7 +886,7 @@ void CodeGenInterface::genUpdateRegLife(const LclVarDsc* varDsc, bool isBorn, bo assert(varDsc->IsAlwaysAliveInMemory() || ((regSet.GetMaskVars() & regMask) == 0)); regSet.AddMaskVars(regMask); } -#endif // EMIT_GENERATE_GCINFO +#endif // EMIT_GENERATE_GCINFO && !TARGET_WASM } #ifndef TARGET_WASM @@ -1032,6 +1034,7 @@ void Compiler::compChangeLife(VARSET_VALARG_TP newLife) bool isByRef = varDsc->TypeIs(TYP_BYREF); bool isInReg = varDsc->lvIsInReg(); bool isInMemory = !isInReg || varDsc->IsAlwaysAliveInMemory(); +#ifndef TARGET_WASM if (isInReg) { // TODO-Cleanup: Move the code from compUpdateLifeVar to genUpdateRegLife that updates the @@ -1047,7 +1050,8 @@ void Compiler::compChangeLife(VARSET_VALARG_TP newLife) } codeGen->genUpdateRegLife(varDsc, false /*isBorn*/, true /*isDying*/ DEBUGARG(nullptr)); } - // Update the gcVarPtrSetCur if it is in memory. +#endif // !TARGET_WASM + // Update the gcVarPtrSetCur if it is in memory. if (isInMemory && (isGCRef || isByRef)) { VarSetOps::RemoveElemD(this, codeGen->gcInfo.gcVarPtrSetCur, deadVarIndex); @@ -1070,6 +1074,7 @@ void Compiler::compChangeLife(VARSET_VALARG_TP newLife) bool isByRef = varDsc->TypeIs(TYP_BYREF); if (varDsc->lvIsInReg()) { +#ifndef TARGET_WASM // If this variable is going live in a register, it is no longer live on the stack, // unless it is an EH/"spill at single-def" var, which always remains live on the stack. if (!varDsc->IsAlwaysAliveInMemory()) @@ -1092,6 +1097,7 @@ void Compiler::compChangeLife(VARSET_VALARG_TP newLife) { codeGen->gcInfo.gcRegByrefSetCur |= regMask; } +#endif // !TARGET_WASM } else if (lvaIsGCTracked(varDsc)) { @@ -1769,7 +1775,7 @@ void CodeGen::genExitCode(BasicBlock* block) genIPmappingAdd(IPmappingDscKind::Epilog, DebugInfo(), true); -#if EMIT_GENERATE_GCINFO && defined(DEBUG) +#if EMIT_GENERATE_GCINFO && defined(DEBUG) && !defined(TARGET_WASM) // For returnining epilogs do some validation that the GC info looks right. if (!block->HasFlag(BBF_HAS_JMP)) { @@ -1791,7 +1797,7 @@ void CodeGen::genExitCode(BasicBlock* block) } } } -#endif // EMIT_GENERATE_GCINFO && defined(DEBUG) +#endif // EMIT_GENERATE_GCINFO && defined(DEBUG) && !defined(TARGET_WASM) if (m_compiler->getNeedsGSSecurityCookie()) { @@ -7210,7 +7216,7 @@ void CodeGen::genReturn(GenTree* treeNode) } } -#if EMIT_GENERATE_GCINFO +#if EMIT_GENERATE_GCINFO && !defined(TARGET_WASM) if (treeNode->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET)) { genMarkReturnGCInfo(); diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 5386aa65a5d74b..a5a0bdf982b46b 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -259,7 +259,7 @@ void CodeGen::genCodeForBlock(BasicBlock* block) // and before first of the current block is emitted genUpdateLife(block->bbLiveIn); -#if EMIT_GENERATE_GCINFO +#if EMIT_GENERATE_GCINFO && !defined(TARGET_WASM) // Even if liveness didn't change, we need to update the registers containing GC references. // genUpdateLife will update the registers live due to liveness changes. But what about registers that didn't // change? We cleared them out above. Maybe we should just not clear them out, but update the ones that change @@ -353,7 +353,7 @@ void CodeGen::genCodeForBlock(BasicBlock* block) } } } -#endif // EMIT_GENERATE_GCINFO +#endif // EMIT_GENERATE_GCINFO && !TARGET_WASM /* Start a new code output block */ @@ -405,6 +405,14 @@ void CodeGen::genCodeForBlock(BasicBlock* block) } #endif +#ifdef TARGET_WASM + // FIXME-WASM: Why is this only necessary on Wasm? + if (m_compiler->bbIsFuncletBeg(block)) + { + needLabel = true; + } +#endif + if (needLabel) { // Mark a label and update the current set of live GC refs @@ -569,7 +577,7 @@ void CodeGen::genCodeForBlock(BasicBlock* block) regSet.rsSpillChk(); -#if EMIT_GENERATE_GCINFO +#if EMIT_GENERATE_GCINFO && !defined(TARGET_WASM) // Make sure we didn't bungle pointer register tracking regMaskTP ptrRegs = gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur; regMaskTP nonVarPtrRegs = ptrRegs & ~regSet.GetMaskVars(); @@ -618,7 +626,7 @@ void CodeGen::genCodeForBlock(BasicBlock* block) } noway_assert(nonVarPtrRegs == RBM_NONE); -#endif // EMIT_GENERATE_GCINFO +#endif // EMIT_GENERATE_GCINFO && !TARGET_WASM #endif // DEBUG #if defined(DEBUG) @@ -1601,7 +1609,7 @@ regNumber CodeGen::genConsumeReg(GenTree* tree) // genUpdateLife() will also spill local var if marked as GTF_SPILL by calling CodeGen::genSpillVar genUpdateLife(tree); -#if EMIT_GENERATE_GCINFO +#if EMIT_GENERATE_GCINFO && !defined(TARGET_WASM) // there are three cases where consuming a reg means clearing the bit in the live mask // 1. it was not produced by a local // 2. it was produced by a local that is going dead @@ -1659,7 +1667,7 @@ regNumber CodeGen::genConsumeReg(GenTree* tree) { gcInfo.gcMarkRegSetNpt(tree->gtGetRegMask()); } -#endif // EMIT_GENERATE_GCINFO +#endif // EMIT_GENERATE_GCINFO && !TARGET_WASM genCheckConsumeNode(tree); return tree->GetRegNum(); diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index a9d5308d63ee41..0c7a08475637ef 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -9,6 +9,8 @@ #include "codegen.h" #include "regallocwasm.h" #include "fgwasm.h" +#include "gcinfo.h" +#include "gcinfoencoder.h" static const int LINEAR_MEMORY_INDEX = 0; @@ -3366,7 +3368,40 @@ void CodeGen::inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock) void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* code)) { - // GCInfo not captured/created by codegen. + IAllocator* allowZeroAlloc = new (m_compiler, CMK_GC) CompIAllocator(m_compiler->getAllocatorGC()); + GcInfoEncoder* gcInfoEncoder = new (m_compiler, CMK_GC) + GcInfoEncoder(m_compiler->info.compCompHnd, m_compiler->info.compMethodInfo, allowZeroAlloc, NOMEM); + assert(gcInfoEncoder != nullptr); + + // Follow the code pattern of the x86 gc info encoder (genCreateAndStoreGCInfoJIT32). + gcInfo.gcInfoBlockHdrSave(gcInfoEncoder, codeSize, prologSize); + + // We keep the call count for the second call to gcMakeRegPtrTable() below. + unsigned callCnt = 0; + + // First we figure out the encoder ID's for the stack slots and registers. + gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_ASSIGN_SLOTS, &callCnt); + + // Now we've requested all the slots we'll need; "finalize" these (make more compact data structures for them). + gcInfoEncoder->FinalizeSlotIds(); + + // Now we can actually use those slot ID's to declare live ranges. + gcInfo.gcMakeRegPtrTable(gcInfoEncoder, codeSize, prologSize, GCInfo::MAKE_REG_PTR_MODE_DO_WORK, &callCnt); + + if (m_compiler->opts.IsReversePInvoke()) + { + unsigned reversePInvokeFrameVarNumber = m_compiler->lvaReversePInvokeFrameVar; + assert(reversePInvokeFrameVarNumber != BAD_VAR_NUM); + const LclVarDsc* reversePInvokeFrameVar = m_compiler->lvaGetDesc(reversePInvokeFrameVarNumber); + gcInfoEncoder->SetReversePInvokeFrameSlot(reversePInvokeFrameVar->GetStackOffset()); + } + + gcInfoEncoder->Build(); + + // GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t) + // let's save the values anyway for debugging purposes + m_compiler->compInfoBlkAddr = gcInfoEncoder->Emit(); + m_compiler->compInfoBlkSize = gcInfoEncoder->GetEncodedGCInfoSize(); } //--------------------------------------------------------------------- diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 98f74b755e1408..5a01409ce41a8a 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -9076,7 +9076,7 @@ void emitter::emitUpdateLiveGCregs(GCtype gcType, regMaskTP regs, BYTE* addr) return; } -#if EMIT_GENERATE_GCINFO +#if EMIT_GENERATE_GCINFO && !defined(TARGET_WASM) regMaskTP life; regMaskTP dead; regMaskTP chg; @@ -9131,7 +9131,7 @@ void emitter::emitUpdateLiveGCregs(GCtype gcType, regMaskTP regs, BYTE* addr) // The 2 GC reg masks can't be overlapping assert((emitThisGCrefRegs & emitThisByrefRegs) == 0); -#endif // EMIT_GENERATE_GCINFO +#endif // EMIT_GENERATE_GCINFO && !TARGET_WASM } /***************************************************************************** @@ -9434,7 +9434,7 @@ void emitter::emitGCregLiveUpd(GCtype gcType, regNumber reg, BYTE* addr) { assert(emitIssuing); -#if EMIT_GENERATE_GCINFO +#if EMIT_GENERATE_GCINFO && !defined(TARGET_WASM) // Don't track GC changes in epilogs if (emitIGisInEpilog(emitCurIG)) { @@ -9476,7 +9476,7 @@ void emitter::emitGCregLiveUpd(GCtype gcType, regNumber reg, BYTE* addr) // The 2 GC reg masks can't be overlapping assert((emitThisGCrefRegs & emitThisByrefRegs) == 0); -#endif // EMIT_GENERATE_GCINFO +#endif // EMIT_GENERATE_GCINFO && !TARGET_WASM } /***************************************************************************** @@ -9494,7 +9494,7 @@ void emitter::emitGCregDeadUpdMask(regMaskTP regs, BYTE* addr) return; } -#if EMIT_GENERATE_GCINFO +#if EMIT_GENERATE_GCINFO && !defined(TARGET_WASM) // First, handle the gcref regs going dead regMaskTP gcrefRegs = emitThisGCrefRegs & regs; @@ -9530,7 +9530,7 @@ void emitter::emitGCregDeadUpdMask(regMaskTP regs, BYTE* addr) emitThisByrefRegs &= ~byrefRegs; } -#endif // EMIT_GENERATE_GCINFO +#endif // EMIT_GENERATE_GCINFO && !TARGET_WASM } /***************************************************************************** @@ -9542,7 +9542,7 @@ void emitter::emitGCregDeadUpd(regNumber reg, BYTE* addr) { assert(emitIssuing); -#if EMIT_GENERATE_GCINFO +#if EMIT_GENERATE_GCINFO && !defined(TARGET_WASM) // Don't track GC changes in epilogs if (emitIGisInEpilog(emitCurIG)) { @@ -9571,7 +9571,7 @@ void emitter::emitGCregDeadUpd(regNumber reg, BYTE* addr) emitThisByrefRegs &= ~regMask; } -#endif // EMIT_GENERATE_GCINFO +#endif // EMIT_GENERATE_GCINFO && !TARGET_WASM } /***************************************************************************** diff --git a/src/coreclr/jit/gcencode.cpp b/src/coreclr/jit/gcencode.cpp index 40908eccefa695..c5d5f6b458b8cb 100644 --- a/src/coreclr/jit/gcencode.cpp +++ b/src/coreclr/jit/gcencode.cpp @@ -4091,7 +4091,12 @@ void GCInfo::gcMakeRegPtrTable( { GCENCODER_WITH_LOGGING(gcInfoEncoderWithLog, gcInfoEncoder); + // TODO-WASM: Enable tracked GC slots for precise GC +#ifdef TARGET_WASM + const bool noTrackedGCSlots = true; +#else const bool noTrackedGCSlots = m_compiler->opts.MinOpts(); +#endif if (mode == MAKE_REG_PTR_MODE_ASSIGN_SLOTS) { @@ -4646,6 +4651,7 @@ void GCInfo::gcInfoRecordGCRegStateChange(GcInfoEncoder* gcInfoEncoder, regMaskSmall byRefMask, regMaskSmall* pPtrRegs) { +#ifndef TARGET_WASM // Precondition: byRefMask is a subset of regMask. assert((byRefMask & ~regMask) == 0); @@ -4703,6 +4709,7 @@ void GCInfo::gcInfoRecordGCRegStateChange(GcInfoEncoder* gcInfoEncoder, // Turn the bit we've just generated off and continue. regMask ^= tmpMask; // EAX,ECX,EDX,EBX,---,EBP,ESI,EDI } +#endif // !TARGET_WASM } /************************************************************************** diff --git a/src/coreclr/jit/gcinfo.cpp b/src/coreclr/jit/gcinfo.cpp index e687e169e2a049..f26c87cbcbeeee 100644 --- a/src/coreclr/jit/gcinfo.cpp +++ b/src/coreclr/jit/gcinfo.cpp @@ -196,7 +196,7 @@ void GCInfo::gcMarkRegSetNpt(regMaskTP regMask DEBUGARG(bool forceOutput)) void GCInfo::gcMarkRegPtrVal(regNumber reg, var_types type) { -#if EMIT_GENERATE_GCINFO +#if EMIT_GENERATE_GCINFO && !defined(TARGET_WASM) regMaskTP regMask = genRegMask(reg); switch (type) @@ -211,7 +211,7 @@ void GCInfo::gcMarkRegPtrVal(regNumber reg, var_types type) gcMarkRegSetNpt(regMask); break; } -#endif // EMIT_GENERATE_GCINFO +#endif // EMIT_GENERATE_GCINFO && !TARGET_WASM } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/targetwasm.h b/src/coreclr/jit/targetwasm.h index ba00eb9624900d..1262df809f9d3b 100644 --- a/src/coreclr/jit/targetwasm.h +++ b/src/coreclr/jit/targetwasm.h @@ -50,7 +50,7 @@ #define CSE_CONSTS 1 // Enable if we want to CSE constants #define LOWER_DECOMPOSE_LONGS 0 // Decompose TYP_LONG operations into (typically two) TYP_INT ones #define EMIT_TRACK_STACK_DEPTH 0 // No need to track arg pushes/pops -#define EMIT_GENERATE_GCINFO 0 // Codegen and emit not responsible for GC liveness tracking and GCInfo generation +#define EMIT_GENERATE_GCINFO 1 // Codegen and emit generate GC info; on WASM this enables stack slot GC info encoding without fixed-register GC tracking // Since we don't have a fixed register set on WASM, we set most of the following register defines to 'none'-like values. #define REG_FP_FIRST REG_NA diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 0be908211636f7..ce51f68858eaee 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -1581,10 +1581,15 @@ private ObjectNode.ObjectData EncodeEHInfo() /// private void setVars(CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars) { - Debug.Assert(_debugVarInfos == null); + // FIXME: This can erroneously trigger when a method fails compilation late and we + // successfully retry compilation after the failure. + // Debug.Assert(_debugVarInfos == null); if (cVars == 0) + { + _debugVarInfos = null; return; + } _debugVarInfos = new NativeVarInfo[cVars]; for (int i = 0; i < cVars; i++) @@ -1601,7 +1606,9 @@ private void setVars(CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* var /// private void setBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap) { - Debug.Assert(_debugLocInfos == null); + // FIXME: This can erroneously trigger when a method fails compilation late and we + // successfully retry compilation after the failure. + // Debug.Assert(_debugLocInfos == null); _debugLocInfos = new OffsetMapping[cMap]; for (int i = 0; i < cMap; i++) diff --git a/src/coreclr/vm/eetwain.cpp b/src/coreclr/vm/eetwain.cpp index a1ec17c0002fa9..85d9d07b731faf 100644 --- a/src/coreclr/vm/eetwain.cpp +++ b/src/coreclr/vm/eetwain.cpp @@ -712,6 +712,7 @@ bool EECodeManager::IsGcSafe( EECodeInfo *pCodeInfo, return false; } +// FIXME-WASM: Add TARGET_WASM once we implement tail calls on Wasm. #if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) bool EECodeManager::HasTailCalls( EECodeInfo *pCodeInfo) { @@ -1941,7 +1942,7 @@ void InterpreterCodeManager::ResumeAfterCatch(CONTEXT *pContext, size_t targetSS #if defined(HOST_AMD64) && defined(HOST_WINDOWS) targetSSP = pInterpreterFrame->GetInterpExecMethodSSP(); -#endif +#endif ExecuteFunctionBelowContext((PCODE)ThrowResumeAfterCatchException, pContext, targetSSP, resumeSP, resumeIP); #endif // TARGET_WASM } @@ -2111,7 +2112,7 @@ static void VirtualUnwindInterpreterCallFrame(TADDR sp, T_CONTEXT *pContext) else { // This indicates that there are no more interpreter frames to unwind in the current InterpExecMethod - // The stack walker will not find any code manager for the address InterpreterFrame::DummyCallerIP (0) + // The stack walker will not find any code manager for the address InterpreterFrame::DummyCallerIP (0) // and move on to the next explicit frame which is the InterpreterFrame. // The SP is set to the address of the InterpreterFrame. For the case of interpreted exception handling // funclets, this matches the pExInfo->m_csfEHClause.SP that the CallFunclet sets. diff --git a/src/coreclr/vm/gcinfodecoder.cpp b/src/coreclr/vm/gcinfodecoder.cpp index 82842705d217f7..681411ae521851 100644 --- a/src/coreclr/vm/gcinfodecoder.cpp +++ b/src/coreclr/vm/gcinfodecoder.cpp @@ -2274,10 +2274,8 @@ template void TGcInfoDecoder::ReportSt pCallBack(hCallBack, pObjRef, gcFlags DAC_ARG(DacSlotLocation(GetStackReg(spBase), spOffset, true))); } -#ifndef TARGET_WASM // Instantiate the decoder so other files can use it template class TGcInfoDecoder; -#endif // !TARGET_WASM #ifdef FEATURE_INTERPRETER template class TGcInfoDecoder;