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

Code before:

    regNumber thisReg = REG_NA;

    if (call->NeedsNullCheck())
    {
        CallArg* thisArg  = call->gtArgs.GetThisArg();
        GenTree* thisNode = thisArg->GetNode();
        thisReg           = GetMultiUseOperandReg(thisNode);
        assert(thisReg != REG_NA);
    }

    for (CallArg& arg : call->gtArgs.EarlyArgs())
    {
        genConsumeReg(arg.GetEarlyNode());
    }

    for (CallArg& arg : call->gtArgs.LateArgs())
    {
        genConsumeReg(arg.GetLateNode());
    }

    if (call->NeedsNullCheck())
    {
        GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, WasmRegToIndex(thisReg));
        GetEmitter()->emitIns_I(INS_I_const, EA_PTRSIZE, m_compiler->compMaxUncheckedOffsetForNullObject);
        GetEmitter()->emitIns(INS_I_le_u);
        genJumpToThrowHlpBlk(SCK_NULL_CHECK);
    }

    genCallInstruction(call);
    WasmProduceReg(call);
}

//------------------------------------------------------------------------
// genCallInstruction - Generate instructions necessary to transfer control to the call.
//
// Arguments:
//    call - the GT_CALL node
//
void CodeGen::genCallInstruction(GenTreeCall* call)
{
    EmitCallParams params;
    params.isJump      = call->IsFastTailCall();
    params.hasAsyncRet = call->IsAsync();

    // We need to propagate the debug information to the call instruction, so we can emit
    // an IL to native mapping record for the call, to support managed return value debugging.
    // We don't want tail call helper calls that were converted from normal calls to get a record,
    // so we skip this hash table lookup logic in that case.
    if (m_compiler->opts.compDbgInfo && m_compiler->genCallSite2DebugInfoMap != nullptr && !call->IsTailCall())
    {

Review comment (suggestion):
We should add a method like `genEmitNullCheck(regNumber reg)` (`reg == REG_NA` would imply 'value already on the value stack) and use it here and in `GT_NULLCHECK`.

Code after:
    {
        var_types   type = tree->TypeGet();
        instruction ins  = ins_Store(type);

        // TODO-WASM: Memory barriers

        GetEmitter()->emitIns_I(ins, emitActualTypeSize(type), 0);
    }

    genUpdateLife(tree);
}

//------------------------------------------------------------------------
// genCall: Produce code for a GT_CALL node
//
// Arguments:
//    call - the GT_CALL node
//
void CodeGen::genCall(GenTreeCall* call)
{
    regNumber thisReg = REG_NA;

    if (call->NeedsNullCheck())
    {
        CallArg* thisArg  = call->gtArgs.GetThisArg();
        GenTree* thisNode = thisArg->GetNode();
        thisReg           = GetMultiUseOperandReg(thisNode);
    }

    for (CallArg& arg : call->gtArgs.EarlyArgs())
    {
        genConsumeReg(arg.GetEarlyNode());
    }

    for (CallArg& arg : call->gtArgs.LateArgs())
    {
        genConsumeReg(arg.GetLateNode());
    }

    if (call->NeedsNullCheck())
    {
        genEmitNullCheck(thisReg);
    }

    genCallInstruction(call);
    WasmProduceReg(call);
}

//------------------------------------------------------------------------
// genCallInstruction - Generate instructions necessary to transfer control to the call.
//