aboutsummaryrefslogtreecommitdiff
path: root/mfd/prog.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-10-11 13:32:52 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2009-12-12 22:00:23 +0200
commitc40609975ec9e14d6b386246c035b3688ed979fc (patch)
tree975aeb66d69efd61ed22b163c43f13be7cb93010 /mfd/prog.c
parentec01d598911397acd15ffa1effcb3bfc815b497b (diff)
downloadmailfromd-c40609975ec9e14d6b386246c035b3688ed979fc.tar.gz
mailfromd-c40609975ec9e14d6b386246c035b3688ed979fc.tar.bz2
Fix exception handling. Introduce user-defined exceptions.
* mfd/bitmask.h: New file. * mfd/Makefile.am: Add bitmask.h * mfd/drivers.c (print_type_catch): Take into account the `all' flag: there may be more exceptions than mf_exception_count. (code_type_catch): Use code_exmask to code exception mask values. * mfd/gram.y (codegen): Take struct exmask * as its third parameter. (%union): New member catchlist. (catchlist): Change type. (T_DCLEX): New token. (decl rule): New production: exdecl. (exdecl): New rule. (catch rule): Use bitmask. (simple_catch rule): Likewise. (catchlist rule): Rewrite. (free_parser_data): New placeholder. (exmask_create): New function. (create_on_node): Use struct exmask* instead of the fixed-size bitmask. (dataseg_layout): Store exception masks in the DS. * mfd/lex.l (dclex): New token. * mfd/mailfromd.h: Include bitmask.h (EXMASK): Rename to STATMASK. (struct catch_node, struct function): Store exception masks in struct exmask. (exmask): New struct. (exmask_create, code_exmask): New prototypes. * mfd/main.c (main): Call free_parser_data. * mfd/mf-status.mfi (mf_exception_str): Change parameter type to unsigned int. Return USER-DEFINED-%d instead of the UNKNOWN for exceptions not in the predefined range. * mfd/opcodes (CATCH): Decrease number of arguments. * mfd/prog.c (exception_count): New global. (code_exmask): New function. (exception_context): New struct. (eval_environ): defcatch and catch replaced by defcatch_ctx and catch_ctx. (instr_catch): Read exceptions from the DS. Take two arguments. (dump_catch): Update. (instr_saveex): For each exception, save on stack its entry point, tos and base addresses in the form of tos invariants. (dump_saveex): Update. (instr_restex): Do the reverse of instr_saveex. (env_init, destroy_environment) (env_save_catches): Reflect changes to eval_environ_t. (env_throw_0): Before passing control to the exception handler, restore tos and base addresses. * mfd/prog.h (exception_count): New extern. * mfd/snarf.m4: Use STATMASK instead of EXMASK. * mfd/symbols.c (function_install): Create mask using exmask_create.
Diffstat (limited to 'mfd/prog.c')
-rw-r--r--mfd/prog.c165
1 files changed, 113 insertions, 52 deletions
diff --git a/mfd/prog.c b/mfd/prog.c
index d9137f51..28e0d87c 100644
--- a/mfd/prog.c
+++ b/mfd/prog.c
@@ -62,6 +62,9 @@ struct rt_regex *regtab;
size_t regcount;
struct obstack regstk;
+/* Exceptions */
+size_t exception_count = mf_exception_count;
+
void
code_init()
@@ -125,6 +128,12 @@ code_immediate(const void *ptr)
return code_instr(ptr);
}
+prog_counter_t
+code_exmask(struct exmask *exmask)
+{
+ return code_immediate((void*) exmask->off);
+}
+
void
code_put(prog_counter_t pos, void *ptr)
{
@@ -250,6 +259,14 @@ disable_prog_trace(const char *modlist)
See comment to env_fixup_autos, below. */
#define MAX_AUTO_PTR 128
+struct exception_context {
+ prog_counter_t pc;
+ prog_counter_t tos;
+ prog_counter_t base;
+};
+
+#define TOS_INVARIANT(env,t) (datasize + (env)->stack_size - (t))
+
struct eval_environ {
prog_counter_t pc; /* Program counter */
@@ -293,8 +310,8 @@ struct eval_environ {
its end before writing. */
/* Non-local exits */
- prog_counter_t defcatch[mf_exception_count];
- prog_counter_t catch[mf_exception_count];
+ struct exception_context *defcatch_ctx;
+ struct exception_context *catch_ctx;
/* Built-in private data */
void **bi_priv_array;
@@ -1627,20 +1644,26 @@ void
instr_catch(eval_environ_t env)
{
long off = (long) get_immediate(env, 0);
- /* int count = (long) get_immediate(env, 1); -- Count is not used */
- unsigned mask = (unsigned) get_immediate(env, 2);
- int i;
- prog_counter_t entry = env->pc + 4;
+ unsigned toff = (unsigned) get_immediate(env, 1);
+ size_t count = (size_t) env->dataseg[toff];
+ STKVAL *tab = (STKVAL *) (env->dataseg + toff + 1);
+ size_t i;
+ prog_counter_t entry = env->pc + 3;
if (PROG_TRACE_ENGINE)
prog_trace(env, "CATCH %ld, %ld", entry, off);
- for (i = 0; i < mf_exception_count; i++)
- if (mask & EXMASK(i)) {
+ for (i = 0; i < count * NBMBITS; i++)
+ if (((bitmask_bits_t)tab[BIT_WORD(i)]) & BIT_MASK(i)) {
if (PROG_TRACE_ENGINE)
- prog_trace(env, "CATCH TARGET: %s",
- mf_exception_str((mf_exception)i));
- env->catch[i] = entry;
+ prog_trace(env, "CATCH TARGET: %lu %s",
+ (unsigned long) i,
+ mf_exception_str(i));
+ env->catch_ctx[i].pc = entry;
+ env->catch_ctx[i].tos =
+ TOS_INVARIANT(env, env->tos);
+ env->catch_ctx[i].base =
+ TOS_INVARIANT(env, env->base);
}
advance_pc(env, off);
@@ -1649,13 +1672,14 @@ instr_catch(eval_environ_t env)
void
dump_catch(prog_counter_t i)
{
- unsigned mask = (unsigned) prog[i+2];
+ size_t toff = (size_t) prog[i+1];
+ size_t count = (size_t) dataseg[toff];
+ STKVAL *tab = (STKVAL *) (dataseg + toff + 1);
printf("%ld (%ld)", (long) prog[i], i + (long) prog[i]);
printf("; Targets: ");
-
- for (i = 0; i < mf_exception_count; i++)
- if (mask & EXMASK(i))
- printf("%s ", mf_exception_str((mf_exception)i));
+ for (i = 0; i < count * NBMBITS; i++)
+ if (((bitmask_bits_t)tab[BIT_WORD(i)]) & BIT_MASK(i))
+ printf(" %lu", (unsigned long) i);
}
void
@@ -1673,7 +1697,7 @@ instr_throw(eval_environ_t env)
void
dump_throw(prog_counter_t i)
{
- printf("%s", mf_exception_str((mf_exception) prog[i]));
+ printf("%s", mf_exception_str((unsigned)prog[i]));
}
@@ -1706,44 +1730,71 @@ instr_retcatch(eval_environ_t env)
void
instr_saveex(eval_environ_t env)
{
- unsigned exmask = (unsigned) get_immediate(env, 0);
- int i;
+ unsigned off = (unsigned) get_immediate(env, 0);
+ size_t count = (size_t) env->dataseg[off];
+ STKVAL *tab = (STKVAL *) (env->dataseg + off + 1);
+ size_t i;
if (PROG_TRACE_ENGINE)
- prog_trace(env, "SAVEEX %x", exmask);
+ prog_trace(env, "SAVEEX %x (%lu ex.)", off,
+ (unsigned long) count);
advance_pc(env, 1);
- for (i = 0; i < mf_exception_count; i++)
- if (EXMASK(i) & exmask) {
- debug3(101, "Push Exception: %d %lu <- %lu",
- i, (unsigned long) env->tos,
- (unsigned long) env->catch[i]);
- push(env, (STKVAL) env->catch[i]);
+ for (i = 0; i < count * NBMBITS; i++)
+ if (((bitmask_bits_t)tab[BIT_WORD(i)]) & BIT_MASK(i)) {
+ debug5(101,
+ "Push Exception: %d %lu <- pc=%lu, tos=%lu, base=%lu",
+ i, (unsigned long) TOS_INVARIANT(env,env->tos),
+ (unsigned long) env->catch_ctx[i].pc,
+ (unsigned long) env->catch_ctx[i].tos,
+ (unsigned long) env->catch_ctx[i].base);
+ push(env, (STKVAL) env->catch_ctx[i].pc);
+ push(env, (STKVAL) env->catch_ctx[i].tos);
+ push(env, (STKVAL) env->catch_ctx[i].base);
}
- push(env, (STKVAL) exmask);
+ push(env, (STKVAL) off);
}
void
-dump_saveex(prog_counter_t i)
+dump_saveex(prog_counter_t ctr)
{
- printf("%x", (unsigned)prog[i]);
+ size_t off = (size_t)prog[ctr];
+ size_t count = (size_t) dataseg[off];
+ STKVAL *tab = (STKVAL *) (dataseg + off + 1);
+ size_t i;
+
+ printf("%lu:", (unsigned long) count);
+ for (i = 0; i < count; i++)
+ if (((bitmask_bits_t)tab[BIT_WORD(i)]) & BIT_MASK(i))
+ printf(" %lu", (unsigned long) i);
}
void
instr_restex(eval_environ_t env)
{
- unsigned exmask = (unsigned) pop(env);
- int i;
+ unsigned off = (unsigned) pop(env);
+ size_t count = (size_t) env->dataseg[off];
+ STKVAL *tab = (STKVAL *) (env->dataseg + off + 1);
+ size_t i;
if (PROG_TRACE_ENGINE)
- prog_trace(env, "RESTEX %x", exmask);
- for (i = mf_exception_count-1; i >= 0; i--)
- if (EXMASK(i) & exmask) {
- env->catch[i] = (prog_counter_t) pop(env);
- debug3(102, "Pop Exception: %d %lu -> %lu",
- i, (unsigned long) env->tos,
- (unsigned long) env->catch[i]);
+ prog_trace(env, "RESTEX %x (%lu ex.)",
+ off, (unsigned long) count);
+ i = count * NBMBITS - 1;
+ do {
+ i--;
+ if (((bitmask_bits_t)tab[BIT_WORD(i)]) & BIT_MASK(i)) {
+ env->catch_ctx[i].base = (prog_counter_t) pop(env);
+ env->catch_ctx[i].tos = (prog_counter_t) pop(env);
+ env->catch_ctx[i].pc = (prog_counter_t) pop(env);
+ debug5(102,
+ "Pop Exception: %d %lu -> pc=%lu, tos=%lu, base=%lu",
+ i, (unsigned long) TOS_INVARIANT(env,env->tos),
+ (unsigned long) env->catch_ctx[i].pc,
+ (unsigned long) env->catch_ctx[i].tos,
+ (unsigned long) env->catch_ctx[i].base);
}
+ } while (i > 0);
}
void
@@ -1963,7 +2014,8 @@ env_init(eval_environ_t env)
env->numautos = 0;
/* Initialize catch functions */
- memcpy (env->catch, env->defcatch, sizeof env->catch);
+ memcpy (env->catch_ctx, env->defcatch_ctx,
+ exception_count * sizeof(env->catch_ctx[0]));
env_final_gc(env);
}
@@ -2102,14 +2154,18 @@ env_vsprintf(eval_environ_t env, const char *biname,
void
env_throw_0(eval_environ_t env, mf_exception status, size_t off)
{
- prog_counter_t pc = env->catch[status];
+ prog_counter_t pc;
+
+ if (status > exception_count)
+ runtime_error(env, "unknown exception: %d\n", status);
+
+ pc = env->catch_ctx[status].pc;
if (pc) {
- /* Reset the exception to avoid recursion. We will never have
- to restore it again, since the catch handler either returns
- from the function, in which case the exception mask will be
- restored, or stops the execution with an action, in which
- case exceptions are not relevant anymore. */
- env->catch[status] = 0;
+ /* Restore tos */
+ env->tos = TOS_INVARIANT(env, env->catch_ctx[status].tos);
+ env->base = TOS_INVARIANT(env, env->catch_ctx[status].base);
+ /* Reset the exception to avoid recursion. */
+ env->catch_ctx[status].pc = 0;
/* Fixup the program counter */
env->pc = pc - 1;
/* Generate normal entry frame */
@@ -2406,7 +2462,7 @@ create_environment(SMFICTX *ctx,
void *data)
{
struct eval_environ *env = calloc(1, sizeof *env);
-
+
if (!env) {
mu_error(_("not enough memory"));
exit(1);
@@ -2428,22 +2484,26 @@ create_environment(SMFICTX *ctx,
env->msgmod = msgmod;
env->status = SMFIS_CONTINUE;
/* FIXME:
- The only register that we initialize here. The rest is initialized
+ The only registers that we initialize here. The rest is initialized
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;
-
+ env->tos = datasize + env->stack_size - 1;
+
env->bi_priv_array = NULL;
- memset(env->defcatch, 0, sizeof env->defcatch);
-
+ env->defcatch_ctx = xzalloc (exception_count *
+ sizeof(env->defcatch_ctx[0]));
+ env->catch_ctx = xzalloc (exception_count * sizeof(env->catch_ctx[0]));
return env;
}
void
destroy_environment(eval_environ_t env)
{
+ free(env->catch_ctx);
+ free(env->defcatch_ctx);
free(env->dataseg);
free(env->matches);
mu_stream_close(env->stream);
@@ -2660,6 +2720,7 @@ env_final_gc(eval_environ_t env)
void
env_save_catches(eval_environ_t env)
{
- memcpy(env->defcatch, env->catch, sizeof env->defcatch);
+ memcpy(env->defcatch_ctx, env->catch_ctx,
+ exception_count * sizeof env->defcatch_ctx[0]);
}

Return to:

Send suggestions and report system problems to the System administrator.