diff --git a/src/CLR/Core/CLR_RT_HeapBlock.cpp b/src/CLR/Core/CLR_RT_HeapBlock.cpp index 0e6acf0b8c..05ac599a91 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock.cpp @@ -774,6 +774,137 @@ HRESULT CLR_RT_HeapBlock::Reassign(const CLR_RT_HeapBlock &value) NANOCLR_NOCLEANUP(); } +HRESULT CLR_RT_HeapBlock::Reassign(CLR_RT_HeapBlock &rhs, const CLR_RT_TypeDef_Instance &expectedType) +{ + NATIVE_PROFILE_CLR_CORE(); + NANOCLR_HEADER(); + + // Build a TypeDescriptor for the *expected* type (the IL TypeSpec/TypeDef) + CLR_RT_TypeDescriptor descExpected; + NANOCLR_CHECK_HRESULT(descExpected.InitializeFromTypeDef(expectedType)); + + // Build a TypeDescriptor for the *actual* runtime object in rhs + CLR_RT_TypeDescriptor descActual; + NANOCLR_CHECK_HRESULT(descActual.InitializeFromObject(rhs)); + + // Compare them (including generics, arrays, value-types, etc.) + if (!TypeDescriptorsMatch(descExpected, descActual)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + // They match: now do the actual copy + // - reference types & arrays: copy the object reference + // - value-types & primitives: copy the raw data + switch (descActual.GetDataType()) + { + case DATATYPE_CLASS: + case DATATYPE_SZARRAY: + { + // object reference or single-dim array + this->Assign(rhs); + break; + } + + default: + { + // value-type, primitive, struct, etc. + // this->CopyFrom(rhs); + break; + } + } + + NANOCLR_NOCLEANUP(); +} + +bool CLR_RT_HeapBlock::TypeDescriptorsMatch( + const CLR_RT_TypeDescriptor &expectedType, + const CLR_RT_TypeDescriptor &actualType) +{ + // Figure out logical DataTypes, promoting ACTUAL CLASS ---> GENERICINST + NanoCLRDataType expectedDataType = expectedType.GetDataType(); + NanoCLRDataType actualDataType = actualType.GetDataType(); + + // If the *actual* object is a closed-generic (even though boxed as CLASS), + // it will have m_handlerGenericType set. Promote it to GENERICINST. + if (actualDataType == DATATYPE_CLASS && actualType.m_handlerGenericType.data != CLR_EmptyToken) + { + actualDataType = DATATYPE_GENERICINST; + } + + // If either side is GENERICINST, we do generic-inst matching + if (expectedDataType == DATATYPE_GENERICINST || actualDataType == DATATYPE_GENERICINST) + { + auto &eSpec = expectedType.m_handlerGenericType; + auto &aSpec = actualType.m_handlerGenericType; + + return eSpec.Assembly() == aSpec.Assembly() && eSpec.typeDefIndex == aSpec.typeDefIndex; + } + + if (actualDataType <= DATATYPE_LAST_PRIMITIVE_TO_PRESERVE) + { + // If they declared a true valuetype, match directly: + if (expectedDataType == DATATYPE_VALUETYPE) + { + const auto &dtl = c_CLR_RT_DataTypeLookup[actualDataType]; + if (dtl.m_cls && dtl.m_cls->data == expectedType.m_handlerCls.data) + { + return true; + } + } + // if they declared a boxed struct (CLASS whose TypeDef is a struct), + // need to match that too: + else if (expectedDataType == DATATYPE_CLASS && expectedType.m_handlerGenericType.data == 0) + { + // Look up the TypeDef record flags to see if it's a VALUE-TYPE. + CLR_RT_TypeDef_Index clsIdx = expectedType.m_handlerCls; + + // fetch the owning assembly + CLR_RT_Assembly *ownerAsm = g_CLR_RT_TypeSystem.m_assemblies[clsIdx.Assembly() - 1]; + const CLR_RECORD_TYPEDEF *rec = ownerAsm->GetTypeDef(clsIdx.Type()); + + if (rec && + ((rec->flags & CLR_RECORD_TYPEDEF::TD_Semantics_Mask) == CLR_RECORD_TYPEDEF::TD_Semantics_ValueType)) + { + const auto &dtl = c_CLR_RT_DataTypeLookup[actualDataType]; + if (dtl.m_cls && dtl.m_cls->data == clsIdx.data) + { + return true; + } + } + } + } + + // For everything else, DataTypes must line up exactly + if (expectedDataType != actualDataType) + { + return false; + } + + // Dispatch on the remaining kinds + switch (expectedDataType) + { + case DATATYPE_CLASS: + case DATATYPE_VALUETYPE: + { + // compare TypeDef indices + auto &eCls = expectedType.m_handlerCls; + auto &aCls = actualType.m_handlerCls; + return eCls.data == aCls.data; + } + + case DATATYPE_SZARRAY: + { + // compare outer dims (always 1) then element types + return TypeDescriptorsMatch(expectedType, actualType); + } + + // primitives and other leaf types match on the DataType alone + default: + return true; + } +} + void CLR_RT_HeapBlock::AssignAndPinReferencedObject(const CLR_RT_HeapBlock &value) { // This is very special case that we have local variable with pinned attribute in metadata. @@ -787,7 +918,7 @@ void CLR_RT_HeapBlock::AssignAndPinReferencedObject(const CLR_RT_HeapBlock &valu m_data.objectReference.ptr->Unpin(); } - // Move the data. + // Move the data m_data = value.m_data; // Leave the same logic as in AssignAndPreserveType diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index b6b8fa4ec4..590b2f6fb6 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -1979,6 +1979,13 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( parser.Initialize_MethodLocals(assembly, methodDef); CLR_RT_SignatureParser::Element element; + // ensure we don’t walk past the available generic parameters + const int maxParams = parser.GenParamCount; + if (genericParamPosition < 0 || genericParamPosition > maxParams) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + // advance into the VAR entry parser.Advance(element); @@ -3217,6 +3224,38 @@ bool CLR_RT_ExecutionEngine::IsInstanceOf( return IsInstanceOf(desc, descTarget, isInstInstruction); } +/// +/// Checks whether the heap-object 'obj' satisfies exactly the type encoded by +/// the compressed token 'token' in the IL stream, under the current generic +/// instantiation in 'caller'. Supports DATATYPE_VAR slots and full GENERICINST. +/// +bool CLR_RT_ExecutionEngine::IsInstanceOfToken( + CLR_UINT32 token, + CLR_RT_HeapBlock &obj, + const CLR_RT_MethodDef_Instance &caller) +{ + // Resolve the *expected* signature into a TypeDescriptor + CLR_RT_TypeDescriptor expectedDesc; + HRESULT hr = expectedDesc.InitializeFromSignatureToken(caller.assembly, token, &caller); + + if (FAILED(hr)) + { + return false; + } + + // Extract the *actual* runtime type of the object + CLR_RT_TypeDescriptor actualDesc; + hr = actualDesc.InitializeFromObject(obj); + + if (FAILED(hr)) + { + return false; + } + + // Delegate to the CLR built-in type-compatibility test + return CLR_RT_HeapBlock::TypeDescriptorsMatch(expectedDesc, actualDesc); +} + HRESULT CLR_RT_ExecutionEngine::CastToType( CLR_RT_HeapBlock &ref, CLR_UINT32 tk, diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index c2eb8fc67c..d846f6caf4 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -2644,9 +2644,9 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) switch (dt) { + case DATATYPE_GENERICINST: case DATATYPE_CLASS: case DATATYPE_VALUETYPE: - case DATATYPE_GENERICINST: obj[fieldInst.CrossReference().offset].AssignAndPreserveType(evalPos[2]); break; case DATATYPE_DATETIME: // Special case. @@ -2969,7 +2969,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) NANOCLR_CHECK_HRESULT(CLR_RT_TypeDescriptor::ExtractTypeIndexFromObject(evalPos[0], cls)); // Check this is an object of the requested type. - if (type.data != cls.data) + if (!g_CLR_RT_ExecutionEngine.IsInstanceOfToken(arg, evalPos[0], stack->m_call)) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -3125,18 +3125,45 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) OPDEF(CEE_STELEM, "stelem", PopRef + PopI + Pop1, Push0, InlineType, IObjModel, 1, 0xFF, 0xA4, NEXT) // Stack: ... ... -> ... { - // Treat STELEM like ldelema + stobj - ip += 2; // Skip type argument, not used... + FETCH_ARG_COMPRESSED_TYPETOKEN(arg, ip); - evalPos -= 3; // "pop" args from evaluation stack + evalPos -= 3; CHECKSTACK(stack, evalPos); + // Build a by-ref to the array slot at [index] NANOCLR_CHECK_HRESULT( evalPos[1].InitializeArrayReference(evalPos[1], evalPos[2].NumericByRef().s4)); evalPos[1].FixArrayReferenceForValueTypes(); - // Reassign will make sure these are objects of the same type. - NANOCLR_CHECK_HRESULT(evalPos[1].Reassign(evalPos[3])); + // Resolve the IL's element type in the context of any generics + CLR_RT_TypeDef_Instance expectedType; + if (!expectedType.ResolveToken(arg, assm, &stack->m_call)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + NanoCLRDataType elemDT = (NanoCLRDataType)expectedType.target->dataType; + + // Promote the value if it's a reference or boxed struct + evalPos[3].Promote(); + + // Compute the element‐size: 0 for refs (incl. genericinst), sizeInBytes for primitives + size_t size = 0; + if (elemDT <= DATATYPE_LAST_PRIMITIVE_TO_PRESERVE) + { + size = c_CLR_RT_DataTypeLookup[elemDT].m_sizeInBytes; + } + else if ( + (expectedType.target->flags & CLR_RECORD_TYPEDEF::TD_Semantics_Mask) == + CLR_RECORD_TYPEDEF::TD_Semantics_ValueType) + { + size = + (CLR_RT_HeapBlock::HB_Object_Fields_Offset + +expectedType.CrossReference().totalFields) * + sizeof(CLR_RT_HeapBlock); + } + + // Store the value into the actual array buffer + NANOCLR_CHECK_HRESULT(evalPos[3].StoreToReference(evalPos[1], size)); break; } diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 9ec3dbdb82..95f47cc7ed 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -968,98 +968,93 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( case TBL_TypeSpec: { + // Grab the raw signature for the IL token (e.g. !T[], List`1, etc.) const CLR_RECORD_TYPESPEC *ts = assm->GetTypeSpec(index); - CLR_RT_SignatureParser parser; parser.Initialize_TypeSpec(assm, ts); - CLR_RT_SignatureParser::Element element; - - // advance signature: get parameter - parser.Advance(element); + CLR_RT_SignatureParser::Element elem; - // store parameter position - auto genericParamPosition = (CLR_INT8)element.GenericParamPosition; - - switch (element.DataType) + // Skip any leading SZARRAY or BYREF + do { - case DATATYPE_VAR: + if (FAILED(parser.Advance(elem))) { - CLR_RT_TypeDef_Index typeDef; - CLR_RT_SignatureParser::Element genericElement; - - CLR_RT_SignatureParser varParser; - varParser.Initialize_TypeSpec(assm, ts); - - // advance once to consume the GENERICINST or VAR entry - varParser.Advance(genericElement); + return false; + } + } while (elem.DataType == DATATYPE_SZARRAY || elem.DataType == DATATYPE_BYREF); - // now walk forward genericParameterPosition steps to land on the actual - // argument in the signature stream. - for (CLR_INT8 i = 0; i <= genericParamPosition; i++) - { - if (FAILED(varParser.Advance(genericElement))) - { - return false; - } - } + // If this is a closed‐generic instantiation header, peel off the wrapper + if (elem.DataType == DATATYPE_GENERICINST) + { + // consume the CLASS/VALUETYPE marker + if (FAILED(parser.Advance(elem))) + { + return false; + } + // consume the generic‐definition token itself + if (FAILED(parser.Advance(elem))) + { + return false; + } + // consume the count of generic arguments + if (FAILED(parser.Advance(elem))) + { + return false; + } + } - // genericElement.Class now holds the TypeDef_Index of the T or U, etc. - typeDef = genericElement.Class; + // walk forward until a VAR (type‐generic) or MVAR (method‐generic) is hit + while (elem.DataType != DATATYPE_VAR && elem.DataType != DATATYPE_MVAR) + { + if (FAILED(parser.Advance(elem))) + { + return false; + } + } - // populate this instance from the resolved TypeDef - data = typeDef.data; - assembly = g_CLR_RT_TypeSystem.m_assemblies[typeDef.Assembly() - 1]; - target = assembly->GetTypeDef(typeDef.Type()); + // If it's a type‐generic slot (!T), resolve against the caller's closed generic + if (elem.DataType == DATATYPE_VAR) + { + int pos = elem.GenericParamPosition; -#if defined(NANOCLR_INSTANCE_NAMES) - name = assembly->GetString(target->name); -#endif - return true; + // Use the *caller's* bound genericType (Stack, etc.) + if (caller == nullptr || caller->genericType == nullptr) + { + return false; } - break; - case DATATYPE_MVAR: - { - CLR_RT_GenericParam_Index gpIndex; + auto &tsi = *caller->genericType; + CLR_UINT32 closedTsRow = tsi.TypeSpec(); - caller->assembly->FindGenericParamAtMethodDef(*caller, genericParamPosition, gpIndex); + CLR_RT_TypeDef_Index realTd; + NanoCLRDataType realDt; - CLR_RT_GenericParam_CrossReference gp = - caller->assembly->crossReferenceGenericParam[gpIndex.GenericParam()]; + // Only call this once to map (e.g. !T→Int32) + caller->assembly->FindGenericParamAtTypeSpec(closedTsRow, (CLR_UINT32)pos, realTd, realDt); - // get TypeDef instance from generic parameter index - data = gp.classTypeDef.data; - assembly = g_CLR_RT_TypeSystem.m_assemblies[gp.classTypeDef.Assembly() - 1]; - target = assembly->GetTypeDef(gp.classTypeDef.Type()); - } - break; + // populate this instance + data = realTd.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[realTd.Assembly() - 1]; + target = assembly->GetTypeDef(realTd.Type()); - default: - return false; + return true; + } + else + { + // elem.DataType == DATATYPE_MVAR + CLR_RT_GenericParam_Index gpIdx; + caller->assembly->FindGenericParamAtMethodDef(*caller, elem.GenericParamPosition, gpIdx); + auto &gp = caller->assembly->crossReferenceGenericParam[gpIdx.GenericParam()]; + + data = gp.classTypeDef.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[gp.classTypeDef.Assembly() - 1]; + target = assembly->GetTypeDef(gp.classTypeDef.Type()); + return true; } - -#if defined(NANOCLR_INSTANCE_NAMES) - name = assembly->GetString(target->name); -#endif - - return true; } default: - //// handle generic type from provided data - // if (sampleData != nullptr) - //{ - // CLR_RT_TypeDescriptor::ExtractTypeIndexFromObject(*sampleData, *this); - // m_assm = g_CLR_RT_TypeSystem.m_assemblies[Assembly() - 1]; - // m_target = m_assm->GetTypeDef(Type()); - // } - // else - //{ - // m_data = g_CLR_RT_WellKnownTypes.Object.m_data; - // m_assm = g_CLR_RT_TypeSystem.m_assemblies[g_CLR_RT_WellKnownTypes.Object.Assembly() - 1]; - // m_target = m_assm->GetTypeDef(g_CLR_RT_WellKnownTypes.Object.Type()); - // } #if defined(NANOCLR_INSTANCE_NAMES) name = assembly->GetString(target->name); @@ -1159,81 +1154,81 @@ void CLR_RT_FieldDef_Instance::ClearInstance() bool CLR_RT_FieldDef_Instance::ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm) { NATIVE_PROFILE_CLR_CORE(); - if (assm) + + if (!assm) { - CLR_UINT32 index = CLR_DataFromTk(tk); + return false; + } - switch (CLR_TypeFromTk(tk)) + CLR_UINT32 index = CLR_DataFromTk(tk); + + switch (CLR_TypeFromTk(tk)) + { + case TBL_FieldRef: { - case TBL_FieldRef: + // Find the raw FIELDREF record + const CLR_RECORD_FIELDREF *fr = assm->GetFieldRef(index); + + switch (fr->Owner()) { - const CLR_RECORD_FIELDREF *fr = assm->GetFieldRef(index); + case TBL_TypeRef: + // Simple (non‐generic) field on a TypeRef + data = assm->crossReferenceFieldRef[index].target.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[Assembly() - 1]; + target = assembly->GetFieldDef(Field()); + genericType = nullptr; // no TypeSpec + break; - switch (fr->Owner()) + case TBL_TypeSpec: { - case TBL_TypeRef: - data = assm->crossReferenceFieldRef[index].target.data; - assembly = g_CLR_RT_TypeSystem.m_assemblies[Assembly() - 1]; - target = assembly->GetFieldDef(Field()); - - // invalidate generic type - genericType = nullptr; + // Field on a generic‐instantiated type. + // Use the MDP TypeSpec (which is already the closed generic), + genericType = &assm->crossReferenceFieldRef[index].genericType; - break; + // Retrieve that closed‐generic TypeSpec blob + const CLR_RECORD_TYPESPEC *ts = assm->GetTypeSpec(genericType->TypeSpec()); - case TBL_TypeSpec: + // Look up the actual FieldDef within that closed type + CLR_RT_FieldDef_Index resolvedField; + if (!assm->FindFieldDef(ts, assm->GetString(fr->name), assm, fr->signature, resolvedField)) { - genericType = &assm->crossReferenceFieldRef[index].genericType; - - const CLR_RECORD_TYPESPEC *ts = assm->GetTypeSpec(genericType->TypeSpec()); - - CLR_RT_FieldDef_Index field; - - if (!assm->FindFieldDef(ts, assm->GetString(fr->name), assm, fr->signature, field)) - { - return false; - } - - Set(assm->assemblyIndex, field.Field()); - - assembly = assm; - target = assembly->GetFieldDef(Field()); - - break; - } - default: - // shouldn't be here return false; + } + + // Bind to that real FieldDef + Set(assm->assemblyIndex, resolvedField.Field()); + assembly = assm; + target = assembly->GetFieldDef(Field()); + break; } -#if defined(NANOCLR_INSTANCE_NAMES) - name = assembly->GetString(target->name); -#endif - return true; + default: + // should not happen + return false; } - case TBL_FieldDef: - Set(assm->assemblyIndex, index); - assembly = assm; - target = assembly->GetFieldDef(index); +#if defined(NANOCLR_INSTANCE_NAMES) + name = assembly->GetString(target->name); +#endif + return true; + } - // invalidate generic type - genericType = nullptr; + case TBL_FieldDef: + // Direct FieldDef token + Set(assm->assemblyIndex, CLR_DataFromTk(tk)); + assembly = assm; + target = assembly->GetFieldDef(Field()); + genericType = nullptr; #if defined(NANOCLR_INSTANCE_NAMES) - name = assembly->GetString(target->name); + name = assembly->GetString(target->name); #endif - return true; + return true; - default: - // the remaining data types aren't to be handled - break; - } + default: + // Not a field token + return false; } - - ClearInstance(); - - return false; } ////////////////////////////// @@ -1680,6 +1675,25 @@ HRESULT CLR_RT_TypeDescriptor::InitializeFromType(const CLR_RT_TypeDef_Index &cl NANOCLR_NOCLEANUP(); } +HRESULT CLR_RT_TypeDescriptor::InitializeFromTypeDef(const CLR_RT_TypeDef_Index &cls) +{ + NATIVE_PROFILE_CLR_CORE(); + NANOCLR_HEADER(); + if (m_handlerCls.InitializeFromIndex(cls) == false) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + else + { + m_flags = CLR_RT_DataTypeLookup::c_ManagedType; + m_reflex.kind = REFLECTION_TYPE; + m_reflex.levels = 0; + m_reflex.data.type = m_handlerCls; + } + m_handlerGenericType.ClearInstance(); + NANOCLR_NOCLEANUP(); +} + HRESULT CLR_RT_TypeDescriptor::InitializeFromGenericType(const CLR_RT_TypeSpec_Index &genericType) { NATIVE_PROFILE_CLR_CORE(); @@ -1748,6 +1762,89 @@ HRESULT CLR_RT_TypeDescriptor::InitializeFromSignatureParser(CLR_RT_SignaturePar NANOCLR_NOCLEANUP(); } +HRESULT CLR_RT_TypeDescriptor::InitializeFromSignatureToken( + CLR_RT_Assembly *assm, + CLR_UINT32 token, + const CLR_RT_MethodDef_Instance *caller) +{ + NANOCLR_HEADER(); + + // Peel the compressed token to find out which table and index we're in + NanoCLRTable dataTable = CLR_TypeFromTk(token); + CLR_UINT32 idx = CLR_DataFromTk(token); + + switch (dataTable) + { + case TBL_TypeRef: + case TBL_TypeDef: + { + CLR_RT_TypeDef_Instance tdInst; + if (!tdInst.ResolveToken(token, assm, caller)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + this->InitializeFromTypeDef(tdInst); + break; + } + + case TBL_TypeSpec: + { + // could be SZARRAY, VAR, MVAR or full GENERICINST + const CLR_RECORD_TYPESPEC *ts = assm->GetTypeSpec(idx); + CLR_RT_SignatureParser parser; + parser.Initialize_TypeSpec(assm, ts); + + CLR_RT_SignatureParser::Element elem; + parser.Advance(elem); + + if (elem.DataType == DATATYPE_VAR) + { + // !T: ask the CLR to map that slot into the *actual* argument + CLR_RT_TypeDef_Index td; + NanoCLRDataType dt; + assm->FindGenericParamAtTypeSpec(caller->genericType->TypeSpec(), elem.GenericParamPosition, td, dt); + this->InitializeFromTypeDef(td); + } + else if (elem.DataType == DATATYPE_MVAR) + { + // !!U: method-generic + CLR_RT_GenericParam_Index gp; + assm->FindGenericParamAtMethodDef(*caller, elem.GenericParamPosition, gp); + auto &info = assm->crossReferenceGenericParam[gp.GenericParam()]; + this->InitializeFromTypeDef(info.classTypeDef); + } + else if (elem.DataType == DATATYPE_GENERICINST) + { + // full generic instantiation: read it out + // CLASS/VALUETYPE + parser.Advance(elem); + // generic-definition token + parser.Advance(elem); + + CLR_RT_TypeSpec_Index tsInst{}; + tsInst.Set(elem.Class.Assembly(), elem.Class.Type()); + + // argument count + parser.Advance(elem); + + // now read each argument and record in tsInst.m_data.GenericArguments + this->InitializeFromTypeSpec(tsInst); + } + else + { + // e.g. SZARRAY, VALUETYPE, CLASS + this->InitializeFromSignatureParser(parser); + } + break; + } + + default: + NANOCLR_SET_AND_LEAVE(CLR_E_NOTIMPL); + } + + NANOCLR_NOCLEANUP(); +} + HRESULT CLR_RT_TypeDescriptor::InitializeFromObject(const CLR_RT_HeapBlock &ref) { NATIVE_PROFILE_CLR_CORE(); @@ -4476,9 +4573,50 @@ bool CLR_RT_Assembly::FindGenericParam(CLR_INDEX typeSpecIndex, CLR_RT_GenericPa return false; } +bool CLR_RT_Assembly::FindGenericParamAtTypeSpec( + CLR_UINT32 typeSpecIndex, + CLR_INT32 genericParameterPosition, + CLR_RT_TypeDef_Index &typeDef, + NanoCLRDataType &dataType) +{ + NATIVE_PROFILE_CLR_CORE(); + + CLR_RT_SignatureParser parser; + parser.Initialize_TypeSpec(this, GetTypeSpec(typeSpecIndex)); + + CLR_RT_SignatureParser::Element element; + + // get into the GENERICINST + if (FAILED(parser.Advance(element))) + { + return false; + } + + // sanity check for invalid parameter position + if (genericParameterPosition > parser.GenParamCount) + { + // not enough parameters!! + return false; + } + + // walk to the requested parameter position + for (int32_t i = 0; i <= genericParameterPosition; i++) + { + if (FAILED(parser.Advance(element))) + { + return false; + } + } + + // element.Class was filled from the VAR position + typeDef = element.Class; + dataType = element.DataType; + return true; +} + bool CLR_RT_Assembly::FindGenericParamAtMethodDef( CLR_RT_MethodDef_Instance md, - CLR_UINT32 genericParameterPosition, + CLR_INT32 genericParameterPosition, CLR_RT_GenericParam_Index &index) { NATIVE_PROFILE_CLR_CORE(); diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index 1c8c7f961f..1ecd2f4a42 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -1422,10 +1422,14 @@ struct CLR_RT_Assembly : public CLR_RT_HeapBlock_Node // EVENT HEAP - NO RELOCAT bool FindTypeDef(CLR_UINT32 hash, CLR_RT_TypeDef_Index &index); bool FindTypeSpec(const CLR_PMETADATA sig, CLR_RT_TypeSpec_Index &index); - + bool FindGenericParamAtTypeSpec( + CLR_UINT32 typeSpecIndex, + CLR_INT32 genericParameterPosition, + CLR_RT_TypeDef_Index &typeDef, + NanoCLRDataType &dataType); bool FindGenericParamAtMethodDef( CLR_RT_MethodDef_Instance md, - CLR_UINT32 genericParameterPosition, + CLR_INT32 genericParameterPosition, CLR_RT_GenericParam_Index &index); bool FindGenericParam(CLR_INDEX typeSpecIndex, CLR_RT_GenericParam_Index &index); bool FindMethodSpecFromTypeSpec(CLR_INDEX typeSpecIndex, CLR_RT_MethodSpec_Index &index); @@ -2329,9 +2333,14 @@ struct CLR_RT_TypeDescriptor HRESULT InitializeFromReflection(const CLR_RT_ReflectionDef_Index &reflex); HRESULT InitializeFromTypeSpec(const CLR_RT_TypeSpec_Index &sig); HRESULT InitializeFromType(const CLR_RT_TypeDef_Index &cls); + HRESULT InitializeFromTypeDef(const CLR_RT_TypeDef_Index &cls); HRESULT InitializeFromGenericType(const CLR_RT_TypeSpec_Index &genericType); HRESULT InitializeFromFieldDefinition(const CLR_RT_FieldDef_Instance &fd); HRESULT InitializeFromSignatureParser(CLR_RT_SignatureParser &parser); + HRESULT InitializeFromSignatureToken( + CLR_RT_Assembly *assm, + CLR_UINT32 token, + const CLR_RT_MethodDef_Instance *caller); HRESULT InitializeFromObject(const CLR_RT_HeapBlock &ref); void ConvertToArray(); @@ -4062,6 +4071,7 @@ struct CLR_RT_ExecutionEngine static bool IsInstanceOf(const CLR_RT_TypeDef_Index &cls, const CLR_RT_TypeDef_Index &clsTarget); static bool IsInstanceOf(CLR_RT_HeapBlock &obj, const CLR_RT_TypeDef_Index &clsTarget); static bool IsInstanceOf(CLR_RT_HeapBlock &obj, CLR_RT_Assembly *assm, CLR_UINT32 token, bool isInstInstruction); + bool IsInstanceOfToken(CLR_UINT32 token, CLR_RT_HeapBlock &obj, const CLR_RT_MethodDef_Instance &caller); static HRESULT CastToType(CLR_RT_HeapBlock &ref, CLR_UINT32 tk, CLR_RT_Assembly *assm, bool isInstInstruction); diff --git a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h index 778ab87287..e7b33e8434 100644 --- a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h +++ b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h @@ -1360,6 +1360,7 @@ struct CLR_RT_HeapBlock HRESULT LoadFromReference(CLR_RT_HeapBlock &ref); HRESULT StoreToReference(CLR_RT_HeapBlock &ref, int size); HRESULT Reassign(const CLR_RT_HeapBlock &value); + HRESULT Reassign(CLR_RT_HeapBlock &rhs, const CLR_RT_TypeDef_Instance &expectedType); HRESULT PerformBoxingIfNeeded(); HRESULT PerformBoxing(const CLR_RT_TypeDef_Instance &cls); HRESULT PerformUnboxing(const CLR_RT_TypeDef_Instance &cls); @@ -1371,6 +1372,7 @@ struct CLR_RT_HeapBlock bool IsZero() const; void Promote(); + static bool TypeDescriptorsMatch(const CLR_RT_TypeDescriptor &exp, const CLR_RT_TypeDescriptor &act); static CLR_UINT32 GetHashCode(CLR_RT_HeapBlock *ptr, bool fRecurse, CLR_UINT32 crc); static bool ObjectsEqual(const CLR_RT_HeapBlock &left, const CLR_RT_HeapBlock &right, bool fSameReference);