diff options
| author | dearblue <[email protected]> | 2020-05-24 00:19:04 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2020-10-12 16:21:32 +0900 |
| commit | a54a3df32c379a6953664f1d9241c731066915ec (patch) | |
| tree | 37ef8811bfe2aaf8533253f6a1025a35bdc58d4d | |
| parent | 3ad6bbc40c87f24819c6d8f25446bc74d348c822 (diff) | |
| download | mruby-a54a3df32c379a6953664f1d9241c731066915ec.tar.gz mruby-a54a3df32c379a6953664f1d9241c731066915ec.zip | |
Extended mruby binary format
The catch handler table is combined with iseq block.
This is to prevent the structure from growing by adding a field for the
catch handler table to the `mrb_irep` structure.
"iseq block" and "catch handler table":
[number of catch handler table (2 bytes)]
[number of byte code (4 bytes)]
[iseq (any bytes)]
[catch handlers (multiple of 7 bytes)]
catch handler:
[catch type (1 byte)]
[begin offset (2 bytes)]
[end offset (2 bytes)]
[target offset (2 bytes)]
catch type: enum mrb_catch_type (0 = rescue, 1 = ensure)
begin offset: Includes the specified instruction address
end offset: Does not include the specified instruction address
target offset: replaces pc with the specified instruction address
This table is not expanded by `read_irep_record_1()`.
The necessary elements are expanded one by one when used.
| -rw-r--r-- | include/mruby/irep.h | 29 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 47 | ||||
| -rw-r--r-- | src/codedump.c | 29 | ||||
| -rw-r--r-- | src/dump.c | 32 | ||||
| -rw-r--r-- | src/load.c | 11 |
5 files changed, 143 insertions, 5 deletions
diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 0a5b3f1a3..430602279 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -39,13 +39,31 @@ typedef struct mrb_pool_value { } u; } mrb_pool_value; +enum mrb_catch_type { + MRB_CATCH_RESCUE = 0, + MRB_CATCH_ENSURE = 1, +}; + +struct mrb_irep_catch_hander { + uint8_t type; /* enum mrb_catch_type */ + uint8_t begin[2]; /* The starting address to match the hander. Includes this. */ + uint8_t end[2]; /* The endpoint address that matches the hander. Not Includes this. */ + uint8_t target[2]; /* The address to jump to if a match is made. */ +}; + /* Program data array struct */ typedef struct mrb_irep { uint16_t nlocals; /* Number of local variables */ uint16_t nregs; /* Number of register variables */ + uint16_t clen; /* Number of catch handlers */ uint8_t flags; const mrb_code *iseq; + /* + * A catch handler table is placed after the iseq entity. + * The reason it doesn't add fields to the structure is to keep the mrb_irep structure from bloating. + * The catch handler table can be obtained with `mrb_irep_catch_handler_table(irep)`. + */ const mrb_pool_value *pool; const mrb_sym *syms; const struct mrb_irep * const *reps; @@ -107,6 +125,17 @@ struct mrb_insn_data { struct mrb_insn_data mrb_decode_insn(const mrb_code *pc); +static inline const struct mrb_irep_catch_hander * +mrb_irep_catch_handler_table(const struct mrb_irep *irep) +{ + if (irep->clen > 0) { + return (const struct mrb_irep_catch_hander *)(irep->iseq + irep->ilen); + } + else { + return (const struct mrb_irep_catch_hander *)NULL; + } +} + MRB_END_DECL #endif /* MRUBY_IREP_H */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 191895668..e55b6791d 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -11,6 +11,7 @@ #include <mruby.h> #include <mruby/compile.h> #include <mruby/proc.h> +#include <mruby/dump.h> #include <mruby/numeric.h> #include <mruby/string.h> #include <mruby/debug.h> @@ -72,6 +73,7 @@ typedef struct scope { mrb_pool_value *pool; mrb_sym *syms; mrb_irep **reps; + struct mrb_irep_catch_hander *catch_table; uint32_t pcapa, scapa, rcapa; uint16_t nlocals; @@ -91,6 +93,15 @@ static struct loopinfo *loop_push(codegen_scope *s, enum looptype t); static void loop_break(codegen_scope *s, node *tree); static void loop_pop(codegen_scope *s, int val); +/* + * The search for catch handlers starts at the end of the table in mrb_vm_run(). + * Therefore, the next handler to be added must meet one of the following conditions. + * - Larger start position + * - Same start position but smaller end position + */ +static int catch_hander_new(codegen_scope *s); +static void catch_hander_set(codegen_scope *s, int ent, enum mrb_catch_type type, uint32_t begin, uint32_t end, uint32_t target); + static void gen_assignment(codegen_scope *s, node *tree, int sp, int val); static void gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val); @@ -3082,9 +3093,18 @@ scope_finish(codegen_scope *s) } irep->flags = 0; if (s->iseq) { - irep->iseq = (const mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc); + size_t catchsize = sizeof(struct mrb_irep_catch_hander) * irep->clen; + irep->iseq = (const mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc + catchsize); irep->ilen = s->pc; + if (irep->clen > 0) { + memcpy((void *)(irep->iseq + irep->ilen), s->catch_table, catchsize); + } } + else { + irep->clen = 0; + } + mrb_free(s->mrb, s->catch_table); + s->catch_table = NULL; irep->pool = (const mrb_pool_value*)codegen_realloc(s, s->pool, sizeof(mrb_pool_value)*irep->plen); irep->syms = (const mrb_sym*)codegen_realloc(s, s->syms, sizeof(mrb_sym)*irep->slen); irep->reps = (const mrb_irep**)codegen_realloc(s, s->reps, sizeof(mrb_irep*)*irep->rlen); @@ -3187,6 +3207,31 @@ loop_pop(codegen_scope *s, int val) if (val) push(); } +static int +catch_hander_new(codegen_scope *s) +{ + size_t newsize = sizeof(struct mrb_irep_catch_hander) * (s->irep->clen + 1); + s->catch_table = (struct mrb_irep_catch_hander *)codegen_realloc(s, (void *)s->catch_table, newsize); + return s->irep->clen ++; +} + +static void +catch_hander_set(codegen_scope *s, int ent, enum mrb_catch_type type, uint32_t begin, uint32_t end, uint32_t target) +{ + struct mrb_irep_catch_hander *e; + + mrb_assert(ent >= 0 && ent < s->irep->clen); + mrb_assert(begin < MAXARG_S); + mrb_assert(end < MAXARG_S); + mrb_assert(target < MAXARG_S); + + e = &s->catch_table[ent]; + uint8_to_bin(type, &e->type); + uint16_to_bin(begin, e->begin); + uint16_to_bin(end, e->end); + uint16_to_bin(target, e->target); +} + static struct RProc* generate_code(mrb_state *mrb, parser_state *p, int val) { diff --git a/src/codedump.c b/src/codedump.c index 106312f67..a19d60708 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -4,6 +4,7 @@ #include <mruby/opcode.h> #include <mruby/string.h> #include <mruby/proc.h> +#include <mruby/dump.h> #ifndef MRB_DISABLE_STDIO static void @@ -80,6 +81,34 @@ codedump(mrb_state *mrb, const mrb_irep *irep) } } + if (irep->clen > 0) { + int i = irep->clen; + const struct mrb_irep_catch_hander *e = mrb_irep_catch_handler_table(irep); + + for (; i > 0; i --, e ++) { + int begin = bin_to_uint16(e->begin); + int end = bin_to_uint16(e->end); + int target = bin_to_uint16(e->target); + char buf[20]; + const char *type; + + switch (e->type) { + case MRB_CATCH_RESCUE: + type = "rescue"; + break; + case MRB_CATCH_ENSURE: + type = "ensure"; + break; + default: + buf[0] = '\0'; + snprintf(buf, sizeof(buf), "0x%02x <unknown>", (int)e->type); + type = buf; + break; + } + printf("catch type: %-8s begin: %04d end: %04d target: %04d\n", type, begin, end, target); + } + } + pc = irep->iseq; pcend = pc + irep->ilen; while (pc < pcend) { diff --git a/src/dump.c b/src/dump.c index 6acba12c2..884c44dc6 100644 --- a/src/dump.c +++ b/src/dump.c @@ -274,12 +274,38 @@ write_syms_block(mrb_state *mrb, const mrb_irep *irep, uint8_t *buf) } static size_t +get_catch_table_block_size(mrb_state *mrb, const mrb_irep *irep) +{ + size_t size = 0; + + size += sizeof(uint16_t); /* number of catch handler */ + size += (sizeof(struct mrb_irep_catch_hander)) * irep->clen; + + return size; +} + +static ptrdiff_t +write_catch_table_block(mrb_state *mrb, const mrb_irep *irep, uint8_t *buf) +{ + uint8_t *cur = buf; + const struct mrb_irep_catch_hander *e = mrb_irep_catch_handler_table(irep); + mrb_static_assert1(sizeof(*e) == 7); + + /* irep->clen has already been written before iseq block */ + memcpy(cur, (const void *)e, sizeof(*e) * irep->clen); + cur += sizeof(*e) * irep->clen; + + return cur - buf; +} + +static size_t get_irep_record_size_1(mrb_state *mrb, const mrb_irep *irep) { size_t size = 0; size += get_irep_header_size(mrb); size += get_iseq_block_size(mrb, irep); + size += get_catch_table_block_size(mrb, irep); size += get_pool_block_size(mrb, irep); size += get_syms_block_size(mrb, irep); return size; @@ -314,7 +340,13 @@ write_irep_record(mrb_state *mrb, const mrb_irep *irep, uint8_t *bin, size_t *ir } bin += write_irep_header(mrb, irep, bin); + /* + * The catch handler table is after iseq block, but the number of + * elements is placed before iseq block. + */ + bin += uint16_to_bin(irep->clen, bin); bin += write_iseq_block(mrb, irep, bin, flags); + bin += write_catch_table_block(mrb, irep, bin); bin += write_pool_block(mrb, irep, bin); bin += write_syms_block(mrb, irep, bin); diff --git a/src/load.c b/src/load.c index 1118fc2ad..59790bc17 100644 --- a/src/load.c +++ b/src/load.c @@ -96,27 +96,30 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag src += sizeof(uint16_t); /* Binary Data Section */ - /* ISEQ BLOCK */ + /* ISEQ BLOCK (and CATCH HANDLER TABLE BLOCK) */ + irep->clen = bin_to_uint16(src); /* number of catch handler */ + src += sizeof(uint16_t); irep->ilen = (uint16_t)bin_to_uint32(src); src += sizeof(uint32_t); src += skip_padding(src); if (irep->ilen > 0) { + size_t data_len = sizeof(mrb_code) * irep->ilen + + sizeof(struct mrb_irep_catch_hander) * irep->clen; + mrb_static_assert1(sizeof(struct mrb_irep_catch_hander) == 7); if (SIZE_ERROR_MUL(irep->ilen, sizeof(mrb_code))) { return NULL; } if ((flags & FLAG_SRC_MALLOC) == 0) { irep->iseq = (mrb_code*)src; - src += sizeof(mrb_code) * irep->ilen; irep->flags |= MRB_ISEQ_NO_FREE; } else { - size_t data_len = sizeof(mrb_code) * irep->ilen; void *buf = mrb_malloc(mrb, data_len); irep->iseq = (mrb_code *)buf; memcpy(buf, src, data_len); - src += data_len; } + src += data_len; } /* POOL BLOCK */ |
