Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
14 changes: 13 additions & 1 deletion src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,8 @@ void ValidateEmittedSequenceTermination(InterpInst *lastIns)
(lastIns->opcode == INTOP_CALLVIRT_TAIL) ||
(lastIns->opcode == INTOP_RETHROW) ||
(lastIns->opcode == INTOP_LEAVE_FILTER) ||
(lastIns->opcode == INTOP_LEAVE_CATCH))
(lastIns->opcode == INTOP_LEAVE_CATCH) ||
(lastIns->opcode == INTOP_JMP))
{
// Valid terminating instruction
return;
Expand Down Expand Up @@ -6929,6 +6930,17 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
EmitUnaryArithmeticOp(INTOP_NOT_I4);
m_ip++;
break;
case CEE_JMP:
{
CHECK_STACK(0);
uint32_t token = getU4LittleEndian(m_ip + 1);
CORINFO_RESOLVED_TOKEN resolvedToken;
ResolveToken(token, CORINFO_TOKENKIND_Method, &resolvedToken);
AddIns(INTOP_JMP);
m_pLastNewIns->data[0] = GetMethodDataItemIndex(resolvedToken.hMethod);
m_ip += 5;
break;
}
case CEE_CALLVIRT:
case CEE_CALL:
EmitCall(pConstrainedToken, readonly, tailcall, false /*newObj*/, false /*isCalli*/);
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/interpreter/inc/intops.def
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ OPDEF(INTOP_CALL_TAIL, "call.tail", 4, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_CALLI_TAIL, "calli.tail", 6, 1, 2, InterpOpLdPtr)
OPDEF(INTOP_CALLVIRT_TAIL, "callvirt.tail", 4, 1, 1, InterpOpMethodHandle)

OPDEF(INTOP_JMP, "jmp", 4, 0, 0, InterpOpMethodHandle)

// The following helper call instructions exist in 2 variants, one for normal methods, and one for cases where a shared generic lookup is needed.
// 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.
// If there is a generic context argument it is always the first SVar to the instruction.
Expand Down
14 changes: 14 additions & 0 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2682,6 +2682,8 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
{
// If we didn't get the interpreter code pointer setup, then this is a method we need to invoke as a compiled method.
// Interpreter-FIXME: Implement tailcall via helpers, see https://github.com/dotnet/runtime/blob/main/docs/design/features/tailcalls-with-helpers.md
// INTOP_JMP handles only managed targets
_ASSERTE(*ip != INTOP_JMP);
InvokeManagedMethod(targetMethod, callArgsAddress, returnValueAddress, (PCODE)NULL);
break;
}
Expand All @@ -2700,6 +2702,10 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
// required to be followed by a ret, so we know nothing is going to read from stack[returnOffset] after the call.
pFrame->ReInit(pFrame->pParent, targetIp, pFrame->pRetVal, pFrame->pStack);
}
else if (*ip == INTOP_JMP)
{
pFrame->ReInit(pFrame->pParent, targetIp, pFrame->pRetVal, pFrame->pStack);
}
else
{
// Save current execution state for when we return from called method
Expand Down Expand Up @@ -2730,6 +2736,14 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
pThreadContext->pStackPointer = stack + pMethod->allocaSize;
break;
}
case INTOP_JMP:
methodSlot = ip[1];
targetMethod = (MethodDesc*)pMethod->pDataItems[methodSlot];
// Set the offsets so that the code at CALL_INTERP_METHOD can compute the callArgsAddress and returnValueAddress
// to be the same as the current frame's ones.
callArgsOffset = 0;
returnOffset = (int32_t)(pFrame->pRetVal - stack);
goto CALL_INTERP_METHOD;
case INTOP_NEWOBJ_GENERIC:
{
isTailcall = false;
Expand Down
Loading