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
2 changes: 2 additions & 0 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class CodeGen final : public CodeGenInterface
//-------------------------------------------------------------------------

void genReportEH();
void genReportEHClauses(EHClauseInfo* clauses);

// Allocates storage for the GC info, writes the GC info into that storage, records the address of the
// GC info of the method with the EE, and returns a pointer to the "info" portion (just post-header) of
Expand Down Expand Up @@ -221,6 +222,7 @@ class CodeGen final : public CodeGenInterface
void genEmitNullCheck(regNumber reg);
unsigned GetStackPointerRegIndex() const;
unsigned GetFramePointerRegIndex() const;
void ensureCurrentFuncIsUnwindable();
#endif

void genEmitStartBlock(BasicBlock* block);
Expand Down
36 changes: 20 additions & 16 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2418,11 +2418,6 @@ void CodeGen::genEmitMachineCode()
//
void CodeGen::genEmitUnwindDebugGCandEH()
{
#ifdef TARGET_WASM
// TODO-WASM: Fix this phase causing an assertion failure even for methods with no GC locals or EH clauses
return;
#endif

/* Now that the code is issued, we can finalize and emit the unwind data */

m_compiler->unwindEmit(*codePtr, coldCodePtr);
Expand Down Expand Up @@ -2529,11 +2524,9 @@ void CodeGen::genEmitUnwindDebugGCandEH()
}

#ifndef TARGET_WASM
/*****************************************************************************
*
* Report EH clauses to the VM
*/

//----------------------------------------------------------------------
// genReportEH: create and report EH info to the VM
//
void CodeGen::genReportEH()
{
if (m_compiler->compHndBBtabCount == 0)
Expand Down Expand Up @@ -2561,12 +2554,6 @@ void CodeGen::genReportEH()
m_compiler->eeSetEHcount(m_compiler->compHndBBtabCount);
m_compiler->Metrics.EHClauseCount = (int)m_compiler->compHndBBtabCount;

struct EHClauseInfo
{
CORINFO_EH_CLAUSE clause;
EHblkDsc* HBtab;
};

EHClauseInfo* clauses = new (m_compiler, CMK_Codegen) EHClauseInfo[m_compiler->compHndBBtabCount];

// Set up EH clause table, but don't report anything to the VM, yet.
Expand Down Expand Up @@ -2605,6 +2592,19 @@ void CodeGen::genReportEH()
clauses[XTnum++] = {clause, HBtab};
}

genReportEHClauses(clauses);
}

#endif // !defined(TARGET_WASM)

//----------------------------------------------------------------------
// genReportEH: create and report EH info to the VM
//
// Arguments:
// clauses -- eh clause data to report
//
void CodeGen::genReportEHClauses(EHClauseInfo* clauses)
{
// The JIT's ordering of EH clauses does not guarantee that clauses covering the same try region are contiguous.
// We need this property to hold true so the CORINFO_EH_CLAUSE_SAMETRY flag is accurate.
jitstd::sort(clauses, clauses + m_compiler->compHndBBtabCount,
Expand All @@ -2624,6 +2624,8 @@ void CodeGen::genReportEH()
return leftTryIndex < rightTryIndex;
});

unsigned XTnum;

// Now, report EH clauses to the VM in order of increasing try region index.
for (XTnum = 0; XTnum < m_compiler->compHndBBtabCount; XTnum++)
{
Expand Down Expand Up @@ -2653,6 +2655,8 @@ void CodeGen::genReportEH()
assert(XTnum == m_compiler->compHndBBtabCount);
}

#ifndef TARGET_WASM

//----------------------------------------------------------------------
// genUseOptimizedWriteBarriers: Determine if an optimized write barrier
// helper should be used.
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/codegeninterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ class NodeInternalRegisters
#endif // !HAS_FIXED_REGISTER_SET
};

struct EHClauseInfo
{
CORINFO_EH_CLAUSE clause;
EHblkDsc* HBtab;
};

class CodeGenInterface
{
friend class emitter;
Expand Down
130 changes: 121 additions & 9 deletions src/coreclr/jit/codegenwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ static const instruction INS_I_ge_u = INS_i32_ge_u;
static const instruction INS_I_gt_u = INS_i32_gt_u;
#endif // !TARGET_64BIT

//------------------------------------------------------------------------
// ensureCurrentFuncIsUnwindable: ensure we set up an unwindable frame
// for the current function or funclet.
//
void CodeGen::ensureCurrentFuncIsUnwindable()
{
FuncInfoDsc* const func = m_compiler->funCurrentFunc();
func->ensureUnwindableFrame(m_compiler);
}

//------------------------------------------------------------------------
// GetStackPointerRegIndex: get the Wasm local index for the stack pointer
//
Expand All @@ -58,10 +68,32 @@ unsigned CodeGen::GetFramePointerRegIndex() const
return WasmRegToIndex(fpReg);
}

