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);