diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-03-31 23:44:35 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-03-31 23:44:35 +0000 |
commit | 05694302ecc310070baffd2cac49f9d61f4a46aa (patch) | |
tree | 97cc84b202806c3b70fb3ae12278dbc9623da2a3 | |
parent | d534e83da02988507374d63648d48dcb52930dac (diff) | |
download | mailfromd-05694302ecc310070baffd2cac49f9d61f4a46aa.tar.gz mailfromd-05694302ecc310070baffd2cac49f9d61f4a46aa.tar.bz2 |
Revert stack growth direction. Expand stack as the need arises.
git-svn-id: file:///svnroot/mailfromd/trunk@1333 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | doc/mailfromd.texi | 26 | ||||
-rw-r--r-- | src/drivers.c | 6 | ||||
-rw-r--r-- | src/prog.c | 151 | ||||
-rw-r--r-- | src/prog.h | 2 |
5 files changed, 106 insertions, 87 deletions
@@ -1,5 +1,13 @@ 2007-04-01 Sergey Poznyakoff <gray@gnu.org.ua> + * src/drivers.c (code_memref, code_type_arg), + src/prog.c (struct eval_environ, adjust_stack, env_base, get_arg) + (push, pop, heap_reserve_words, heap_tempspace, heap_max_tempspace) + (heap_fix_tempspace, instr_xchg, instr_dup, env_init) + (env_make_frame, env_leave_frame, eval_environment, env_final_gc), + src/prog.h, NEWS, doc/mailfromd.texi: Revert stack growth + direction. Expand stack as the need arises. + * src/gram.y (dataseg_layout): Make sure all global variables are subject to final_gc diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi index d8d61a58..0f97f1f5 100644 --- a/doc/mailfromd.texi +++ b/doc/mailfromd.texi @@ -3023,15 +3023,33 @@ database and its management. @subsection Pragma stacksize @cindex stacksize, pragma @cindex #pragma stacksize - The @code{stacksize} pragma sets the run-time stack size in words. -The default size is @value{STACK-SIZE}. You may wish to increase this -number if your configuration program has recursive functions or does -an excessive amount of string manipulations. Example syntax: + The @code{stacksize} pragma sets the initial size of the run-time +stack size in words. The default size is @value{STACK-SIZE}. You may +wish to increase this number if your configuration program has +recursive functions or does an excessive amount of string +manipulations. Example syntax: @smallexample #pragma stacksize 7168 @end smallexample +@FIXME{Improve the description:} +When the @acronym{MFL} engine notices that there is no more stack +available, it attempts to expand it. If this attempt succeeds, the +operation continues. + +If you are concerned about the execution time of your script, you +may wish to avoid such reallocations. To help you find out the +optimal stack size, each time the stack is expanded, +@command{mailfromd} issues a similar warning ti its log file: + +@smallexample +warning: stack segment expanded, new size=8192 +@end smallexample + +You can use these messages to adjust your stack size configuration +settings. + @node regex @subsection Pragma regex @cindex regex, pragma diff --git a/src/drivers.c b/src/drivers.c index 2e9c7c01..e3d22635 100644 --- a/src/drivers.c +++ b/src/drivers.c @@ -39,13 +39,13 @@ code_memref(NODE *node) case storage_auto: code_op(opcode_memstk); code_immediate((void*)node->v.var_ref.nframes); - code_immediate((void*)node->v.var_ref.variable->off); + code_immediate((void*)-node->v.var_ref.variable->off); break; case storage_param: code_op(opcode_memstk); code_immediate((void*)node->v.var_ref.nframes); - code_immediate((void*)(-(node->v.var_ref.variable->off + 2))); + code_immediate((void*)(node->v.var_ref.variable->off + 2)); break; } } @@ -1202,7 +1202,7 @@ code_type_arg(NODE *node, struct locus **old_locus) MARK_LOCUS(); code_op(opcode_memstk); code_immediate((void*)0); - code_immediate((void*)(-(node->v.arg.number+2))); + code_immediate((void*)(node->v.arg.number + 2)); code_op(opcode_deref); } @@ -230,12 +230,15 @@ disable_prog_trace(const char *modlist) struct eval_environ { prog_counter_t pc; /* Program counter */ - prog_counter_t tos; /* Top of stack: datasize <= tos <= toh */ + prog_counter_t tos; /* Top of stack: + toh <= tos <= datasize + stack_size */ prog_counter_t toh; /* Top of heap: - tos <= toh <= datasize + stack_size */ + datasize <= toh <= tos */ + prog_counter_t base; /* Base pointer */ STKVAL reg; /* General purpose register */ STKVAL *dataseg; /* Data space */ + size_t stack_size; /* Size of allocated stack + heap */ struct locus locus; /* Program locus corresponding to PC */ @@ -277,7 +280,7 @@ advance_pc(eval_environ_t env, unsigned cnt) void adjust_stack(eval_environ_t env, unsigned cnt) { - env->tos -= cnt; + env->tos += cnt; } size_t @@ -285,7 +288,7 @@ env_base(eval_environ_t env, size_t frame) { size_t base = env->base; for (; frame; frame--) - base = (size_t) env->dataseg[base-1]; + base = (size_t) env->dataseg[base + 1] + base + 1; return base; } @@ -307,6 +310,31 @@ env_get_stream(eval_environ_t env) return env->stream; } +#define STACK_EXPAND_BLOCK 64 + +static void +expand_dataseg(eval_environ_t env, size_t count, const char *errtext) +{ + STKVAL *newds; + count = ((count + STACK_EXPAND_BLOCK - 1) / STACK_EXPAND_BLOCK) + * STACK_EXPAND_BLOCK; + newds = realloc(env->dataseg, + (env->stack_size + datasize + count) + * sizeof env->dataseg[0]); + if (!newds) + runtime_error(env, errtext); + + + env->dataseg = newds; + env->stack_size += count; + env->tos += count; + memmove(newds + env->tos, newds + env->tos - count, + (datasize + env->stack_size - env->tos) + * sizeof newds[0]); + mu_error("warning: stack segment expanded, new size=%lu", + (unsigned long) env->stack_size); +} + void prog_trace(eval_environ_t env, const char *fmt, ...) @@ -370,7 +398,7 @@ get_literal(eval_environ_t env, unsigned n) STKVAL get_arg(eval_environ_t env, unsigned n) { - return env->dataseg[env->tos - n - 1]; + return env->dataseg[env->tos + n + 1]; } char * @@ -388,36 +416,33 @@ get_numeric_arg(eval_environ_t env, unsigned n) void push(eval_environ_t env, STKVAL val) { - if (env->tos >= env->toh) { + if (env->tos < env->toh) { debug2(100, "tos=%lu, toh=%lu", (unsigned long) env->tos, (unsigned long) env->toh); - runtime_error(env, - "Out of stack space; increase #pragma stacksize"); + expand_dataseg(env, 1, + "Out of stack space; increase #pragma stacksize"); } - env->dataseg[env->tos++] = val; + env->dataseg[env->tos--] = val; } STKVAL pop(eval_environ_t env) { - if (env->tos == 0) + if (env->tos == datasize + env->stack_size - 1) runtime_error(env, "Stack underflow"); - return env->dataseg[--env->tos]; + return env->dataseg[++env->tos]; } size_t heap_reserve_words(eval_environ_t env, size_t words) { - if (env->toh - words <= env->tos) { - /* Heap overrun: */ - /* gc(); */ - if (env->tos - words <= env->tos) - runtime_error(env, - "Heap overrun; increase #pragma stacksize"); - } - env->toh -= words; - return env->toh--; + size_t off = env->toh; + if (env->toh + words > env->tos) + expand_dataseg(env, 1, + "Heap overrun; increase #pragma stacksize"); + env->toh += words; + return off; } size_t @@ -431,36 +456,32 @@ heap_tempspace(eval_environ_t env, size_t size) { size_t words = B2STACK(size); - if (env->toh - words <= env->tos) { - /* Heap overrun: */ - /* gc(); */ - if (env->tos - words <= env->tos) - runtime_error(env, - "Heap overrun; increase #pragma stacksize"); - } - return env->dataseg + env->toh - words; + if (env->toh + words > env->tos) + expand_dataseg(env, words, + "Heap overrun; increase #pragma stacksize"); + return env->dataseg + env->toh; } STKVAL heap_max_tempspace(eval_environ_t env, size_t *size) { - *size = (env->toh - env->tos - 1) * sizeof env->dataseg[0]; - return env->dataseg + env->tos + 1; + *size = (env->tos - env->toh - 1) * sizeof env->dataseg[0]; + return env->dataseg + env->toh; } -STKVAL +size_t heap_fix_tempspace(eval_environ_t env, size_t size) { size_t words = B2STACK(size); - - if (words >= env->toh - env->tos) - runtime_error(env, - "INTERNAL ERROR: memory chunk too big " - "to fit into heap"); - env->toh -= words; - memmove(env->dataseg + env->toh, env->dataseg + env->tos + 1, size); - return env->dataseg + env->toh--; + size_t off; + + if (words >= env->tos - env->toh) + expand_dataseg(env, words, + "memory chunk too big to fit into heap"); + off = env->toh; + env->toh += words; + return off; } STKVAL * @@ -500,10 +521,10 @@ dump_locus(prog_counter_t i) void instr_xchg(eval_environ_t env) { - prog_counter_t p = env->tos - 1; + prog_counter_t p = env->tos + 1; STKVAL tmp = env->dataseg[p]; - env->dataseg[p] = env->dataseg[p - 1]; - env->dataseg[p - 1] = tmp; + env->dataseg[p] = env->dataseg[p + 1]; + env->dataseg[p + 1] = tmp; if (PROG_TRACE_ENGINE) prog_trace(env, "XCHG"); } @@ -544,7 +565,7 @@ instr_memstk(eval_environ_t env) { size_t frame = (size_t) get_immediate(env, 0); long off = (long) get_immediate(env, 1); - size_t val = env_base(env, frame) + off; + size_t val = env_base(env, frame) + off; advance_pc(env, 2); if (PROG_TRACE_ENGINE) prog_trace(env, "MEMSTK %lu(%ld)=%lu", @@ -578,7 +599,7 @@ instr_stkalloc(eval_environ_t env) unsigned n = (unsigned) get_immediate(env, 0); if (PROG_TRACE_ENGINE) prog_trace(env, "STKALLOC %p", n); - env->tos += n; + env->tos -= n; advance_pc(env, 1); } @@ -1641,7 +1662,7 @@ env_init(eval_environ_t env) /* Initialize status and registers */ env->status = SMFIS_CONTINUE; - env->tos = datasize; + env->tos = datasize + env->stack_size - 1; env->base = 0; env->reg = 0; @@ -1661,7 +1682,7 @@ void env_make_frame(eval_environ_t env) { push(env, (STKVAL) (env->pc + 1)); - push(env, (STKVAL) env->base); + push(env, (STKVAL) (env->base - env->tos)); env->base = env->tos; } @@ -1669,7 +1690,7 @@ void env_leave_frame(eval_environ_t env, int nargs) { env->tos = env->base; - env->base = (prog_counter_t) pop(env); + env->base += (prog_counter_t) pop(env) + 1; env->pc = (prog_counter_t) pop(env); adjust_stack(env, nargs); } @@ -1687,35 +1708,6 @@ env_push_number(eval_environ_t env, long arg) } int -env_set_variable(eval_environ_t env, char *ident, char *value) -{ - char *end; - struct variable *var = variable_lookup(ident); - if (!var) { - mu_error("Variable %s is not declared", ident); - return 1; - } - switch (var->type) { - case dtype_string: - env->dataseg[var->off] = (STKVAL) strdup(value); - break; - - case dtype_number: - env->dataseg[var->off] = (STKVAL) strtol(value, &end, 0); - if (*end) { - mu_error("%s is not a number", value); - return 1; - } - break; - - default: - mu_error("Type of %s is unknown", ident); - return 1; - } - return 0; -} - -int eval_environment(eval_environ_t env, prog_counter_t start) { if (setjmp(env->x_jmp)) @@ -2035,6 +2027,7 @@ create_environment(SMFICTX *ctx, exit(1); } + env->stack_size = stack_size; env->dataseg = calloc(stack_size + datasize, sizeof env->dataseg[0]); if (!env->dataseg) { mu_error("Not enough memory"); @@ -2054,7 +2047,7 @@ create_environment(SMFICTX *ctx, in env_init. The top of heap should be retained across calls to handlers, since we store string variables there. This raises stack size requirements. */ - env->toh = datasize + stack_size - 1; + env->toh = datasize + env->stack_size - 1; env->bi_priv_array = NULL; @@ -2223,7 +2216,7 @@ env_final_gc(eval_environ_t env) { size_t i; size_t top = env->toh; - size_t bot = datasize + stack_size; + size_t bot = datasize + env->stack_size; genv = env; /* Prepare s_off/s_count: remove any variables that are not @@ -2237,7 +2230,7 @@ env_final_gc(eval_environ_t env) qsort(s_off, s_cnt, sizeof s_off[0], s_off_cmp); /* Compact the variables */ - env->toh = datasize + stack_size - 1; + env->toh = datasize; for (i = 0; i < s_cnt; i++) { size_t off = s_off[i]; char *p = (char*) env_data_ref(env, @@ -42,7 +42,7 @@ size_t heap_reserve(eval_environ_t env, size_t size); size_t heap_reserve_words(eval_environ_t env, size_t size); STKVAL heap_tempspace(eval_environ_t env, size_t size); STKVAL heap_max_tempspace(eval_environ_t env, size_t *size); -STKVAL heap_fix_tempspace(eval_environ_t env, size_t size); +size_t heap_fix_tempspace(eval_environ_t env, size_t size); void pushs(eval_environ_t env, char *s); void advance_pc(eval_environ_t env, unsigned cnt); void adjust_stack(eval_environ_t env, unsigned cnt); |