mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
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.
This commit is contained in:
committed by
Yukihiro "Matz" Matsumoto
parent
3ad6bbc40c
commit
a54a3df32c
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+32
@@ -273,6 +273,31 @@ write_syms_block(mrb_state *mrb, const mrb_irep *irep, uint8_t *buf)
|
||||
return cur - 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)
|
||||
{
|
||||
@@ -280,6 +305,7 @@ get_irep_record_size_1(mrb_state *mrb, const mrb_irep *irep)
|
||||
|
||||
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);
|
||||
|
||||
|
||||
+7
-4
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user