diff options
author | Ilya Kurdyukov <ilyakurdyukov@altlinux.org> | 2021-07-02 12:00:00 +0700 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2022-01-12 09:59:55 +0300 |
commit | 9ddbbae8e860c779d7fa548daceb1130916059ff (patch) | |
tree | 272389e85cd443134e6351672ae3a5f4474f7899 /mach_dep.c | |
parent | 7ef3eca8a709ce679664e280a44a828fb7caba5e (diff) | |
download | bdwgc-9ddbbae8e860c779d7fa548daceb1130916059ff.tar.gz |
Support Elbrus 2000 (Linux/e2k)
(a port of altlinux libgc-e2k.patch (8ed786c))
Issue #411 (bdwgc).
* include/gc/gc.h [__GNUC__ && !__INTEL_COMPILER && __e2k__]
(GC_reachable_here): Specify "r" contraint for ptr.
* include/gc/gc.h [__e2k__] (GC_stack_base): Declare reg_base field.
* include/private/gc_priv.h [E2K] (GC_push_all_register_sections,
GC_save_regs_in_stack, GC_get_procedure_stack): Declare.
* include/private/gc_priv.h [E2K && __ptr64__] (LOAD_TAGGED_VALUE):
Define macro.
* include/private/gc_priv.h (LOAD_WORD_OR_CONTINUE): Likewise.
* include/private/gcconfig.h [LINUX && __e2k__] (E2K, mach_type_known):
Likewise.
* include/private/gcconfig.h [E2K] (MACH_TYPE, CPP_WORDSZ, ALIGNMENT,
HBLKSIZE): Likewise.
* include/private/gcconfig.h [E2K && LINUX] (DATASTART): Likewise.
* mach_dep.c [E2K] (VA_SIZE, E2K_PSHTP_SIZE, get_stack_index):
Likewise.
* include/private/gcconfig.h [GC_GNUC_PREREQ(2,8)]
(HAVE_BUILTIN_UNWIND_INIT): Do not define if E2K.
* include/private/gcconfig.h [E2K && LINUX] (__dso_handle): Declare
extern variable.
* include/private/pthread_support.h [E2K] (GC_Thread_Rep): Declare
backing_store_end and backing_store_ptr fields.
* mach_dep.c [E2K]: Include errno.h, sys/syscall.h, asm/e2k_syswork.h.
* mach_dep.c [E2K] (e2k_rwap_lo_fields, e2k_rwap_hi_fields): Declare
struct.
* mach_dep.c [E2K] (e2k_rwap_lo_u, e2k_rwap_hi_u): Declare union.
* mach_dep.c [E2K] (GC_get_procedure_stack, GC_save_regs_in_stack):
Implement.
* mach_dep.c [E2K] (GC_with_callee_saves_pushed): Call
GC_save_regs_in_stack() (not saving the result).
* mark.c (GC_mark_from, GC_push_all_eager): Use LOAD_WORD_OR_CONTINUE()
instead of direct dereference of current_p.
* mark.c [!SMALL_CONFIG] (GC_mark_from): Do not prefetch if E2K.
* mark_rts.c [E2K] (GC_push_all_register_sections): Implement but
ignore traced_stack_sect (add TODO item).
* mark_rts.c [!THREADS && E2K] (GC_push_current_stack): Call
GC_get_procedure_stack() and GC_push_all_register_sections().
* misc.c [E2K] (GC_call_with_stack_base): Initialize reg_base to 0.
* misc.c [!THREADS && E2K] (GC_do_blocking_inner,
GC_get_my_stackbottom): Likewise.
* os_dep.c [((HAVE_PTHREAD_ATTR_GET_NP || HAVE_PTHREAD_GETATTR_NP)
&& THREADS || !HAVE_GET_STACK_BASE) && E2K] (GC_get_stack_base):
Likewise.
* pthread_support.c [E2K] (GC_get_my_stackbottom): Likewise.
* pthread_stop_world.c [E2K] (GC_suspend_handler): Call
GC_with_callee_saves_pushed().
* pthread_stop_world.c [E2K] (GC_store_stack_ptr): Call
GC_save_regs_in_stack() and GC_get_procedure_stack().
* pthread_stop_world.c [E2K] (GC_suspend_handler_inner): Call
free(me->backing_store_end) before return.
* pthread_stop_world.c [E2K] (GC_push_all_stacks): Declare bs_lo,
bs_hi, stack_size local variables; call GC_save_regs_in_stack() and
GC_get_procedure_stack() (and free() at the end) for self thread;
call GC_push_all_register_sections().
* pthread_support.c [E2K] (GC_do_blocking_inner): Call
GC_save_regs_in_stack(); add FIXME.
Diffstat (limited to 'mach_dep.c')
-rw-r--r-- | mach_dep.c | 105 |
1 files changed, 103 insertions, 2 deletions
@@ -26,6 +26,104 @@ # endif #endif +#ifdef E2K +# include <errno.h> +# include <sys/syscall.h> + +# include <asm/e2k_syswork.h> + +# define VA_SIZE 48 +# define E2K_PSHTP_SIZE 12 + + struct e2k_rwap_lo_fields { + word base : VA_SIZE; /* [VA_SIZE-1:0] */ + }; + + union e2k_rwap_lo_u { + struct e2k_rwap_lo_fields fields; + word w; + }; + + struct e2k_rwap_hi_fields { + word curptr : 32; /* [31:0] */ + }; + + union e2k_rwap_hi_u { + struct e2k_rwap_hi_fields fields; + word w; + }; + +# define get_stack_index(ps_ptr) \ + do { \ + union e2k_rwap_lo_u psp_lo; \ + union e2k_rwap_hi_u psp_hi; \ + signed_word pshtp; \ + char tmp = 0; \ + char val = 0; \ + \ + __asm__ __volatile__ ( \ + "1:\n\t" \ + "ldb [%[tmp] + 0x0] 0x7, %[val]\n\t" \ + "rrd %%pshtp, %[pshtp]\n\t" \ + "rrd %%psp.lo, %[psp_lo]\n\t" \ + "rrd %%psp.hi, %[psp_hi]\n\t" \ + "stb [%[tmp] + 0x0] 0x2, %[val]\n\t" \ + "ibranch 1b ? %%MLOCK\n" \ + : [val] "=&r" (val), \ + [psp_lo] "=&r" (psp_lo.w), \ + [psp_hi] "=&r" (psp_hi.w), \ + [pshtp] "=&r" (pshtp) \ + : [tmp] "r" (&tmp)); \ + *(ps_ptr) = psp_lo.fields.base + psp_hi.fields.curptr \ + + 2 * ((word)((pshtp << (64 - E2K_PSHTP_SIZE)) \ + >> (64 - E2K_PSHTP_SIZE))); \ + } while (0) + + GC_INNER size_t GC_get_procedure_stack(ptr_t *buf_ptr) { + word ps; + ptr_t buf = NULL; + word buf_sz = 0; + word new_sz = 0; + + get_stack_index(&ps); + for (;;) { + int res = syscall(__NR_access_hw_stacks, E2K_READ_PROCEDURE_STACK, + &ps, buf, buf_sz, &new_sz); + + if (res != -1) break; + if (ENOMEM == errno && buf_sz != new_sz) { + /* FIXME: use GC_scratch_alloc to support malloc redirection? */ + free(buf); + buf = malloc((size_t)new_sz); + if (NULL == buf) + ABORT_ARG1("Could not allocate memory for procedure stack", + ", %lu bytes requested", (unsigned long)new_sz); + if (0 == buf_sz) { + buf_sz = new_sz; + continue; /* skip get_stack_index() once */ + } + buf_sz = new_sz; + } else if (errno != EAGAIN) { + ABORT_ARG1("Cannot read procedure stack", ": errno= %d", errno); + } + get_stack_index(&ps); + } + + if (buf_sz != new_sz) + ABORT_ARG2("Buffer size mismatch while reading procedure stack", + ": buf_sz= %lu, new_sz= %lu", + (unsigned long)buf_sz, (unsigned long)new_sz); + GC_ASSERT(buf != NULL); + *buf_ptr = buf; + return (size_t)buf_sz; + } + + ptr_t GC_save_regs_in_stack(void) { + __asm__ __volatile__ ("flushr"); + return NULL; + } +#endif /* E2K */ + #if defined(MACOS) && defined(__MWERKS__) #if defined(POWERPC) @@ -286,11 +384,14 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *), ABORT("feenableexcept failed"); # endif # endif /* GETCONTEXT_FPU_EXCMASK_BUG */ -# if defined(SPARC) || defined(IA64) +# if defined(E2K) || defined(IA64) || defined(SPARC) /* On a register window machine, we need to save register */ /* contents on the stack for this to work. This may already be */ /* subsumed by the getcontext() call. */ - GC_save_regs_ret_val = GC_save_regs_in_stack(); +# if defined(IA64) || defined(SPARC) + GC_save_regs_ret_val = +# endif + GC_save_regs_in_stack(); # endif if (NULL == context) /* getcontext failed */ # endif /* !NO_GETCONTEXT */ |