Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
175 changes: 153 additions & 22 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2181,6 +2181,27 @@ int32_t InterpCompiler::GetDataItemIndexForHelperFtn(CorInfoHelpFunc ftn)
return GetDataItemIndex(addr);
}

static int32_t GetLdindForType(InterpType interpType)
{
switch (interpType)
{
case InterpTypeI1: return INTOP_LDIND_I1;
case InterpTypeU1: return INTOP_LDIND_U1;
case InterpTypeI2: return INTOP_LDIND_I2;
case InterpTypeU2: return INTOP_LDIND_U2;
case InterpTypeI4: return INTOP_LDIND_I4;
case InterpTypeI8: return INTOP_LDIND_I8;
case InterpTypeR4: return INTOP_LDIND_R4;
case InterpTypeR8: return INTOP_LDIND_R8;
case InterpTypeO: return INTOP_LDIND_I;
case InterpTypeVT: return INTOP_LDIND_VT;
case InterpTypeByRef: return INTOP_LDIND_I;
default:
assert(0);
}
return -1;
}

bool InterpCompiler::EmitNamedIntrinsicCall(NamedIntrinsic ni, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO sig)
{
bool mustExpand = (method == m_methodHnd);
Expand All @@ -2201,6 +2222,135 @@ bool InterpCompiler::EmitNamedIntrinsicCall(NamedIntrinsic ni, CORINFO_CLASS_HAN
AddIns(INTOP_THROW_PNSE);
return true;

case NI_System_Runtime_CompilerServices_StaticsHelpers_VolatileReadAsByref:
{
CHECK_STACK(1);

m_pStackPointer--;
int32_t addrVar = m_pStackPointer[0].var;

InterpType retType = GetInterpType(sig.retType);
int32_t opcode = GetLdindForType(retType);
AddIns(opcode);
m_pLastNewIns->SetSVar(addrVar);

CORINFO_CLASS_HANDLE clsHnd = NULL;
if (sig.retType == CORINFO_TYPE_CLASS)
{
clsHnd = sig.retTypeClass;
}
PushInterpType(retType, clsHnd);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);

// Acquire barrier after the load
AddIns(INTOP_MEMBAR);
return true;
}

case NI_System_Threading_Volatile_ReadBarrier:
AddIns(INTOP_MEMBAR);
return true;

case NI_System_Runtime_CompilerServices_RuntimeHelpers_GetMethodTable:
{
CHECK_STACK(1);
m_pStackPointer--;
AddIns(INTOP_LDIND_I);
m_pLastNewIns->data[0] = 0;
m_pLastNewIns->SetSVar(m_pStackPointer[0].var);
PushStackType(StackTypeI, NULL);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
return true;
}

case NI_System_Threading_Interlocked_CompareExchange:
{
CHECK_STACK(3);
InterpType retType = GetInterpType(sig.retType);

int32_t opcode;
switch (retType)
{
case InterpTypeI4:
opcode = INTOP_COMPARE_EXCHANGE_I4;
break;
case InterpTypeI8:
opcode = INTOP_COMPARE_EXCHANGE_I8;
break;
default:
return false;
}

AddIns(opcode);
m_pStackPointer -= 3;

int32_t addrVar = m_pStackPointer[0].var;
int32_t valueVar = m_pStackPointer[1].var;
int32_t comparandVar = m_pStackPointer[2].var;

PushInterpType(retType, nullptr);
m_pLastNewIns->SetSVars3(addrVar, valueVar, comparandVar);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
return true;
}

case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences:
{
CORINFO_CLASS_HANDLE clsHnd = sig.sigInst.methInst[0];
bool isValueType = (m_compHnd->getClassAttribs(clsHnd) & CORINFO_FLG_VALUECLASS) != 0;
bool hasGCRefs = false;

if (isValueType)
{
// Walk the layout to see if any field is a GC pointer
const uint32_t maxSlots = 256;
BYTE gcLayout[maxSlots];
uint32_t numSlots = m_compHnd->getClassGClayout(clsHnd, gcLayout);

for (uint32_t i = 0; i < numSlots; ++i)
{
if (gcLayout[i] != TYPE_GC_NONE)
{
hasGCRefs = true;
break;
}
}
}

int32_t result = (!isValueType || hasGCRefs) ? 1 : 0;

AddIns(INTOP_LDC_I4);
m_pLastNewIns->data[0] = result;

PushInterpType(InterpTypeI4, nullptr);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);

return true;
}
case NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference:
{
CHECK_STACK(1);

m_pStackPointer--;
int32_t arrayVar = m_pStackPointer[0].var;

AddIns(INTOP_NULLCHECK);
m_pLastNewIns->SetSVar(arrayVar);

AddIns(INTOP_ADD_P_IMM);
m_pLastNewIns->SetSVar(arrayVar);
m_pLastNewIns->data[0] = OFFSETOF__CORINFO_Array__data;

PushInterpType(InterpTypeByRef, NULL);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);

return true;
}

case NI_System_Threading_Thread_FastPollGC:
AddIns(INTOP_SAFEPOINT);
return true;

default:
{
#ifdef DEBUG
Expand Down Expand Up @@ -2257,7 +2407,6 @@ bool InterpCompiler::EmitCallIntrinsics(CORINFO_METHOD_HANDLE method, CORINFO_SI
return true;
}
}
// TODO: Add multi-dimensional array getters and setters
}

return false;
Expand Down Expand Up @@ -2990,27 +3139,6 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
m_ip += 5;
}

static int32_t GetLdindForType(InterpType interpType)
{
switch (interpType)
{
case InterpTypeI1: return INTOP_LDIND_I1;
case InterpTypeU1: return INTOP_LDIND_U1;
case InterpTypeI2: return INTOP_LDIND_I2;
case InterpTypeU2: return INTOP_LDIND_U2;
case InterpTypeI4: return INTOP_LDIND_I4;
case InterpTypeI8: return INTOP_LDIND_I8;
case InterpTypeR4: return INTOP_LDIND_R4;
case InterpTypeR8: return INTOP_LDIND_R8;
case InterpTypeO: return INTOP_LDIND_I;
case InterpTypeVT: return INTOP_LDIND_VT;
case InterpTypeByRef: return INTOP_LDIND_I;
default:
assert(0);
}
return -1;
}

static int32_t GetStindForType(InterpType interpType)
{
switch (interpType)
Expand Down Expand Up @@ -5153,6 +5281,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
volatile_ = true;
m_ip++;
break;
case CEE_UNALIGNED:
m_ip += 2;
break;
case CEE_INITOBJ:
{
CHECK_STACK(1);
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/interpreter/intops.def
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ OPDEF(INTOP_LDC_R8, "ldc.r8", 4, 1, 0, InterpOpDouble)

OPDEF(INTOP_LDPTR, "ldptr", 3, 1, 0, InterpOpLdPtr)
OPDEF(INTOP_LDPTR_DEREF, "ldptr.deref", 3, 1, 0, InterpOpLdPtr)
OPDEF(INTOP_NULLCHECK, "nullcheck", 2, 1, 0, InterpOpNoArgs)
OPDEF(INTOP_NEWARR, "newarr", 5, 1, 1, InterpOpPointerHelperFtn)
OPDEF(INTOP_NEWARR_GENERIC, "newarr.generic", 6, 1, 2, InterpOpGenericHelperFtn)
OPDEF(INTOP_NEWMDARR, "newmdarr", 5, 1, 1, InterpOpPointerInt)
Expand Down Expand Up @@ -403,6 +404,10 @@ OPDEF(INTOP_GC_COLLECT, "gc.collect", 1, 0, 0, InterpOpNoArgs)

OPDEF(INTOP_LOAD_FRAMEVAR, "load.framevar", 2, 1, 0, InterpOpNoArgs)

// Intrinsics
OPDEF(INTOP_COMPARE_EXCHANGE_I4, "compare.exchange.i4", 5, 1, 3, InterpOpNoArgs)
OPDEF(INTOP_COMPARE_EXCHANGE_I8, "compare.exchange.i8", 5, 1, 3, InterpOpNoArgs)

// All instructions after this point are IROPS, instructions that are not emitted/executed
OPDEF(INTOP_NOP, "nop", 1, 0, 0, InterpOpNoArgs)
OPDEF(INTOP_DEF, "def", 2, 1, 0, InterpOpNoArgs)
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/interpreter/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ NamedIntrinsic GetNamedIntrinsic(COMP_HANDLE compHnd, CORINFO_METHOD_HANDLE comp
if (!namespaceName)
return NI_Illegal;

// Namespace is zero-terinated empty string
if (!strcmp(className, "Arm64"))
{
if (!strcmp(methodName, "get_IsSupported"))
return NI_IsSupported_False;
}

if (!HAS_PREFIX(namespaceName, "System"))
return NI_Illegal;

Expand Down Expand Up @@ -76,6 +83,8 @@ NamedIntrinsic GetNamedIntrinsic(COMP_HANDLE compHnd, CORINFO_METHOD_HANDLE comp
{
if (!strcmp(methodName, "IsReferenceOrContainsReferences"))
return NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences;
else if (!strcmp(methodName, "GetMethodTable"))
return NI_System_Runtime_CompilerServices_RuntimeHelpers_GetMethodTable;
}
}
else if (!strcmp(namespaceName, "System.Runtime.InteropServices"))
Expand Down
30 changes: 29 additions & 1 deletion src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ template <typename TResult, typename TSource> void ConvOvfHelper(int8_t *stack,
void* DoGenericLookup(void* genericVarAsPtr, InterpGenericLookup* pLookup)
{
// TODO! If this becomes a performance bottleneck, we could expand out the various permutations of this
// so that we have 24 versions of lookup (or 48 is we allow for avoiding the null check), do the only
// so that we have 24 versions of lookup (or 48 is we allow for avoiding the null check), do the only
// if check to figure out which one to use, and then have the rest of the logic be straight-line code.
MethodTable *pMT = nullptr;
MethodDesc* pMD = nullptr;
Expand Down Expand Up @@ -506,6 +506,10 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
LOCAL_VAR(ip[1], void*) = *(void**)pMethod->pDataItems[ip[2]];
ip += 3;
break;
case INTOP_NULLCHECK:
NULL_CHECK(LOCAL_VAR(ip[1], void*));
ip += 2;
break;
case INTOP_RET:
// Return stack slot sized value
*(int64_t*)pFrame->pRetVal = LOCAL_VAR(ip[1], int64_t);
Expand Down Expand Up @@ -1946,6 +1950,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr

// clear the valuetype
memset(vtThis, 0, vtSize);

// pass the address of the valuetype
LOCAL_VAR(callArgsOffset, void*) = vtThis;

Expand Down Expand Up @@ -2360,6 +2365,29 @@ do { \
break;
}

#define COMPARE_EXCHANGE(type) \
do \
{ \
type* dst = (type*)LOCAL_VAR(ip[2], void*); \
NULL_CHECK(dst); \
type newValue = LOCAL_VAR(ip[3], type); \
type comparand = LOCAL_VAR(ip[4], type); \
type old = InterlockedCompareExchangeT(dst, newValue, comparand); \
LOCAL_VAR(ip[1], type) = old; \
ip += 5; \
} while (0)
case INTOP_COMPARE_EXCHANGE_I4:
{
COMPARE_EXCHANGE(int32_t);
break;
}

case INTOP_COMPARE_EXCHANGE_I8:
{
COMPARE_EXCHANGE(int64_t);
break;
}

case INTOP_CALL_FINALLY:
{
const int32_t* targetIp = ip + ip[1];
Expand Down
Loading
Loading