diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-10-11 13:32:52 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-12-12 22:00:23 +0200 |
commit | c40609975ec9e14d6b386246c035b3688ed979fc (patch) | |
tree | 975aeb66d69efd61ed22b163c43f13be7cb93010 /mfd/prog.c | |
parent | ec01d598911397acd15ffa1effcb3bfc815b497b (diff) | |
download | mailfromd-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.c | 165 |
1 files changed, 113 insertions, 52 deletions
@@ -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]); } |