diff --git a/src/hx/gc/CapturedState.arm64.cpp b/src/hx/gc/CapturedState.arm64.cpp new file mode 100644 index 000000000..1ce24a845 --- /dev/null +++ b/src/hx/gc/CapturedState.arm64.cpp @@ -0,0 +1,114 @@ +#include +#include "GcRegCapture.h" + +constexpr size_t intRegSize{ sizeof(uintptr_t) * 31 }; + +hx::gc::CapturedState::CapturedState() + : stackBase(0) + , stackLimit(0) + , registers(intRegSize) +{} + +void hx::gc::Capture(CapturedState& state) +{ + uintptr_t rX0{}; + asm("mov %0, x0\n\t" : "=r" (rX0)); + uintptr_t rX1{}; + asm("mov %0, x1\n\t" : "=r" (rX1)); + uintptr_t rX2{}; + asm("mov %0, x2\n\t" : "=r" (rX2)); + uintptr_t rX3{}; + asm("mov %0, x3\n\t" : "=r" (rX3)); + uintptr_t rX4{}; + asm("mov %0, x4\n\t" : "=r" (rX4)); + uintptr_t rX5{}; + asm("mov %0, x5\n\t" : "=r" (rX5)); + uintptr_t rX6{}; + asm("mov %0, x6\n\t" : "=r" (rX6)); + uintptr_t rX7{}; + asm("mov %0, x7\n\t" : "=r" (rX7)); + uintptr_t rX8{}; + asm("mov %0, x8\n\t" : "=r" (rX8)); + uintptr_t rX9{}; + asm("mov %0, x9\n\t" : "=r" (rX9)); + uintptr_t rX10{}; + asm("mov %0, x10\n\t" : "=r" (rX10)); + uintptr_t rX11{}; + asm("mov %0, x11\n\t" : "=r" (rX11)); + uintptr_t rX12{}; + asm("mov %0, x12\n\t" : "=r" (rX12)); + uintptr_t rX13{}; + asm("mov %0, x13\n\t" : "=r" (rX13)); + uintptr_t rX14{}; + asm("mov %0, x14\n\t" : "=r" (rX14)); + uintptr_t rX15{}; + asm("mov %0, x15\n\t" : "=r" (rX15)); + uintptr_t rX16{}; + asm("mov %0, x16\n\t" : "=r" (rX16)); + uintptr_t rX17{}; + asm("mov %0, x17\n\t" : "=r" (rX17)); + uintptr_t rX18{}; + asm("mov %0, x18\n\t" : "=r" (rX18)); + uintptr_t rX19{}; + asm("mov %0, x19\n\t" : "=r" (rX19)); + uintptr_t rX20{}; + asm("mov %0, x20\n\t" : "=r" (rX20)); + uintptr_t rX21{}; + asm("mov %0, x21\n\t" : "=r" (rX21)); + uintptr_t rX22{}; + asm("mov %0, x22\n\t" : "=r" (rX22)); + uintptr_t rX23{}; + asm("mov %0, x23\n\t" : "=r" (rX23)); + uintptr_t rX24{}; + asm("mov %0, x24\n\t" : "=r" (rX24)); + uintptr_t rX25{}; + asm("mov %0, x25\n\t" : "=r" (rX25)); + uintptr_t rX26{}; + asm("mov %0, x26\n\t" : "=r" (rX26)); + uintptr_t rX27{}; + asm("mov %0, x27\n\t" : "=r" (rX27)); + uintptr_t rX28{}; + asm("mov %0, x28\n\t" : "=r" (rX28)); + uintptr_t rX29{}; + asm("mov %0, x29\n\t" : "=r" (rX29)); + uintptr_t rX30{}; + asm("mov %0, x30\n\t" : "=r" (rX30)); + + uintptr_t rSp{}; + asm("mov %0, sp\n\t" : "=r" (rSp)); + + state.stackLimit = rSp; + + auto pointers = reinterpret_cast(state.registers.data()); + pointers[0] = rX0; + pointers[1] = rX1; + pointers[2] = rX2; + pointers[3] = rX3; + pointers[4] = rX4; + pointers[5] = rX5; + pointers[6] = rX6; + pointers[7] = rX7; + pointers[8] = rX8; + pointers[9] = rX9; + pointers[10] = rX10; + pointers[11] = rX11; + pointers[12] = rX12; + pointers[13] = rX13; + pointers[14] = rX14; + pointers[15] = rX15; + pointers[16] = rX16; + pointers[17] = rX17; + pointers[18] = rX18; + pointers[19] = rX19; + pointers[20] = rX20; + pointers[21] = rX21; + pointers[22] = rX22; + pointers[23] = rX23; + pointers[24] = rX24; + pointers[25] = rX25; + pointers[26] = rX26; + pointers[27] = rX27; + pointers[28] = rX28; + pointers[29] = rX29; + pointers[30] = rX30; +} \ No newline at end of file diff --git a/src/hx/gc/CapturedState.setjmp.cpp b/src/hx/gc/CapturedState.setjmp.cpp new file mode 100644 index 000000000..f275be7cd --- /dev/null +++ b/src/hx/gc/CapturedState.setjmp.cpp @@ -0,0 +1,23 @@ +#include +#include "GcRegCapture.h" +#include + +hx::gc::CapturedState::CapturedState() + : stackBase(0) + , stackLimit(0) + , registers(sizeof(jmp_buf)) +{} + +void hx::gc::Capture(CapturedState& state) +{ + volatile uintptr_t v{}; + state.stackLimit = reinterpret_cast(&v); + + jmp_buf buffer{}; + if (0 != setjmp(buffer)) + { + hx::CriticalError(HX_CSTRING("Failed to save jump buffer")); + } + + std::memcpy(state.registers.data(), buffer, state.registers.size()); +} \ No newline at end of file diff --git a/src/hx/gc/CapturedState.win32.cpp b/src/hx/gc/CapturedState.win32.cpp new file mode 100644 index 000000000..6cf781e14 --- /dev/null +++ b/src/hx/gc/CapturedState.win32.cpp @@ -0,0 +1,61 @@ +#include +#include +#include "GcRegCapture.h" + +// Strictly speaking we don't need tp capture all of the integer registers +// But let's just do it for simplicity + +#if defined(HXCPP_ARM64) +constexpr size_t intRegSize{ sizeof(uintptr_t) * 31 }; +constexpr size_t xmmRegSize{ sizeof(ARM64_NT_NEON128) * 32 }; +#elif defined(HXCPP_M64) +constexpr size_t intRegSize{ sizeof(uintptr_t) * 16 }; +constexpr size_t xmmRegSize{ sizeof(M128A) * 16 }; +#elif defined(HXCPP_M32) +constexpr size_t intRegSize{ sizeof(uintptr_t) * 8 }; +constexpr size_t xmmRegSize{ sizeof(__m128) * 8 }; +#else +#error Unsupported Architecture +#endif + +hx::gc::CapturedState::CapturedState() + : stackBase(0) + , stackLimit(0) + , registers(intRegSize + xmmRegSize) +{} + +void hx::gc::Capture(CapturedState& state) +{ +#if defined(HXCPP_ARM64) + ARM64_NT_CONTEXT context{}; + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_FLOATING_POINT; + RtlCaptureContext(reinterpret_cast(&context)); + + state.stackLimit = context.Sp; + + std::memcpy(state.registers.data(), &context.X, intRegSize); + std::memcpy(state.registers.data() + intRegSize, &context.V, xmmRegSize); +#elif defined(HXCPP_M64) + CONTEXT context{}; + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_FLOATING_POINT; + RtlCaptureContext(&context); + + state.stackLimit = context.Rsp; + + std::memcpy(state.registers.data(), &context.Rax, intRegSize); + std::memcpy(state.registers.data() + intRegSize, &context.Xmm0, xmmRegSize); +#elif defined(HXCPP_M32) + CONTEXT context{}; + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_EXTENDED_REGISTERS; + RtlCaptureContext(&context); + + state.stackLimit = context.Esp; + + // ExtendedRegisters seems to be the x87 FXSAVE area + // So we can offset 160 bytes into it to get the 8 SSE registers + std::memcpy(state.registers.data(), &context.Edi, intRegSize); + std::memcpy(state.registers.data() + intRegSize, reinterpret_cast(&context.ExtendedRegisters) + 160, xmmRegSize); +#else +#error Unsupported Architecture +#endif +} \ No newline at end of file diff --git a/src/hx/gc/CapturedState.x86.cpp b/src/hx/gc/CapturedState.x86.cpp new file mode 100644 index 000000000..b833058a2 --- /dev/null +++ b/src/hx/gc/CapturedState.x86.cpp @@ -0,0 +1,113 @@ +#include +#include +#include "GcRegCapture.h" + +#if defined(HXCPP_M32) +constexpr size_t intRegSize = sizeof(uintptr_t) * 8; +constexpr size_t xmmRegSize = 16 * 8; +#elif defined(HXCPP_M64) +constexpr size_t intRegSize = sizeof(uintptr_t) * 16; +constexpr size_t xmmRegSize = 16 * 16; +#else +#error Unable to determine x86 architecture +#endif + +hx::gc::CapturedState::CapturedState() + : stackBase(0) + , stackLimit(0) + , registers(intRegSize + xmmRegSize) +{} + +void hx::gc::Capture(CapturedState& state) +{ +#if defined(HXCPP_M32) + uintptr_t rEax{}; + asm("mov %%eax, %0\n\t" : "=r" (rEax)); + uintptr_t rEbx{}; + asm("mov %%ebx, %0\n\t" : "=r" (rEbx)); + uintptr_t rEcx{}; + asm("mov %%ecx, %0\n\t" : "=r" (rEcx)); + uintptr_t rEdx{}; + asm("mov %%edx, %0\n\t" : "=r" (rEdx)); + uintptr_t rEbp{}; + asm("mov %%ebp, %0\n\t" : "=r" (rEbp)); + uintptr_t rEdi{}; + asm("mov %%edi, %0\n\t" : "=r" (rEdi)); + uintptr_t rEsi{}; + asm("mov %%esi, %0\n\t" : "=r" (rEsi)); + uintptr_t rEsp{}; + asm("mov %%esp, %0\n\t" : "=r" (rEsp)); + + state.stackLimit = rEsp; + + auto pointers = reinterpret_cast(state.registers.data()); + pointers[0] = rEax; + pointers[1] = rEbx; + pointers[2] = rEcx; + pointers[3] = rEdx; + pointers[4] = rEsi; + pointers[5] = rEdi; + pointers[6] = rEsp; + pointers[7] = rEbp; +#elif defined(HXCPP_M64) + uintptr_t rRax{}; + asm("movq %%rax, %0\n\t" : "=r" (rRax)); + uintptr_t rRbx{}; + asm("movq %%rbx, %0\n\t" : "=r" (rRbx)); + uintptr_t rRcx{}; + asm("movq %%rcx, %0\n\t" : "=r" (rRcx)); + uintptr_t rRdx{}; + asm("movq %%rdx, %0\n\t" : "=r" (rRdx)); + uintptr_t rRsi{}; + asm("movq %%rsi, %0\n\t" : "=r" (rRsi)); + uintptr_t rRdi{}; + asm("movq %%rdi, %0\n\t" : "=r" (rRdi)); + uintptr_t rRsp{}; + asm("movq %%rsp, %0\n\t" : "=r" (rRsp)); + uintptr_t rRbp{}; + asm("movq %%rbp, %0\n\t" : "=r" (rRbp)); + uintptr_t rR8{}; + asm("movq %%r8, %0\n\t" : "=r" (rR8)); + uintptr_t rR9{}; + asm("movq %%r9, %0\n\t" : "=r" (rR9)); + uintptr_t rR10{}; + asm("movq %%r10, %0\n\t" : "=r" (rR10)); + uintptr_t rR11{}; + asm("movq %%r11, %0\n\t" : "=r" (rR11)); + uintptr_t rR12{}; + asm("movq %%r12, %0\n\t" : "=r" (rR12)); + uintptr_t rR13{}; + asm("movq %%r13, %0\n\t" : "=r" (rR13)); + uintptr_t rR14{}; + asm("movq %%r14, %0\n\t" : "=r" (rR14)); + uintptr_t rR15{}; + asm("movq %%r15, %0\n\t" : "=r" (rR15)); + + state.stackLimit = rRsp; + + auto pointers = reinterpret_cast(state.registers.data()); + pointers[ 0] = rRax; + pointers[ 1] = rRbx; + pointers[ 2] = rRcx; + pointers[ 3] = rRdx; + pointers[ 4] = rRsi; + pointers[ 5] = rRdi; + pointers[ 6] = rRsp; + pointers[ 7] = rRbp; + pointers[ 8] = rR8; + pointers[ 9] = rR9; + pointers[10] = rR10; + pointers[11] = rR11; + pointers[12] = rR12; + pointers[13] = rR13; + pointers[14] = rR14; + pointers[15] = rR15; +#else +#error Unable to determine x86 architecture +#endif + + char fxsaveRegion[512] __attribute__((aligned(16))); + _fxsave(fxsaveRegion); + + std::memcpy(state.registers.data() + intRegSize, fxsaveRegion + 160, xmmRegSize); +} \ No newline at end of file diff --git a/src/hx/gc/GcRegCapture.h b/src/hx/gc/GcRegCapture.h index 61e41713d..5618f954e 100644 --- a/src/hx/gc/GcRegCapture.h +++ b/src/hx/gc/GcRegCapture.h @@ -1,6 +1,8 @@ #ifndef HX_GC_HELPERS_INCLUDED #define HX_GC_HELPERS_INCLUDED +#include + #if defined(HX_WINDOWS) && defined(HXCPP_ARM64) // Eg, Microsoft Surface #define HXCPP_CAPTURE_SETJMP @@ -27,10 +29,26 @@ #endif +#include namespace hx { - + namespace gc + { + struct CapturedState + { + // Base is the address that stack scanning begins and it goes until it reaches the limit value. + // I'm avoiding "top" and "bottom" terminology because emscripten has the stack "upside down" in comparison to everything else. + + uintptr_t stackBase; + uintptr_t stackLimit; + std::vector registers; + + CapturedState(); + }; + + void Capture(CapturedState& buffer); + } // Capture Registers // #ifdef HXCPP_CAPTURE_SETJMP // { diff --git a/src/hx/gc/Immix.cpp b/src/hx/gc/Immix.cpp index fab5d8812..3253d8497 100644 --- a/src/hx/gc/Immix.cpp +++ b/src/hx/gc/Immix.cpp @@ -5769,13 +5769,7 @@ class LocalAllocator : public hx::StackContext bool mMoreHoles; - #ifndef HXCPP_EXPLICIT_STACK_EXTENT - int *mTopOfStack; - int *mBottomOfStack; - #endif - - hx::RegisterCaptureBuffer mRegisterBuf; - int mRegisterBufSize; + ::hx::gc::CapturedState state; #ifndef HXCPP_SINGLE_THREADED_APP bool mGCFreeZone; @@ -5810,11 +5804,8 @@ class LocalAllocator : public hx::StackContext void AttachThread(int *inTopOfStack) { - #ifndef HXCPP_EXPLICIT_STACK_EXTENT - mTopOfStack = mBottomOfStack = inTopOfStack; - #endif + state.stackBase = state.stackLimit = reinterpret_cast(inTopOfStack); - mRegisterBufSize = 0; mStackLocks = 0; mGlobalStackLock = false; #ifdef HX_WINDOWS @@ -5870,10 +5861,6 @@ class LocalAllocator : public hx::StackContext } #endif - #ifndef HXCPP_EXPLICIT_STACK_EXTENT - mTopOfStack = mBottomOfStack = 0; - #endif - sGlobalAlloc->RemoveLocalLocked(this); hx::tlsStackContext = 0; @@ -5948,8 +5935,8 @@ class LocalAllocator : public hx::StackContext { if (inTop) { - if (!mTopOfStack) - mTopOfStack = inTop; + if (!state.stackBase) + state.stackBase = reinterpret_cast(inTop); // EMSCRIPTEN the stack grows upwards - not wasm. // It could be that the main routine was called from deep with in the stack, // then some callback was called from a higher location on the stack @@ -5957,8 +5944,8 @@ class LocalAllocator : public hx::StackContext else if (inTop < mTopOfStack) mTopOfStack = inTop; #else - else if (inTop > mTopOfStack) - mTopOfStack = inTop; + else if (reinterpret_cast(inTop) > state.stackBase) + state.stackBase = reinterpret_cast(inTop); #endif if (inPush) @@ -6009,7 +5996,7 @@ class LocalAllocator : public hx::StackContext void SetBottomOfStack(int *inBottom) { - mBottomOfStack = inBottom; + state.stackLimit = reinterpret_cast(inBottom); #ifdef VerifyStackRead VerifyStackRead(mBottomOfStack, mTopOfStack) #endif @@ -6018,10 +6005,7 @@ class LocalAllocator : public hx::StackContext void PauseForCollect() { - #ifndef HXCPP_SINGLE_THREADED_APP - volatile int dummy = 1; - mBottomOfStack = (int *)&dummy; - CAPTURE_REGS; + ::hx::gc::Capture(state); #ifdef VerifyStackRead VerifyStackRead(mBottomOfStack, mTopOfStack) #endif @@ -6031,25 +6015,17 @@ class LocalAllocator : public hx::StackContext mReadyForCollect.Set(); mCollectDone.Wait(); - #endif } void EnterGCFreeZone() { - #ifndef HXCPP_SINGLE_THREADED_APP - volatile int dummy = 1; - mBottomOfStack = (int *)&dummy; - if (mTopOfStack) - { - CAPTURE_REGS; - } + ::hx::gc::Capture(state); #ifdef VerifyStackRead VerifyStackRead(mBottomOfStack, mTopOfStack) #endif mGCFreeZone = true; mReadyForCollect.Set(); - #endif } bool TryGCFreeZone() @@ -6152,30 +6128,24 @@ class LocalAllocator : public hx::StackContext #endif #endif - #ifndef HXCPP_EXPLICIT_STACK_EXTENT - volatile int dummy = 1; - mBottomOfStack = (int *)&dummy; + ::hx::gc::Capture(state); - CAPTURE_REGS; - - if (!mTopOfStack) - mTopOfStack = mBottomOfStack; + if (!state.stackBase) + state.stackBase = state.stackLimit; // EMSCRIPTEN the stack grows upwards #ifdef HXCPP_STACK_UP if (mBottomOfStack < mTopOfStack) mTopOfStack = mBottomOfStack; #else - if (mBottomOfStack > mTopOfStack) - mTopOfStack = mBottomOfStack; + if (state.stackLimit > state.stackBase) + state.stackBase = state.stackLimit; #endif #ifdef VerifyStackRead VerifyStackRead(mBottomOfStack, mTopOfStack) #endif - #endif - sGlobalAlloc->Collect(inMajor, inForceCompact, inLocked, inFreeIsFragged); } @@ -6370,13 +6340,11 @@ class LocalAllocator : public hx::StackContext void Mark(hx::MarkContext *__inCtx) { - #ifndef HXCPP_SINGLE_THREADED_APP - if (!mTopOfStack) + if (!state.stackBase) { Reset(); return; } - #endif #ifdef SHOW_MEM_EVENTS //int here = 0; @@ -6390,8 +6358,8 @@ class LocalAllocator : public hx::StackContext #ifdef HXCPP_EXPLICIT_STACK_EXTENT hx::MarkConservative( (int *)emscripten_stack_get_current(),(int *)emscripten_stack_get_base(), __inCtx); #else - if (mTopOfStack && mBottomOfStack) - hx::MarkConservative(mBottomOfStack, mTopOfStack , __inCtx); + if (state.stackBase && state.stackLimit) + hx::MarkConservative(reinterpret_cast(state.stackLimit), reinterpret_cast(state.stackBase), __inCtx); #endif #ifdef HXCPP_SCRIPTABLE @@ -6399,7 +6367,7 @@ class LocalAllocator : public hx::StackContext hx::MarkConservative((int *)(stack), (int *)(pointer),__inCtx); #endif MarkSetMember("Registers",__inCtx); - hx::MarkConservative(CAPTURE_REG_START, CAPTURE_REG_END, __inCtx); + hx::MarkConservative(reinterpret_cast(state.registers.data()), reinterpret_cast(state.registers.data() + state.registers.size()), __inCtx); MarkPopClass(__inCtx); @@ -6408,9 +6376,9 @@ class LocalAllocator : public hx::StackContext #ifdef HXCPP_EXPLICIT_STACK_EXTENT hx::MarkConservative( (int *)emscripten_stack_get_current(), (int *) emscripten_stack_get_base(), __inCtx); #else - if (mTopOfStack && mBottomOfStack) - hx::MarkConservative(mBottomOfStack, mTopOfStack , __inCtx); - hx::MarkConservative(CAPTURE_REG_START, CAPTURE_REG_END, __inCtx); + if (state.stackBase && state.stackLimit) + hx::MarkConservative(reinterpret_cast(state.stackLimit), reinterpret_cast(state.stackBase), __inCtx); + hx::MarkConservative(reinterpret_cast(state.registers.data()), reinterpret_cast(state.registers.data() + state.registers.size()), __inCtx); #endif #ifdef HXCPP_SCRIPTABLE diff --git a/toolchain/common-defines.xml b/toolchain/common-defines.xml index e2f241bb4..6e47e9b9a 100644 --- a/toolchain/common-defines.xml +++ b/toolchain/common-defines.xml @@ -5,6 +5,7 @@ + diff --git a/toolchain/haxe-target.xml b/toolchain/haxe-target.xml index 86da1a8ce..024e19c78 100644 --- a/toolchain/haxe-target.xml +++ b/toolchain/haxe-target.xml @@ -191,6 +191,15 @@ +
+ +
+
+ + + +
+
diff --git a/toolchain/linux-toolchain.xml b/toolchain/linux-toolchain.xml index dbf012e4d..3fecfa9cb 100644 --- a/toolchain/linux-toolchain.xml +++ b/toolchain/linux-toolchain.xml @@ -49,6 +49,7 @@ +