/* * A version of GC_push_all that treats all interior pointers as valid * and scans part of the area immediately, to make sure that saved * register values are not lost. * Cold_gc_frame delimits the stack section that must be scanned * eagerly. A zero value indicates that no eager scanning is needed. * We don't need to worry about the MANUAL_VDB case here, since this * is only called in the single-threaded case. We assume that we * cannot collect between an assignment and the corresponding * GC_dirty() call. */ STATIC void GC_push_all_stack_partially_eager(ptr_t bottom, ptr_t top, ptr_t cold_gc_frame) { #ifndef NEED_FIXUP_POINTER if (GC_all_interior_pointers) { /* Push the hot end of the stack eagerly, so that register values */ /* saved inside GC frames are marked before they disappear. */ /* The rest of the marking can be deferred until later. */ if (0 == cold_gc_frame) { GC_push_all_stack(bottom, top); return; } GC_ASSERT((word)bottom <= (word)cold_gc_frame && (word)cold_gc_frame <= (word)top); # ifdef STACK_GROWS_DOWN GC_push_all(cold_gc_frame - sizeof(ptr_t), top); GC_push_all_eager(bottom, cold_gc_frame); # else /* STACK_GROWS_UP */ GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t)); GC_push_all_eager(cold_gc_frame, top); # endif /* STACK_GROWS_UP */ } else #endif /* else */ { GC_push_all_eager(bottom, top); } # ifdef TRACE_BUF GC_add_trace_entry("GC_push_all_stack", (word)bottom, (word)top); # endif }
/* Similar to GC_push_all_stack_sections() but for IA-64 registers store. */ GC_INNER void GC_push_all_register_sections(ptr_t bs_lo, ptr_t bs_hi, int eager, struct GC_traced_stack_sect_s *traced_stack_sect) { while (traced_stack_sect != NULL) { ptr_t frame_bs_lo = traced_stack_sect -> backing_store_end; GC_ASSERT((word)frame_bs_lo <= (word)bs_hi); if (eager) { GC_push_all_eager(frame_bs_lo, bs_hi); } else { GC_push_all_stack(frame_bs_lo, bs_hi); } bs_hi = traced_stack_sect -> saved_backing_store_ptr; traced_stack_sect = traced_stack_sect -> prev; } GC_ASSERT((word)bs_lo <= (word)bs_hi); if (eager) { GC_push_all_eager(bs_lo, bs_hi); } else { GC_push_all_stack(bs_lo, bs_hi); } }
GC_INNER void GC_push_all_stack_sections(ptr_t lo, ptr_t hi, struct GC_traced_stack_sect_s *traced_stack_sect) { while (traced_stack_sect != NULL) { GC_ASSERT((word)lo HOTTER_THAN (word)traced_stack_sect); # ifdef STACK_GROWS_UP GC_push_all_stack((ptr_t)traced_stack_sect, lo); # else /* STACK_GROWS_DOWN */ GC_push_all_stack(lo, (ptr_t)traced_stack_sect); # endif lo = traced_stack_sect -> saved_stack_ptr; GC_ASSERT(lo != NULL); traced_stack_sect = traced_stack_sect -> prev; } GC_ASSERT(!((word)hi HOTTER_THAN (word)lo)); # ifdef STACK_GROWS_UP /* We got them backwards! */ GC_push_all_stack(hi, lo); # else /* STACK_GROWS_DOWN */ GC_push_all_stack(lo, hi); # endif }
static void push_copied_stacks(int init) { /* This is called after everything else is marked. Mark from those stacks that are still reachable. If we mark from a stack, we need to go back though the list all over to check the previously unmarked stacks. */ CopiedStack *cs; int pushed_one; if (init) { for (cs = *first_copied_stack; cs; cs = *cs->next) { if (get_copy(cs)) cs->pushed = 0; else cs->pushed = 1; } } GC_flush_mark_stack(); do { pushed_one = 0; for (cs = *first_copied_stack; cs; cs = *cs->next) { if (!cs->pushed && GC_is_marked(get_copy(cs))) { pushed_one = 1; cs->pushed = 1; GC_push_all_stack(get_copy(cs), (char *)get_copy(cs) + cs->size); if (GC_did_mark_stack_overflow()) { /* printf("mark stack overflow\n"); */ return; } else { GC_flush_mark_stack(); if (GC_did_mark_stack_overflow()) { /* printf("mark stack overflow (late)\n"); */ return; } } } } } while (pushed_one); }
void GC_push_stack_for(GC_thread thread) { int dummy; ptr_t sp, stack_min; DWORD me = GetCurrentThreadId(); if (thread -> stack_base) { if (thread -> id == me) { sp = (ptr_t) &dummy; } else { CONTEXT context; context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL; if (!GetThreadContext(thread -> handle, &context)) ABORT("GetThreadContext failed"); /* Push all registers that might point into the heap. Frame */ /* pointer registers are included in case client code was */ /* compiled with the 'omit frame pointer' optimisation. */ # define PUSH1(reg) GC_push_one((word)context.reg) # define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2) # define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4) # if defined(I386) PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp); sp = (ptr_t)context.Esp; # elif defined(X86_64) PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi); PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15); sp = (ptr_t)context.Rsp; # elif defined(ARM32) PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12); sp = (ptr_t)context.Sp; # elif defined(SHx) PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11); PUSH2(R12,R13), PUSH1(R14); sp = (ptr_t)context.R15; # elif defined(MIPS) PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0); PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0); PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8); PUSH4(IntT9,IntK0,IntK1,IntS8); sp = (ptr_t)context.IntSp; # elif defined(PPC) PUSH4(Gpr0, Gpr3, Gpr4, Gpr5), PUSH4(Gpr6, Gpr7, Gpr8, Gpr9); PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18); PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26); PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31); sp = (ptr_t)context.Gpr1; # elif defined(ALPHA) PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6); PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp); PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9); PUSH4(IntT10,IntT11,IntT12,IntAt); sp = (ptr_t)context.IntSp; # else # error "architecture is not supported" # endif } /* ! current thread */ stack_min = GC_get_stack_min(thread->stack_base); if (sp >= stack_min && sp < thread->stack_base) { # if DEBUG_WIN32_PTHREADS || DEBUG_WIN32_THREADS \ || DEBUG_CYGWIN_THREADS GC_printf("Pushing thread from %p to %p for 0x%x from 0x%x\n", sp, thread -> stack_base, thread -> id, me); # endif GC_push_all_stack(sp, thread->stack_base); } else { WARN("Thread stack pointer 0x%lx out of range, pushing everything\n", (unsigned long)(size_t)sp); GC_push_all_stack(stack_min, thread->stack_base); } } /* thread looks live */ }