runtime: scan register backing store on ia64

On ia64, a separate stack is used for saving/restoring register frames,
    occupying the other end of the stack mapping. This must also be scanned
    for pointers into the heap.
    
    Reviewed-on: https://go-review.googlesource.com/85276

From-SVN: r257323
This commit is contained in:
Ian Lance Taylor 2018-02-02 00:16:43 +00:00
parent 2e30f1ee86
commit 38f08ec0bd
5 changed files with 44 additions and 1 deletions

View File

@ -1,4 +1,4 @@
e148068360699f24118950b728f23a5c98e1f85e
5e8a91bf239c253d7b5c84bd2c1dd3ecb18980e9
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -409,11 +409,15 @@ type g struct {
// gcnextsegment: unused
// gcnextsp: current SP while executing a syscall
// gcinitialsp: g0: top of stack; others: start of stack memory
// gcnextsp2: current secondary stack pointer (if present)
// gcinitialsp2: start of secondary stack (if present)
gcstack uintptr
gcstacksize uintptr
gcnextsegment uintptr
gcnextsp uintptr
gcinitialsp unsafe.Pointer
gcnextsp2 uintptr
gcinitialsp2 unsafe.Pointer
// gcregs holds the register values while executing a syscall.
// This is set by getcontext and scanned by the garbage collector.

View File

@ -308,6 +308,7 @@ runtime_mcall(FuncVal *fv)
// Ensure that all registers are on the stack for the garbage
// collector.
__builtin_unwind_init();
flush_registers_to_secondary_stack();
gp = g;
mp = gp->m;
@ -322,6 +323,7 @@ runtime_mcall(FuncVal *fv)
// We have to point to an address on the stack that is
// below the saved registers.
gp->gcnextsp = (uintptr)(&afterregs);
gp->gcnextsp2 = (uintptr)(secondary_stack_pointer());
#endif
gp->fromgogo = false;
getcontext(ucontext_arg(&gp->context[0]));
@ -500,6 +502,8 @@ runtime_mstart(void *arg)
// is the top of the stack, not the bottom.
gp->gcstacksize = 0;
gp->gcnextsp = (uintptr)(&arg);
gp->gcinitialsp2 = secondary_stack_pointer();
gp->gcnextsp2 = (uintptr)(gp->gcinitialsp2);
#endif
// Save the currently active context. This will return
@ -576,6 +580,8 @@ setGContext(void)
gp->gcstack = 0;
gp->gcstacksize = 0;
gp->gcnextsp = (uintptr)(&val);
gp->gcinitialsp2 = secondary_stack_pointer();
gp->gcnextsp2 = (uintptr)(gp->gcinitialsp2);
#endif
getcontext(ucontext_arg(&gp->context[0]));
@ -654,6 +660,7 @@ doentersyscall(uintptr pc, uintptr sp)
void *v;
g->gcnextsp = (uintptr)(&v);
g->gcnextsp2 = (uintptr)(secondary_stack_pointer());
}
#endif
@ -694,6 +701,7 @@ doentersyscallblock(uintptr pc, uintptr sp)
void *v;
g->gcnextsp = (uintptr)(&v);
g->gcnextsp2 = (uintptr)(secondary_stack_pointer());
}
#endif
@ -756,6 +764,7 @@ runtime_malg(bool allocatestack, bool signalstack, byte** ret_stack, uintptr* re
*ret_stacksize = (uintptr)stacksize;
newg->gcinitialsp = *ret_stack;
newg->gcstacksize = (uintptr)stacksize;
newg->gcinitialsp2 = initial_secondary_stack_pointer(*ret_stack);
#endif
}
return newg;
@ -807,6 +816,7 @@ resetNewG(G *newg, void **sp, uintptr *spsize)
if(*spsize == 0)
runtime_throw("bad spsize in resetNewG");
newg->gcnextsp = (uintptr)(*sp);
newg->gcnextsp2 = (uintptr)(newg->gcinitialsp2);
#endif
}

View File

@ -437,6 +437,23 @@ void runtime_check(void)
// the stacks are allocated by the splitstack library.
extern uintptr runtime_stacks_sys;
/*
* ia64's register file is spilled to a separate stack, the register backing
* store, on window overflow, and must also be scanned. This occupies the other
* end of the normal stack allocation, growing upwards.
* We also need to ensure all register windows are flushed to the backing
* store, as unlike SPARC, __builtin_unwind_init doesn't do this on ia64.
*/
#ifdef __ia64__
# define secondary_stack_pointer() __builtin_ia64_bsp()
# define initial_secondary_stack_pointer(stack_alloc) (stack_alloc)
# define flush_registers_to_secondary_stack() __builtin_ia64_flushrs()
#else
# define secondary_stack_pointer() nil
# define initial_secondary_stack_pointer(stack_alloc) nil
# define flush_registers_to_secondary_stack()
#endif
struct backtrace_state;
extern struct backtrace_state *__go_get_backtrace_state(void);
extern _Bool __go_file_line(uintptr, int, String*, String*, intgo *);

View File

@ -34,6 +34,7 @@ void doscanstack(G *gp, void* gcw) {
// Save registers on the stack, so that if we are scanning our
// own stack we will see them.
__builtin_unwind_init();
flush_registers_to_secondary_stack();
doscanstack1(gp, gcw);
}
@ -82,21 +83,32 @@ static void doscanstack1(G *gp, void *gcw) {
#else
byte* bottom;
byte* top;
byte* nextsp2;
byte* initialsp2;
if(gp == runtime_g()) {
// Scanning our own stack.
bottom = (byte*)&gp;
nextsp2 = secondary_stack_pointer();
} else {
// Scanning another goroutine's stack.
// The goroutine is usually asleep (the world is stopped).
bottom = (void*)gp->gcnextsp;
if(bottom == nil)
return;
nextsp2 = (void*)gp->gcnextsp2;
}
top = (byte*)(void*)(gp->gcinitialsp) + gp->gcstacksize;
if(top > bottom)
scanstackblock(bottom, (uintptr)(top - bottom), gcw);
else
scanstackblock(top, (uintptr)(bottom - top), gcw);
if (nextsp2 != nil) {
initialsp2 = (byte*)(void*)(gp->gcinitialsp2);
if(initialsp2 > nextsp2)
scanstackblock(nextsp2, (uintptr)(initialsp2 - nextsp2), gcw);
else
scanstackblock(initialsp2, (uintptr)(nextsp2 - initialsp2), gcw);
}
#endif
}