Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
62 changes: 58 additions & 4 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1188,7 +1188,7 @@ static InterpType GetInterpType(CorInfoType corInfoType)
case CORINFO_TYPE_VOID:
return InterpTypeVoid;
default:
assert(0);
assert(!"Unimplemented CorInfoType");
break;
}
return InterpTypeVoid;
Expand Down Expand Up @@ -1721,7 +1721,17 @@ int32_t InterpCompiler::GetDataItemIndex(void *data)

int32_t InterpCompiler::GetMethodDataItemIndex(CORINFO_METHOD_HANDLE mHandle)
{
size_t data = (size_t)mHandle | INTERP_METHOD_DESC_TAG;
size_t data = (size_t)mHandle | INTERP_METHOD_HANDLE_TAG;
return GetDataItemIndex((void*)data);
}

int32_t InterpCompiler::GetDataItemIndexForHelperFtn(CorInfoHelpFunc ftn)
{
void *indirect;
void *direct = m_compHnd->getHelperFtn(ftn, &indirect);
size_t data = !direct
? (size_t)indirect | INTERP_INDIRECT_HELPER_TAG
: (size_t)direct;
return GetDataItemIndex((void*)data);
}

Expand Down Expand Up @@ -3457,6 +3467,43 @@ int InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
m_ip += 1;
break;

case CEE_BOX:
{
CHECK_STACK(1);
m_pStackPointer -= 1;
CORINFO_CLASS_HANDLE clsHnd = ResolveClassToken(getU4LittleEndian(m_ip + 1));
CORINFO_CLASS_HANDLE boxedClsHnd = m_compHnd->getTypeForBox(clsHnd);
CorInfoHelpFunc helpFunc = m_compHnd->getBoxHelper(clsHnd);
AddIns(INTOP_BOX);
m_pLastNewIns->SetSVar(m_pStackPointer[0].var);
PushStackType(StackTypeO, boxedClsHnd);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
m_pLastNewIns->data[0] = GetDataItemIndex(clsHnd);
m_pLastNewIns->data[1] = GetDataItemIndexForHelperFtn(helpFunc);
m_ip += 5;
break;
}

case CEE_UNBOX:
case CEE_UNBOX_ANY:
{
CHECK_STACK(1);
m_pStackPointer -= 1;
CORINFO_CLASS_HANDLE clsHnd = ResolveClassToken(getU4LittleEndian(m_ip + 1));
CorInfoHelpFunc helpFunc = m_compHnd->getUnBoxHelper(clsHnd);
AddIns(opcode == CEE_UNBOX ? INTOP_UNBOX : INTOP_UNBOX_ANY);
m_pLastNewIns->SetSVar(m_pStackPointer[0].var);
if (opcode == CEE_UNBOX)
PushStackType(StackTypeI, NULL);
else
PushInterpType(GetInterpType(m_compHnd->asCorInfoType(clsHnd)), clsHnd);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
m_pLastNewIns->data[0] = GetDataItemIndex(clsHnd);
m_pLastNewIns->data[1] = GetDataItemIndexForHelperFtn(helpFunc);
m_ip += 5;
break;
}

default:
assert(0);
break;
Expand Down Expand Up @@ -3644,13 +3691,20 @@ void InterpCompiler::PrintInsData(InterpInst *ins, int32_t insOffset, const int3
printf(")");
break;
}
case InterpOpMethodToken:
case InterpOpMethodHandle:
{
CORINFO_METHOD_HANDLE mh = (CORINFO_METHOD_HANDLE)((size_t)m_dataItems.Get(*pData) & ~INTERP_METHOD_DESC_TAG);
CORINFO_METHOD_HANDLE mh = (CORINFO_METHOD_HANDLE)((size_t)m_dataItems.Get(*pData) & ~INTERP_METHOD_HANDLE_TAG);
printf(" ");
PrintMethodName(mh);
break;
}
case InterpOpClassHandle:
{
CORINFO_CLASS_HANDLE ch = (CORINFO_CLASS_HANDLE)((size_t)m_dataItems.Get(*pData));
printf(" ");
PrintClassName(ch);
break;
}
default:
assert(0);
break;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/interpreter/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ class InterpCompiler
TArray<void*> m_dataItems;
int32_t GetDataItemIndex(void* data);
int32_t GetMethodDataItemIndex(CORINFO_METHOD_HANDLE mHandle);
int32_t GetDataItemIndexForHelperFtn(CorInfoHelpFunc ftn);

int GenerateCode(CORINFO_METHOD_INFO* methodInfo);
void PatchInitLocals(CORINFO_METHOD_INFO* methodInfo);
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/interpreter/interpretershared.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
#define INTERP_STACK_SLOT_SIZE 8 // Alignment of each var offset on the interpreter stack
#define INTERP_STACK_ALIGNMENT 16 // Alignment of interpreter stack at the start of a frame

#define INTERP_METHOD_DESC_TAG 4 // Tag of a MethodDesc in the interp method dataItems
#define INTERP_METHOD_HANDLE_TAG 4 // Tag of a MethodDesc in the interp method dataItems
#define INTERP_INDIRECT_HELPER_TAG 1 // When a helper ftn's address is indirect we tag it with this tag bit

struct InterpMethod
{
Expand Down
12 changes: 8 additions & 4 deletions src/coreclr/interpreter/intops.def
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ OPDEF(INTOP_CONV_R8_R4, "conv.r8.r4", 3, 1, 1, InterpOpNoArgs)

OPDEF(INTOP_CONV_U8_R4, "conv.u8.r4", 3, 1, 1, InterpOpNoArgs)
OPDEF(INTOP_CONV_U8_R8, "conv.u8.r8", 3, 1, 1, InterpOpNoArgs)

OPDEF(INTOP_BOX, "box", 5, 1, 1, InterpOpClassHandle) // [class handle data item] [helper data item]
OPDEF(INTOP_UNBOX, "unbox", 5, 1, 1, InterpOpClassHandle) // [class handle data item] [helper data item]
OPDEF(INTOP_UNBOX_ANY, "unbox.any", 5, 1, 1, InterpOpClassHandle) // [class handle data item] [helper data item]
// Unary operations end

OPDEF(INTOP_ADD_I4_IMM, "add.i4.imm", 4, 1, 1, InterpOpInt)
Expand Down Expand Up @@ -251,10 +255,10 @@ OPDEF(INTOP_STIND_VT_NOREF, "stind.vt.noref", 5, 0, 2, InterpOpTwoInts)
OPDEF(INTOP_LDFLDA, "ldflda", 4, 1, 1, InterpOpInt)

// Calls
OPDEF(INTOP_CALL, "call", 4, 1, 1, InterpOpMethodToken)
OPDEF(INTOP_CALLVIRT, "callvirt", 4, 1, 1, InterpOpMethodToken)
OPDEF(INTOP_NEWOBJ, "newobj", 5, 1, 1, InterpOpMethodToken)
OPDEF(INTOP_NEWOBJ_VT, "newobj.vt", 5, 1, 1, InterpOpMethodToken)
OPDEF(INTOP_CALL, "call", 4, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_CALLVIRT, "callvirt", 4, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_NEWOBJ, "newobj", 5, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_NEWOBJ_VT, "newobj.vt", 5, 1, 1, InterpOpMethodHandle)

OPDEF(INTOP_CALL_HELPER_PP, "call.helper.pp", 5, 1, 0, InterpOpThreeInts)

Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/interpreter/intops.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ typedef enum
InterpOpThreeInts,
InterpOpBranch,
InterpOpSwitch,
InterpOpMethodToken,
InterpOpMethodHandle,
InterpOpClassHandle,
} InterpOpArgType;

extern const uint8_t g_interpOpLen[];
Expand Down
37 changes: 35 additions & 2 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "interpexec.h"

typedef void* (*HELPER_FTN_PP)(void*);
typedef void* (*HELPER_FTN_BOX_UNBOX)(MethodTable*, void*);

InterpThreadContext::InterpThreadContext()
{
Expand Down Expand Up @@ -1057,11 +1058,11 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
CALL_INTERP_SLOT:
{
size_t targetMethod = (size_t)pMethod->pDataItems[methodSlot];
if (targetMethod & INTERP_METHOD_DESC_TAG)
if (targetMethod & INTERP_METHOD_HANDLE_TAG)
{
// First execution of this call. Ensure target method is compiled and
// patch the data item slot with the actual method code.
MethodDesc *pMD = (MethodDesc*)(targetMethod & ~INTERP_METHOD_DESC_TAG);
MethodDesc *pMD = (MethodDesc*)(targetMethod & ~INTERP_METHOD_HANDLE_TAG);
PCODE code = pMD->GetNativeCode();
if (!code) {
// This is an optimization to ensure that the stack walk will not have to search
Expand Down Expand Up @@ -1200,6 +1201,38 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
UNREACHABLE();
break;
}
case INTOP_BOX:
case INTOP_UNBOX:
case INTOP_UNBOX_ANY:
{
int opcode = *ip;
int dreg = ip[1];
int sreg = ip[2];
MethodTable *pMT = (MethodTable*)pMethod->pDataItems[ip[3]];
size_t helperDirectOrIndirect = (size_t)pMethod->pDataItems[ip[4]];
HELPER_FTN_BOX_UNBOX helper = nullptr;
if (helperDirectOrIndirect & INTERP_INDIRECT_HELPER_TAG)
helper = *(HELPER_FTN_BOX_UNBOX *)(helperDirectOrIndirect & ~INTERP_INDIRECT_HELPER_TAG);
else
helper = (HELPER_FTN_BOX_UNBOX)helperDirectOrIndirect;

if (opcode == INTOP_BOX) {
// internal static object Box(MethodTable* typeMT, ref byte unboxedData)
void *unboxedData = LOCAL_VAR_ADDR(sreg, void);
LOCAL_VAR(dreg, Object*) = (Object*)helper(pMT, unboxedData);
} else {
// private static ref byte Unbox(MethodTable* toTypeHnd, object obj)
Object *src = LOCAL_VAR(sreg, Object*);
void *unboxedData = helper(pMT, src);
if (opcode == INTOP_UNBOX)
LOCAL_VAR(dreg, void*) = unboxedData;
else
CopyValueClassUnchecked(LOCAL_VAR_ADDR(dreg, void), unboxedData, pMT);
}

ip += 5;
break;
}
case INTOP_FAILFAST:
assert(0);
break;
Expand Down
17 changes: 17 additions & 0 deletions src/tests/JIT/interpreter/Interpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ public static void RunInterpreterTests()
if (!TestVirtual())
Environment.FailFast(null);

if (!TestBoxing())
Environment.FailFast(null);

System.GC.Collect();
}

Expand Down Expand Up @@ -386,4 +389,18 @@ public static bool TestVirtual()
return false;
return true;
}

public static bool TestBoxing()
{
int l = 7, r = 4;
object s = BoxedSubtraction(l, r);
// `(s is int result)` generates isinst so we have to do this in steps
int result = (int)s;
return result == 3;
}

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
static object BoxedSubtraction (object lhs, object rhs) {
return (int)lhs - (int)rhs;
}
}
Loading