Unverified Commit a54a3df3 authored by dearblue's avatar dearblue Committed by Yukihiro "Matz" Matsumoto

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.
parent 3ad6bbc4
......@@ -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) {
......
......@@ -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);
......
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment