Skip to content

Commit 65ee8fb

Browse files
authored
Implement CEE_JMP for the interpreter (#121130)
This makes around 50 more coreclr tests pass with the interpreter.
1 parent d9df086 commit 65ee8fb

File tree

5 files changed

+157
-1
lines changed

5 files changed

+157
-1
lines changed

src/coreclr/interpreter/compiler.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2233,7 +2233,7 @@ void InterpCompiler::CreateBasicBlocks(CORINFO_METHOD_INFO* methodInfo)
22332233
default:
22342234
assert(0);
22352235
}
2236-
if (opcode == CEE_THROW || opcode == CEE_ENDFINALLY || opcode == CEE_RETHROW)
2236+
if (opcode == CEE_THROW || opcode == CEE_ENDFINALLY || opcode == CEE_RETHROW || opcode == CEE_JMP)
22372237
GetBB((int32_t)(ip - codeStart));
22382238
}
22392239
}
@@ -3898,6 +3898,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
38983898

38993899
bool isVirtual = (*m_ip == CEE_CALLVIRT);
39003900
bool isDelegateInvoke = false;
3901+
bool isJmp = (*m_ip == CEE_JMP);
39013902

39023903
CORINFO_RESOLVED_TOKEN resolvedCallToken;
39033904
CORINFO_CALL_INFO callInfo;
@@ -3941,6 +3942,16 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
39413942
BADCODE("Vararg methods are not supported in interpreted code");
39423943
}
39433944

3945+
if (isJmp)
3946+
{
3947+
if (callInfo.sig.numArgs != m_methodInfo->args.numArgs ||
3948+
callInfo.sig.retType != m_methodInfo->args.retType ||
3949+
callInfo.sig.callConv != m_methodInfo->args.callConv)
3950+
{
3951+
BADCODE("Incompatible target for CEE_JMP");
3952+
}
3953+
}
3954+
39443955
// Inject call to callsite callout helper
39453956
EmitCallsiteCallout(callInfo.accessAllowed, &callInfo.callsiteCalloutHelper);
39463957

@@ -4029,6 +4040,16 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
40294040
CORINFO_ARG_LIST_HANDLE args;
40304041
args = callInfo.sig.args;
40314042

4043+
if (isJmp)
4044+
{
4045+
assert(tailcall);
4046+
// CEE_JMP is simulated as a tail call, so we need to load the current method's args
4047+
for (int i = 0; i < numArgsFromStack; i++)
4048+
{
4049+
EmitLoadVar(i);
4050+
}
4051+
}
4052+
40324053
for (int iActualArg = 0, iLogicalArg = 0; iActualArg < numArgs; iActualArg++)
40334054
{
40344055
if (iActualArg == extraParamArgLocation)
@@ -6970,6 +6991,18 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
69706991
EmitUnaryArithmeticOp(INTOP_NOT_I4);
69716992
m_ip++;
69726993
break;
6994+
case CEE_JMP:
6995+
{
6996+
CHECK_STACK(0);
6997+
if (m_pCBB->clauseType != BBClauseNone)
6998+
{
6999+
// CEE_JMP inside a funclet is not allowed
7000+
BADCODE("CEE_JMP inside funclet");
7001+
}
7002+
EmitCall(pConstrainedToken, readonly, true /* tailcall */, false /*newObj*/, false /*isCalli*/);
7003+
linkBBlocks = false;
7004+
break;
7005+
}
69737006
case CEE_CALLVIRT:
69747007
case CEE_CALL:
69757008
EmitCall(pConstrainedToken, readonly, tailcall, false /*newObj*/, false /*isCalli*/);

src/tests/JIT/Directed/Directed_1.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<ItemGroup>
33
<MergedWrapperProjectReference Include="coverage/**/*.??proj" />
44
<MergedWrapperProjectReference Include="nullabletypes/**/*.??proj" />
5+
<ProjectReference Include="jmp/**/*.??proj" />
56
</ItemGroup>
67

78
<Import Project="$(TestSourceDir)MergedTestRunner.targets" />

src/tests/JIT/Directed/Directed_3.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<!-- Directed_1 -->
66
<MergedWrapperProjectReference Remove="coverage/**/*.??proj" />
77
<MergedWrapperProjectReference Remove="nullabletypes/**/*.??proj" />
8+
<MergedWrapperProjectReference Remove="jmp/**/*.??proj" />
89

910
<!-- Directed_2 -->
1011
<MergedWrapperProjectReference Remove="cmov/**/*.??proj" />
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
.assembly JmpGenericTest {}
2+
.assembly extern System.Console
3+
{
4+
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
5+
.ver 0:0:0:0
6+
}
7+
.assembly extern System.Runtime
8+
{
9+
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
10+
.ver 0:0:0:0
11+
}
12+
.assembly extern xunit.core {}
13+
.assembly extern xunit.assert {}
14+
15+
.assembly genericjmp { }
16+
17+
.class public auto ansi beforefieldinit JmpGenericToGeneric extends [System.Runtime]System.Object
18+
{
19+
.method public static void Target<T>() cil managed
20+
{
21+
.maxstack 8
22+
ldstr "Target<T> called"
23+
call void [System.Console]System.Console::WriteLine(string)
24+
ret
25+
}
26+
27+
.method public static void Source<T>() cil managed
28+
{
29+
jmp void JmpGenericToGeneric::Target<!!0>()
30+
}
31+
32+
.method public static void TestEntryPoint() cil managed
33+
{
34+
.custom instance void [xunit.core]Xunit.FactAttribute::.ctor() = (
35+
01 00 00 00
36+
)
37+
call void JmpGenericToGeneric::Source<int32>()
38+
ret
39+
}
40+
}
41+
42+
.class public auto ansi beforefieldinit JmpGenericToRegular extends [System.Runtime]System.Object
43+
{
44+
.method public static void Target() cil managed
45+
{
46+
.maxstack 8
47+
ldstr "Regular Target called"
48+
call void [System.Console]System.Console::WriteLine(string)
49+
ret
50+
}
51+
52+
.method public static void Source<T>() cil managed
53+
{
54+
jmp void JmpGenericToRegular::Target()
55+
}
56+
57+
.method public static void TestEntryPoint() cil managed
58+
{
59+
.custom instance void [xunit.core]Xunit.FactAttribute::.ctor() = (
60+
01 00 00 00
61+
)
62+
.try
63+
{
64+
call void JmpGenericToRegular::Source<int32>()
65+
ldstr "JMP from generic to regular method is not allowed"
66+
call void [xunit.assert]Xunit.Assert::Fail(string)
67+
leave END
68+
}
69+
catch [System.Runtime]System.InvalidProgramException
70+
{
71+
leave END
72+
}
73+
END:
74+
ret
75+
}
76+
}
77+
78+
.class public auto ansi beforefieldinit JmpRegularToGeneric extends [System.Runtime]System.Object
79+
{
80+
.method public static void Target<T>() cil managed
81+
{
82+
.maxstack 8
83+
ldstr "Generic Target<T> called"
84+
call void [System.Console]System.Console::WriteLine(string)
85+
ret
86+
}
87+
88+
.method public static void Source() cil managed
89+
{
90+
jmp void JmpRegularToGeneric::Target<int32>()
91+
}
92+
93+
.method public static void TestEntryPoint() cil managed
94+
{
95+
.custom instance void [xunit.core]Xunit.FactAttribute::.ctor() = (
96+
01 00 00 00
97+
)
98+
.try
99+
{
100+
call void JmpRegularToGeneric::Source()
101+
ldstr "JMP from regular to generic method is not allowed"
102+
call void [xunit.assert]Xunit.Assert::Fail(string)
103+
leave END
104+
}
105+
catch [System.Runtime]System.InvalidProgramException
106+
{
107+
leave END
108+
}
109+
END:
110+
ret
111+
}
112+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk.IL">
2+
<PropertyGroup>
3+
<DebugType>Full</DebugType>
4+
<CLRTestPriority>1</CLRTestPriority>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="genericjmp.il" />
8+
</ItemGroup>
9+
</Project>

0 commit comments

Comments
 (0)