From e134f9cd2d2fdd517849ba3f219bccb61cb2b883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 12 Sep 2025 15:10:22 +0100 Subject: [PATCH 1/9] Signature parser Advance() now resets generic instance flag on parsing the instance --- src/CLR/Core/TypeSystem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 57bee990d8..38c2d3a69f 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -615,6 +615,9 @@ HRESULT CLR_RT_SignatureParser::Advance(Element &res) // need to update the parser counter too ParamCount = GenParamCount; + + // reset the generic instance flag + IsGenericInst = false; } NANOCLR_SET_AND_LEAVE(S_OK); From 05c9a03bd3c7e989f3daca9d8821aff35608bfcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 12 Sep 2025 15:17:13 +0100 Subject: [PATCH 2/9] Work on TypeSpec instance - Token resolution for TypeSpec now takes caller parameter. - TypeSpec Instance now caches element TypeDef on token resolution (when parsing VAR). - TypeSpec now stores level to deal with arrays from TypeSpecs. - ClearInstance() now clears all elements. --- src/CLR/Core/Interpreter.cpp | 2 +- src/CLR/Core/TypeSystem.cpp | 59 ++++++++++++++++++++++++++++--- src/CLR/Include/nanoCLR_Runtime.h | 5 ++- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index 1916bd7af6..771601fccc 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -3308,7 +3308,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) case TBL_TypeSpec: { CLR_RT_TypeSpec_Instance tsInst{}; - if (tsInst.ResolveToken(arg, assm) == false) + if (tsInst.ResolveToken(arg, assm, &stack->m_call) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 38c2d3a69f..777e510c1b 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -712,7 +712,14 @@ bool CLR_RT_TypeSpec_Instance::InitializeFromIndex(const CLR_RT_TypeSpec_Index & CLR_RT_SignatureParser::Element element; // if this is a generic, advance another one - parser.Advance(element); + if (FAILED(parser.Advance(element))) + { + ClearInstance(); + + return false; + } + + levels = element.Levels; if (element.DataType == DATATYPE_GENERICINST) { @@ -725,9 +732,7 @@ bool CLR_RT_TypeSpec_Instance::InitializeFromIndex(const CLR_RT_TypeSpec_Index & return true; } - data = 0; - assembly = nullptr; - target = nullptr; + ClearInstance(); return false; } @@ -739,9 +744,15 @@ void CLR_RT_TypeSpec_Instance::ClearInstance() assembly = nullptr; target = nullptr; + levels = 0; + genericTypeDef.Clear(); + data = 0; } -bool CLR_RT_TypeSpec_Instance::ResolveToken(CLR_UINT32 token, CLR_RT_Assembly *assm) +bool CLR_RT_TypeSpec_Instance::ResolveToken( + CLR_UINT32 token, + CLR_RT_Assembly *assm, + const CLR_RT_MethodDef_Instance *caller) { NATIVE_PROFILE_CLR_CORE(); if (assm && CLR_TypeFromTk(token) == TBL_TypeSpec) @@ -761,6 +772,8 @@ bool CLR_RT_TypeSpec_Instance::ResolveToken(CLR_UINT32 token, CLR_RT_Assembly *a // if this is a generic, advance another one parser.Advance(element); + levels = element.Levels; + if (element.DataType == DATATYPE_GENERICINST) { // this is a generic instance, so we need to advance one more time @@ -768,6 +781,42 @@ bool CLR_RT_TypeSpec_Instance::ResolveToken(CLR_UINT32 token, CLR_RT_Assembly *a genericTypeDef = element.Class; } + else if (element.DataType == DATATYPE_VAR) + { + // this is type‐generic slot (!T), resolve against the caller's closed generic + + int pos = element.GenericParamPosition; + + // Use the *caller's* bound genericType (Stack, etc.) + if (caller == nullptr || caller->genericType == nullptr) + { + ClearInstance(); + + return false; + } + + auto &tsi = *caller->genericType; + CLR_UINT32 closedTsRow = tsi.TypeSpec(); + + Set(caller->genericType->Assembly(), closedTsRow); + assembly = g_CLR_RT_TypeSystem.m_assemblies[caller->genericType->Assembly() - 1]; + + target = assm->GetTypeSpec(closedTsRow); + + NanoCLRDataType realDataType; + + g_CLR_RT_TypeSystem.m_assemblies[caller->genericType->Assembly() - 1] + ->FindGenericParamAtTypeSpec(closedTsRow, (CLR_UINT32)pos, cachedElementType, realDataType); + } + else if (element.DataType == DATATYPE_MVAR) + { + ASSERT(false); + } + else + { + genericTypeDef.Clear(); + } + return true; } diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index e3d77e6608..4336ea58e6 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -2087,13 +2087,16 @@ struct CLR_RT_TypeSpec_Instance : public CLR_RT_TypeSpec_Index const CLR_RECORD_TYPESPEC *target; CLR_RT_TypeDef_Index genericTypeDef; + CLR_UINT32 levels; + + CLR_RT_TypeDef_Index cachedElementType; //--// bool InitializeFromIndex(const CLR_RT_TypeSpec_Index &index); void ClearInstance(); - bool ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm); + bool ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm, const CLR_RT_MethodDef_Instance *caller = nullptr); }; //--// From c89e6a78ebd7fcc3a29e023d71050cb50c8d03bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 12 Sep 2025 15:18:20 +0100 Subject: [PATCH 3/9] ldtoken handler now properly parses TypeSpec token - Calls appropriate reflection and returning the correct reflection for the closed type instance. --- src/CLR/Core/Interpreter.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index 771601fccc..031894ed31 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -3307,13 +3307,34 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) { case TBL_TypeSpec: { + // this has to provide the closed instance of the type in the context of the caller'sc CLR_RT_TypeSpec_Instance tsInst{}; if (tsInst.ResolveToken(arg, assm, &stack->m_call) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } - evalPos[0].SetReflection((const CLR_RT_TypeSpec_Index &)tsInst.data); + // Check if this is an array type + if (tsInst.levels > 0) + { + // This is an array + + // Create a fake reflection index to pass the element type and levels. + CLR_RT_ReflectionDef_Index reflex; + reflex.kind = REFLECTION_TYPE; + reflex.levels = tsInst.levels; + reflex.data.type = tsInst.cachedElementType; + + evalPos[0].SetReflection(reflex); + } + else + { + // set reflection with TypeDef instance + CLR_RT_TypeDef_Instance cls{}; + cls.InitializeFromIndex(tsInst.cachedElementType); + + evalPos[0].SetReflection(cls); + } } break; From 3290a5d468e9573637040f64a6b7fb187ae58eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 12 Sep 2025 15:22:52 +0100 Subject: [PATCH 4/9] Rework HeapBlock array - When creating instance now uses proper reflection data with cached element type. - Rename local var for clarity. - Revert fix added before to tackle creation of jagged arrays from TypeSpec. --- src/CLR/Core/CLR_RT_HeapBlock_Array.cpp | 38 ++++++++----------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp index a5293a8987..25095b575e 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp @@ -19,7 +19,6 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( CLR_RT_TypeDef_Index cls; CLR_RT_TypeDef_Instance inst{}; CLR_RT_TypeDescriptor desc{}; - CLR_RT_ReflectionDef_Index workingReflex = reflex; reference.SetObjectReference(nullptr); @@ -28,31 +27,12 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( if (reflex.kind != REFLECTION_TYPE) { - // check for typespec - if (reflex.kind == REFLECTION_TYPESPEC) - { - // get the type descriptor for the typespec - (desc.InitializeFromTypeSpec(reflex.data.typeSpec)); - - // check that this ends up being a reflecion type - if (desc.m_reflex.kind != REFLECTION_TYPE) - { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); - } - - // copy over to working reflex - workingReflex = desc.m_reflex; - workingReflex.levels++; - } - else - { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); - } + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } - if (workingReflex.levels == 1) + if (reflex.levels == 1) { - cls = workingReflex.data.type; + cls = reflex.data.type; } else { @@ -115,7 +95,7 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( CLR_RT_HeapBlock ref; CLR_RT_TypeDef_Instance cls{}; - CLR_RT_TypeSpec_Instance def{}; + CLR_RT_TypeSpec_Instance tsInst{}; memset(&ref, 0, sizeof(struct CLR_RT_HeapBlock)); @@ -123,9 +103,15 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( { NANOCLR_CHECK_HRESULT(ref.SetReflection(cls)); } - else if (def.ResolveToken(tk, assm)) + else if (tsInst.ResolveToken(tk, assm)) { - NANOCLR_CHECK_HRESULT(ref.SetReflection((CLR_RT_TypeSpec_Index)def)); + // Create a fake reflection index to pass the element type and levels. + CLR_RT_ReflectionDef_Index reflex{}; + reflex.kind = REFLECTION_TYPE; + reflex.levels = tsInst.levels; + reflex.data.type = tsInst.cachedElementType; + + NANOCLR_CHECK_HRESULT(ref.SetReflection(reflex)); } else { From 67af5cf8cf756d242dc1c9901a101d3f61819865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 12 Sep 2025 15:24:04 +0100 Subject: [PATCH 5/9] Code style fixes --- src/CLR/Core/TypeSystem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 777e510c1b..f757ff5d00 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1033,6 +1033,7 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( const CLR_RT_MethodDef_Instance *caller) { NATIVE_PROFILE_CLR_CORE(); + if (assm) { CLR_UINT32 index = CLR_DataFromTk(tk); From a05efb11425cbfd57157e085b6a3e55fb63f79ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 12 Sep 2025 15:45:56 +0100 Subject: [PATCH 6/9] Token resolution now stores cached type for non generic instances --- src/CLR/Core/TypeSystem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index f757ff5d00..27cdd79f28 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -814,6 +814,8 @@ bool CLR_RT_TypeSpec_Instance::ResolveToken( } else { + cachedElementType = element.Class; + genericTypeDef.Clear(); } From b33d2750ae87ca5a8f79fa9246f27d05b545ea3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 12 Sep 2025 16:02:14 +0100 Subject: [PATCH 7/9] Fix ldtoken for TypeSpec with direct type instance --- src/CLR/Core/Interpreter.cpp | 37 +++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index 031894ed31..32a474b552 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -3323,17 +3323,44 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) CLR_RT_ReflectionDef_Index reflex; reflex.kind = REFLECTION_TYPE; reflex.levels = tsInst.levels; - reflex.data.type = tsInst.cachedElementType; + + // prefer generic type + if (NANOCLR_INDEX_IS_VALID(tsInst.genericTypeDef) && + NANOCLR_INDEX_IS_INVALID(tsInst.cachedElementType)) + { + reflex.data.type = tsInst.genericTypeDef; + } + else if (NANOCLR_INDEX_IS_VALID(tsInst.cachedElementType)) + { + reflex.data.type = tsInst.cachedElementType; + } + else + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } evalPos[0].SetReflection(reflex); } else { - // set reflection with TypeDef instance - CLR_RT_TypeDef_Instance cls{}; - cls.InitializeFromIndex(tsInst.cachedElementType); + // prefer generic type + if (NANOCLR_INDEX_IS_VALID(tsInst.genericTypeDef) && NANOCLR_INDEX_IS_INVALID(tsInst.cachedElementType)) + { + evalPos[0].SetReflection((const CLR_RT_TypeSpec_Index &)tsInst.data); + } + else if (NANOCLR_INDEX_IS_VALID(tsInst.cachedElementType)) + { + // set reflection with TypeDef instance + CLR_RT_TypeDef_Instance cls{}; + cls.InitializeFromIndex(tsInst.cachedElementType); + + evalPos[0].SetReflection(cls); + } + else + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } - evalPos[0].SetReflection(cls); } } break; From cbfa31961c14cba49f6e9ce81c86afe38383b05d Mon Sep 17 00:00:00 2001 From: "nfbot[bot]" Date: Fri, 12 Sep 2025 16:53:09 +0100 Subject: [PATCH 8/9] Code style fixes (#166) Automated fixes for code style. --- src/CLR/Core/Interpreter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index 32a474b552..4211e80831 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -3344,7 +3344,8 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) else { // prefer generic type - if (NANOCLR_INDEX_IS_VALID(tsInst.genericTypeDef) && NANOCLR_INDEX_IS_INVALID(tsInst.cachedElementType)) + if (NANOCLR_INDEX_IS_VALID(tsInst.genericTypeDef) && + NANOCLR_INDEX_IS_INVALID(tsInst.cachedElementType)) { evalPos[0].SetReflection((const CLR_RT_TypeSpec_Index &)tsInst.data); } @@ -3360,7 +3361,6 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } - } } break; From a2d661a09730cfcf75b3e5076d29b58a3263b844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 12 Sep 2025 17:05:02 +0100 Subject: [PATCH 9/9] Remove unused var --- src/CLR/Core/CLR_RT_HeapBlock_Array.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp index 25095b575e..c655986912 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp @@ -18,7 +18,6 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( CLR_RT_HeapBlock_Array *pArray; CLR_RT_TypeDef_Index cls; CLR_RT_TypeDef_Instance inst{}; - CLR_RT_TypeDescriptor desc{}; reference.SetObjectReference(nullptr);