From 66a56ac049880b754f19ee3260cce9c2f867c494 Mon Sep 17 00:00:00 2001 From: Apprentice-Alchemist <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Mon, 14 Feb 2022 21:23:10 +0100 Subject: [PATCH 01/11] New atomic functions. --- include/hx/StdLibs.h | 94 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/include/hx/StdLibs.h b/include/hx/StdLibs.h index d661c2698..963a78ced 100644 --- a/include/hx/StdLibs.h +++ b/include/hx/StdLibs.h @@ -305,6 +305,100 @@ bool _hx_atomic_exchange_if(::cpp::Pointer inPtr, int test, int int _hx_atomic_inc(::cpp::Pointer inPtr ); int _hx_atomic_dec(::cpp::Pointer inPtr ); +// Assumptions made: +// Everyone uses GCC, Clang or MSVC +// People are not using 8 year old versions of GCC. + +#if defined(__GNUC__) || defined(__clang__) +#define HX_GCC_ATOMICS +#elif defined(_MSC_VER) +#define HX_MSVC_ATOMICS +#include +#else // Nearly everyone uses GCC, Clang or MSVC, right? +#error "Neither GCC, clang or MSVC is being used. Please contribute the relevant atomic instrinsics for your compiler." +#endif + +inline int _hx_atomic_add(int *a, int b) { +#if defined(HX_GCC_ATOMICS) + return __atomic_fetch_add(a, b, __ATOMIC_SEQ_CST); +#elif defined(HX_MSVC_ATOMICS) + return InterlockedExchangeAdd((LONG volatile *)a, b); +#endif +} + +inline int _hx_atomic_sub(int *a, int b) { +#if defined(HX_GCC_ATOMICS) + return __atomic_fetch_sub(a, b, __ATOMIC_SEQ_CST); +#elif defined(HX_MSVC_ATOMICS) + return InterlockedExchangeAdd((LONG volatile *)a, -b); +#endif +} + +inline int _hx_atomic_and(int *a, int b) { +#if defined(HX_GCC_ATOMICS) + return __atomic_fetch_and(a, b, __ATOMIC_SEQ_CST); +#elif defined(HX_MSVC_ATOMICS) + return InterlockedAnd((LONG volatile *)a, b); +#endif +} + +inline int _hx_atomic_or(int *a, int b) { +#if defined(HX_GCC_ATOMICS) + return __atomic_fetch_or(a, b, __ATOMIC_SEQ_CST); +#elif defined(HX_MSVC_ATOMICS) + return InterlockedOr((LONG volatile *)a, b); +#endif +} + +inline int _hx_atomic_xor(int *a, int b) { +#if defined(HX_GCC_ATOMICS) + return __atomic_fetch_xor(a, b, __ATOMIC_SEQ_CST); +#elif defined(HX_MSVC_ATOMICS) + return InterlockedXor((LONG volatile *)a, b); +#endif +} + +inline int _hx_atomic_compare_exchange(int *a, int expected, + int replacement) { +#if defined(HX_GCC_ATOMICS) + int _expected = expected; + __atomic_compare_exchange(a, &_expected, &replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + return _expected; +#elif defined(HX_MSVC_ATOMICS) + return InterlockedCompareExchange((LONG volatile *)a, replacement, expected); +#endif +} + +inline int _hx_atomic_exchange(int *a, int replacement) { +#if defined(HX_GCC_ATOMICS) + int ret = 0; + __atomic_exchange(a, &replacement, &ret, __ATOMIC_SEQ_CST); + return ret; +#elif defined(HX_MSVC_ATOMICS) + return InterlockedExchange((LONG volatile *)a, replacement); +#endif +} + +inline int _hx_atomic_load(int *a) { +#if defined(HX_GCC_ATOMICS) + int ret = 0; + __atomic_load(a, &ret, __ATOMIC_SEQ_CST); + return ret; +#elif defined(HX_MSVC_ATOMICS) + return InterlockedXor((LONG volatile *)a, 0); +#endif +} + +inline int _hx_atomic_store(int *a, int value) { +#if defined(HX_GCC_ATOMICS) + __atomic_store(a, &value, __ATOMIC_SEQ_CST); + return value; +#elif defined(HX_MSVC_ATOMICS) + InterlockedExchange((LONG volatile *)a, value); + return value; +#endif +} + Array __hxcpp_get_call_stack(bool inSkipLast); Array __hxcpp_get_exception_stack(); #define HXCPP_HAS_CLASSLIST From b10cebbffbd8944f060fc51fc0329e32865c4c98 Mon Sep 17 00:00:00 2001 From: Apprentice-Alchemist <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:38:36 +0100 Subject: [PATCH 02/11] Use MSVC intrinsics, instead of Win32 calls. --- include/hx/StdLibs.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/hx/StdLibs.h b/include/hx/StdLibs.h index 963a78ced..68818088b 100644 --- a/include/hx/StdLibs.h +++ b/include/hx/StdLibs.h @@ -313,7 +313,7 @@ int _hx_atomic_dec(::cpp::Pointer inPtr ); #define HX_GCC_ATOMICS #elif defined(_MSC_VER) #define HX_MSVC_ATOMICS -#include +#include #else // Nearly everyone uses GCC, Clang or MSVC, right? #error "Neither GCC, clang or MSVC is being used. Please contribute the relevant atomic instrinsics for your compiler." #endif @@ -322,7 +322,7 @@ inline int _hx_atomic_add(int *a, int b) { #if defined(HX_GCC_ATOMICS) return __atomic_fetch_add(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) - return InterlockedExchangeAdd((LONG volatile *)a, b); + return _InterlockedExchangeAdd((long volatile *)a, b); #endif } @@ -330,7 +330,7 @@ inline int _hx_atomic_sub(int *a, int b) { #if defined(HX_GCC_ATOMICS) return __atomic_fetch_sub(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) - return InterlockedExchangeAdd((LONG volatile *)a, -b); + return _InterlockedExchangeAdd((long volatile *)a, -b); #endif } @@ -338,7 +338,7 @@ inline int _hx_atomic_and(int *a, int b) { #if defined(HX_GCC_ATOMICS) return __atomic_fetch_and(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) - return InterlockedAnd((LONG volatile *)a, b); + return _InterlockedAnd((long volatile *)a, b); #endif } @@ -346,7 +346,7 @@ inline int _hx_atomic_or(int *a, int b) { #if defined(HX_GCC_ATOMICS) return __atomic_fetch_or(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) - return InterlockedOr((LONG volatile *)a, b); + return _InterlockedOr((long volatile *)a, b); #endif } @@ -354,7 +354,7 @@ inline int _hx_atomic_xor(int *a, int b) { #if defined(HX_GCC_ATOMICS) return __atomic_fetch_xor(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) - return InterlockedXor((LONG volatile *)a, b); + return _InterlockedXor((long volatile *)a, b); #endif } @@ -365,7 +365,7 @@ inline int _hx_atomic_compare_exchange(int *a, int expected, __atomic_compare_exchange(a, &_expected, &replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return _expected; #elif defined(HX_MSVC_ATOMICS) - return InterlockedCompareExchange((LONG volatile *)a, replacement, expected); + return _InterlockedCompareExchange((long volatile *)a, replacement, expected); #endif } @@ -375,7 +375,7 @@ inline int _hx_atomic_exchange(int *a, int replacement) { __atomic_exchange(a, &replacement, &ret, __ATOMIC_SEQ_CST); return ret; #elif defined(HX_MSVC_ATOMICS) - return InterlockedExchange((LONG volatile *)a, replacement); + return _InterlockedExchange((long volatile *)a, replacement); #endif } @@ -385,7 +385,7 @@ inline int _hx_atomic_load(int *a) { __atomic_load(a, &ret, __ATOMIC_SEQ_CST); return ret; #elif defined(HX_MSVC_ATOMICS) - return InterlockedXor((LONG volatile *)a, 0); + return _InterlockedXor((long volatile *)a, 0); #endif } @@ -394,7 +394,7 @@ inline int _hx_atomic_store(int *a, int value) { __atomic_store(a, &value, __ATOMIC_SEQ_CST); return value; #elif defined(HX_MSVC_ATOMICS) - InterlockedExchange((LONG volatile *)a, value); + _InterlockedExchange((long volatile *)a, value); return value; #endif } From 4517e6a490142fa2b8b07cf5632f56d2faddc358 Mon Sep 17 00:00:00 2001 From: Zeta <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Mon, 4 Apr 2022 09:39:20 +0200 Subject: [PATCH 03/11] Use the new _hx_atomic* functions instead of the old HxAtomic*. --- include/hx/StdLibs.h | 10 ++++ include/hx/Thread.h | 112 ------------------------------------------- src/String.cpp | 4 +- src/hx/Thread.cpp | 6 +-- src/hx/gc/Immix.cpp | 56 +++++++++++----------- 5 files changed, 43 insertions(+), 145 deletions(-) diff --git a/include/hx/StdLibs.h b/include/hx/StdLibs.h index 68818088b..967cc1b62 100644 --- a/include/hx/StdLibs.h +++ b/include/hx/StdLibs.h @@ -399,6 +399,16 @@ inline int _hx_atomic_store(int *a, int value) { #endif } +inline void* _hx_atomic_compare_exchange_ptr(void **a, void *expected, void* replacement) { +#if defined(HX_GCC_ATOMICS) + void* _expected = expected; + __atomic_compare_exchange(a, &_expected, &replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + return _expected; +#elif defined(HX_MSVC_ATOMICS) + return _InterlockedCompareExchangePointer((long volatile *)a, replacement, expected); +#endif +} + Array __hxcpp_get_call_stack(bool inSkipLast); Array __hxcpp_get_exception_stack(); #define HXCPP_HAS_CLASSLIST diff --git a/include/hx/Thread.h b/include/hx/Thread.h index 9998de3ea..b2c3bbfb4 100644 --- a/include/hx/Thread.h +++ b/include/hx/Thread.h @@ -41,118 +41,6 @@ #undef RegisterClass #endif -#if defined(ANDROID) - -#define HX_HAS_ATOMIC 1 - -#if (HXCPP_ANDROID_PLATFORM>=16) -// Nice one, google, no one was using that. -#define __ATOMIC_INLINE__ static __inline__ __attribute__((always_inline)) -// returns 0=exchange took place, 1=not -__ATOMIC_INLINE__ int __atomic_cmpxchg(int old, int _new, volatile int *ptr) - { return __sync_val_compare_and_swap(ptr, old, _new) != old; } -__ATOMIC_INLINE__ int __atomic_dec(volatile int *ptr) { return __sync_fetch_and_sub (ptr, 1); } -__ATOMIC_INLINE__ int __atomic_inc(volatile int *ptr) { return __sync_fetch_and_add (ptr, 1); } -#else -#include -#endif - -// returns 1 if exchange took place -inline bool HxAtomicExchangeIf(int inTest, int inNewVal,volatile int *ioWhere) - { return !__atomic_cmpxchg(inTest, inNewVal, ioWhere); } -inline bool HxAtomicExchangeIfPtr(void *inTest, void *inNewVal,void * volatile *ioWhere) - { return __sync_val_compare_and_swap(ioWhere, inTest, inNewVal)==inTest; } - -// Returns old value naturally -inline int HxAtomicInc(volatile int *ioWhere) - { return __atomic_inc(ioWhere); } -inline int HxAtomicDec(volatile int *ioWhere) - { return __atomic_dec(ioWhere); } - - -#elif defined(HX_WINDOWS) - -inline bool HxAtomicExchangeIf(int inTest, int inNewVal,volatile int *ioWhere) - { return InterlockedCompareExchange((volatile LONG *)ioWhere, inNewVal, inTest)==inTest; } - -inline bool HxAtomicExchangeIfPtr(void *inTest, void *inNewVal,void *volatile *ioWhere) - { return InterlockedCompareExchangePointer(ioWhere, inNewVal, inTest)==inTest; } - -// Make it return old value -inline int HxAtomicInc(volatile int *ioWhere) - { return InterlockedIncrement((volatile LONG *)ioWhere)-1; } -inline int HxAtomicDec(volatile int *ioWhere) - { return InterlockedDecrement((volatile LONG *)ioWhere)+1; } - -#define HX_HAS_ATOMIC 1 - -#elif defined(HX_MACOS) || defined(IPHONE) || defined(APPLETV) -#include - -#define HX_HAS_ATOMIC 1 - -inline bool HxAtomicExchangeIf(int inTest, int inNewVal,volatile int *ioWhere) - { return OSAtomicCompareAndSwap32Barrier(inTest, inNewVal, ioWhere); } -inline bool HxAtomicExchangeIfPtr(void *inTest, void *inNewVal,void * volatile *ioWhere) - { return OSAtomicCompareAndSwapPtrBarrier(inTest, inNewVal, ioWhere); } -inline int HxAtomicInc(volatile int *ioWhere) - { return OSAtomicIncrement32Barrier(ioWhere)-1; } -inline int HxAtomicDec(volatile int *ioWhere) - { return OSAtomicDecrement32Barrier(ioWhere)+1; } - - -#elif defined(HX_LINUX) - -#define HX_HAS_ATOMIC 1 - -inline bool HxAtomicExchangeIf(int inTest, int inNewVal,volatile int *ioWhere) - { return __sync_bool_compare_and_swap(ioWhere, inTest, inNewVal); } -inline bool HxAtomicExchangeIfPtr(void *inTest, void *inNewVal,void *volatile *ioWhere) - { return __sync_bool_compare_and_swap(ioWhere, inTest, inNewVal); } -// Returns old value naturally -inline int HxAtomicInc(volatile int *ioWhere) - { return __sync_fetch_and_add(ioWhere,1); } -inline int HxAtomicDec(volatile int *ioWhere) - { return __sync_fetch_and_sub(ioWhere,1); } - -#else - -#define HX_HAS_ATOMIC 0 - -inline bool HxAtomicExchangeIfPtr(void *inTest, void *inNewVal,void *volatile *ioWhere) -{ - if (*ioWhere == inTest) - { - *ioWhere = inNewVal; - return true; - } - return false; -} - - -inline int HxAtomicExchangeIf(int inTest, int inNewVal,volatile int *ioWhere) -{ - if (*ioWhere == inTest) - { - *ioWhere = inNewVal; - return true; - } - return false; -} -inline int HxAtomicInc(volatile int *ioWhere) - { return (*ioWhere)++; } -inline int HxAtomicDec(volatile int *ioWhere) - { return (*ioWhere)--; } - - -#endif - -inline bool HxAtomicExchangeIfCastPtr(void *inTest, void *inNewVal,void *ioWhere) -{ - return HxAtomicExchangeIfPtr(inTest, inNewVal, (void *volatile *)ioWhere); -} - - #if defined(HX_WINDOWS) diff --git a/src/String.cpp b/src/String.cpp index 52029eba5..bb7226ea7 100644 --- a/src/String.cpp +++ b/src/String.cpp @@ -1172,7 +1172,7 @@ const ::String &::String::makePermanent() const { unsigned int myHash = hash(); { - while(! HxAtomicExchangeIf(0,1,&sPermanentStringSetMutex) ) + while(_hx_atomic_compare_exchange(&sPermanentStringSetMutex, 0, 1) != 0) __hxcpp_gc_safe_point(); TNonGcStringSet *element = sPermanentStringSet->find(myHash , *this); sPermanentStringSetMutex = 0; @@ -1198,7 +1198,7 @@ const ::String &::String::makePermanent() const const_cast(this)->__s = s; } - while(! HxAtomicExchangeIf(0,1,&sPermanentStringSetMutex) ) + while(_hx_atomic_compare_exchange(&sPermanentStringSetMutex, 0, 1) != 0) __hxcpp_gc_safe_point(); sPermanentStringSet->set(*this,null()); sPermanentStringSetMutex = 0; diff --git a/src/hx/Thread.cpp b/src/hx/Thread.cpp index 5aff7c867..0dedb89d9 100644 --- a/src/hx/Thread.cpp +++ b/src/hx/Thread.cpp @@ -930,17 +930,17 @@ int __hxcpp_GetCurrentThreadNumber() bool _hx_atomic_exchange_if(::cpp::Pointer inPtr, int test, int newVal ) { - return HxAtomicExchangeIf(test, newVal, inPtr); + return _hx_atomic_compare_exchange(inPtr, test, newVal) == test; } int _hx_atomic_inc(::cpp::Pointer inPtr ) { - return HxAtomicInc(inPtr); + return _hx_atomic_add(inPtr, 1); } int _hx_atomic_dec(::cpp::Pointer inPtr ) { - return HxAtomicDec(inPtr); + return _hx_atomic_sub(inPtr, 1); } diff --git a/src/hx/gc/Immix.cpp b/src/hx/gc/Immix.cpp index bdee325ef..5c26fd810 100644 --- a/src/hx/gc/Immix.cpp +++ b/src/hx/gc/Immix.cpp @@ -859,7 +859,7 @@ struct BlockDataInfo if (mZeroed) return false; - if (HxAtomicExchangeIf(0,1,&mZeroLock)) + if (_hx_atomic_compare_exchange(&mZeroLock, 0,1) == 0) return zeroAndUnlock(); return false; @@ -1469,7 +1469,7 @@ void GCOnNewPointer(void *inPtr) { #ifdef HXCPP_GC_DEBUG_ALWAYS_MOVE hx::sgPointerMoved.erase(inPtr); - HxAtomicInc(&sgAllocsSinceLastSpam); + _hx_atomic_add(&sgAllocsSinceLastSpam, 1); #endif } @@ -1502,7 +1502,7 @@ struct GlobalChunks { MarkChunk *head = (MarkChunk *)processList; inChunk->next = head; - if (HxAtomicExchangeIfCastPtr(head, inChunk, &processList)) + if (_hx_atomic_compare_exchange_ptr(&processList, head, inChunk) == head) break; } @@ -1515,12 +1515,12 @@ struct GlobalChunks { MarkChunk *head = (MarkChunk *)processList; inChunk->next = head; - if (HxAtomicExchangeIfCastPtr(head, inChunk, &processList)) + if (_hx_atomic_compare_exchange_ptr(&processList, head, inChunk) == head) break; } #ifdef PROFILE_THREAD_USAGE - HxAtomicInc(&sThreadChunkPushCount); + _hx_atomic_add(&sThreadChunkPushCount, 1); #endif if (MAX_GC_THREADS>1 && sLazyThreads) @@ -1623,7 +1623,7 @@ struct GlobalChunks { MarkChunk *head = (MarkChunk *)freeList; inChunk->next = head; - if (HxAtomicExchangeIfCastPtr(head, inChunk, &freeList)) + if (_hx_atomic_compare_exchange_ptr(&freeList, head, inChunk) == head) return; } } @@ -1634,11 +1634,11 @@ struct GlobalChunks if (inChunk) release(inChunk); - while( !HxAtomicExchangeIf(0,1,&processListPopLock) ) + while(_hx_atomic_compare_exchange(&processListPopLock, 0, 1) != 0) { // Spin #ifdef PROFILE_THREAD_USAGE - HxAtomicInc(&sSpinCount); + _hx_atomic_add(&sSpinCount, 1); #endif } @@ -1651,7 +1651,7 @@ struct GlobalChunks return 0; } MarkChunk *next = head->next; - if (HxAtomicExchangeIfCastPtr(head, next, &processList)) + if (_hx_atomic_compare_exchange_ptr(&processList, head, inChunk) == head) { processListPopLock = 0; @@ -1717,11 +1717,11 @@ struct GlobalChunks inline MarkChunk *alloc() { - while( !HxAtomicExchangeIf(0,1,&freeListPopLock) ) + while(_hx_atomic_compare_exchange(&freeListPopLock, 0, 1) != 0) { // Spin #ifdef PROFILE_THREAD_USAGE - HxAtomicInc(&sSpinCount); + _hx_atomic_add(&sSpinCount, 1); #endif } @@ -1734,7 +1734,7 @@ struct GlobalChunks return new MarkChunk; } MarkChunk *next = head->next; - if (HxAtomicExchangeIfCastPtr(head, next, &freeList)) + if (_hx_atomic_compare_exchange_ptr(&freeList, head, inChunk) == head) { freeListPopLock = 0; @@ -2047,7 +2047,7 @@ void MarkAllocUnchecked(void *inPtr,hx::MarkContext *__inCtx) unsigned int *pos = info->allocStart + startRow; unsigned int val = *pos; - while(!HxAtomicExchangeIf(val,val|gImmixStartFlag[start&127], (volatile int *)pos)) + while(_hx_atomic_compare_exchange((volatile int *)pos, val,val|gImmixStartFlag[start&127]) != val) val = *pos; #ifdef HXCPP_GC_GENERATIONAL @@ -2132,7 +2132,7 @@ void MarkObjectAllocUnchecked(hx::Object *inPtr,hx::MarkContext *__inCtx) unsigned int *pos = info->allocStart + startRow; unsigned int val = *pos; - while(!HxAtomicExchangeIf(val,val|gImmixStartFlag[start&127], (volatile int *)pos)) + while(_hx_atomic_compare_exchange( (volatile int *)pos, val, val|gImmixStartFlag[start&127]) != val) val = *pos; #ifdef HXCPP_GC_GENERATIONAL info->mHasSurvivor = true; @@ -3364,7 +3364,7 @@ class GlobalAllocator if (!info->mOwned && info->mMaxHoleSize>=inRequiredBytes) { // Acquire the zero-lock - if (HxAtomicExchangeIf(0,1,&info->mZeroLock)) + if (_hx_atomic_compare_exchange(&info->mZeroLock, 0, 1) == 0) { // Acquire ownership... if (info->mOwned) @@ -3380,7 +3380,7 @@ class GlobalAllocator int idx = nextFreeBlock; while(idxmOwned) { - HxAtomicExchangeIf(idx,idx+1,mNextFreeBlockOfSize+sizeSlot); + _hx_atomic_compare_exchange(mNextFreeBlockOfSize+sizeSlot, idx, idx+1); idx++; } @@ -3392,7 +3392,7 @@ class GlobalAllocator else { if (!info->mZeroed) - HxAtomicInc(&sThreadZeroMisses); + _hx_atomic_add(&sThreadZeroMisses, 1); } #endif } @@ -4279,7 +4279,7 @@ class GlobalAllocator { while(!sgThreadPoolAbort) { - int blockId = HxAtomicInc( &mThreadJobId ); + int blockId = _hx_atomic_add(&mThreadJobId, 1); if (blockId>=mAllBlocks.size()) break; @@ -4294,7 +4294,7 @@ class GlobalAllocator { while(!sgThreadPoolAbort) { - int blockId = HxAtomicInc( &mThreadJobId ); + int blockId = _hx_atomic_add(&mThreadJobId, 1); if (blockId>=mAllBlocks.size()) break; @@ -4307,7 +4307,7 @@ class GlobalAllocator { while(!sgThreadPoolAbort) { - int blockId = HxAtomicInc( &mThreadJobId ); + int blockId = _hx_atomic_add(&mThreadJobId, 1); if (blockId>=mAllBlocks.size()) break; @@ -4322,7 +4322,7 @@ class GlobalAllocator { while(!sgThreadPoolAbort) { - int blockId = HxAtomicInc( &mThreadJobId ); + int blockId = _hx_atomic_add(&mThreadJobId, 1); if (blockId>=mAllBlocks.size()) break; @@ -4336,7 +4336,7 @@ class GlobalAllocator { while(!sgThreadPoolAbort) { - int zeroListId = HxAtomicInc( &mThreadJobId ); + int zeroListId = _hx_atomic_add(&mThreadJobId, 1); if (zeroListId>=mZeroList.size()) break; @@ -4362,7 +4362,7 @@ class GlobalAllocator spinCount = 0; // Look at next block... - int zeroListId = HxAtomicInc( &mThreadJobId ); + int zeroListId = _hx_atomic_add(&mThreadJobId, 1); if (zeroListId>=mZeroList.size()) { // Done, so sleep... @@ -4373,7 +4373,7 @@ class GlobalAllocator if (info->tryZero()) { // We zeroed it, so increase queue count - HxAtomicInc(&mZeroListQueue); + _hx_atomic_add(&mZeroListQueue, 1); #ifdef PROFILE_THREAD_USAGE sThreadBlockZeroCount++; #endif @@ -4387,7 +4387,7 @@ class GlobalAllocator void onZeroedBlockDequeued() { // Wake the thread? - if (HxAtomicDec(&mZeroListQueue) 0xffffffff then we are the collector // otherwise, someone else is collecting at the moment - so wait... - if (!HxAtomicExchangeIf(0, 0xffffffff,(volatile int *)&hx::gPauseForCollect)) + if (_hx_atomic_compare_exchange(0, 0xffffffff,(volatile int *)&hx::gPauseForCollect) != 0) { if (inLocked) { @@ -6568,7 +6568,7 @@ void *InternalNew(int inSize,bool inIsObject) //GCLOG("InternalNew spam\n"); CollectFromThisThread(false,false); } - HxAtomicInc(&sgAllocsSinceLastSpam); + _hx_atomic_add(&sgAllocsSinceLastSpam, 1); #endif if (inSize>=IMMIX_LARGE_OBJ_SIZE) @@ -6679,7 +6679,7 @@ void *InternalRealloc(int inFromSize, void *inData,int inSize, bool inExpand) //GCLOG("InternalNew spam\n"); CollectFromThisThread(false,false); } - HxAtomicInc(&sgAllocsSinceLastSpam); + _hx_atomic_add(&sgAllocsSinceLastSpam, 1); #endif void *new_data = 0; From 595ac4080d781708a0b2e965a13e16a6afcfa02c Mon Sep 17 00:00:00 2001 From: Zeta <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Mon, 4 Apr 2022 10:21:22 +0200 Subject: [PATCH 04/11] Fix some casts. --- include/hx/StdLibs.h | 2 +- src/hx/Thread.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/hx/StdLibs.h b/include/hx/StdLibs.h index 967cc1b62..05b293759 100644 --- a/include/hx/StdLibs.h +++ b/include/hx/StdLibs.h @@ -405,7 +405,7 @@ inline void* _hx_atomic_compare_exchange_ptr(void **a, void *expected, void* rep __atomic_compare_exchange(a, &_expected, &replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return _expected; #elif defined(HX_MSVC_ATOMICS) - return _InterlockedCompareExchangePointer((long volatile *)a, replacement, expected); + return _InterlockedCompareExchangePointer((void *volatile *)a, replacement, expected); #endif } diff --git a/src/hx/Thread.cpp b/src/hx/Thread.cpp index 0dedb89d9..d29069fd2 100644 --- a/src/hx/Thread.cpp +++ b/src/hx/Thread.cpp @@ -930,17 +930,17 @@ int __hxcpp_GetCurrentThreadNumber() bool _hx_atomic_exchange_if(::cpp::Pointer inPtr, int test, int newVal ) { - return _hx_atomic_compare_exchange(inPtr, test, newVal) == test; + return _hx_atomic_compare_exchange((int*)(volatile int*)inPtr, test, newVal) == test; } int _hx_atomic_inc(::cpp::Pointer inPtr ) { - return _hx_atomic_add(inPtr, 1); + return _hx_atomic_add((int*)(volatile int*)inPtr, 1); } int _hx_atomic_dec(::cpp::Pointer inPtr ) { - return _hx_atomic_sub(inPtr, 1); + return _hx_atomic_sub((int*)(volatile int*)inPtr, 1); } From 6727880e83194f82f714994d06d3cc84d6db8aea Mon Sep 17 00:00:00 2001 From: Apprentice-Alchemist <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Sat, 9 Apr 2022 17:18:17 +0200 Subject: [PATCH 05/11] Use volatile int. --- include/hx/StdLibs.h | 16 ++++++++-------- src/hx/Thread.cpp | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/hx/StdLibs.h b/include/hx/StdLibs.h index 05b293759..569806153 100644 --- a/include/hx/StdLibs.h +++ b/include/hx/StdLibs.h @@ -326,7 +326,7 @@ inline int _hx_atomic_add(int *a, int b) { #endif } -inline int _hx_atomic_sub(int *a, int b) { +inline int _hx_atomic_sub(volatile int *a, int b) { #if defined(HX_GCC_ATOMICS) return __atomic_fetch_sub(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) @@ -334,7 +334,7 @@ inline int _hx_atomic_sub(int *a, int b) { #endif } -inline int _hx_atomic_and(int *a, int b) { +inline int _hx_atomic_and(volatile int *a, int b) { #if defined(HX_GCC_ATOMICS) return __atomic_fetch_and(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) @@ -342,7 +342,7 @@ inline int _hx_atomic_and(int *a, int b) { #endif } -inline int _hx_atomic_or(int *a, int b) { +inline int _hx_atomic_or(volatile int *a, int b) { #if defined(HX_GCC_ATOMICS) return __atomic_fetch_or(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) @@ -358,7 +358,7 @@ inline int _hx_atomic_xor(int *a, int b) { #endif } -inline int _hx_atomic_compare_exchange(int *a, int expected, +inline int _hx_atomic_compare_exchange(volatile int *a, int expected, int replacement) { #if defined(HX_GCC_ATOMICS) int _expected = expected; @@ -369,7 +369,7 @@ inline int _hx_atomic_compare_exchange(int *a, int expected, #endif } -inline int _hx_atomic_exchange(int *a, int replacement) { +inline int _hx_atomic_exchange(volatile int *a, int replacement) { #if defined(HX_GCC_ATOMICS) int ret = 0; __atomic_exchange(a, &replacement, &ret, __ATOMIC_SEQ_CST); @@ -379,7 +379,7 @@ inline int _hx_atomic_exchange(int *a, int replacement) { #endif } -inline int _hx_atomic_load(int *a) { +inline int _hx_atomic_load(volatile int *a) { #if defined(HX_GCC_ATOMICS) int ret = 0; __atomic_load(a, &ret, __ATOMIC_SEQ_CST); @@ -389,7 +389,7 @@ inline int _hx_atomic_load(int *a) { #endif } -inline int _hx_atomic_store(int *a, int value) { +inline int _hx_atomic_store(volatile int *a, int value) { #if defined(HX_GCC_ATOMICS) __atomic_store(a, &value, __ATOMIC_SEQ_CST); return value; @@ -399,7 +399,7 @@ inline int _hx_atomic_store(int *a, int value) { #endif } -inline void* _hx_atomic_compare_exchange_ptr(void **a, void *expected, void* replacement) { +inline void* _hx_atomic_compare_exchange_ptr(volatile void **a, void *expected, void* replacement) { #if defined(HX_GCC_ATOMICS) void* _expected = expected; __atomic_compare_exchange(a, &_expected, &replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); diff --git a/src/hx/Thread.cpp b/src/hx/Thread.cpp index d29069fd2..0dedb89d9 100644 --- a/src/hx/Thread.cpp +++ b/src/hx/Thread.cpp @@ -930,17 +930,17 @@ int __hxcpp_GetCurrentThreadNumber() bool _hx_atomic_exchange_if(::cpp::Pointer inPtr, int test, int newVal ) { - return _hx_atomic_compare_exchange((int*)(volatile int*)inPtr, test, newVal) == test; + return _hx_atomic_compare_exchange(inPtr, test, newVal) == test; } int _hx_atomic_inc(::cpp::Pointer inPtr ) { - return _hx_atomic_add((int*)(volatile int*)inPtr, 1); + return _hx_atomic_add(inPtr, 1); } int _hx_atomic_dec(::cpp::Pointer inPtr ) { - return _hx_atomic_sub((int*)(volatile int*)inPtr, 1); + return _hx_atomic_sub(inPtr, 1); } From f6a3c447780f9ec65dd3bea9cc1d6b775f4a4e14 Mon Sep 17 00:00:00 2001 From: Zeta <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Sun, 10 Apr 2022 07:59:43 +0200 Subject: [PATCH 06/11] More volatile. --- include/hx/StdLibs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hx/StdLibs.h b/include/hx/StdLibs.h index 569806153..5a059851b 100644 --- a/include/hx/StdLibs.h +++ b/include/hx/StdLibs.h @@ -318,7 +318,7 @@ int _hx_atomic_dec(::cpp::Pointer inPtr ); #error "Neither GCC, clang or MSVC is being used. Please contribute the relevant atomic instrinsics for your compiler." #endif -inline int _hx_atomic_add(int *a, int b) { +inline int _hx_atomic_add(volatile int *a, int b) { #if defined(HX_GCC_ATOMICS) return __atomic_fetch_add(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) From e5e2636fec298a69ba4ece2ac2e6898eb6669968 Mon Sep 17 00:00:00 2001 From: Apprentice-Alchemist <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Sun, 10 Apr 2022 08:17:46 +0200 Subject: [PATCH 07/11] Fix more C++ casting stuff. --- include/hx/StdLibs.h | 4 ++++ src/hx/gc/Immix.cpp | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/hx/StdLibs.h b/include/hx/StdLibs.h index 569806153..20afc4472 100644 --- a/include/hx/StdLibs.h +++ b/include/hx/StdLibs.h @@ -409,6 +409,10 @@ inline void* _hx_atomic_compare_exchange_ptr(volatile void **a, void *expected, #endif } +inline void* _hx_atomic_compare_exchange_cast_ptr(void *a, void *expected, void *replacement) { + return _hx_atomic_compare_exchange_ptr((volatile void **)a, expected, replacement); +} + Array __hxcpp_get_call_stack(bool inSkipLast); Array __hxcpp_get_exception_stack(); #define HXCPP_HAS_CLASSLIST diff --git a/src/hx/gc/Immix.cpp b/src/hx/gc/Immix.cpp index 5c26fd810..36f5d43dc 100644 --- a/src/hx/gc/Immix.cpp +++ b/src/hx/gc/Immix.cpp @@ -1502,7 +1502,7 @@ struct GlobalChunks { MarkChunk *head = (MarkChunk *)processList; inChunk->next = head; - if (_hx_atomic_compare_exchange_ptr(&processList, head, inChunk) == head) + if (_hx_atomic_compare_exchange_cast_ptr(&processList, head, inChunk) == head) break; } @@ -1515,7 +1515,7 @@ struct GlobalChunks { MarkChunk *head = (MarkChunk *)processList; inChunk->next = head; - if (_hx_atomic_compare_exchange_ptr(&processList, head, inChunk) == head) + if (_hx_atomic_compare_exchange_cast_ptr(&processList, head, inChunk) == head) break; } @@ -1623,7 +1623,7 @@ struct GlobalChunks { MarkChunk *head = (MarkChunk *)freeList; inChunk->next = head; - if (_hx_atomic_compare_exchange_ptr(&freeList, head, inChunk) == head) + if (_hx_atomic_compare_exchange_cast_ptr(&freeList, head, inChunk) == head) return; } } @@ -1651,7 +1651,7 @@ struct GlobalChunks return 0; } MarkChunk *next = head->next; - if (_hx_atomic_compare_exchange_ptr(&processList, head, inChunk) == head) + if (_hx_atomic_compare_exchange_cast_ptr(&processList, head, inChunk) == head) { processListPopLock = 0; @@ -1734,7 +1734,7 @@ struct GlobalChunks return new MarkChunk; } MarkChunk *next = head->next; - if (_hx_atomic_compare_exchange_ptr(&freeList, head, inChunk) == head) + if (_hx_atomic_compare_exchange_cast_ptr(&freeList, head, inChunk) == head) { freeListPopLock = 0; @@ -4811,7 +4811,7 @@ class GlobalAllocator #ifndef HXCPP_SINGLE_THREADED_APP // If we set the flag from 0 -> 0xffffffff then we are the collector // otherwise, someone else is collecting at the moment - so wait... - if (_hx_atomic_compare_exchange(0, 0xffffffff,(volatile int *)&hx::gPauseForCollect) != 0) + if (_hx_atomic_compare_exchange((volatile int *)&hx::gPauseForCollect, 0, 0xffffffff) != 0) { if (inLocked) { From 8abcfbdff4effd33a52a2cf584339e17fa6c64ff Mon Sep 17 00:00:00 2001 From: Apprentice-Alchemist <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Sun, 10 Apr 2022 08:25:28 +0200 Subject: [PATCH 08/11] More C++ casting stuff. --- include/hx/StdLibs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hx/StdLibs.h b/include/hx/StdLibs.h index b19745c87..885e1927b 100644 --- a/include/hx/StdLibs.h +++ b/include/hx/StdLibs.h @@ -402,7 +402,7 @@ inline int _hx_atomic_store(volatile int *a, int value) { inline void* _hx_atomic_compare_exchange_ptr(volatile void **a, void *expected, void* replacement) { #if defined(HX_GCC_ATOMICS) void* _expected = expected; - __atomic_compare_exchange(a, &_expected, &replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange(a, (volatile void **)&_expected, &replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return _expected; #elif defined(HX_MSVC_ATOMICS) return _InterlockedCompareExchangePointer((void *volatile *)a, replacement, expected); From 8f9a83b455967135faab161b5cd2764a831b0ac6 Mon Sep 17 00:00:00 2001 From: Apprentice-Alchemist <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Sun, 10 Apr 2022 09:43:56 +0200 Subject: [PATCH 09/11] Try fixing things some more. --- include/hx/StdLibs.h | 2 +- src/hx/gc/Immix.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/hx/StdLibs.h b/include/hx/StdLibs.h index 885e1927b..23e36990a 100644 --- a/include/hx/StdLibs.h +++ b/include/hx/StdLibs.h @@ -402,7 +402,7 @@ inline int _hx_atomic_store(volatile int *a, int value) { inline void* _hx_atomic_compare_exchange_ptr(volatile void **a, void *expected, void* replacement) { #if defined(HX_GCC_ATOMICS) void* _expected = expected; - __atomic_compare_exchange(a, (volatile void **)&_expected, &replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + __atomic_compare_exchange(a, (volatile void **)&_expected, (volatile void**)&replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return _expected; #elif defined(HX_MSVC_ATOMICS) return _InterlockedCompareExchangePointer((void *volatile *)a, replacement, expected); diff --git a/src/hx/gc/Immix.cpp b/src/hx/gc/Immix.cpp index 36f5d43dc..3b045f681 100644 --- a/src/hx/gc/Immix.cpp +++ b/src/hx/gc/Immix.cpp @@ -1734,7 +1734,7 @@ struct GlobalChunks return new MarkChunk; } MarkChunk *next = head->next; - if (_hx_atomic_compare_exchange_cast_ptr(&freeList, head, inChunk) == head) + if (_hx_atomic_compare_exchange_cast_ptr(&freeList, head, next) == head) { freeListPopLock = 0; From c073db0b69d6f214dfb50e8358b7c8e88c479790 Mon Sep 17 00:00:00 2001 From: Apprentice-Alchemist <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Sun, 10 Apr 2022 11:43:58 +0200 Subject: [PATCH 10/11] Fix typo. --- src/hx/gc/Immix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hx/gc/Immix.cpp b/src/hx/gc/Immix.cpp index 3b045f681..da502d404 100644 --- a/src/hx/gc/Immix.cpp +++ b/src/hx/gc/Immix.cpp @@ -1651,7 +1651,7 @@ struct GlobalChunks return 0; } MarkChunk *next = head->next; - if (_hx_atomic_compare_exchange_cast_ptr(&processList, head, inChunk) == head) + if (_hx_atomic_compare_exchange_cast_ptr(&processList, head, next) == head) { processListPopLock = 0; From 9bf292c85cdce6ccea322a1290c4e542e6fd4b99 Mon Sep 17 00:00:00 2001 From: Apprentice-Alchemist <53486764+Apprentice-Alchemist@users.noreply.github.com> Date: Sun, 10 Apr 2022 15:52:17 +0200 Subject: [PATCH 11/11] Add non-atomic fallback instead of erroring. --- include/hx/StdLibs.h | 46 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/include/hx/StdLibs.h b/include/hx/StdLibs.h index 23e36990a..aa2751a32 100644 --- a/include/hx/StdLibs.h +++ b/include/hx/StdLibs.h @@ -306,16 +306,17 @@ int _hx_atomic_inc(::cpp::Pointer inPtr ); int _hx_atomic_dec(::cpp::Pointer inPtr ); // Assumptions made: -// Everyone uses GCC, Clang or MSVC // People are not using 8 year old versions of GCC. #if defined(__GNUC__) || defined(__clang__) #define HX_GCC_ATOMICS +#define HX_HAS_ATOMIC 1 #elif defined(_MSC_VER) #define HX_MSVC_ATOMICS +#define HX_HAS_ATOMIC 1 #include -#else // Nearly everyone uses GCC, Clang or MSVC, right? -#error "Neither GCC, clang or MSVC is being used. Please contribute the relevant atomic instrinsics for your compiler." +#else +#define HX_HAS_ATOMIC 0 #endif inline int _hx_atomic_add(volatile int *a, int b) { @@ -323,6 +324,10 @@ inline int _hx_atomic_add(volatile int *a, int b) { return __atomic_fetch_add(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) return _InterlockedExchangeAdd((long volatile *)a, b); +#else + int old = *a; + *a += b; + return old; #endif } @@ -331,6 +336,10 @@ inline int _hx_atomic_sub(volatile int *a, int b) { return __atomic_fetch_sub(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) return _InterlockedExchangeAdd((long volatile *)a, -b); +#else + int old = *a; + *a -= b; + return old; #endif } @@ -339,6 +348,10 @@ inline int _hx_atomic_and(volatile int *a, int b) { return __atomic_fetch_and(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) return _InterlockedAnd((long volatile *)a, b); +#else + int old = *a; + *a &= b; + return old; #endif } @@ -347,6 +360,10 @@ inline int _hx_atomic_or(volatile int *a, int b) { return __atomic_fetch_or(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) return _InterlockedOr((long volatile *)a, b); +#else + int old = *a; + *a |= b; + return old; #endif } @@ -355,6 +372,10 @@ inline int _hx_atomic_xor(int *a, int b) { return __atomic_fetch_xor(a, b, __ATOMIC_SEQ_CST); #elif defined(HX_MSVC_ATOMICS) return _InterlockedXor((long volatile *)a, b); +#else + int old = *a; + *a ^= b; + return old; #endif } @@ -366,6 +387,12 @@ inline int _hx_atomic_compare_exchange(volatile int *a, int expected, return _expected; #elif defined(HX_MSVC_ATOMICS) return _InterlockedCompareExchange((long volatile *)a, replacement, expected); +#else + int old = *a; + if(old == expected) { + *a = replacement; + } + return old; #endif } @@ -376,6 +403,10 @@ inline int _hx_atomic_exchange(volatile int *a, int replacement) { return ret; #elif defined(HX_MSVC_ATOMICS) return _InterlockedExchange((long volatile *)a, replacement); +#else + int old = *a; + *a = replacement; + return old; #endif } @@ -386,6 +417,8 @@ inline int _hx_atomic_load(volatile int *a) { return ret; #elif defined(HX_MSVC_ATOMICS) return _InterlockedXor((long volatile *)a, 0); +#else + return *a; #endif } @@ -396,6 +429,9 @@ inline int _hx_atomic_store(volatile int *a, int value) { #elif defined(HX_MSVC_ATOMICS) _InterlockedExchange((long volatile *)a, value); return value; +#else + *a = value; + return value; #endif } @@ -406,6 +442,10 @@ inline void* _hx_atomic_compare_exchange_ptr(volatile void **a, void *expected, return _expected; #elif defined(HX_MSVC_ATOMICS) return _InterlockedCompareExchangePointer((void *volatile *)a, replacement, expected); +#else + void *old = *a; + *a = replacement; + return old; #endif }