Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d1d3737
[wasm][R2R] Model inline-unbox slow-path helper as value-returning on…
lewing Jul 26, 2026
d1c5be2
[wasm] Fix two more helper calls modeled with the wrong return arity
lewing Jul 26, 2026
d8dba2a
[wasm] Add regression test for the stack-allocated unbox type-test he…
lewing Jul 26, 2026
0993520
[wasm] Rename HelperUnboxRetType to make the discard intent explicit
lewing Jul 26, 2026
fff0265
Trim comments
lewing Jul 26, 2026
96a1e56
Model the inline unbox helper as TYP_BYREF on all targets
lewing Jul 26, 2026
d34c5d5
Model the discarded unbox helper as value-returning only on wasm
lewing Jul 26, 2026
93b5bcd
Drop the gtUnusedValNode wrapper in fgMorphInit
lewing Jul 27, 2026
99c4432
[wasm][R2R] Model inline-unbox slow-path helper as value-returning on…
lewing Jul 26, 2026
31d63ea
[wasm] Fix two more helper calls modeled with the wrong return arity
lewing Jul 26, 2026
648c6ef
[wasm] Add regression test for the stack-allocated unbox type-test he…
lewing Jul 26, 2026
f2fec2e
[wasm] Rename HelperUnboxRetType to make the discard intent explicit
lewing Jul 26, 2026
4331eb3
Trim comments
lewing Jul 26, 2026
f2a71f6
Model the inline unbox helper as TYP_BYREF on all targets
lewing Jul 26, 2026
60c1db7
Model the discarded unbox helper as value-returning only on wasm
lewing Jul 26, 2026
94a3572
Drop the gtUnusedValNode wrapper in fgMorphInit
lewing Jul 27, 2026
ecdc3d1
Merge commit '93b5bcdb856c4dc16e668f6fdfdbd5995630c5d4' into lewing-i…
lewing Jul 27, 2026
7b5982b
Merge branch 'main' into lewing-ideal-invention
lewing Jul 27, 2026
f6aa26d
Fix argument order for the box type test helper
lewing Jul 27, 2026
f226e24
Make Runtime_131377 a normal merged test, comment the arg swap
lewing Jul 27, 2026
a53d8e1
Match RhUnboxTypeTest to the new Unbox_TypeTest argument order
lewing Jul 28, 2026
4a20aa8
Revert "Match RhUnboxTypeTest to the new Unbox_TypeTest argument order"
lewing Jul 28, 2026
2247634
Fix the reversed unbox cast message in Unbox_TypeTest_Helper
lewing Jul 28, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,9 @@ private static void Unbox_TypeTest_Helper(MethodTable *pMT1, MethodTable *pMT2)
#endif // FEATURE_TYPEEQUIVALENCE
)
{
CastHelpers.ThrowInvalidCastException(pMT1, pMT2);
// The JIT passes (target, source) to match Unbox, but ThrowInvalidCastException
// takes (source, target) and names them in that order in the message.
CastHelpers.ThrowInvalidCastException(pMT2, pMT1);
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3362,8 +3362,12 @@ class Compiler
// On wasm these helpers return void* (InitHelpers.InitClass/InitInstantiatedClass). Model them as
// value-returning so the call_indirect signature matches the compiled managed helper; the value is unused.
static constexpr var_types HelperInitClassRetType = TYP_I_IMPL;
// Likewise for CastHelpers.Unbox at sites that discard the result. Modeling it TYP_BYREF off
Comment thread
lewing marked this conversation as resolved.
// wasm is equally correct but costs code size for no benefit.
static constexpr var_types HelperUnboxDiscardedRetType = TYP_BYREF;
#else
static constexpr var_types HelperInitClassRetType = TYP_VOID;
static constexpr var_types HelperInitClassRetType = TYP_VOID;
static constexpr var_types HelperUnboxDiscardedRetType = TYP_VOID;
#endif // TARGET_WASM

GenTreeCall* gtNewVirtualFunctionLookupHelperCallNode(
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10700,7 +10700,9 @@ void Compiler::impImportBlockCode(BasicBlock* block)
{ // compDonotInline()
return;
}
op1 = gtNewHelperCallNode(helper, TYP_VOID, op2, op1);
// The byref is formed from clone + TARGET_POINTER_SIZE below, so discard the
// helper result to keep the enclosing COLON/QMARK void.
op1 = gtUnusedValNode(gtNewHelperCallNode(helper, HelperUnboxDiscardedRetType, op2, op1));
Comment thread
lewing marked this conversation as resolved.

op1 = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), op1);
op1 = gtNewQmarkNode(TYP_VOID, condBox, op1->AsColon());
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/morph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ PhaseStatus Compiler::fgMorphInit()
{
// confirm that the argument is a GC pointer (for debugging (GC stress))
GenTree* op = gtNewLclvNode(i, TYP_REF);
op = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_VOID, op);
op = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_REF, op);

fgNewStmtAtBeg(fgFirstBB, op);
madeChanges = true;
Comment thread
lewing marked this conversation as resolved.
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/jit/objectalloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2832,12 +2832,16 @@ void ObjectAllocator::RewriteUses()

// Rewrite the call to make the box accesses explicit in jitted code.
// user = COMMA(
// CALL(UNBOX_HELPER_TYPETEST, obj->MethodTable, type),
// CALL(UNBOX_HELPER_TYPETEST, type, obj->MethodTable),
// ADD(obj, TARGET_POINTER_SIZE))
//
JITDUMP("Rewriting to invoke box type test helper%s\n", isForEffect ? " for side effect" : "");

// Unbox_TypeTest returns void, unlike Unbox. isForEffect above reads the
// original type.
call->gtCallMethHnd = m_compiler->eeFindHelper(CORINFO_HELP_UNBOX_TYPETEST);
call->gtType = TYP_VOID;
call->gtReturnType = TYP_VOID;
GenTree* const mt = m_compiler->gtNewMethodTableLookup(lcl, /* onStack */ true);
call->gtArgs.Remove(secondArg);
call->gtArgs.PushBack(m_compiler, NewCallArg::Primitive(mt));
Expand Down
36 changes: 36 additions & 0 deletions src/tests/JIT/Regression/JitBlue/Runtime_131377/Runtime_131377.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// Stack allocating a box retargets its unbox to the void UNBOX_TYPETEST helper, but the call kept
// its byref type, so wasm emitted a value-returning call_indirect and trapped. The non-Guid arg is
// load bearing: a same-type unbox skips the helper. Only reproduces under crossgen wasm R2R.

using System;
using System.Runtime.CompilerServices;
using Xunit;

public class Runtime_131377
{
[Fact]
public static void TestEntryPoint()
{
Unbox(null);
Assert.Throws<InvalidCastException>(() => Unbox("not a guid"));
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static void Unbox(object o)
{
if (o is null)
{
o = new Guid();
}

Consume((Guid)o);
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static void Consume<T>(T _)
{
}
}
1 change: 1 addition & 0 deletions src/tests/JIT/Regression/Regression_o_2.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
<Compile Include="JitBlue\Runtime_117794\Runtime_117794.cs" />
<Compile Include="JitBlue\Runtime_119710\Runtime_119710.cs" />
<Compile Include="JitBlue\Runtime_1241\Runtime_1241.cs" />
<Compile Include="JitBlue\Runtime_131377\Runtime_131377.cs" />
<Compile Include="JitBlue\Runtime_13417\Runtime_13417.cs" />
<Compile Include="JitBlue\Runtime_13669\Runtime_13669.cs" />
<Compile Include="JitBlue\Runtime_13762\Runtime_13762.cs" />
Expand Down
Loading