From 022586f92105c674e2698f2418ad74623366e336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 7 Jul 2025 15:57:04 +0100 Subject: [PATCH 01/61] Fix box/unbox Nullable types - TypeDef_Instance ResolveToken now properly handles TypeSpec tokens for class and value types. - Add ResolveNullableType() to resolve T for Nullable types. - Add Nullable`1 to well known types array. - Add System_Nullable_1 to mscorlib class declaration. - Rework box/unbox handler code to properly deal with nullable types. --- src/CLR/CorLib/corlib_native.h | 8 ++ src/CLR/Core/Interpreter.cpp | 96 +++++++++++++++++++- src/CLR/Core/TypeSystem.cpp | 146 ++++++++++++++++++++++++------ src/CLR/Include/nanoCLR_Runtime.h | 2 + 4 files changed, 223 insertions(+), 29 deletions(-) diff --git a/src/CLR/CorLib/corlib_native.h b/src/CLR/CorLib/corlib_native.h index a133cf247d..0024bd5eaf 100644 --- a/src/CLR/CorLib/corlib_native.h +++ b/src/CLR/CorLib/corlib_native.h @@ -644,6 +644,14 @@ struct Library_corlib_native_System_MulticastDelegate //--// }; +struct Library_corlib_native_System_Nullable_1 +{ + static const int FIELD__hasValue = 1; + static const int FIELD__value = 2; + + //--// +}; + struct Library_corlib_native_System_Number { NANOCLR_NATIVE_DECLARE(FormatNative___STATIC__STRING__OBJECT__BOOLEAN__STRING__STRING__STRING__STRING__SZARRAY_I4); diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index ba41d2ff27..d2bafe8ce5 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -5,6 +5,8 @@ // #include "Core.h" +typedef Library_corlib_native_System_Nullable_1 Sys_Nullable; + //////////////////////////////////////////////////////////////////////////////////////////////////// #if defined(NANOCLR_TRACE_EXCEPTIONS) && defined(VIRTUAL_DEVICE) @@ -2802,13 +2804,101 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) UPDATESTACK(stack, evalPos); + // check if value is a nullable type + bool hasValue = false; + CLR_RT_HeapBlock *nullableValue = nullptr; + bool valueIsNullableType = false; + bool tokenIsNullableType = false; + CLR_RT_TypeDef_Instance destinationType; + + valueIsNullableType = + CLR_RT_ExecutionEngine::IsInstanceOf(evalPos[0], g_CLR_RT_WellKnownTypes.Nullable); + tokenIsNullableType = + CLR_RT_ExecutionEngine::IsInstanceOf(typeInst, g_CLR_RT_WellKnownTypes.Nullable); + + // resolve the T to box to / unbox from + if (tokenIsNullableType && destinationType.ResolveNullableType(arg, assm, &stack->m_call) == false) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + if (valueIsNullableType) + { + // check HasValue property + nullableValue = evalPos[0].Dereference(); + hasValue = nullableValue[Library_corlib_native_System_Nullable_1::FIELD__hasValue] + .NumericByRefConst() + .u1; + } + if (op == CEE_BOX) { - NANOCLR_CHECK_HRESULT(evalPos[0].PerformBoxing(typeInst)); + if (tokenIsNullableType) + { + if (!hasValue) + { + // box a null reference + evalPos[0].SetObjectReference(nullptr); + } + else + { + // reach the value to box + CLR_RT_HeapBlock &value = + nullableValue[Library_corlib_native_System_Nullable_1::FIELD__value]; + + // box the value + NANOCLR_CHECK_HRESULT(value.PerformBoxing(destinationType)); + + // assign the boxed result back to the evaluation stack + evalPos[0].Assign(value); + } + } + else + { + NANOCLR_CHECK_HRESULT(evalPos[0].PerformBoxing(typeInst)); + } } else { - NANOCLR_CHECK_HRESULT(evalPos[0].PerformUnboxing(typeInst)); + if (tokenIsNullableType) + { + // create a Nullable... + CLR_RT_HeapBlock nullableObject; + CLR_RT_TypeSpec_Index destinationTypeSpec; + destinationTypeSpec.data = arg; + + NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewGenericInstanceObject( + nullableObject, + typeInst, + destinationTypeSpec)); + + CLR_RT_ProtectFromGC gc(nullableObject); + + if (evalPos[0].Dereference() == nullptr) + { + // assign a null reference (already carried out by NewObjectFromIndex) + // set HasValue to false + nullableObject.Dereference()[Sys_Nullable::FIELD__hasValue].SetBoolean(false); + } + else + { + // unbox the T value... + NANOCLR_CHECK_HRESULT(evalPos[0].PerformUnboxing(destinationType)); + + // assign the copied unboxed value + nullableObject.Dereference()[Sys_Nullable::FIELD__value].Assign(evalPos[0]); + + // set HasValue to true + nullableObject.Dereference()[Sys_Nullable::FIELD__hasValue].SetBoolean(true); + } + + // assign the Nullable object to the evaluation stack + evalPos[0].SetObjectReference(nullableObject.Dereference()); + } + else + { + NANOCLR_CHECK_HRESULT(evalPos[0].PerformUnboxing(typeInst)); + } } break; } @@ -2825,6 +2915,8 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) // ldobj.) When applied to a reference type, the unbox.any instruction has the same effect as // castclass typeTok. + // TODO: still not handling Nullable types here + CLR_RT_TypeDef_Instance typeInst{}; if (typeInst.ResolveToken(arg, assm, &stack->m_call) == false) { diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index d9fc7ea430..e273b180aa 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -976,34 +976,23 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( parser.Initialize_TypeSpec(assm, ts); CLR_RT_SignatureParser::Element elem; - - // Skip any leading SZARRAY or BYREF - do + if (FAILED(parser.Advance(elem))) { - if (FAILED(parser.Advance(elem))) - { - return false; - } - } while (elem.DataType == DATATYPE_SZARRAY || elem.DataType == DATATYPE_BYREF); + return false; + } - // If this is a closed‐generic instantiation header, peel off the wrapper - if (elem.DataType == DATATYPE_GENERICINST) + if (elem.DataType == DATATYPE_CLASS || elem.DataType == DATATYPE_VALUETYPE) { - // 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; - } + // If it's a class or value type, resolve the type + data = elem.Class.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[elem.Class.Assembly() - 1]; + target = assembly->GetTypeDef(elem.Class.Type()); + +#if defined(NANOCLR_INSTANCE_NAMES) + name = assembly->GetString(target->name); +#endif + + return true; } // walk forward until a VAR (type‐generic) or MVAR (method‐generic) is hit @@ -1045,8 +1034,6 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( } else { - // elem.DataType == DATATYPE_MVAR - // Use the *caller's* bound genericType (Stack, etc.) if (caller == nullptr || caller->genericType == nullptr) { @@ -1060,6 +1047,7 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( data = gp.classTypeDef.data; assembly = g_CLR_RT_TypeSystem.m_assemblies[gp.classTypeDef.Assembly() - 1]; target = assembly->GetTypeDef(gp.classTypeDef.Type()); + return true; } } @@ -1081,6 +1069,109 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( return false; } +bool CLR_RT_TypeDef_Instance::ResolveNullableType( + CLR_UINT32 tk, + CLR_RT_Assembly *assm, + const CLR_RT_MethodDef_Instance *caller) +{ + NATIVE_PROFILE_CLR_CORE(); + + if (assm) + { + CLR_UINT32 index = CLR_DataFromTk(tk); + + if (CLR_TypeFromTk(tk) != TBL_TypeSpec) + { + // not a TypeSpec, so return false + ClearInstance(); + return false; + } + + // 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 elem; + if (FAILED(parser.Advance(elem))) + { + return false; + } + + if (elem.DataType != DATATYPE_VALUETYPE) + { + // If it's not a value type, we can't resolve it as a nullable type + ClearInstance(); + return false; + } + + // move to the next element in the signature + if (FAILED(parser.Advance(elem))) + { + return false; + } + + // If it's a type‐generic slot (!T), resolve against the caller's closed generic + if (elem.DataType == DATATYPE_VAR) + { + int pos = elem.GenericParamPosition; + + // Use the *caller's* bound genericType (Stack, etc.) + if (caller == nullptr || caller->genericType == nullptr) + { + return false; + } + + auto &tsi = *caller->genericType; + CLR_UINT32 closedTsRow = tsi.TypeSpec(); + + CLR_RT_TypeDef_Index realTypeDef; + NanoCLRDataType realDataType; + + // Only call this once to map (e.g. !T→Int32) + caller->assembly->FindGenericParamAtTypeSpec(closedTsRow, (CLR_UINT32)pos, realTypeDef, realDataType); + + // populate this instance + data = realTypeDef.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[realTypeDef.Assembly() - 1]; + target = assembly->GetTypeDef(realTypeDef.Type()); + + return true; + } + else if (elem.DataType == DATATYPE_MVAR) + { + // Use the *caller's* bound genericType (Stack, etc.) + if (caller == nullptr || caller->genericType == nullptr) + { + return false; + } + + 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; + } + else + { + // If it's a class or value type, resolve the type + data = elem.Class.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[elem.Class.Assembly() - 1]; + target = assembly->GetTypeDef(elem.Class.Type()); + + return true; + } + } + + ClearInstance(); + + return false; +} + //--// bool CLR_RT_TypeDef_Instance::SwitchToParent() @@ -4293,6 +4384,7 @@ static const TypeIndexLookup c_TypeIndexLookup[] = { TIL("System", "Object", Object), TIL("System", "ValueType", ValueType), TIL("System", "Enum", Enum), + TIL("System", "Nullable`1", Nullable), TIL("System", "AppDomainUnloadedException", AppDomainUnloadedException), TIL("System", "ArgumentNullException", ArgumentNullException), diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index f59689d17c..170037ff63 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -1691,6 +1691,7 @@ struct CLR_RT_WellKnownTypes CLR_RT_TypeDef_Index Object; CLR_RT_TypeDef_Index ValueType; CLR_RT_TypeDef_Index Enum; + CLR_RT_TypeDef_Index Nullable; CLR_RT_TypeDef_Index AppDomainUnloadedException; CLR_RT_TypeDef_Index ArgumentNullException; @@ -2114,6 +2115,7 @@ struct CLR_RT_TypeDef_Instance : public CLR_RT_TypeDef_Index void ClearInstance(); bool ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm, const CLR_RT_MethodDef_Instance *caller = nullptr); + bool ResolveNullableType(CLR_UINT32 tk, CLR_RT_Assembly *assm, const CLR_RT_MethodDef_Instance *caller = nullptr); //--// From f5694b83d7185dda30739c4157d47d07c720add7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Tue, 5 Aug 2025 15:17:41 +0100 Subject: [PATCH 02/61] Replace SetGenericInstanceObject with SetGenericInstanceType --- src/CLR/Core/CLR_RT_HeapBlock.cpp | 13 ++----------- src/CLR/Include/nanoCLR_Runtime__HeapBlock.h | 14 +++++++++++--- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/CLR/Core/CLR_RT_HeapBlock.cpp b/src/CLR/Core/CLR_RT_HeapBlock.cpp index 6bcf07ab0a..bca81f460b 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock.cpp @@ -349,21 +349,12 @@ HRESULT CLR_RT_HeapBlock::SetObjectCls(const CLR_RT_TypeDef_Index &cls) NANOCLR_NOCLEANUP(); } -HRESULT CLR_RT_HeapBlock::SetGenericInstanceObject(const CLR_RT_TypeSpec_Index &genericType) +HRESULT CLR_RT_HeapBlock::SetGenericInstanceType(const CLR_RT_TypeSpec_Index &genericType) { NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); - CLR_RT_TypeSpec_Instance instance; - - if (instance.InitializeFromIndex(genericType) == false) - { - NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); - } - - m_data.genericInstance.genericType = genericType; - m_data.genericInstance.ptr = nullptr; - m_id.raw = CLR_RT_HEAPBLOCK_RAW_ID(DATATYPE_GENERICINST, 0, 1); + m_data.reflection.data.genericType = genericType; NANOCLR_NOCLEANUP(); } diff --git a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h index 1498c409dc..74b7165a7e 100644 --- a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h +++ b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h @@ -114,7 +114,7 @@ struct CLR_RT_HeapBlock static const CLR_UINT32 HB_Event = 0x04; static const CLR_UINT32 HB_Pinned = 0x08; static const CLR_UINT32 HB_Boxed = 0x10; - static const CLR_UINT32 HB_Unused20 = 0x20; + static const CLR_UINT32 HB_GenericInstance = 0x20; // If more bits are needed, HB_Signaled and HB_SignalAutoReset can be freed for use with a little work. // It is not necessary that any heapblock can be waited upon. Currently, only Threads (Thread.Join), // ManualResetEvent, and AutoResetEvent are waitable objects. @@ -1192,10 +1192,18 @@ struct CLR_RT_HeapBlock const CLR_RT_TypeSpec_Index &ObjectGenericType() const { - return m_data.genericInstance.genericType; + if ((m_id.type.flags & CLR_RT_HeapBlock::HB_GenericInstance) == CLR_RT_HeapBlock::HB_GenericInstance) + { + return m_data.reflection.data.genericType; + } + else + { + // Invalid index + return (CLR_RT_TypeSpec_Index)0x0; + } } - HRESULT SetGenericInstanceObject(const CLR_RT_TypeSpec_Index &genericType); + HRESULT SetGenericInstanceType(const CLR_RT_TypeSpec_Index &genericType); //--// From aff8379aad4eaaf8bf1597df1a9269216eeec37d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Tue, 5 Aug 2025 15:21:58 +0100 Subject: [PATCH 03/61] Fix creation of generic objects - Fix signature parser for genetic instances. - Fix resolve token for TypeDef instance. Now gets generic instance as parameter. - Fix ResolveToken for FieldDef. Now gets generic instance as parameter. - Update calls accordingly. - Also fixed dump generic objects. --- src/CLR/Core/Execution.cpp | 242 +++++++++++++----- src/CLR/Core/Interpreter.cpp | 60 ++--- src/CLR/Core/TypeSystem.cpp | 311 ++++++++++++++++++----- src/CLR/Diagnostics/Diagnostics_stub.cpp | 4 +- src/CLR/Include/nanoCLR_Runtime.h | 29 ++- 5 files changed, 470 insertions(+), 176 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index f1629f98e5..20597bf863 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -1567,9 +1567,11 @@ CLR_RT_HeapBlock *CLR_RT_ExecutionEngine::ExtractHeapBlocksForGenericInstance( flags = flags | CLR_RT_HeapBlock::HB_InitializeToZero; CLR_RT_HeapBlock *hb = ExtractHeapBlocks(m_heap, DATATYPE_GENERICINST, flags, length); + _ASSERT(true); + if (hb) { - hb->SetGenericInstanceObject(genericType); + // hb->SetGenericInstanceObject(genericType); #if defined(NANOCLR_PROFILE_NEW_ALLOCATIONS) g_CLR_PRF_Profiler.TrackObjectCreation(hb); @@ -1821,7 +1823,10 @@ CLR_RT_HeapBlock *CLR_RT_ExecutionEngine::AccessStaticField(const CLR_RT_FieldDe return nullptr; } -HRESULT CLR_RT_ExecutionEngine::InitializeReference(CLR_RT_HeapBlock &ref, CLR_RT_SignatureParser &parser) +HRESULT CLR_RT_ExecutionEngine::InitializeReference( + CLR_RT_HeapBlock &ref, + CLR_RT_SignatureParser &parser, + const CLR_RT_TypeSpec_Instance *genericInstance) { NATIVE_PROFILE_CLR_CORE(); // @@ -1834,10 +1839,12 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference(CLR_RT_HeapBlock &ref, CLR_R CLR_RT_SignatureParser::Element res; NanoCLRDataType dt; + CLR_RT_TypeDef_Index realTypeDef; NANOCLR_CHECK_HRESULT(parser.Advance(res)); dt = res.DataType; + realTypeDef.data = res.Class.data; if (res.Levels > 0) // Array { @@ -1845,10 +1852,59 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference(CLR_RT_HeapBlock &ref, CLR_R } else { - if (dt == DATATYPE_VALUETYPE) + process_datatype: + + if (dt == DATATYPE_VAR) + { + genericInstance->assembly + ->FindGenericParamAtTypeSpec(genericInstance->data, res.GenericParamPosition, realTypeDef, dt); + + goto process_datatype; + } + else if (dt == DATATYPE_MVAR) + { + _ASSERT(true); + + goto process_datatype; + } + else if (dt == DATATYPE_GENERICINST) + { + // need to unwind one position in the signature to have the complete one to seach TypeSpecs + CLR_PMETADATA typeSpecSignature = parser.Signature; + typeSpecSignature--; + + CLR_RT_TypeSpec_Index genericTSIndex = {}; + if (!parser.Assembly->FindTypeSpec(typeSpecSignature, genericTSIndex)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + // copy over to parameter + CLR_RT_TypeSpec_Instance genericTSInstance; + genericTSInstance.InitializeFromIndex(genericTSIndex); + genericInstance = &genericTSInstance; + + CLR_RT_SignatureParser sp; + sp.Initialize_TypeSpec(parser.Assembly, parser.Assembly->GetTypeSpec(genericTSInstance.TypeSpec())); + + CLR_RT_SignatureParser::Element element; + NANOCLR_CHECK_HRESULT(sp.Advance(element)); + + // if this is another generic instance, need to advance to get the type + if (dt == DATATYPE_GENERICINST) + { + NANOCLR_CHECK_HRESULT(sp.Advance(element)); + } + + dt = element.DataType; + realTypeDef.data = element.Class.data; + + goto process_datatype; + } + else if (dt == DATATYPE_VALUETYPE) { CLR_RT_TypeDef_Instance inst{}; - inst.InitializeFromIndex(res.Class); + inst.InitializeFromIndex(realTypeDef); if ((inst.target->flags & CLR_RECORD_TYPEDEF::TD_Semantics_Mask) == CLR_RECORD_TYPEDEF::TD_Semantics_Enum) { @@ -1856,11 +1912,12 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference(CLR_RT_HeapBlock &ref, CLR_R } else { - NANOCLR_SET_AND_LEAVE(NewObject(ref, inst)); + NANOCLR_SET_AND_LEAVE(NewObject(ref, inst, genericInstance)); } } else { + if (c_CLR_RT_DataTypeLookup[dt].m_flags & CLR_RT_DataTypeLookup::c_Reference) { dt = DATATYPE_OBJECT; @@ -1877,7 +1934,8 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference(CLR_RT_HeapBlock &ref, CLR_R HRESULT CLR_RT_ExecutionEngine::InitializeReference( CLR_RT_HeapBlock &ref, const CLR_RECORD_FIELDDEF *target, - CLR_RT_Assembly *assm) + CLR_RT_Assembly *assm, + const CLR_RT_TypeSpec_Instance *genericInstance) { NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); @@ -1885,7 +1943,7 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference( CLR_RT_SignatureParser parser{}; parser.Initialize_FieldDef(assm, target); - NANOCLR_SET_AND_LEAVE(InitializeReference(ref, parser)); + NANOCLR_SET_AND_LEAVE(InitializeReference(ref, parser, genericInstance)); NANOCLR_NOCLEANUP(); } @@ -1897,11 +1955,13 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( const CLR_RT_MethodDef_Instance &methodDefInstance) { NATIVE_PROFILE_CLR_CORE(); - // - // WARNING!!! - // - // This method is a shortcut for the following code: - // + + ////////////////////////////////////////////////////////////////////// + // // + // ***** WARNING ***** // + // // + // Changes here must be ported to "CLR_RT_SignatureParser::Advance" // + ////////////////////////////////////////////////////////////////////// NANOCLR_HEADER(); @@ -1910,6 +1970,8 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( CLR_PMETADATA sig = assembly->GetSignature(methodDef->locals); CLR_UINT32 count = methodDef->localsCount; bool fZeroed = false; + bool isGenericInstance = false; + CLR_RT_TypeSpec_Instance genericInstance = {}; while (count) { @@ -1958,52 +2020,76 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( } case DATATYPE_GENERICINST: - // need to rewind the signature so that the ELEMENT_TYPE is present - // otherwise the comparison won't be possible - sig--; + { + // set flag + isGenericInstance = true; + + // need to unwind one position in the signature to have the complete one to seach TypeSpecs + CLR_PMETADATA typeSpecSignature = sig; + typeSpecSignature--; + + CLR_RT_TypeSpec_Index genericTSIndex = {}; + if (!assembly->FindTypeSpec(typeSpecSignature, genericTSIndex)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + // copy over to parameter + genericInstance.InitializeFromIndex(genericTSIndex); - // Parse the TypeSpec signature to get the instantiated element CLR_RT_SignatureParser sp; - sp.Initialize_TypeSpec(assembly, sig); + sp.Initialize_TypeSpec(assembly, assembly->GetTypeSpec(genericInstance.TypeSpec())); CLR_RT_SignatureParser::Element element; NANOCLR_CHECK_HRESULT(sp.Advance(element)); - // element.Class and element.DataType represent the T + // if this is another generic instance, need to advance to get the type + if (dt == DATATYPE_GENERICINST) + { + NANOCLR_CHECK_HRESULT(sp.Advance(element)); + } + cls = element.Class; dt = element.DataType; goto done; + } case DATATYPE_VAR: { // type-level generic parameter in a locals signature (e.g. 'T' inside a generic type) CLR_INT8 genericParamPosition = *sig++; - // parse the locals-signature to extract that T - CLR_RT_SignatureParser parser; - parser.Initialize_MethodLocals(assembly, methodDef); - CLR_RT_SignatureParser::Element sigElement; - - // ensure we don’t walk past the available generic parameters - const int maxParams = methodDefInstance.target->genericParamCount; - if (genericParamPosition < 0 || genericParamPosition > maxParams) - { - NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); - } - - // advance into the VAR entry - parser.Advance(sigElement); - - // walk forward to the Nth generic-parameter - for (int i = 0; i < genericParamPosition; i++) - { - parser.Advance(sigElement); - } - - // element.Class and element.DataType represent the T - cls = sigElement.Class; - dt = sigElement.DataType; + assembly->FindGenericParamAtTypeSpec( + methodDefInstance.genericType->TypeSpec(), + genericParamPosition, + cls, + dt); + + //// parse the locals-signature to extract that T + // CLR_RT_SignatureParser parser; + // parser.Initialize_MethodLocals(assembly, methodDef); + // CLR_RT_SignatureParser::Element sigElement; + + //// ensure we don’t walk past the available generic parameters + // const int maxParams = methodDefInstance.target->genericParamCount; + // if (genericParamPosition < 0 || genericParamPosition > maxParams) + //{ + // NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + // } + + //// advance into the VAR entry + // parser.Advance(sigElement); + + //// walk forward to the Nth generic-parameter + // for (int i = 0; i < genericParamPosition; i++) + //{ + // parser.Advance(sigElement); + // } + + //// element.Class and element.DataType represent the T + // cls = sigElement.Class; + // dt = sigElement.DataType; goto done; } @@ -2084,7 +2170,14 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( } while (++ptr < ptrEnd); } - NANOCLR_CHECK_HRESULT(NewObject(*locals, inst)); + // if (isGenericInstance) + //{ + // NANOCLR_CHECK_HRESULT(NewGenericInstanceObject(*locals, inst, &genericInstance)); + // } + // else + { + NANOCLR_CHECK_HRESULT(NewObject(*locals, inst, &genericInstance)); + } } } else @@ -2108,7 +2201,10 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( //--// -HRESULT CLR_RT_ExecutionEngine::NewObjectFromIndex(CLR_RT_HeapBlock &reference, const CLR_RT_TypeDef_Index &cls) +HRESULT CLR_RT_ExecutionEngine::NewObjectFromIndex( + CLR_RT_HeapBlock &reference, + const CLR_RT_TypeDef_Index &cls, + const CLR_RT_TypeSpec_Instance *genericInstance) { NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); @@ -2118,12 +2214,15 @@ HRESULT CLR_RT_ExecutionEngine::NewObjectFromIndex(CLR_RT_HeapBlock &reference, if (inst.InitializeFromIndex(cls) == false) NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); - NANOCLR_SET_AND_LEAVE(NewObject(reference, inst)); + NANOCLR_SET_AND_LEAVE(NewObject(reference, inst, genericInstance)); NANOCLR_NOCLEANUP(); } -HRESULT CLR_RT_ExecutionEngine::NewObject(CLR_RT_HeapBlock &reference, const CLR_RT_TypeDef_Instance &inst) +HRESULT CLR_RT_ExecutionEngine::NewObject( + CLR_RT_HeapBlock &reference, + const CLR_RT_TypeDef_Instance &inst, + const CLR_RT_TypeSpec_Instance *genericInstance) { NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); @@ -2174,7 +2273,15 @@ HRESULT CLR_RT_ExecutionEngine::NewObject(CLR_RT_HeapBlock &reference, const CLR { int clsFields = inst.target->instanceFieldsCount; int totFields = inst.CrossReference().totalFields + CLR_RT_HeapBlock::HB_Object_Fields_Offset; - CLR_RT_HeapBlock *obj = ExtractHeapBlocksForClassOrValueTypes(dt, 0, inst, totFields); + + CLR_UINT32 flags = 0; + + if (genericInstance != nullptr && NANOCLR_INDEX_IS_VALID(*genericInstance)) + { + flags |= CLR_RT_HeapBlock::HB_GenericInstance; + } + + CLR_RT_HeapBlock *obj = ExtractHeapBlocksForClassOrValueTypes(dt, flags, inst, totFields); CHECK_ALLOCATION(obj); reference.SetObjectReference(obj); @@ -2186,11 +2293,17 @@ HRESULT CLR_RT_ExecutionEngine::NewObject(CLR_RT_HeapBlock &reference, const CLR NANOCLR_CHECK_HRESULT(obj->SetObjectCls(inst)); + if (genericInstance != nullptr && NANOCLR_INDEX_IS_VALID(*genericInstance)) + { + // If we have a generic instance, we need to set the corresponding TypeSpec + obj->SetGenericInstanceType(*genericInstance); + } + // // Initialize field types, from last to first. // - // We do the decrement BEFORE the comparison because we want to stop short of the first field, the - // object descriptor (already initialized). + // We do the decrement BEFORE the comparison because we want to stop short of the first field, + // the object descriptor (already initialized). // obj += totFields; while (--totFields > 0) @@ -2208,13 +2321,18 @@ HRESULT CLR_RT_ExecutionEngine::NewObject(CLR_RT_HeapBlock &reference, const CLR { assm = instSub.assembly; target = assm->GetFieldDef(instSub.target->firstInstanceField + clsFields); + +#if defined(NANOCLR_INSTANCE_NAMES) + const char *typeName = assm->GetString(target->type); + const char *fieldName = assm->GetString(target->name); +#endif } obj--; target--; clsFields--; - NANOCLR_CHECK_HRESULT(InitializeReference(*obj, target, assm)); + NANOCLR_CHECK_HRESULT(InitializeReference(*obj, target, assm, genericInstance)); } } @@ -2225,9 +2343,6 @@ HRESULT CLR_RT_ExecutionEngine::NewObject(CLR_RT_HeapBlock &reference, const CLR } break; - case DATATYPE_GENERICINST: - break; - default: NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -2256,19 +2371,19 @@ HRESULT CLR_RT_ExecutionEngine::NewObject(CLR_RT_HeapBlock &reference, CLR_UINT3 HRESULT CLR_RT_ExecutionEngine::NewGenericInstanceObject( CLR_RT_HeapBlock &reference, const CLR_RT_TypeDef_Instance &typeDef, - const CLR_RT_TypeSpec_Index &genericType) + const CLR_RT_TypeSpec_Index *genericType) { NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); CLR_RT_TypeSpec_Instance inst; - if (inst.InitializeFromIndex(genericType) == false) + if (inst.InitializeFromIndex(*genericType) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } - NANOCLR_SET_AND_LEAVE(NewGenericInstanceObject(reference, typeDef, inst)); + NANOCLR_SET_AND_LEAVE(NewGenericInstanceObject(reference, typeDef, &inst)); NANOCLR_NOCLEANUP(); } @@ -2276,7 +2391,7 @@ HRESULT CLR_RT_ExecutionEngine::NewGenericInstanceObject( HRESULT CLR_RT_ExecutionEngine::NewGenericInstanceObject( CLR_RT_HeapBlock &reference, const CLR_RT_TypeDef_Instance &instance, - CLR_RT_TypeSpec_Instance &genericInstance) + const CLR_RT_TypeSpec_Instance *genericInstance) { NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); @@ -2292,7 +2407,7 @@ HRESULT CLR_RT_ExecutionEngine::NewGenericInstanceObject( int clsFields = instance.target->instanceFieldsCount; int totFields = instance.CrossReference().totalFields + CLR_RT_HeapBlock::HB_Object_Fields_Offset; - giHeader = (CLR_RT_HeapBlock_GenericInstance *)ExtractHeapBlocksForGenericInstance(0, genericInstance, totFields); + giHeader = (CLR_RT_HeapBlock_GenericInstance *)ExtractHeapBlocksForGenericInstance(0, *genericInstance, totFields); CHECK_ALLOCATION(giHeader); reference.SetObjectReference(giHeader); @@ -2332,7 +2447,7 @@ HRESULT CLR_RT_ExecutionEngine::NewGenericInstanceObject( target--; clsFields--; - NANOCLR_CHECK_HRESULT(InitializeReference(*fieldCursor, target, assm)); + NANOCLR_CHECK_HRESULT(InitializeReference(*fieldCursor, target, assm, genericInstance)); } if (instance.HasFinalizer()) @@ -2378,11 +2493,18 @@ HRESULT CLR_RT_ExecutionEngine::CloneObject(CLR_RT_HeapBlock &reference, const C // Save the pointer to the object to clone, in case 'reference' and 'source' point to the same block. // CLR_RT_HeapBlock safeSource; + CLR_RT_TypeSpec_Instance genericInstance = {}; safeSource.SetObjectReference(obj); CLR_RT_ProtectFromGC gc(safeSource); - NANOCLR_CHECK_HRESULT(NewObjectFromIndex(reference, obj->ObjectCls())); + if (NANOCLR_INDEX_IS_VALID(obj->ObjectGenericType())) + { + // instanciate the generic type + genericInstance.InitializeFromIndex(obj->ObjectGenericType()); + } + + NANOCLR_CHECK_HRESULT(NewObjectFromIndex(reference, obj->ObjectCls(), &genericInstance)); NANOCLR_CHECK_HRESULT(CopyValueType(reference.Dereference(), obj)); } break; diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index d2bafe8ce5..eaea599c04 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -2463,8 +2463,11 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) } else { - NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine - .NewGenericInstanceObject(top[0], cls, *calleeInst.genericType)); + CLR_RT_TypeSpec_Instance calleeInstGenericType; + calleeInstGenericType.InitializeFromIndex(*calleeInst.genericType); + + NANOCLR_CHECK_HRESULT( + g_CLR_RT_ExecutionEngine.NewObject(top[0], cls, &calleeInstGenericType)); } // @@ -2563,7 +2566,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) FETCH_ARG_COMPRESSED_FIELDTOKEN(arg, ip); CLR_RT_FieldDef_Instance fieldInst; - if (fieldInst.ResolveToken(arg, assm) == false) + if (fieldInst.ResolveToken(arg, assm, &stack->m_call) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -2617,7 +2620,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) FETCH_ARG_COMPRESSED_FIELDTOKEN(arg, ip); CLR_RT_FieldDef_Instance fieldInst; - if (fieldInst.ResolveToken(arg, assm) == false) + if (fieldInst.ResolveToken(arg, assm, &stack->m_call) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -2661,7 +2664,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) CHECKSTACK(stack, evalPos); CLR_RT_FieldDef_Instance fieldInst; - if (fieldInst.ResolveToken(arg, assm) == false) + if (fieldInst.ResolveToken(arg, assm, &stack->m_call) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -2715,7 +2718,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) FETCH_ARG_COMPRESSED_FIELDTOKEN(arg, ip); CLR_RT_FieldDef_Instance field; - if (field.ResolveToken(arg, assm) == false) + if (field.ResolveToken(arg, assm, &stack->m_call) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -2743,7 +2746,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) FETCH_ARG_COMPRESSED_FIELDTOKEN(arg, ip); CLR_RT_FieldDef_Instance field; - if (field.ResolveToken(arg, assm) == false) + if (field.ResolveToken(arg, assm, &stack->m_call) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -2770,7 +2773,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) FETCH_ARG_COMPRESSED_FIELDTOKEN(arg, ip); CLR_RT_FieldDef_Instance field; - if (field.ResolveToken(arg, assm) == false) + if (field.ResolveToken(arg, assm, &stack->m_call) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -2870,7 +2873,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewGenericInstanceObject( nullableObject, typeInst, - destinationTypeSpec)); + &destinationTypeSpec)); CLR_RT_ProtectFromGC gc(nullableObject); @@ -3329,7 +3332,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) case TBL_FieldDef: { CLR_RT_FieldDef_Instance field; - if (field.ResolveToken(arg, assm) == false) + if (field.ResolveToken(arg, assm, &stack->m_call) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -3353,8 +3356,8 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) case TBL_GenericParam: { - CLR_RT_GenericParam_Instance param; - if (param.ResolveToken(arg, assm) == false) + CLR_RT_GenericParam_Instance genericParam; + if (genericParam.ResolveToken(arg, assm) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -3378,37 +3381,12 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) if (gpCR.typeOrMethodDef == TBL_MethodDef) { // Method generic parameter (!!T) - - CLR_RT_MethodSpec_Index msIndex; - if (!resolveAsm->FindMethodSpecFromTypeSpec( - stack->m_call.genericType->TypeSpec(), - msIndex)) - { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); - } - - CLR_RT_MethodSpec_Instance ms; - if (ms.InitializeFromIndex(msIndex) == false) - { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); - } - - int genericParamPos = param.GenericParam(); - - CLR_RT_SignatureParser parser; - CLR_RT_SignatureParser::Element element; - parser.Initialize_MethodSignature(&ms); - - for (int i = 0; i <= genericParamPos; i++) - { - NANOCLR_CHECK_HRESULT(parser.Advance(element)); - } - - evalPos[0].SetReflection(element.Class); + // already resolved + evalPos[0].SetReflection(gpCR.classTypeDef); } else { - // type generic parameter (!T) + // Type generic parameter (!T) if (stack->m_call.genericType == nullptr) { // No closed‐generic context available: fall back to returning the @@ -3426,7 +3404,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) if (!resolveAsm->FindGenericParamAtTypeSpec( callerTypeSpec->TypeSpec(), - param.target->number, + genericParam.target->number, resolvedTypeDef, dummyDataType)) { diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 8db89fb16e..4717e57bcf 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -33,7 +33,7 @@ int s_CLR_RT_fTrace_Exceptions = NANOCLR_TRACE_DEFAULT(c_CLR_RT_Trace_Info, c_CL #endif #if defined(NANOCLR_TRACE_INSTRUCTIONS) -int s_CLR_RT_fTrace_Instructions = NANOCLR_TRACE_DEFAULT(c_CLR_RT_Trace_Info, c_CLR_RT_Trace_None); +int s_CLR_RT_fTrace_Instructions = NANOCLR_TRACE_DEFAULT(c_CLR_RT_Trace_Verbose, c_CLR_RT_Trace_None); #endif #if defined(NANOCLR_GC_VERBOSE) @@ -432,11 +432,13 @@ void CLR_RT_SignatureParser::Initialize_Objects(CLR_RT_HeapBlock *lst, int count HRESULT CLR_RT_SignatureParser::Advance(Element &res) { NATIVE_PROFILE_CLR_CORE(); - // - // WARNING!!! - // - // If you change this method, change "CLR_RT_ExecutionEngine::InitializeLocals" too. - // + + /////////////////////////////////////////////////////////////////////////////// + // // + // ***** WARNING ***** // + // // + // Changes here must be ported to "CLR_RT_ExecutionEngine::InitializeLocals" // + /////////////////////////////////////////////////////////////////////////////// NANOCLR_HEADER(); @@ -539,7 +541,6 @@ HRESULT CLR_RT_SignatureParser::Advance(Element &res) case DATATYPE_CLASS: case DATATYPE_VALUETYPE: { - parse_type: CLR_UINT32 tk = CLR_TkFromStream(Signature); CLR_UINT32 index = CLR_DataFromTk(tk); @@ -603,24 +604,7 @@ HRESULT CLR_RT_SignatureParser::Advance(Element &res) { // set flag for GENERICINST IsGenericInst = true; - - // get data type - auto dt = (NanoCLRDataType)*Signature++; - - // sanity check - if (dt == DATATYPE_CLASS || dt == DATATYPE_VALUETYPE) - { - res.DataType = dt; - - // parse type - goto parse_type; - } - else - { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); - } - - break; + NANOCLR_SET_AND_LEAVE(S_OK); } case DATATYPE_VAR: @@ -696,6 +680,9 @@ 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); + // get type parser.Advance(element); @@ -981,18 +968,31 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( return false; } - if (elem.DataType == DATATYPE_CLASS || elem.DataType == DATATYPE_VALUETYPE) + if (elem.DataType == DATATYPE_GENERICINST) { - // If it's a class or value type, resolve the type - data = elem.Class.data; - assembly = g_CLR_RT_TypeSystem.m_assemblies[elem.Class.Assembly() - 1]; - target = assembly->GetTypeDef(elem.Class.Type()); - -#if defined(NANOCLR_INSTANCE_NAMES) - name = assembly->GetString(target->name); -#endif + if (FAILED(parser.Advance(elem))) + { + return false; + } + } - return true; + if (elem.DataType == DATATYPE_CLASS || elem.DataType == DATATYPE_VALUETYPE) + { + // 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; + } } // walk forward until a VAR (type‐generic) or MVAR (method‐generic) is hit @@ -1030,6 +1030,10 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( assembly = g_CLR_RT_TypeSystem.m_assemblies[realTypeDef.Assembly() - 1]; target = assembly->GetTypeDef(realTypeDef.Type()); +#if defined(NANOCLR_INSTANCE_NAMES) + name = assembly->GetString(target->name); +#endif + return true; } else @@ -1048,6 +1052,10 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( assembly = g_CLR_RT_TypeSystem.m_assemblies[gp.classTypeDef.Assembly() - 1]; target = assembly->GetTypeDef(gp.classTypeDef.Type()); +#if defined(NANOCLR_INSTANCE_NAMES) + name = assembly->GetString(target->name); +#endif + return true; } } @@ -1098,6 +1106,14 @@ bool CLR_RT_TypeDef_Instance::ResolveNullableType( return false; } + if (elem.DataType == DATATYPE_GENERICINST) + { + if (FAILED(parser.Advance(elem))) + { + return false; + } + } + if (elem.DataType != DATATYPE_VALUETYPE) { // If it's not a value type, we can't resolve it as a nullable type @@ -1252,7 +1268,10 @@ void CLR_RT_FieldDef_Instance::ClearInstance() genericType = nullptr; } -bool CLR_RT_FieldDef_Instance::ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm) +bool CLR_RT_FieldDef_Instance::ResolveToken( + CLR_UINT32 tk, + CLR_RT_Assembly *assm, + const CLR_RT_MethodDef_Instance *caller) { NATIVE_PROFILE_CLR_CORE(); @@ -1282,22 +1301,77 @@ bool CLR_RT_FieldDef_Instance::ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm case TBL_TypeSpec: { - // Field on a generic‐instantiated type. - // Use the MDP TypeSpec (which is already the closed generic), - genericType = &assm->crossReferenceFieldRef[index].genericType; + const CLR_RECORD_FIELDREF *fr = assm->GetFieldRef(index); - // Look up the actual FieldDef within that closed type - CLR_RT_FieldDef_Index resolvedField; - if (!assm->FindFieldDef(genericType, assm->GetString(fr->name), assm, fr->signature, resolvedField)) + switch (fr->Owner()) { - return false; - } + case TBL_TypeSpec: + { + // the metadata’s own (possibly open) TypeSpec… + const CLR_RT_TypeSpec_Index *mdTS = &assm->crossReferenceFieldRef[index].genericType; - // Bind to that real FieldDef - Set(assm->assemblyIndex, resolvedField.Field()); - assembly = assm; - target = assembly->GetFieldDef(Field()); - break; + // decide whether to prefer the caller’s closed-generic + const CLR_RT_TypeSpec_Index *effectiveTS = mdTS; + if (caller && caller->genericType && NANOCLR_INDEX_IS_VALID(*caller->genericType)) + { + CLR_RT_TypeSpec_Instance instCaller, instMd; + if (instCaller.InitializeFromIndex(*caller->genericType) && + instMd.InitializeFromIndex(*mdTS)) + { + CLR_RT_SignatureParser pC, pM; + CLR_RT_SignatureParser::Element eC, eM; + + pC.Initialize_TypeSpec(instCaller.assembly, instCaller.target); + pM.Initialize_TypeSpec(instMd.assembly, instMd.target); + + if (SUCCEEDED(pC.Advance(eC)) && SUCCEEDED(pM.Advance(eM)) && + eC.Class.data == eM.Class.data) + { + // same generic-definition token → use the caller’s closed TypeSpec + effectiveTS = caller->genericType; + } + } + } + + // now bind against effectiveTS + genericType = effectiveTS; + //CLR_RT_Assembly *tsAsm = g_CLR_RT_TypeSystem.m_assemblies[effectiveTS->Assembly() - 1]; + //const CLR_RECORD_TYPESPEC *tsRec = tsAsm->GetTypeSpec(effectiveTS->TypeSpec()); + + //// if (!tsAsm->FindFieldDef(tsRec, tsAsm->GetString(fr->name), tsAsm, fr->signature, + //// resolved)) + ////{ + //// return false; + //// } + CLR_RT_FieldDef_Index resolved; + + if (!assm->FindFieldDef( + genericType, + assm->GetString(fr->name), + assm, + fr->signature, + resolved)) + { + return false; + } + + data = resolved.data; + assembly = assm; + target = assembly->GetFieldDef(Field()); + return true; + } + + case TBL_TypeRef: + { + // non-generic + data = assm->crossReferenceFieldRef[index].target.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[Assembly() - 1]; + target = assembly->GetFieldDef(Field()); + genericType = nullptr; + return true; + } + } + return false; // unknown owner } default: @@ -1380,6 +1454,15 @@ bool CLR_RT_MethodDef_Instance::InitializeFromIndex( return false; } + // if this is a generic type, need to advance to the next + if (elem.DataType == DATATYPE_GENERICINST) + { + if (FAILED(parser.Advance(elem))) + { + return false; + } + } + CLR_RT_TypeDef_Index ownerTypeIdx; CLR_RT_MethodDef_Index mdRebound; @@ -1668,6 +1751,12 @@ bool CLR_RT_MethodDef_Instance::GetDeclaringType(CLR_RT_TypeDef_Instance &declTy CLR_RT_SignatureParser::Element elem; parser.Advance(elem); + // if this a generic, advance again to get the type + if (elem.DataType == DATATYPE_GENERICINST) + { + parser.Advance(elem); + } + return declType.InitializeFromIndex(elem.Class); } else @@ -4870,6 +4959,12 @@ bool CLR_RT_Assembly::FindGenericParamAtTypeSpec( return false; } + // move to type + if (FAILED(parser.Advance(element))) + { + return false; + } + // sanity check for invalid parameter position if (genericParameterPosition > parser.GenParamCount) { @@ -5172,6 +5267,15 @@ bool CLR_RT_Assembly::FindMethodDef( return false; } + // if this is a generic type, need the type + if (elem.DataType == DATATYPE_GENERICINST) + { + if (FAILED(parser.Advance(elem))) + { + return false; + } + } + CLR_UINT32 genericDefToken = elem.Class.data; CLR_RT_TypeDef_Index typeDef; @@ -6293,10 +6397,40 @@ bool CLR_RT_TypeSystem::MatchSignatureElement( return false; } - if ((resLeft.DataType == DATATYPE_VAR && resRight.DataType == DATATYPE_VAR) && - (resLeft.GenericParamPosition != resRight.GenericParamPosition)) + if (resLeft.DataType == DATATYPE_VAR && resRight.DataType == DATATYPE_VAR) { - return false; + if (resLeft.GenericParamPosition != resRight.GenericParamPosition) + { + return false; + } + else + { + if (parserLeft.IsGenericInst && parserRight.IsGenericInst) + { + // TODO: we can do better here by checking the actual type of the generic parameters + // CLR_RT_TypeDef_Index leftTypeDef; + // NanoCLRDataType leftDT; + // CLR_RT_TypeDef_Index rightTypeDef; + // NanoCLRDataType rightDT; + + // parserLeft.Assembly->FindGenericParamAtTypeSpec( + // resLeft.TypeSpec.TypeSpec(), + // resLeft.GenericParamPosition, + // leftTypeDef, + // leftDT); + + // parserRight.Assembly->FindGenericParamAtTypeSpec( + // resRight.TypeSpec.TypeSpec(), + // resRight.GenericParamPosition, + // rightTypeDef, + // rightDT); + + // if (leftTypeDef.data != rightTypeDef.data || leftDT != rightDT) + //{ + // return false; + // } + } + } } if (parserLeft.IsGenericInst != parserRight.IsGenericInst) @@ -6306,27 +6440,65 @@ bool CLR_RT_TypeSystem::MatchSignatureElement( if (parserLeft.IsGenericInst || parserRight.IsGenericInst) { - if (resLeft.GenericParamPosition == 0xFFFF && resRight.GenericParamPosition == 0xFFFF) + if (resLeft.DataType == DATATYPE_GENERICINST && resRight.DataType == DATATYPE_GENERICINST) { + // processing generic instance signature + // need to advance to get generic type and param count + if (FAILED(parserLeft.Advance(resLeft)) || FAILED(parserRight.Advance(resRight))) + { + return false; + } + // need to check if type of generic parameters match, if there are more if (parserLeft.ParamCount > 0 && parserRight.ParamCount > 0) { - if (FAILED(parserLeft.Advance(resLeft)) || FAILED(parserRight.Advance(resRight))) + if (parserLeft.ParamCount != parserRight.ParamCount) { return false; } - } - if (resLeft.DataType != resRight.DataType) - { - return false; + if (resLeft.DataType != resRight.DataType) + { + return false; + } } } - else if (resLeft.GenericParamPosition != resRight.GenericParamPosition) + else { - return false; + if (parserLeft.GenParamCount != parserRight.GenParamCount) + { + return false; + } + else if (resLeft.GenericParamPosition != resRight.GenericParamPosition) + { + return false; + } } } + + // if (parserLeft.IsGenericInst || parserRight.IsGenericInst) + //{ + // if (resLeft.GenericParamPosition == 0xFFFF && resRight.GenericParamPosition == 0xFFFF) + // { + // // need to check if type of generic parameters match, if there are more + // if (parserLeft.ParamCount > 0 && parserRight.ParamCount > 0) + // { + // if (FAILED(parserLeft.Advance(resLeft)) || FAILED(parserRight.Advance(resRight))) + // { + // return false; + // } + // } + + // if (resLeft.DataType != resRight.DataType) + // { + // return false; + // } + // } + // else if (resLeft.GenericParamPosition != resRight.GenericParamPosition) + // { + // return false; + // } + //} } return true; @@ -6379,6 +6551,12 @@ HRESULT CLR_RT_TypeSystem::BuildTypeName( // get type parser.Advance(element); + // if this is a generic type, need to advance to get type + if (element.DataType == DATATYPE_GENERICINST) + { + parser.Advance(element); + } + CLR_RT_TypeDef_Index typeDef; typeDef.data = element.Class.data; @@ -6552,6 +6730,13 @@ HRESULT CLR_RT_TypeSystem::BuildMethodName( { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } + + if (instOwner.InitializeFromMethod(inst) == false) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + NANOCLR_CHECK_HRESULT(BuildTypeName(instOwner, szBuffer, iBuffer)); } else { @@ -6560,14 +6745,10 @@ HRESULT CLR_RT_TypeSystem::BuildMethodName( { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } - } - if (instOwner.InitializeFromMethod(inst) == false) - { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + NANOCLR_CHECK_HRESULT(BuildTypeName(*genericType, szBuffer, iBuffer, 0)); } - NANOCLR_CHECK_HRESULT(BuildTypeName(instOwner, szBuffer, iBuffer)); CLR_SafeSprintf(szBuffer, iBuffer, "::%s", inst.assembly->GetString(inst.target->name)); diff --git a/src/CLR/Diagnostics/Diagnostics_stub.cpp b/src/CLR/Diagnostics/Diagnostics_stub.cpp index d543cd753d..9ae8e56760 100644 --- a/src/CLR/Diagnostics/Diagnostics_stub.cpp +++ b/src/CLR/Diagnostics/Diagnostics_stub.cpp @@ -111,8 +111,8 @@ __nfweak const CLR_UINT8 *CLR_SkipBodyOfOpcodeCompressed(const CLR_UINT8 *ip, CL } #if defined(NANOCLR_TRACE_INSTRUCTIONS) - -__nfweak void CLR_RT_Assembly::DumpToken(CLR_UINT32 tk, const CLR_RT_TypeSpec_Index *genericType) + +__nfweak void CLR_RT_Assembly::DumpToken(CLR_UINT32 tk, const CLR_RT_MethodDef_Instance &methodDefInstance) { NATIVE_PROFILE_CLR_DIAGNOSTICS(); } diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index 6b93dcda73..05d07c1611 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -1564,7 +1564,7 @@ struct CLR_RT_Assembly : public CLR_RT_HeapBlock_Node // EVENT HEAP - NO RELOCAT DECL_POSTFIX; private: - void DumpToken(CLR_UINT32 tk, const CLR_RT_TypeSpec_Index *genericType) DECL_POSTFIX; + void DumpToken(CLR_UINT32 tk, const CLR_RT_MethodDef_Instance &methodDefInstance) DECL_POSTFIX; void DumpSignature(CLR_SIG sig) DECL_POSTFIX; void DumpSignature(CLR_PMETADATA &p) DECL_POSTFIX; void DumpSignatureToken(CLR_PMETADATA &p) DECL_POSTFIX; @@ -2148,7 +2148,7 @@ struct CLR_RT_FieldDef_Instance : public CLR_RT_FieldDef_Index bool InitializeFromIndex(const CLR_RT_FieldDef_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); //--// @@ -4042,23 +4042,36 @@ struct CLR_RT_ExecutionEngine void PutInProperList(CLR_RT_Thread *th); CLR_INT32 GetNextThreadId(); - HRESULT InitializeReference(CLR_RT_HeapBlock &ref, CLR_RT_SignatureParser &parser); - HRESULT InitializeReference(CLR_RT_HeapBlock &ref, const CLR_RECORD_FIELDDEF *target, CLR_RT_Assembly *assm); + HRESULT InitializeReference( + CLR_RT_HeapBlock &ref, + CLR_RT_SignatureParser &parser, + const CLR_RT_TypeSpec_Instance *genericInstance = nullptr); + HRESULT InitializeReference( + CLR_RT_HeapBlock &ref, + const CLR_RECORD_FIELDDEF *target, + CLR_RT_Assembly *assm, + const CLR_RT_TypeSpec_Instance *genericInstance = nullptr); HRESULT InitializeLocals(CLR_RT_HeapBlock *locals, const CLR_RT_MethodDef_Instance &methodDefInstance); - HRESULT NewObjectFromIndex(CLR_RT_HeapBlock &reference, const CLR_RT_TypeDef_Index &cls); - HRESULT NewObject(CLR_RT_HeapBlock &reference, const CLR_RT_TypeDef_Instance &inst); + HRESULT NewObjectFromIndex( + CLR_RT_HeapBlock &reference, + const CLR_RT_TypeDef_Index &cls, + const CLR_RT_TypeSpec_Instance *genericInstance = nullptr); + HRESULT NewObject( + CLR_RT_HeapBlock &reference, + const CLR_RT_TypeDef_Instance &inst, + const CLR_RT_TypeSpec_Instance *genericInstance = nullptr); HRESULT NewObject(CLR_RT_HeapBlock &reference, CLR_UINT32 token, CLR_RT_Assembly *assm); HRESULT NewGenericInstanceObject( CLR_RT_HeapBlock &reference, const CLR_RT_TypeDef_Instance &typeDef, - const CLR_RT_TypeSpec_Index &genericType); + const CLR_RT_TypeSpec_Index *genericType); HRESULT NewGenericInstanceObject( CLR_RT_HeapBlock &reference, const CLR_RT_TypeDef_Instance &typeDef, - CLR_RT_TypeSpec_Instance &genericInstance); + const CLR_RT_TypeSpec_Instance *genericInstance); HRESULT CloneObject(CLR_RT_HeapBlock &reference, const CLR_RT_HeapBlock &source); HRESULT CopyValueType(CLR_RT_HeapBlock *destination, const CLR_RT_HeapBlock *source); From 4803a772df20647512b0e829691cd1d8f7140088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 7 Aug 2025 17:01:26 +0100 Subject: [PATCH 04/61] Fix locals initialization - When parsing a generic type, it wasn't consuming the complete signature. --- src/CLR/Core/Execution.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 20597bf863..9fe5deb3de 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2037,21 +2037,33 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( // copy over to parameter genericInstance.InitializeFromIndex(genericTSIndex); - CLR_RT_SignatureParser sp; - sp.Initialize_TypeSpec(assembly, assembly->GetTypeSpec(genericInstance.TypeSpec())); + CLR_RT_SignatureParser parser; + parser.Initialize_TypeSpec(assembly, assembly->GetTypeSpec(genericInstance.TypeSpec())); CLR_RT_SignatureParser::Element element; - NANOCLR_CHECK_HRESULT(sp.Advance(element)); + NANOCLR_CHECK_HRESULT(parser.Advance(element)); // if this is another generic instance, need to advance to get the type if (dt == DATATYPE_GENERICINST) { - NANOCLR_CHECK_HRESULT(sp.Advance(element)); + NANOCLR_CHECK_HRESULT(parser.Advance(element)); } cls = element.Class; dt = element.DataType; + // consume the generic parameters from the signature + for (int paramIndex = 0; paramIndex < parser.GenParamCount; paramIndex++) + { + NANOCLR_CHECK_HRESULT(parser.Advance(element)); + } + + // need to advance the signature to consume it + while (parser.Signature != sig) + { + sig++; + } + goto done; } From 5c8418334ded2f7bbca747270e71a8a5e35b6e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 7 Aug 2025 17:01:51 +0100 Subject: [PATCH 05/61] Move debug info about fields name to correct location --- src/CLR/Core/Execution.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 9fe5deb3de..a27a3422c0 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2333,17 +2333,17 @@ HRESULT CLR_RT_ExecutionEngine::NewObject( { assm = instSub.assembly; target = assm->GetFieldDef(instSub.target->firstInstanceField + clsFields); - -#if defined(NANOCLR_INSTANCE_NAMES) - const char *typeName = assm->GetString(target->type); - const char *fieldName = assm->GetString(target->name); -#endif } obj--; target--; clsFields--; +#if defined(NANOCLR_INSTANCE_NAMES) + const char *typeName = assm->GetString(target->type); + const char *fieldName = assm->GetString(target->name); +#endif + NANOCLR_CHECK_HRESULT(InitializeReference(*obj, target, assm, genericInstance)); } } From 534a98070c1b50f3378c9070760df48ff6379496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 7 Aug 2025 17:02:12 +0100 Subject: [PATCH 06/61] Remove commented code --- src/CLR/Core/Execution.cpp | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index a27a3422c0..1b90e7f7ad 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2078,31 +2078,6 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( cls, dt); - //// parse the locals-signature to extract that T - // CLR_RT_SignatureParser parser; - // parser.Initialize_MethodLocals(assembly, methodDef); - // CLR_RT_SignatureParser::Element sigElement; - - //// ensure we don’t walk past the available generic parameters - // const int maxParams = methodDefInstance.target->genericParamCount; - // if (genericParamPosition < 0 || genericParamPosition > maxParams) - //{ - // NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); - // } - - //// advance into the VAR entry - // parser.Advance(sigElement); - - //// walk forward to the Nth generic-parameter - // for (int i = 0; i < genericParamPosition; i++) - //{ - // parser.Advance(sigElement); - // } - - //// element.Class and element.DataType represent the T - // cls = sigElement.Class; - // dt = sigElement.DataType; - goto done; } From e0c3b3137a2500714ab9f1dfd57fa54bc39c4b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 7 Aug 2025 17:04:08 +0100 Subject: [PATCH 07/61] Fix FieldDef_Instance::ResolveToken - Was duplicating the parsing of the FieldRef. - Now it's pointing to the correct FieldDef. --- src/CLR/Core/TypeSystem.cpp | 92 ++++++++++++------------------------- 1 file changed, 30 insertions(+), 62 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 4717e57bcf..20f2fe4aa4 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1301,79 +1301,47 @@ bool CLR_RT_FieldDef_Instance::ResolveToken( case TBL_TypeSpec: { - const CLR_RECORD_FIELDREF *fr = assm->GetFieldRef(index); + // the metadata own (possibly open) TypeSpec... + const CLR_RT_TypeSpec_Index *mdTS = &assm->crossReferenceFieldRef[index].genericType; - switch (fr->Owner()) + // decide whether to prefer the caller’s closed-generic + const CLR_RT_TypeSpec_Index *effectiveTS = mdTS; + if (caller && caller->genericType && NANOCLR_INDEX_IS_VALID(*caller->genericType)) { - case TBL_TypeSpec: + CLR_RT_TypeSpec_Instance instCaller, instMd; + if (instCaller.InitializeFromIndex(*caller->genericType) && instMd.InitializeFromIndex(*mdTS)) { - // the metadata’s own (possibly open) TypeSpec… - const CLR_RT_TypeSpec_Index *mdTS = &assm->crossReferenceFieldRef[index].genericType; + CLR_RT_SignatureParser pC, pM; + CLR_RT_SignatureParser::Element eC, eM; - // decide whether to prefer the caller’s closed-generic - const CLR_RT_TypeSpec_Index *effectiveTS = mdTS; - if (caller && caller->genericType && NANOCLR_INDEX_IS_VALID(*caller->genericType)) - { - CLR_RT_TypeSpec_Instance instCaller, instMd; - if (instCaller.InitializeFromIndex(*caller->genericType) && - instMd.InitializeFromIndex(*mdTS)) - { - CLR_RT_SignatureParser pC, pM; - CLR_RT_SignatureParser::Element eC, eM; - - pC.Initialize_TypeSpec(instCaller.assembly, instCaller.target); - pM.Initialize_TypeSpec(instMd.assembly, instMd.target); - - if (SUCCEEDED(pC.Advance(eC)) && SUCCEEDED(pM.Advance(eM)) && - eC.Class.data == eM.Class.data) - { - // same generic-definition token → use the caller’s closed TypeSpec - effectiveTS = caller->genericType; - } - } - } + pC.Initialize_TypeSpec(instCaller.assembly, instCaller.target); + pM.Initialize_TypeSpec(instMd.assembly, instMd.target); - // now bind against effectiveTS - genericType = effectiveTS; - //CLR_RT_Assembly *tsAsm = g_CLR_RT_TypeSystem.m_assemblies[effectiveTS->Assembly() - 1]; - //const CLR_RECORD_TYPESPEC *tsRec = tsAsm->GetTypeSpec(effectiveTS->TypeSpec()); - - //// if (!tsAsm->FindFieldDef(tsRec, tsAsm->GetString(fr->name), tsAsm, fr->signature, - //// resolved)) - ////{ - //// return false; - //// } - CLR_RT_FieldDef_Index resolved; - - if (!assm->FindFieldDef( - genericType, - assm->GetString(fr->name), - assm, - fr->signature, - resolved)) + if (SUCCEEDED(pC.Advance(eC)) && SUCCEEDED(pM.Advance(eM)) && + eC.Class.data == eM.Class.data) { - return false; + // same generic-definition token → use the caller’s closed TypeSpec + effectiveTS = caller->genericType; } - - data = resolved.data; - assembly = assm; - target = assembly->GetFieldDef(Field()); - return true; } + } - case TBL_TypeRef: - { - // non-generic - data = assm->crossReferenceFieldRef[index].target.data; - assembly = g_CLR_RT_TypeSystem.m_assemblies[Assembly() - 1]; - target = assembly->GetFieldDef(Field()); - genericType = nullptr; - return true; - } + // now bind against effectiveTS + genericType = effectiveTS; + + CLR_RT_FieldDef_Index resolved; + + if (!assm->FindFieldDef(genericType, assm->GetString(fr->name), assm, fr->signature, resolved)) + { + return false; } - return false; // unknown owner - } + data = resolved.data; + assembly = assm; + target = assembly->GetFieldDef(Field()); + + break; + } default: // should not happen return false; From cff66f0a854242b925226441a31866cc82584f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 7 Aug 2025 17:04:31 +0100 Subject: [PATCH 08/61] Code style fixes --- src/CLR/Core/TypeSystem.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 20f2fe4aa4..7f12b4b9df 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -3979,11 +3979,10 @@ HRESULT CLR_RT_AppDomain::GetManagedObject(CLR_RT_HeapBlock &res) pRes = res.Dereference(); - NANOCLR_CHECK_HRESULT( - CLR_RT_ObjectToEvent_Source::CreateInstance( - this, - *pRes, - pRes[Library_corlib_native_System_AppDomain::FIELD___appDomain])); + NANOCLR_CHECK_HRESULT(CLR_RT_ObjectToEvent_Source::CreateInstance( + this, + *pRes, + pRes[Library_corlib_native_System_AppDomain::FIELD___appDomain])); pRes[Library_corlib_native_System_AppDomain::FIELD___friendlyName].SetObjectReference(m_strName); } @@ -6717,7 +6716,6 @@ HRESULT CLR_RT_TypeSystem::BuildMethodName( NANOCLR_CHECK_HRESULT(BuildTypeName(*genericType, szBuffer, iBuffer, 0)); } - CLR_SafeSprintf(szBuffer, iBuffer, "::%s", inst.assembly->GetString(inst.target->name)); NANOCLR_NOCLEANUP(); @@ -7296,11 +7294,10 @@ HRESULT CLR_RT_AttributeParser::Next(Value *&res) } // instantiate array to hold parameters values - NANOCLR_CHECK_HRESULT( - CLR_RT_HeapBlock_Array::CreateInstance( - m_lastValue.m_value, - paramCount, - g_CLR_RT_WellKnownTypes.Object)); + NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( + m_lastValue.m_value, + paramCount, + g_CLR_RT_WellKnownTypes.Object)); // get a pointer to the first element auto *currentParam = (CLR_RT_HeapBlock *)m_lastValue.m_value.DereferenceArray()->GetFirstElement(); From d4f1beb8d30b6001b022886d1b6525445e624dc7 Mon Sep 17 00:00:00 2001 From: "nfbot[bot]" Date: Thu, 7 Aug 2025 17:20:15 +0100 Subject: [PATCH 09/61] Code style fixes (#160) Automated fixes for code style. --- src/CLR/Core/Interpreter.cpp | 18 ++++++++++-------- src/CLR/Core/TypeSystem.cpp | 18 ++++++++++-------- src/CLR/Diagnostics/Diagnostics_stub.cpp | 2 +- src/CLR/Include/nanoCLR_Runtime__HeapBlock.h | 2 +- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index eaea599c04..81953c25c8 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -2396,10 +2396,11 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) // check that... // changes = -calleeInst.target->argumentsCount; - NANOCLR_CHECK_HRESULT(CLR_Checks::VerifyStackOK( - *stack, - stack->m_evalStackPos, - changes)); // Check to see if we have enough parameters. + NANOCLR_CHECK_HRESULT( + CLR_Checks::VerifyStackOK( + *stack, + stack->m_evalStackPos, + changes)); // Check to see if we have enough parameters. stack->m_evalStackPos += changes; top = stack->m_evalStackPos++; // Push back the result. @@ -2435,10 +2436,11 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) else { changes = calleeInst.target->argumentsCount; - NANOCLR_CHECK_HRESULT(CLR_Checks::VerifyStackOK( - *stack, - stack->m_evalStackPos, - -changes)); // Check to see if we have enough parameters. + NANOCLR_CHECK_HRESULT( + CLR_Checks::VerifyStackOK( + *stack, + stack->m_evalStackPos, + -changes)); // Check to see if we have enough parameters. top = stack->m_evalStackPos; // diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 7f12b4b9df..5b6a2e0256 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -3979,10 +3979,11 @@ HRESULT CLR_RT_AppDomain::GetManagedObject(CLR_RT_HeapBlock &res) pRes = res.Dereference(); - NANOCLR_CHECK_HRESULT(CLR_RT_ObjectToEvent_Source::CreateInstance( - this, - *pRes, - pRes[Library_corlib_native_System_AppDomain::FIELD___appDomain])); + NANOCLR_CHECK_HRESULT( + CLR_RT_ObjectToEvent_Source::CreateInstance( + this, + *pRes, + pRes[Library_corlib_native_System_AppDomain::FIELD___appDomain])); pRes[Library_corlib_native_System_AppDomain::FIELD___friendlyName].SetObjectReference(m_strName); } @@ -7294,10 +7295,11 @@ HRESULT CLR_RT_AttributeParser::Next(Value *&res) } // instantiate array to hold parameters values - NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( - m_lastValue.m_value, - paramCount, - g_CLR_RT_WellKnownTypes.Object)); + NANOCLR_CHECK_HRESULT( + CLR_RT_HeapBlock_Array::CreateInstance( + m_lastValue.m_value, + paramCount, + g_CLR_RT_WellKnownTypes.Object)); // get a pointer to the first element auto *currentParam = (CLR_RT_HeapBlock *)m_lastValue.m_value.DereferenceArray()->GetFirstElement(); diff --git a/src/CLR/Diagnostics/Diagnostics_stub.cpp b/src/CLR/Diagnostics/Diagnostics_stub.cpp index 9ae8e56760..2ca278ea77 100644 --- a/src/CLR/Diagnostics/Diagnostics_stub.cpp +++ b/src/CLR/Diagnostics/Diagnostics_stub.cpp @@ -111,7 +111,7 @@ __nfweak const CLR_UINT8 *CLR_SkipBodyOfOpcodeCompressed(const CLR_UINT8 *ip, CL } #if defined(NANOCLR_TRACE_INSTRUCTIONS) - + __nfweak void CLR_RT_Assembly::DumpToken(CLR_UINT32 tk, const CLR_RT_MethodDef_Instance &methodDefInstance) { NATIVE_PROFILE_CLR_DIAGNOSTICS(); diff --git a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h index 74b7165a7e..89eb2cad87 100644 --- a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h +++ b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h @@ -1199,7 +1199,7 @@ struct CLR_RT_HeapBlock else { // Invalid index - return (CLR_RT_TypeSpec_Index)0x0; + return (CLR_RT_TypeSpec_Index)0x0; } } From bb1c2e19a50bd8c95c58fb01c660a7e4459d3178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Wed, 13 Aug 2025 16:15:45 +0100 Subject: [PATCH 10/61] Fix resolving type descriptor from TypeSpec token --- src/CLR/Core/TypeSystem.cpp | 104 +++--------------------------------- 1 file changed, 8 insertions(+), 96 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 5b6a2e0256..2b8a316dbd 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -957,107 +957,19 @@ 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); + const CLR_RT_TypeSpec_Index typeSpecIdx = assm->crossReferenceTypeSpec[index].genericType; + CLR_RT_TypeSpec_Instance typeSpecInstance{}; + typeSpecInstance.InitializeFromIndex(typeSpecIdx); - CLR_RT_SignatureParser::Element elem; - if (FAILED(parser.Advance(elem))) - { - return false; - } - - if (elem.DataType == DATATYPE_GENERICINST) - { - if (FAILED(parser.Advance(elem))) - { - return false; - } - } - - if (elem.DataType == DATATYPE_CLASS || elem.DataType == DATATYPE_VALUETYPE) - { - // 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; - } - } - - // 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; - } - } - - // If it's a type‐generic slot (!T), resolve against the caller's closed generic - if (elem.DataType == DATATYPE_VAR) - { - int pos = elem.GenericParamPosition; - - // Use the *caller's* bound genericType (Stack, etc.) - if (caller == nullptr || caller->genericType == nullptr) - { - return false; - } - - auto &tsi = *caller->genericType; - CLR_UINT32 closedTsRow = tsi.TypeSpec(); - - CLR_RT_TypeDef_Index realTypeDef; - NanoCLRDataType realDataType; - - // Only call this once to map (e.g. !T→Int32) - caller->assembly - ->FindGenericParamAtTypeSpec(closedTsRow, (CLR_UINT32)pos, realTypeDef, realDataType); - - // populate this instance - data = realTypeDef.data; - assembly = g_CLR_RT_TypeSystem.m_assemblies[realTypeDef.Assembly() - 1]; - target = assembly->GetTypeDef(realTypeDef.Type()); + data = typeSpecInstance.genericTypeDef.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[typeSpecInstance.genericTypeDef.Assembly() - 1]; + target = assembly->GetTypeDef(typeSpecInstance.genericTypeDef.Type()); #if defined(NANOCLR_INSTANCE_NAMES) - name = assembly->GetString(target->name); -#endif - - return true; - } - else - { - // Use the *caller's* bound genericType (Stack, etc.) - if (caller == nullptr || caller->genericType == nullptr) - { - return false; - } - - 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()); - -#if defined(NANOCLR_INSTANCE_NAMES) - name = assembly->GetString(target->name); + name = assembly->GetString(target->name); #endif - return true; - } + return true; } default: From f3a70b7ca59aa624106d9248a8e6b3054e8d4702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Wed, 13 Aug 2025 16:44:18 +0100 Subject: [PATCH 11/61] Fix finding FieldDef for a generic instance --- src/CLR/Core/TypeSystem.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 2b8a316dbd..1cdbb5b288 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -5000,19 +5000,29 @@ bool CLR_RT_Assembly::FindFieldDef( // get type parser.Advance(element); + CLR_RT_TypeDef_Index typeDef{}; + CLR_RT_TypeDef_Instance typeDefInstance{}; + const char *typeName; + // if this is a generic type, need to advance to get type if (element.DataType == DATATYPE_GENERICINST) { parser.Advance(element); + + // OK to set the data directly + typeDef.data = element.Class.data; } + else if (element.DataType == DATATYPE_VAR) + { + // resolve the !T against the *closed* typeIndex + CLR_RT_TypeSpec_Instance typeSpecInstance; + typeSpecInstance.InitializeFromIndex(*tsIndex); - CLR_RT_TypeDef_Index typeDef; - typeDef.data = element.Class.data; + typeDef.data = typeSpecInstance.genericTypeDef.data; + } - CLR_RT_TypeDef_Instance typeDefInstance; typeDefInstance.InitializeFromIndex(typeDef); - - const char *typeName = GetString(typeDefInstance.target->name); + typeName = GetString(typeDefInstance.target->name); const CLR_RECORD_FIELDDEF *fd = GetFieldDef(0); From 677a8fa3dbe5eba460f4185d21f348c0aaca5589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Wed, 13 Aug 2025 16:59:50 +0100 Subject: [PATCH 12/61] TypeSpec instance now has a CLR_RT_TypeDef_Index - Improves usage as it's now easier to instanciate the generic type. - Adjust code accordingly. --- src/CLR/Core/CLR_RT_HeapBlock.cpp | 2 +- src/CLR/Core/TypeSystem.cpp | 17 ++++------------- src/CLR/Include/nanoCLR_Runtime.h | 2 +- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/CLR/Core/CLR_RT_HeapBlock.cpp b/src/CLR/Core/CLR_RT_HeapBlock.cpp index bca81f460b..5d1a4a4c70 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock.cpp @@ -841,7 +841,7 @@ bool CLR_RT_HeapBlock::TypeDescriptorsMatch( auto &eSpec = expectedType.m_handlerGenericType; auto &aSpec = actualType.m_handlerGenericType; - return eSpec.Assembly() == aSpec.Assembly() && eSpec.typeDefIndex == aSpec.typeDefIndex; + return eSpec.Assembly() == aSpec.Assembly() && eSpec.genericTypeDef.data == aSpec.genericTypeDef.data; } if (actualDataType <= DATATYPE_LAST_PRIMITIVE_TO_PRESERVE) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 1cdbb5b288..f44902a86c 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -686,7 +686,7 @@ bool CLR_RT_TypeSpec_Instance::InitializeFromIndex(const CLR_RT_TypeSpec_Index & // get type parser.Advance(element); - typeDefIndex = element.Class.Type(); + genericTypeDef = element.Class; return true; } @@ -2336,7 +2336,7 @@ HRESULT CLR_RT_TypeDescriptor::ExtractTypeIndexFromObject(const CLR_RT_HeapBlock if (desc.GetDataType() == DATATYPE_GENERICINST) { - res.Set(desc.m_handlerGenericType.Assembly(), desc.m_handlerGenericType.typeDefIndex); + res.Set(desc.m_handlerGenericType.Assembly(), desc.m_handlerGenericType.genericTypeDef.Type()); } else { @@ -5129,16 +5129,7 @@ bool CLR_RT_Assembly::FindMethodDef( // switch to the assembly that declared this TypeSpec CLR_RT_Assembly *declAssm = tsInstance.assembly; - CLR_INDEX typeDefIdx = tsInstance.typeDefIndex; - - // validate that it really is in-range - if (typeDefIdx >= declAssm->tablesSize[TBL_TypeDef]) - { - // doesn't seem to be, jump to TypeSpec parsing - goto try_typespec; - } - - if (declAssm->FindMethodDef(declAssm->GetTypeDef(typeDefIdx), methodName, base, sig, index)) + if (declAssm->FindMethodDef(declAssm->GetTypeDef(tsInstance.genericTypeDef.Type()), methodName, base, sig, index)) { assmIndex = declAssm->assemblyIndex; return true; @@ -6606,7 +6597,7 @@ HRESULT CLR_RT_TypeSystem::BuildMethodName( if (tsInst.InitializeFromIndex(*genericType)) { - if (tsInst.typeDefIndex == declTypeIdx.Type()) + if (tsInst.genericTypeDef.Type() == declTypeIdx.Type()) { useGeneric = true; } diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index 05d07c1611..bad5ec756b 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -2083,7 +2083,7 @@ struct CLR_RT_TypeSpec_Instance : public CLR_RT_TypeSpec_Index CLR_RT_Assembly *assembly; const CLR_RECORD_TYPESPEC *target; - CLR_INDEX typeDefIndex; + CLR_RT_TypeDef_Index genericTypeDef; //--// From 1f5201597c5a4c4577d4003ab92c6839d6314730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Wed, 13 Aug 2025 17:02:06 +0100 Subject: [PATCH 13/61] Fix DumpToken in info - Now takes a MethodDef instance to be able to decode the caller. - Also fixed the parsing of a generic instance and generics parameters in type and method. --- src/CLR/Diagnostics/Info.cpp | 98 +++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 24 deletions(-) diff --git a/src/CLR/Diagnostics/Info.cpp b/src/CLR/Diagnostics/Info.cpp index 6a703cd098..9217f35dda 100644 --- a/src/CLR/Diagnostics/Info.cpp +++ b/src/CLR/Diagnostics/Info.cpp @@ -413,7 +413,7 @@ const CLR_UINT8 *CLR_SkipBodyOfOpcodeCompressed(const CLR_UINT8 *ip, CLR_OPCODE #if defined(NANOCLR_TRACE_INSTRUCTIONS) -void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *genericType) +void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_MethodDef_Instance &methodDefInstance) { NATIVE_PROFILE_CLR_DIAGNOSTICS(); CLR_UINT32 index = CLR_DataFromTk(token); @@ -447,12 +447,12 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g const auto &xref = crossReferenceFieldRef[index]; // If the caller passed in a closed‐generic TypeSpec, use that … - if (genericType != nullptr && genericType->data != CLR_EmptyToken) + if (methodDefInstance.genericType != nullptr && methodDefInstance.genericType->data != CLR_EmptyToken) { // Build the closed‐generic owner name char rgType[256], *sz = rgType; size_t cb = sizeof(rgType); - g_CLR_RT_TypeSystem.BuildTypeName(*genericType, sz, cb, 0); + g_CLR_RT_TypeSystem.BuildTypeName(*methodDefInstance.genericType, sz, cb, 0); // Append the field name CLR_SafeSprintf(sz, cb, "::%s", GetString(fr->name)); @@ -481,9 +481,9 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g // use that, so ResizeArray prints as SimpleList::ResizeArray. // 2) Otherwise, fall back to xref.genericType (the raw MethodRef own owner). const CLR_RT_TypeSpec_Index *ownerTypeSpec; - if (genericType != nullptr && NANOCLR_INDEX_IS_VALID(*genericType)) + if (methodDefInstance.genericType != nullptr && NANOCLR_INDEX_IS_VALID(*methodDefInstance.genericType)) { - ownerTypeSpec = genericType; + ownerTypeSpec = methodDefInstance.genericType; } else { @@ -525,9 +525,9 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g // CLR_UINT32 ownerAsm = assemblyIndex; - if (genericType != nullptr && NANOCLR_INDEX_IS_VALID(*genericType)) + if (methodDefInstance.genericType != nullptr && NANOCLR_INDEX_IS_VALID(*methodDefInstance.genericType)) { - ownerAsm = genericType->Assembly(); + ownerAsm = methodDefInstance.genericType->Assembly(); } CLR_RT_TypeSpec_Index tsIdx; @@ -559,17 +559,31 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g break; } - if (elem.DataType == DATATYPE_VAR || elem.DataType == DATATYPE_MVAR) + if (elem.DataType == DATATYPE_GENERICINST) { - int gpIndex = elem.GenericParamPosition; + if (FAILED(parser.Advance(elem))) + { + // unable to bind; dump raw RID + CLR_Debug::Printf("[TYPESPEC:%08x]", token); + break; + } + } + + if (elem.DataType == DATATYPE_VAR) + { + int gpPosition = elem.GenericParamPosition; // if the caller's genericType is non‐null, ask the CLR to map !n→actual argument: - if (genericType != nullptr && NANOCLR_INDEX_IS_VALID(*genericType)) + if (methodDefInstance.genericType != nullptr && NANOCLR_INDEX_IS_VALID(*methodDefInstance.genericType)) { CLR_RT_TypeDef_Index tdArg{}; NanoCLRDataType dtArg; - bool ok = g_CLR_RT_TypeSystem.m_assemblies[genericType->Assembly() - 1] - ->FindGenericParamAtTypeSpec(genericType->TypeSpec(), gpIndex, tdArg, dtArg); + bool ok = g_CLR_RT_TypeSystem.m_assemblies[methodDefInstance.genericType->Assembly() - 1] + ->FindGenericParamAtTypeSpec( + methodDefInstance.genericType->TypeSpec(), + gpPosition, + tdArg, + dtArg); if (ok) { char bufArg[256]{}; @@ -585,15 +599,47 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g } } - // Couldn't resolve or caller was not generic: print "!n" or "!!n" literally - if (elem.DataType == DATATYPE_VAR) - { - CLR_Debug::Printf("!%d", gpIndex); - } - else + // Couldn't resolve or caller was not generic: print "!n" literally + CLR_Debug::Printf("!%d", gpPosition); + + break; + } + else if (elem.DataType == DATATYPE_MVAR) + { + int gpPosition = elem.GenericParamPosition; + + // if the caller's genericType is non‐null, ask the CLR to map !n→actual argument: + if (methodDefInstance.genericType != nullptr && NANOCLR_INDEX_IS_VALID(*methodDefInstance.genericType)) { - CLR_Debug::Printf("!!%d", gpIndex); + CLR_RT_GenericParam_Index gpIndex; + + bool ok = g_CLR_RT_TypeSystem.m_assemblies[methodDefInstance.genericType->Assembly() - 1] + ->FindGenericParamAtMethodDef(methodDefInstance, gpPosition, gpIndex); + if (ok) + { + CLR_RT_GenericParam_CrossReference gp = + g_CLR_RT_TypeSystem.m_assemblies[methodDefInstance.genericType->Assembly() - 1] + ->crossReferenceGenericParam[gpIndex.GenericParam()]; + + char bufArg[256]{}; + char *pArg = bufArg; + size_t cbArg = sizeof(bufArg); + + g_CLR_RT_TypeSystem.BuildTypeName( + gp.classTypeDef, + pArg, + cbArg, + CLR_RT_TypeSystem::TYPENAME_FLAGS_FULL, + elem.Levels); + + CLR_Debug::Printf("%s", bufArg); + + break; + } } + // Couldn't resolve or caller was not generic: print "!!n" literally + CLR_Debug::Printf("!!%d", gpPosition); + break; } else if (elem.DataType == DATATYPE_SZARRAY) @@ -611,13 +657,17 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g { int gpIndex = elem.GenericParamPosition; - if (genericType != nullptr && NANOCLR_INDEX_IS_VALID(*genericType)) + if (methodDefInstance.genericType != nullptr && + NANOCLR_INDEX_IS_VALID(*methodDefInstance.genericType)) { CLR_RT_TypeDef_Index tdArg{}; NanoCLRDataType dtArg; - bool genericParamFound = - tsInst.assembly->FindGenericParamAtTypeSpec(genericType->TypeSpec(), gpIndex, tdArg, dtArg); + bool genericParamFound = tsInst.assembly->FindGenericParamAtTypeSpec( + methodDefInstance.genericType->TypeSpec(), + gpIndex, + tdArg, + dtArg); if (genericParamFound) { // print "I4[]" or the bound argument plus [] @@ -887,12 +937,12 @@ void CLR_RT_Assembly::DumpOpcodeDirect( else { // In the unlikely case ResolveToken fails, fall back to raw DumpToken: - DumpToken(token, call.genericType); + DumpToken(token, call); } } else { - DumpToken(token, call.genericType); + DumpToken(token, call); } } else From 65dc497809a7d428b4ca09a06165a933ba19a22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Wed, 13 Aug 2025 17:05:41 +0100 Subject: [PATCH 14/61] Revert wrong trace config --- src/CLR/Core/TypeSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index f44902a86c..8f870031dc 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -33,7 +33,7 @@ int s_CLR_RT_fTrace_Exceptions = NANOCLR_TRACE_DEFAULT(c_CLR_RT_Trace_Info, c_CL #endif #if defined(NANOCLR_TRACE_INSTRUCTIONS) -int s_CLR_RT_fTrace_Instructions = NANOCLR_TRACE_DEFAULT(c_CLR_RT_Trace_Verbose, c_CLR_RT_Trace_None); +int s_CLR_RT_fTrace_Instructions = NANOCLR_TRACE_DEFAULT(c_CLR_RT_Trace_Info, c_CLR_RT_Trace_None); #endif #if defined(NANOCLR_GC_VERBOSE) From 903e3db300df1dcfc07e88dad9c75a91c990480b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 18 Aug 2025 12:58:28 +0100 Subject: [PATCH 15/61] Fix locals initialization for generic types - Signature is now advanced properly following generic type processing. - Add new signature parser to consume local vars. --- src/CLR/Core/Execution.cpp | 20 +++++++++++++++----- src/CLR/Core/TypeSystem.cpp | 15 +++++++++++++++ src/CLR/Include/nanoCLR_Runtime.h | 2 ++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 1b90e7f7ad..98f6ec4283 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2052,14 +2052,24 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( cls = element.Class; dt = element.DataType; - // consume the generic parameters from the signature - for (int paramIndex = 0; paramIndex < parser.GenParamCount; paramIndex++) + // done, now consume the remaining of the local var signature + CLR_RT_SignatureParser varParser; + varParser.Initialize_LocalVar(assembly, typeSpecSignature); + + CLR_RT_SignatureParser::Element varElement; + // consume GENERICINST + varParser.Advance(varElement); + // consume class|valuetype + varParser.Advance(varElement); + + // consume parameters + for (int paramIndex = 0; paramIndex < varParser.GenParamCount; paramIndex++) { - NANOCLR_CHECK_HRESULT(parser.Advance(element)); + NANOCLR_CHECK_HRESULT(varParser.Advance(varElement)); } - // need to advance the signature to consume it - while (parser.Signature != sig) + // advance locals signature + while (sig < varParser.Signature) { sig++; } diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 8f870031dc..20d258af4f 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -412,6 +412,21 @@ void CLR_RT_SignatureParser::Initialize_MethodLocals(CLR_RT_Assembly *assm, cons IsGenericInst = false; } +void CLR_RT_SignatureParser::Initialize_LocalVar(CLR_RT_Assembly *assm, const CLR_PMETADATA sig) +{ + NATIVE_PROFILE_CLR_CORE(); + + Assembly = assm; + Signature = sig; + + Type = CLR_RT_SignatureParser::c_Locals; + Flags = 0; + ParamCount = 1; + + GenParamCount = 0; + IsGenericInst = false; +} + //--// void CLR_RT_SignatureParser::Initialize_Objects(CLR_RT_HeapBlock *lst, int count, bool fTypes) diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index bad5ec756b..dc4e8bef70 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -1164,6 +1164,7 @@ struct CLR_RT_SignatureParser static const int c_Object = 5; static const int c_GenericParamType = 6; static const int c_MethodSpec = 7; + static const int c_LocalVar = 8; struct Element { @@ -1206,6 +1207,7 @@ struct CLR_RT_SignatureParser void Initialize_Interfaces(CLR_RT_Assembly *assm, const CLR_RECORD_TYPEDEF *td); void Initialize_MethodLocals(CLR_RT_Assembly *assm, const CLR_RECORD_METHODDEF *md); + void Initialize_LocalVar(CLR_RT_Assembly *assm, const CLR_PMETADATA sig); bool Initialize_GenericParamTypeSignature(CLR_RT_Assembly *assm, const CLR_RECORD_GENERICPARAM *gp); void Initialize_FieldDef(CLR_RT_Assembly *assm, const CLR_RECORD_FIELDDEF *fd); From cfab319f4063858ee049e092f450232cce514c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 18 Aug 2025 12:59:20 +0100 Subject: [PATCH 16/61] Fix initialization of TypeSpec from index - Now correctly advances parser on generic instance. --- src/CLR/Core/TypeSystem.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 20d258af4f..0df8ae8595 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -698,10 +698,13 @@ bool CLR_RT_TypeSpec_Instance::InitializeFromIndex(const CLR_RT_TypeSpec_Index & // if this is a generic, advance another one parser.Advance(element); - // get type - parser.Advance(element); + if (element.DataType == DATATYPE_GENERICINST) + { + // this is a generic instance, so we need to advance one more time + parser.Advance(element); - genericTypeDef = element.Class; + genericTypeDef = element.Class; + } return true; } From 024d9766c9c4d1827dff18be0069b9a7756f78b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 18 Aug 2025 13:00:33 +0100 Subject: [PATCH 17/61] Fix token resolution for TypeDef - Now can handle generic type specs and properly parse generic parameters. --- src/CLR/Core/TypeSystem.cpp | 114 +++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 0df8ae8595..2182404e25 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -979,9 +979,117 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( CLR_RT_TypeSpec_Instance typeSpecInstance{}; typeSpecInstance.InitializeFromIndex(typeSpecIdx); - data = typeSpecInstance.genericTypeDef.data; - assembly = g_CLR_RT_TypeSystem.m_assemblies[typeSpecInstance.genericTypeDef.Assembly() - 1]; - target = assembly->GetTypeDef(typeSpecInstance.genericTypeDef.Type()); + if (NANOCLR_INDEX_IS_VALID(typeSpecInstance.genericTypeDef)) + { + // this is a generic type definition + data = typeSpecInstance.genericTypeDef.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[typeSpecInstance.genericTypeDef.Assembly() - 1]; + target = assembly->GetTypeDef(typeSpecInstance.genericTypeDef.Type()); + } + else + { + // this a generic parameter + const CLR_RECORD_TYPESPEC *ts = assm->GetTypeSpec(index); + CLR_RT_SignatureParser parser; + parser.Initialize_TypeSpec(assm, ts); + + CLR_RT_SignatureParser::Element elem; + if (FAILED(parser.Advance(elem))) + { + return false; + } + + if (elem.Levels > 0) + { + // this is an array + data = elem.Class.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[elem.Class.Assembly() - 1]; + target = assembly->GetTypeDef(elem.Class.Type()); + } + else + { + if (elem.DataType == DATATYPE_GENERICINST) + { + if (FAILED(parser.Advance(elem))) + { + return false; + } + + if (elem.DataType == DATATYPE_CLASS || elem.DataType == DATATYPE_VALUETYPE) + { + // 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; + } + } + + // 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; + } + } + } + + // If it's a type‐generic slot (!T), resolve against the caller's closed generic + if (elem.DataType == DATATYPE_VAR) + { + int pos = elem.GenericParamPosition; + + // Use the *caller's* bound genericType (Stack, etc.) + if (caller == nullptr || caller->genericType == nullptr) + { + return false; + } + + auto &tsi = *caller->genericType; + CLR_UINT32 closedTsRow = tsi.TypeSpec(); + + CLR_RT_TypeDef_Index realTypeDef; + NanoCLRDataType realDataType; + + // Only call this once to map (e.g. !T→Int32) + caller->assembly + ->FindGenericParamAtTypeSpec(closedTsRow, (CLR_UINT32)pos, realTypeDef, realDataType); + + // populate this instance + data = realTypeDef.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[realTypeDef.Assembly() - 1]; + target = assembly->GetTypeDef(realTypeDef.Type()); + } + + else if (elem.DataType == DATATYPE_MVAR) + { + // Use the caller bound genericType (Stack, etc.) + if (caller == nullptr || caller->genericType == nullptr) + { + return false; + } + + 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()); + } + } + } #if defined(NANOCLR_INSTANCE_NAMES) name = assembly->GetString(target->name); From 4c9f1dd8c065dc1379e906c79b7b416830fed35a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 18 Aug 2025 13:01:21 +0100 Subject: [PATCH 18/61] Fix field token resolution - Remove unnecessary code and checks for generic types. --- src/CLR/Core/TypeSystem.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 2182404e25..1b3f30b413 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1349,16 +1349,10 @@ bool CLR_RT_FieldDef_Instance::ResolveToken( CLR_RT_TypeSpec_Instance instCaller, instMd; if (instCaller.InitializeFromIndex(*caller->genericType) && instMd.InitializeFromIndex(*mdTS)) { - CLR_RT_SignatureParser pC, pM; - CLR_RT_SignatureParser::Element eC, eM; - - pC.Initialize_TypeSpec(instCaller.assembly, instCaller.target); - pM.Initialize_TypeSpec(instMd.assembly, instMd.target); - - if (SUCCEEDED(pC.Advance(eC)) && SUCCEEDED(pM.Advance(eM)) && - eC.Class.data == eM.Class.data) + // check if generic definition token is the same... + if (instCaller.genericTypeDef.data == instMd.genericTypeDef.data) { - // same generic-definition token → use the caller’s closed TypeSpec + // it is, therefore use the caller closed TypeSpec effectiveTS = caller->genericType; } } From e93e8bb722bab3ad438f807e94a84885df2da216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 18 Aug 2025 13:02:19 +0100 Subject: [PATCH 19/61] Fix finding FieldDef - Now uses typespec assembly instead of assuming same assembly. --- src/CLR/Core/TypeSystem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 1b3f30b413..7b1ced76fe 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -5112,8 +5112,11 @@ bool CLR_RT_Assembly::FindFieldDef( { NATIVE_PROFILE_CLR_CORE(); + // find assembly of TypeSpec + CLR_RT_Assembly *assm = g_CLR_RT_TypeSystem.m_assemblies[tsIndex->Assembly() - 1]; + CLR_RT_SignatureParser parser; - parser.Initialize_TypeSpec(base, base->GetTypeSpec(tsIndex->TypeSpec())); + parser.Initialize_TypeSpec(assm, assm->GetTypeSpec(tsIndex->TypeSpec())); CLR_RT_SignatureParser::Element element; From a008b142cacf0d1c9c31546976e00a7af5590fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 18 Aug 2025 13:02:45 +0100 Subject: [PATCH 20/61] Remove unecessary code from MethodDef finder --- src/CLR/Core/TypeSystem.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 7b1ced76fe..ae240e840a 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -5249,17 +5249,6 @@ bool CLR_RT_Assembly::FindMethodDef( return false; } - // switch to the assembly that declared this TypeSpec - CLR_RT_Assembly *declAssm = tsInstance.assembly; - - if (declAssm->FindMethodDef(declAssm->GetTypeDef(tsInstance.genericTypeDef.Type()), methodName, base, sig, index)) - { - assmIndex = declAssm->assemblyIndex; - return true; - } - -try_typespec: - // parse the TypeSpec signature to get the *definition* token of the generic type: CLR_RT_SignatureParser parser{}; parser.Initialize_TypeSpec(this, ts); From bfdb13e398329b3722333a2c96f5ac36ac41bc34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Wed, 20 Aug 2025 13:18:34 +0100 Subject: [PATCH 21/61] Fix unboxing operation - Check was wrong. Per ECMA-335 if src is not boxed or value type, exception has to be InvalidCastException. --- src/CLR/Core/CLR_RT_HeapBlock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CLR/Core/CLR_RT_HeapBlock.cpp b/src/CLR/Core/CLR_RT_HeapBlock.cpp index 5d1a4a4c70..e99bd444a8 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock.cpp @@ -1088,7 +1088,7 @@ HRESULT CLR_RT_HeapBlock::PerformUnboxing(const CLR_RT_TypeDef_Instance &cls) // Validates that src keeps something boxed and the boxed value is VALUE type. if (src->IsBoxed() == false || src->DataType() != DATATYPE_VALUETYPE) { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_CAST); } // Validates the type of data kept by object corresponds to type in cls. From 4c6ad002511b1d6953767461bd8965f1ade46a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Wed, 20 Aug 2025 13:29:19 +0100 Subject: [PATCH 22/61] Fix reflection for TypeSpec - Rename Reflection struct element to typeSpec for clarity. - Update code accordingly. - Rework SetReflection from TypeSpec (fix parameters and implementation). - Add new refelction type for TypeSpec. --- src/CLR/Core/CLR_RT_HeapBlock.cpp | 49 ++------------ src/CLR/Core/CLR_RT_HeapBlock_Array.cpp | 2 +- src/CLR/Core/Interpreter.cpp | 2 +- src/CLR/Core/TypeSystem.cpp | 67 ++++++++++++++++++-- src/CLR/Include/nanoCLR_Runtime.h | 2 +- src/CLR/Include/nanoCLR_Runtime__HeapBlock.h | 4 +- src/CLR/Include/nanoCLR_Types.h | 1 + 7 files changed, 74 insertions(+), 53 deletions(-) diff --git a/src/CLR/Core/CLR_RT_HeapBlock.cpp b/src/CLR/Core/CLR_RT_HeapBlock.cpp index e99bd444a8..4dfe7cb53b 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock.cpp @@ -232,54 +232,15 @@ HRESULT CLR_RT_HeapBlock::SetReflection(const CLR_RT_Assembly_Index &assm) NANOCLR_NOCLEANUP_NOLABEL(); } -HRESULT CLR_RT_HeapBlock::SetReflection(const CLR_RT_TypeSpec_Instance &tsInst, const CLR_RT_TypeSpec_Index *caller) +HRESULT CLR_RT_HeapBlock::SetReflection(const CLR_RT_TypeSpec_Index &typeSpec) { NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); m_id.raw = CLR_RT_HEAPBLOCK_RAW_ID(DATATYPE_REFLECTION, 0, 1); - m_data.reflection.kind = REFLECTION_TYPE; - - // start parsing the signature - CLR_RT_SignatureParser parser; - parser.Initialize_TypeSpec(tsInst.assembly, tsInst.target); - - // read first element - CLR_RT_SignatureParser::Element elem; - if (FAILED(parser.Advance(elem))) - { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); - } - - if (elem.DataType == DATATYPE_VAR || elem.DataType == DATATYPE_MVAR) - { - int gpIndex = elem.GenericParamPosition; - - // if the caller's genericType is non‐null, ask the CLR to map !n→actual argument: - if (caller != nullptr && NANOCLR_INDEX_IS_VALID(*caller)) - { - CLR_RT_TypeDef_Index tdArg{}; - NanoCLRDataType dtArg; - - bool ok = g_CLR_RT_TypeSystem.m_assemblies[caller->Assembly() - 1] - ->FindGenericParamAtTypeSpec(caller->TypeSpec(), gpIndex, tdArg, dtArg); - if (ok) - { - m_data.reflection.data.type = tdArg; - m_data.reflection.levels = elem.Levels; - } - } - else - { - // TODO - _ASSERTE(false); - } - } - else - { - m_data.reflection.data.type = elem.Class; - m_data.reflection.levels = elem.Levels; - } + m_data.reflection.kind = REFLECTION_TYPESPEC; + m_data.reflection.levels = 0; + m_data.reflection.data.typeSpec = typeSpec; NANOCLR_NOCLEANUP(); } @@ -354,7 +315,7 @@ HRESULT CLR_RT_HeapBlock::SetGenericInstanceType(const CLR_RT_TypeSpec_Index &ge NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); - m_data.reflection.data.genericType = genericType; + m_data.reflection.data.typeSpec = genericType; NANOCLR_NOCLEANUP(); } diff --git a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp index 7939644212..cff9b96fb7 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp @@ -104,7 +104,7 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( } else if (def.ResolveToken(tk, assm)) { - NANOCLR_CHECK_HRESULT(ref.SetReflection(def, caller->genericType)); + NANOCLR_CHECK_HRESULT(ref.SetReflection((CLR_RT_TypeSpec_Index)def)); } else { diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index 81953c25c8..264d4faeef 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -3313,7 +3313,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } - evalPos[0].SetReflection(tsInst, stack->m_call.genericType); + evalPos[0].SetReflection((CLR_RT_TypeSpec_Index)tsInst.data); } break; diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index ae240e840a..acb0cf5c4e 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -737,6 +737,21 @@ bool CLR_RT_TypeSpec_Instance::ResolveToken(CLR_UINT32 token, CLR_RT_Assembly *a assembly = assm; target = assm->GetTypeSpec(index); + CLR_RT_SignatureParser parser; + parser.Initialize_TypeSpec(assembly, assembly->GetTypeSpec(index)); + + CLR_RT_SignatureParser::Element element; + + // if this is a generic, advance another one + parser.Advance(element); + + if (element.DataType == DATATYPE_GENERICINST) + { + // this is a generic instance, so we need to advance one more time + parser.Advance(element); + + genericTypeDef = element.Class; + } return true; } @@ -775,6 +790,29 @@ bool CLR_RT_TypeDef_Instance::InitializeFromReflection(const CLR_RT_ReflectionDe ptr = &cls; } break; + + case REFLECTION_TYPESPEC: + assembly = g_CLR_RT_TypeSystem.m_assemblies[reflex.data.typeSpec.Assembly() - 1]; + + const CLR_RECORD_TYPESPEC *ts = assembly->GetTypeSpec(reflex.data.typeSpec.TypeSpec()); + + CLR_RT_SignatureParser parser; + parser.Initialize_TypeSpec(assembly, ts); + + CLR_RT_SignatureParser::Element element; + if (FAILED(parser.Advance(element))) + { + return false; + } + + // if this is a generic type, need to advance to get type + if (element.DataType == DATATYPE_GENERICINST) + { + parser.Advance(element); + } + + ptr = &element.Class; + break; } return ptr ? InitializeFromIndex(*ptr) : false; @@ -1751,13 +1789,28 @@ bool CLR_RT_MethodDef_Instance::GetDeclaringType(CLR_RT_TypeDef_Instance &declTy CLR_RT_SignatureParser::Element elem; parser.Advance(elem); - // if this a generic, advance again to get the type if (elem.DataType == DATATYPE_GENERICINST) { + // generic type, advance again to get the type parser.Advance(elem); + + return declType.InitializeFromIndex(elem.Class); } + else if (elem.DataType == DATATYPE_VAR) + { + // generic type, advance to get the type + int pos = elem.GenericParamPosition; + // Use the *caller's* bound genericType (Stack, etc.) + CLR_RT_TypeDef_Index td; + NanoCLRDataType dt; + if (tsAsm == nullptr || + tsAsm->FindGenericParamAtTypeSpec(genericType->TypeSpec(), (CLR_UINT32)pos, td, dt) == false) + { + return false; + } - return declType.InitializeFromIndex(elem.Class); + return declType.InitializeFromIndex(td); + } } else { @@ -2046,7 +2099,7 @@ HRESULT CLR_RT_TypeDescriptor::InitializeFromGenericType(const CLR_RT_TypeSpec_I m_flags = CLR_RT_DataTypeLookup::c_ManagedType | CLR_RT_DataTypeLookup::c_GenericInstance; m_reflex.kind = REFLECTION_GENERICTYPE; - m_reflex.data.genericType = m_handlerGenericType; + m_reflex.data.typeSpec = m_handlerGenericType; } m_handlerCls.ClearInstance(); @@ -2280,6 +2333,12 @@ HRESULT CLR_RT_TypeDescriptor::InitializeFromObject(const CLR_RT_HeapBlock &ref) case REFLECTION_FIELD: cls = &g_CLR_RT_WellKnownTypes.FieldInfo; break; + case REFLECTION_GENERICTYPE: + cls = &g_CLR_RT_WellKnownTypes.Type; + break; + case REFLECTION_TYPESPEC: + genericType = &((CLR_RT_HeapBlock *)obj)->ReflectionData().data.typeSpec; + break; } break; @@ -2456,7 +2515,7 @@ HRESULT CLR_RT_TypeDescriptor::ExtractTypeIndexFromObject(const CLR_RT_HeapBlock if (desc.GetDataType() == DATATYPE_GENERICINST) { - res.Set(desc.m_handlerGenericType.Assembly(), desc.m_handlerGenericType.genericTypeDef.Type()); + res.data = desc.m_handlerGenericType.data; } else { diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index dc4e8bef70..3215069a14 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -843,7 +843,7 @@ struct CLR_RT_ReflectionDef_Index CLR_RT_TypeDef_Index type; CLR_RT_MethodDef_Index method; CLR_RT_FieldDef_Index field; - CLR_RT_TypeSpec_Index genericType; + CLR_RT_TypeSpec_Index typeSpec; CLR_UINT32 raw; } data; diff --git a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h index 89eb2cad87..7fa15ad3d5 100644 --- a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h +++ b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h @@ -1194,7 +1194,7 @@ struct CLR_RT_HeapBlock { if ((m_id.type.flags & CLR_RT_HeapBlock::HB_GenericInstance) == CLR_RT_HeapBlock::HB_GenericInstance) { - return m_data.reflection.data.genericType; + return m_data.reflection.data.typeSpec; } else { @@ -1355,7 +1355,7 @@ struct CLR_RT_HeapBlock HRESULT SetReflection(const CLR_RT_ReflectionDef_Index &reflex); HRESULT SetReflection(const CLR_RT_Assembly_Index &assm); - HRESULT SetReflection(const CLR_RT_TypeSpec_Instance &tsInst, const CLR_RT_TypeSpec_Index *caller); + HRESULT SetReflection(const CLR_RT_TypeSpec_Index &typeSpec); HRESULT SetReflection(const CLR_RT_TypeDef_Index &cls); HRESULT SetReflection(const CLR_RT_FieldDef_Index &fd); HRESULT SetReflection(const CLR_RT_MethodDef_Index &md); diff --git a/src/CLR/Include/nanoCLR_Types.h b/src/CLR/Include/nanoCLR_Types.h index c9607d3457..666106a2cc 100644 --- a/src/CLR/Include/nanoCLR_Types.h +++ b/src/CLR/Include/nanoCLR_Types.h @@ -530,6 +530,7 @@ enum CLR_ReflectionType REFLECTION_METHOD = 0x05, REFLECTION_FIELD = 0x06, REFLECTION_GENERICTYPE = 0x07, + REFLECTION_TYPESPEC = 0x08, }; //////////////////////////////////////////////////////////////////////////////////////////////////// From 4701c189031f37da483740de59ccf567f5ded381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 11:42:26 +0100 Subject: [PATCH 23/61] Add new Initialize_TypeSpec to initialize from TypeSpec instance - Replace callers where applicable. --- src/CLR/Core/Execution.cpp | 2 +- src/CLR/Core/TypeSystem.cpp | 27 ++++++++++++++++++++------- src/CLR/Diagnostics/Info.cpp | 6 +++--- src/CLR/Include/nanoCLR_Runtime.h | 1 + 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 98f6ec4283..c56b08a433 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2038,7 +2038,7 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( genericInstance.InitializeFromIndex(genericTSIndex); CLR_RT_SignatureParser parser; - parser.Initialize_TypeSpec(assembly, assembly->GetTypeSpec(genericInstance.TypeSpec())); + parser.Initialize_TypeSpec(genericInstance); CLR_RT_SignatureParser::Element element; NANOCLR_CHECK_HRESULT(parser.Advance(element)); diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index acb0cf5c4e..20ba3c8f46 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -216,6 +216,19 @@ void CLR_RT_SignatureParser::Initialize_TypeSpec(CLR_RT_Assembly *assm, CLR_PMET IsGenericInst = false; } +void CLR_RT_SignatureParser::Initialize_TypeSpec(CLR_RT_TypeSpec_Instance tsInstance) +{ + NATIVE_PROFILE_CLR_CORE(); + + Assembly = tsInstance.assembly; + Signature = Assembly->GetSignature(tsInstance.target->signature); + + Type = CLR_RT_SignatureParser::c_TypeSpec; + Flags = 0; + ParamCount = 1; + GenParamCount = 0; + IsGenericInst = false; +} //--// void CLR_RT_SignatureParser::Initialize_Interfaces(CLR_RT_Assembly *assm, const CLR_RECORD_TYPEDEF *td) @@ -1585,7 +1598,7 @@ bool CLR_RT_MethodDef_Instance::ResolveToken( if (callerInst.InitializeFromIndex(*callerGeneric)) { CLR_RT_SignatureParser parserCaller; - parserCaller.Initialize_TypeSpec(callerInst.assembly, callerInst.target); + parserCaller.Initialize_TypeSpec(callerInst); CLR_RT_SignatureParser::Element elemCaller; @@ -1599,7 +1612,7 @@ bool CLR_RT_MethodDef_Instance::ResolveToken( if (ownerInst.InitializeFromIndex(*methodOwnerTS)) { CLR_RT_SignatureParser parserOwner; - parserOwner.Initialize_TypeSpec(ownerInst.assembly, ownerInst.target); + parserOwner.Initialize_TypeSpec(ownerInst); CLR_RT_SignatureParser::Element elemOwner; @@ -5301,7 +5314,7 @@ bool CLR_RT_Assembly::FindMethodDef( return false; } - CLR_RT_TypeSpec_Instance tsInstance; + CLR_RT_TypeSpec_Instance tsInstance{}; if (!tsInstance.InitializeFromIndex(tsIndex)) { index.Clear(); @@ -6587,16 +6600,16 @@ HRESULT CLR_RT_TypeSystem::BuildTypeName( NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); - CLR_RT_TypeSpec_Instance instance; + CLR_RT_TypeSpec_Instance typeSpecInstance; bool closeGenericSignature = false; - if (instance.InitializeFromIndex(typeIndex) == false) + if (typeSpecInstance.InitializeFromIndex(typeIndex) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } CLR_RT_SignatureParser parser; - parser.Initialize_TypeSpec(instance.assembly, instance.assembly->GetTypeSpec(typeIndex.TypeSpec())); + parser.Initialize_TypeSpec(typeSpecInstance); CLR_RT_SignatureParser::Element element; @@ -6633,7 +6646,7 @@ HRESULT CLR_RT_TypeSystem::BuildTypeName( NanoCLRDataType realDt; // this will bind !T→System.Int32, etc. - instance.assembly->FindGenericParamAtTypeSpec( + typeSpecInstance.assembly->FindGenericParamAtTypeSpec( typeIndex.TypeSpec(), // closed instantiation row element.GenericParamPosition, // the !N slot realTd, diff --git a/src/CLR/Diagnostics/Info.cpp b/src/CLR/Diagnostics/Info.cpp index 9217f35dda..ee18bb70e1 100644 --- a/src/CLR/Diagnostics/Info.cpp +++ b/src/CLR/Diagnostics/Info.cpp @@ -530,7 +530,7 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_MethodDef_Instanc ownerAsm = methodDefInstance.genericType->Assembly(); } - CLR_RT_TypeSpec_Index tsIdx; + CLR_RT_TypeSpec_Index tsIdx{}; tsIdx.Set(assemblyIndex, index); // bind to get the signature blob @@ -543,8 +543,8 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_MethodDef_Instanc } // start parsing the signature - CLR_RT_SignatureParser parser; - parser.Initialize_TypeSpec(tsInst.assembly, tsInst.target); + CLR_RT_SignatureParser parser{}; + parser.Initialize_TypeSpec(tsInst); // read first element CLR_RT_SignatureParser::Element elem; diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index 3215069a14..e3d77e6608 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -1204,6 +1204,7 @@ struct CLR_RT_SignatureParser void Initialize_TypeSpec(CLR_RT_Assembly *assm, CLR_PMETADATA ts); void Initialize_TypeSpec(CLR_RT_Assembly *assm, const CLR_RECORD_TYPESPEC *ts); + void Initialize_TypeSpec(CLR_RT_TypeSpec_Instance tsInstance); void Initialize_Interfaces(CLR_RT_Assembly *assm, const CLR_RECORD_TYPEDEF *td); void Initialize_MethodLocals(CLR_RT_Assembly *assm, const CLR_RECORD_METHODDEF *md); From 39944b72b259c5344c16b50e1a732706a1f1511a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 11:43:15 +0100 Subject: [PATCH 24/61] Add IsAGenericInstance to Heapblock - Update callers where appropriate. --- src/CLR/Core/Execution.cpp | 2 +- src/CLR/Include/nanoCLR_Runtime__HeapBlock.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index c56b08a433..078bffa2b9 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2495,7 +2495,7 @@ HRESULT CLR_RT_ExecutionEngine::CloneObject(CLR_RT_HeapBlock &reference, const C safeSource.SetObjectReference(obj); CLR_RT_ProtectFromGC gc(safeSource); - if (NANOCLR_INDEX_IS_VALID(obj->ObjectGenericType())) + if (obj->IsAGenericInstance()) { // instanciate the generic type genericInstance.InitializeFromIndex(obj->ObjectGenericType()); diff --git a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h index 7fa15ad3d5..1d143f4f0a 100644 --- a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h +++ b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h @@ -1084,6 +1084,11 @@ struct CLR_RT_HeapBlock return false; } + bool IsAGenericInstance() const + { + return ((DataFlags() & CLR_RT_HeapBlock::HB_GenericInstance) == CLR_RT_HeapBlock::HB_GenericInstance); + } + bool SameHeader(const CLR_RT_HeapBlock &right) const { return this->m_data.numeric.u8 == right.m_data.numeric.u8; From 5babab335a4ea2ab0734ecee1619a2692b0a5176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 11:44:20 +0100 Subject: [PATCH 25/61] Fix TypeDescriptor from generic type - Now uses kind as REFLECTION_TYPESPEC. - Doesn't flag it as generic instance. --- src/CLR/Core/TypeSystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 20ba3c8f46..e33632c698 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -2109,9 +2109,9 @@ HRESULT CLR_RT_TypeDescriptor::InitializeFromGenericType(const CLR_RT_TypeSpec_I } else { - m_flags = CLR_RT_DataTypeLookup::c_ManagedType | CLR_RT_DataTypeLookup::c_GenericInstance; + m_flags = CLR_RT_DataTypeLookup::c_ManagedType; - m_reflex.kind = REFLECTION_GENERICTYPE; + m_reflex.kind = REFLECTION_TYPESPEC; m_reflex.data.typeSpec = m_handlerGenericType; } From 92f1eb1df6cfd981e841038859f4b4f88aaff910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 11:46:12 +0100 Subject: [PATCH 26/61] Fix TypeDescriptor initialization from object - TypeSpec now also sets the class to use as type for reflection. - Doesn't initialize from generic type anymore (wrong init causing "double" initialization). --- src/CLR/Core/TypeSystem.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index e33632c698..49dc03e1b6 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -2350,6 +2350,7 @@ HRESULT CLR_RT_TypeDescriptor::InitializeFromObject(const CLR_RT_HeapBlock &ref) cls = &g_CLR_RT_WellKnownTypes.Type; break; case REFLECTION_TYPESPEC: + cls = &g_CLR_RT_WellKnownTypes.Type; genericType = &((CLR_RT_HeapBlock *)obj)->ReflectionData().data.typeSpec; break; } @@ -2395,11 +2396,6 @@ HRESULT CLR_RT_TypeDescriptor::InitializeFromObject(const CLR_RT_HeapBlock &ref) m_reflex = *reflex; } - if (genericType) - { - NANOCLR_CHECK_HRESULT(InitializeFromGenericType(*genericType)); - } - if (dt == DATATYPE_SZARRAY) { ConvertToArray(); From beb14da2d8eddd68edbd7fccbf78932f3e8ebf6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 11:47:18 +0100 Subject: [PATCH 27/61] Fix extracting type index in TypeDescriptor - Now uses generic TypeDef data. --- src/CLR/Core/TypeSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 49dc03e1b6..abd90deb14 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -2524,7 +2524,7 @@ HRESULT CLR_RT_TypeDescriptor::ExtractTypeIndexFromObject(const CLR_RT_HeapBlock if (desc.GetDataType() == DATATYPE_GENERICINST) { - res.data = desc.m_handlerGenericType.data; + res.data = desc.m_handlerGenericType.genericTypeDef.data; } else { From 036f260a0b93ad7c64c4ff1f35a106100a60aea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 11:48:45 +0100 Subject: [PATCH 28/61] ObjectGenericType in heap block now returns reflection data - Removed check. Callers should use IsAGenericInstance before calling, if needed. --- src/CLR/Include/nanoCLR_Runtime__HeapBlock.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h index 1d143f4f0a..dc926e9f43 100644 --- a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h +++ b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h @@ -1197,15 +1197,7 @@ struct CLR_RT_HeapBlock const CLR_RT_TypeSpec_Index &ObjectGenericType() const { - if ((m_id.type.flags & CLR_RT_HeapBlock::HB_GenericInstance) == CLR_RT_HeapBlock::HB_GenericInstance) - { - return m_data.reflection.data.typeSpec; - } - else - { - // Invalid index - return (CLR_RT_TypeSpec_Index)0x0; - } + return m_data.reflection.data.typeSpec; } HRESULT SetGenericInstanceType(const CLR_RT_TypeSpec_Index &genericType); From 0a7527970117c6f0d5a071c919ee1a114fbc9a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 11:51:23 +0100 Subject: [PATCH 29/61] Update declaration of mscorlib --- src/CLR/CorLib/corlib_native.cpp | 41 +++++++++++++++++++++++++++++++- src/CLR/CorLib/corlib_native.h | 36 ++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/CLR/CorLib/corlib_native.cpp b/src/CLR/CorLib/corlib_native.cpp index f05e5fd438..845166f9ce 100644 --- a/src/CLR/CorLib/corlib_native.cpp +++ b/src/CLR/CorLib/corlib_native.cpp @@ -56,6 +56,7 @@ static const CLR_RT_MethodHandler method_lookup[] = Library_corlib_native_System_Reflection_FieldInfo::GetCustomAttributesNative___SZARRAY_OBJECT__BOOLEAN, nullptr, Library_corlib_native_System_Type::get_DeclaringType___SystemType, + Library_corlib_native_System_Type::GetGenericTypeDefinition___SystemType, nullptr, nullptr, nullptr, @@ -69,6 +70,7 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, Library_corlib_native_System_Type::IsInstanceOfType___BOOLEAN__OBJECT, nullptr, + Library_corlib_native_System_Type::GetGenericArguments___SZARRAY_SystemType, Library_corlib_native_System_Type::InvokeMember___OBJECT__STRING__SystemReflectionBindingFlags__SystemReflectionBinder__OBJECT__SZARRAY_OBJECT, Library_corlib_native_System_Type::GetConstructor___SystemReflectionConstructorInfo__SZARRAY_SystemType, Library_corlib_native_System_Type::GetConstructors___SZARRAY_SystemReflectionConstructorInfo, @@ -86,6 +88,8 @@ static const CLR_RT_MethodHandler method_lookup[] = Library_corlib_native_System_Type::get_IsEnum___BOOLEAN, Library_corlib_native_System_Type::get_IsSerializable___BOOLEAN, Library_corlib_native_System_Type::get_IsArray___BOOLEAN, + Library_corlib_native_System_Type::get_IsGenericType___BOOLEAN, + Library_corlib_native_System_Type::get_IsGenericTypeDefinition___BOOLEAN, nullptr, nullptr, Library_corlib_native_System_Type::GetTypeInternal___STATIC__SystemType__STRING__STRING__BOOLEAN__SZARRAY_I4, @@ -253,6 +257,7 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + nullptr, Library_corlib_native_System_Array::TrySzIndexOf___STATIC__BOOLEAN__SystemArray__I4__I4__OBJECT__BYREF_I4, nullptr, nullptr, @@ -267,6 +272,10 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + nullptr, + nullptr, + nullptr, + nullptr, Library_corlib_native_System_BitConverter::get_IsLittleEndian___STATIC__BOOLEAN, Library_corlib_native_System_BitConverter::DoubleToInt64Bits___STATIC__I8__R8, Library_corlib_native_System_BitConverter::GetBytes___STATIC__SZARRAY_U1__BOOLEAN, @@ -522,6 +531,7 @@ static const CLR_RT_MethodHandler method_lookup[] = Library_corlib_native_System_Reflection_Assembly::LoadInternal___STATIC__SystemReflectionAssembly__STRING__BOOLEAN__I4__I4__I4__I4, Library_corlib_native_System_Reflection_Assembly::Load___STATIC__SystemReflectionAssembly__SZARRAY_U1, nullptr, + nullptr, Library_corlib_native_System_Enum::HasFlag___BOOLEAN__SystemEnum, nullptr, nullptr, @@ -623,6 +633,18 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, Library_corlib_native_System_Number::FormatNative___STATIC__STRING__OBJECT__BOOLEAN__STRING__STRING__STRING__STRING__SZARRAY_I4, nullptr, nullptr, @@ -643,6 +665,15 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, Library_corlib_native_System_Reflection_ConstructorInfo::GetCustomAttributes___SZARRAY_OBJECT__BOOLEAN, Library_corlib_native_System_Reflection_ConstructorInfo::Invoke___OBJECT__SZARRAY_OBJECT, nullptr, @@ -689,10 +720,12 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + nullptr, Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::InitializeArray___STATIC__VOID__SystemArray__SystemRuntimeFieldHandle, Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::GetObjectValue___STATIC__OBJECT__OBJECT, Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::RunClassConstructor___STATIC__VOID__SystemRuntimeTypeHandle, Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers::get_OffsetToStringData___STATIC__I4, + nullptr, Library_corlib_native_System_Runtime_Remoting_RemotingServices::IsTransparentProxy___STATIC__BOOLEAN__OBJECT, nullptr, nullptr, @@ -732,6 +765,12 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + Library_corlib_native_System_Span_1::CopyTo___VOID__SystemSpan_1, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, nullptr, nullptr, nullptr, @@ -1505,7 +1544,7 @@ const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_mscorlib = #if (NANOCLR_REFLECTION == TRUE) - 0x4E06901B, + 0x6BB74C3A, #elif (NANOCLR_REFLECTION == FALSE) diff --git a/src/CLR/CorLib/corlib_native.h b/src/CLR/CorLib/corlib_native.h index 0024bd5eaf..4eee68f0c3 100644 --- a/src/CLR/CorLib/corlib_native.h +++ b/src/CLR/CorLib/corlib_native.h @@ -91,8 +91,10 @@ struct Library_corlib_native_System_Reflection_FieldInfo struct Library_corlib_native_System_Type { NANOCLR_NATIVE_DECLARE(get_DeclaringType___SystemType); + NANOCLR_NATIVE_DECLARE(GetGenericTypeDefinition___SystemType); NANOCLR_NATIVE_DECLARE(GetMethod___SystemReflectionMethodInfo__STRING__SystemReflectionBindingFlags); NANOCLR_NATIVE_DECLARE(IsInstanceOfType___BOOLEAN__OBJECT); + NANOCLR_NATIVE_DECLARE(GetGenericArguments___SZARRAY_SystemType); NANOCLR_NATIVE_DECLARE( InvokeMember___OBJECT__STRING__SystemReflectionBindingFlags__SystemReflectionBinder__OBJECT__SZARRAY_OBJECT); NANOCLR_NATIVE_DECLARE(GetConstructor___SystemReflectionConstructorInfo__SZARRAY_SystemType); @@ -108,6 +110,8 @@ struct Library_corlib_native_System_Type NANOCLR_NATIVE_DECLARE(get_IsEnum___BOOLEAN); NANOCLR_NATIVE_DECLARE(get_IsSerializable___BOOLEAN); NANOCLR_NATIVE_DECLARE(get_IsArray___BOOLEAN); + NANOCLR_NATIVE_DECLARE(get_IsGenericType___BOOLEAN); + NANOCLR_NATIVE_DECLARE(get_IsGenericTypeDefinition___BOOLEAN); NANOCLR_NATIVE_DECLARE(GetTypeInternal___STATIC__SystemType__STRING__STRING__BOOLEAN__SZARRAY_I4); NANOCLR_NATIVE_DECLARE(GetTypeFromHandle___STATIC__SystemType__SystemRuntimeTypeHandle); @@ -719,6 +723,19 @@ struct Library_corlib_native_System_Random static HRESULT GetRandom(CLR_RT_StackFrame &stack, CLR_RT_Random *&rand, bool create = false); }; +#if (NANOCLR_REFLECTION == TRUE) + +struct Library_corlib_native_System_ReadOnlySpan_1 +{ + static const int FIELD___array = 1; + static const int FIELD___start = 2; + static const int FIELD___length = 3; + + //--// +}; + +#endif // NANOCLR_REFLECTION + struct Library_corlib_native_System_Reflection_AssemblyName { static const int FIELD___assembly = 1; @@ -865,6 +882,23 @@ struct Library_corlib_native_System_Single //--// }; +#if (NANOCLR_REFLECTION == TRUE) + +struct Library_corlib_native_System_Span_1 +{ + static const int FIELD___array = 1; + static const int FIELD___start = 2; + static const int FIELD___length = 3; + + NANOCLR_NATIVE_DECLARE(CopyTo___VOID__SystemSpan_1); + + //--// +}; + +#endif // NANOCLR_REFLECTION + +#if (NANOCLR_REFLECTION != TRUE) + struct Library_corlib_native_System_SpanByte { static const int FIELD___array = 1; @@ -874,6 +908,8 @@ struct Library_corlib_native_System_SpanByte //--// }; +#endif // NANOCLR_REFLECTION + struct Library_corlib_native_System_Threading_AutoResetEvent { NANOCLR_NATIVE_DECLARE(_ctor___VOID__BOOLEAN); From a7e957c1c246c0a7a2f0d68fd838a1a8e5610b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 11:52:06 +0100 Subject: [PATCH 30/61] Add implementation for new methods in Type class --- src/CLR/CorLib/corlib_native_System_Type.cpp | 191 +++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/src/CLR/CorLib/corlib_native_System_Type.cpp b/src/CLR/CorLib/corlib_native_System_Type.cpp index 2263f6fe02..5d00318654 100644 --- a/src/CLR/CorLib/corlib_native_System_Type.cpp +++ b/src/CLR/CorLib/corlib_native_System_Type.cpp @@ -32,6 +32,48 @@ HRESULT Library_corlib_native_System_Type::get_DeclaringType___SystemType(CLR_RT NANOCLR_NOCLEANUP(); } +HRESULT Library_corlib_native_System_Type::GetGenericTypeDefinition___SystemType(CLR_RT_StackFrame &stack) +{ + NATIVE_PROFILE_CLR_CORE(); + NANOCLR_HEADER(); + + CLR_RT_TypeDescriptor desc{}; + CLR_RT_TypeSpec_Instance genericInstance = {}; + + CLR_RT_HeapBlock &top = stack.PushValueAndClear(); + + // build a TypeDescriptor from "this" + CLR_RT_HeapBlock *hbType = stack.This(); + + NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(top, g_CLR_RT_WellKnownTypes.TypeStatic)); + + if (hbType->ReflectionDataConst().kind == CLR_ReflectionType::REFLECTION_TYPESPEC) + { + // instanciate the generic type + genericInstance.InitializeFromIndex(hbType->ObjectGenericType()); + + CLR_RT_SignatureParser parser; + parser.Initialize_TypeSpec(genericInstance); + + CLR_RT_SignatureParser::Element element; + + // consume GENERICINST + parser.Advance(element); + + // consume class | value type + parser.Advance(element); + + top.Dereference()->SetReflection(element.Class); + } + else + { + NANOCLR_CHECK_HRESULT(desc.InitializeFromReflection(hbType->ReflectionDataConst())); + top.Dereference()->SetReflection(desc.m_handlerCls); + } + + NANOCLR_NOCLEANUP(); +} + HRESULT Library_corlib_native_System_Type::GetMethod___SystemReflectionMethodInfo__STRING__SystemReflectionBindingFlags( CLR_RT_StackFrame &stack) { @@ -66,6 +108,67 @@ HRESULT Library_corlib_native_System_Type::IsInstanceOfType___BOOLEAN__OBJECT(CL NANOCLR_NOCLEANUP(); } +HRESULT Library_corlib_native_System_Type::GetGenericArguments___SZARRAY_SystemType(CLR_RT_StackFrame &stack) +{ + NATIVE_PROFILE_CLR_CORE(); + NANOCLR_HEADER(); + + int count; + + CLR_RT_SignatureParser parser{}; + CLR_RT_SignatureParser::Element elem; + CLR_RT_TypeSpec_Instance genericInstance; + CLR_RT_HeapBlock *hbType; + CLR_RT_HeapBlock *pElems; + + CLR_RT_HeapBlock &top = stack.PushValueAndClear(); + + // build a TypeDescriptor from "this" + hbType = stack.This(); + + // sanity check for type spec instance + if (hbType->ReflectionDataConst().kind != CLR_ReflectionType::REFLECTION_TYPESPEC) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_OPERATION); + } + + // instanciate the generic type + if (genericInstance.InitializeFromIndex(hbType->ObjectGenericType())) + { + // parse the type spec to get the generic arguments + parser.Initialize_TypeSpec(genericInstance); + + // consume GENERICINST + NANOCLR_CHECK_HRESULT(parser.Advance(elem)); + + // consume class | value type + NANOCLR_CHECK_HRESULT(parser.Advance(elem)); + + // get the number of generic parameters + count = parser.GenParamCount; + + // allocate an array to hold the generic arguments + NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, count, g_CLR_RT_WellKnownTypes.TypeStatic)); + + pElems = (CLR_RT_HeapBlock *)top.DereferenceArray()->GetFirstElement(); + + // fill the array with Type objects for each generic argument + for (int i = 0; i < count; i++) + { + NANOCLR_CHECK_HRESULT(parser.Advance(elem)); + + CLR_RT_HeapBlock &slot = pElems[i]; + NANOCLR_CHECK_HRESULT( + g_CLR_RT_ExecutionEngine.NewObjectFromIndex(slot, g_CLR_RT_WellKnownTypes.TypeStatic)); + + CLR_RT_HeapBlock *hbObj = slot.Dereference(); + hbObj->SetReflection(elem.Class); + } + } + + NANOCLR_NOCLEANUP(); +} + HRESULT Library_corlib_native_System_Type:: InvokeMember___OBJECT__STRING__SystemReflectionBindingFlags__SystemReflectionBinder__OBJECT__SZARRAY_OBJECT( CLR_RT_StackFrame &stack) @@ -260,6 +363,94 @@ HRESULT Library_corlib_native_System_Type::get_IsArray___BOOLEAN(CLR_RT_StackFra NANOCLR_NOCLEANUP(); } +HRESULT Library_corlib_native_System_Type::get_IsGenericType___BOOLEAN(CLR_RT_StackFrame &stack) +{ + NATIVE_PROFILE_CLR_CORE(); + NANOCLR_HEADER(); + + bool isGenericType; + CLR_RT_TypeDescriptor desc{}; + + CLR_RT_HeapBlock *hbType = stack.This(); + + // turn the boxed System.Type ("this") into a TypeDescriptor + NANOCLR_CHECK_HRESULT(desc.InitializeFromReflection(hbType->ReflectionDataConst())); + + // simple check: a generic type has generic parameters + isGenericType = (desc.m_handlerCls.target->genericParamCount > 0); + + stack.SetResult_Boolean(isGenericType); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_corlib_native_System_Type::get_IsGenericTypeDefinition___BOOLEAN(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + bool isTypeDefinition = false; + CLR_RT_TypeDescriptor desc{}; + CLR_RT_TypeSpec_Instance genericInstance = {}; + + CLR_RT_HeapBlock *hbType = stack.This(); + + if (hbType->ReflectionDataConst().kind == CLR_ReflectionType::REFLECTION_TYPESPEC) + { + // instanciate the generic type + genericInstance.InitializeFromIndex(hbType->ObjectGenericType()); + + CLR_RT_SignatureParser parser; + parser.Initialize_TypeSpec(genericInstance); + + CLR_RT_SignatureParser::Element element; + + // consume GENERICINST + parser.Advance(element); + + // consume class | value type + parser.Advance(element); + + // check if it has generic parameters + if (parser.GenParamCount == 0) + { + isTypeDefinition = false; + } + else + { + // keep reading the generic parameters + for (int i = 0; i < parser.GenParamCount; i++) + { + if (SUCCEEDED(parser.Advance(element))) + { + if (element.DataType == DATATYPE_VAR || element.DataType == DATATYPE_MVAR) + { + // if we find a VAR or MVAR, then this is a generic type definition + isTypeDefinition = true; + break; + } + else + { + // anything else, this is not a generic type definition + isTypeDefinition = false; + break; + } + } + } + } + } + else + { + // turn the boxed System.Type ("this") into a TypeDescriptor + NANOCLR_CHECK_HRESULT(desc.InitializeFromReflection(hbType->ReflectionDataConst())); + + isTypeDefinition = (desc.m_handlerCls.target->genericParamCount > 0); + } + + stack.SetResult_Boolean(isTypeDefinition); + + NANOCLR_NOCLEANUP(); +} + HRESULT Library_corlib_native_System_Type::GetTypeInternal___STATIC__SystemType__STRING__STRING__BOOLEAN__SZARRAY_I4( CLR_RT_StackFrame &stack) { From 10c46d860100d1dcb73a4af8285ce9bea5e9bdac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 12:31:45 +0100 Subject: [PATCH 31/61] Fix get_IsArray to deal with TypeSpecs --- src/CLR/CorLib/corlib_native_System_Type.cpp | 25 ++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/CLR/CorLib/corlib_native_System_Type.cpp b/src/CLR/CorLib/corlib_native_System_Type.cpp index 5d00318654..14a6a5d1a7 100644 --- a/src/CLR/CorLib/corlib_native_System_Type.cpp +++ b/src/CLR/CorLib/corlib_native_System_Type.cpp @@ -354,11 +354,32 @@ HRESULT Library_corlib_native_System_Type::get_IsArray___BOOLEAN(CLR_RT_StackFra NANOCLR_HEADER(); CLR_RT_TypeDef_Instance td; + CLR_RT_TypeSpec_Instance genericInstance = {}; + CLR_RT_HeapBlock *hbType = stack.This(); - NANOCLR_CHECK_HRESULT(Library_corlib_native_System_RuntimeType::GetTypeDescriptor(*hbType, td)); + if (hbType->ReflectionDataConst().kind == CLR_ReflectionType::REFLECTION_TYPESPEC) + { + // instanciate the generic type + genericInstance.InitializeFromIndex(hbType->ObjectGenericType()); + + CLR_RT_SignatureParser parser{}; + parser.Initialize_TypeSpec(genericInstance); - stack.SetResult_Boolean(td.data == g_CLR_RT_WellKnownTypes.Array.data); + CLR_RT_SignatureParser::Element element; + + // only need to consume the 1st element which has the level data we're looking for + parser.Advance(element); + + // check if element has levels + stack.SetResult_Boolean(element.Levels > 0); + } + else + { + NANOCLR_CHECK_HRESULT(Library_corlib_native_System_RuntimeType::GetTypeDescriptor(*hbType, td)); + + stack.SetResult_Boolean(td.data == g_CLR_RT_WellKnownTypes.Array.data); + } NANOCLR_NOCLEANUP(); } From 7151fd66592a8abdfdcb3219b3fe4bf6116850c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 16:44:44 +0100 Subject: [PATCH 32/61] Fix compiler errors --- src/CLR/Core/CLR_RT_HeapBlock.cpp | 4 ++-- src/CLR/Core/Execution.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CLR/Core/CLR_RT_HeapBlock.cpp b/src/CLR/Core/CLR_RT_HeapBlock.cpp index 4dfe7cb53b..98b3572682 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock.cpp @@ -242,7 +242,7 @@ HRESULT CLR_RT_HeapBlock::SetReflection(const CLR_RT_TypeSpec_Index &typeSpec) m_data.reflection.levels = 0; m_data.reflection.data.typeSpec = typeSpec; - NANOCLR_NOCLEANUP(); + NANOCLR_NOCLEANUP_NOLABEL(); } HRESULT CLR_RT_HeapBlock::SetReflection(const CLR_RT_TypeDef_Index &cls) @@ -317,7 +317,7 @@ HRESULT CLR_RT_HeapBlock::SetGenericInstanceType(const CLR_RT_TypeSpec_Index &ge m_data.reflection.data.typeSpec = genericType; - NANOCLR_NOCLEANUP(); + NANOCLR_NOCLEANUP_NOLABEL(); } //--// diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 078bffa2b9..5b78bceb4b 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -1567,7 +1567,7 @@ CLR_RT_HeapBlock *CLR_RT_ExecutionEngine::ExtractHeapBlocksForGenericInstance( flags = flags | CLR_RT_HeapBlock::HB_InitializeToZero; CLR_RT_HeapBlock *hb = ExtractHeapBlocks(m_heap, DATATYPE_GENERICINST, flags, length); - _ASSERT(true); + _ASSERTE(true); if (hb) { @@ -1863,7 +1863,7 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference( } else if (dt == DATATYPE_MVAR) { - _ASSERT(true); + _ASSERTE(true); goto process_datatype; } From b3d6213b2dfbe9f83feb47c00bd1ebb3af3e1ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 17:13:25 +0100 Subject: [PATCH 33/61] Fix build error - Evaluate to remove parameter. *** TODO *** --- src/CLR/Core/Execution.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 5b78bceb4b..7749580499 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -1559,6 +1559,8 @@ CLR_RT_HeapBlock *CLR_RT_ExecutionEngine::ExtractHeapBlocksForGenericInstance( { NATIVE_PROFILE_CLR_CORE(); + (void)genericType; + if (length > CLR_RT_HeapBlock::HB_MaxSize) { return nullptr; From 51889c087fb8bb6bdb4aa66c7b1e061fb42bfd30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 17:22:10 +0100 Subject: [PATCH 34/61] Remove unused var --- src/CLR/Core/Execution.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 7749580499..690fe93cc6 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -1972,7 +1972,6 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( CLR_PMETADATA sig = assembly->GetSignature(methodDef->locals); CLR_UINT32 count = methodDef->localsCount; bool fZeroed = false; - bool isGenericInstance = false; CLR_RT_TypeSpec_Instance genericInstance = {}; while (count) @@ -2023,9 +2022,6 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( case DATATYPE_GENERICINST: { - // set flag - isGenericInstance = true; - // need to unwind one position in the signature to have the complete one to seach TypeSpecs CLR_PMETADATA typeSpecSignature = sig; typeSpecSignature--; From b136778db8e4a757e0169695a1d0e438cf6736e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 21:14:43 +0100 Subject: [PATCH 35/61] Fix dangling pointer --- src/CLR/Core/Execution.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 690fe93cc6..5dd90ad2c7 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -1884,7 +1884,6 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference( // copy over to parameter CLR_RT_TypeSpec_Instance genericTSInstance; genericTSInstance.InitializeFromIndex(genericTSIndex); - genericInstance = &genericTSInstance; CLR_RT_SignatureParser sp; sp.Initialize_TypeSpec(parser.Assembly, parser.Assembly->GetTypeSpec(genericTSInstance.TypeSpec())); From 2996ca478ccd878fd7b03394933069a2422cf251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 21:34:52 +0100 Subject: [PATCH 36/61] Fix pointer --- src/CLR/Core/Interpreter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index 264d4faeef..1916bd7af6 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -3313,7 +3313,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } - evalPos[0].SetReflection((CLR_RT_TypeSpec_Index)tsInst.data); + evalPos[0].SetReflection((const CLR_RT_TypeSpec_Index &)tsInst.data); } break; From dba8b3da6e0dc0176e8573c982a9b9b6f5382328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 21:44:05 +0100 Subject: [PATCH 37/61] Fix compiler errors --- src/CLR/Core/TypeSystem.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index abd90deb14..26802ce32a 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1830,6 +1830,8 @@ bool CLR_RT_MethodDef_Instance::GetDeclaringType(CLR_RT_TypeDef_Instance &declTy // Normal (non‐generic or open‐generic) return declType.InitializeFromMethod(*this); } + + return false; } ////////////////////////////// @@ -2282,7 +2284,6 @@ HRESULT CLR_RT_TypeDescriptor::InitializeFromObject(const CLR_RT_HeapBlock &ref) { const CLR_RT_TypeDef_Index *cls = nullptr; const CLR_RT_ReflectionDef_Index *reflex = nullptr; - const CLR_RT_TypeSpec_Index *genericType = nullptr; switch (dt) { @@ -2351,7 +2352,6 @@ HRESULT CLR_RT_TypeDescriptor::InitializeFromObject(const CLR_RT_HeapBlock &ref) break; case REFLECTION_TYPESPEC: cls = &g_CLR_RT_WellKnownTypes.Type; - genericType = &((CLR_RT_HeapBlock *)obj)->ReflectionData().data.typeSpec; break; } @@ -2376,10 +2376,6 @@ HRESULT CLR_RT_TypeDescriptor::InitializeFromObject(const CLR_RT_HeapBlock &ref) } break; - case DATATYPE_GENERICINST: - genericType = &obj->ObjectGenericType(); - break; - //--// default: From 5e5d3cf22327767daeaf874061fcb3ee1c024c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 23:10:43 +0100 Subject: [PATCH 38/61] Add Span_1 to project and class stub --- src/CLR/CorLib/CorLib.vcxproj | 3 ++- src/CLR/CorLib/CorLib.vcxproj.filters | 3 +++ src/CLR/CorLib/corlib_native_System_Span_1.cpp | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/CLR/CorLib/corlib_native_System_Span_1.cpp diff --git a/src/CLR/CorLib/CorLib.vcxproj b/src/CLR/CorLib/CorLib.vcxproj index 1917a4a142..e7245e5e83 100644 --- a/src/CLR/CorLib/CorLib.vcxproj +++ b/src/CLR/CorLib/CorLib.vcxproj @@ -60,6 +60,7 @@ + @@ -208,4 +209,4 @@ - + \ No newline at end of file diff --git a/src/CLR/CorLib/CorLib.vcxproj.filters b/src/CLR/CorLib/CorLib.vcxproj.filters index 94b8a4c749..e545e99d37 100644 --- a/src/CLR/CorLib/CorLib.vcxproj.filters +++ b/src/CLR/CorLib/CorLib.vcxproj.filters @@ -173,5 +173,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/src/CLR/CorLib/corlib_native_System_Span_1.cpp b/src/CLR/CorLib/corlib_native_System_Span_1.cpp new file mode 100644 index 0000000000..064ef4a2c6 --- /dev/null +++ b/src/CLR/CorLib/corlib_native_System_Span_1.cpp @@ -0,0 +1,16 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) Microsoft Corporation. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +#include "CorLib.h" + +HRESULT Library_corlib_native_System_Span_1::CopyTo___VOID__SystemSpan_1(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + NANOCLR_SET_AND_LEAVE(stack.NotImplementedStub()); + + NANOCLR_NOCLEANUP(); +} From fd820e73ca52d767f08d964fa1ac0c6c8f362160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 23:11:34 +0100 Subject: [PATCH 39/61] Replaced SpanByte with Span_1 --- ..._spi_native_System_Device_Spi_SpiDevice.cpp | 14 +++++++------- ...o_hashing_System_IO_Hashing_Crc32_stubs.cpp | 8 ++++---- ..._i2c_native_System_Device_I2c_I2cDevice.cpp | 16 ++++++++-------- ..._i2c_native_System_Device_I2c_I2cDevice.cpp | 16 ++++++++-------- ..._sys_io_hashing_System_IO_Hashing_Crc32.cpp | 8 ++++---- ..._i2c_native_System_Device_I2c_I2cDevice.cpp | 16 ++++++++-------- ..._sys_io_hashing_System_IO_Hashing_Crc32.cpp | 8 ++++---- ...native_System_Device_I2c_I2cSlaveDevice.cpp | 14 +++++++------- ..._i2c_native_System_Device_I2c_I2cDevice.cpp | 16 ++++++++-------- ..._i2s_native_System_Device_I2s_I2sDevice.cpp | 18 +++++++++--------- ..._sys_io_hashing_System_IO_Hashing_Crc32.cpp | 8 ++++---- ..._i2c_native_System_Device_I2c_I2cDevice.cpp | 8 ++++---- ..._i2c_native_System_Device_I2c_I2cDevice.cpp | 8 ++++---- 13 files changed, 79 insertions(+), 79 deletions(-) diff --git a/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp b/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp index c8958a14dd..1e684e2c57 100644 --- a/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp +++ b/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp @@ -9,7 +9,7 @@ // define this type here to make it shorter and improve code readability typedef Library_sys_dev_spi_native_System_Device_Spi_SpiConnectionSettings SpiConnectionSettings; -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; void System_Device_nano_spi_callback(int busIndex) { @@ -139,15 +139,15 @@ HRESULT Library_sys_dev_spi_native_System_Device_Spi_SpiDevice::NativeTransfer( if (writeSpanByte != nullptr) { // get buffer - writeBuffer = writeSpanByte[SpanByte::FIELD___array].DereferenceArray(); + writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { // Get the write offset, only the elements defined by the span must be written, not the whole // array - writeOffset = writeSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - writeSize = writeSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + writeSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; writeData = (unsigned char *)writeBuffer->GetElement(writeOffset); // pin the buffer @@ -165,14 +165,14 @@ HRESULT Library_sys_dev_spi_native_System_Device_Spi_SpiDevice::NativeTransfer( if (readSpanByte != nullptr) { // get buffer - readBuffer = readSpanByte[SpanByte::FIELD___array].DereferenceArray(); + readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as read size, only the elements defined by the span must be read - readSize = readSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + readSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; readData = (unsigned char *)readBuffer->GetElement(readOffset); // pin the buffer diff --git a/src/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32_stubs.cpp b/src/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32_stubs.cpp index 645a87fae1..ce2585f497 100644 --- a/src/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32_stubs.cpp +++ b/src/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32_stubs.cpp @@ -5,7 +5,7 @@ #include "nf_sys_io_hashing.h" -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; uint32_t ComputeCrc32(uint32_t crc, const uint8_t *buf, size_t len) { @@ -70,13 +70,13 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ crc32 = stack.Arg0().NumericByRef().u4; // get buffer - buffer = bufferSpanByte[SpanByte::FIELD___array].DereferenceArray(); + buffer = bufferSpanByte[Span::FIELD___array].DereferenceArray(); // Get the write offset - bufferOffset = bufferSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + bufferOffset = bufferSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - bufferSize = bufferSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + bufferSize = bufferSpanByte[Span::FIELD___length].NumericByRef().s4; bufferData = buffer->GetElement(bufferOffset); if (bufferSize == 0) diff --git a/targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index ec6a5df500..b1f4cdd44f 100644 --- a/targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -7,7 +7,7 @@ typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cConnectionSettings I2cConnectionSettings; typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cTransferResult I2cTransferResult; -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; //////////////////////////////////////////// // declaration of the the I2C PAL structs // @@ -448,19 +448,19 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: break; } - // dereference the write and read SpanByte from the arguments + // dereference the write and read Span from the arguments writeSpanByte = stack.Arg1().Dereference(); if (writeSpanByte != nullptr) { // get buffer - writeBuffer = writeSpanByte[SpanByte::FIELD___array].DereferenceArray(); + writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { // Get the write offset, only the elements defined by the span must be written, not the whole array - writeOffset = writeSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - palI2c->WriteSize = writeSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + palI2c->WriteSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; // pin the buffer so DMA can find it where its supposed to be writeBuffer->Pin(); @@ -477,14 +477,14 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (readSpanByte != nullptr) { // get buffer - readBuffer = readSpanByte[SpanByte::FIELD___array].DereferenceArray(); + readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as read size, only the elements defined by the span must be read - palI2c->ReadSize = readSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + palI2c->ReadSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; // pin the buffer so DMA can find it where its supposed to be readBuffer->Pin(); diff --git a/targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index 43547f50b9..3758f42f11 100644 --- a/targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -7,7 +7,7 @@ typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cConnectionSettings I2cConnectionSettings; typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cTransferResult I2cTransferResult; -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; //////////////////////////////////////////// // declaration of the the I2C PAL structs // @@ -458,21 +458,21 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: break; } - // dereference the write and read SpanByte from the arguments + // dereference the write and read Span from the arguments writeSpanByte = stack.Arg1().Dereference(); if (writeSpanByte != nullptr) { // get buffer - writeBuffer = writeSpanByte[SpanByte::FIELD___array].DereferenceArray(); + writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { // Get the write offset, only the elements defined by the span must be written, not the whole array - writeOffset = writeSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - palI2c->WriteSize = writeSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + palI2c->WriteSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; // pin the buffer so DMA can find it where its supposed to be writeBuffer->Pin(); @@ -490,15 +490,15 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (readSpanByte != nullptr) { // get buffer - readBuffer = readSpanByte[SpanByte::FIELD___array].DereferenceArray(); + readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as read size, only the elements defined by the span must be read - palI2c->ReadSize = readSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + palI2c->ReadSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; // pin the buffer so DMA can find it where its supposed to be readBuffer->Pin(); diff --git a/targets/AzureRTOS/SiliconLabs/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp b/targets/AzureRTOS/SiliconLabs/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp index 5e63e04977..5298b54a6c 100644 --- a/targets/AzureRTOS/SiliconLabs/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp +++ b/targets/AzureRTOS/SiliconLabs/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp @@ -10,7 +10,7 @@ #include #include -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC__U4__U4__SystemSpanByte( CLR_RT_StackFrame &stack) @@ -33,13 +33,13 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ crc32 = stack.Arg0().NumericByRef().u4; // get buffer - buffer = bufferSpanByte[SpanByte::FIELD___array].DereferenceArray(); + buffer = bufferSpanByte[Span::FIELD___array].DereferenceArray(); // Get the write offset - bufferOffset = bufferSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + bufferOffset = bufferSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - bufferSize = bufferSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + bufferSize = bufferSpanByte[Span::FIELD___length].NumericByRef().s4; bufferData = (unsigned char *)buffer->GetElement(bufferOffset); if (bufferSize == 0) diff --git a/targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index c826100089..e908f717c4 100644 --- a/targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -7,7 +7,7 @@ typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cConnectionSettings I2cConnectionSettings; typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cTransferResult I2cTransferResult; -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; //////////////////////////////////////////// // declaration of the the I2C PAL structs // @@ -407,19 +407,19 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: break; } - // dereference the write and read SpanByte from the arguments + // dereference the write and read Span from the arguments writeSpanByte = stack.Arg1().Dereference(); if (writeSpanByte != nullptr) { // get buffer - writeBuffer = writeSpanByte[SpanByte::FIELD___array].DereferenceArray(); + writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { // Get the write offset, only the elements defined by the span must be written, not the whole array - writeOffset = writeSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - palI2c->WriteSize = writeSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + palI2c->WriteSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; // pin the buffer so DMA can find it where its supposed to be writeBuffer->Pin(); @@ -436,14 +436,14 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (readSpanByte != nullptr) { // get buffer - readBuffer = readSpanByte[SpanByte::FIELD___array].DereferenceArray(); + readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as read size, only the elements defined by the span must be read - palI2c->ReadSize = readSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + palI2c->ReadSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; // pin the buffer so DMA can find it where its supposed to be readBuffer->Pin(); diff --git a/targets/ChibiOS/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp b/targets/ChibiOS/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp index 9520fa5aa8..3e692909a7 100644 --- a/targets/ChibiOS/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp +++ b/targets/ChibiOS/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp @@ -7,7 +7,7 @@ #include #include -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; // set config to use standard CRC32 crcConfig crc32Config = { @@ -39,13 +39,13 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ crc32 = stack.Arg0().NumericByRef().u4; // get buffer - buffer = bufferSpanByte[SpanByte::FIELD___array].DereferenceArray(); + buffer = bufferSpanByte[Span::FIELD___array].DereferenceArray(); // Get the write offset - bufferOffset = bufferSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + bufferOffset = bufferSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - bufferSize = bufferSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + bufferSize = bufferSpanByte[Span::FIELD___length].NumericByRef().s4; bufferData = (unsigned char *)buffer->GetElement(bufferOffset); crcAquireModule(); diff --git a/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp b/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp index a25e4da369..c627603c53 100644 --- a/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp @@ -11,7 +11,7 @@ #define I2C_SLAVE_WORKER_TASK_STACK_SIZE 2048 -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; #if SOC_I2C_NUM > 0 NF_PAL_I2CSLAVE I2cSlave0_PAL; @@ -264,7 +264,7 @@ HRESULT Library_sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice:: NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); } - readBuffer = readSpanByte[SpanByte::FIELD___array].DereferenceArray(); + readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { @@ -272,23 +272,23 @@ HRESULT Library_sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice:: isRead = true; // Get the read offset, only the elements defined by the span must be read, not the whole array - bufferOffset = readSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + bufferOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as read size, only the elements defined by the span must be read - requestedCount = readSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + requestedCount = readSpanByte[Span::FIELD___length].NumericByRef().s4; } if (!isRead) { - writeBuffer = writeSpanByte[SpanByte::FIELD___array].DereferenceArray(); + writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { // Get the write offset, only the elements defined by the span must be written, not the whole array - bufferOffset = writeSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + bufferOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - requestedCount = writeSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + requestedCount = writeSpanByte[Span::FIELD___length].NumericByRef().s4; } } diff --git a/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index 76b962abc1..cfdf86b87f 100644 --- a/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -13,7 +13,7 @@ typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cConnectionSettings I2cConnectionSettings; typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cTransferResult I2cTransferResult; -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; bool SetConfig(i2c_port_t bus, CLR_RT_HeapBlock *config) { @@ -171,19 +171,19 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: cmd = i2c_cmd_link_create(); - // dereference the write and read SpanByte from the arguments + // dereference the write and read Span from the arguments writeSpanByte = stack.Arg1().Dereference(); if (writeSpanByte != nullptr) { - writeData = writeSpanByte[SpanByte::FIELD___array].DereferenceArray(); + writeData = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeData != nullptr) { // Get the write offset, only the elements defined by the span must be written, not the whole array - writeOffset = writeSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - writeSize = writeSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + writeSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; if (writeSize > 0) { @@ -214,15 +214,15 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: readSpanByte = stack.Arg2().Dereference(); if (readSpanByte != 0) { - readData = readSpanByte[SpanByte::FIELD___array].DereferenceArray(); + readData = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readData != nullptr) { // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as read size, only the elements defined by the span must be read - readSize = readSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + readSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; if (readSize > 0) { diff --git a/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp b/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp index 6ae31b52f8..4ebac1787b 100644 --- a/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp @@ -21,7 +21,7 @@ #define I2S_RX_FRAME_SIZE_IN_BYTES (8) typedef Library_sys_dev_i2s_native_System_Device_I2s_I2sConnectionSettings I2sConnectionSettings; -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; static char Esp_I2S_Initialised_Flag[I2S_NUM_MAX] = { 0, @@ -392,19 +392,19 @@ HRESULT Library_sys_dev_i2s_native_System_Device_I2s_I2sDevice::Read___VOID__Sys NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); } - // dereference the SpanByte from the arguments + // dereference the Span from the arguments readSpanByte = stack.Arg1().Dereference(); if (readSpanByte != nullptr) { - readBuffer = readSpanByte[SpanByte::FIELD___array].DereferenceArray(); + readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as read size, only the elements defined by the span must be read - readSize = readSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + readSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; if (readSize > 0) { @@ -508,19 +508,19 @@ HRESULT Library_sys_dev_i2s_native_System_Device_I2s_I2sDevice::Write___VOID__Sy NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); } - // dereference the write and read SpanByte from the arguments + // dereference the write and read Span from the arguments writeSpanByte = stack.Arg1().Dereference(); if (writeSpanByte != nullptr) { - writeBuffer = writeSpanByte[SpanByte::FIELD___array].DereferenceArray(); + writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { // Get the write offset, only the elements defined by the span must be written, not the whole array - writeOffset = writeSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - writeSize = writeSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + writeSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; if (writeSize > 0) { diff --git a/targets/ESP32/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp b/targets/ESP32/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp index 3dd2b12652..a3670ad705 100644 --- a/targets/ESP32/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp +++ b/targets/ESP32/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp @@ -6,7 +6,7 @@ #include #include -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC__U4__U4__SystemSpanByte( CLR_RT_StackFrame &stack) @@ -29,13 +29,13 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ crc32 = stack.Arg0().NumericByRef().u4; // get buffer - buffer = bufferSpanByte[SpanByte::FIELD___array].DereferenceArray(); + buffer = bufferSpanByte[Span::FIELD___array].DereferenceArray(); // Get the write offset - bufferOffset = bufferSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + bufferOffset = bufferSpanByte[Span::FIELD___start].NumericByRef().s4; // use the span length as write size, only the elements defined by the span must be written - bufferSize = bufferSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + bufferSize = bufferSpanByte[Span::FIELD___length].NumericByRef().s4; bufferData = (unsigned char *)buffer->GetElement(bufferOffset); #ifdef ESP_ROM_HAS_CRC_LE diff --git a/targets/FreeRTOS/NXP/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/FreeRTOS/NXP/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index 8d2bf36618..b2c8ea4259 100644 --- a/targets/FreeRTOS/NXP/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/FreeRTOS/NXP/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -32,7 +32,7 @@ static LPI2C_Type *i2cBaseAddress[] = LPI2C_BASE_PTRS; typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cConnectionSettings I2cConnectionSettings; typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cTransferResult I2cTransferResult; -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; i2c_structure_t *I2C_ChoosePeripheralStructure(uint8_t busIndex) { @@ -309,12 +309,12 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: I2C_ClearBuffers(pI2Cx); - // dereference the write and read SpanByte from the arguments + // dereference the write and read Span from the arguments writeSpanByte = stack.Arg1().Dereference(); if (writeSpanByte != nullptr) { // get buffer - writeBuffer = writeSpanByte[SpanByte::FIELD___array].DereferenceArray(); + writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { pI2Cx->txBuffer = writeBuffer->GetFirstElement(); @@ -332,7 +332,7 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (readSpanByte != nullptr) { // get buffer - readBuffer = readSpanByte[SpanByte::FIELD___array].DereferenceArray(); + readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { pI2Cx->rxBuffer = readBuffer->GetFirstElement(); diff --git a/targets/TI_SimpleLink/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/TI_SimpleLink/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index f86afb251e..9f4827409d 100644 --- a/targets/TI_SimpleLink/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/TI_SimpleLink/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -7,7 +7,7 @@ typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cConnectionSettings I2cConnectionSettings; typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cTransferResult I2cTransferResult; -typedef Library_corlib_native_System_SpanByte SpanByte; +typedef Library_corlib_native_System_Span_1 Span; ///////////////////////////////////////////////////// // I2C PAL structs declared in sys_dev_i2c_native.h // @@ -178,12 +178,12 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: break; } - // dereference the write and read SpanByte from the arguments + // dereference the write and read Span from the arguments writeSpanByte = stack.Arg1().Dereference(); if (writeSpanByte != nullptr) { // get buffer - writeBuffer = writeSpanByte[SpanByte::FIELD___array].DereferenceArray(); + writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { // get the size of the buffer by reading the number of elements in the CLR_RT_HeapBlock_Array @@ -201,7 +201,7 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (readSpanByte != nullptr) { // get buffer - readBuffer = readSpanByte[SpanByte::FIELD___array].DereferenceArray(); + readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { // get the size of the buffer by reading the number of elements in the CLR_RT_HeapBlock_Array From df4b419b4af6aa8811534130dcdc7493e00d0334 Mon Sep 17 00:00:00 2001 From: "nfbot[bot]" Date: Thu, 21 Aug 2025 23:17:12 +0100 Subject: [PATCH 40/61] Code style fixes (#161) Automated fixes for code style. --- .../sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp b/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp index 4ebac1787b..c988cd0c6c 100644 --- a/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp @@ -319,7 +319,7 @@ HRESULT SetI2sConfig(i2s_port_t bus, CLR_RT_HeapBlock *config) #endif } -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) // apply low-level workaround for bug in some ESP-IDF versions that swap // the left and right channels // https://github.com/espressif/esp-idf/issues/6625 From 385670fda740af6fda86e2e6e18d2326fb02261f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 21 Aug 2025 23:37:17 +0100 Subject: [PATCH 41/61] Add missing ref to Span<> source code --- CMake/Modules/FindNF_CoreCLR.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/CMake/Modules/FindNF_CoreCLR.cmake b/CMake/Modules/FindNF_CoreCLR.cmake index 10425d0682..3733171055 100644 --- a/CMake/Modules/FindNF_CoreCLR.cmake +++ b/CMake/Modules/FindNF_CoreCLR.cmake @@ -111,6 +111,7 @@ set(NF_CoreCLR_SRCS corlib_native_System_Runtime_CompilerServices_RuntimeHelpers.cpp corlib_native_System_Runtime_Remoting_RemotingServices.cpp corlib_native_System_String.cpp + corlib_native_System_Span_1.cpp corlib_native_System_Threading_AutoResetEvent.cpp corlib_native_System_Threading_Interlocked.cpp corlib_native_System_Threading_ManualResetEvent.cpp From 09ba158e30b873154c38571589294b908217486a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Mon, 1 Sep 2025 17:33:30 +0100 Subject: [PATCH 42/61] Fix InitializeReference for nested generic types --- src/CLR/Core/Execution.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 5dd90ad2c7..ae57c784a3 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -1839,9 +1839,11 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference( NANOCLR_HEADER(); + CLR_RT_SignatureParser internalParser{}; CLR_RT_SignatureParser::Element res; NanoCLRDataType dt; - CLR_RT_TypeDef_Index realTypeDef; + CLR_RT_TypeDef_Index realTypeDef{}; + CLR_RT_TypeSpec_Instance internalGenericInstance{}; NANOCLR_CHECK_HRESULT(parser.Advance(res)); @@ -1882,19 +1884,19 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference( } // copy over to parameter - CLR_RT_TypeSpec_Instance genericTSInstance; - genericTSInstance.InitializeFromIndex(genericTSIndex); + internalGenericInstance.InitializeFromIndex(genericTSIndex); - CLR_RT_SignatureParser sp; - sp.Initialize_TypeSpec(parser.Assembly, parser.Assembly->GetTypeSpec(genericTSInstance.TypeSpec())); + internalParser.Initialize_TypeSpec( + parser.Assembly, + parser.Assembly->GetTypeSpec(internalGenericInstance.TypeSpec())); CLR_RT_SignatureParser::Element element; - NANOCLR_CHECK_HRESULT(sp.Advance(element)); + NANOCLR_CHECK_HRESULT(internalParser.Advance(element)); // if this is another generic instance, need to advance to get the type if (dt == DATATYPE_GENERICINST) { - NANOCLR_CHECK_HRESULT(sp.Advance(element)); + NANOCLR_CHECK_HRESULT(internalParser.Advance(element)); } dt = element.DataType; @@ -1913,12 +1915,15 @@ HRESULT CLR_RT_ExecutionEngine::InitializeReference( } else { - NANOCLR_SET_AND_LEAVE(NewObject(ref, inst, genericInstance)); + // prefer the generic instance contained in the signature + NANOCLR_SET_AND_LEAVE(NewObject( + ref, + inst, + NANOCLR_INDEX_IS_VALID(internalGenericInstance) ? &internalGenericInstance : genericInstance)); } } else { - if (c_CLR_RT_DataTypeLookup[dt].m_flags & CLR_RT_DataTypeLookup::c_Reference) { dt = DATATYPE_OBJECT; From 1900db4525371930d5f025de6d31575ea94cf19b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 4 Sep 2025 09:35:17 +0100 Subject: [PATCH 43/61] Fix mscorlib checksum --- src/CLR/CorLib/corlib_native.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CLR/CorLib/corlib_native.cpp b/src/CLR/CorLib/corlib_native.cpp index 2a93e5f710..0a3986ea2d 100644 --- a/src/CLR/CorLib/corlib_native.cpp +++ b/src/CLR/CorLib/corlib_native.cpp @@ -1546,7 +1546,7 @@ const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_mscorlib = #if (NANOCLR_REFLECTION == TRUE) - 0x6BB74C3A, + 0x80786053, #elif (NANOCLR_REFLECTION == FALSE) From 4b03921cec4231db5ea5658124f3c88db9630183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 4 Sep 2025 12:31:26 +0100 Subject: [PATCH 44/61] Add implementation for Span CopyTo --- .../CorLib/corlib_native_System_Span_1.cpp | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/CLR/CorLib/corlib_native_System_Span_1.cpp b/src/CLR/CorLib/corlib_native_System_Span_1.cpp index 064ef4a2c6..1ab4debd9a 100644 --- a/src/CLR/CorLib/corlib_native_System_Span_1.cpp +++ b/src/CLR/CorLib/corlib_native_System_Span_1.cpp @@ -10,7 +10,33 @@ HRESULT Library_corlib_native_System_Span_1::CopyTo___VOID__SystemSpan_1(CLR_RT_ { NANOCLR_HEADER(); - NANOCLR_SET_AND_LEAVE(stack.NotImplementedStub()); + CLR_RT_HeapBlock_Array *sourceArray; + CLR_RT_HeapBlock_Array *destinationArray; + CLR_RT_HeapBlock *sourceSpan = stack.This(); + CLR_RT_HeapBlock *destinationSpan = stack.Arg1().Dereference(); + + // check lengths + if (sourceSpan[FIELD___length].NumericByRefConst().u4 > destinationSpan[FIELD___length].NumericByRefConst().u4) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + // get pointers to the arrays + sourceArray = sourceSpan[FIELD___array].DereferenceArray(); + destinationArray = destinationSpan[FIELD___array].DereferenceArray(); + + { + // prevent GC from moving the arrays while we copy the data + CLR_RT_ProtectFromGC gc1(*sourceArray); + CLR_RT_ProtectFromGC gc2(*destinationArray); + + // copy the data + memcpy( + &destinationArray[sourceSpan[FIELD___start].NumericByRefConst().u4], + &sourceArray[sourceSpan[FIELD___start].NumericByRefConst().u4], + sourceSpan[FIELD___length].NumericByRefConst().u4 * + c_CLR_RT_DataTypeLookup[sourceArray->DataType()].m_sizeInBytes); + } NANOCLR_NOCLEANUP(); } From ed9126c366c294472b9cf220e938bd27c366fdfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 4 Sep 2025 16:02:44 +0100 Subject: [PATCH 45/61] Fix token resolution for MethodDef when using empty generic types --- src/CLR/Core/TypeSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 26802ce32a..2296952b57 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1621,7 +1621,7 @@ bool CLR_RT_MethodDef_Instance::ResolveToken( CLR_UINT32 ownerTypeDefToken = elemOwner.Class.data; - if (callerTypeDefToken == ownerTypeDefToken) + if ((callerTypeDefToken == ownerTypeDefToken) && callerTypeDefToken != 0x0) { // we have a match on the typeDef, so they refer to the same type // lets bind using the closed generic From e2d8d6c46c0c5b65b2a95d7ca6deec75aefe42f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 4 Sep 2025 16:07:56 +0100 Subject: [PATCH 46/61] Fix local initialization for method in generic type --- src/CLR/Core/Execution.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index ae57c784a3..3490b5af40 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2031,13 +2031,22 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( typeSpecSignature--; CLR_RT_TypeSpec_Index genericTSIndex = {}; - if (!assembly->FindTypeSpec(typeSpecSignature, genericTSIndex)) + + if (methodDefInstance.genericType && methodDefInstance.genericType->data != 0) { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + // method is generic, it can only use class from method's class generic parameters + genericInstance.InitializeFromIndex(*methodDefInstance.genericType); } + else + { + if (!assembly->FindTypeSpec(typeSpecSignature, genericTSIndex)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } - // copy over to parameter - genericInstance.InitializeFromIndex(genericTSIndex); + // copy over to parameter + genericInstance.InitializeFromIndex(genericTSIndex); + } CLR_RT_SignatureParser parser; parser.Initialize_TypeSpec(genericInstance); From ba315fc175fc0044786c3c14004f5f4768b13537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 4 Sep 2025 16:10:56 +0100 Subject: [PATCH 47/61] Update mscorlib declaration with Span and ReadOnlySpan - Add implemenation for both native constructors. --- CMake/Modules/FindNF_CoreCLR.cmake | 1 + src/CLR/CorLib/CorLib.vcxproj | 1 + src/CLR/CorLib/CorLib.vcxproj.filters | 3 ++ src/CLR/CorLib/corlib_native.cpp | 4 +- src/CLR/CorLib/corlib_native.h | 9 ++-- .../corlib_native_System_ReadOnlySpan_1.cpp | 52 +++++++++++++++++++ .../CorLib/corlib_native_System_Span_1.cpp | 48 ++++++++++++++--- ..._hashing_System_IO_Hashing_Crc32_stubs.cpp | 6 +-- 8 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp diff --git a/CMake/Modules/FindNF_CoreCLR.cmake b/CMake/Modules/FindNF_CoreCLR.cmake index 3733171055..3896adb7f1 100644 --- a/CMake/Modules/FindNF_CoreCLR.cmake +++ b/CMake/Modules/FindNF_CoreCLR.cmake @@ -106,6 +106,7 @@ set(NF_CoreCLR_SRCS corlib_native_System_Number.cpp corlib_native_System_Object.cpp corlib_native_System_Random.cpp + corlib_native_System_ReadOnlySpan_1.cpp corlib_native_System_Reflection_Binder.cpp corlib_native_System_Reflection_MemberInfo.cpp corlib_native_System_Runtime_CompilerServices_RuntimeHelpers.cpp diff --git a/src/CLR/CorLib/CorLib.vcxproj b/src/CLR/CorLib/CorLib.vcxproj index e7245e5e83..52ba6cf841 100644 --- a/src/CLR/CorLib/CorLib.vcxproj +++ b/src/CLR/CorLib/CorLib.vcxproj @@ -48,6 +48,7 @@ + diff --git a/src/CLR/CorLib/CorLib.vcxproj.filters b/src/CLR/CorLib/CorLib.vcxproj.filters index e545e99d37..ebb17ab622 100644 --- a/src/CLR/CorLib/CorLib.vcxproj.filters +++ b/src/CLR/CorLib/CorLib.vcxproj.filters @@ -176,5 +176,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/src/CLR/CorLib/corlib_native.cpp b/src/CLR/CorLib/corlib_native.cpp index 0a3986ea2d..41cedd813f 100644 --- a/src/CLR/CorLib/corlib_native.cpp +++ b/src/CLR/CorLib/corlib_native.cpp @@ -667,6 +667,7 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + Library_corlib_native_System_ReadOnlySpan_1::NativeReadOnlySpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4, nullptr, nullptr, nullptr, @@ -771,6 +772,7 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + Library_corlib_native_System_Span_1::NativeSpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4, nullptr, nullptr, nullptr, @@ -1546,7 +1548,7 @@ const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_mscorlib = #if (NANOCLR_REFLECTION == TRUE) - 0x80786053, + 0x17B85422, #elif (NANOCLR_REFLECTION == FALSE) diff --git a/src/CLR/CorLib/corlib_native.h b/src/CLR/CorLib/corlib_native.h index d1e59462f3..2eb0d33c09 100644 --- a/src/CLR/CorLib/corlib_native.h +++ b/src/CLR/CorLib/corlib_native.h @@ -781,8 +781,9 @@ struct Library_corlib_native_System_Random struct Library_corlib_native_System_ReadOnlySpan_1 { static const int FIELD___array = 1; - static const int FIELD___start = 2; - static const int FIELD___length = 3; + static const int FIELD___length = 2; + + NANOCLR_NATIVE_DECLARE(NativeReadOnlySpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4); //--// }; @@ -940,10 +941,10 @@ struct Library_corlib_native_System_Single struct Library_corlib_native_System_Span_1 { static const int FIELD___array = 1; - static const int FIELD___start = 2; - static const int FIELD___length = 3; + static const int FIELD___length = 2; NANOCLR_NATIVE_DECLARE(CopyTo___VOID__SystemSpan_1); + NANOCLR_NATIVE_DECLARE(NativeSpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4); //--// }; diff --git a/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp b/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp new file mode 100644 index 0000000000..b3dcd53119 --- /dev/null +++ b/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp @@ -0,0 +1,52 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) Microsoft Corporation. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +#include "CorLib.h" + +HRESULT Library_corlib_native_System_ReadOnlySpan_1::NativeReadOnlySpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int32_t start; + int32_t length; + + CLR_RT_TypeDescriptor descDst{}; + CLR_RT_TypeDef_Index sourceType{}; + CLR_RT_HeapBlock_Array *destinationArray; + CLR_RT_HeapBlock_Array *sourceArray = stack.Arg1().DereferenceArray(); + CLR_RT_HeapBlock *thisSpan = stack.This(); + + // get working values + start = stack.Arg2().NumericByRefConst().s4; + length = stack.Arg3().NumericByRefConst().s4; + + { + // get type of the source array + NANOCLR_CHECK_HRESULT(descDst.InitializeFromObject(*sourceArray)); + descDst.GetElementType(descDst); + + sourceType.data = descDst.m_handlerCls.data; + + CLR_RT_HeapBlock &refArray = thisSpan[FIELD___array]; + CLR_RT_HeapBlock_Array::CreateInstance(refArray, length, sourceType); + + // get pointer to the array + destinationArray = thisSpan[FIELD___array].DereferenceArray(); + + // protect from GC + CLR_RT_ProtectFromGC gc1(*sourceArray); + CLR_RT_ProtectFromGC gc2(refArray); + + // copy array + CLR_RT_HeapBlock_Array::Copy(sourceArray, start, destinationArray, 0, length); + + // set length + thisSpan[FIELD___length].NumericByRef().s4 = length; + } + + NANOCLR_NOCLEANUP(); +} diff --git a/src/CLR/CorLib/corlib_native_System_Span_1.cpp b/src/CLR/CorLib/corlib_native_System_Span_1.cpp index 1ab4debd9a..161728ac58 100644 --- a/src/CLR/CorLib/corlib_native_System_Span_1.cpp +++ b/src/CLR/CorLib/corlib_native_System_Span_1.cpp @@ -27,15 +27,47 @@ HRESULT Library_corlib_native_System_Span_1::CopyTo___VOID__SystemSpan_1(CLR_RT_ { // prevent GC from moving the arrays while we copy the data + +HRESULT Library_corlib_native_System_Span_1::NativeSpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int32_t start; + int32_t length; + + CLR_RT_TypeDescriptor descDst{}; + CLR_RT_TypeDef_Index sourceType{}; + CLR_RT_HeapBlock_Array *destinationArray; + CLR_RT_HeapBlock_Array *sourceArray = stack.Arg1().DereferenceArray(); + CLR_RT_HeapBlock *thisSpan = stack.This(); + + // get working values + start = stack.Arg2().NumericByRefConst().s4; + length = stack.Arg3().NumericByRefConst().s4; + + { + // get type of the source array + NANOCLR_CHECK_HRESULT(descDst.InitializeFromObject(*sourceArray)); + descDst.GetElementType(descDst); + + sourceType.data = descDst.m_handlerCls.data; + + CLR_RT_HeapBlock &refArray = thisSpan[FIELD___array]; + CLR_RT_HeapBlock_Array::CreateInstance(refArray, length, sourceType); + + // get pointer to the array + destinationArray = thisSpan[FIELD___array].DereferenceArray(); + + // protect from GC CLR_RT_ProtectFromGC gc1(*sourceArray); - CLR_RT_ProtectFromGC gc2(*destinationArray); - - // copy the data - memcpy( - &destinationArray[sourceSpan[FIELD___start].NumericByRefConst().u4], - &sourceArray[sourceSpan[FIELD___start].NumericByRefConst().u4], - sourceSpan[FIELD___length].NumericByRefConst().u4 * - c_CLR_RT_DataTypeLookup[sourceArray->DataType()].m_sizeInBytes); + CLR_RT_ProtectFromGC gc2(refArray); + + // copy array + CLR_RT_HeapBlock_Array::Copy(sourceArray, start, destinationArray, 0, length); + + // set length + thisSpan[FIELD___length].NumericByRef().s4 = length; } NANOCLR_NOCLEANUP(); diff --git a/src/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32_stubs.cpp b/src/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32_stubs.cpp index ce2585f497..7d06053ea8 100644 --- a/src/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32_stubs.cpp +++ b/src/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32_stubs.cpp @@ -58,7 +58,6 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ CLR_RT_HeapBlock_Array *buffer; uint8_t *bufferData = nullptr; int32_t bufferSize = 0; - int32_t bufferOffset = 0; uint32_t crc32 = 0; uint32_t hash = 0; @@ -72,12 +71,9 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ // get buffer buffer = bufferSpanByte[Span::FIELD___array].DereferenceArray(); - // Get the write offset - bufferOffset = bufferSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written bufferSize = bufferSpanByte[Span::FIELD___length].NumericByRef().s4; - bufferData = buffer->GetElement(bufferOffset); + bufferData = buffer->GetFirstElement(); if (bufferSize == 0) { From 44c1c700355ffd625a727a10589fde77f83186e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 4 Sep 2025 16:11:41 +0100 Subject: [PATCH 48/61] Fix Span CopyTo - Addin validations for empty spans. --- .../CorLib/corlib_native_System_Span_1.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/CLR/CorLib/corlib_native_System_Span_1.cpp b/src/CLR/CorLib/corlib_native_System_Span_1.cpp index 161728ac58..72e791d78e 100644 --- a/src/CLR/CorLib/corlib_native_System_Span_1.cpp +++ b/src/CLR/CorLib/corlib_native_System_Span_1.cpp @@ -27,6 +27,29 @@ HRESULT Library_corlib_native_System_Span_1::CopyTo___VOID__SystemSpan_1(CLR_RT_ { // prevent GC from moving the arrays while we copy the data + if (sourceArray) + { + CLR_RT_ProtectFromGC gc1(*sourceArray); + } + if (destinationArray) + { + CLR_RT_ProtectFromGC gc2(*destinationArray); + } + + // does the source array has a reference? + if (sourceArray && destinationArray) + { + // copy the data + memcpy( + destinationArray->GetFirstElement(), + sourceArray->GetFirstElement(), + sourceSpan[FIELD___length].NumericByRefConst().u4 * + c_CLR_RT_DataTypeLookup[sourceArray->DataType()].m_sizeInBytes); + } + } + + NANOCLR_NOCLEANUP(); +} HRESULT Library_corlib_native_System_Span_1::NativeSpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4( CLR_RT_StackFrame &stack) From 9d8af32017410c512ee5bf2296da9f43fa30e799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 4 Sep 2025 16:20:41 +0100 Subject: [PATCH 49/61] Span CopyTo now uses Array::Copy --- src/CLR/CorLib/corlib_native_System_Span_1.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/CLR/CorLib/corlib_native_System_Span_1.cpp b/src/CLR/CorLib/corlib_native_System_Span_1.cpp index 72e791d78e..e9cebde926 100644 --- a/src/CLR/CorLib/corlib_native_System_Span_1.cpp +++ b/src/CLR/CorLib/corlib_native_System_Span_1.cpp @@ -39,12 +39,13 @@ HRESULT Library_corlib_native_System_Span_1::CopyTo___VOID__SystemSpan_1(CLR_RT_ // does the source array has a reference? if (sourceArray && destinationArray) { - // copy the data - memcpy( - destinationArray->GetFirstElement(), - sourceArray->GetFirstElement(), - sourceSpan[FIELD___length].NumericByRefConst().u4 * - c_CLR_RT_DataTypeLookup[sourceArray->DataType()].m_sizeInBytes); + // copy array + CLR_RT_HeapBlock_Array::Copy( + sourceArray, + 0, + destinationArray, + 0, + sourceSpan[FIELD___length].NumericByRefConst().s4); } } From 5bc67dbd5f704ed1f5587bddeca2f8cd66c675f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 5 Sep 2025 00:26:32 +0100 Subject: [PATCH 50/61] Fix ResolveToken for TypeDef when token is a TypeSpec --- src/CLR/Core/TypeSystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 2296952b57..d6e5ba9e72 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1113,7 +1113,8 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( NanoCLRDataType realDataType; // Only call this once to map (e.g. !T→Int32) - caller->assembly + + g_CLR_RT_TypeSystem.m_assemblies[caller->genericType->Assembly() - 1] ->FindGenericParamAtTypeSpec(closedTsRow, (CLR_UINT32)pos, realTypeDef, realDataType); // populate this instance From e7651b6373039467143e3987efc80953f492d2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 5 Sep 2025 00:27:41 +0100 Subject: [PATCH 51/61] Fix locals initialization for VAR signature with generic caller --- src/CLR/Core/Execution.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 3490b5af40..f56d9f80aa 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2093,11 +2093,25 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( // type-level generic parameter in a locals signature (e.g. 'T' inside a generic type) CLR_INT8 genericParamPosition = *sig++; - assembly->FindGenericParamAtTypeSpec( - methodDefInstance.genericType->TypeSpec(), - genericParamPosition, - cls, - dt); + if (methodDefInstance.genericType && methodDefInstance.genericType->data != 0) + { + CLR_RT_TypeSpec_Instance typeSpec{}; + typeSpec.InitializeFromIndex((CLR_RT_TypeSpec_Index)methodDefInstance.genericType->data); + + typeSpec.assembly->FindGenericParamAtTypeSpec( + methodDefInstance.genericType->TypeSpec(), + genericParamPosition, + cls, + dt); + } + else + { + assembly->FindGenericParamAtTypeSpec( + methodDefInstance.genericType->TypeSpec(), + genericParamPosition, + cls, + dt); + } goto done; } From fdd237b02fb1cdf35a931cd648bc03d4e631aeac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 5 Sep 2025 10:35:45 +0100 Subject: [PATCH 52/61] Fix DumpToken for MethodRef in generic types --- src/CLR/Diagnostics/Info.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/CLR/Diagnostics/Info.cpp b/src/CLR/Diagnostics/Info.cpp index ee18bb70e1..68b2a8a8ce 100644 --- a/src/CLR/Diagnostics/Info.cpp +++ b/src/CLR/Diagnostics/Info.cpp @@ -472,12 +472,12 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_MethodDef_Instanc CLR_UINT32 idx = CLR_DataFromTk(token); auto &xref = crossReferenceMethodRef[idx]; - // Build a MethodRef_Index so we can format the reference: - CLR_RT_MethodRef_Index mri; - mri.Set(assemblyIndex, idx); + // Build a MethodDef_Index so we can format the reference: + CLR_RT_MethodDef_Index mdi; + mdi.data = xref.target.data; - // Decide which TypeSpec to supply to BuildMethodRefName: - // 1) If the caller passed a non-null genericType (i.e. we’re inside SimpleList), + // Decide which TypeSpec to supply to BuildMethodName: + // 1) If the caller passed a non-null genericType (i.e. we're inside SimpleList), // use that, so ResizeArray prints as SimpleList::ResizeArray. // 2) Otherwise, fall back to xref.genericType (the raw MethodRef own owner). const CLR_RT_TypeSpec_Index *ownerTypeSpec; @@ -492,7 +492,9 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_MethodDef_Instanc char buf[256], *p = buf; size_t cb = sizeof(buf); - g_CLR_RT_TypeSystem.BuildMethodRefName(mri, ownerTypeSpec, p, cb); + + g_CLR_RT_TypeSystem.BuildMethodName(mdi, ownerTypeSpec, p, cb); + CLR_Debug::Printf("%s", buf); break; } From 0e4891ddf3defac7a273366436e11202e1d26da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 5 Sep 2025 10:38:18 +0100 Subject: [PATCH 53/61] Fix token resolution for MedthoDef with generic instances - Signature crawling for comparison was missing advance past GENERICINST. - Was setting the MethodDef of the open generic type instead of the closed one. --- src/CLR/Core/TypeSystem.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index d6e5ba9e72..3f6e636c4c 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1606,6 +1606,11 @@ bool CLR_RT_MethodDef_Instance::ResolveToken( // advance to the generic instance which will point to the class parserCaller.Advance(elemCaller); + if (elemCaller.DataType == DATATYPE_GENERICINST) + { + parserCaller.Advance(elemCaller); + } + CLR_UINT32 callerTypeDefToken = elemCaller.Class.data; // parse the MethodRef declared TypeSpec @@ -1620,6 +1625,11 @@ bool CLR_RT_MethodDef_Instance::ResolveToken( // advance to the generic instance which will point to the class parserOwner.Advance(elemOwner); + if (elemOwner.DataType == DATATYPE_GENERICINST) + { + parserOwner.Advance(elemOwner); + } + CLR_UINT32 ownerTypeDefToken = elemOwner.Class.data; if ((callerTypeDefToken == ownerTypeDefToken) && callerTypeDefToken != 0x0) @@ -1636,17 +1646,17 @@ bool CLR_RT_MethodDef_Instance::ResolveToken( const CLR_RT_TypeSpec_Index *definitiveTypeSpec = useCaller ? callerGeneric : methodOwnerTS; genericType = (CLR_RT_TypeSpec_Index *)definitiveTypeSpec; - CLR_INDEX tsAsmIdx = genericType->Assembly(); - CLR_RT_Assembly *genericTypeAssembly = g_CLR_RT_TypeSystem.m_assemblies[tsAsmIdx - 1]; + CLR_INDEX tsAsmIdx = methodOwnerTS->Assembly(); + CLR_RT_Assembly *methodAssembly = g_CLR_RT_TypeSystem.m_assemblies[methodOwnerTS->Assembly() - 1]; - const CLR_RECORD_TYPESPEC *ts = genericTypeAssembly->GetTypeSpec(definitiveTypeSpec->TypeSpec()); + const CLR_RECORD_TYPESPEC *ts = methodAssembly->GetTypeSpec(methodOwnerTS->TypeSpec()); CLR_UINT32 assemblyIndex = 0xFFFF; CLR_RT_MethodDef_Index methodIndex; - if (!genericTypeAssembly->FindMethodDef( + if (!methodAssembly->FindMethodDef( ts, - genericTypeAssembly->GetString(mr->name), - genericTypeAssembly, + methodAssembly->GetString(mr->name), + methodAssembly, mr->signature, methodIndex, assemblyIndex)) From 642546b566bd806eb39691346755c53cc09691b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 5 Sep 2025 11:21:26 +0100 Subject: [PATCH 54/61] Add missing levels processing in TypeDef instance from TypeSpec --- 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 3f6e636c4c..c3286e38dd 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -818,6 +818,8 @@ bool CLR_RT_TypeDef_Instance::InitializeFromReflection(const CLR_RT_ReflectionDe return false; } + *levels = element.Levels; + // if this is a generic type, need to advance to get type if (element.DataType == DATATYPE_GENERICINST) { From 17167dcec303afde893ab618982191ea2b4dacad Mon Sep 17 00:00:00 2001 From: "nfbot[bot]" Date: Fri, 5 Sep 2025 14:35:58 +0100 Subject: [PATCH 55/61] Code style fixes (#163) Automated fixes for code style. --- src/CLR/Core/TypeSystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index c3286e38dd..b534a296e9 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1627,9 +1627,9 @@ bool CLR_RT_MethodDef_Instance::ResolveToken( // advance to the generic instance which will point to the class parserOwner.Advance(elemOwner); - if (elemOwner.DataType == DATATYPE_GENERICINST) + if (elemOwner.DataType == DATATYPE_GENERICINST) { - parserOwner.Advance(elemOwner); + parserOwner.Advance(elemOwner); } CLR_UINT32 ownerTypeDefToken = elemOwner.Class.data; From 9ca18148ede9c6a6a888f751f4db9f67c53dd69d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Fri, 5 Sep 2025 15:09:32 +0100 Subject: [PATCH 56/61] Fix compiler errors --- ...dev_spi_native_System_Device_Spi_SpiDevice.cpp | 15 +++------------ ...dev_i2c_native_System_Device_I2c_I2cDevice.cpp | 12 ++---------- ...dev_i2c_native_System_Device_I2c_I2cDevice.cpp | 12 ++---------- .../nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp | 6 +----- ...dev_i2c_native_System_Device_I2c_I2cDevice.cpp | 12 ++---------- .../nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp | 6 +----- ...ve_native_System_Device_I2c_I2cSlaveDevice.cpp | 9 +-------- ...dev_i2c_native_System_Device_I2c_I2cDevice.cpp | 10 +--------- ...dev_i2s_native_System_Device_I2s_I2sDevice.cpp | 12 ++---------- .../nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp | 6 +----- 10 files changed, 16 insertions(+), 84 deletions(-) diff --git a/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp b/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp index 1e684e2c57..3a65207658 100644 --- a/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp +++ b/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp @@ -82,8 +82,6 @@ HRESULT Library_sys_dev_spi_native_System_Device_Spi_SpiDevice::NativeTransfer( uint8_t *readData = nullptr; int16_t writeSize = 0; int16_t readSize = 0; - int16_t readOffset = 0; - int16_t writeOffset = 0; SPI_WRITE_READ_SETTINGS rws; uint32_t deviceId; @@ -142,13 +140,9 @@ HRESULT Library_sys_dev_spi_native_System_Device_Spi_SpiDevice::NativeTransfer( writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { - // Get the write offset, only the elements defined by the span must be written, not the whole - // array - writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written writeSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; - writeData = (unsigned char *)writeBuffer->GetElement(writeOffset); + writeData = (unsigned char *)writeBuffer->GetFirstElement(); // pin the buffer writeBuffer->Pin(); @@ -168,12 +162,9 @@ HRESULT Library_sys_dev_spi_native_System_Device_Spi_SpiDevice::NativeTransfer( readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { - // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; - - // use the span length as read size, only the elements defined by the span must be read + // use the span length as read size, only the elements defined by the span must be read readSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; - readData = (unsigned char *)readBuffer->GetElement(readOffset); + readData = (unsigned char *)readBuffer->GetFirstElement(); // pin the buffer readBuffer->Pin(); diff --git a/targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index b1f4cdd44f..3ed7425c61 100644 --- a/targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/AzureRTOS/ST/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -406,8 +406,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: CLR_RT_HeapBlock *connectionSettings; CLR_RT_HeapBlock_Array *writeBuffer = nullptr; CLR_RT_HeapBlock_Array *readBuffer = nullptr; - int readOffset = 0; - int writeOffset = 0; // get a pointer to the managed object instance and check that it's not nullptr CLR_RT_HeapBlock *pThis = stack.This(); @@ -456,9 +454,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { - // Get the write offset, only the elements defined by the span must be written, not the whole array - writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written palI2c->WriteSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; @@ -480,9 +475,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { - // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as read size, only the elements defined by the span must be read palI2c->ReadSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; @@ -527,7 +519,7 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (writeBuffer != nullptr) { // grab the pointer to the array by starting and the offset specified in the span - palI2c->WriteBuffer = (uint8_t *)writeBuffer->GetElement(writeOffset); + palI2c->WriteBuffer = (uint8_t *)writeBuffer->GetFirstElement(); // flush DMA buffer to ensure cache coherency // (only required for Cortex-M7) @@ -537,7 +529,7 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (readBuffer != nullptr) { // grab the pointer to the array by starting and the offset specified in the span - palI2c->ReadBuffer = (uint8_t *)readBuffer->GetElement(readOffset); + palI2c->ReadBuffer = (uint8_t *)readBuffer->GetFirstElement(); } // because the bus access is shared, acquire the appropriate bus diff --git a/targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index 3758f42f11..81e5e7372f 100644 --- a/targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/AzureRTOS/SiliconLabs/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -412,8 +412,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: CLR_RT_HeapBlock *connectionSettings; CLR_RT_HeapBlock_Array *writeBuffer = nullptr; CLR_RT_HeapBlock_Array *readBuffer = nullptr; - int readOffset = 0; - int writeOffset = 0; I2C_TransferSeq_TypeDef i2cTransfer; I2C_TransferReturn_TypeDef transactionResult = i2cTransferInProgress; @@ -468,9 +466,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (writeBuffer != nullptr) { - // Get the write offset, only the elements defined by the span must be written, not the whole array - writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written palI2c->WriteSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; @@ -494,9 +489,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (readBuffer != nullptr) { - // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as read size, only the elements defined by the span must be read palI2c->ReadSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; @@ -538,13 +530,13 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (writeBuffer != nullptr) { // grab the pointer to the array by starting and the offset specified in the span - palI2c->WriteBuffer = (uint8_t *)writeBuffer->GetElement(writeOffset); + palI2c->WriteBuffer = (uint8_t *)writeBuffer->GetFirstElement(); } if (readBuffer != nullptr) { // grab the pointer to the array by starting and the offset specified in the span - palI2c->ReadBuffer = (uint8_t *)readBuffer->GetElement(readOffset); + palI2c->ReadBuffer = (uint8_t *)readBuffer->GetFirstElement(); } } diff --git a/targets/AzureRTOS/SiliconLabs/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp b/targets/AzureRTOS/SiliconLabs/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp index 5298b54a6c..7853204544 100644 --- a/targets/AzureRTOS/SiliconLabs/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp +++ b/targets/AzureRTOS/SiliconLabs/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp @@ -21,7 +21,6 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ CLR_RT_HeapBlock_Array *buffer; uint8_t *bufferData = nullptr; int16_t bufferSize = 0; - int16_t bufferOffset = 0; uint32_t crc32 = 0; uint32_t hash = 0; @@ -35,12 +34,9 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ // get buffer buffer = bufferSpanByte[Span::FIELD___array].DereferenceArray(); - // Get the write offset - bufferOffset = bufferSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written bufferSize = bufferSpanByte[Span::FIELD___length].NumericByRef().s4; - bufferData = (unsigned char *)buffer->GetElement(bufferOffset); + bufferData = (unsigned char *)buffer->GetFirstElement(); if (bufferSize == 0) { diff --git a/targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index e908f717c4..f3b8f7b8ff 100644 --- a/targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/ChibiOS/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -365,8 +365,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: CLR_RT_HeapBlock *connectionSettings; CLR_RT_HeapBlock_Array *writeBuffer = nullptr; CLR_RT_HeapBlock_Array *readBuffer = nullptr; - int readOffset = 0; - int writeOffset = 0; // get a pointer to the managed object instance and check that it's not nullptr CLR_RT_HeapBlock *pThis = stack.This(); @@ -415,9 +413,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: writeBuffer = writeSpanByte[Span::FIELD___array].DereferenceArray(); if (writeBuffer != nullptr) { - // Get the write offset, only the elements defined by the span must be written, not the whole array - writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written palI2c->WriteSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; @@ -439,9 +434,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { - // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as read size, only the elements defined by the span must be read palI2c->ReadSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; @@ -486,7 +478,7 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (writeBuffer != nullptr) { // grab the pointer to the array by starting and the offset specified in the span - palI2c->WriteBuffer = (uint8_t *)writeBuffer->GetElement(writeOffset); + palI2c->WriteBuffer = (uint8_t *)writeBuffer->GetFirstElement(); // flush DMA buffer to ensure cache coherency // (only required for Cortex-M7) @@ -496,7 +488,7 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (readBuffer != nullptr) { // grab the pointer to the array by starting and the offset specified in the span - palI2c->ReadBuffer = (uint8_t *)readBuffer->GetElement(readOffset); + palI2c->ReadBuffer = (uint8_t *)readBuffer->GetFirstElement(); } // because the bus access is shared, acquire the appropriate bus diff --git a/targets/ChibiOS/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp b/targets/ChibiOS/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp index 3e692909a7..75b5eb6e31 100644 --- a/targets/ChibiOS/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp +++ b/targets/ChibiOS/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp @@ -27,7 +27,6 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ CLR_RT_HeapBlock_Array *buffer; uint8_t *bufferData = nullptr; int16_t bufferSize = 0; - int16_t bufferOffset = 0; uint32_t crc32 = 0; uint32_t hash = 0; @@ -41,12 +40,9 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ // get buffer buffer = bufferSpanByte[Span::FIELD___array].DereferenceArray(); - // Get the write offset - bufferOffset = bufferSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written bufferSize = bufferSpanByte[Span::FIELD___length].NumericByRef().s4; - bufferData = (unsigned char *)buffer->GetElement(bufferOffset); + bufferData = (unsigned char *)buffer->GetFirstElement(); crcAquireModule(); diff --git a/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp b/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp index c627603c53..1fa731ee27 100644 --- a/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp @@ -221,7 +221,6 @@ HRESULT Library_sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice:: NF_PAL_I2CSLAVE *palI2c = nullptr; - int32_t bufferOffset = 0; int32_t requestedCount = 0; uint32_t readCount = 0; uint32_t bytesTransfered = 0; @@ -271,9 +270,6 @@ HRESULT Library_sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice:: // set flag to read operation isRead = true; - // Get the read offset, only the elements defined by the span must be read, not the whole array - bufferOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as read size, only the elements defined by the span must be read requestedCount = readSpanByte[Span::FIELD___length].NumericByRef().s4; } @@ -284,9 +280,6 @@ HRESULT Library_sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice:: if (writeBuffer != nullptr) { - // Get the write offset, only the elements defined by the span must be written, not the whole array - bufferOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written requestedCount = writeSpanByte[Span::FIELD___length].NumericByRef().s4; } @@ -384,7 +377,7 @@ HRESULT Library_sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice:: // write operation // copy buffer content to working buffer - memcpy(palI2c->Buffer, (uint8_t *)writeBuffer->GetElement(bufferOffset), requestedCount); + memcpy(palI2c->Buffer, (uint8_t *)writeBuffer->GetFirstElement(), requestedCount); if (requestedCount < I2C_SLAVE_TX_BUF_LEN) { diff --git a/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index cfdf86b87f..f317ba80ad 100644 --- a/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -136,9 +136,7 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: uint8_t *writeBuffer = nullptr; uint8_t *readBuffer = nullptr; - int writeOffset = 0; int writeSize = 0; - int readOffset = 0; int readSize = 0; esp_err_t opResult; uint32_t transferResult; @@ -179,9 +177,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (writeData != nullptr) { - // Get the write offset, only the elements defined by the span must be written, not the whole array - writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written writeSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; @@ -196,7 +191,7 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: } // copy buffer content - memcpy(writeBuffer, (uint8_t *)writeData->GetElement(writeOffset), writeSize); + memcpy(writeBuffer, (uint8_t *)writeData->GetFirstElement(), writeSize); // setup write transaction i2c_master_start(cmd); @@ -218,9 +213,6 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (readData != nullptr) { - // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as read size, only the elements defined by the span must be read readSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; diff --git a/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp b/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp index c988cd0c6c..cf8da95c5a 100644 --- a/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.I2s/sys_dev_i2s_native_System_Device_I2s_I2sDevice.cpp @@ -364,7 +364,6 @@ HRESULT Library_sys_dev_i2s_native_System_Device_I2s_I2sDevice::Read___VOID__Sys CLR_RT_HeapBlock_Array *readBuffer = nullptr; uint8_t *readData = nullptr; int readSize = 0; - int readOffset = 0; uint8_t transform_buffer[SIZEOF_TRANSFORM_BUFFER_IN_BYTES]; uint32_t a_index = 0; @@ -400,15 +399,12 @@ HRESULT Library_sys_dev_i2s_native_System_Device_I2s_I2sDevice::Read___VOID__Sys if (readBuffer != nullptr) { - // Get the read offset, only the elements defined by the span must be read, not the whole array - readOffset = readSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as read size, only the elements defined by the span must be read readSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; if (readSize > 0) { - readData = (uint8_t *)readBuffer->GetElement(readOffset); + readData = (uint8_t *)readBuffer->GetFirstElement(); uint32_t num_bytes_needed_from_dma = readSize * (I2S_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes); @@ -485,7 +481,6 @@ HRESULT Library_sys_dev_i2s_native_System_Device_I2s_I2sDevice::Write___VOID__Sy CLR_RT_HeapBlock_Array *writeBuffer = nullptr; uint8_t *writeData = nullptr; int writeSize = 0; - int writeOffset = 0; size_t bytesWritten; esp_err_t opResult; @@ -516,16 +511,13 @@ HRESULT Library_sys_dev_i2s_native_System_Device_I2s_I2sDevice::Write___VOID__Sy if (writeBuffer != nullptr) { - // Get the write offset, only the elements defined by the span must be written, not the whole array - writeOffset = writeSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written writeSize = writeSpanByte[Span::FIELD___length].NumericByRef().s4; if (writeSize > 0) { CLR_RT_ProtectFromGC gcWriteBuffer(*writeBuffer); - writeData = (unsigned char *)writeBuffer->GetElement(writeOffset); + writeData = (unsigned char *)writeBuffer->GetFirstElement(); if (bitsPerSample == I2S_BITS_PER_SAMPLE_32BIT) { diff --git a/targets/ESP32/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp b/targets/ESP32/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp index a3670ad705..6871a99569 100644 --- a/targets/ESP32/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp +++ b/targets/ESP32/_nanoCLR/nanoFramework.System.IO.Hashing/nf_sys_io_hashing_System_IO_Hashing_Crc32.cpp @@ -17,7 +17,6 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ CLR_RT_HeapBlock_Array *buffer; uint8_t *bufferData = nullptr; int16_t bufferSize = 0; - int16_t bufferOffset = 0; uint32_t crc32 = 0; uint32_t hash = 0; @@ -31,12 +30,9 @@ HRESULT Library_nf_sys_io_hashing_System_IO_Hashing_Crc32::ComputeHash___STATIC_ // get buffer buffer = bufferSpanByte[Span::FIELD___array].DereferenceArray(); - // Get the write offset - bufferOffset = bufferSpanByte[Span::FIELD___start].NumericByRef().s4; - // use the span length as write size, only the elements defined by the span must be written bufferSize = bufferSpanByte[Span::FIELD___length].NumericByRef().s4; - bufferData = (unsigned char *)buffer->GetElement(bufferOffset); + bufferData = (unsigned char *)buffer->GetFirstElement(); #ifdef ESP_ROM_HAS_CRC_LE From 8c140deb344623575bec68f08ff02c8894c7298d Mon Sep 17 00:00:00 2001 From: "nfbot[bot]" Date: Fri, 5 Sep 2025 15:12:54 +0100 Subject: [PATCH 57/61] Code style fixes (#164) Automated fixes for code style. --- .../sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp b/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp index 3a65207658..d96468594d 100644 --- a/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp +++ b/src/System.Device.Spi/sys_dev_spi_native_System_Device_Spi_SpiDevice.cpp @@ -162,7 +162,7 @@ HRESULT Library_sys_dev_spi_native_System_Device_Spi_SpiDevice::NativeTransfer( readBuffer = readSpanByte[Span::FIELD___array].DereferenceArray(); if (readBuffer != nullptr) { - // use the span length as read size, only the elements defined by the span must be read + // use the span length as read size, only the elements defined by the span must be read readSize = readSpanByte[Span::FIELD___length].NumericByRef().s4; readData = (unsigned char *)readBuffer->GetFirstElement(); From 197503c0c0cfc0b8d7e68e796d82dc9329530cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Tue, 9 Sep 2025 13:52:19 +0100 Subject: [PATCH 58/61] Fix compiler warning --- src/CLR/Core/Execution.cpp | 2 +- src/CLR/Core/TypeSystem.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index f56d9f80aa..b16f9b485f 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2096,7 +2096,7 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( if (methodDefInstance.genericType && methodDefInstance.genericType->data != 0) { CLR_RT_TypeSpec_Instance typeSpec{}; - typeSpec.InitializeFromIndex((CLR_RT_TypeSpec_Index)methodDefInstance.genericType->data); + typeSpec.InitializeFromIndex((const CLR_RT_TypeSpec_Index&)methodDefInstance.genericType->data); typeSpec.assembly->FindGenericParamAtTypeSpec( methodDefInstance.genericType->TypeSpec(), diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index b534a296e9..41575c38ca 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1648,7 +1648,6 @@ bool CLR_RT_MethodDef_Instance::ResolveToken( const CLR_RT_TypeSpec_Index *definitiveTypeSpec = useCaller ? callerGeneric : methodOwnerTS; genericType = (CLR_RT_TypeSpec_Index *)definitiveTypeSpec; - CLR_INDEX tsAsmIdx = methodOwnerTS->Assembly(); CLR_RT_Assembly *methodAssembly = g_CLR_RT_TypeSystem.m_assemblies[methodOwnerTS->Assembly() - 1]; const CLR_RECORD_TYPESPEC *ts = methodAssembly->GetTypeSpec(methodOwnerTS->TypeSpec()); From b99fad96c87f8423fc2f8450f627d552f147c563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Tue, 9 Sep 2025 17:02:46 +0100 Subject: [PATCH 59/61] Fix resolving token from TypeSpec when creating an array - Now passing to secondary resolution in TypeDef. - Create array now accepts TypeSpec reflection and parses TypeSpec from reflection inside. --- src/CLR/Core/CLR_RT_HeapBlock_Array.cpp | 27 ++++++++++++++++++++++--- src/CLR/Core/TypeSystem.cpp | 6 ++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp index cff9b96fb7..a5293a8987 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp @@ -18,6 +18,8 @@ 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{}; + CLR_RT_ReflectionDef_Index workingReflex = reflex; reference.SetObjectReference(nullptr); @@ -26,12 +28,31 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( if (reflex.kind != REFLECTION_TYPE) { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_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); + } } - if (reflex.levels == 1) + if (workingReflex.levels == 1) { - cls = reflex.data.type; + cls = workingReflex.data.type; } else { diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 41575c38ca..57bee990d8 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1054,10 +1054,8 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( if (elem.Levels > 0) { - // this is an array - data = elem.Class.data; - assembly = g_CLR_RT_TypeSystem.m_assemblies[elem.Class.Assembly() - 1]; - target = assembly->GetTypeDef(elem.Class.Type()); + // this is an array, can't init like this + return false; } else { From f9b3f21697dbebf1c392b34b0e776d090a95cc65 Mon Sep 17 00:00:00 2001 From: "nfbot[bot]" Date: Tue, 9 Sep 2025 17:05:50 +0100 Subject: [PATCH 60/61] Code style fixes (#165) Automated fixes for code style. --- src/CLR/Core/Execution.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index b16f9b485f..e31e66e3be 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -2096,7 +2096,8 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( if (methodDefInstance.genericType && methodDefInstance.genericType->data != 0) { CLR_RT_TypeSpec_Instance typeSpec{}; - typeSpec.InitializeFromIndex((const CLR_RT_TypeSpec_Index&)methodDefInstance.genericType->data); + typeSpec.InitializeFromIndex( + (const CLR_RT_TypeSpec_Index &)methodDefInstance.genericType->data); typeSpec.assembly->FindGenericParamAtTypeSpec( methodDefInstance.genericType->TypeSpec(), From f46021b3e8deddc882a35074ef2827e1524c8638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Tue, 9 Sep 2025 17:31:36 +0100 Subject: [PATCH 61/61] Missed previous commit --- ...ys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp | 2 +- .../sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp b/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp index 1fa731ee27..e758206b3e 100644 --- a/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.I2c.Slave/sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice.cpp @@ -471,7 +471,7 @@ HRESULT Library_sys_dev_i2c_slave_native_System_Device_I2c_I2cSlaveDevice:: { // copy over to the managed buffer // grab the pointer to the array by starting and the offset specified in the span - memcpy(readBuffer->GetElement(bufferOffset), palI2c->Buffer, bytesTransfered); + memcpy(readBuffer->GetFirstElement(), palI2c->Buffer, bytesTransfered); } // pop read count from the stack diff --git a/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp index f317ba80ad..74d1c3a8ea 100644 --- a/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp +++ b/targets/ESP32/_nanoCLR/System.Device.I2c/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -287,7 +287,7 @@ HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: if (readSize > 0) { // grab the pointer to the array by starting and the offset specified in the span - memcpy(readData->GetElement(readOffset), readBuffer, readSize); + memcpy(readData->GetFirstElement(), readBuffer, readSize); } result[I2cTransferResult::FIELD___status].SetInteger((CLR_UINT32)I2cTransferStatus_FullTransfer);