aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-03-31 23:44:35 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-03-31 23:44:35 +0000
commit05694302ecc310070baffd2cac49f9d61f4a46aa (patch)
tree97cc84b202806c3b70fb3ae12278dbc9623da2a3
parentd534e83da02988507374d63648d48dcb52930dac (diff)
downloadmailfromd-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--ChangeLog8
-rw-r--r--doc/mailfromd.texi26
-rw-r--r--src/drivers.c6
-rw-r--r--src/prog.c151
-rw-r--r--src/prog.h2
5 files changed, 106 insertions, 87 deletions
diff --git a/ChangeLog b/ChangeLog
index 965d65e4..8b3bdc17 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);
}
diff --git a/src/prog.c b/src/prog.c
index 7cc0a307..d29387c0 100644
--- a/src/prog.c
+++ b/src/prog.c
@@ -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,
diff --git a/src/prog.h b/src/prog.h
index f16ecce1..e16c35ed 100644
--- a/src/prog.h
+++ b/src/prog.h
@@ -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);

Return to:

Send suggestions and report system problems to the System administrator.