Keeping track of the maximum stack depth a procedure needs for accurate stack checks

(fixes bug #130).  Done in conjunction with code generation refactoring, so that context
objects temporarily use their specific slot instead of having space for useful fields
at runtime.
This commit is contained in:
Alex Shinn 2012-07-16 16:23:54 +09:00
parent 254f6dee05
commit 6de7d5621d
4 changed files with 72 additions and 48 deletions

12
eval.c
View file

@ -260,7 +260,7 @@ void sexp_shrink_bcode (sexp ctx, sexp_uint_t i) {
void sexp_expand_bcode (sexp ctx, sexp_uint_t size) { void sexp_expand_bcode (sexp ctx, sexp_uint_t size) {
sexp tmp; sexp tmp;
if (sexp_bytecode_length(sexp_context_bc(ctx)) if (sexp_bytecode_length(sexp_context_bc(ctx))
< (sexp_context_pos(ctx))+size) { < (sexp_unbox_fixnum(sexp_context_pos(ctx)))+size) {
tmp=sexp_alloc_bytecode(ctx, sexp_bytecode_length(sexp_context_bc(ctx))*2); tmp=sexp_alloc_bytecode(ctx, sexp_bytecode_length(sexp_context_bc(ctx))*2);
sexp_bytecode_name(tmp) = sexp_bytecode_name(sexp_context_bc(ctx)); sexp_bytecode_name(tmp) = sexp_bytecode_name(sexp_context_bc(ctx));
sexp_bytecode_length(tmp) sexp_bytecode_length(tmp)
@ -278,13 +278,14 @@ void sexp_expand_bcode (sexp ctx, sexp_uint_t size) {
void sexp_emit (sexp ctx, unsigned char c) { void sexp_emit (sexp ctx, unsigned char c) {
sexp_expand_bcode(ctx, 1); sexp_expand_bcode(ctx, 1);
sexp_bytecode_data(sexp_context_bc(ctx))[sexp_context_pos(ctx)++] = c; sexp_bytecode_data(sexp_context_bc(ctx))[sexp_unbox_fixnum(sexp_context_pos(ctx))] = c;
sexp_context_pos(ctx) = sexp_fx_add(sexp_context_pos(ctx), SEXP_ONE);
} }
sexp sexp_complete_bytecode (sexp ctx) { sexp sexp_complete_bytecode (sexp ctx) {
sexp bc; sexp bc;
sexp_emit_return(ctx); sexp_emit_return(ctx);
sexp_shrink_bcode(ctx, sexp_context_pos(ctx)); sexp_shrink_bcode(ctx, sexp_unbox_fixnum(sexp_context_pos(ctx)));
bc = sexp_context_bc(ctx); bc = sexp_context_bc(ctx);
if (sexp_pairp(sexp_bytecode_literals(bc))) { /* compress literals */ if (sexp_pairp(sexp_bytecode_literals(bc))) { /* compress literals */
if (sexp_nullp(sexp_cdr(sexp_bytecode_literals(bc)))) if (sexp_nullp(sexp_cdr(sexp_bytecode_literals(bc))))
@ -294,6 +295,7 @@ sexp sexp_complete_bytecode (sexp ctx) {
else else
sexp_bytecode_literals(bc) = sexp_list_to_vector(ctx, sexp_bytecode_literals(bc)); sexp_bytecode_literals(bc) = sexp_list_to_vector(ctx, sexp_bytecode_literals(bc));
} }
sexp_bytecode_max_depth(bc) = sexp_unbox_fixnum(sexp_context_max_depth(ctx));
#if SEXP_USE_FULL_SOURCE_INFO #if SEXP_USE_FULL_SOURCE_INFO
if (sexp_bytecode_source(bc) && sexp_pairp(sexp_bytecode_source(bc))) { if (sexp_bytecode_source(bc) && sexp_pairp(sexp_bytecode_source(bc))) {
sexp_bytecode_source(bc) = sexp_nreverse(ctx, sexp_bytecode_source(bc)); sexp_bytecode_source(bc) = sexp_nreverse(ctx, sexp_bytecode_source(bc));
@ -444,6 +446,9 @@ sexp sexp_make_eval_context (sexp ctx, sexp stack, sexp env, sexp_uint_t size, s
return res; return res;
if (ctx) sexp_gc_preserve1(ctx, res); if (ctx) sexp_gc_preserve1(ctx, res);
sexp_context_env(res) = (env ? env : sexp_make_primitive_env(res, SEXP_SEVEN)); sexp_context_env(res) = (env ? env : sexp_make_primitive_env(res, SEXP_SEVEN));
sexp_context_specific(res) = sexp_make_vector(res, SEXP_SEVEN, SEXP_ZERO);
sexp_context_lambda(res) = SEXP_FALSE;
sexp_context_fv(res) = SEXP_NULL;
sexp_context_bc(res) = sexp_alloc_bytecode(res, SEXP_INIT_BCODE_SIZE); sexp_context_bc(res) = sexp_alloc_bytecode(res, SEXP_INIT_BCODE_SIZE);
if (sexp_exceptionp(sexp_context_bc(res))) { if (sexp_exceptionp(sexp_context_bc(res))) {
res = sexp_context_bc(res); res = sexp_context_bc(res);
@ -2126,6 +2131,7 @@ sexp sexp_compile_op (sexp ctx, sexp self, sexp_sint_t n, sexp obj, sexp env) {
sexp_emit_enter(ctx2); sexp_emit_enter(ctx2);
sexp_generate(ctx2, 0, 0, 0, ast); sexp_generate(ctx2, 0, 0, 0, ast);
res = sexp_complete_bytecode(ctx2); res = sexp_complete_bytecode(ctx2);
sexp_context_specific(ctx2) = SEXP_FALSE;
vec = sexp_make_vector(ctx2, 0, SEXP_VOID); vec = sexp_make_vector(ctx2, 0, SEXP_VOID);
if (sexp_exceptionp(vec)) res = vec; if (sexp_exceptionp(vec)) res = vec;
else res = sexp_make_procedure(ctx2, SEXP_ZERO, SEXP_ZERO, res, vec); else res = sexp_make_procedure(ctx2, SEXP_ZERO, SEXP_ZERO, res, vec);

View file

@ -367,7 +367,7 @@ struct sexp_struct {
#endif #endif
} env; } env;
struct { struct {
sexp_uint_t length; sexp_uint_t length, max_depth;
sexp name, literals, source; sexp name, literals, source;
unsigned char data[]; unsigned char data[];
} bytecode; } bytecode;
@ -421,8 +421,8 @@ struct sexp_struct {
struct timeval tval; struct timeval tval;
#endif #endif
char tailp, tracep, timeoutp, waitp; char tailp, tracep, timeoutp, waitp;
sexp_uint_t pos, depth, last_fp; sexp_uint_t last_fp;
sexp bc, lambda, stack, env, fv, parent, child, sexp stack, env, parent, child,
globals, dk, params, proc, name, specific, event; globals, dk, params, proc, name, specific, event;
#if SEXP_USE_DL #if SEXP_USE_DL
sexp dl; sexp dl;
@ -922,6 +922,7 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_cpointer_maybe_null_value(x) (sexp_not(x) ? NULL : sexp_cpointer_value(x)) #define sexp_cpointer_maybe_null_value(x) (sexp_not(x) ? NULL : sexp_cpointer_value(x))
#define sexp_bytecode_length(x) (sexp_field(x, bytecode, SEXP_BYTECODE, length)) #define sexp_bytecode_length(x) (sexp_field(x, bytecode, SEXP_BYTECODE, length))
#define sexp_bytecode_max_depth(x) (sexp_field(x, bytecode, SEXP_BYTECODE, max_depth))
#define sexp_bytecode_name(x) (sexp_field(x, bytecode, SEXP_BYTECODE, name)) #define sexp_bytecode_name(x) (sexp_field(x, bytecode, SEXP_BYTECODE, name))
#define sexp_bytecode_literals(x) (sexp_field(x, bytecode, SEXP_BYTECODE, literals)) #define sexp_bytecode_literals(x) (sexp_field(x, bytecode, SEXP_BYTECODE, literals))
#define sexp_bytecode_source(x) (sexp_field(x, bytecode, SEXP_BYTECODE, source)) #define sexp_bytecode_source(x) (sexp_field(x, bytecode, SEXP_BYTECODE, source))
@ -1014,11 +1015,6 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_context_env(x) (sexp_field(x, context, SEXP_CONTEXT, env)) #define sexp_context_env(x) (sexp_field(x, context, SEXP_CONTEXT, env))
#define sexp_context_stack(x) (sexp_field(x, context, SEXP_CONTEXT, stack)) #define sexp_context_stack(x) (sexp_field(x, context, SEXP_CONTEXT, stack))
#define sexp_context_depth(x) (sexp_field(x, context, SEXP_CONTEXT, depth))
#define sexp_context_bc(x) (sexp_field(x, context, SEXP_CONTEXT, bc))
#define sexp_context_fv(x) (sexp_field(x, context, SEXP_CONTEXT, fv))
#define sexp_context_pos(x) (sexp_field(x, context, SEXP_CONTEXT, pos))
#define sexp_context_lambda(x) (sexp_field(x, context, SEXP_CONTEXT, lambda))
#define sexp_context_parent(x) (sexp_field(x, context, SEXP_CONTEXT, parent)) #define sexp_context_parent(x) (sexp_field(x, context, SEXP_CONTEXT, parent))
#define sexp_context_child(x) (sexp_field(x, context, SEXP_CONTEXT, child)) #define sexp_context_child(x) (sexp_field(x, context, SEXP_CONTEXT, child))
#define sexp_context_saves(x) (sexp_field(x, context, SEXP_CONTEXT, saves)) #define sexp_context_saves(x) (sexp_field(x, context, SEXP_CONTEXT, saves))
@ -1039,6 +1035,17 @@ SEXP_API sexp sexp_make_unsigned_integer(sexp ctx, sexp_luint_t x);
#define sexp_context_waitp(x) (sexp_field(x, context, SEXP_CONTEXT, waitp)) #define sexp_context_waitp(x) (sexp_field(x, context, SEXP_CONTEXT, waitp))
#define sexp_context_dl(x) (sexp_field(x, context, SEXP_CONTEXT, dl)) #define sexp_context_dl(x) (sexp_field(x, context, SEXP_CONTEXT, dl))
/* during compilation, sexp_context_specific is set to a vector */
/* containing the following elements: */
#define sexp_context_bc(x) (sexp_vector_ref(sexp_context_specific(x), SEXP_ZERO))
#define sexp_context_fv(x) (sexp_vector_ref(sexp_context_specific(x), SEXP_ONE))
#define sexp_context_lambda(x) (sexp_vector_ref(sexp_context_specific(x), SEXP_TWO))
#define sexp_context_pos(x) (sexp_vector_ref(sexp_context_specific(x), SEXP_THREE))
#define sexp_context_depth(x) (sexp_vector_ref(sexp_context_specific(x), SEXP_FOUR))
#define sexp_context_max_depth(x) (sexp_vector_ref(sexp_context_specific(x), SEXP_FIVE))
#define sexp_context_exception(x) (sexp_vector_ref(sexp_context_specific(x), SEXP_SIX))
#if SEXP_USE_ALIGNED_BYTECODE #if SEXP_USE_ALIGNED_BYTECODE
#define sexp_context_align_pos(ctx) sexp_context_pos(ctx) = sexp_word_align(sexp_context_pos(ctx)) #define sexp_context_align_pos(ctx) sexp_context_pos(ctx) = sexp_word_align(sexp_context_pos(ctx))
#else #else

6
sexp.c
View file

@ -212,7 +212,7 @@ static struct sexp_type_struct _sexp_type_specs[] = {
{SEXP_SEQ, sexp_offsetof(seq, ls), 2, 2, 0, 0, sexp_sizeof(seq), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Sequence", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL}, {SEXP_SEQ, sexp_offsetof(seq, ls), 2, 2, 0, 0, sexp_sizeof(seq), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Sequence", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL},
{SEXP_LIT, sexp_offsetof(lit, value), 2, 2, 0, 0, sexp_sizeof(lit), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Literal", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL}, {SEXP_LIT, sexp_offsetof(lit, value), 2, 2, 0, 0, sexp_sizeof(lit), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Literal", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL},
{SEXP_STACK, sexp_offsetof(stack, data), 1, 1, sexp_offsetof(stack, top), 1, sexp_sizeof(stack), offsetof(struct sexp_struct, value.stack.length), sizeof(sexp), 0, 0, 0, 0, 0, 0, (sexp)"Stack", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, NULL}, {SEXP_STACK, sexp_offsetof(stack, data), 1, 1, sexp_offsetof(stack, top), 1, sexp_sizeof(stack), offsetof(struct sexp_struct, value.stack.length), sizeof(sexp), 0, 0, 0, 0, 0, 0, (sexp)"Stack", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, NULL},
{SEXP_CONTEXT, sexp_offsetof(context, bc), 14+SEXP_USE_DL, 14+SEXP_USE_DL, 0, 0, sexp_sizeof(context), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Context", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, NULL}, {SEXP_CONTEXT, sexp_offsetof(context, stack), 11+SEXP_USE_DL, 11+SEXP_USE_DL, 0, 0, sexp_sizeof(context), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Context", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, NULL},
{SEXP_CPOINTER, sexp_offsetof(cpointer, parent), 1, 0, 0, 0, sexp_sizeof(cpointer), sexp_offsetof(cpointer, length), 1, 0, 0, 0, 0, 0, 0, (sexp)"Cpointer", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, NULL}, {SEXP_CPOINTER, sexp_offsetof(cpointer, parent), 1, 0, 0, 0, sexp_sizeof(cpointer), sexp_offsetof(cpointer, length), 1, 0, 0, 0, 0, 0, 0, (sexp)"Cpointer", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, NULL},
#if SEXP_USE_AUTO_FORCE #if SEXP_USE_AUTO_FORCE
{SEXP_PROMISE, sexp_offsetof(promise, thunk), 2, 2, 0, 0, sexp_sizeof(promise), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Promise", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, NULL}, {SEXP_PROMISE, sexp_offsetof(promise, thunk), 2, 2, 0, 0, sexp_sizeof(promise), 0, 0, 0, 0, 0, 0, 0, 0, (sexp)"Promise", SEXP_FALSE, SEXP_FALSE, NULL, SEXP_FALSE, NULL, NULL},
@ -445,12 +445,10 @@ sexp sexp_make_context (sexp ctx, size_t size, size_t max_size) {
} }
if (!res || sexp_exceptionp(res)) return res; if (!res || sexp_exceptionp(res)) return res;
sexp_context_parent(res) = ctx; sexp_context_parent(res) = ctx;
sexp_context_lambda(res) = SEXP_FALSE;
sexp_context_name(res) = sexp_context_specific(res) = SEXP_FALSE; sexp_context_name(res) = sexp_context_specific(res) = SEXP_FALSE;
sexp_context_fv(res) = SEXP_NULL;
sexp_context_saves(res) = NULL; sexp_context_saves(res) = NULL;
sexp_context_params(res) = SEXP_NULL; sexp_context_params(res) = SEXP_NULL;
sexp_context_depth(res)=sexp_context_tracep(res)=sexp_context_pos(res)=0; sexp_context_tracep(res) = 0;
sexp_context_tailp(res) = 1; sexp_context_tailp(res) = 1;
#if SEXP_USE_GREEN_THREADS #if SEXP_USE_GREEN_THREADS
sexp_context_event(res) = SEXP_FALSE; sexp_context_event(res) = SEXP_FALSE;

65
vm.c
View file

@ -82,6 +82,17 @@ sexp sexp_stack_trace_op (sexp ctx, sexp self, sexp_sint_t n, sexp out) {
/************************* code generation ****************************/ /************************* code generation ****************************/
static void sexp_inc_context_pos(sexp ctx, sexp_sint_t off) {
sexp_context_pos(ctx) = sexp_fx_add(sexp_context_pos(ctx), sexp_make_fixnum(off));
}
static void sexp_inc_context_depth(sexp ctx, sexp_sint_t off) {
sexp_context_depth(ctx) = sexp_fx_add(sexp_context_depth(ctx), sexp_make_fixnum(off));
if (sexp_unbox_fixnum(sexp_context_depth(ctx))
> sexp_unbox_fixnum(sexp_context_max_depth(ctx)))
sexp_context_max_depth(ctx) = sexp_context_depth(ctx);
}
static void bytecode_preserve (sexp ctx, sexp obj) { static void bytecode_preserve (sexp ctx, sexp obj) {
sexp ls = sexp_bytecode_literals(sexp_context_bc(ctx)); sexp ls = sexp_bytecode_literals(sexp_context_bc(ctx));
if (sexp_pointerp(obj) && !sexp_symbolp(obj) if (sexp_pointerp(obj) && !sexp_symbolp(obj)
@ -94,13 +105,14 @@ static void sexp_emit_word (sexp ctx, sexp_uint_t val) {
sexp_expand_bcode(ctx, sizeof(sexp)); sexp_expand_bcode(ctx, sizeof(sexp));
data = sexp_bytecode_data(sexp_context_bc(ctx)); data = sexp_bytecode_data(sexp_context_bc(ctx));
sexp_context_align_pos(ctx); sexp_context_align_pos(ctx);
*((sexp_uint_t*)(&(data[sexp_context_pos(ctx)]))) = val; *((sexp_uint_t*)(&(data[sexp_unbox_fixnum(sexp_context_pos(ctx))]))) = val;
sexp_context_pos(ctx) += sizeof(sexp); sexp_inc_context_pos(ctx, sizeof(sexp));
} }
static void sexp_emit_push (sexp ctx, sexp obj) { static void sexp_emit_push (sexp ctx, sexp obj) {
sexp_emit(ctx, SEXP_OP_PUSH); sexp_emit(ctx, SEXP_OP_PUSH);
sexp_emit_word(ctx, (sexp_uint_t)obj); sexp_emit_word(ctx, (sexp_uint_t)obj);
sexp_inc_context_depth(ctx, 1);
bytecode_preserve(ctx, obj); bytecode_preserve(ctx, obj);
} }
@ -116,9 +128,9 @@ static void sexp_push_source (sexp ctx, sexp source) {
src = sexp_bytecode_source(bc); src = sexp_bytecode_source(bc);
if (!src) src = sexp_bytecode_source(bc) = SEXP_NULL; if (!src) src = sexp_bytecode_source(bc) = SEXP_NULL;
if (!sexp_pairp(src) if (!sexp_pairp(src)
|| sexp_context_pos(ctx) > sexp_unbox_fixnum(sexp_caar(src))) { || sexp_unbox_fixnum(sexp_context_pos(ctx)) > sexp_unbox_fixnum(sexp_caar(src))) {
sexp_gc_preserve1(ctx, tmp); sexp_gc_preserve1(ctx, tmp);
tmp = sexp_cons(ctx, sexp_make_fixnum(sexp_context_pos(ctx)), source); tmp = sexp_cons(ctx, sexp_context_pos(ctx), source);
if (sexp_pairp(tmp)) { if (sexp_pairp(tmp)) {
tmp = sexp_cons(ctx, tmp, src); tmp = sexp_cons(ctx, tmp, src);
if (sexp_pairp(tmp)) sexp_bytecode_source(bc) = tmp; if (sexp_pairp(tmp)) sexp_bytecode_source(bc) = tmp;
@ -132,15 +144,15 @@ static void sexp_push_source (sexp ctx, sexp source) {
static sexp_sint_t sexp_context_make_label (sexp ctx) { static sexp_sint_t sexp_context_make_label (sexp ctx) {
sexp_sint_t label; sexp_sint_t label;
sexp_context_align_pos(ctx); sexp_context_align_pos(ctx);
label = sexp_context_pos(ctx); label = sexp_unbox_fixnum(sexp_context_pos(ctx));
sexp_context_pos(ctx) += sizeof(sexp_uint_t); sexp_inc_context_pos(ctx, sizeof(sexp_uint_t));
return label; return label;
} }
static void sexp_context_patch_label (sexp ctx, sexp_sint_t label) { static void sexp_context_patch_label (sexp ctx, sexp_sint_t label) {
sexp bc = sexp_context_bc(ctx); sexp bc = sexp_context_bc(ctx);
unsigned char *data = sexp_bytecode_data(bc)+label; unsigned char *data = sexp_bytecode_data(bc)+label;
*((sexp_sint_t*)data) = sexp_context_pos(ctx)-label; *((sexp_sint_t*)data) = sexp_unbox_fixnum(sexp_context_pos(ctx))-label;
} }
static void generate_lit (sexp ctx, sexp value) { static void generate_lit (sexp ctx, sexp value) {
@ -153,7 +165,7 @@ static void generate_drop_prev (sexp ctx, sexp prev) {
&& sexp_opcode_class(sexp_car(prev)) != SEXP_OPC_FOREIGN) && sexp_opcode_class(sexp_car(prev)) != SEXP_OPC_FOREIGN)
|| (sexp_opcode_code(sexp_car(prev)) == SEXP_OP_PUSH))) || (sexp_opcode_code(sexp_car(prev)) == SEXP_OP_PUSH)))
|| sexp_setp(prev) || sexp_litp(prev) || prev == SEXP_VOID) || sexp_setp(prev) || sexp_litp(prev) || prev == SEXP_VOID)
sexp_context_pos(ctx) -= 1 + sizeof(sexp); sexp_inc_context_pos(ctx, -(1 + sizeof(sexp)));
else else
sexp_emit(ctx, SEXP_OP_DROP); sexp_emit(ctx, SEXP_OP_DROP);
} }
@ -167,7 +179,7 @@ static void generate_seq (sexp ctx, sexp name, sexp loc, sexp lam, sexp app) {
if (sexp_pointerp(sexp_car(head)) && (! sexp_litp(sexp_car(head)))) { if (sexp_pointerp(sexp_car(head)) && (! sexp_litp(sexp_car(head)))) {
sexp_generate(ctx, name, loc, lam, sexp_car(head)); sexp_generate(ctx, name, loc, lam, sexp_car(head));
generate_drop_prev(ctx, sexp_car(head)); generate_drop_prev(ctx, sexp_car(head));
sexp_context_depth(ctx)--; sexp_inc_context_depth(ctx, -1);
} }
sexp_context_tailp(ctx) = tailp; sexp_context_tailp(ctx) = tailp;
sexp_generate(ctx, name, loc, lam, sexp_car(head)); sexp_generate(ctx, name, loc, lam, sexp_car(head));
@ -180,12 +192,12 @@ static void generate_cnd (sexp ctx, sexp name, sexp loc, sexp lam, sexp cnd) {
sexp_generate(ctx, name, loc, lam, sexp_cnd_test(cnd)); sexp_generate(ctx, name, loc, lam, sexp_cnd_test(cnd));
sexp_context_tailp(ctx) = tailp; sexp_context_tailp(ctx) = tailp;
sexp_emit(ctx, SEXP_OP_JUMP_UNLESS); sexp_emit(ctx, SEXP_OP_JUMP_UNLESS);
sexp_context_depth(ctx)--; sexp_inc_context_depth(ctx, -1);
label1 = sexp_context_make_label(ctx); label1 = sexp_context_make_label(ctx);
sexp_generate(ctx, name, loc, lam, sexp_cnd_pass(cnd)); sexp_generate(ctx, name, loc, lam, sexp_cnd_pass(cnd));
sexp_context_tailp(ctx) = tailp; sexp_context_tailp(ctx) = tailp;
sexp_emit(ctx, SEXP_OP_JUMP); sexp_emit(ctx, SEXP_OP_JUMP);
sexp_context_depth(ctx)--; sexp_inc_context_depth(ctx, -1);
label2 = sexp_context_make_label(ctx); label2 = sexp_context_make_label(ctx);
sexp_context_patch_label(ctx, label1); sexp_context_patch_label(ctx, label1);
sexp_generate(ctx, name, loc, lam, sexp_cnd_fail(cnd)); sexp_generate(ctx, name, loc, lam, sexp_cnd_fail(cnd));
@ -211,7 +223,7 @@ static void generate_non_global_ref (sexp ctx, sexp name, sexp cell,
} }
if (unboxp && (sexp_truep(sexp_memq(ctx, name, sexp_lambda_sv(loc))))) if (unboxp && (sexp_truep(sexp_memq(ctx, name, sexp_lambda_sv(loc)))))
sexp_emit(ctx, SEXP_OP_CDR); sexp_emit(ctx, SEXP_OP_CDR);
sexp_context_depth(ctx)++; sexp_inc_context_depth(ctx, +1);
} }
static void generate_ref (sexp ctx, sexp ref, int unboxp) { static void generate_ref (sexp ctx, sexp ref, int unboxp) {
@ -266,7 +278,7 @@ static void generate_set (sexp ctx, sexp set) {
} }
} }
sexp_emit_push(ctx, SEXP_VOID); sexp_emit_push(ctx, SEXP_VOID);
sexp_context_depth(ctx)--; sexp_inc_context_depth(ctx, +1);
} }
static void generate_opcode_app (sexp ctx, sexp app) { static void generate_opcode_app (sexp ctx, sexp app) {
@ -298,7 +310,7 @@ static void generate_opcode_app (sexp ctx, sexp app) {
} else { } else {
sexp_emit_push(ctx, sexp_opcode_data(op)); sexp_emit_push(ctx, sexp_opcode_data(op));
} }
sexp_context_depth(ctx)++; sexp_inc_context_depth(ctx, +1);
num_args++; num_args++;
} }
} }
@ -324,7 +336,7 @@ static void generate_opcode_app (sexp ctx, sexp app) {
if (inv_default) { if (inv_default) {
sexp_emit_push(ctx, sexp_opcode_data(op)); sexp_emit_push(ctx, sexp_opcode_data(op));
if (sexp_opcode_opt_param_p(op)) sexp_emit(ctx, SEXP_OP_CDR); if (sexp_opcode_opt_param_p(op)) sexp_emit(ctx, SEXP_OP_CDR);
sexp_context_depth(ctx)++; sexp_inc_context_depth(ctx, +1);
num_args++; num_args++;
} }
@ -409,7 +421,7 @@ static void generate_opcode_app (sexp ctx, sexp app) {
&& sexp_opcode_class(op) != SEXP_OPC_FOREIGN) && sexp_opcode_class(op) != SEXP_OPC_FOREIGN)
sexp_emit_push(ctx, SEXP_VOID); sexp_emit_push(ctx, SEXP_VOID);
sexp_context_depth(ctx) -= (num_args-1); sexp_inc_context_depth(ctx, -(num_args-1));
sexp_gc_release1(ctx); sexp_gc_release1(ctx);
} }
@ -432,7 +444,7 @@ static void generate_general_app (sexp ctx, sexp app) {
sexp_emit_word(ctx, (sexp_uint_t)sexp_make_fixnum(len)); sexp_emit_word(ctx, (sexp_uint_t)sexp_make_fixnum(len));
sexp_context_tailp(ctx) = tailp; sexp_context_tailp(ctx) = tailp;
sexp_context_depth(ctx) -= len; sexp_inc_context_depth(ctx, -len);
sexp_gc_release1(ctx); sexp_gc_release1(ctx);
} }
@ -460,7 +472,7 @@ static void generate_tail_jump (sexp ctx, sexp name, sexp loc, sexp lam, sexp ap
/* drop the current result and jump */ /* drop the current result and jump */
sexp_emit(ctx, SEXP_OP_JUMP); sexp_emit(ctx, SEXP_OP_JUMP);
sexp_emit_word(ctx, (sexp_uint_t) (-sexp_context_pos(ctx) + sexp_emit_word(ctx, (sexp_uint_t) (-sexp_unbox_fixnum(sexp_context_pos(ctx)) +
(sexp_pairp(sexp_lambda_locals(lam)) (sexp_pairp(sexp_lambda_locals(lam))
? 1 + sizeof(sexp) : 0))); ? 1 + sizeof(sexp) : 0)));
@ -508,7 +520,7 @@ static int generate_lambda_locals (sexp ctx, sexp name, sexp loc, sexp lam, sexp
return 1; return 1;
} else if (sexp_setp(x) && sexp_internal_definep(ctx, sexp_set_var(x))) { } else if (sexp_setp(x) && sexp_internal_definep(ctx, sexp_set_var(x))) {
sexp_generate(ctx, name, loc, lam, x); sexp_generate(ctx, name, loc, lam, x);
sexp_context_pos(ctx) -= 1 + sizeof(sexp); sexp_inc_context_pos(ctx, -(1 + sizeof(sexp)));
return 1; return 1;
} }
return 0; return 0;
@ -559,7 +571,7 @@ static int generate_lambda_body (sexp ctx, sexp name, sexp loc, sexp lam, sexp x
sexp_emit(ctx, SEXP_OP_STACK_REF); sexp_emit(ctx, SEXP_OP_STACK_REF);
sexp_emit_word(ctx, 3); sexp_emit_word(ctx, 3);
sexp_emit(ctx, SEXP_OP_VECTOR_SET); sexp_emit(ctx, SEXP_OP_VECTOR_SET);
sexp_context_depth(ctx)--; sexp_inc_context_depth(ctx, -1);
} }
} }
} }
@ -633,7 +645,7 @@ static void generate_lambda (sexp ctx, sexp name, sexp loc, sexp lam, sexp lambd
sexp_emit_push(ctx, SEXP_VOID); sexp_emit_push(ctx, SEXP_VOID);
sexp_emit_push(ctx, sexp_length(ctx, fv)); sexp_emit_push(ctx, sexp_length(ctx, fv));
sexp_emit(ctx, SEXP_OP_MAKE_VECTOR); sexp_emit(ctx, SEXP_OP_MAKE_VECTOR);
sexp_context_depth(ctx)--; sexp_inc_context_depth(ctx, -1);
for (k=0; sexp_pairp(fv); fv=sexp_cdr(fv), k++) { for (k=0; sexp_pairp(fv); fv=sexp_cdr(fv), k++) {
ref = sexp_car(fv); ref = sexp_car(fv);
generate_non_global_ref(ctx, sexp_ref_name(ref), sexp_ref_cell(ref), generate_non_global_ref(ctx, sexp_ref_name(ref), sexp_ref_cell(ref),
@ -642,7 +654,7 @@ static void generate_lambda (sexp ctx, sexp name, sexp loc, sexp lam, sexp lambd
sexp_emit(ctx, SEXP_OP_STACK_REF); sexp_emit(ctx, SEXP_OP_STACK_REF);
sexp_emit_word(ctx, 3); sexp_emit_word(ctx, 3);
sexp_emit(ctx, SEXP_OP_VECTOR_SET); sexp_emit(ctx, SEXP_OP_VECTOR_SET);
sexp_context_depth(ctx)--; sexp_inc_context_depth(ctx, -1);
} }
/* push the additional procedure info and make the closure */ /* push the additional procedure info and make the closure */
sexp_emit(ctx, SEXP_OP_MAKE_PROCEDURE); sexp_emit(ctx, SEXP_OP_MAKE_PROCEDURE);
@ -880,9 +892,9 @@ sexp sexp_print_vm_profile (sexp ctx, sexp self, sexp_sint_t n) {
#if SEXP_USE_CHECK_STACK #if SEXP_USE_CHECK_STACK
#define sexp_ensure_stack(n) \ #define sexp_ensure_stack(n) \
if (top+n >= sexp_stack_length(sexp_context_stack(ctx))) { \ if (top+(n) >= sexp_stack_length(sexp_context_stack(ctx))) { \
sexp_context_top(ctx) = top; \ sexp_context_top(ctx) = top; \
if (sexp_grow_stack(ctx, n)) { \ if (sexp_grow_stack(ctx, (n))) { \
stack = sexp_stack_data(sexp_context_stack(ctx)); \ stack = sexp_stack_data(sexp_context_stack(ctx)); \
} else { \ } else { \
_ARG1 = sexp_global(ctx, SEXP_G_OOS_ERROR); \ _ARG1 = sexp_global(ctx, SEXP_G_OOS_ERROR); \
@ -1029,7 +1041,7 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) {
top -= 2; top -= 2;
apply1: apply1:
i = sexp_unbox_fixnum(sexp_length(ctx, tmp2)); i = sexp_unbox_fixnum(sexp_length(ctx, tmp2));
sexp_ensure_stack(i + 64); sexp_ensure_stack(i + 64 + sexp_procedurep(tmp1) ? sexp_bytecode_max_depth(sexp_procedure_code(tmp1)) : 0);
top += i; top += i;
for ( ; sexp_pairp(tmp2); tmp2=sexp_cdr(tmp2), top--) for ( ; sexp_pairp(tmp2); tmp2=sexp_cdr(tmp2), top--)
_ARG1 = sexp_car(tmp2); _ARG1 = sexp_car(tmp2);
@ -1054,7 +1066,6 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) {
fp = sexp_unbox_fixnum(tmp2); fp = sexp_unbox_fixnum(tmp2);
goto make_call; goto make_call;
case SEXP_OP_CALL: case SEXP_OP_CALL:
sexp_ensure_stack(64); /* TODO: pre-compute stack needed for each proc */
_ALIGN_IP(); _ALIGN_IP();
i = sexp_unbox_fixnum(_WORD0); i = sexp_unbox_fixnum(_WORD0);
tmp1 = _ARG1; tmp1 = _ARG1;
@ -1074,6 +1085,8 @@ sexp sexp_apply (sexp ctx, sexp proc, sexp args) {
if (j < 0) if (j < 0)
sexp_raise("not enough args", sexp_raise("not enough args",
sexp_list2(ctx, tmp1, sexp_make_fixnum(i))); sexp_list2(ctx, tmp1, sexp_make_fixnum(i)));
/* ensure there's sufficient stack space before pushing args */
sexp_ensure_stack(sexp_bytecode_max_depth(sexp_procedure_code(tmp1))+64);
if (j > 0) { if (j > 0) {
if (sexp_procedure_variadic_p(tmp1)) { if (sexp_procedure_variadic_p(tmp1)) {
if (!sexp_procedure_unused_rest_p(tmp1)) { if (!sexp_procedure_unused_rest_p(tmp1)) {