diff --git a/IL2C.Runtime/include/System/String.h b/IL2C.Runtime/include/System/String.h index 43dadf38..292c8554 100644 --- a/IL2C.Runtime/include/System/String.h +++ b/IL2C.Runtime/include/System/String.h @@ -95,7 +95,7 @@ typedef const struct // IL2C_REF_HEADER void* pNext; // Const string will not collect by GC, so this link is always NULL. IL2C_RUNTIME_TYPE type; // Const string always fixed runtime type pointer from "System_String_RUNTIME_TYPE__." - interlock_t characteristic; // Const string always marked (IL2C_CHARACTERISTIC_CONST) + interlock_t characteristic; // Const string always marked (IL2C_CHARACTERISTIC_CONST | IL2C_CHARACTERISTIC_INITIALIZED) // Instance's vptr System_String_VTABLE_DECL__* vptr0__; // Const string always fixed VTable pointer from "System_String_VTABLE__." @@ -105,7 +105,7 @@ typedef const struct #define IL2C_CONST_STRING(name, string_body) \ static IL2C_CONST_STRING_DECL name##_CONST_STRING__ = { \ - NULL, il2c_typeof(System_String), /* IL2C_CHARACTERISTIC_CONST */ (interlock_t)0x80000000UL, &System_String_VTABLE__, string_body }; \ + NULL, il2c_typeof(System_String), /* IL2C_CHARACTERISTIC_CONST | IL2C_CHARACTERISTIC_INITIALIZED */ (interlock_t)0xc0000000UL, &System_String_VTABLE__, string_body }; \ System_String* const name = ((System_String*)&(name##_CONST_STRING__.vptr0__)) #ifdef __cplusplus diff --git a/IL2C.Runtime/src/System/Array.c b/IL2C.Runtime/src/System/Array.c index ac41c4fb..da7ae328 100644 --- a/IL2C.Runtime/src/System/Array.c +++ b/IL2C.Runtime/src/System/Array.c @@ -66,25 +66,30 @@ System_Array* il2c_new_array__( il2c_assert(0); } - uintptr_t elementSize = il2c_sizeof__(elementType); + const uintptr_t elementSize = il2c_sizeof__(elementType); il2c_assert(elementSize >= 1); // -1 is "uint8_t Item[1]" - uintptr_t size = (uintptr_t)sizeof(System_Array) + ((uintptr_t)length) * elementSize; + const uintptr_t size = (uintptr_t)sizeof(System_Array) + ((uintptr_t)length) * elementSize; #if defined(IL2C_USE_LINE_INFORMATION) - System_Array* arr = il2c_get_uninitialized_object_internal__( + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__( il2c_typeof(System_Array), size, pFile, line); #else - System_Array* arr = il2c_get_uninitialized_object_internal__( + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__( il2c_typeof(System_Array), size); #endif - arr->vptr0__ = &System_Array_VTABLE__; + System_Array* arr = (System_Array*)(pHeader + 1); + + il2c_assert(arr->vptr0__ == &System_Array_VTABLE__); arr->elementType__ = elementType; arr->Length = length; + // Marked instance is initialized. (and will handle by GC) + il2c_ior(&pHeader->characteristic, IL2C_CHARACTERISTIC_INITIALIZED); + return arr; } diff --git a/IL2C.Runtime/src/System/Delegate.c b/IL2C.Runtime/src/System/Delegate.c index 08e99301..45df18bf 100644 --- a/IL2C.Runtime/src/System/Delegate.c +++ b/IL2C.Runtime/src/System/Delegate.c @@ -84,23 +84,29 @@ System_Delegate* System_Delegate_Combine(System_Delegate* a, System_Delegate* b) il2c_assert(0); } - uintptr_t count = a->count__ + b->count__; - uintptr_t size = sizeof(System_Delegate) + + const uintptr_t count = a->count__ + b->count__; + const uintptr_t size = sizeof(System_Delegate) + (uintptr_t)(count - 1 /* included System_Delegate */) * sizeof(IL2C_METHOD_TABLE); #if defined(IL2C_USE_LINE_INFORMATION) - System_Delegate* dlg = il2c_get_uninitialized_object_internal__(pHeaderA->type, size, __FILE__, __LINE__); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(pHeaderA->type, size, __FILE__, __LINE__); #else - System_Delegate* dlg = il2c_get_uninitialized_object_internal__(pHeaderA->type, size); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(pHeaderA->type, size); #endif - dlg->vptr0__ = &System_Delegate_VTABLE__; + System_Delegate* dlg = (System_Delegate*)(pHeader + 1); + + il2c_assert(dlg->vptr0__ == &System_Delegate_VTABLE__); dlg->count__ = count; + struct IL2C_METHOD_TABLE_DECL* pMethodtbl = (struct IL2C_METHOD_TABLE_DECL*)&dlg->methodtbl__[0]; memcpy(&pMethodtbl[0], &a->methodtbl__[0], a->count__ * sizeof(IL2C_METHOD_TABLE)); memcpy(&pMethodtbl[a->count__], &b->methodtbl__[0], b->count__ * sizeof(IL2C_METHOD_TABLE)); + // Marked instance is initialized. (and will handle by GC) + il2c_ior(&pHeader->characteristic, IL2C_CHARACTERISTIC_INITIALIZED); + return dlg; } @@ -159,12 +165,14 @@ System_Delegate* System_Delegate_Remove(System_Delegate* source, System_Delegate (uintptr_t)(count - 1 /* included System_Delegate */) * sizeof(IL2C_METHOD_TABLE); #if defined(IL2C_USE_LINE_INFORMATION) - System_Delegate* dlg = il2c_get_uninitialized_object_internal__(pHeaderSource->type, size, __FILE__, __LINE__); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(pHeaderSource->type, size, __FILE__, __LINE__); #else - System_Delegate* dlg = il2c_get_uninitialized_object_internal__(pHeaderSource->type, size); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(pHeaderSource->type, size); #endif - dlg->vptr0__ = &System_Delegate_VTABLE__; + System_Delegate* dlg = (System_Delegate*)(pHeader + 1); + + il2c_assert(dlg->vptr0__ == &System_Delegate_VTABLE__); dlg->count__ = count; @@ -172,6 +180,9 @@ System_Delegate* System_Delegate_Remove(System_Delegate* source, System_Delegate memcpy(&pMethodtbl[0], &source->methodtbl__[0], ((size_t)index) * sizeof(IL2C_METHOD_TABLE)); memcpy(&pMethodtbl[index], &source->methodtbl__[((uintptr_t)index) + value->count__], ((size_t)count - (size_t)index) * sizeof(IL2C_METHOD_TABLE)); + // Marked instance is initialized. (and will handle by GC) + il2c_ior(&pHeader->characteristic, IL2C_CHARACTERISTIC_INITIALIZED); + return dlg; } } @@ -195,19 +206,24 @@ System_Delegate* il2c_new_delegate__( il2c_assert(method != 0); #if defined(IL2C_USE_LINE_INFORMATION) - System_Delegate* dlg = il2c_get_uninitialized_object_internal__(delegateType, sizeof(System_Delegate), pFile, line); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(delegateType, sizeof(System_Delegate), pFile, line); #else - System_Delegate* dlg = il2c_get_uninitialized_object_internal__(delegateType, sizeof(System_Delegate)); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(delegateType, sizeof(System_Delegate)); #endif - dlg->vptr0__ = &System_Delegate_VTABLE__; - + System_Delegate* dlg = (System_Delegate*)(pHeader + 1); + + il2c_assert(dlg->vptr0__ == &System_Delegate_VTABLE__); + dlg->count__ = 1; struct IL2C_METHOD_TABLE_DECL* pMethodTbl = (struct IL2C_METHOD_TABLE_DECL*)&dlg->methodtbl__[0]; pMethodTbl->target = object; pMethodTbl->methodPtr = method; + // Marked instance is initialized. (and will handle by GC) + il2c_ior(&pHeader->characteristic, IL2C_CHARACTERISTIC_INITIALIZED); + return dlg; } diff --git a/IL2C.Runtime/src/System/String.c b/IL2C.Runtime/src/System/String.c index 624ae3d4..f243c469 100644 --- a/IL2C.Runtime/src/System/String.c +++ b/IL2C.Runtime/src/System/String.c @@ -38,10 +38,10 @@ static System_String* new_string_internal__(uintptr_t byteSize, const char* pFil static System_String* new_string_internal__(uintptr_t byteSize) #endif { - uintptr_t bodySize = sizeof(System_String) + byteSize; + const uintptr_t bodySize = sizeof(System_String) + byteSize; #if defined(IL2C_USE_LINE_INFORMATION) - System_String* pString = il2c_get_uninitialized_object_internal__( + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__( il2c_typeof(System_String), bodySize, pFile, line); #else @@ -50,9 +50,16 @@ static System_String* new_string_internal__(uintptr_t byteSize) bodySize); #endif - pString->vptr0__ = &System_String_VTABLE__; + System_String* pString = (System_String*)(pHeader + 1); + + il2c_assert(pString->vptr0__ == &System_String_VTABLE__); + wchar_t* string_body = (wchar_t*)(((uint8_t*)pString) + sizeof(System_String)); pString->string_body__ = string_body; + + // Marked instance is initialized. (and will handle by GC) + il2c_ior(&pHeader->characteristic, IL2C_CHARACTERISTIC_INITIALIZED); + return pString; } diff --git a/IL2C.Runtime/src/il2c.c b/IL2C.Runtime/src/il2c.c index a73bb890..e4558a17 100644 --- a/IL2C.Runtime/src/il2c.c +++ b/IL2C.Runtime/src/il2c.c @@ -56,11 +56,32 @@ const uintptr_t* il2c_initializer_count = &g_InitializerCount; ///////////////////////////////////////////////////////////// // Instance allocator functions +static void il2c_setup_interface_vptrs(IL2C_RUNTIME_TYPE type, void* pReference) +{ + il2c_assert(type != NULL); + il2c_assert(pReference != NULL); + + // Setup interface vptrs. + IL2C_IMPLEMENTED_INTERFACE* pInterface = + (IL2C_IMPLEMENTED_INTERFACE*)(((IL2C_MARK_TARGET*)(type + 1)) + type->markTarget); + uintptr_t index; + for (index = 0; + il2c_likely__(index < type->interfaceCount); + index++, pInterface++) + { + il2c_assert((pInterface->type->flags & IL2C_TYPE_INTERFACE) == IL2C_TYPE_INTERFACE); + + // The interface vptr offset placed at vptr[0]. + uintptr_t offset = *(const uintptr_t*)(pInterface->vptr0); + *((const void**)(((uint8_t*)pReference) + offset)) = pInterface->vptr0; + } +} + #if defined(IL2C_USE_LINE_INFORMATION) -void* il2c_get_uninitialized_object_internal__( +IL2C_REF_HEADER* il2c_get_uninitialized_object_internal__( IL2C_RUNTIME_TYPE type, uintptr_t bodySize, const char* pFile, int line) #else -void* il2c_get_uninitialized_object_internal__( +IL2C_REF_HEADER* il2c_get_uninitialized_object_internal__( IL2C_RUNTIME_TYPE type, uintptr_t bodySize) #endif { @@ -79,7 +100,8 @@ void* il2c_get_uninitialized_object_internal__( // | : | v // +----------------------+ ------- - IL2C_REF_HEADER* pHeader = (IL2C_REF_HEADER*)il2c_malloc(sizeof(IL2C_REF_HEADER) + bodySize); + const uintptr_t totalSize = sizeof(IL2C_REF_HEADER) + bodySize; + IL2C_REF_HEADER* pHeader = (IL2C_REF_HEADER*)il2c_malloc(totalSize); if (il2c_unlikely__(pHeader == NULL)) { while (1) @@ -92,7 +114,7 @@ void* il2c_get_uninitialized_object_internal__( #endif // Retry - pHeader = (IL2C_REF_HEADER*)il2c_malloc(sizeof(IL2C_REF_HEADER) + bodySize); + pHeader = (IL2C_REF_HEADER*)il2c_malloc(totalSize); if (il2c_likely__(pHeader != NULL)) { break; @@ -103,15 +125,22 @@ void* il2c_get_uninitialized_object_internal__( } } - void* pReference = ((uint8_t*)pHeader) + sizeof(IL2C_REF_HEADER); // Guarantee cleared body - memset(pReference, 0, bodySize); + memset((void*)pHeader, 0, totalSize); + // Set RTTI. pHeader->type = type; // HACK: Current GC mark status is same as g_CollectionMarkIndex__, it means "Marked." pHeader->characteristic = g_CollectionMarkIndex__; + // Setup vptr0. + void* pReference = ((uint8_t*)pHeader) + sizeof(IL2C_REF_HEADER); + *((const void**)pReference) = type->vptr0; + + // Setup interface vptrs. + il2c_setup_interface_vptrs(type, pReference); + // Safe link both headers. while (1) { @@ -123,28 +152,10 @@ void* il2c_get_uninitialized_object_internal__( } } - return pReference; -} - -static void il2c_setup_interface_vptrs(IL2C_RUNTIME_TYPE type, void* pReference) -{ - il2c_assert(type != NULL); - il2c_assert(pReference != NULL); - - // Setup interface vptrs. - IL2C_IMPLEMENTED_INTERFACE* pInterface = - (IL2C_IMPLEMENTED_INTERFACE*)(((IL2C_MARK_TARGET*)(type + 1)) + type->markTarget); - uintptr_t index; - for (index = 0; - il2c_likely__(index < type->interfaceCount); - index++, pInterface++) - { - il2c_assert((pInterface->type->flags & IL2C_TYPE_INTERFACE) == IL2C_TYPE_INTERFACE); + // NOTE: Enter critical section for partially construted instance. + // IL2C will make the mark IL2C_CHARACTERISTIC_INITIALIZED. - // The interface vptr offset placed at vptr[0]. - uintptr_t offset = *(const uintptr_t*)(pInterface->vptr0); - *((const void**)(((uint8_t*)pReference) + offset)) = pInterface->vptr0; - } + return pHeader; } #if defined(IL2C_USE_LINE_INFORMATION) @@ -163,18 +174,15 @@ void* il2c_get_uninitialized_object__(IL2C_RUNTIME_TYPE type) // Allocate heap memory. #if defined(IL2C_USE_LINE_INFORMATION) - uint8_t* pReference = il2c_get_uninitialized_object_internal__(type, type->bodySize, pFile, line); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(type, type->bodySize, pFile, line); #else - uint8_t* pReference = il2c_get_uninitialized_object_internal__(type, type->bodySize); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(type, type->bodySize); #endif - // Setup vptr0. - *((const void**)pReference) = type->vptr0; + // Marked instance is initialized. (and will handle by GC) + il2c_ior(&pHeader->characteristic, IL2C_CHARACTERISTIC_INITIALIZED); - // Setup interface vptrs. - il2c_setup_interface_vptrs(type, pReference); - - return pReference; + return ((uint8_t*)pHeader) + sizeof(IL2C_REF_HEADER); } ///////////////////////////////////////////////////////////// @@ -681,12 +689,17 @@ static void il2c_release_all_monitor_lock_for_final_shutdown__(void) ///////////////////////////////////////////////////////////// // Internal GC mark handlers -// Has to ignore if objref is const. (NOT const and NOT marked) +// Has to ignore if objref is const. (NOT const and initialized and NOT marked) // HACK: It's shame the icmpxchg may cause system fault if header is placed at read-only memory (CONST). // (at x86/x64 cause, another platform may cause) +// TODO: Reduce flags calculation. #define TRY_GET_HEADER(pHeader, pAdjustedReference) \ IL2C_REF_HEADER* pHeader = il2c_get_header__(pAdjustedReference); \ - if (il2c_unlikely__(((pHeader->characteristic & (IL2C_CHARACTERISTIC_CONST | IL2C_CHARACTERISTIC_MARK_INDEX)) ^ IL2C_CHARACTERISTIC_MARK_INDEX) == g_CollectionMarkIndex__)) + if (il2c_unlikely__(( \ + (pHeader->characteristic & \ + (IL2C_CHARACTERISTIC_CONST | IL2C_CHARACTERISTIC_INITIALIZED | IL2C_CHARACTERISTIC_MARK_INDEX)) ^ \ + (IL2C_CHARACTERISTIC_INITIALIZED | IL2C_CHARACTERISTIC_MARK_INDEX)) == \ + g_CollectionMarkIndex__)) static void il2c_mark_handler_recursive__(void* pTarget, IL2C_RUNTIME_TYPE type, const uint8_t offset); @@ -698,6 +711,7 @@ static void il2c_mark_handler_for_objref__(System_Object* pAdjustedReference) IL2C_REF_HEADER* pHeader = il2c_get_header__(pAdjustedReference); il2c_assert(pHeader->type != NULL); + il2c_assert(pHeader->characteristic & IL2C_CHARACTERISTIC_INITIALIZED); // Marking with atomicity. const interlock_t lastCharacteristic = il2c_ixor(&pHeader->characteristic, IL2C_CHARACTERISTIC_MARK_INDEX); @@ -968,7 +982,9 @@ static void il2c_step3_sweep_garbage__(void) while (il2c_likely__(pCurrentHeader != NULL)) { IL2C_REF_HEADER* pNext = pCurrentHeader->pNext; - if (il2c_unlikely__((pCurrentHeader->characteristic & IL2C_CHARACTERISTIC_MARK_INDEX) != g_CollectionMarkIndex__)) + if (il2c_unlikely__(((pCurrentHeader->characteristic & + (IL2C_CHARACTERISTIC_INITIALIZED | IL2C_CHARACTERISTIC_MARK_INDEX)) ^ + IL2C_CHARACTERISTIC_INITIALIZED) != g_CollectionMarkIndex__)) { // Very important unlink step: because cause misread on purpose this__ instance is living. *ppUnlinkTarget = pNext; @@ -1333,16 +1349,19 @@ System_ValueType* il2c_box__( valueType->bodySize + valueType->interfaceCount * sizeof(void*); // interface vptrs #if defined(IL2C_USE_LINE_INFORMATION) - System_ValueType* pBoxed = il2c_get_uninitialized_object_internal__(valueType, bodySize, pFile, line); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(valueType, bodySize, pFile, line); #else - System_ValueType* pBoxed = il2c_get_uninitialized_object_internal__(valueType, bodySize); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(valueType, bodySize); #endif - pBoxed->vptr0__ = valueType->vptr0; + System_ValueType* pBoxed = (System_ValueType*)(pHeader + 1); + + il2c_assert(pBoxed->vptr0__ == valueType->vptr0); + memcpy(((uint8_t*)pBoxed) + sizeof(System_ValueType), pValue, valueType->bodySize); - // Setup interface vptrs. - il2c_setup_interface_vptrs(valueType, pBoxed); + // Marked instance is initialized. (and will handle by GC) + il2c_ior(&pHeader->characteristic, IL2C_CHARACTERISTIC_INITIALIZED); return pBoxed; } @@ -1460,17 +1479,18 @@ System_ValueType* il2c_box2__( il2c_throw_invalidcastexception__(); } - uintptr_t bodySize = sizeof(System_ValueType) + + const uintptr_t bodySize = sizeof(System_ValueType) + valueType->bodySize + valueType->interfaceCount * sizeof(void*); // interface vptrs #if defined(IL2C_USE_LINE_INFORMATION) - System_ValueType* pBoxed = il2c_get_uninitialized_object_internal__(valueType, bodySize, pFile, line); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(valueType, bodySize, pFile, line); #else - System_ValueType* pBoxed = il2c_get_uninitialized_object_internal__(valueType, bodySize); + IL2C_REF_HEADER* pHeader = il2c_get_uninitialized_object_internal__(valueType, bodySize); #endif - // vptr0 setup. - pBoxed->vptr0__ = valueType->vptr0; + System_ValueType* pBoxed = (System_ValueType*)(pHeader + 1); + + il2c_assert(pBoxed->vptr0__ == valueType->vptr0); switch (valueType->bodySize) { @@ -1488,8 +1508,8 @@ System_ValueType* il2c_box2__( break; } - // Setup interface vptrs. - il2c_setup_interface_vptrs(valueType, pBoxed); + // Marked instance is initialized. (and will handle by GC) + il2c_ior(&pHeader->characteristic, IL2C_CHARACTERISTIC_INITIALIZED); return pBoxed; } diff --git a/IL2C.Runtime/src/il2c_private.h b/IL2C.Runtime/src/il2c_private.h index d4b09257..b193641b 100644 --- a/IL2C.Runtime/src/il2c_private.h +++ b/IL2C.Runtime/src/il2c_private.h @@ -105,9 +105,10 @@ struct IL2C_RUNTIME_TYPE_DECL //}; // IL2C_REF_HEADER_DECL.characteristic -#define IL2C_CHARACTERISTIC_ACQUIRED_MONITOR_LOCK ((interlock_t)0x10000000UL) -#define IL2C_CHARACTERISTIC_SUPPRESS_FINALIZE ((interlock_t)0x20000000UL) -#define IL2C_CHARACTERISTIC_MARK_INDEX ((interlock_t)0x40000000UL) // Mark index is only 0 or 1. +#define IL2C_CHARACTERISTIC_ACQUIRED_MONITOR_LOCK ((interlock_t)0x08000000UL) +#define IL2C_CHARACTERISTIC_SUPPRESS_FINALIZE ((interlock_t)0x10000000UL) +#define IL2C_CHARACTERISTIC_MARK_INDEX ((interlock_t)0x20000000UL) // Mark index is only 0 or 1. +#define IL2C_CHARACTERISTIC_INITIALIZED ((interlock_t)0x40000000UL) // GC will ignore if not initialized #define IL2C_CHARACTERISTIC_CONST ((interlock_t)0x80000000UL) #define il2c_get_header__(pReference) \ @@ -162,9 +163,9 @@ typeName##_VTABLE_DECL__ typeName##_VTABLE__ = { \ // Internal runtime functions #if defined(IL2C_USE_LINE_INFORMATION) -extern void* il2c_get_uninitialized_object_internal__(IL2C_RUNTIME_TYPE type, uintptr_t bodySize, const char* pFile, int line); +extern IL2C_REF_HEADER* il2c_get_uninitialized_object_internal__(IL2C_RUNTIME_TYPE type, uintptr_t bodySize, const char* pFile, int line); #else -extern void* il2c_get_uninitialized_object_internal__(IL2C_RUNTIME_TYPE type, uintptr_t bodySize); +extern IL2C_REF_HEADER* il2c_get_uninitialized_object_internal__(IL2C_RUNTIME_TYPE type, uintptr_t bodySize); #endif extern void il2c_register_root_reference__(void* pReference, bool isFixed);