Skip to content

Conversation

@kg
Copy link
Member

@kg kg commented Jan 9, 2026

Depends on #123021

Starting to put together all the code we need for helper calls and calls in general.

@kg kg added arch-wasm WebAssembly architecture area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI labels Jan 9, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to figure out in detail how to specify what method we want to call.

We know roughly what kind of Wasm we want to produce (per the calling convention doc we'll be making lots of indirect calls) but we need help from the JIT host to make this all work out.

I think it might be ok for now to just defer this part of the work and try and get everything else lined up?

// Generate a direct call to a non-virtual user defined or helper method
assert(call->IsHelperCall() || (call->gtCallType == CT_USER_FUNC));

if (call->gtEntryPoint.addr != NULL)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per the calling convention, for user and helper calls we'll also be invoking them indirectly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I'm not clear on whether that means there won't be an addr filled in

@kg kg force-pushed the wasm-genemithelpercall branch from b95ce18 to 499127d Compare January 16, 2026 04:26
@kg
Copy link
Member Author

kg commented Jan 16, 2026

This branch now hits this in crossgen2:

Z:\runtime\src\coreclr\jit\codegenwasm.cpp:1123
Assertion failed 'NYI_WASM: load call target from indirection cell in register' in 'Program:callVoidFunc()' during 'Generate code' (IL size 8; hash 0x4bd04ee2; MinOpts)

@kg
Copy link
Member Author

kg commented Jan 16, 2026

For this:

    [MethodImpl(MethodImplOptions.NoInlining)]
    static void voidFunc () {
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static void callVoidFunc () {
        voidFunc();
    }

R2R now compiles without crashing or asserting, and disasmo generates this:

; Method Program:callVoidFunc() (FullOpts)
G_M45341_IG01:  ;; offset=0x0000
            local.cnt 4
            local[0] type=i32
            local[1] type=i64
            local[2] type=f32
            local[3] type=f64
						;; size=9 bbWeight=1 PerfScore 5.00

G_M45341_IG02:  ;; offset=0x0009
            i32.const 140722950757336
            i32.load 0 0
            call_indirect 0 0
						;; size=14 bbWeight=1 PerfScore 3.00

G_M45341_IG03:  ;; offset=0x0017
            end
						;; size=1 bbWeight=1 PerfScore 1.00
; Total bytes of code: 24

It's not correct but it's a start.

@kg
Copy link
Member Author

kg commented Jan 16, 2026

cc @dotnet/jit-contrib need to figure out how this should actually be factored and shaped and implemented, now that it "works". I don't understand 75% of the code I touched here, for example whether we use EA_8BYTE or a different one still makes no sense to me, and the way we historically separate out emitNewInstrXxx from emitIns_Xxx seems arbitrary. But this is my best guess at how everything should be arranged to make sense for wasm.

@AndyAyersMS
Copy link
Member

@kg what do we need to do to unblock this?

I don't think we'll have the crossgen2 relocation stuff around for a bit, so emitting long-form placeholder values for the various indices/offsets is the best we can do. If you want to try getting the reloc machinery started with this PR then we can look into that too.

@kg
Copy link
Member Author

kg commented Jan 22, 2026

@kg what do we need to do to unblock this?

I don't think we'll have the crossgen2 relocation stuff around for a bit, so emitting long-form placeholder values for the various indices/offsets is the best we can do. If you want to try getting the reloc machinery started with this PR then we can look into that too.

As far as I'm concerned it's done, but I was waiting for someone to review it on the presumption that there's a bunch of things wrong in this PR since I didn't really know what I was doing.

@AndyAyersMS
Copy link
Member

@kg what do we need to do to unblock this?
I don't think we'll have the crossgen2 relocation stuff around for a bit, so emitting long-form placeholder values for the various indices/offsets is the best we can do. If you want to try getting the reloc machinery started with this PR then we can look into that too.

As far as I'm concerned it's done, but I was waiting for someone to review it on the presumption that there's a bunch of things wrong in this PR since I didn't really know what I was doing.

We should be able to do some testing, especially now that #123262 is in. What happens if we try and compile a method that has a call (eg fact or something equally simple).

@kg
Copy link
Member Author

kg commented Jan 22, 2026

@kg what do we need to do to unblock this?
I don't think we'll have the crossgen2 relocation stuff around for a bit, so emitting long-form placeholder values for the various indices/offsets is the best we can do. If you want to try getting the reloc machinery started with this PR then we can look into that too.

As far as I'm concerned it's done, but I was waiting for someone to review it on the presumption that there's a bunch of things wrong in this PR since I didn't really know what I was doing.

We should be able to do some testing, especially now that #123262 is in. What happens if we try and compile a method that has a call (eg fact or something equally simple).

Is this what you mean? #123044 (comment)

EC_MANAGED_PTR, // call_indirect to an unknown managed method or helper (two levels of indirection - ptr to
// arbitrary cell)
// should generate: <push args>; call <func-index>
EC_FUNCTION_INDEX, // call to a known wasm import or function from same module, no indirection
Copy link
Contributor

@SingleAccretion SingleAccretion Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For WASM we only have direct call and indirect call_indirect, which already map to EC_FUNC_TOKEN and EC_INDIR_R, so I don't think we need these kinds to be under ifdefs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have the concept of function pointers in wasm? Or is the idea that the extra level of indirection will be handled somewhere else?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proposal is to use EC_FUNC_TOKEN for what is currently called EC_FUNCTION_INDEX, remove EC_MANAGED_CELL and EC_MANAGED_PTR by handling the indirections they represent in the caller(s), and using EC_INDIR_R to represent "emit call_indirect".

The overall principle is to have emitIns_Call only emit one WASM instruction, the call itself. It is (more) consistent with how other targets represent these things.

@AndyAyersMS
Copy link
Member

We should be able to do some testing, especially now that #123262 is in. What happens if we try and compile a method that has a call (eg fact or something equally simple).

Is this what you mean? #123044 (comment)

Yes --make sure that basic cases look plausible

@AndyAyersMS
Copy link
Member

@kg somehow my comments never got posted, so some are out of date. At any rate I think we can just bypass calling LegalizeArgPlacement for Wasm, the stackifier should take care of this.

@kg
Copy link
Member Author

kg commented Jan 26, 2026

FindEarliestPutArg also appears to call MarkCallPutArgAndFieldListNodes. I will try disabling legalization.

@SingleAccretion
Copy link
Contributor

bypass calling LegalizeArgPlacement

That's true, but only because we don't have any stack arguments currently (were we to have them, we'd have PUTARG_STK, and FEATURE_FIXED_OUT_ARGS == 1. So if we disable it, some asserts will also need to be added. The alternative is to modify MarkPutArgAndFieldListNodes to skip marking non-putarg nodes under !HAS_FIXED_REGISTER_SET.

@kg
Copy link
Member Author

kg commented Jan 26, 2026

FindEarliestPutArg also appears to call MarkCallPutArgAndFieldListNodes. I will try disabling legalization.

With legalization disabled:

Z:\runtime\src\coreclr\jit\lower.cpp:9274
Assertion failed 'arg->OperIsPutArg()' in 'Program:callVoidFunc()' during 'Lowering nodeinfo' (IL size 8; hash 0x4bd04ee2; MinOpts)

I think we can keep chasing all these down, but is it strictly necessary to get rid of putarg? What's bad about having it, at least for now?

@kg
Copy link
Member Author

kg commented Jan 28, 2026

Generating: N002 (???,???) [000005] H----+-----                    t5 =    CNS_INT(h) int    0x420040 ftn
IN0004:             i32.const 4611686018431713344
                                                                        /--*  t4     int    arg1 $1
                                                                        +--*  t5     int    r2r cell $0
Generating: N003 (???,???) [000001] --CXG+-----                         *  CALL r2r_ind void   Program:voidFunc()

This is weird, according to the spew the constant is 0x420040 but we're seemingly getting a huge 64-bit constant (that I'm dutifully writing out for now). Or is that huge number the r2r cell address?
When writing constants do I need to mask off the high bits of what emitGetInsSC returns?

@kg
Copy link
Member Author

kg commented Jan 28, 2026

In codegenwasm.cpp:

        case TYP_INT:
        {
            ins                      = INS_i32_const;
            GenTreeIntConCommon* con = treeNode->AsIntConCommon();
            bits                     = con->IntegralValue();
            assert(((INT64)(INT32)bits) == bits); // <- this fails
            break;
        }

It looks like we have TYP_INT constants with garbage in the high bits somehow.

@kg
Copy link
Member Author

kg commented Jan 28, 2026

I think the problem is here:

    static var_types gtGetTypeForIconFlags(GenTreeFlags flags)
    {
        return flags == GTF_ICON_OBJ_HDL ? TYP_REF : TYP_I_IMPL;
    }

The value in gtNewIconHandleNode is a 64-bit handle (r2r cell address) but we're picking TYP_REF or TYP_I_IMPL for it which both get mapped to a 32-bit int on the wasm target. In this case it looks like we picked TYP_I_IMPL which becomes TYP_INT, and we have a 32-bit constant node with garbage in the high bits.

@AndyAyersMS
Copy link
Member

The right long-term fix is to mark (the instr desc for) this constant as needing a reloc, and have the instr desc refer to the (64 bit) compile-time handle, and encode a maximum-length value in the constant field, and then have the emitter call emitRecordReloc with the instruction stream address of the cosntant field, the compile-time handle, and the fixup type (and also, fix the emit display to indicate what the constant refers to...).

The value we write into the constant can potentially be anything since it will be replaced by the reloc later on. Likely zero is a good choice, or perhaps the low 32 bits of the compile time handle.

For now you might just leave a todo for the reloc part and encode zero.

@kg kg force-pushed the wasm-genemithelpercall branch from fc8c8bd to 83bc9d1 Compare January 28, 2026 17:37
@kg
Copy link
Member Author

kg commented Jan 28, 2026

Latest failure is outside crossgen in the test harness:

[CompileError: WebAssembly.compile(): Compiling function #7 failed: not enough arguments on the stack for call_indirect (need 4, got 1) @+674]

Two of those missing stack values are sp and pep but I'm not sure what the last one is, since I'm calling a void func.

@kg
Copy link
Member Author

kg commented Jan 28, 2026

The missing PEP is easy to fix for now by generating an i32.const for it before a call.
The other missing arg is because the type index was wrong (we need a reloc to be fixed up by r2r). If I delete all the other managed methods from my test assembly, type index 0 becomes correct and I get this far:

Loading test-module.wasm...
Compiling test-module.wasm...
Instantiating test-module.wasm...
OK!
exports=["memory","table","wasm_test_Program__callVoidFunc","wasm_test_Program__voidFunc"]
running 'exports.wasm_test_Program__callVoidFunc(1024, 0)...
wasm://wasm/2afc428a:1


RuntimeError: table index is out of bounds
    at wasm://wasm/2afc428a:wasm-function[1]:0xb6
    at eval (eval at doEval (file:///E:/Documents/Projects/wasm-ryujit-runner/wasm-ryujit-runner.mjs:20:24), <anonymous>:1:9)
    at doEval (file:///E:/Documents/Projects/wasm-ryujit-runner/wasm-ryujit-runner.mjs:20:24)
    at file:///E:/Documents/Projects/wasm-ryujit-runner/wasm-ryujit-runner.mjs:18:5

This is because we currently have an empty function pointer table, so there's nothing callable in it to invoke (let alone at the index we have on the stack.)

@adamperlin
Copy link
Contributor

This is because we currently have an empty function pointer table, so there's nothing callable in it to invoke (let alone at the index we have on the stack.)

Could you possibly post a disasm of what codegen looks like for this function now?

@kg
Copy link
Member Author

kg commented Jan 28, 2026

This is because we currently have an empty function pointer table, so there's nothing callable in it to invoke (let alone at the index we have on the stack.)

Could you possibly post a disasm of what codegen looks like for this function now?

; Total bytes of code 41, prolog size 22, PerfScore 21.00, instruction count 21, allocated bytes for code 41 (MethodHash=4bd04ee2) for method Program:callVoidFunc() (MinOpts)
; ============================================================

*************** After end code gen, before unwindEmit()
G_M45341_IG01:        ; func=00, offs=0x000000, size=0x0016, bbWeight=1, PerfScore 11.00, gcrefRegs=00000000, byrefRegs=00000000, byref, nogc <-- Prolog IG

IN000a: 000000      local.cnt 0
IN000b: 000001      local.get 0
IN000c: 000003      i32.const 8
IN000d: 000005      i32.sub
IN000e: 000006      local.set 0
IN000f: 000008      local.get 0
IN0010: 00000A      local.get 0
IN0011: 00000C      i32.store 0 4
IN0012: 00000F      local.get 0
IN0013: 000011      local.get 1
IN0014: 000013      i32.store 0 0

G_M45341_IG02:        ; offs=0x000016, size=0x0012, bbWeight=1, PerfScore 9.00, gcrefRegs=00000000, byrefRegs=00000000, BB01 [0000], byref

IN0001: 000016      nop
IN0002: 000017      local.get 0
IN0003: 000019      i32.load 0 4
IN0004: 00001C      i32.const 0
IN0005: 00001E      i32.const 0
IN0006: 000020      i32.load 0 0
IN0007: 000023      call_indirect 0 0
IN0008: 000026      nop
IN0009: 000027      nop

G_M45341_IG03:        ; offs=0x000028, size=0x0001, bbWeight=1, PerfScore 1.00, epilog, nogc, extend

IN0015: 000028      end

@adamperlin
Copy link
Contributor

adamperlin commented Jan 28, 2026

IN0001: 000016 nop
IN0002: 000017 local.get 0
IN0003: 000019 i32.load 0 4
IN0004: 00001C i32.const 0
IN0005: 00001E i32.const 0
IN0006: 000020 i32.load 0 0
IN0007: 000023 call_indirect 0 0
IN0008: 000026 nop
IN0009: 000027 nop

I'm a bit confused about the load right before the call_indirect here. I thought the table entry index for call_indirect was encoded directly into the instruction, and didn't come from the stack? I would think we would need something like call_indirect (type index reloc) (table index reloc)

@kg
Copy link
Member Author

kg commented Jan 28, 2026

IN0001: 000016 nop
IN0002: 000017 local.get 0
IN0003: 000019 i32.load 0 4
IN0004: 00001C i32.const 0
IN0005: 00001E i32.const 0
IN0006: 000020 i32.load 0 0
IN0007: 000023 call_indirect 0 0
IN0008: 000026 nop
IN0009: 000027 nop

I'm a bit confused about the load right before the call_indirect here. I thought the table entry index for call_indirect was encoded directly into the instruction, and didn't come from the stack? I would think we would need something like call_indirect (type index reloc) (table index reloc)

EDIT: It should always be either an indirection cell's address (for a direct call) or the address of an indirection cell's address (for an indirect call of a delegate or ftn ptr)

@adamperlin
Copy link
Contributor

EDIT: It should always be either an indirection cell's address (for a direct call) or the address of an indirection cell's address (for an indirect call of a delegate or ftn ptr)

That makes sense, I managed to confuse myself reading the spec.

kg added 5 commits January 29, 2026 09:04
Checkpoint

Fix build

Wasm doesn't have special argument registers in the traditional sense, at least not yet

Checkpoint

Checkpoint

Checkpoint

Fix build

R2R completes simple call without crashing

Handle different callTypes

Emit indirections

Add comment

jit-format

Fix clang build

Checkpoint cleanup

Cleanup

Cleanup

Fix erroneous ifdef

Clean up putarg dependencies
@kg kg force-pushed the wasm-genemithelpercall branch from ab101b1 to 131a1b5 Compare January 29, 2026 17:16
Copilot AI review requested due to automatic review settings January 29, 2026 17:16
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds initial scaffolding for call instructions and helper calls in the WebAssembly RyuJIT backend. The changes enable the compiler to generate direct calls, indirect calls, and tail calls for the WASM target.

Changes:

  • Add support for call-related WebAssembly instructions (call, call_indirect, return_call, return_call_indirect)
  • Implement emitIns_Call in the WASM emitter to handle different call types
  • Add code generation logic for calls in genCall, genCallInstruction, and genEmitHelperCall
  • Update lowering logic to handle WASM's lack of fixed register set
  • Exclude shared helper call allocation methods from WASM builds
  • Enhance constant generation to handle relocations

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/coreclr/jit/lower.cpp Corrects preprocessor directive from #ifdef to #if HAS_FIXED_REGISTER_SET, adds guards for assertions that expect PutArg nodes which WASM doesn't use
src/coreclr/jit/instrswasm.h Adds four new call instructions with proper opcodes and instruction formats
src/coreclr/jit/emitwasm.h Removes unused method declarations for call instruction descriptors that are not needed for WASM
src/coreclr/jit/emitwasm.cpp Implements emitIns_Call with support for direct and indirect calls, adds handling for IF_CALL_INDIRECT format in size calculation, output, and display methods
src/coreclr/jit/emitfmtswasm.h Adds IF_CALL_INDIRECT instruction format definition
src/coreclr/jit/emit.cpp Guards existing helper call allocation methods with #ifndef TARGET_WASM since WASM uses a different approach
src/coreclr/jit/codegenwasm.cpp Implements call generation with genCall, genCallInstruction, and genEmitHelperCall; updates constant generation to handle relocations
src/coreclr/jit/codegencommon.cpp Removes WASM-specific guard around genEmitCallWithCurrentGC, adds guard to exclude async resume functions from WASM

kg and others added 2 commits January 29, 2026 09:23
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings January 29, 2026 17:29
@kg kg marked this pull request as ready for review January 29, 2026 17:30
@kg
Copy link
Member Author

kg commented Jan 29, 2026

I'd like to try and finalize this so we can get it in. Crossgen successfully generates a valid module, though we can't actually perform the call since stuff like relocs is missing. I think the rest of the followup work should be done in separate PRs.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

} while (numMarkedNodes > 0);

// WASM-FIXME: !HAS_FIXED_REGISTER_SET ||
assert(node->OperIsPutArg());
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WASM-FIXME comment suggests that the assertion at line 3106 may fail for WASM because !HAS_FIXED_REGISTER_SET means there are no PUTARG nodes. However, this function already returns nullptr at line 3088 if numMarkedNodes is 0, which would happen when MarkPutArgAndFieldListNodes returns 0 (as it does for WASM when there are no PutArg or FieldList nodes). The assertion may still be reachable if there are FieldList nodes without PutArg nodes. Consider whether this assertion should be conditional on HAS_FIXED_REGISTER_SET, or whether the early exit logic needs adjustment.

Suggested change
assert(node->OperIsPutArg());
assert(!HAS_FIXED_REGISTER_SET || node->OperIsPutArg());

Copilot uses AI. Check for mistakes.
case IF_CALL_INDIRECT:
{
cnsval_ssize_t imm = emitGetInsSC(id);
printf(" 0 %llu", (uint64_t)imm);
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The display format for IF_CALL_INDIRECT at line 720 shows "0 %llu" (table index, then type index), but the actual encoding at lines 539-541 outputs the type index first, then the table index. According to the WebAssembly specification, call_indirect should be encoded as: opcode, type_idx, table_idx. The encoding order is correct, but the display format should be updated to match: "printf(" %llu 0", (uint64_t)imm);" to show type index followed by table index.

Suggested change
printf(" 0 %llu", (uint64_t)imm);
printf(" %llu 0", (uint64_t)imm);

Copilot uses AI. Check for mistakes.

instruction ins;

// FIXME-WASM: Currently while we're loading SP onto the stack we're not loading PEP, so generate one here.
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hardcoded PEP (Program Entry Point) value of 0 is a temporary workaround. The comment indicates this is because SP is loaded onto the stack but not PEP. This needs to be properly implemented before this code can work correctly. Consider tracking this with a more specific TODO or issue reference.

Suggested change
// FIXME-WASM: Currently while we're loading SP onto the stack we're not loading PEP, so generate one here.
// TODO-WASM: Push the actual Program Entry Point (PEP) instead of the placeholder 0 value here
// once PEP is properly propagated and loaded alongside SP in the WASM backend. See issue #NNNNN.

Copilot uses AI. Check for mistakes.
{
instruction ins;
cnsval_ssize_t bits;
instruction ins = INS_unreachable;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
instruction ins = INS_unreachable;
instruction ins = INS_none;

Comment on lines +1034 to +1035
// WASM-TODO: Generate reloc for this handle; 64-bit support
ins = INS_i32_const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// WASM-TODO: Generate reloc for this handle; 64-bit support
ins = INS_i32_const;
// WASM-TODO: Generate reloc for this handle
ins = INS_I_const;

case TYP_DOUBLE:
}

if (ins == INS_unreachable)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (ins == INS_unreachable)
if (ins == INS_none)


assert(!call->IsTailCall());

genCallInstruction(call);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arguments need to be consumed. Something like:

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

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

Comment on lines +1420 to +1421
// Determine return value size(s).
const ReturnTypeDesc* pRetTypeDesc = call->GetReturnTypeDesc();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Determine return value size(s).
const ReturnTypeDesc* pRetTypeDesc = call->GetReturnTypeDesc();

Unused.

Comment on lines +189 to +202
// for the purpose of GC safepointing tail-calls are not real calls
id->idSetIsNoGC(params.isJump || params.noSafePoint || emitNoGChelper(params.methHnd));

#ifdef DEBUG
if (EMIT_GC_VERBOSE)
{
if (id->idIsLargeCall())
{
printf("[%02u] Rec call GC vars = %s\n", id->idDebugOnlyInfo()->idNum,
VarSetOps::ToString(emitComp, ((instrDescCGCA*)id)->idcGCvars));
}
}
#endif

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// for the purpose of GC safepointing tail-calls are not real calls
id->idSetIsNoGC(params.isJump || params.noSafePoint || emitNoGChelper(params.methHnd));
#ifdef DEBUG
if (EMIT_GC_VERBOSE)
{
if (id->idIsLargeCall())
{
printf("[%02u] Rec call GC vars = %s\n", id->idDebugOnlyInfo()->idNum,
VarSetOps::ToString(emitComp, ((instrDescCGCA*)id)->idcGCvars));
}
}
#endif

Same here; no GCInfo tracking in emit.

Comment on lines +404 to +405
size += SizeOfULEB128(0);
size += SizeOfULEB128(emitGetInsSC(this));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
size += SizeOfULEB128(0);
size += SizeOfULEB128(emitGetInsSC(this));
size += SizeOfULEB128(emitGetInsSC(this));
size += SizeOfULEB128(0);

Just to match the actual operand order.

Comment on lines +9252 to +9253
// WASM-FIXME
assert(!HAS_FIXED_REGISTER_SET || use.GetNode()->OperIsPutArg());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// WASM-FIXME
assert(!HAS_FIXED_REGISTER_SET || use.GetNode()->OperIsPutArg());
assert(!HAS_FIXED_REGISTER_SET || use.GetNode()->OperIsPutArg());

This is indeed how it should be.

}
} while (numMarkedNodes > 0);

// WASM-FIXME: !HAS_FIXED_REGISTER_SET ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// WASM-FIXME: !HAS_FIXED_REGISTER_SET ||

We're still only marking putargs (PUTARG_STK, which we don't use currently), so this assert is correct as-is.

Comment on lines +178 to +179
// Indirect load of actual ftn ptr from indirection cell (on the stack)
emitIns_I(INS_i32_load, EA_PTRSIZE, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should push the concept of a function pointer being "the portable entrypoint" down into emitter. For example, we will have indirect unmanaged calls, which will use nakes table indices as function pointers. Obviously, for NAOT this won't hold as well. But it can be a TODO for now.

Suggested change
// Indirect load of actual ftn ptr from indirection cell (on the stack)
emitIns_I(INS_i32_load, EA_PTRSIZE, 0);
// 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);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants