diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index 3b090273c6a68a..db45085e6f188f 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -3095,7 +3095,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re break; case CORINFO_VIRTUALCALL_LDVIRTFTN: - if ((callInfo.sig.sigInst.methInstCount != 0) || (m_compHnd->getClassAttribs(resolvedCallToken.hClass) & CORINFO_FLG_SHAREDINST)) + if ((callInfo.sig.sigInst.methInstCount != 0) || (m_compHnd->getMethodAttribs(callInfo.hMethod) & CORINFO_FLG_SHAREDINST)) { assert(extraParamArgLocation == INT_MAX); // We should not have a type argument for the ldvirtftn path since we don't know @@ -5805,17 +5805,34 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) CorInfoType elemCorType = m_compHnd->asCorInfoType(elemClsHnd); m_pStackPointer -= 2; - if (elemCorType == CORINFO_TYPE_CLASS) + if ((elemCorType == CORINFO_TYPE_CLASS) && !readonly) { - AddIns(INTOP_LDELEMA_REF); - m_pLastNewIns->SetSVars2(m_pStackPointer[0].var, m_pStackPointer[1].var); - PushInterpType(InterpTypeByRef, elemClsHnd); - m_pLastNewIns->SetDVar(m_pStackPointer[-1].var); - m_pLastNewIns->data[0] = m_compHnd->getClassSize(elemClsHnd); - m_pLastNewIns->data[1] = GetDataItemIndex(elemClsHnd); + CORINFO_GENERICHANDLE_RESULT embedInfo; + m_compHnd->embedGenericHandle(&resolvedToken, false, m_methodInfo->ftn, &embedInfo); + DeclarePointerIsClass((CORINFO_CLASS_HANDLE)embedInfo.compileTimeHandle); + + if (embedInfo.lookup.lookupKind.needsRuntimeLookup) + { + GenericHandleData handleData = GenericHandleToGenericHandleData(embedInfo); + + AddIns(INTOP_LDELEMA_REF_GENERIC); + m_pLastNewIns->SetSVars3(m_pStackPointer[0].var, m_pStackPointer[1].var, handleData.genericVar); + PushInterpType(InterpTypeByRef, elemClsHnd); + m_pLastNewIns->SetDVar(m_pStackPointer[-1].var); + m_pLastNewIns->data[0] = handleData.dataItemIndex; + } + else + { + AddIns(INTOP_LDELEMA_REF); + m_pLastNewIns->SetSVars2(m_pStackPointer[0].var, m_pStackPointer[1].var); + PushInterpType(InterpTypeByRef, elemClsHnd); + m_pLastNewIns->SetDVar(m_pStackPointer[-1].var); + m_pLastNewIns->data[0] = GetDataItemIndex(elemClsHnd); + } } else { + readonly = false; // If readonly was set, it is no longer needed as its been handled. AddIns(INTOP_LDELEMA); m_pLastNewIns->SetSVars2(m_pStackPointer[0].var, m_pStackPointer[1].var); PushInterpType(InterpTypeByRef, elemClsHnd); diff --git a/src/coreclr/interpreter/intops.def b/src/coreclr/interpreter/intops.def index b88b71129a28c2..95ea7a745e66f6 100644 --- a/src/coreclr/interpreter/intops.def +++ b/src/coreclr/interpreter/intops.def @@ -53,7 +53,8 @@ OPDEF(INTOP_STELEM_VT, "stelem.vt", 6, 0, 3, InterpOpTwoInts) OPDEF(INTOP_STELEM_VT_NOREF, "stelem.vt.noref", 5, 0, 3, InterpOpInt) OPDEF(INTOP_LDELEMA, "ldelema", 5, 1, 2, InterpOpInt) -OPDEF(INTOP_LDELEMA_REF, "ldelema.ref", 6, 1, 2, InterpOpTwoInts) +OPDEF(INTOP_LDELEMA_REF, "ldelema.ref", 5, 1, 2, InterpOpClassHandle) +OPDEF(INTOP_LDELEMA_REF_GENERIC, "ldelema.ref.generic", 6, 1, 3, InterpOpGenericLookup) OPDEF(INTOP_MOV_I4_I1, "mov.i4.i1", 3, 1, 1, InterpOpNoArgs) OPDEF(INTOP_MOV_I4_U1, "mov.i4.u1", 3, 1, 1, InterpOpNoArgs) diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 288444e493aa45..6fc1faeb0e5485 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -2459,11 +2459,38 @@ do { \ COMPlusThrow(kIndexOutOfRangeException); uint8_t* pData = arr->GetDataPtr(); - size_t elemSize = ip[4]; - void* elemAddr = pData + idx * elemSize; + void* elemAddr = pData + idx * sizeof(void*); MethodTable* arrayElemMT = arr->GetArrayElementTypeHandle().AsMethodTable(); - MethodTable* expectedMT = (MethodTable*)pMethod->pDataItems[ip[5]]; + MethodTable* expectedMT = (MethodTable*)pMethod->pDataItems[ip[4]]; + if (arrayElemMT != expectedMT) + { + COMPlusThrow(kArrayTypeMismatchException); + } + + LOCAL_VAR(ip[1], void*) = elemAddr; + ip += 5; + break; + } + + case INTOP_LDELEMA_REF_GENERIC: + { + BASEARRAYREF arrayRef = LOCAL_VAR(ip[2], BASEARRAYREF); + if (arrayRef == NULL) + COMPlusThrow(kNullReferenceException); + + ArrayBase* arr = (ArrayBase*)OBJECTREFToObject(arrayRef); + uint32_t len = arr->GetNumComponents(); + uint32_t idx = (uint32_t)LOCAL_VAR(ip[3], int32_t); + if (idx >= len) + COMPlusThrow(kIndexOutOfRangeException); + + uint8_t* pData = arr->GetDataPtr(); + void* elemAddr = pData + idx * sizeof(void*); + + MethodTable* arrayElemMT = arr->GetArrayElementTypeHandle().AsMethodTable(); + InterpGenericLookup *pLookup = (InterpGenericLookup*)&pMethod->pDataItems[ip[5]]; + MethodTable* expectedMT = (MethodTable*)DoGenericLookup(LOCAL_VAR(ip[4], void*), pLookup); if (arrayElemMT != expectedMT) { COMPlusThrow(kArrayTypeMismatchException);