Repository: dotnet/runtime
File: src/coreclr/jit/codegenwasm.cpp (C++)

Code before:

    GetEmitter()->emitIns(ins);
    genProduceReg(tree);
}

//---------------------------------------------------------------------
// genJumpToThrowHlpBlk - generate code to invoke a throw helper call
//
// Arguments:
//    codeKind -- kind of throw helper call needed
//
void CodeGen::genJumpToThrowHlpBlk(SpecialCodeKind codeKind)
{
    if (m_compiler->fgUseThrowHelperBlocks())
    {
        Compiler::AddCodeDsc* const add = m_compiler->fgGetExcptnTarget(codeKind, m_compiler->compCurBB);
        assert(add != nullptr);
        assert(add->acdUsed);
        GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, m_compiler->compMaxUncheckedOffsetForNullObject);
        GetEmitter()->emitIns(INS_I_le_u);
        inst_JMP(EJ_jmpif, add->acdDstBlk);
    }
    else
    {
        GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, m_compiler->compMaxUncheckedOffsetForNullObject);
        GetEmitter()->emitIns(INS_I_le_u);
        GetEmitter()->emitIns(INS_if);
        genEmitHelperCall(m_compiler->acdHelper(codeKind), 0, EA_UNKNOWN);
        GetEmitter()->emitIns(INS_end);
    }
}

//---------------------------------------------------------------------
// genCodeForNullCheck - generate code for a GT_NULLCHECK node
//
// Arguments:
//    tree - the GT_NULLCHECK node
//
void CodeGen::genCodeForNullCheck(GenTreeIndir* tree)
{
    genConsumeAddress(tree->Addr());
    GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, m_compiler->compMaxUncheckedOffsetForNullObject);
    GetEmitter()->emitIns(INS_I_le_u);
    genJumpToThrowHlpBlk(SCK_NULL_CHECK);
}

//------------------------------------------------------------------------
// genRangeCheck - generate code for a GT_BOUNDS_CHECK node
//
// Arguments:
//    tree - the GT_BOUNDS_CHECK node

Review comment (bug):
This code incorrectly emits a comparison that duplicates the comparison already performed by the caller. Both genCodeForNullCheck (lines 1246-1247) and genRangeCheck (lines 1260-1261) emit their own comparison instructions before calling genJumpToThrowHlpBlk. The comparison result is already on the stack when genJumpToThrowHlpBlk is called, so these lines should be removed. The function should expect the comparison result to be on the stack and only emit the if/end block around the helper call.

Code after:

    GetEmitter()->emitIns(ins);
    genProduceReg(tree);
}

//---------------------------------------------------------------------
// genJumpToThrowHlpBlk - generate code to invoke a throw helper call
//
// Arguments:
//    codeKind -- kind of throw helper call needed
//
// Notes:
//    On entry the predicate for the throw helper is the only item on the Wasm stack.
//    An exception is thrown if the predicate is true.
//
void CodeGen::genJumpToThrowHlpBlk(SpecialCodeKind codeKind)
{
    if (m_compiler->fgUseThrowHelperBlocks())
    {
        Compiler::AddCodeDsc* const add = m_compiler->fgGetExcptnTarget(codeKind, m_compiler->compCurBB);
        assert(add != nullptr);
        assert(add->acdUsed);
        inst_JMP(EJ_jmpif, add->acdDstBlk);
    }
    else
    {
        GetEmitter()->emitIns(INS_if);
        // Throw helper arity is (i (sp)) -> (void).
        // Push SP here as the arg for the call.
        GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, WasmRegToIndex(GetStackPointerReg()));
        genEmitHelperCall(m_compiler->acdHelper(codeKind), 0, EA_UNKNOWN);
        GetEmitter()->emitIns(INS_end);
    }
}

//---------------------------------------------------------------------
// genCodeForNullCheck - generate code for a GT_NULLCHECK node
//
// Arguments:
//    tree - the GT_NULLCHECK node
//
void CodeGen::genCodeForNullCheck(GenTreeIndir* tree)
{
    genConsumeAddress(tree->Addr());
    GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, m_compiler->compMaxUncheckedOffsetForNullObject);
    GetEmitter()->emitIns(INS_I_le_u);
    genJumpToThrowHlpBlk(SCK_NULL_CHECK);
}

//------------------------------------------------------------------------
// genRangeCheck - generate code for a GT_BOUNDS_CHECK node