Skip to content

Commit d978828

Browse files
committed
Add dedicated interpreter opcodes for tailcalls and generate them
1 parent 4b2a7d5 commit d978828

File tree

2 files changed

+15
-5
lines changed

2 files changed

+15
-5
lines changed

src/coreclr/interpreter/compiler.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3074,7 +3074,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
30743074
}
30753075
else if (isCalli)
30763076
{
3077-
AddIns(INTOP_CALLI);
3077+
AddIns(tailcall ? INTOP_CALLI_TAIL : INTOP_CALLI);
30783078
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
30793079
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, callIFunctionPointerVar);
30803080
}
@@ -3092,6 +3092,11 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
30923092
assert(!isPInvoke && !isMarshaledPInvoke);
30933093
AddIns(INTOP_CALLDELEGATE);
30943094
}
3095+
else if (tailcall)
3096+
{
3097+
assert(!isPInvoke && !isMarshaledPInvoke);
3098+
AddIns(INTOP_CALL_TAIL);
3099+
}
30953100
else
30963101
{
30973102
AddIns((isPInvoke && !isMarshaledPInvoke) ? INTOP_CALL_PINVOKE : INTOP_CALL);
@@ -3128,14 +3133,14 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
31283133

31293134
calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);
31303135

3131-
AddIns(INTOP_CALLI);
3136+
AddIns(tailcall ? INTOP_CALLI_TAIL : INTOP_CALLI);
31323137
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
31333138
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, codePointerLookupResult);
31343139
break;
31353140
}
31363141
case CORINFO_VIRTUALCALL_VTABLE:
31373142
// Traditional virtual call. In theory we could optimize this to using the vtable
3138-
AddIns(INTOP_CALLVIRT);
3143+
AddIns(tailcall ? INTOP_CALLVIRT_TAIL : INTOP_CALLVIRT);
31393144
m_pLastNewIns->data[0] = GetDataItemIndex(callInfo.hMethod);
31403145
break;
31413146

@@ -3163,13 +3168,13 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
31633168

31643169
calliCookie = m_compHnd->GetCookieForInterpreterCalliSig(&callInfo.sig);
31653170

3166-
AddIns(INTOP_CALLI);
3171+
AddIns(tailcall ? INTOP_CALLI_TAIL : INTOP_CALLI);
31673172
m_pLastNewIns->data[0] = GetDataItemIndex(calliCookie);
31683173
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, synthesizedLdvirtftnPtrVar);
31693174
}
31703175
else
31713176
{
3172-
AddIns(INTOP_CALLVIRT);
3177+
AddIns(tailcall ? INTOP_CALLVIRT_TAIL : INTOP_CALLVIRT);
31733178
m_pLastNewIns->data[0] = GetDataItemIndex(callInfo.hMethod);
31743179
}
31753180
break;

src/coreclr/interpreter/intops.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,11 @@ OPDEF(INTOP_NEWOBJ, "newobj", 5, 1, 1, InterpOpMethodHandle)
365365
OPDEF(INTOP_NEWOBJ_GENERIC, "newobj.generic", 6, 1, 2, InterpOpMethodHandle)
366366
OPDEF(INTOP_NEWOBJ_VT, "newobj.vt", 5, 1, 1, InterpOpMethodHandle)
367367

368+
// Tail calls
369+
OPDEF(INTOP_CALL_TAIL, "call.tail", 4, 1, 1, InterpOpMethodHandle)
370+
OPDEF(INTOP_CALLI_TAIL, "calli", 5, 1, 2, InterpOpLdPtr)
371+
OPDEF(INTOP_CALLVIRT_TAIL, "callvirt.tail", 4, 1, 1, InterpOpMethodHandle)
372+
368373
// The following helper call instructions exist in 2 variants, one for normal methods, and one for cases where a shared generic lookup is needed.
369374
// In the case where a shared generic lookup is needed an extra argument is passed as an svar, which is a pointer to the generic context.
370375
// If there is a generic context argument it is always the first SVar to the instruction.

0 commit comments

Comments
 (0)