1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 11:50:28 +02:00

Return unused parts of the stack to the OS

* libguile/vm.h (struct scm_vm): Reorder fields.  Add "sp_max_since_gc"
  field.
* libguile/vm-engine.c (ALLOC_FRAME, RESET_FRAME):
* libguile/vm.c (vm_return_to_continuation)
  (vm_reinstate_partial_continuation, scm_call_n): In places where we
  could increase the stack height, update sp_max_since_gc.
  (vm_expand_stack): Relocate sp_max_since_gc on expansion.
  (scm_bootstrap_vm): Record the page size using gnulib's getpagesize.
  (return_unused_stack_to_os): New routine, run when marking stacks.
This commit is contained in:
Andy Wingo 2014-01-31 21:41:36 +01:00
parent 7161ec1133
commit 7dba1c2ff1
3 changed files with 63 additions and 11 deletions

View file

@ -196,6 +196,8 @@
do { \ do { \
vp->sp = LOCAL_ADDRESS (n - 1); \ vp->sp = LOCAL_ADDRESS (n - 1); \
CHECK_OVERFLOW (); \ CHECK_OVERFLOW (); \
if (vp->sp > vp->sp_max_since_gc) \
vp->sp_max_since_gc = vp->sp; \
} while (0) } while (0)
/* Reset the current frame to hold N locals. Used when we know that no /* Reset the current frame to hold N locals. Used when we know that no
@ -203,6 +205,8 @@
#define RESET_FRAME(n) \ #define RESET_FRAME(n) \
do { \ do { \
vp->sp = LOCAL_ADDRESS (n - 1); \ vp->sp = LOCAL_ADDRESS (n - 1); \
if (vp->sp > vp->sp_max_since_gc) \
vp->sp_max_since_gc = vp->sp; \
} while (0) } while (0)
/* Compute the number of locals in the frame. At a call, this is equal /* Compute the number of locals in the frame. At a call, this is equal

View file

@ -28,6 +28,7 @@
#include <alignof.h> #include <alignof.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <unistd.h>
#ifdef HAVE_SYS_MMAN_H #ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h> #include <sys/mman.h>
@ -142,6 +143,8 @@ vm_return_to_continuation (struct scm_vm *vp, SCM cont, size_t n, SCM *argv)
vp->sp++; vp->sp++;
*vp->sp = argv_copy[i]; *vp->sp = argv_copy[i];
} }
if (vp->sp > vp->sp_max_since_gc)
vp->sp_max_since_gc = vp->sp;
vp->ip = cp->ra; vp->ip = cp->ra;
} }
} }
@ -288,6 +291,8 @@ vm_abort (struct scm_vm *vp, SCM tag,
scm_c_abort (vp, tag, nstack + tail_len, argv, current_registers); scm_c_abort (vp, tag, nstack + tail_len, argv, current_registers);
} }
static void vm_expand_stack (struct scm_vm *vp) SCM_NOINLINE;
static void static void
vm_reinstate_partial_continuation (struct scm_vm *vp, SCM cont, vm_reinstate_partial_continuation (struct scm_vm *vp, SCM cont,
size_t n, SCM *argv, size_t n, SCM *argv,
@ -303,17 +308,25 @@ vm_reinstate_partial_continuation (struct scm_vm *vp, SCM cont,
memcpy (argv_copy, argv, n * sizeof(SCM)); memcpy (argv_copy, argv, n * sizeof(SCM));
cp = SCM_VM_CONT_DATA (cont); cp = SCM_VM_CONT_DATA (cont);
while (1)
{
scm_t_ptrdiff saved_stack_height = vp->sp - vp->stack_base;
base = SCM_FRAME_LOCALS_ADDRESS (vp->fp); base = SCM_FRAME_LOCALS_ADDRESS (vp->fp);
reloc = cp->reloc + (base - cp->stack_base); reloc = cp->reloc + (base - cp->stack_base);
vp->sp = base + cp->stack_size + n + 1;
if (vp->sp < vp->stack_limit)
break;
vm_expand_stack (vp);
vp->sp = vp->stack_base + saved_stack_height;
}
#define RELOC(scm_p) \ #define RELOC(scm_p) \
(((SCM *) (scm_p)) + reloc) (((SCM *) (scm_p)) + reloc)
if ((base - vp->stack_base) + cp->stack_size + n + 1 > vp->stack_size)
scm_misc_error ("vm-engine",
"not enough space to instate partial continuation",
scm_list_1 (cont));
memcpy (base, cp->stack_base, cp->stack_size * sizeof (SCM)); memcpy (base, cp->stack_base, cp->stack_size * sizeof (SCM));
/* now relocate frame pointers */ /* now relocate frame pointers */
@ -336,6 +349,9 @@ vm_reinstate_partial_continuation (struct scm_vm *vp, SCM cont,
*vp->sp = argv_copy[i]; *vp->sp = argv_copy[i];
} }
if (vp->sp > vp->sp_max_since_gc)
vp->sp_max_since_gc = vp->sp;
/* The prompt captured a slice of the dynamic stack. Here we wind /* The prompt captured a slice of the dynamic stack. Here we wind
those entries onto the current thread's stack. We also have to those entries onto the current thread's stack. We also have to
relocate any prompts that we see along the way. */ relocate any prompts that we see along the way. */
@ -672,7 +688,6 @@ initialize_default_stack_size (void)
default_max_stack_size = size; default_max_stack_size = size;
} }
static void vm_expand_stack (struct scm_vm *vp) SCM_NOINLINE;
#define VM_NAME vm_regular_engine #define VM_NAME vm_regular_engine
#define VM_USE_HOOKS 0 #define VM_USE_HOOKS 0
#define FUNC_NAME "vm-regular-engine" #define FUNC_NAME "vm-regular-engine"
@ -788,6 +803,27 @@ make_vm (void)
} }
#undef FUNC_NAME #undef FUNC_NAME
static size_t page_size;
static void
return_unused_stack_to_os (struct scm_vm *vp)
{
#if HAVE_SYS_MMAN_H
scm_t_uintptr start = (scm_t_uintptr) vp->sp;
scm_t_uintptr end = (scm_t_uintptr) vp->sp_max_since_gc;
start = ((start - 1U) | (page_size - 1U)) + 1U; /* round up */
end = ((end - 1U) | (page_size - 1U)) + 1U; /* round up */
/* Return these pages to the OS. The next time they are paged in,
they will be zeroed. */
if (start < end)
madvise ((void *) start, end - start, MADV_DONTNEED);
vp->sp_max_since_gc = vp->sp;
#endif
}
/* Mark the VM stack region between its base and its current top. */ /* Mark the VM stack region between its base and its current top. */
struct GC_ms_entry * struct GC_ms_entry *
scm_i_vm_mark_stack (struct scm_vm *vp, struct GC_ms_entry *mark_stack_ptr, scm_i_vm_mark_stack (struct scm_vm *vp, struct GC_ms_entry *mark_stack_ptr,
@ -838,6 +874,8 @@ scm_i_vm_mark_stack (struct scm_vm *vp, struct GC_ms_entry *mark_stack_ptr,
scm_find_dead_slot_map_unlocked (SCM_FRAME_RETURN_ADDRESS (fp)); scm_find_dead_slot_map_unlocked (SCM_FRAME_RETURN_ADDRESS (fp));
} }
return_unused_stack_to_os (vp);
return mark_stack_ptr; return mark_stack_ptr;
} }
@ -884,6 +922,7 @@ vm_expand_stack (struct scm_vm *vp)
SCM *fp; SCM *fp;
vp->fp += reloc; vp->fp += reloc;
vp->sp += reloc; vp->sp += reloc;
vp->sp_max_since_gc += reloc;
fp = vp->fp; fp = vp->fp;
while (fp) while (fp)
{ {
@ -982,6 +1021,9 @@ scm_call_n (SCM proc, SCM *argv, size_t nargs)
vp->fp = &base[5]; vp->fp = &base[5];
vp->sp = &SCM_FRAME_LOCAL (vp->fp, nargs); vp->sp = &SCM_FRAME_LOCAL (vp->fp, nargs);
if (vp->sp > vp->sp_max_since_gc)
vp->sp_max_since_gc = vp->sp;
{ {
int resume = SCM_I_SETJMP (registers); int resume = SCM_I_SETJMP (registers);
@ -1210,6 +1252,11 @@ scm_bootstrap_vm (void)
(scm_t_extension_init_func)scm_init_vm_builtins, (scm_t_extension_init_func)scm_init_vm_builtins,
NULL); NULL);
page_size = getpagesize ();
/* page_size should be a power of two. */
if (page_size & (page_size - 1))
abort ();
initialize_default_stack_size (); initialize_default_stack_size ();
sym_vm_run = scm_from_latin1_symbol ("vm-run"); sym_vm_run = scm_from_latin1_symbol ("vm-run");

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. /* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
@ -39,10 +39,11 @@ struct scm_vm {
scm_t_uint32 *ip; /* instruction pointer */ scm_t_uint32 *ip; /* instruction pointer */
SCM *sp; /* stack pointer */ SCM *sp; /* stack pointer */
SCM *fp; /* frame pointer */ SCM *fp; /* frame pointer */
size_t stack_size; /* stack size */
SCM *stack_base; /* stack base address */
SCM *stack_limit; /* stack limit address */ SCM *stack_limit; /* stack limit address */
int trace_level; /* traces enabled if trace_level > 0 */ int trace_level; /* traces enabled if trace_level > 0 */
SCM *sp_max_since_gc; /* highest sp since last gc */
size_t stack_size; /* stack size */
SCM *stack_base; /* stack base address */
size_t max_stack_size; size_t max_stack_size;
SCM hooks[SCM_VM_NUM_HOOKS]; /* hooks */ SCM hooks[SCM_VM_NUM_HOOKS]; /* hooks */
int engine; /* which vm engine we're using */ int engine; /* which vm engine we're using */