From 2ffcdddf4a98c2d61a83e14d96a909ae99264fc9 Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <vital.had@gmail.com>
Date: Sun, 4 Feb 2024 01:58:18 +0800
Subject: [PATCH] gc: backport basic arm64 support for Darwin

https://github.com/ivmai/bdwgc/commit/d5d091accae6046d2a5dadb283e110b31f4684bd
https://github.com/ivmai/bdwgc/commit/0a8d46700a9d633ab8167c7781f314742630d186
https://github.com/ivmai/bdwgc/commit/02954567894bc270ffe7cb075448b56a706c9381

See: https://github.com/Constellation/iv/issues/107

darwin_stop_world.c: arm64
---
 iv/lv5/third_party/gc/darwin_stop_world.c     | 48 ++++++++++++++++++-
 .../third_party/gc/include/private/gc_priv.h  | 20 ++++----
 .../third_party/gc/include/private/gcconfig.h | 29 ++++++++++-
 iv/lv5/third_party/gc/os_dep.c                |  5 ++
 4 files changed, 91 insertions(+), 11 deletions(-)

diff --git iv/lv5/third_party/gc/darwin_stop_world.c iv/lv5/third_party/gc/darwin_stop_world.c
index 14aa1d36..551eb898 100644
--- iv/lv5/third_party/gc/darwin_stop_world.c
+++ iv/lv5/third_party/gc/darwin_stop_world.c
@@ -53,13 +53,19 @@ GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
 {
   StackFrame *frame;
 
-# ifdef POWERPC
+# if defined(POWERPC) || defined(AARCH64)
     if (stack_start == 0) {
+#   ifdef POWERPC
 #     if CPP_WORDSZ == 32
         __asm__ __volatile__ ("lwz %0,0(r1)" : "=r" (frame));
 #     else
         __asm__ __volatile__ ("ld %0,0(r1)" : "=r" (frame));
 #     endif
+#   elif defined(AARCH64)
+        volatile ptr_t sp_reg;
+        __asm__ __volatile__ ("mov %0, x29\n" : "=r" (sp_reg));
+        frame = (StackFrame *)sp_reg;
+#   endif
     } else
 # else
     GC_ASSERT(stack_start != 0); /* not implemented */
@@ -248,6 +254,46 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
       /* GC_push_one(state.__pc); */
       GC_push_one(state.__cpsr);
 
+#   elif defined(AARCH64)
+      lo = (void *)state.__sp;
+#     ifndef DARWIN_DONT_PARSE_STACK
+        *phi = GC_FindTopOfStack(state.__sp);
+#     endif
+      GC_push_one(state.__x[0]);
+      GC_push_one(state.__x[1]);
+      GC_push_one(state.__x[2]);
+      GC_push_one(state.__x[3]);
+      GC_push_one(state.__x[4]);
+      GC_push_one(state.__x[5]);
+      GC_push_one(state.__x[6]);
+      GC_push_one(state.__x[7]);
+      GC_push_one(state.__x[8]);
+      GC_push_one(state.__x[9]);
+      GC_push_one(state.__x[10]);
+      GC_push_one(state.__x[11]);
+      GC_push_one(state.__x[12]);
+      GC_push_one(state.__x[13]);
+      GC_push_one(state.__x[14]);
+      GC_push_one(state.__x[15]);
+      GC_push_one(state.__x[16]);
+      GC_push_one(state.__x[17]);
+      GC_push_one(state.__x[18]);
+      GC_push_one(state.__x[19]);
+      GC_push_one(state.__x[20]);
+      GC_push_one(state.__x[21]);
+      GC_push_one(state.__x[22]);
+      GC_push_one(state.__x[23]);
+      GC_push_one(state.__x[24]);
+      GC_push_one(state.__x[25]);
+      GC_push_one(state.__x[26]);
+      GC_push_one(state.__x[27]);
+      GC_push_one(state.__x[28]);
+      GC_push_one(state.__fp);
+      GC_push_one(state.__lr);
+      /* GC_push_one(state.__sp); */
+      /* GC_push_one(state.__pc); */
+      /* GC_push_one(state.__cpsr); */
+
 #   else
 #     error FIXME for non-x86 || ppc || arm architectures
 #   endif
diff --git iv/lv5/third_party/gc/include/private/gc_priv.h iv/lv5/third_party/gc/include/private/gc_priv.h
index 0ad92fc4..56fa0b71 100644
--- iv/lv5/third_party/gc/include/private/gc_priv.h
+++ iv/lv5/third_party/gc/include/private/gc_priv.h
@@ -587,16 +587,18 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
 #     define GC_MACH_THREAD_STATE       x86_THREAD_STATE64
 #     define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
 #   endif
-# else
-#   if defined(ARM32)
-#     define GC_THREAD_STATE_T                  arm_thread_state_t
-#     ifdef ARM_MACHINE_THREAD_STATE_COUNT
-#       define GC_MACH_THREAD_STATE             ARM_MACHINE_THREAD_STATE
-#       define GC_MACH_THREAD_STATE_COUNT       ARM_MACHINE_THREAD_STATE_COUNT
-#     endif
-#   else
-#     error define GC_THREAD_STATE_T
+# elif defined(ARM32)
+#   define GC_THREAD_STATE_T            arm_thread_state_t
+#   ifdef ARM_MACHINE_THREAD_STATE_COUNT
+#     define GC_MACH_THREAD_STATE       ARM_MACHINE_THREAD_STATE
+#     define GC_MACH_THREAD_STATE_COUNT ARM_MACHINE_THREAD_STATE_COUNT
 #   endif
+# elif defined(AARCH64)
+#   define GC_THREAD_STATE_T            arm_thread_state64_t
+#   define GC_MACH_THREAD_STATE         ARM_THREAD_STATE64
+#   define GC_MACH_THREAD_STATE_COUNT   ARM_THREAD_STATE64_COUNT
+# else
+#   error define GC_THREAD_STATE_T
 # endif
 # ifndef GC_MACH_THREAD_STATE
 #   define GC_MACH_THREAD_STATE         MACHINE_THREAD_STATE
diff --git iv/lv5/third_party/gc/include/private/gcconfig.h iv/lv5/third_party/gc/include/private/gcconfig.h
index c753cc2b..0df3551d 100644
--- iv/lv5/third_party/gc/include/private/gcconfig.h
+++ iv/lv5/third_party/gc/include/private/gcconfig.h
@@ -97,7 +97,7 @@
 # endif
 # if defined(__aarch64__)
 #    define AARCH64
-#    if !defined(LINUX)
+#    if !defined(LINUX) && !defined(DARWIN)
 #      define NOSYS
 #      define mach_type_known
 #    endif
@@ -368,6 +368,10 @@
 #    define ARM32
 #    define mach_type_known
 #    define DARWIN_DONT_PARSE_STACK
+#   elif defined(__aarch64__)
+#    define AARCH64
+#    define mach_type_known
+#    define DARWIN_DONT_PARSE_STACK
 #   endif
 # endif
 # if defined(__rtems__) && (defined(i386) || defined(__i386__))
@@ -1998,6 +2002,29 @@
       extern char _end[];
 #     define DATAEND ((ptr_t)(&_end))
 #   endif
+#   ifdef DARWIN
+      /* iOS */
+#     define OS_TYPE "DARWIN"
+#     ifndef GC_DONT_REGISTER_MAIN_STATIC_DATA
+#       define DYNAMIC_LOADING
+#     endif
+#     define DATASTART ((ptr_t) get_etext())
+#     define DATAEND   ((ptr_t) get_end())
+#     define STACKBOTTOM ((ptr_t) 0x16fdfffff)
+#     ifndef USE_MMAP
+#       define USE_MMAP
+#     endif
+#     define USE_MMAP_ANON
+#     define MPROTECT_VDB
+#     include <unistd.h>
+#     define GETPAGESIZE() getpagesize()
+      /* FIXME: There seems to be some issues with trylock hanging on   */
+      /* darwin. This should be looked into some more.                  */
+#     define NO_PTHREAD_TRYLOCK
+#     ifndef NO_DYLD_BIND_FULLY_IMAGE
+#       define NO_DYLD_BIND_FULLY_IMAGE
+#     endif
+#   endif
 #   ifdef NOSYS
       /* __data_start is usually defined in the target linker script.   */
       extern int __data_start[];
diff --git iv/lv5/third_party/gc/os_dep.c iv/lv5/third_party/gc/os_dep.c
index 08c501df..2a124781 100644
--- iv/lv5/third_party/gc/os_dep.c
+++ iv/lv5/third_party/gc/os_dep.c
@@ -4274,6 +4274,11 @@ STATIC kern_return_t GC_forward_exception(mach_port_t thread, mach_port_t task,
 # define DARWIN_EXC_STATE_COUNT   ARM_EXCEPTION_STATE_COUNT
 # define DARWIN_EXC_STATE_T       arm_exception_state_t
 # define DARWIN_EXC_STATE_DAR     THREAD_FLD(far)
+#elif defined(AARCH64)
+# define DARWIN_EXC_STATE         ARM_EXCEPTION_STATE64
+# define DARWIN_EXC_STATE_COUNT   ARM_EXCEPTION_STATE64_COUNT
+# define DARWIN_EXC_STATE_T       arm_exception_state64_t
+# define DARWIN_EXC_STATE_DAR     THREAD_FLD(far)
 #elif defined(POWERPC)
 # if CPP_WORDSZ == 32
 #   define DARWIN_EXC_STATE       PPC_EXCEPTION_STATE
