Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/gcinfo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/gcinfo/gcinfoencoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<TargetGcInfoEncoding>;
#endif // !TARGET_WASM

#ifdef FEATURE_INTERPRETER
template class TGcInfoEncoder<InterpreterGcInfoEncoding>;
Expand Down
53 changes: 51 additions & 2 deletions src/coreclr/inc/gcinfotypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -909,13 +909,62 @@ 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
Comment thread
kg marked this conversation as resolved.

#define TargetGcInfoEncoding InterpreterGcInfoEncoding
#define TargetGcInfoEncoding Wasm32GcInfoEncoding

// TODO-WASM: Investigate normalizing stack slots to save space based on wasm stack alignment

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); }
Comment thread
kg marked this conversation as resolved.
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

Expand Down
6 changes: 3 additions & 3 deletions src/coreclr/jit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Comment thread
kg marked this conversation as resolved.

Expand Down Expand Up @@ -120,6 +120,8 @@ set( JIT_SOURCES
fgstmt.cpp
flowgraph.cpp
forwardsub.cpp
gcdecode.cpp
gcencode.cpp
gcinfo.cpp
gentree.cpp
gschecks.cpp
Expand Down Expand Up @@ -186,8 +188,6 @@ set ( JIT_NATIVE_TARGET_SOURCES
lsra.cpp
lsrabuild.cpp
regMaskTPOps.cpp
gcdecode.cpp
gcencode.cpp
unwind.cpp
)

Expand Down
20 changes: 13 additions & 7 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
// Targets like Wasm do not have a fixed set of registers so the regset logic in this method is unnecessary.
#if EMIT_GENERATE_GCINFO && HAS_FIXED_REGISTER_SET
// The regset being updated here is only needed for codegen-level GCness tracking.
regMaskTP regMask = genGetRegMask(varDsc);

#ifdef DEBUG
Expand Down Expand Up @@ -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 && HAS_FIXED_REGISTER_SET
}

#ifndef TARGET_WASM
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -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())
Expand All @@ -1092,6 +1097,7 @@ void Compiler::compChangeLife(VARSET_VALARG_TP newLife)
{
codeGen->gcInfo.gcRegByrefSetCur |= regMask;
}
#endif // !TARGET_WASM
}
else if (lvaIsGCTracked(varDsc))
{
Expand Down Expand Up @@ -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))
{
Expand All @@ -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())
{
Expand Down Expand Up @@ -7202,12 +7208,12 @@ void CodeGen::genReturn(GenTree* treeNode)
}
}

#if EMIT_GENERATE_GCINFO
#if EMIT_GENERATE_GCINFO && HAS_FIXED_REGISTER_SET
if (treeNode->OperIs(GT_RETURN, GT_SWIFT_ERROR_RET))
{
genMarkReturnGCInfo();
}
#endif // EMIT_GENERATE_GCINFO
#endif // EMIT_GENERATE_GCINFO && HAS_FIXED_REGISTER_SET

#ifdef PROFILING_SUPPORTED

Expand Down
12 changes: 6 additions & 6 deletions src/coreclr/jit/codegenlinear.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 && HAS_FIXED_REGISTER_SET
// 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
Expand Down Expand Up @@ -353,7 +353,7 @@ void CodeGen::genCodeForBlock(BasicBlock* block)
}
}
}
#endif // EMIT_GENERATE_GCINFO
#endif // EMIT_GENERATE_GCINFO && HAS_FIXED_REGISTER_SET

/* Start a new code output block */

Expand Down Expand Up @@ -569,7 +569,7 @@ void CodeGen::genCodeForBlock(BasicBlock* block)

regSet.rsSpillChk();

#if EMIT_GENERATE_GCINFO
#if EMIT_GENERATE_GCINFO && HAS_FIXED_REGISTER_SET
// Make sure we didn't bungle pointer register tracking
regMaskTP ptrRegs = gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur;
regMaskTP nonVarPtrRegs = ptrRegs & ~regSet.GetMaskVars();
Expand Down Expand Up @@ -618,7 +618,7 @@ void CodeGen::genCodeForBlock(BasicBlock* block)
}

noway_assert(nonVarPtrRegs == RBM_NONE);
#endif // EMIT_GENERATE_GCINFO
#endif // EMIT_GENERATE_GCINFO && HAS_FIXED_REGISTER_SET
#endif // DEBUG

#if defined(DEBUG)
Expand Down Expand Up @@ -1601,7 +1601,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 && HAS_FIXED_REGISTER_SET
// 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
Expand Down Expand Up @@ -1659,7 +1659,7 @@ regNumber CodeGen::genConsumeReg(GenTree* tree)
{
gcInfo.gcMarkRegSetNpt(tree->gtGetRegMask());
}
#endif // EMIT_GENERATE_GCINFO
#endif // EMIT_GENERATE_GCINFO && HAS_FIXED_REGISTER_SET

genCheckConsumeNode(tree);
return tree->GetRegNum();
Expand Down
37 changes: 36 additions & 1 deletion src/coreclr/jit/codegenwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -3351,7 +3353,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();
}

//---------------------------------------------------------------------
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10738,6 +10738,10 @@ void Compiler::EnregisterStats::RecordLocal(const LclVarDsc* varDsc)
m_simdUserForcesDep++;
break;

case DoNotEnregisterReason::WasmGCVisibility:
Comment thread
kg marked this conversation as resolved.
m_wasmGcVisibility++;
break;

default:
unreached();
break;
Expand Down Expand Up @@ -10866,6 +10870,7 @@ void Compiler::EnregisterStats::Dump(FILE* fout) const
PRINT_STATS(m_swizzleArg, notEnreg);
PRINT_STATS(m_blockOpRet, notEnreg);
PRINT_STATS(m_returnSpCheck, notEnreg);
PRINT_STATS(m_wasmGcVisibility, notEnreg);
PRINT_STATS(m_callSpCheck, notEnreg);
PRINT_STATS(m_simdUserForcesDep, notEnreg);

Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ enum class DoNotEnregisterReason
CallSpCheck, // the local is used to do SP check on every call
SimdUserForcesDep, // a promoted struct was used by a SIMD/HWI node; it must be dependently promoted
HiddenBufferStructArg, // the argument is a hidden return buffer passed to a method.
WasmGCVisibility,
};

enum class AddressExposedReason
Expand Down Expand Up @@ -11759,6 +11760,7 @@ class Compiler
unsigned m_liveInOutHndlr;
unsigned m_depField;
unsigned m_noRegVars;
unsigned m_wasmGcVisibility;
#ifdef JIT32_GCENCODER
unsigned m_PinningRef;
#endif // JIT32_GCENCODER
Expand Down
Loading
Loading