//------------------------------------------------------------------------
// genMarkLabelsForCodegen: mark labels for codegen
//
void CodeGen::genMarkLabelsForCodegen()
{
// No work needed here for now.
// We mark labels as needed in genEmitStartBlock.
assert(!m_compiler->fgSafeBasicBlockCreation);

JITDUMP("Mark labels for codegen\n");

#ifdef DEBUG
// No label flags should be set before this.
for (BasicBlock* const block : m_compiler->Blocks())
{
assert(!block->HasFlag(BBF_HAS_LABEL));
}
#endif // DEBUG

// Mark all the funclet boundaries.
//
for (FuncInfoDsc* const func : m_compiler->Funcs())
{
BasicBlock* const firstBlock = func->GetStartBlock(m_compiler);
firstBlock->SetFlags(BBF_HAS_LABEL);

JITDUMP(" " FMT_BB " : %s begin\n", firstBlock->bbNum, (func->funKind == FUNC_ROOT) ? "method" : "funclet");
}
}

//------------------------------------------------------------------------
Expand Down Expand Up @@ -108,6 +140,8 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni
return;
}

m_compiler->unwindAllocStack(frameSize);

// TODO-WASM: reverse pinvoke frame allocation
//
if (!m_compiler->lvaGetDesc(m_compiler->lvaWasmSpArg)->lvIsParam)
Expand All @@ -132,6 +166,22 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, spLclIndex);
GetEmitter()->emitIns_I(INS_local_set, EA_PTRSIZE, WasmRegToIndex(fpReg));
}

FuncInfoDsc* const func = m_compiler->funGetFunc(ROOT_FUNC_IDX);

if (func->needsUnwindableFrame)
{
assert(m_compiler->lvaWasmVirtualIP != BAD_VAR_NUM);
assert(m_compiler->lvaWasmFunctionIndex != BAD_VAR_NUM);

// fp[0] == functionIndex
//
// TODO-WASM: Save the actual function index. For now we save a fixed constant
//
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetFramePointerRegIndex());
GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, 0xBBBB);
Comment thread
AndyAyersMS marked this conversation as resolved.
GetEmitter()->emitIns_S(ins_Store(TYP_I_IMPL), EA_PTRSIZE, m_compiler->lvaWasmFunctionIndex, 0);
}
}

//------------------------------------------------------------------------
Expand Down Expand Up @@ -306,6 +356,32 @@ void CodeGen::genFuncletProlog(BasicBlock* block)

// All the funclet params are used from their home registers, so nothing
// needs homing here.
//
// If the funclet needs to be unwindable (contains any calls), set up
// what we need.
//
if (func->needsUnwindableFrame)
{
// We need two stack slots for the function index and for the funclet virtual IP.
// We also need to keep SP aligned.
//
size_t slotSize = 2 * TARGET_POINTER_SIZE;
size_t frameSize = AlignUp(slotSize, STACK_ALIGN);
m_compiler->unwindAllocStack((unsigned)frameSize);

// Move SP
//
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetStackPointerRegIndex());
GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, frameSize);
GetEmitter()->emitIns(INS_I_sub);
GetEmitter()->emitIns_I(INS_local_set, EA_PTRSIZE, GetStackPointerRegIndex());

// TODO-WASM: Save the funclet index. For now we save a fixed constant
//
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetStackPointerRegIndex());
GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, 0xAAAA);
Comment thread
AndyAyersMS marked this conversation as resolved.
GetEmitter()->emitIns_I(ins_Store(TYP_I_IMPL), EA_PTRSIZE, 0);
}
}

