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

Code before:
//   attr        - emit attributes
//   localCount  - the count of locals in this declaration
//   type        - the type of local in the declaration
//   lclOffset   - used to provide the starting index of this local
//
// Notes:
//   `lclOffset` is stored as debug info attached to the instruction,
//    so the offset will only be used if m_debugInfoSize > 0
emitter::instrDesc* emitter::emitNewInstrLclVarDecl(emitAttr      attr,
                                                    unsigned int  localCount,
                                                    WasmValueType type,
                                                    int           lclOffset)
{
    instrDescLclVarDecl* id = static_cast<instrDescLclVarDecl*>(emitAllocAnyInstr(sizeof(instrDescLclVarDecl), attr));
    id->idLclCnt(localCount);
    id->idLclType(type);

    if (m_debugInfoSize > 0)
    {
        id->idDebugOnlyInfo()->lclOffset = lclOffset;
    }

    return id;
}

//-----------------------------------------------------------------------------------
// emitIns_I_Ty: Emit an instruction for a local variable declaration, encoding both
// a count (immediate) and a value type. This is specifically used for local variable
// declarations that require both the number of locals and their type to be encoded.
//
// Arguments:
//   ins      - instruction to emit
//   imm      - immediate value (local count)
//   valType  - value type of the local variable
//   offs     - local variable offset (= count of preceding locals) for debug info
void emitter::emitIns_I_Ty(instruction ins, unsigned int imm, WasmValueType valType, int offs)
{
    instrDesc* id  = emitNewInstrLclVarDecl(EA_8BYTE, imm, valType, offs);
    insFormat  fmt = emitInsFormat(ins);

    id->idIns(ins);
    id->idInsFmt(fmt);

    dispIns(id);
    appendToCurIG(id);
}

WasmValueType emitter::emitGetLclVarDeclType(const instrDesc* id)
{
    assert(id->idIsLclVarDecl());
    return static_cast<const instrDescLclVarDecl*>(id)->lclType;

Review comment (suggestion):
The FIXME comment on line 150 mentions 'we're not loading PEP' but doesn't explain what PEP stands for or why loading it is important. Consider expanding this comment to clarify what PEP means in this context and the intended future implementation.
```suggestion
    // FIXME-WASM: The WASM calling convention for managed code expects both SP and an additional
    // "PEP" value (a companion stack/metadata pointer used by the runtime for stack walking/GC)
    // to be present on the stack before making the call. The current lowering/prolog code only
    // materializes SP and does not yet produce the real PEP value. As a temporary workaround,
    // we synthesize a placeholder PEP here by pushing a constant zero so that the generated
    // stack layout matches what the runtime expects. Once the prolog/epilog and lowering logic
    // are updated to compute and load the correct PEP, this manual i32.const should be removed
    // and replaced with code that pushes the actual PEP value.
```

Code after:
 *
 */

void emitter::emitIns_Call(const EmitCallParams& params)
{
    /* Sanity check the arguments depending on callType */

    assert(params.callType < EC_COUNT);
    assert((params.callType == EC_FUNC_TOKEN) || (params.addr == nullptr));

    /* Managed RetVal: emit sequence point for the call */
    if (emitComp->opts.compDbgInfo && params.debugInfo.GetLocation().IsValid())
    {
        codeGen->genIPmappingAdd(IPmappingDscKind::Normal, params.debugInfo, false);
    }

    /*
        We need to allocate the appropriate instruction descriptor based
        on whether this is a direct/indirect call, and whether we need to
        record an updated set of live GC variables.
     */
    instrDesc* id = nullptr;

    instruction ins;

    // FIXME-WASM: Currently while we're loading SP onto the stack we're not loading PEP, so generate one here.
    emitIns_I(INS_i32_const, EA_4BYTE, 0);

    switch (params.callType)
    {
        case EC_FUNC_TOKEN:
            ins = params.isJump ? INS_return_call : INS_call;
            id  = emitNewInstrSC(EA_8BYTE, 0 /* FIXME-WASM: function index reloc */);
            id->idIns(ins);
            id->idInsFmt(IF_ULEB128);
            break;
        case EC_INDIR_R:
            // Indirect load of actual ftn ptr from indirection cell (on the stack)
            // TODO-WASM: temporary, move this into higher layers (lowering).
            emitIns_I(INS_i32_load, EA_PTRSIZE, 0);
            ins = params.isJump ? INS_return_call_indirect : INS_call_indirect;
            id  = emitNewInstrSC(EA_8BYTE, 0 /* FIXME-WASM: type index reloc */);
            id->idIns(ins);
            id->idInsFmt(IF_CALL_INDIRECT);
            break;
        default:
            unreached();
    }

    if (m_debugInfoSize > 0)
    {