diff --git a/src/CLR/CorLib/corlib_native.cpp b/src/CLR/CorLib/corlib_native.cpp index 34d3d4dd95..0c8b5532cb 100644 --- a/src/CLR/CorLib/corlib_native.cpp +++ b/src/CLR/CorLib/corlib_native.cpp @@ -696,6 +696,10 @@ static const CLR_RT_MethodHandler method_lookup[] = Library_corlib_native_System_Random::_ctor___VOID, Library_corlib_native_System_Random::_ctor___VOID__I4, nullptr, + Library_corlib_native_System_ReadOnlySpan_1::_ctor___VOID__VOIDptr__I4, + nullptr, + nullptr, + nullptr, nullptr, nullptr, nullptr, @@ -711,6 +715,14 @@ static const CLR_RT_MethodHandler method_lookup[] = 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, @@ -798,6 +810,7 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + Library_corlib_native_System_Span_1::_ctor___VOID__VOIDptr__I4, nullptr, nullptr, nullptr, @@ -827,6 +840,10 @@ static const CLR_RT_MethodHandler method_lookup[] = nullptr, nullptr, nullptr, + nullptr, + nullptr, + nullptr, + nullptr, Library_corlib_native_System_Threading_AutoResetEvent::_ctor___VOID__BOOLEAN, Library_corlib_native_System_Threading_AutoResetEvent::Reset___BOOLEAN, Library_corlib_native_System_Threading_AutoResetEvent::Set___BOOLEAN, @@ -1596,7 +1613,7 @@ const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_mscorlib = #if (NANOCLR_REFLECTION == TRUE) - 0x3C34952A, + 0xCECAB752, #elif (NANOCLR_REFLECTION == FALSE) diff --git a/src/CLR/CorLib/corlib_native.h b/src/CLR/CorLib/corlib_native.h index 7305b59f69..bbeea04d69 100644 --- a/src/CLR/CorLib/corlib_native.h +++ b/src/CLR/CorLib/corlib_native.h @@ -783,6 +783,7 @@ struct Library_corlib_native_System_ReadOnlySpan_1 static const int FIELD___array = 1; static const int FIELD___length = 2; + NANOCLR_NATIVE_DECLARE(_ctor___VOID__VOIDptr__I4); NANOCLR_NATIVE_DECLARE(NativeReadOnlySpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4); //--// @@ -962,6 +963,7 @@ struct Library_corlib_native_System_Span_1 static const int FIELD___array = 1; static const int FIELD___length = 2; + NANOCLR_NATIVE_DECLARE(_ctor___VOID__VOIDptr__I4); 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 index b3dcd53119..a87a3d6ebb 100644 --- a/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp +++ b/src/CLR/CorLib/corlib_native_System_ReadOnlySpan_1.cpp @@ -6,6 +6,105 @@ #include "CorLib.h" +typedef Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers RuntimeHelpers; + +HRESULT Library_corlib_native_System_ReadOnlySpan_1::_ctor___VOID__VOIDptr__I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int32_t length; + bool isRefContainsRefs = false; + uintptr_t objectRawPointer; + + CLR_RT_HeapBlock *thisSpan = stack.This(); + + // grab caller to get the generic type + CLR_RT_MethodDef_Instance &caller = stack.MethodCall(); + + if (caller.genericType == nullptr || !NANOCLR_INDEX_IS_VALID(*caller.genericType)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + CLR_RT_TypeSpec_Instance typeSpec; + if (!typeSpec.InitializeFromIndex(*caller.genericType)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + CLR_RT_SignatureParser parser; + parser.Initialize_TypeSpec(typeSpec); + + CLR_RT_SignatureParser::Element element; + + if (FAILED(parser.Advance(element))) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + // The first element should be the generic type instantiation + if (element.DataType != DATATYPE_GENERICINST) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + // Advance to get the generic argument (T) + if (FAILED(parser.Advance(element))) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + if (element.DataType == DATATYPE_VALUETYPE) + { + // For value types we need to advance again + if (FAILED(parser.Advance(element))) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + } + + // check if T is a reference type or contains references + NANOCLR_CHECK_HRESULT( + RuntimeHelpers::CheckReferenceOrContainsReferences( + element.Class, + element.DataType, + &parser, + isRefContainsRefs)); + + if (isRefContainsRefs) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + // validate length parameter + length = stack.Arg2().NumericByRefConst().s4; + + if (length < 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + // get the pointer to the array + // validate data type as being an unmanaged pointer + if (stack.Arg1().DataType() != DATATYPE_PTR) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + objectRawPointer = (uintptr_t)stack.Arg1().UnmanagedPointer(); + + { + CLR_RT_HeapBlock &refArray = thisSpan[FIELD___array]; + NANOCLR_CHECK_HRESULT( + CLR_RT_HeapBlock_Array::CreateInstanceWithStorage(refArray, length, objectRawPointer, element.Class)); + } + + // set length + thisSpan[FIELD___length].NumericByRef().s4 = length; + + NANOCLR_NOCLEANUP(); +} + HRESULT Library_corlib_native_System_ReadOnlySpan_1::NativeReadOnlySpanConstructor___VOID__SZARRAY_GENERICTYPE__I4__I4( CLR_RT_StackFrame &stack) { @@ -16,7 +115,6 @@ HRESULT Library_corlib_native_System_ReadOnlySpan_1::NativeReadOnlySpanConstruct 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(); @@ -24,29 +122,23 @@ HRESULT Library_corlib_native_System_ReadOnlySpan_1::NativeReadOnlySpanConstruct 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(); + // get type of the source array + NANOCLR_CHECK_HRESULT(descDst.InitializeFromObject(*sourceArray)); + descDst.GetElementType(descDst); - // protect from GC - CLR_RT_ProtectFromGC gc1(*sourceArray); - CLR_RT_ProtectFromGC gc2(refArray); + sourceType.data = descDst.m_handlerCls.data; - // copy array - CLR_RT_HeapBlock_Array::Copy(sourceArray, start, destinationArray, 0, length); + { + // get the pointer to the element at start address + uintptr_t ptrToStartElement = (uintptr_t)sourceArray->GetElement(start); - // set length - thisSpan[FIELD___length].NumericByRef().s4 = length; + CLR_RT_HeapBlock &refArray = thisSpan[FIELD___array]; + NANOCLR_CHECK_HRESULT( + CLR_RT_HeapBlock_Array::CreateInstanceWithStorage(refArray, length, ptrToStartElement, sourceType)); } + // 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 e9cebde926..be28aca598 100644 --- a/src/CLR/CorLib/corlib_native_System_Span_1.cpp +++ b/src/CLR/CorLib/corlib_native_System_Span_1.cpp @@ -6,6 +6,105 @@ #include "CorLib.h" +typedef Library_corlib_native_System_Runtime_CompilerServices_RuntimeHelpers RuntimeHelpers; + +HRESULT Library_corlib_native_System_Span_1::_ctor___VOID__VOIDptr__I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int32_t length; + bool isRefContainsRefs = false; + uintptr_t objectRawPointer; + + CLR_RT_HeapBlock *thisSpan = stack.This(); + + // grab caller to get the generic type + CLR_RT_MethodDef_Instance &caller = stack.MethodCall(); + + if (caller.genericType == nullptr || !NANOCLR_INDEX_IS_VALID(*caller.genericType)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + CLR_RT_TypeSpec_Instance typeSpec; + if (!typeSpec.InitializeFromIndex(*caller.genericType)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + CLR_RT_SignatureParser parser; + parser.Initialize_TypeSpec(typeSpec); + + CLR_RT_SignatureParser::Element element; + + if (FAILED(parser.Advance(element))) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + // The first element should be the generic type instantiation + if (element.DataType != DATATYPE_GENERICINST) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + // Advance to get the generic argument (T) + if (FAILED(parser.Advance(element))) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + + if (element.DataType == DATATYPE_VALUETYPE) + { + // For value types we need to advance again + if (FAILED(parser.Advance(element))) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + } + + // check if T is a reference type or contains references + NANOCLR_CHECK_HRESULT( + RuntimeHelpers::CheckReferenceOrContainsReferences( + element.Class, + element.DataType, + &parser, + isRefContainsRefs)); + + if (isRefContainsRefs) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + // validate length parameter + length = stack.Arg2().NumericByRefConst().s4; + + if (length < 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + // get the pointer to the array + // validate data type as being an unmanaged pointer + if (stack.Arg1().DataType() != DATATYPE_PTR) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + objectRawPointer = (uintptr_t)stack.Arg1().UnmanagedPointer(); + + { + CLR_RT_HeapBlock &refArray = thisSpan[FIELD___array]; + NANOCLR_CHECK_HRESULT( + CLR_RT_HeapBlock_Array::CreateInstanceWithStorage(refArray, length, objectRawPointer, element.Class)); + } + + // set length + thisSpan[FIELD___length].NumericByRef().s4 = length; + + NANOCLR_NOCLEANUP(); +} + HRESULT Library_corlib_native_System_Span_1::CopyTo___VOID__SystemSpan_1(CLR_RT_StackFrame &stack) { NANOCLR_HEADER(); @@ -26,27 +125,20 @@ HRESULT Library_corlib_native_System_Span_1::CopyTo___VOID__SystemSpan_1(CLR_RT_ destinationArray = destinationSpan[FIELD___array].DereferenceArray(); { - // prevent GC from moving the arrays while we copy the data - if (sourceArray) + // sanity check for empty source array + if (sourceSpan[FIELD___length].NumericByRefConst().s4 == 0) { - CLR_RT_ProtectFromGC gc1(*sourceArray); - } - if (destinationArray) - { - CLR_RT_ProtectFromGC gc2(*destinationArray); + NANOCLR_SET_AND_LEAVE(S_OK); } - // does the source array has a reference? - if (sourceArray && destinationArray) - { - // copy array - CLR_RT_HeapBlock_Array::Copy( - sourceArray, - 0, - destinationArray, - 0, - sourceSpan[FIELD___length].NumericByRefConst().s4); - } + // prevent GC from moving the arrays while we copy the data + CLR_RT_ProtectFromGC gc1(*sourceArray); + CLR_RT_ProtectFromGC gc2(*destinationArray); + + memmove( + destinationArray->GetElement(0), + sourceArray->GetElement(0), + sourceSpan[FIELD___length].NumericByRefConst().s4 * sourceArray->m_sizeOfElement); } NANOCLR_NOCLEANUP(); @@ -62,7 +154,6 @@ HRESULT Library_corlib_native_System_Span_1::NativeSpanConstructor___VOID__SZARR 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(); @@ -70,29 +161,23 @@ HRESULT Library_corlib_native_System_Span_1::NativeSpanConstructor___VOID__SZARR 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); + // get type of the source array + NANOCLR_CHECK_HRESULT(descDst.InitializeFromObject(*sourceArray)); + descDst.GetElementType(descDst); - sourceType.data = descDst.m_handlerCls.data; + 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); + { + // get the pointer to the element at start address + uintptr_t ptrToStartElement = (uintptr_t)sourceArray->GetElement(start); - // set length - thisSpan[FIELD___length].NumericByRef().s4 = length; + CLR_RT_HeapBlock &refArray = thisSpan[FIELD___array]; + NANOCLR_CHECK_HRESULT( + CLR_RT_HeapBlock_Array::CreateInstanceWithStorage(refArray, length, ptrToStartElement, sourceType)); } + // set length + thisSpan[FIELD___length].NumericByRef().s4 = length; + NANOCLR_NOCLEANUP(); } diff --git a/src/CLR/Core/CLR_RT_HeapBlock.cpp b/src/CLR/Core/CLR_RT_HeapBlock.cpp index ae1877f779..23d900075f 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock.cpp @@ -641,6 +641,14 @@ HRESULT CLR_RT_HeapBlock::StoreToReference(CLR_RT_HeapBlock &ref, int size) { obj = &ref; } + else if (dt == DATATYPE_PTR) + { + // unmanaged pointer, perform a direct memory move as the addresses can overlap + memmove((void *)ref.UnmanagedPointer(), (void *)&NumericByRef(), size); + + // Nothing to assign back to a HeapBlock in this case + NANOCLR_SET_AND_LEAVE(S_OK); + } else { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); @@ -1466,6 +1474,9 @@ bool CLR_RT_HeapBlock::ObjectsEqual( objLeft->m_sizeOfElement == objRight->m_sizeOfElement && objLeft->m_typeOfElement == objRight->m_typeOfElement) { + // check that array is not stored in stack + ASSERT(objLeft->m_StoragePointer == 0); + if (!objLeft->m_fReference) { if (memcmp( @@ -2073,6 +2084,20 @@ HRESULT CLR_RT_HeapBlock::NumericAdd(const CLR_RT_HeapBlock &right) } break; + case DATATYPE_PTR: + if (right.DataType() == DATATYPE_I4) + { + // binary numeric add (byte wise) (ECMA-335 Table III.2) + uint8_t *unmanagedPtr = (uint8_t *)UnmanagedPointer(); + unmanagedPtr += right.NumericByRefConst().s4; + + SetUnmanagedPointer((uintptr_t)unmanagedPtr); + + break; + } + // fall through, can't add other types to a PTR + [[fallthrough]]; + default: NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -2159,6 +2184,21 @@ HRESULT CLR_RT_HeapBlock::NumericSub(const CLR_RT_HeapBlock &right) m_data.arrayReference.index -= right.m_data.numeric.s4 / array->m_sizeOfElement; } break; + + case DATATYPE_PTR: + if (right.DataType() == DATATYPE_I4) + { + // binary numeric sub (byte wise) (ECMA-335 Table III.2) + uint8_t *unmanagedPtr = (uint8_t *)UnmanagedPointer(); + unmanagedPtr -= right.NumericByRefConst().s4; + + SetUnmanagedPointer((uintptr_t)unmanagedPtr); + + break; + } + // fall through, can't subtract other types to a PTR + [[fallthrough]]; + default: NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } diff --git a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp index c655986912..59514fa169 100644 --- a/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp +++ b/src/CLR/Core/CLR_RT_HeapBlock_Array.cpp @@ -24,7 +24,7 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( if ((CLR_INT32)length < 0) NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); - if (reflex.kind != REFLECTION_TYPE) + if (reflex.kind != REFLECTION_TYPE && reflex.kind != REFLECTION_STORAGE_PTR) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -57,7 +57,12 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( reference.SetObjectReference(pArray); - NANOCLR_SET_AND_LEAVE(pArray->ClearElements(0, length)); + // only clear elements if they belong to the array + // don't do it when they are stored elsewhere + if (reflex.kind != REFLECTION_STORAGE_PTR) + { + NANOCLR_SET_AND_LEAVE(pArray->ClearElements(0, length)); + } } NANOCLR_NOCLEANUP(); @@ -82,12 +87,43 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( NANOCLR_NOCLEANUP(); } +HRESULT CLR_RT_HeapBlock_Array::CreateInstanceWithStorage( + CLR_RT_HeapBlock &reference, + CLR_UINT32 length, + const uintptr_t storageAddress, + const CLR_RT_TypeDef_Index &cls) +{ + NATIVE_PROFILE_CLR_CORE(); + NANOCLR_HEADER(); + + CLR_RT_HeapBlock_Array *thisArray; + CLR_RT_ReflectionDef_Index reflex; + + reflex.kind = REFLECTION_STORAGE_PTR; + reflex.levels = 1; + reflex.data.type = cls; + + // create an instance with ZERO length because there is no need to allocate storage + NANOCLR_CHECK_HRESULT(CreateInstance(reference, 0, reflex)); + + thisArray = reference.DereferenceArray(); + + // set the storage + thisArray->m_StoragePointer = storageAddress; + + // adjust the number of elements with the provided length + thisArray->m_numOfElements = length; + + NANOCLR_NOCLEANUP(); +} + HRESULT CLR_RT_HeapBlock_Array::CreateInstance( CLR_RT_HeapBlock &reference, CLR_UINT32 length, CLR_RT_Assembly *assm, CLR_UINT32 tk, - const CLR_RT_MethodDef_Instance *caller) + const CLR_RT_MethodDef_Instance *caller, + const CLR_RT_TypeSpec_Index *contextTypeSpec) { NATIVE_PROFILE_CLR_CORE(); NANOCLR_HEADER(); @@ -98,7 +134,7 @@ HRESULT CLR_RT_HeapBlock_Array::CreateInstance( memset(&ref, 0, sizeof(struct CLR_RT_HeapBlock)); - if (cls.ResolveToken(tk, assm, caller)) + if (cls.ResolveToken(tk, assm, caller, contextTypeSpec)) { NANOCLR_CHECK_HRESULT(ref.SetReflection(cls)); } @@ -132,6 +168,12 @@ HRESULT CLR_RT_HeapBlock_Array::ClearElements(int index, int length) const CLR_RT_ReflectionDef_Index &reflex = ReflectionDataConst(); CLR_UINT8 *data = GetElement(index); + // sanity check + if (IsStoragePointer()) + { + NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); + } + CLR_RT_Memory::ZeroFill(data, length * m_sizeOfElement); if (m_fReference) @@ -345,6 +387,9 @@ HRESULT CLR_RT_HeapBlock_Array::Copy( if (!arraySrc->m_fReference) { + // check that array is not stored in stack + ASSERT(arraySrc->m_StoragePointer == 0); + memmove(dataDst, dataSrc, length * sizeElem); } else diff --git a/src/CLR/Core/CLR_RT_StackFrame.cpp b/src/CLR/Core/CLR_RT_StackFrame.cpp index 3a6678dd2e..e11e5be5ee 100644 --- a/src/CLR/Core/CLR_RT_StackFrame.cpp +++ b/src/CLR/Core/CLR_RT_StackFrame.cpp @@ -120,6 +120,14 @@ HRESULT CLR_RT_StackFrame::Push(CLR_RT_Thread *th, const CLR_RT_MethodDef_Instan // // Initialize generic type context storage to invalid stack->m_genericTypeSpecStorage.Clear(); + + // initialize localloc elements + stack->m_localAllocCount = 0; + for (CLR_INT32 i = 0; i < CLR_RT_StackFrame::c_Max_Localloc_Count; i++) + { + stack->m_localAllocs[i] = 0; + } + // #ifndef NANOCLR_NO_IL_INLINE stack->m_inlineFrame = nullptr; @@ -323,6 +331,11 @@ bool CLR_RT_StackFrame::PushInline( m_inlineFrame->m_frame.m_call = m_call; m_inlineFrame->m_frame.m_evalStack = m_evalStack; m_inlineFrame->m_frame.m_evalPos = pThis; + m_inlineFrame->m_frame.m_localAllocCount = m_localAllocCount; + for (CLR_INT32 i = 0; i < c_Max_Localloc_Count; i++) + { + m_inlineFrame->m_frame.m_localAllocs[i] = m_localAllocs[i]; + } // increment the evalPos pointer so that we don't corrupt the real stack evalPos++; @@ -338,6 +351,13 @@ bool CLR_RT_StackFrame::PushInline( m_IPstart = ip; m_IP = ip; + // initialize localloc for the inline frame + m_localAllocCount = 0; + for (CLR_INT32 i = 0; i < c_Max_Localloc_Count; i++) + { + m_localAllocs[i] = 0; + } + if (md->localsCount) { g_CLR_RT_ExecutionEngine.InitializeLocals(m_locals, calleeInst); @@ -412,6 +432,11 @@ void CLR_RT_StackFrame::RestoreFromInlineStack() m_IPstart = m_inlineFrame->m_frame.m_IPStart; m_evalStack = m_inlineFrame->m_frame.m_evalStack; m_evalStackPos = m_inlineFrame->m_frame.m_evalPos; + m_localAllocCount = m_inlineFrame->m_frame.m_localAllocCount; + for (CLR_INT32 i = 0; i < c_Max_Localloc_Count; i++) + { + m_localAllocs[i] = m_inlineFrame->m_frame.m_localAllocs[i]; + } } void CLR_RT_StackFrame::RestoreStack(CLR_RT_InlineFrame &frame) @@ -424,6 +449,11 @@ void CLR_RT_StackFrame::RestoreStack(CLR_RT_InlineFrame &frame) m_evalStack = frame.m_evalStack; m_evalStackPos = frame.m_evalPos; m_evalStackEnd -= m_call.target->localsCount; + m_localAllocCount = frame.m_localAllocCount; + for (CLR_INT32 i = 0; i < c_Max_Localloc_Count; i++) + { + m_localAllocs[i] = frame.m_localAllocs[i]; + } } void CLR_RT_StackFrame::SaveStack(CLR_RT_InlineFrame &frame) @@ -435,6 +465,11 @@ void CLR_RT_StackFrame::SaveStack(CLR_RT_InlineFrame &frame) frame.m_IPStart = m_IPstart; frame.m_evalPos = m_evalStackPos; frame.m_evalStack = m_evalStack; + frame.m_localAllocCount = m_localAllocCount; + for (CLR_INT32 i = 0; i < c_Max_Localloc_Count; i++) + { + frame.m_localAllocs[i] = m_localAllocs[i]; + } } #endif @@ -822,6 +857,14 @@ void CLR_RT_StackFrame::Pop() { NATIVE_PROFILE_CLR_CORE(); + // Clear localloc references before popping + for (CLR_INT32 i = 0; i < m_localAllocCount; i++) + { + platform_free((void *)m_localAllocs[i]); + m_localAllocs[i] = 0; + } + m_localAllocCount = 0; + #if defined(NANOCLR_PROFILE_NEW_CALLS) { // diff --git a/src/CLR/Core/Execution.cpp b/src/CLR/Core/Execution.cpp index 9d5d87f078..456f5d99d1 100644 --- a/src/CLR/Core/Execution.cpp +++ b/src/CLR/Core/Execution.cpp @@ -1716,6 +1716,7 @@ CLR_RT_HeapBlock *CLR_RT_ExecutionEngine::ExtractHeapBlocksForArray( pArray->m_typeOfElement = dt; pArray->m_sizeOfElement = dtl.m_sizeInBytes; pArray->m_fReference = (dtl.m_flags & CLR_RT_DataTypeLookup::c_Numeric) == 0; + pArray->m_StoragePointer = 0; #if defined(NANOCLR_PROFILE_NEW_ALLOCATIONS) g_CLR_PRF_Profiler.TrackObjectCreation(pArray); @@ -2360,13 +2361,20 @@ HRESULT CLR_RT_ExecutionEngine::InitializeLocals( if (NANOCLR_INDEX_IS_VALID(methodDefInstance.methodSpec)) { CLR_RT_MethodSpec_Instance methodSpec; + CLR_RT_SignatureParser::Element element; + if (!methodSpec.InitializeFromIndex(methodDefInstance.methodSpec)) { NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); } // Use GetGenericArgument to get the concrete type from MethodSpec's signature - if (!methodSpec.GetGenericArgument(genericParamPosition, cls, dt)) + if (methodSpec.GetGenericArgument(genericParamPosition, element)) + { + cls = element.Class; + dt = element.DataType; + } + else { NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); } diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index 10e8a2b2fb..87d1b4abc3 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -1100,25 +1100,25 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) { // Capture stack position before opcode execution evalPosBeforeOp = evalPos; - + const CLR_RT_OpcodeLookup &opcodeInfo = c_CLR_RT_OpcodeLookup[op]; CLR_INT32 stackPop = opcodeInfo.StackPop(); CLR_INT32 stackPush = opcodeInfo.StackPush(); CLR_INT32 stackChange = opcodeInfo.StackChanges(); - + // Skip validation for opcodes with variable stack behavior (VarPop/VarPush) // These include CEE_CALL, CEE_CALLVIRT, CEE_RET, CEE_NEWOBJ which have stack // changes that depend on method signatures and cannot be validated statically // Note: VarPop and VarPush are both encoded as 0, so check if EITHER is 0 bool isVariableStackOp = (stackPop == 0 || stackPush == 0); - + if (!isVariableStackOp) { // Validate we have enough items on stack for this opcode to pop // evalPos points to the slot AFTER the top item, so &evalPos[0] is top item // stack->m_evalStack is the base, so (evalPos - stack->m_evalStack) is current depth CLR_INT32 currentDepth = (CLR_INT32)(evalPos - stack->m_evalStack) + 1; - + if (stackPop > 0 && currentDepth < (CLR_INT32)stackPop) { // Stack underflow: trying to pop more items than available @@ -1130,13 +1130,13 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) (int)currentDepth); NANOCLR_SET_AND_LEAVE(CLR_E_STACK_UNDERFLOW); } - + // Validate we have enough space for items this opcode will push // After popping stackPop items and pushing stackPush items, new depth will be: // currentDepth - stackPop + stackPush = currentDepth + stackChange CLR_INT32 projectedDepth = currentDepth + stackChange; CLR_INT32 maxDepth = (CLR_INT32)(stack->m_evalStackEnd - stack->m_evalStack); - + if (projectedDepth > maxDepth) { // Stack overflow: would exceed maximum stack depth @@ -1872,6 +1872,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) evalPos[2].Promote(); NANOCLR_CHECK_HRESULT(evalPos[2].StoreToReference(evalPos[1], size)); + break; } @@ -2524,7 +2525,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) { // Inline return - skip stack validation as the context is restored by PopInline() #if defined(NANOCLR_OPCODE_STACKCHANGES) - evalPosBeforeOp = nullptr; // Disable post-validation for inline return + evalPosBeforeOp = nullptr; // Disable post-validation for inline return #endif stack->m_evalStackPos = evalPos; @@ -3131,7 +3132,25 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) evalPos++; CHECKSTACK(stack, evalPos); - evalPos[0].SetReference(*ptr); + // check if field has RVA + CLR_RT_FieldDef_Instance inst; + if (inst.InitializeFromIndex(field) && (inst.target->flags & CLR_RECORD_FIELDDEF::FD_HasFieldRVA) && + inst.target->defaultValue != CLR_EmptyIndex) + { + CLR_PMETADATA ptrSrc; + + // Get the data from the Signatures table (this contains the raw byte array) + ptrSrc = inst.assembly->GetSignature(inst.target->defaultValue); + CLR_UINT32 dummyVar; + NANOCLR_READ_UNALIGNED_UINT16(dummyVar, ptrSrc); + + evalPos[0].SetUnmanagedPointer((uintptr_t)ptrSrc); + } + else + { + evalPos[0].SetReference(*ptr); + } + break; } @@ -3446,7 +3465,13 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) for (int pass = 0; pass < 2; pass++) { - hr = CLR_RT_HeapBlock_Array::CreateInstance(evalPos[0], size, assm, arg, &stack->m_call); + hr = CLR_RT_HeapBlock_Array::CreateInstance( + evalPos[0], + size, + assm, + arg, + &stack->m_call, + &stack->m_genericTypeSpecStorage); if (SUCCEEDED(hr)) { break; @@ -4267,6 +4292,86 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) //----------------------------------------------------------------------------------------------------------// + OPDEF(CEE_LOCALLOC, "localloc", PopI, PushI, InlineNone, IPrimitive, 2, 0xFE, 0x0F, NEXT) + { + CLR_INT32 sizeRaw = evalPos[0].NumericByRef().s4; + + if (sizeRaw < 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + CLR_UINT32 size = (CLR_UINT32)sizeRaw; + + evalPos--; + CHECKSTACK(stack, evalPos); + + // check if we have room for another localloc + if (stack->m_localAllocCount >= CLR_RT_StackFrame::c_Max_Localloc_Count) + { + NANOCLR_SET_AND_LEAVE(CLR_E_STACK_OVERFLOW); + } + + // allocate from platform heap + uintptr_t allocPointer = (uintptr_t)platform_malloc(size); + + // sanity check + if (allocPointer == 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY); + } + + // per ECMA-335 zero-initialize the memory + memset((void *)allocPointer, 0, size); + + // store the pointer to the local allocated memory + stack->m_localAllocs[stack->m_localAllocCount++] = allocPointer; + + evalPos++; + CHECKSTACK(stack, evalPos); + + // store the pointer of the local allocated memory + evalPos[0].SetUnmanagedPointer(allocPointer); + + break; + } + + //----------------------------------------------------------------------------------------------------------// + + OPDEF(CEE_CPBLK, "cpblk", PopI + PopI + PopI, Push0, InlineNone, IPrimitive, 2, 0xFE, 0x17, NEXT) + { + // Stack: ... ... -> ... + + // get size + CLR_UINT32 size = evalPos[0].NumericByRef().u4; + evalPos--; + + // get source address +#ifdef _WIN64 + uintptr_t sourceAddress = evalPos[0].NumericByRef().s8; +#else + uintptr_t sourceAddress = evalPos[0].NumericByRef().s4; +#endif + evalPos--; + + // get destination address +#ifdef _WIN64 + uintptr_t destinationAddress = evalPos[0].NumericByRef().s8; +#else + uintptr_t destinationAddress = evalPos[0].NumericByRef().s4; +#endif + evalPos--; + + CHECKSTACK(stack, evalPos); + + // perform memory move as addresses may overlap + memmove((void *)destinationAddress, (const void *)sourceAddress, size); + + break; + } + + //----------------------------------------------------------------------------------------------------------// + ////////////////////////////////////////////////////////////////////////////////////////// // // These opcodes do nothing... @@ -4275,6 +4380,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) OPDEF(CEE_UNALIGNED, "unaligned.", Pop0, Push0, ShortInlineI, IPrefix, 2, 0xFE, 0x12, META) OPDEF(CEE_VOLATILE, "volatile.", Pop0, Push0, InlineNone, IPrefix, 2, 0xFE, 0x13, META) OPDEF(CEE_TAILCALL, "tail.", Pop0, Push0, InlineNone, IPrefix, 2, 0xFE, 0x14, META) + OPDEF(CEE_READONLY, "readonly.", Pop0, Push0, InlineNone, IPrefix, 2, 0xFE, 0x1E, META) break; ////////////////////////////////////////////////////////////////////////////////////////// @@ -4282,16 +4388,13 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) // Unsupported opcodes... // OPDEF(CEE_ARGLIST, "arglist", Pop0, PushI, InlineNone, IPrimitive, 2, 0xFE, 0x00, NEXT) - OPDEF(CEE_CPBLK, "cpblk", PopI + PopI + PopI, Push0, InlineNone, IPrimitive, 2, 0xFE, 0x17, NEXT) OPDEF(CEE_JMP, "jmp", Pop0, Push0, InlineMethod, IPrimitive, 1, 0xFF, 0x27, CALL) OPDEF(CEE_INITBLK, "initblk", PopI + PopI + PopI, Push0, InlineNone, IPrimitive, 2, 0xFE, 0x18, NEXT) OPDEF(CEE_CALLI, "calli", VarPop, VarPush, InlineSig, IPrimitive, 1, 0xFF, 0x29, CALL) OPDEF(CEE_CKFINITE, "ckfinite", Pop1, PushR8, InlineNone, IPrimitive, 1, 0xFF, 0xC3, NEXT) - OPDEF(CEE_LOCALLOC, "localloc", PopI, PushI, InlineNone, IPrimitive, 2, 0xFE, 0x0F, NEXT) OPDEF(CEE_MKREFANY, "mkrefany", PopI, Push1, InlineType, IPrimitive, 1, 0xFF, 0xC6, NEXT) OPDEF(CEE_REFANYTYPE, "refanytype", Pop1, PushI, InlineNone, IPrimitive, 2, 0xFE, 0x1D, NEXT) OPDEF(CEE_REFANYVAL, "refanyval", Pop1, PushI, InlineType, IPrimitive, 1, 0xFF, 0xC2, NEXT) - OPDEF(CEE_READONLY, "readonly.", Pop0, Push0, InlineNone, IPrefix, 2, 0xFE, 0x1E, META) NANOCLR_CHECK_HRESULT(CLR_Checks::VerifyUnsupportedInstruction(op)); break; @@ -4305,33 +4408,34 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) } #if defined(NANOCLR_OPCODE_STACKCHANGES) - // Post-execution validation: verify stack depth changed by expected amount - if (op != CEE_PREFIX1 && evalPosBeforeOp != nullptr) - { - const CLR_RT_OpcodeLookup &opcodeInfo = c_CLR_RT_OpcodeLookup[op]; - CLR_INT32 expectedChange = opcodeInfo.StackChanges(); - CLR_INT32 actualChange = (CLR_INT32)(evalPos - evalPosBeforeOp); - - if (actualChange != expectedChange) + // Post-execution validation: verify stack depth changed by expected amount + if (op != CEE_PREFIX1 && evalPosBeforeOp != nullptr) { - // Stack depth mismatch: opcode didn't change stack as expected - CLR_Debug::Printf( - "STACK DEPTH MISMATCH POST-CHECK: Opcode %s (0x%X) expected change %d but actual change was %d\r\n", - opcodeInfo.Name(), - (int)op, - (int)expectedChange, - (int)actualChange); - CLR_Debug::Printf( - " Stack before: %d items, after: %d items\r\n", - (int)(evalPosBeforeOp - stack->m_evalStack) + 1, - (int)(evalPos - stack->m_evalStack) + 1); - - // This is a critical error indicating a bug in the opcode implementation - NANOCLR_SET_AND_LEAVE(CLR_E_STACK_UNDERFLOW); + const CLR_RT_OpcodeLookup &opcodeInfo = c_CLR_RT_OpcodeLookup[op]; + CLR_INT32 expectedChange = opcodeInfo.StackChanges(); + CLR_INT32 actualChange = (CLR_INT32)(evalPos - evalPosBeforeOp); + + if (actualChange != expectedChange) + { + // Stack depth mismatch: opcode didn't change stack as expected + CLR_Debug::Printf( + "STACK DEPTH MISMATCH POST-CHECK: Opcode %s (0x%X) expected change %d but actual change was " + "%d\r\n", + opcodeInfo.Name(), + (int)op, + (int)expectedChange, + (int)actualChange); + CLR_Debug::Printf( + " Stack before: %d items, after: %d items\r\n", + (int)(evalPosBeforeOp - stack->m_evalStack) + 1, + (int)(evalPos - stack->m_evalStack) + 1); + + // This is a critical error indicating a bug in the opcode implementation + NANOCLR_SET_AND_LEAVE(CLR_E_STACK_UNDERFLOW); + } + + evalPosBeforeOp = nullptr; } - - evalPosBeforeOp = nullptr; - } #endif #if defined(NANOCLR_ENABLE_SOURCELEVELDEBUGGING) diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 7f5db4e53e..b9d81189e1 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -540,6 +540,16 @@ HRESULT CLR_RT_SignatureParser::Advance(Element &res) switch (res.DataType) { + case ELEMENT_TYPE_CMOD_REQD: + case ELEMENT_TYPE_CMOD_OPT: + // Consume the modifier type token (TypeDefOrRef coded index) + // Format: CMOD_REQD/OPT + token + actual_type + // We don't need to do anything with the modifier itself, + // just skip it to get to the actual type + CLR_TkFromStream(Signature); + // Continue loop to read the actual element type + break; + case DATATYPE_BYREF: if (res.IsByRef) { @@ -1157,7 +1167,8 @@ void CLR_RT_TypeDef_Instance::ClearInstance() bool CLR_RT_TypeDef_Instance::ResolveToken( CLR_UINT32 tk, CLR_RT_Assembly *assm, - const CLR_RT_MethodDef_Instance *caller) + const CLR_RT_MethodDef_Instance *caller, + const CLR_RT_TypeSpec_Index *contextTypeSpec) { NATIVE_PROFILE_CLR_CORE(); @@ -1226,6 +1237,8 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( CLR_RT_SignatureParser parser; parser.Initialize_TypeSpec(assm, ts); + CLR_INDEX genericPosition; + CLR_RT_SignatureParser::Element elem; if (FAILED(parser.Advance(elem))) { @@ -1275,13 +1288,30 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( } } + genericPosition = elem.GenericParamPosition; + // If it's a type‐generic slot (!T), resolve against the caller's closed generic if (elem.DataType == DATATYPE_VAR) { - int pos = elem.GenericParamPosition; + // Determine the effective generic type context + // Prefer explicit contextTypeSpec over caller->genericType + const CLR_RT_TypeSpec_Index *effectiveContext = nullptr; + + if (contextTypeSpec != nullptr && NANOCLR_INDEX_IS_VALID(*contextTypeSpec)) + { + effectiveContext = contextTypeSpec; + } + else if (caller != nullptr && NANOCLR_INDEX_IS_VALID(*caller->genericType)) + { + effectiveContext = caller->genericType; + } + else + { + return false; + } CLR_RT_TypeSpec_Instance callerTypeSpec; - if (!callerTypeSpec.InitializeFromIndex(*caller->genericType)) + if (!callerTypeSpec.InitializeFromIndex(*effectiveContext)) { return false; } @@ -1289,7 +1319,7 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( CLR_RT_SignatureParser::Element paramElement; // Try to map using the generic context (e.g. !T→Int32) - if (callerTypeSpec.GetGenericParam((CLR_UINT32)pos, paramElement)) + if (callerTypeSpec.GetGenericParam(genericPosition, paramElement)) { // Successfully resolved from generic context if (NANOCLR_INDEX_IS_VALID(paramElement.Class)) @@ -1300,32 +1330,10 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( } else if (paramElement.DataType == DATATYPE_MVAR) { - // resolve from methodspec context - if (NANOCLR_INDEX_IS_VALID(caller->methodSpec)) - { - CLR_RT_MethodSpec_Instance methodSpecInstance; - if (methodSpecInstance.InitializeFromIndex(caller->methodSpec)) - { - NanoCLRDataType dataType; - CLR_RT_TypeDef_Index typeDef; - methodSpecInstance.GetGenericArgument( - paramElement.GenericParamPosition, - typeDef, - dataType); - - data = typeDef.data; - assembly = g_CLR_RT_TypeSystem.m_assemblies[typeDef.Assembly() - 1]; - target = assembly->GetTypeDef(typeDef.Type()); - } - else - { - return false; - } - } - else - { - return false; - } + // need to defer to generic method argument + genericPosition = paramElement.GenericParamPosition; + + goto resolve_generic_argument; } else if (paramElement.DataType == DATATYPE_VAR) { @@ -1338,7 +1346,7 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( return false; } } - else if (NANOCLR_INDEX_IS_VALID(caller->arrayElementType) && pos == 0) + else if (NANOCLR_INDEX_IS_VALID(caller->arrayElementType) && genericPosition == 0) { // Fallback to arrayElementType for SZArrayHelper scenarios data = caller->arrayElementType.data; @@ -1352,20 +1360,61 @@ bool CLR_RT_TypeDef_Instance::ResolveToken( } else if (elem.DataType == DATATYPE_MVAR) { + resolve_generic_argument: + // Use the caller bound genericType (Stack, etc.) - if (caller == nullptr || caller->genericType == nullptr) + if (caller == nullptr || NANOCLR_INDEX_IS_INVALID(*caller->genericType)) { return false; } - CLR_RT_GenericParam_Index gpIdx; - caller->assembly->FindGenericParamAtMethodDef(*caller, elem.GenericParamPosition, gpIdx); + // resolve from methodspec context + if (NANOCLR_INDEX_IS_VALID(caller->methodSpec)) + { + CLR_RT_MethodSpec_Instance methodSpecInstance; + if (methodSpecInstance.InitializeFromIndex(caller->methodSpec)) + { + CLR_RT_SignatureParser::Element element; + + if (!methodSpecInstance.GetGenericArgument(genericPosition, element)) + { + return false; + } + + if (element.DataType == DATATYPE_VAR) + { + // need to defer to generic type parameter + CLR_RT_TypeSpec_Instance contextTs; + if (!contextTypeSpec || !contextTs.InitializeFromIndex(*contextTypeSpec)) + { + return false; + } - auto &gp = caller->assembly->crossReferenceGenericParam[gpIdx.GenericParam()]; + if (!contextTs.GetGenericParam(element.GenericParamPosition, element)) + { + return false; + } + } + else if (element.DataType == DATATYPE_MVAR) + { + // nested MVAR not implemented + ASSERT(false); + return false; + } - data = gp.classTypeDef.data; - assembly = g_CLR_RT_TypeSystem.m_assemblies[gp.classTypeDef.Assembly() - 1]; - target = assembly->GetTypeDef(gp.classTypeDef.Type()); + data = element.Class.data; + assembly = g_CLR_RT_TypeSystem.m_assemblies[element.Class.Assembly() - 1]; + target = assembly->GetTypeDef(element.Class.Type()); + } + else + { + return false; + } + } + else + { + return false; + } } } } @@ -2230,8 +2279,7 @@ void CLR_RT_MethodSpec_Instance::ClearInstance() bool CLR_RT_MethodSpec_Instance::GetGenericArgument( CLR_INT32 argumentPosition, - CLR_RT_TypeDef_Index &typeDef, - NanoCLRDataType &dataType) + CLR_RT_SignatureParser::Element &element) { CLR_RT_SignatureParser parser; parser.Initialize_MethodSignature(this); @@ -2242,20 +2290,15 @@ bool CLR_RT_MethodSpec_Instance::GetGenericArgument( return false; } - CLR_RT_SignatureParser::Element elem; - // loop through parameters to find the desired one for (CLR_INT32 i = 0; i <= argumentPosition; i++) { - if (FAILED(parser.Advance(elem))) + if (FAILED(parser.Advance(element))) { return false; } } - typeDef = elem.Class; - dataType = elem.DataType; - return true; } @@ -5660,7 +5703,10 @@ HRESULT CLR_RT_Assembly::AllocateGenericStaticFieldsOnDemand( { CLR_RT_HeapBlock_Delegate *dlg = refDlg.DereferenceDelegate(); - // Store the TypeSpec index so the .cctor can resolve type generic parameters + // Developer notes: + // - Store the TypeSpec index so the .cctor can resolve type generic parameters + // - Use the typeSpecIndex which represents the closed generic type being initialized + // NOT the caller's context which may be non-generic dlg->m_genericTypeSpec = typeSpecIndex; // Store the caller's MethodSpec (if any) to enable reolution of method generic parameters @@ -7583,14 +7629,50 @@ HRESULT CLR_RT_TypeSystem::BuildTypeName( if (NANOCLR_INDEX_IS_VALID(contextMethodDef->methodSpec)) { CLR_RT_MethodSpec_Instance methodSpec{}; + CLR_RT_SignatureParser::Element paramElement; + CLR_RT_TypeDef_Index paramTypeDef; methodSpec.InitializeFromIndex(contextMethodDef->methodSpec); - if (!methodSpec.GetGenericArgument(element.GenericParamPosition, typeDef, element.DataType)) + if (!methodSpec.GetGenericArgument(element.GenericParamPosition, paramElement)) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } - NANOCLR_CHECK_HRESULT(BuildTypeName(typeDef, szBuffer, iBuffer)); + paramTypeDef = paramElement.Class; + + if (paramElement.DataType == DATATYPE_VAR) + { + // Build the type name for this generic argument + // Use the method's declaring type as context for VAR resolution + + CLR_RT_TypeSpec_Instance contextTs; + CLR_RT_SignatureParser::Element argElement; + + // try to resolve from method context + if (!contextTs.InitializeFromIndex(*contextMethodDef->genericType)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); + } + + if (contextTs.GetGenericParam(paramElement.GenericParamPosition, argElement)) + { + paramTypeDef = argElement.Class; + + goto output_type; + } + else + { + // Couldn't resolve + char encodedParam[7]; + snprintf(encodedParam, ARRAYSIZE(encodedParam), "!%d", argElement.GenericParamPosition); + NANOCLR_CHECK_HRESULT(QueueStringToBuffer(szBuffer, iBuffer, encodedParam)); + } + } + else + { + output_type: + NANOCLR_CHECK_HRESULT(BuildTypeName(paramTypeDef, szBuffer, iBuffer)); + } } } else @@ -7814,28 +7896,14 @@ HRESULT CLR_RT_TypeSystem::BuildMethodName( NANOCLR_CHECK_HRESULT(BuildTypeName(instOwner, szBuffer, iBuffer)); CLR_SafeSprintf(szBuffer, iBuffer, "::%s", mdInst.assembly->GetString(mdInst.target->name)); - } else { // First, build the type name (either from genericType or from the method's declaring type) - if (genericType != nullptr && NANOCLR_INDEX_IS_VALID(*genericType) && genericType->data != CLR_EmptyToken) + if (mdInst.genericType != nullptr && NANOCLR_INDEX_IS_VALID(*mdInst.genericType)) { - // Use the provided generic type context - if (!SUCCEEDED(BuildTypeName(*genericType, szBuffer, iBuffer, 0, nullptr, &mdInst))) - { - // Fall back to the declaring type - if (instOwner.InitializeFromMethod(mdInst) == false) - { - NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); - } - NANOCLR_CHECK_HRESULT(BuildTypeName(instOwner, szBuffer, iBuffer)); - } - } - else if (mdInst.genericType != nullptr && NANOCLR_INDEX_IS_VALID(*mdInst.genericType)) - { - // Use the method instance's generic type - if (!SUCCEEDED(BuildTypeName(*mdInst.genericType, szBuffer, iBuffer, 0))) + // Use the method's genericType and pass itself as context to resolve VAR parameters + if (FAILED(BuildTypeName(*mdInst.genericType, szBuffer, iBuffer, 0, mdInst.genericType, &mdInst))) { // Fall back to the declaring type if (instOwner.InitializeFromMethod(mdInst) == false) @@ -7883,53 +7951,32 @@ HRESULT CLR_RT_TypeSystem::BuildMethodName( CLR_SafeSprintf(szBuffer, iBuffer, ", "); } - // Build the type name for this generic argument - // Use the method's declaring type as context for VAR resolution - const CLR_RT_TypeSpec_Index *context = - (mdInst.genericType && NANOCLR_INDEX_IS_VALID(*mdInst.genericType)) ? mdInst.genericType - : nullptr; - - if (elem.DataType == DATATYPE_VAR || elem.DataType == DATATYPE_MVAR) + if (elem.DataType == DATATYPE_VAR) { - // Generic parameter - try to resolve it - if (context != nullptr) - { - CLR_RT_TypeSpec_Instance contextTs; - if (!contextTs.InitializeFromIndex(*context)) - { - NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); - } + // Build the type name for this generic argument + // Use the method's declaring type as context for VAR resolution - CLR_RT_SignatureParser::Element paramElement; - if (contextTs.GetGenericParam(elem.GenericParamPosition, paramElement)) - { - NANOCLR_CHECK_HRESULT(BuildTypeName(paramElement.Class, szBuffer, iBuffer)); - } - else - { - // Couldn't resolve - show as !n or !!n - if (elem.DataType == DATATYPE_VAR) - { - CLR_SafeSprintf(szBuffer, iBuffer, "!%d", elem.GenericParamPosition); - } - else - { - CLR_SafeSprintf(szBuffer, iBuffer, "!!%d", elem.GenericParamPosition); - } - } + CLR_RT_TypeSpec_Instance contextTs; + CLR_RT_SignatureParser::Element paramElement; + + // try to resolve from method context + if (!contextTs.InitializeFromIndex(*genericType)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); } - else + + if (!contextTs.GetGenericParam(elem.GenericParamPosition, paramElement)) { - // No context - show as !n or !!n - if (elem.DataType == DATATYPE_VAR) - { - CLR_SafeSprintf(szBuffer, iBuffer, "!%d", elem.GenericParamPosition); - } - else - { - CLR_SafeSprintf(szBuffer, iBuffer, "!!%d", elem.GenericParamPosition); - } + // Couldn't resolve + CLR_SafeSprintf(szBuffer, iBuffer, "!%d", elem.GenericParamPosition); + continue; } + + NANOCLR_CHECK_HRESULT(BuildTypeName(paramElement.Class, szBuffer, iBuffer)); + } + else if (elem.DataType == DATATYPE_MVAR) + { + CLR_SafeSprintf(szBuffer, iBuffer, "!!%d", elem.GenericParamPosition); } else if (NANOCLR_INDEX_IS_VALID(elem.Class)) { @@ -8478,6 +8525,7 @@ CLR_UINT32 CLR_RT_TypeSystem::ComputeHashForClosedGenericType( { CLR_UINT32 hash = 0; int argCount; + CLR_INDEX genericPosition; // Start with the generic type definition hash = SUPPORT_ComputeCRC(&typeInstance.genericTypeDef.data, sizeof(CLR_UINT32), hash); @@ -8511,9 +8559,14 @@ CLR_UINT32 CLR_RT_TypeSystem::ComputeHashForClosedGenericType( break; } + // copy generic position + genericPosition = elem.GenericParamPosition; + // Check if this is an unresolved generic parameter (VAR or MVAR) if (elem.DataType == DATATYPE_VAR && contextTypeSpec && NANOCLR_INDEX_IS_VALID(*contextTypeSpec)) { + resolve_type_param: + // Resolve VAR (type parameter) from context TypeSpec CLR_RT_TypeSpec_Instance contextTs; if (!contextTs.InitializeFromIndex(*contextTypeSpec)) @@ -8523,7 +8576,7 @@ CLR_UINT32 CLR_RT_TypeSystem::ComputeHashForClosedGenericType( } CLR_RT_SignatureParser::Element paramElement; - if (contextTs.GetGenericParam(elem.GenericParamPosition, paramElement)) + if (contextTs.GetGenericParam(genericPosition, paramElement)) { // Use the resolved type from context hash = SUPPORT_ComputeCRC(¶mElement.DataType, sizeof(paramElement.DataType), hash); @@ -8547,13 +8600,22 @@ CLR_UINT32 CLR_RT_TypeSystem::ComputeHashForClosedGenericType( CLR_RT_MethodSpec_Instance methodSpecInst{}; if (methodSpecInst.InitializeFromIndex(contextMethod->methodSpec)) { - CLR_RT_TypeDef_Index resolvedTypeDef; - NanoCLRDataType resolvedDataType; + CLR_RT_SignatureParser::Element argElement; - if (methodSpecInst.GetGenericArgument(elem.GenericParamPosition, resolvedTypeDef, resolvedDataType)) + if (methodSpecInst.GetGenericArgument(genericPosition, argElement)) { + if (argElement.DataType == DATATYPE_VAR) + { + // need another pass to resolve a generic type parameter + + // copy generic parameter position + genericPosition = argElement.GenericParamPosition; + + goto resolve_type_param; + } + // Use the resolved type from MethodSpec - hash = SUPPORT_ComputeCRC(&resolvedDataType, sizeof(resolvedDataType), hash); + hash = SUPPORT_ComputeCRC(&argElement.DataType, sizeof(argElement.DataType), hash); } else { diff --git a/src/CLR/Debugger/Debugger.cpp b/src/CLR/Debugger/Debugger.cpp index 9265464b88..98e081ed8c 100644 --- a/src/CLR/Debugger/Debugger.cpp +++ b/src/CLR/Debugger/Debugger.cpp @@ -2429,10 +2429,11 @@ bool CLR_DBG_Debugger::Debugging_Thread_Get(WP_Message *msg) pRes[Library_corlib_native_System_Threading_Thread::FIELD___priority].NumericByRef().s4 = pri; - if (SUCCEEDED(CLR_RT_ObjectToEvent_Source::CreateInstance( - th, - *pRes, - pRes[Library_corlib_native_System_Threading_Thread::FIELD___thread]))) + if (SUCCEEDED( + CLR_RT_ObjectToEvent_Source::CreateInstance( + th, + *pRes, + pRes[Library_corlib_native_System_Threading_Thread::FIELD___thread]))) { #if defined(NANOCLR_APPDOMAINS) CLR_RT_ObjectToEvent_Source::CreateInstance( @@ -3065,6 +3066,11 @@ bool CLR_DBG_Debugger::Debugging_Value_GetArray(WP_Message *msg) { blk = (CLR_RT_HeapBlock *)array->GetElement(cmd->m_index); } + else if (array->m_StoragePointer != 0) + { + // TODO need to handle this case properly + ASSERT(FALSE); + } else { if (FAILED(tmp.LoadFromReference(ref))) diff --git a/src/CLR/Diagnostics/Diagnostics_stub.cpp b/src/CLR/Diagnostics/Diagnostics_stub.cpp index 24a4ace5e7..1cd6046570 100644 --- a/src/CLR/Diagnostics/Diagnostics_stub.cpp +++ b/src/CLR/Diagnostics/Diagnostics_stub.cpp @@ -112,7 +112,10 @@ __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) +__nfweak void CLR_RT_Assembly::DumpToken( + CLR_UINT32 tk, + const CLR_RT_MethodDef_Instance &methodDefInstance, + const CLR_RT_TypeSpec_Index *contextTypeSpec) { NATIVE_PROFILE_CLR_DIAGNOSTICS(); } diff --git a/src/CLR/Diagnostics/Info.cpp b/src/CLR/Diagnostics/Info.cpp index d48d0bc71e..d01eb47734 100644 --- a/src/CLR/Diagnostics/Info.cpp +++ b/src/CLR/Diagnostics/Info.cpp @@ -413,7 +413,10 @@ 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_MethodDef_Instance &methodDefInstance) +void CLR_RT_Assembly::DumpToken( + CLR_UINT32 token, + const CLR_RT_MethodDef_Instance &methodDefInstance, + const CLR_RT_TypeSpec_Index *contextTypeSpec) { NATIVE_PROFILE_CLR_DIAGNOSTICS(); CLR_UINT32 index = CLR_DataFromTk(token); @@ -547,6 +550,7 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_MethodDef_Instanc // Only if it is not a plain VAR/MVAR do we then check for arrays or else fall // back to BuildTypeName for the full concrete name. // + CLR_INDEX genericPosition; CLR_UINT32 ownerAsm = assemblyIndex; if (methodDefInstance.genericType != nullptr && NANOCLR_INDEX_IS_VALID(*methodDefInstance.genericType)) @@ -578,7 +582,13 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_MethodDef_Instanc char bufCorrupt[256]; char *pCorrupt = bufCorrupt; size_t cbCorrupt = sizeof(bufCorrupt); - g_CLR_RT_TypeSystem.BuildTypeName(tsIdx, pCorrupt, cbCorrupt, elem.Levels); + g_CLR_RT_TypeSystem.BuildTypeName( + tsIdx, + pCorrupt, + cbCorrupt, + elem.Levels, + methodDefInstance.genericType, + &methodDefInstance); CLR_Debug::Printf("%s", bufCorrupt); break; } @@ -593,80 +603,116 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_MethodDef_Instanc } } + genericPosition = elem.GenericParamPosition; + if (elem.DataType == DATATYPE_VAR) { - int gpPosition = elem.GenericParamPosition; + // Use contextTypeSpec if provided, otherwise fall back to methodDefInstance.genericType + const CLR_RT_TypeSpec_Index *effectiveContext = + (contextTypeSpec && NANOCLR_INDEX_IS_VALID(*contextTypeSpec)) ? contextTypeSpec + : methodDefInstance.genericType; - // 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)) + if (effectiveContext != nullptr && NANOCLR_INDEX_IS_VALID(*effectiveContext)) { CLR_RT_TypeSpec_Instance typeSpec; - if (!typeSpec.InitializeFromIndex(*methodDefInstance.genericType)) + if (!typeSpec.InitializeFromIndex(*effectiveContext)) { - CLR_Debug::Printf("!%d", gpPosition); + CLR_Debug::Printf("!%d", genericPosition); break; } CLR_RT_SignatureParser::Element paramElement; - if (typeSpec.GetGenericParam(gpPosition, paramElement)) + if (typeSpec.GetGenericParam(genericPosition, paramElement)) { - char bufArg[256]{}; - char *pArg = bufArg; - size_t cbArg = sizeof(bufArg); - - g_CLR_RT_TypeSystem.BuildTypeName( - paramElement.Class, - pArg, - cbArg, - CLR_RT_TypeSystem::TYPENAME_FLAGS_FULL, - elem.Levels); - - CLR_Debug::Printf("%s", bufArg); + // Successfully resolved from generic context + if (NANOCLR_INDEX_IS_VALID(paramElement.Class)) + { + char bufArg[256]{}; + char *pArg = bufArg; + size_t cbArg = sizeof(bufArg); + + g_CLR_RT_TypeSystem.BuildTypeName( + paramElement.Class, + pArg, + cbArg, + CLR_RT_TypeSystem::TYPENAME_FLAGS_FULL, + elem.Levels); + + CLR_Debug::Printf("%s", bufArg); + } + else if (paramElement.DataType == DATATYPE_MVAR) + { + // need to defer to generic method argument + genericPosition = paramElement.GenericParamPosition; - break; + goto resolve_generic_argument; + } + else if (paramElement.DataType == DATATYPE_VAR) + { + // nested VAR not implemented + ASSERT(false); + } } } // Couldn't resolve or caller was not generic: print "!n" literally - CLR_Debug::Printf("!%d", gpPosition); + CLR_Debug::Printf("!%d", genericPosition); break; } else if (elem.DataType == DATATYPE_MVAR) { - int gpPosition = elem.GenericParamPosition; + resolve_generic_argument: - // 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)) + if (NANOCLR_INDEX_IS_VALID(methodDefInstance.methodSpec)) { - 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_MethodSpec_Instance methodSpecInstance; + if (methodSpecInstance.InitializeFromIndex(methodDefInstance.methodSpec)) { - CLR_RT_GenericParam_CrossReference gp = - g_CLR_RT_TypeSystem.m_assemblies[methodDefInstance.genericType->Assembly() - 1] - ->crossReferenceGenericParam[gpIndex.GenericParam()]; + CLR_RT_SignatureParser::Element element; + + if (methodSpecInstance.GetGenericArgument(genericPosition, element)) + { + if (element.DataType == DATATYPE_VAR) + { + // need to defer to generic type parameter + CLR_RT_TypeSpec_Instance contextTs; + if (contextTypeSpec && contextTs.InitializeFromIndex(*contextTypeSpec)) + { + if (!contextTs.GetGenericParam(element.GenericParamPosition, element)) + { + CLR_Debug::Printf("!!%d", genericPosition); + + break; + } + } + } + else if (element.DataType == DATATYPE_MVAR) + { + // nested MVAR not implemented + ASSERT(false); + } - char bufArg[256]{}; - char *pArg = bufArg; - size_t cbArg = sizeof(bufArg); + 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); + g_CLR_RT_TypeSystem.BuildTypeName( + element.Class, + pArg, + cbArg, + CLR_RT_TypeSystem::TYPENAME_FLAGS_FULL, + elem.Levels); - CLR_Debug::Printf("%s", bufArg); + CLR_Debug::Printf("%s", bufArg); - break; + break; + } } } + // Couldn't resolve or caller was not generic: print "!!n" literally - CLR_Debug::Printf("!!%d", gpPosition); + CLR_Debug::Printf("!!%d", genericPosition); break; } @@ -722,7 +768,13 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_MethodDef_Instanc char bufArr[256]; char *pArr = bufArr; size_t cbArr = sizeof(bufArr); - g_CLR_RT_TypeSystem.BuildTypeName(tsIdx, pArr, cbArr, elem.Levels); + g_CLR_RT_TypeSystem.BuildTypeName( + tsIdx, + pArr, + cbArr, + elem.Levels, + methodDefInstance.genericType, + &methodDefInstance); CLR_Debug::Printf("%s", bufArr); break; } @@ -732,7 +784,13 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_MethodDef_Instanc char bufTypeName[256]; char *pTypeName = bufTypeName; size_t cbType = sizeof(bufTypeName); - g_CLR_RT_TypeSystem.BuildTypeName(tsIdx, pTypeName, cbType, elem.Levels); + g_CLR_RT_TypeSystem.BuildTypeName( + tsIdx, + pTypeName, + cbType, + elem.Levels, + methodDefInstance.genericType, + &methodDefInstance); CLR_Debug::Printf("%s", bufTypeName); break; } @@ -962,12 +1020,17 @@ void CLR_RT_Assembly::DumpOpcodeDirect( else { // In the unlikely case ResolveToken fails, fall back to raw DumpToken: - DumpToken(token, call); + DumpToken(token, call, nullptr); } } else { - DumpToken(token, call); + // Pass the stack's generic type storage as context for VAR resolution + const CLR_RT_TypeSpec_Index *context = + (NANOCLR_INDEX_IS_VALID(call) && call.genericType && NANOCLR_INDEX_IS_VALID(*call.genericType)) + ? call.genericType + : nullptr; + DumpToken(token, call, context); } } else diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index bcda8ff63b..55c995fcd6 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -1593,7 +1593,10 @@ struct CLR_RT_Assembly : public CLR_RT_HeapBlock_Node // EVENT HEAP - NO RELOCAT DECL_POSTFIX; private: - void DumpToken(CLR_UINT32 tk, const CLR_RT_MethodDef_Instance &methodDefInstance) DECL_POSTFIX; + void DumpToken( + CLR_UINT32 tk, + const CLR_RT_MethodDef_Instance &methodDefInstance, + const CLR_RT_TypeSpec_Index *contextTypeSpec) DECL_POSTFIX; void DumpSignature(CLR_SIG sig) DECL_POSTFIX; void DumpSignature(CLR_PMETADATA &p) DECL_POSTFIX; void DumpSignatureToken(CLR_PMETADATA &p) DECL_POSTFIX; @@ -2216,7 +2219,11 @@ 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 ResolveToken( + CLR_UINT32 tk, + CLR_RT_Assembly *assm, + const CLR_RT_MethodDef_Instance *caller = nullptr, + const CLR_RT_TypeSpec_Index *contextTypeSpec = nullptr); bool ResolveNullableType(CLR_UINT32 tk, CLR_RT_Assembly *assm, const CLR_RT_MethodDef_Instance *caller = nullptr); //--// @@ -2349,7 +2356,7 @@ struct CLR_RT_MethodSpec_Instance : public CLR_RT_MethodSpec_Index CLR_EncodedMethodDefOrRef InstanceOfMethod; - bool GetGenericArgument(CLR_INT32 argumentPosition, CLR_RT_TypeDef_Index &typeDef, NanoCLRDataType &dataType); + bool GetGenericArgument(CLR_INT32 argumentPosition, CLR_RT_SignatureParser::Element &element); }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -2529,6 +2536,9 @@ struct CLR_RT_HeapCluster : public CLR_RT_HeapBlock_Node // EVENT HEAP - NO RELO //--// +// maximum number of local allocations per stack frame +#define MAX_LOCALALLOC_COUNT 4 + #ifndef NANOCLR_NO_IL_INLINE struct CLR_RT_InlineFrame { @@ -2539,6 +2549,8 @@ struct CLR_RT_InlineFrame CLR_RT_MethodDef_Instance m_call; CLR_PMETADATA m_IP; CLR_PMETADATA m_IPStart; + CLR_UINT8 m_localAllocCount; + uintptr_t m_localAllocs[MAX_LOCALALLOC_COUNT]; }; struct CLR_RT_InlineBuffer @@ -2562,6 +2574,9 @@ struct CLR_RT_StackFrame : public CLR_RT_HeapBlock_Node // EVENT HEAP - NO RELOC static const int c_OverheadForNewObjOrInteropMethod = 2; static const int c_MinimumStack = 10; + // max mumber of local allocations per stack frame + static const int c_Max_Localloc_Count = MAX_LOCALALLOC_COUNT; + static const CLR_UINT32 c_MethodKind_Native = 0x00000000; static const CLR_UINT32 c_MethodKind_Interpreted = 0x00000001; static const CLR_UINT32 c_UNUSED_00000002 = 0x00000002; // c_MethodKind_Jitted @@ -2663,6 +2678,9 @@ struct CLR_RT_StackFrame : public CLR_RT_HeapBlock_Node // EVENT HEAP - NO RELOC bool m_fNativeProfiled; #endif + CLR_UINT8 m_localAllocCount; + uintptr_t m_localAllocs[c_Max_Localloc_Count]; + CLR_RT_HeapBlock m_extension[1]; //////////////////////////////////////// diff --git a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h index d9a22795b4..14719fe3c2 100644 --- a/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h +++ b/src/CLR/Include/nanoCLR_Runtime__HeapBlock.h @@ -760,6 +760,13 @@ struct CLR_RT_HeapBlock //--// + struct UnmanagedPointer + { + uintptr_t ptr; + } unmanagedPointer; + + //--// + } m_data; public: @@ -1078,7 +1085,9 @@ struct CLR_RT_HeapBlock CLR_RT_HeapBlock *obj = Dereference(); if (obj && obj->DataType() == DATATYPE_VALUETYPE && obj->IsBoxed() == false) + { return true; + } } return false; @@ -1096,6 +1105,19 @@ struct CLR_RT_HeapBlock //--// + void SetUnmanagedPointer(const uintptr_t ptr) + { + m_id.raw = CLR_RT_HEAPBLOCK_RAW_ID(DATATYPE_PTR, 0, 1); + m_data.unmanagedPointer.ptr = ptr; + } + + uintptr_t UnmanagedPointer() const + { + return (DataType() == DATATYPE_PTR) ? m_data.unmanagedPointer.ptr : 0; + } + + //--// + CLR_RT_HeapBlock_Array *RecoverArrayHeader() const { return (DataType() == DATATYPE_ARRAY_BYREF) ? m_data.arrayReference.array : nullptr; @@ -1837,6 +1859,7 @@ struct CLR_RT_HeapBlock_Array : public CLR_RT_HeapBlock CLR_UINT8 m_sizeOfElement; CLR_UINT8 m_fReference; CLR_UINT8 m_pad; + uintptr_t m_StoragePointer; //--// @@ -1850,11 +1873,24 @@ struct CLR_RT_HeapBlock_Array : public CLR_RT_HeapBlock CLR_UINT32 length, CLR_RT_Assembly *assm, CLR_UINT32 tk, - const CLR_RT_MethodDef_Instance *caller); + const CLR_RT_MethodDef_Instance *caller, + const CLR_RT_TypeSpec_Index *contextTypeSpec); + static HRESULT CreateInstanceWithStorage( + CLR_RT_HeapBlock &reference, + CLR_UINT32 length, + const uintptr_t storageAddress, + const CLR_RT_TypeDef_Index &cls); CLR_UINT8 *GetFirstElement() { - return ((CLR_UINT8 *)&this[1]); + if (ReflectionData().kind == REFLECTION_STORAGE_PTR) + { + return ((CLR_UINT8 *)this->m_StoragePointer); + } + else + { + return ((CLR_UINT8 *)&this[1]); + } } CLR_UINT8 *GetElement(CLR_UINT32 index) @@ -1864,7 +1900,14 @@ struct CLR_RT_HeapBlock_Array : public CLR_RT_HeapBlock CLR_UINT16 *GetFirstElementUInt16() { - return ((CLR_UINT16 *)&this[1]); + if (ReflectionData().kind == REFLECTION_STORAGE_PTR) + { + return ((CLR_UINT16 *)this->m_StoragePointer); + } + else + { + return ((CLR_UINT16 *)&this[1]); + } } CLR_UINT16 *GetElementUInt16(CLR_UINT32 index) @@ -1872,6 +1915,11 @@ struct CLR_RT_HeapBlock_Array : public CLR_RT_HeapBlock return GetFirstElementUInt16() + m_sizeOfElement * index; } + bool IsStoragePointer() + { + return (ReflectionData().kind == REFLECTION_STORAGE_PTR); + } + HRESULT ClearElements(int index, int length); //--// diff --git a/src/CLR/Include/nanoCLR_Types.h b/src/CLR/Include/nanoCLR_Types.h index 666106a2cc..d6e52a01af 100644 --- a/src/CLR/Include/nanoCLR_Types.h +++ b/src/CLR/Include/nanoCLR_Types.h @@ -518,6 +518,9 @@ enum NanoCLRDataType // KEEP IN SYNC WITH nanoCLR_DataType enum in nanoFramework DATATYPE_TYPE_PINNED = 0x05 | DATATYPE_TYPE_MODIFIER, DATATYPE_TYPE_R4_HFA = 0x06 | DATATYPE_TYPE_MODIFIER, // used only internally for R4 HFA types DATATYPE_TYPE_R8_HFA = 0x07 | DATATYPE_TYPE_MODIFIER, // used only internally for R8 HFA types + + // unamaged pointer + DATATYPE_PTR }; enum CLR_ReflectionType @@ -531,6 +534,7 @@ enum CLR_ReflectionType REFLECTION_FIELD = 0x06, REFLECTION_GENERICTYPE = 0x07, REFLECTION_TYPESPEC = 0x08, + REFLECTION_STORAGE_PTR = 0x09, }; ////////////////////////////////////////////////////////////////////////////////////////////////////