avoid retaining unneeded runstacks in continuations
While a continuation is set up to avoid retaining runstacks, partly by storing a prompt ID instead of a prompt record, prompt records can remain on the C stack and get captured anyway. Mitigate that problem by making the runstack link weak in some prompt record. Racket CS doesn't have this problem, of course. Relevant to jeapostrophe/lux#10
This commit is contained in:
parent
6eb2175f7a
commit
0ca19cfa08
75
pkgs/racket-test/tests/racket/stress/prompt-mem-use.rkt
Normal file
75
pkgs/racket-test/tests/racket/stress/prompt-mem-use.rkt
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
;; Version 1, using DOS
|
||||||
|
#;(require dos)
|
||||||
|
|
||||||
|
;; Version 2, going direct
|
||||||
|
(begin
|
||||||
|
(define 0x80 (make-continuation-prompt-tag 'dos))
|
||||||
|
|
||||||
|
(define (run-process-until-syscall p st)
|
||||||
|
(call-with-continuation-barrier
|
||||||
|
(λ ()
|
||||||
|
(call-with-continuation-prompt
|
||||||
|
(λ () (p st))
|
||||||
|
0x80
|
||||||
|
(λ (x) x)))))
|
||||||
|
|
||||||
|
(define (dos-syscall k->syscall)
|
||||||
|
;; First we capture our context back to the OS
|
||||||
|
(call-with-current-continuation
|
||||||
|
(λ (k)
|
||||||
|
;; Then we abort, give it to the OS, along with a syscall
|
||||||
|
;; specification
|
||||||
|
(abort-current-continuation 0x80 (k->syscall k)))
|
||||||
|
0x80))
|
||||||
|
|
||||||
|
(define USE-OBSCENE-MEMORY? #t)
|
||||||
|
(define (map-reduce f + a l)
|
||||||
|
(if USE-OBSCENE-MEMORY?
|
||||||
|
(cond
|
||||||
|
[(null? l) a]
|
||||||
|
[else
|
||||||
|
(+ (f (car l)) (map-reduce f + a (cdr l)))])
|
||||||
|
(cond
|
||||||
|
[(null? l)
|
||||||
|
a]
|
||||||
|
[(pair? l)
|
||||||
|
(+ (map-reduce f + a (car l))
|
||||||
|
(map-reduce f + a (cdr l)))]
|
||||||
|
[else
|
||||||
|
(f l)])))
|
||||||
|
|
||||||
|
(define USE-LOTS-OF-MEMORY? #t)
|
||||||
|
(define (dos-boot merge-effects last-state ps empty-effects)
|
||||||
|
(if USE-LOTS-OF-MEMORY?
|
||||||
|
(map-reduce (λ (p) (run-process-until-syscall p last-state))
|
||||||
|
merge-effects
|
||||||
|
empty-effects
|
||||||
|
ps)
|
||||||
|
(map (λ (p) (run-process-until-syscall p last-state)) ps))))
|
||||||
|
|
||||||
|
(define nothing-threads
|
||||||
|
(for/list ([i (in-range 1900)])
|
||||||
|
(λ (init-st)
|
||||||
|
(let lp ()
|
||||||
|
(dos-syscall (λ (k) k))
|
||||||
|
(lp)))))
|
||||||
|
|
||||||
|
;; prevent inlining
|
||||||
|
(set! dos-boot dos-boot)
|
||||||
|
|
||||||
|
(begin
|
||||||
|
(let lp ([ps nothing-threads] [max-use 0] [n 0] [grow-n 0])
|
||||||
|
(printf "~s ~s ~s\n" max-use n grow-n)
|
||||||
|
(unless (= n 200)
|
||||||
|
(when (= grow-n 25)
|
||||||
|
(error "memory use grew too many times"))
|
||||||
|
(collect-garbage)
|
||||||
|
(define use (current-memory-use))
|
||||||
|
(lp (dos-boot cons #f ps null)
|
||||||
|
(max use max-use)
|
||||||
|
(add1 n)
|
||||||
|
(if (use . > . max-use)
|
||||||
|
(add1 grow-n)
|
||||||
|
grow-n)))))
|
|
@ -996,16 +996,61 @@ int scheme_intern_prim_opt_flags(int flags)
|
||||||
/* prompt helpers */
|
/* prompt helpers */
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
|
|
||||||
static void initialize_prompt(Scheme_Thread *p, Scheme_Prompt *prompt, void *stack_boundary)
|
static void initialize_prompt(Scheme_Thread *p, Scheme_Prompt *prompt, void *stack_boundary, int is_barrier)
|
||||||
{
|
{
|
||||||
prompt->is_barrier = 0;
|
prompt->is_barrier = is_barrier;
|
||||||
prompt->stack_boundary = stack_boundary;
|
prompt->stack_boundary = stack_boundary;
|
||||||
prompt->runstack_boundary_start = MZ_RUNSTACK_START;
|
if (is_barrier) {
|
||||||
|
/* Avoid leak in case barrier is retained longer than the rest of the stack */
|
||||||
|
Scheme_Object *ref;
|
||||||
|
ref = scheme_make_weak_box((Scheme_Object *)MZ_RUNSTACK_START);
|
||||||
|
prompt->u.runstack_boundary_start_ref = ref;
|
||||||
|
prompt->weak_boundary = 1;
|
||||||
|
} else
|
||||||
|
prompt->u.runstack_boundary_start = MZ_RUNSTACK_START;
|
||||||
prompt->runstack_boundary_offset = (MZ_RUNSTACK - MZ_RUNSTACK_START);
|
prompt->runstack_boundary_offset = (MZ_RUNSTACK - MZ_RUNSTACK_START);
|
||||||
prompt->mark_boundary = MZ_CONT_MARK_STACK;
|
prompt->mark_boundary = MZ_CONT_MARK_STACK;
|
||||||
prompt->boundary_mark_pos = MZ_CONT_MARK_POS;
|
prompt->boundary_mark_pos = MZ_CONT_MARK_POS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scheme_Object **scheme_prompt_runstack_boundary_start(Scheme_Prompt *p)
|
||||||
|
{
|
||||||
|
if (p->weak_boundary)
|
||||||
|
return (Scheme_Object **)(SCHEME_BOX_VAL(p->u.runstack_boundary_start_ref));
|
||||||
|
else
|
||||||
|
return p->u.runstack_boundary_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_prompt_id(Scheme_Prompt *prompt)
|
||||||
|
{
|
||||||
|
Scheme_Object *id;
|
||||||
|
|
||||||
|
if (!prompt->id) {
|
||||||
|
id = scheme_make_pair(scheme_false, scheme_false);
|
||||||
|
prompt->id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Scheme_Prompt *make_weak_prompt(Scheme_Prompt *p)
|
||||||
|
{
|
||||||
|
Scheme_Prompt *p2;
|
||||||
|
Scheme_Object *ref;
|
||||||
|
|
||||||
|
if (p->weak_boundary)
|
||||||
|
return p;
|
||||||
|
|
||||||
|
init_prompt_id(p);
|
||||||
|
|
||||||
|
p2 = MALLOC_ONE_TAGGED(Scheme_Prompt);
|
||||||
|
memcpy(p2, p, sizeof(Scheme_Prompt));
|
||||||
|
|
||||||
|
ref = scheme_make_weak_box((Scheme_Object *)p2->u.runstack_boundary_start);
|
||||||
|
p2->u.runstack_boundary_start_ref = ref;
|
||||||
|
p2->weak_boundary = 1;
|
||||||
|
|
||||||
|
return p2;
|
||||||
|
}
|
||||||
|
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
/* stack-overflow wrapper */
|
/* stack-overflow wrapper */
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
|
@ -1193,11 +1238,7 @@ void *scheme_top_level_do_worker(void *(*k)(void), int eb, int new_thread)
|
||||||
|
|
||||||
if (eb) {
|
if (eb) {
|
||||||
prompt = allocate_prompt(&available_prompt);
|
prompt = allocate_prompt(&available_prompt);
|
||||||
initialize_prompt(p, prompt, PROMPT_STACK(prompt));
|
initialize_prompt(p, prompt, PROMPT_STACK(prompt), !new_thread);
|
||||||
|
|
||||||
if (!new_thread) {
|
|
||||||
prompt->is_barrier = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MZ_PRECISE_GC
|
#ifdef MZ_PRECISE_GC
|
||||||
|
@ -4589,7 +4630,7 @@ static Scheme_Saved_Stack *copy_out_runstack(Scheme_Thread *p,
|
||||||
size += MAX_CALL_CC_ARG_COUNT;
|
size += MAX_CALL_CC_ARG_COUNT;
|
||||||
else
|
else
|
||||||
size += shared_amt;
|
size += shared_amt;
|
||||||
} else if (effective_prompt && (effective_prompt->runstack_boundary_start == runstack_start)) {
|
} else if (effective_prompt && (scheme_prompt_runstack_boundary_start(effective_prompt) == runstack_start)) {
|
||||||
/* Copy only up to the prompt */
|
/* Copy only up to the prompt */
|
||||||
size = effective_prompt->runstack_boundary_offset - (runstack XFORM_OK_MINUS runstack_start);
|
size = effective_prompt->runstack_boundary_offset - (runstack XFORM_OK_MINUS runstack_start);
|
||||||
} else {
|
} else {
|
||||||
|
@ -4604,7 +4645,7 @@ static Scheme_Saved_Stack *copy_out_runstack(Scheme_Thread *p,
|
||||||
memcpy(saved->runstack_start, runstack, size * sizeof(Scheme_Object *));
|
memcpy(saved->runstack_start, runstack, size * sizeof(Scheme_Object *));
|
||||||
saved->runstack_offset = (runstack XFORM_OK_MINUS runstack_start);
|
saved->runstack_offset = (runstack XFORM_OK_MINUS runstack_start);
|
||||||
|
|
||||||
if (!effective_prompt || (effective_prompt->runstack_boundary_start != runstack_start)) {
|
if (!effective_prompt || (scheme_prompt_runstack_boundary_start(effective_prompt) != runstack_start)) {
|
||||||
|
|
||||||
/* Copy saved runstacks: */
|
/* Copy saved runstacks: */
|
||||||
if (share_from) {
|
if (share_from) {
|
||||||
|
@ -4630,7 +4671,7 @@ static Scheme_Saved_Stack *copy_out_runstack(Scheme_Thread *p,
|
||||||
isaved->prev = ss;
|
isaved->prev = ss;
|
||||||
isaved = ss;
|
isaved = ss;
|
||||||
|
|
||||||
if (effective_prompt && (effective_prompt->runstack_boundary_start == csaved->runstack_start)) {
|
if (effective_prompt && (scheme_prompt_runstack_boundary_start(effective_prompt) == csaved->runstack_start)) {
|
||||||
size = effective_prompt->runstack_boundary_offset - csaved->runstack_offset;
|
size = effective_prompt->runstack_boundary_offset - csaved->runstack_offset;
|
||||||
done = 1;
|
done = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -5071,16 +5112,16 @@ static Scheme_Meta_Continuation *clone_meta_cont(Scheme_Meta_Continuation *mc,
|
||||||
saved = clone_runstack_copied(cnaya->runstack_copied,
|
saved = clone_runstack_copied(cnaya->runstack_copied,
|
||||||
cnaya->runstack_start,
|
cnaya->runstack_start,
|
||||||
cnaya->runstack_saved,
|
cnaya->runstack_saved,
|
||||||
prompt->runstack_boundary_start,
|
scheme_prompt_runstack_boundary_start(prompt),
|
||||||
prompt->runstack_boundary_offset);
|
prompt->runstack_boundary_offset);
|
||||||
cnaya->runstack_copied = saved;
|
cnaya->runstack_copied = saved;
|
||||||
|
|
||||||
/* Prune unneeded buffers */
|
/* Prune unneeded buffers */
|
||||||
if (prompt->runstack_boundary_start == cnaya->runstack_start)
|
if (scheme_prompt_runstack_boundary_start(prompt) == cnaya->runstack_start)
|
||||||
saved = NULL;
|
saved = NULL;
|
||||||
else
|
else
|
||||||
saved = clone_runstack_saved(cnaya->runstack_saved,
|
saved = clone_runstack_saved(cnaya->runstack_saved,
|
||||||
prompt->runstack_boundary_start,
|
scheme_prompt_runstack_boundary_start(prompt),
|
||||||
NULL);
|
NULL);
|
||||||
cnaya->runstack_saved = saved;
|
cnaya->runstack_saved = saved;
|
||||||
|
|
||||||
|
@ -5383,16 +5424,12 @@ static Scheme_Cont *grab_continuation(Scheme_Thread *p, int for_prompt, int comp
|
||||||
cont->meta_continuation = NULL;
|
cont->meta_continuation = NULL;
|
||||||
} else if (prompt) {
|
} else if (prompt) {
|
||||||
Scheme_Meta_Continuation *mc;
|
Scheme_Meta_Continuation *mc;
|
||||||
Scheme_Object *id;
|
|
||||||
mc = clone_meta_cont(p->meta_continuation, pt, -1, prompt_cont, prompt, NULL, composable);
|
mc = clone_meta_cont(p->meta_continuation, pt, -1, prompt_cont, prompt, NULL, composable);
|
||||||
cont->meta_continuation = mc;
|
cont->meta_continuation = mc;
|
||||||
if (!prompt_cont) {
|
if (!prompt_cont) {
|
||||||
/* Remember the prompt id, so we can maybe take a shortcut on
|
/* Remember the prompt id, so we can maybe take a shortcut on
|
||||||
invocation. (The shortcut only works within a meta-continuation.) */
|
invocation. (The shortcut only works within a meta-continuation.) */
|
||||||
if (!prompt->id) {
|
init_prompt_id(prompt);
|
||||||
id = scheme_make_pair(scheme_false, scheme_false);
|
|
||||||
prompt->id = id;
|
|
||||||
}
|
|
||||||
cont->prompt_id = prompt->id;
|
cont->prompt_id = prompt->id;
|
||||||
}
|
}
|
||||||
cont->has_prompt_dw = 1;
|
cont->has_prompt_dw = 1;
|
||||||
|
@ -5475,11 +5512,11 @@ static Scheme_Cont *grab_continuation(Scheme_Thread *p, int for_prompt, int comp
|
||||||
(Note that this is different than runstack_copied;
|
(Note that this is different than runstack_copied;
|
||||||
runstack_saved keeps the shared runstack buffers,
|
runstack_saved keeps the shared runstack buffers,
|
||||||
not the content.) */
|
not the content.) */
|
||||||
if (SAME_OBJ(prompt->runstack_boundary_start, MZ_RUNSTACK_START))
|
if (scheme_prompt_runstack_boundary_start(prompt) == MZ_RUNSTACK_START)
|
||||||
saved = NULL;
|
saved = NULL;
|
||||||
else
|
else
|
||||||
saved = clone_runstack_saved(cont->runstack_saved,
|
saved = clone_runstack_saved(cont->runstack_saved,
|
||||||
prompt->runstack_boundary_start,
|
scheme_prompt_runstack_boundary_start(prompt),
|
||||||
NULL);
|
NULL);
|
||||||
cont->runstack_saved = saved;
|
cont->runstack_saved = saved;
|
||||||
}
|
}
|
||||||
|
@ -5629,11 +5666,11 @@ static void restore_continuation(Scheme_Cont *cont, Scheme_Thread *p, int for_pr
|
||||||
/* In shortcut mode, we need to preserve saved runstacks
|
/* In shortcut mode, we need to preserve saved runstacks
|
||||||
that were pruned when capturing the continuation. */
|
that were pruned when capturing the continuation. */
|
||||||
Scheme_Saved_Stack *rs;
|
Scheme_Saved_Stack *rs;
|
||||||
if (shortcut_prompt->runstack_boundary_start == MZ_RUNSTACK_START)
|
if (scheme_prompt_runstack_boundary_start(shortcut_prompt) == MZ_RUNSTACK_START)
|
||||||
rs = p->runstack_saved;
|
rs = p->runstack_saved;
|
||||||
else {
|
else {
|
||||||
rs = p->runstack_saved;
|
rs = p->runstack_saved;
|
||||||
while (rs && (rs->runstack_start != shortcut_prompt->runstack_boundary_start)) {
|
while (rs && (rs->runstack_start != scheme_prompt_runstack_boundary_start(shortcut_prompt))) {
|
||||||
rs = rs->prev;
|
rs = rs->prev;
|
||||||
}
|
}
|
||||||
if (rs)
|
if (rs)
|
||||||
|
@ -5762,10 +5799,10 @@ static void restore_continuation(Scheme_Cont *cont, Scheme_Thread *p, int for_pr
|
||||||
actual = actual->prev;
|
actual = actual->prev;
|
||||||
}
|
}
|
||||||
if (actual) {
|
if (actual) {
|
||||||
meta_prompt->runstack_boundary_start = actual->runstack_start;
|
meta_prompt->u.runstack_boundary_start = actual->runstack_start;
|
||||||
meta_prompt->runstack_boundary_offset = actual->runstack_offset + saved->runstack_size;
|
meta_prompt->runstack_boundary_offset = actual->runstack_offset + saved->runstack_size;
|
||||||
} else {
|
} else {
|
||||||
meta_prompt->runstack_boundary_start = MZ_RUNSTACK_START;
|
meta_prompt->u.runstack_boundary_start = MZ_RUNSTACK_START;
|
||||||
meta_prompt->runstack_boundary_offset = (MZ_RUNSTACK - MZ_RUNSTACK_START) + saved->runstack_size + delta;
|
meta_prompt->runstack_boundary_offset = (MZ_RUNSTACK - MZ_RUNSTACK_START) + saved->runstack_size + delta;
|
||||||
MZ_ASSERT(meta_prompt->runstack_boundary_offset <= scheme_current_thread->runstack_size);
|
MZ_ASSERT(meta_prompt->runstack_boundary_offset <= scheme_current_thread->runstack_size);
|
||||||
}
|
}
|
||||||
|
@ -5935,6 +5972,13 @@ internal_call_cc (int argc, Scheme_Object *argv[])
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This prompt is likely to be on the C stack when we capture it for
|
||||||
|
the continuation, but we only want to retain the prompt's
|
||||||
|
runstack. Convert it to one that has the same ID but holds the
|
||||||
|
runstack weakly. */
|
||||||
|
if (prompt)
|
||||||
|
prompt = make_weak_prompt(prompt);
|
||||||
|
|
||||||
barrier_prompt = scheme_get_barrier_prompt(&barrier_cont, &barrier_pos);
|
barrier_prompt = scheme_get_barrier_prompt(&barrier_cont, &barrier_pos);
|
||||||
|
|
||||||
if (composable && SCHEME_FALSEP(argv[2])) {
|
if (composable && SCHEME_FALSEP(argv[2])) {
|
||||||
|
@ -6736,7 +6780,7 @@ static void restore_from_prompt(Scheme_Prompt *prompt)
|
||||||
{
|
{
|
||||||
Scheme_Thread *p = scheme_current_thread;
|
Scheme_Thread *p = scheme_current_thread;
|
||||||
|
|
||||||
while (MZ_RUNSTACK_START != prompt->runstack_boundary_start) {
|
while (MZ_RUNSTACK_START != scheme_prompt_runstack_boundary_start(prompt)) {
|
||||||
MZ_RUNSTACK_START = p->runstack_saved->runstack_start;
|
MZ_RUNSTACK_START = p->runstack_saved->runstack_start;
|
||||||
p->runstack_saved = p->runstack_saved->prev;
|
p->runstack_saved = p->runstack_saved->prev;
|
||||||
}
|
}
|
||||||
|
@ -7029,7 +7073,7 @@ static Scheme_Object *call_with_prompt (int in_argc, Scheme_Object *in_argv[])
|
||||||
|
|
||||||
ASSERT_SUSPEND_BREAK_ZERO();
|
ASSERT_SUSPEND_BREAK_ZERO();
|
||||||
|
|
||||||
initialize_prompt(p, prompt, NULL);
|
initialize_prompt(p, prompt, NULL, 0);
|
||||||
|
|
||||||
if (p->overflow) {
|
if (p->overflow) {
|
||||||
ensure_overflow_id(p->overflow);
|
ensure_overflow_id(p->overflow);
|
||||||
|
|
|
@ -2857,8 +2857,8 @@ static int runstack_val_MARK(void *p, struct NewGC *gc) {
|
||||||
#ifndef GC_NO_MARK_PROCEDURE_NEEDED
|
#ifndef GC_NO_MARK_PROCEDURE_NEEDED
|
||||||
intptr_t *s = (intptr_t *)p;
|
intptr_t *s = (intptr_t *)p;
|
||||||
void **a, **b;
|
void **a, **b;
|
||||||
a = (void **)s + 5 + s[2];
|
a = (void **)s + RUNSTACK_HEADER_FIELDS + s[2];
|
||||||
b = (void **)s + 5 + s[3];
|
b = (void **)s + RUNSTACK_HEADER_FIELDS + s[3];
|
||||||
while (a < b) {
|
while (a < b) {
|
||||||
gcMARK2(*a, gc);
|
gcMARK2(*a, gc);
|
||||||
a++;
|
a++;
|
||||||
|
@ -2866,14 +2866,14 @@ static int runstack_val_MARK(void *p, struct NewGC *gc) {
|
||||||
|
|
||||||
/* Zero out the part that we didn't mark, in case it becomes
|
/* Zero out the part that we didn't mark, in case it becomes
|
||||||
live later. */
|
live later. */
|
||||||
a = (void **)s + 5;
|
a = (void **)s + RUNSTACK_HEADER_FIELDS;
|
||||||
b = (void **)s + 5 + s[2];
|
b = (void **)s + RUNSTACK_HEADER_FIELDS + s[2];
|
||||||
while (a < b) {
|
while (a < b) {
|
||||||
*a = RUNSTACK_ZERO_VAL;
|
*a = RUNSTACK_ZERO_VAL;
|
||||||
a++;
|
a++;
|
||||||
}
|
}
|
||||||
a = (void **)s + 5 + s[3];
|
a = (void **)s + RUNSTACK_HEADER_FIELDS + s[3];
|
||||||
b = (void **)s + 5 + (s[1] - 5);
|
b = (void **)s + RUNSTACK_HEADER_FIELDS + (s[1] - RUNSTACK_HEADER_FIELDS);
|
||||||
while (a < b) {
|
while (a < b) {
|
||||||
*a = RUNSTACK_ZERO_VAL;
|
*a = RUNSTACK_ZERO_VAL;
|
||||||
a++;
|
a++;
|
||||||
|
@ -2892,8 +2892,8 @@ static int runstack_val_FIXUP(void *p, struct NewGC *gc) {
|
||||||
#ifndef GC_NO_FIXUP_PROCEDURE_NEEDED
|
#ifndef GC_NO_FIXUP_PROCEDURE_NEEDED
|
||||||
intptr_t *s = (intptr_t *)p;
|
intptr_t *s = (intptr_t *)p;
|
||||||
void **a, **b;
|
void **a, **b;
|
||||||
a = (void **)s + 5 + s[2];
|
a = (void **)s + RUNSTACK_HEADER_FIELDS + s[2];
|
||||||
b = (void **)s + 5 + s[3];
|
b = (void **)s + RUNSTACK_HEADER_FIELDS + s[3];
|
||||||
while (a < b) {
|
while (a < b) {
|
||||||
gcFIXUP2(*a, gc);
|
gcFIXUP2(*a, gc);
|
||||||
a++;
|
a++;
|
||||||
|
@ -2925,8 +2925,12 @@ static int prompt_val_MARK(void *p, struct NewGC *gc) {
|
||||||
#ifndef GC_NO_MARK_PROCEDURE_NEEDED
|
#ifndef GC_NO_MARK_PROCEDURE_NEEDED
|
||||||
Scheme_Prompt *pr = (Scheme_Prompt *)p;
|
Scheme_Prompt *pr = (Scheme_Prompt *)p;
|
||||||
gcMARK2(pr->boundary_overflow_id, gc);
|
gcMARK2(pr->boundary_overflow_id, gc);
|
||||||
if (!GC_merely_accounting())
|
if (!GC_merely_accounting()) {
|
||||||
gcMARK2(pr->runstack_boundary_start, gc);
|
if (pr->is_barrier)
|
||||||
|
gcMARK2(pr->u.runstack_boundary_start_ref, gc);
|
||||||
|
else
|
||||||
|
gcMARK2(pr->u.runstack_boundary_start, gc);
|
||||||
|
}
|
||||||
gcMARK2(pr->tag, gc);
|
gcMARK2(pr->tag, gc);
|
||||||
gcMARK2(pr->id, gc);
|
gcMARK2(pr->id, gc);
|
||||||
# ifdef GC_NO_SIZE_NEEDED_FROM_PROCS
|
# ifdef GC_NO_SIZE_NEEDED_FROM_PROCS
|
||||||
|
@ -2942,8 +2946,12 @@ static int prompt_val_FIXUP(void *p, struct NewGC *gc) {
|
||||||
#ifndef GC_NO_FIXUP_PROCEDURE_NEEDED
|
#ifndef GC_NO_FIXUP_PROCEDURE_NEEDED
|
||||||
Scheme_Prompt *pr = (Scheme_Prompt *)p;
|
Scheme_Prompt *pr = (Scheme_Prompt *)p;
|
||||||
gcFIXUP2(pr->boundary_overflow_id, gc);
|
gcFIXUP2(pr->boundary_overflow_id, gc);
|
||||||
if (!GC_merely_accounting())
|
if (!GC_merely_accounting()) {
|
||||||
gcFIXUP2(pr->runstack_boundary_start, gc);
|
if (pr->is_barrier)
|
||||||
|
gcFIXUP2(pr->u.runstack_boundary_start_ref, gc);
|
||||||
|
else
|
||||||
|
gcFIXUP2(pr->u.runstack_boundary_start, gc);
|
||||||
|
}
|
||||||
gcFIXUP2(pr->tag, gc);
|
gcFIXUP2(pr->tag, gc);
|
||||||
gcFIXUP2(pr->id, gc);
|
gcFIXUP2(pr->id, gc);
|
||||||
# ifdef GC_NO_SIZE_NEEDED_FROM_PROCS
|
# ifdef GC_NO_SIZE_NEEDED_FROM_PROCS
|
||||||
|
|
|
@ -810,8 +810,8 @@ runstack_val {
|
||||||
intptr_t *s = (intptr_t *)p;
|
intptr_t *s = (intptr_t *)p;
|
||||||
mark:
|
mark:
|
||||||
void **a, **b;
|
void **a, **b;
|
||||||
a = (void **)s + 5 + s[2];
|
a = (void **)s + RUNSTACK_HEADER_FIELDS + s[2];
|
||||||
b = (void **)s + 5 + s[3];
|
b = (void **)s + RUNSTACK_HEADER_FIELDS + s[3];
|
||||||
while (a < b) {
|
while (a < b) {
|
||||||
gcMARK2(*a, gc);
|
gcMARK2(*a, gc);
|
||||||
a++;
|
a++;
|
||||||
|
@ -820,14 +820,14 @@ runstack_val {
|
||||||
START_MARK_ONLY;
|
START_MARK_ONLY;
|
||||||
/* Zero out the part that we didn't mark, in case it becomes
|
/* Zero out the part that we didn't mark, in case it becomes
|
||||||
live later. */
|
live later. */
|
||||||
a = (void **)s + 5;
|
a = (void **)s + RUNSTACK_HEADER_FIELDS;
|
||||||
b = (void **)s + 5 + s[2];
|
b = (void **)s + RUNSTACK_HEADER_FIELDS + s[2];
|
||||||
while (a < b) {
|
while (a < b) {
|
||||||
*a = RUNSTACK_ZERO_VAL;
|
*a = RUNSTACK_ZERO_VAL;
|
||||||
a++;
|
a++;
|
||||||
}
|
}
|
||||||
a = (void **)s + 5 + s[3];
|
a = (void **)s + RUNSTACK_HEADER_FIELDS + s[3];
|
||||||
b = (void **)s + 5 + (s[1] - 5);
|
b = (void **)s + RUNSTACK_HEADER_FIELDS + (s[1] - RUNSTACK_HEADER_FIELDS);
|
||||||
while (a < b) {
|
while (a < b) {
|
||||||
*a = RUNSTACK_ZERO_VAL;
|
*a = RUNSTACK_ZERO_VAL;
|
||||||
a++;
|
a++;
|
||||||
|
@ -842,8 +842,12 @@ prompt_val {
|
||||||
mark:
|
mark:
|
||||||
Scheme_Prompt *pr = (Scheme_Prompt *)p;
|
Scheme_Prompt *pr = (Scheme_Prompt *)p;
|
||||||
gcMARK2(pr->boundary_overflow_id, gc);
|
gcMARK2(pr->boundary_overflow_id, gc);
|
||||||
if (!GC_merely_accounting())
|
if (!GC_merely_accounting()) {
|
||||||
gcMARK2(pr->runstack_boundary_start, gc);
|
if (pr->is_barrier)
|
||||||
|
gcMARK2(pr->u.runstack_boundary_start_ref, gc);
|
||||||
|
else
|
||||||
|
gcMARK2(pr->u.runstack_boundary_start, gc);
|
||||||
|
}
|
||||||
gcMARK2(pr->tag, gc);
|
gcMARK2(pr->tag, gc);
|
||||||
gcMARK2(pr->id, gc);
|
gcMARK2(pr->id, gc);
|
||||||
size:
|
size:
|
||||||
|
|
|
@ -736,6 +736,10 @@ THREAD_LOCAL_DECL(extern MZ_MARK_POS_TYPE scheme_current_cont_mark_pos);
|
||||||
# define MZ_CONT_MARK_POS (scheme_current_thread->cont_mark_pos)
|
# define MZ_CONT_MARK_POS (scheme_current_thread->cont_mark_pos)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MZ_PRECISE_GC
|
||||||
|
# define RUNSTACK_HEADER_FIELDS 5
|
||||||
|
#endif
|
||||||
|
|
||||||
THREAD_LOCAL_DECL(extern volatile int scheme_fuel_counter);
|
THREAD_LOCAL_DECL(extern volatile int scheme_fuel_counter);
|
||||||
|
|
||||||
THREAD_LOCAL_DECL(extern Scheme_Thread *scheme_main_thread);
|
THREAD_LOCAL_DECL(extern Scheme_Thread *scheme_main_thread);
|
||||||
|
@ -1977,19 +1981,24 @@ typedef struct Scheme_Meta_Continuation {
|
||||||
|
|
||||||
typedef struct Scheme_Prompt {
|
typedef struct Scheme_Prompt {
|
||||||
Scheme_Object so;
|
Scheme_Object so;
|
||||||
char is_barrier, has_chaperone;
|
char is_barrier, has_chaperone, weak_boundary;
|
||||||
Scheme_Object *tag;
|
Scheme_Object *tag;
|
||||||
Scheme_Object *id; /* created as needed; allows direct-jump optimization for cont app */
|
Scheme_Object *id; /* created as needed; allows direct-jump optimization for cont app */
|
||||||
void *stack_boundary; /* where to stop copying the C stack */
|
void *stack_boundary; /* where to stop copying the C stack */
|
||||||
void *boundary_overflow_id; /* indicates the C stack segment */
|
void *boundary_overflow_id; /* indicates the C stack segment */
|
||||||
MZ_MARK_STACK_TYPE mark_boundary; /* where to stop copying cont marks */
|
MZ_MARK_STACK_TYPE mark_boundary; /* where to stop copying cont marks */
|
||||||
MZ_MARK_POS_TYPE boundary_mark_pos; /* mark position of prompt */
|
MZ_MARK_POS_TYPE boundary_mark_pos; /* mark position of prompt */
|
||||||
Scheme_Object **runstack_boundary_start; /* which stack has runstack_boundary */
|
union {
|
||||||
|
Scheme_Object **runstack_boundary_start; /* which stack has runstack_boundary */
|
||||||
|
Scheme_Object *runstack_boundary_start_ref; /* weak-ref variant, used when `weak_boundary` */
|
||||||
|
} u;
|
||||||
intptr_t runstack_boundary_offset; /* where to stop copying the Scheme stack */
|
intptr_t runstack_boundary_offset; /* where to stop copying the Scheme stack */
|
||||||
mz_jmp_buf *prompt_buf; /* to jump directly to the prompt */
|
mz_jmp_buf *prompt_buf; /* to jump directly to the prompt */
|
||||||
intptr_t runstack_size; /* needed for restore */
|
intptr_t runstack_size; /* needed for restore */
|
||||||
} Scheme_Prompt;
|
} Scheme_Prompt;
|
||||||
|
|
||||||
|
XFORM_NONGCING Scheme_Object **scheme_prompt_runstack_boundary_start(Scheme_Prompt *p);
|
||||||
|
|
||||||
/* Compiler helper: */
|
/* Compiler helper: */
|
||||||
#define ESCAPED_BEFORE_HERE return NULL
|
#define ESCAPED_BEFORE_HERE return NULL
|
||||||
|
|
||||||
|
|
|
@ -2740,7 +2740,7 @@ Scheme_Object **scheme_alloc_runstack(intptr_t len)
|
||||||
#ifdef MZ_PRECISE_GC
|
#ifdef MZ_PRECISE_GC
|
||||||
intptr_t sz;
|
intptr_t sz;
|
||||||
void **p;
|
void **p;
|
||||||
sz = sizeof(Scheme_Object*) * (len + 5);
|
sz = sizeof(Scheme_Object*) * (len + RUNSTACK_HEADER_FIELDS);
|
||||||
p = (void **)GC_malloc_tagged_allow_interior(sz);
|
p = (void **)GC_malloc_tagged_allow_interior(sz);
|
||||||
*(Scheme_Type *)(void *)p = scheme_rt_runstack;
|
*(Scheme_Type *)(void *)p = scheme_rt_runstack;
|
||||||
((intptr_t *)(void *)p)[1] = gcBYTES_TO_WORDS(sz);
|
((intptr_t *)(void *)p)[1] = gcBYTES_TO_WORDS(sz);
|
||||||
|
@ -2748,7 +2748,7 @@ Scheme_Object **scheme_alloc_runstack(intptr_t len)
|
||||||
((intptr_t *)(void *)p)[3] = len;
|
((intptr_t *)(void *)p)[3] = len;
|
||||||
# define MZ_RUNSTACK_OVERFLOW_CANARY 0xFF77FF77
|
# define MZ_RUNSTACK_OVERFLOW_CANARY 0xFF77FF77
|
||||||
((intptr_t *)(void *)p)[4] = MZ_RUNSTACK_OVERFLOW_CANARY;
|
((intptr_t *)(void *)p)[4] = MZ_RUNSTACK_OVERFLOW_CANARY;
|
||||||
return (Scheme_Object **)(p + 5);
|
return (Scheme_Object **)(p + RUNSTACK_HEADER_FIELDS);
|
||||||
#else
|
#else
|
||||||
return (Scheme_Object **)scheme_malloc_allow_interior(sizeof(Scheme_Object*) * len);
|
return (Scheme_Object **)scheme_malloc_allow_interior(sizeof(Scheme_Object*) * len);
|
||||||
#endif
|
#endif
|
||||||
|
@ -9093,7 +9093,7 @@ static void prepare_thread_for_GC(Scheme_Object *t)
|
||||||
Scheme_Object **rs_start;
|
Scheme_Object **rs_start;
|
||||||
|
|
||||||
/* If there's a meta-prompt, we can also zero out past the unused part */
|
/* If there's a meta-prompt, we can also zero out past the unused part */
|
||||||
if (p->meta_prompt && (p->meta_prompt->runstack_boundary_start == p->runstack_start)) {
|
if (p->meta_prompt && (scheme_prompt_runstack_boundary_start(p->meta_prompt) == p->runstack_start)) {
|
||||||
rs_end = p->meta_prompt->runstack_boundary_offset;
|
rs_end = p->meta_prompt->runstack_boundary_offset;
|
||||||
} else {
|
} else {
|
||||||
rs_end = p->runstack_size;
|
rs_end = p->runstack_size;
|
||||||
|
@ -9115,7 +9115,7 @@ static void prepare_thread_for_GC(Scheme_Object *t)
|
||||||
for (saved = p->runstack_saved; saved; saved = saved->prev) {
|
for (saved = p->runstack_saved; saved; saved = saved->prev) {
|
||||||
RUNSTACK_TUNE( size += saved->runstack_size; );
|
RUNSTACK_TUNE( size += saved->runstack_size; );
|
||||||
|
|
||||||
if (p->meta_prompt && (p->meta_prompt->runstack_boundary_start == saved->runstack_start)) {
|
if (p->meta_prompt && (scheme_prompt_runstack_boundary_start(p->meta_prompt) == saved->runstack_start)) {
|
||||||
rs_end = p->meta_prompt->runstack_boundary_offset;
|
rs_end = p->meta_prompt->runstack_boundary_offset;
|
||||||
} else {
|
} else {
|
||||||
rs_end = saved->runstack_size;
|
rs_end = saved->runstack_size;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user