//------------------------------------------------------------------------
Expand Down Expand Up @@ -2375,6 +2451,8 @@ void CodeGen::genCall(GenTreeCall* call)
//
void CodeGen::genCallInstruction(GenTreeCall* call)
{
ensureCurrentFuncIsUnwindable();

EmitCallParams params;
params.isJump = call->IsFastTailCall();
params.hasAsyncRet = call->IsAsync();
Expand Down Expand Up @@ -2504,6 +2582,8 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
//
void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTargetReg /*= REG_NA */)
{
ensureCurrentFuncIsUnwindable();

EmitCallParams params;

CORINFO_CONST_LOOKUP helperFunction = m_compiler->compGetHelperFtn((CorInfoHelpFunc)helper);
Expand Down Expand Up @@ -2788,9 +2868,9 @@ void CodeGen::genCompareFloat(GenTreeOp* treeNode)
// * whether the size operand is a constant or not
// * whether the allocated memory needs to be zeroed or not (info.compInitMem)
//
// If the sp is changed, the value at sp[0] must be the frame pointer
// so that the runtime unwinder can locate the base of the fixed area
// in the shadow stack.
// If the sp is changed, the value at sp[0] must be set to zero and
Comment thread
AndyAyersMS marked this conversation as resolved.
// the frame pointer stored at sp[TARGET_POINTER_SIZE] so that the runtime unwinder
// can locate the base of the fixed area in the shadow stack.
//
void CodeGen::genLclHeap(GenTree* tree)
{
Expand Down Expand Up @@ -2845,10 +2925,16 @@ void CodeGen::genLclHeap(GenTree* tree)
}

// SP now points at the reserved space just below the allocation.
// Save the frame pointer at sp[0].
// Save the frame pointer at sp[TARGET_POINTER_SIZE].
//
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetStackPointerRegIndex());
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetFramePointerRegIndex());
GetEmitter()->emitIns_I(ins_Store(TYP_I_IMPL), EA_PTRSIZE, TARGET_POINTER_SIZE);

// Set sp[0] zero.
//
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetStackPointerRegIndex());
GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, 0);
GetEmitter()->emitIns_I(ins_Store(TYP_I_IMPL), EA_PTRSIZE, 0);

// Leave the base address of the allocated region on the stack.
Expand Down Expand Up @@ -2918,9 +3004,17 @@ void CodeGen::genLclHeap(GenTree* tree)
GetEmitter()->emitIns_I(INS_memory_fill, EA_4BYTE, LINEAR_MEMORY_INDEX);
}

// Re-establish unwind invariant: store FP at SP[0]
// SP now points at the reserved space just below the allocation.
// Save the frame pointer at sp[TARGET_POINTER_SIZE].
//
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetStackPointerRegIndex());
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetFramePointerRegIndex());
GetEmitter()->emitIns_I(ins_Store(TYP_I_IMPL), EA_PTRSIZE, TARGET_POINTER_SIZE);

// Set sp[0] zero.
//
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, GetStackPointerRegIndex());
GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, 0);
GetEmitter()->emitIns_I(ins_Store(TYP_I_IMPL), EA_PTRSIZE, 0);

// Return value
Expand Down Expand Up @@ -3175,7 +3269,11 @@ void CodeGen::genCallFinally(BasicBlock* block)
//
void CodeGen::genEHCatchRet(BasicBlock* block)
{
// No codegen needed for Wasm
// TODO-WASM: return the actual ResumeIP here?
// The runtime expects a return value from a catch funclet,
// but nothing will depend on it.
//
GetEmitter()->emitIns_I(INS_i32_const, EA_4BYTE, 0);
}

void CodeGen::genStructReturn(GenTree* treeNode)
Expand Down Expand Up @@ -3262,9 +3360,23 @@ void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, un
// GCInfo not captured/created by codegen.
}

//---------------------------------------------------------------------
// genReportEH - report EH info to the VM
//
void CodeGen::genReportEH()
{
// EHInfo not captured/created by codegen.
// We created the EH info earlier, during fgWasmVirtualIP.
//
EHClauseInfo* const info = m_compiler->fgWasmEHInfo;
if (info != nullptr)
{

// Tell the VM how many EH clauses to expect.
m_compiler->eeSetEHcount(m_compiler->compHndBBtabCount);
m_compiler->Metrics.EHClauseCount = (int)m_compiler->compHndBBtabCount;

genReportEHClauses(info);
}
}

//---------------------------------------------------------------------
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5030,6 +5030,13 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
stackLevelSetter.Run();
m_pLowering->FinalizeOutgoingArgSpace();

#ifdef TARGET_WASM
// Determine if a Virtual IP is needed and add code as needed to
// keep the Virtual IP updated.
//
DoPhase(this, PHASE_WASM_VIRTUAL_IP, &Compiler::fgWasmVirtualIP);
#endif

FinalizeEH();

// We can not add any new tracked variables after this point.
Expand Down
Loading
Loading