[M3devel] getting all registers in gc?

Jay K jay.krell at cornell.edu
Mon Jun 27 11:14:13 CEST 2016


ok, the Boehm code:

For the current live thread, merely:

                        /* Push enough of the current stack eagerly to  */
                        /* ensure that callee-save registers saved in   */
                        /* GC frames are scanned.                       */
                        /* In the non-threads case, schedule entire     */
                        /* stack for scanning.                          */
                        /* The second argument is a pointer to the      */
                        /* (possibly null) thread context, for          */
                        /* (currently hypothetical) more precise        */
                        /* stack scanning.                              */
/*
 * In the absence of threads, push the stack contents.
 * In the presence of threads, push enough of the current stack
 * to ensure that callee-save registers saved in collector frames have been
 * seen.
 * FIXME: Merge with per-thread stuff.
 */
/*ARGSUSED*/
STATIC void GC_push_current_stack(ptr_t cold_gc_frame, void * context)
{
#   if defined(THREADS)
        if (0 == cold_gc_frame) return;
#       ifdef STACK_GROWS_DOWN
          GC_push_all_eager(GC_approx_sp(), cold_gc_frame);
          /* For IA64, the register stack backing store is handled      */
          /* in the thread-specific code.                               */
#       else
          GC_push_all_eager(cold_gc_frame, GC_approx_sp());
#       endif
#   else
...
#   endif /* !THREADS */


GC_INNER ptr_t GC_approx_sp(void)
{
    volatile word sp;
    sp = (word)&sp;
                /* Also force stack to grow if necessary. Otherwise the */
                /* later accesses might cause the kernel to think we're */
                /* doing something wrong.                               */
    return((ptr_t)sp);
                /* GNU C: alternatively, we may return the value of     */
                /*__builtin_frame_address(0).                           */
}


Notice that it doesn't even do what it says -- no attempt
to save registers to stack.


but for suspended threads it is more convincing:


/* Ensure that either registers are pushed, or callee-save registers    */
/* are somewhere on the stack, and then call fn(arg, ctxt).             */
/* ctxt is either a pointer to a ucontext_t we generated, or NULL.      */
GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
                                          ptr_t arg)
{
    volatile int dummy;
    void * context = 0;


..
....


 a mix of methods: 
  - sometimes processor specific assembly 
  - sometimes getcontext, and then workaround a bug on Linux/amd64 
  - and then _setjmp on Unix 
  - setjmp on Windows 


 getcontext to me seems more promising than setjmp,
 and you can use both
 
  for Win32, I suggest RtlCaptureContext (for live thread too)
  
  
  We maybe should copy getcontext from various BSDs?
  i.e. Win32 RtlCaptureContext, else carry the assembly with us (no need
  to worry about the glibc getcontext bug).

or maybe just getcontext. The gradually expanding register set on x86 makes me nervous
that this isn't a maintenance problem, but I'm guessing you never get pointers
spilled to the ymm/zmm registers.

 - Jay



----------------------------------------
> From: jay.krell at cornell.edu
> To: m3devel at elegosoft.com
> Date: Mon, 27 Jun 2016 08:37:12 +0000
> Subject: [M3devel] getting all registers in gc?
>
> I just noticed this in the Boehm GC documentation:
>
> - Changed the alpha port to use the generic register scanning code instead
> of alpha_mach_dep.s. Alpha_mach_dep.s doesn't look for pointers in fp
> registers, but gcc sometimes spills pointers there. (Thanks to Manuel
> Serrano for helping me debug this by email.) Changed the IA64 code to
> do something similar for similar reasons.
>
>
> This would seem like a hazard for us too.
>
> And not convincingly Alpha/IA64-specific.
>
> We basically assume setjmp stores a context, or at least all live pointers.
>
>
> In hindsight I see two problems:
> - one alluded to -- jmpbuf might not have floating point registers,
> and floating point registers might have pointers.
>
>
> - Same thing but more general: jmpbuf might not even have all integer
> registers?
>
>
>
> So that leaves the question "What is generic register scanning code"?
>
> I don't know yet but..thinking...
>
> Maybe we should instead use Posix-deprecated getcontext and Win32 RtlCaptureContext?
>
> I'm actually looking for how Boehm gc gets the "second half" of the IA64 stack,
> as I think that is a lingering thing we need to handle to finish our portability.
>
> Ignoring IA64 for now, maybe here:
>
> void
> __cdecl
> ThreadPThread__sigsuspend(void)
> {
> struct {
> sigjmp_buf jb;
> } s;
>
> ZERO_MEMORY(s);
>
> if (sigsetjmp(s.jb, 0) == 0) /* save registers to stack */
> #ifdef M3_REGISTER_WINDOWS
> siglongjmp(s.jb, 1); /* flush register windows */
> else
> #endif
> sigsuspend(&mask);
> }
>
>
> and here:
>
> void
> __cdecl
> ThreadPThread__ProcessLive(char *bottom, void (*p)(void *start, void *limit))
> {
> struct {
> sigjmp_buf jb;
> } s;
>
> ZERO_MEMORY(s);
>
> if (sigsetjmp(s.jb, 0) == 0) /* save registers to stack */
>
>
> we should use getcontext/RtlCaptureContext/GetThreadContext?
>
>
> I'll look more at the Boehm code.
>
>
> - Jay
>
>
>
>
> _______________________________________________
> M3devel mailing list
> M3devel at elegosoft.com
> https://m3lists.elegosoft.com/mailman/listinfo/m3devel
 		 	   		  


More information about the M3devel mailing list