summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authortake_cheeze <[email protected]>2013-09-01 22:43:17 +0900
committertake_cheeze <[email protected]>2013-09-02 00:48:06 +0900
commit3d1fffbd6bce3a6f9a77af3116078574ce8d5fe9 (patch)
tree35d6c58a23442ca055671c3b9e34f736153bc4ec /src
parentbc131350d416409220fd3294d2ffcea3ae73027d (diff)
downloadmruby-3d1fffbd6bce3a6f9a77af3116078574ce8d5fe9.tar.gz
mruby-3d1fffbd6bce3a6f9a77af3116078574ce8d5fe9.zip
support multiple filename in irep
Diffstat (limited to 'src')
-rw-r--r--src/backtrace.c30
-rw-r--r--src/codegen.c36
-rw-r--r--src/debug.c192
-rw-r--r--src/dump.c221
-rw-r--r--src/error.c9
-rw-r--r--src/load.c114
-rw-r--r--src/parse.y8
-rw-r--r--src/state.c3
8 files changed, 574 insertions, 39 deletions
diff --git a/src/backtrace.c b/src/backtrace.c
index d7881dce1..a1c35d09f 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -10,6 +10,7 @@
#include "mruby/array.h"
#include "mruby/string.h"
#include "mruby/class.h"
+#include "mruby/debug.h"
#include <stdarg.h>
typedef void (*output_stream_func)(mrb_state*, void*, int, const char*, ...);
@@ -70,7 +71,7 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun
for (i = ciidx; i >= 0; i--) {
ci = &mrb->c->cibase[i];
- filename = "(unknown)";
+ filename = NULL;
line = -1;
if (!verbose && MRB_PROC_CFUNC_P(ci->proc)) {
@@ -78,21 +79,16 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun
}
if(!MRB_PROC_CFUNC_P(ci->proc)) {
mrb_irep *irep = ci->proc->body.irep;
- if (irep->filename != NULL)
- filename = irep->filename;
- if (irep->lines != NULL) {
- mrb_code *pc;
-
- if (i+1 <= ciidx) {
- pc = mrb->c->cibase[i+1].pc;
- }
- else {
- pc = (mrb_code*)mrb_voidp(mrb_obj_iv_get(mrb, exc, mrb_intern2(mrb, "lastpc", 6)));
- }
- if (irep->iseq <= pc && pc < irep->iseq + irep->ilen) {
- line = irep->lines[pc - irep->iseq - 1];
- }
+ mrb_code *pc;
+
+ if (i+1 <= ciidx) {
+ pc = mrb->c->cibase[i+1].pc;
+ }
+ else {
+ pc = (mrb_code*)mrb_voidp(mrb_obj_iv_get(mrb, exc, mrb_intern2(mrb, "lastpc", 6)));
}
+ filename = mrb_get_filename(irep, pc - irep->iseq - 1);
+ line = mrb_get_line(irep, pc - irep->iseq - 1);
}
if (!verbose && line == -1) continue;
if (ci->target_class == ci->proc->target_class)
@@ -100,6 +96,10 @@ mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func fun
else
sep = "#";
+ if (!filename) {
+ filename = "(unknown)";
+ }
+
method = mrb_sym2name(mrb, ci->mid);
if (verbose && !method && ci->proc->env) {
method = mrb_sym2name(mrb, ci->proc->env->mid);
diff --git a/src/codegen.c b/src/codegen.c
index 50916a473..5ba5e4f03 100644
--- a/src/codegen.c
+++ b/src/codegen.c
@@ -12,6 +12,7 @@
#include "mruby/irep.h"
#include "mruby/numeric.h"
#include "mruby/string.h"
+#include "mruby/debug.h"
#include "node.h"
#include "opcode.h"
#include "re.h"
@@ -51,7 +52,7 @@ typedef struct scope {
struct loopinfo *loop;
int ensure_level;
- char *filename;
+ char const *filename;
short lineno;
mrb_code *iseq;
@@ -67,6 +68,8 @@ typedef struct scope {
int ai;
int idx;
+
+ int debug_start_pos;
} codegen_scope;
static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv);
@@ -142,6 +145,7 @@ genop(codegen_scope *s, mrb_code i)
s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa);
if (s->lines) {
s->lines = (short*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa);
+ s->irep->lines = s->lines;
}
}
s->iseq[s->pc] = i;
@@ -1107,6 +1111,17 @@ codegen(codegen_scope *s, node *tree, int val)
int nt;
if (!tree) return;
+
+ if (s->irep) {
+ if (s->pc > 0 && strcmp(s->filename, tree->filename) != 0) {
+ mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc);
+ s->debug_start_pos = s->pc;
+ // fprintf(stderr, "%s\n", s->filename);
+ }
+ s->irep->filename = tree->filename;
+ s->filename = tree->filename;
+ }
+
nt = (intptr_t)tree->car;
s->lineno = tree->lineno;
tree = tree->cdr;
@@ -2395,6 +2410,18 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
p->lines = (short*)mrb_malloc(mrb, sizeof(short)*p->icapa);
}
p->lineno = prev->lineno;
+
+ // debug setting
+ p->debug_start_pos = 0;
+ if(p->filename) {
+ mrb_debug_info_alloc(mrb, p->irep);
+ p->irep->filename = p->filename;
+ p->irep->lines = p->lines;
+ }
+ else {
+ p->irep->debug_info = NULL;
+ }
+
return p;
}
@@ -2420,6 +2447,8 @@ scope_finish(codegen_scope *s)
irep->pool = (mrb_value *)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen);
irep->syms = (mrb_sym *)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen);
if (s->filename) {
+ mrb_debug_info_append_file(mrb, s->irep, s->debug_start_pos, s->pc);
+
fname_len = strlen(s->filename);
fname = codegen_malloc(s, fname_len + 1);
memcpy(fname, s->filename, fname_len);
@@ -2831,7 +2860,6 @@ codedump_all(mrb_state *mrb, int start)
codedump(mrb, i);
}
}
-
static int
codegen_start(mrb_state *mrb, parser_state *p)
{
@@ -2841,9 +2869,7 @@ codegen_start(mrb_state *mrb, parser_state *p)
return -1;
}
scope->mrb = mrb;
- if (p->filename) {
- scope->filename = p->filename;
- }
+ scope->filename = p->filename;
if (setjmp(scope->jmp) == 0) {
// prepare irep
codegen(scope, p->tree, NOVAL);
diff --git a/src/debug.c b/src/debug.c
new file mode 100644
index 000000000..637d39bcc
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,192 @@
+#include "mruby/debug.h"
+
+#include "mruby.h"
+#include "mruby/irep.h"
+
+#include <string.h>
+
+static mrb_irep_debug_info_file*
+get_file(mrb_irep_debug_info* info, uint32_t const pc)
+{
+ if(pc >= info->pc_count) { return NULL; }
+
+ // get upper bound
+ mrb_irep_debug_info_file** ret = info->files;
+ int32_t count = info->flen;
+ while (count > 0) {
+ int32_t const step = count / 2;
+ mrb_irep_debug_info_file** const it = ret + step;
+ if (!(pc < (*it)->start_pos)) {
+ ret = it + 1;
+ count -= step + 1;
+ } else { count = step; }
+ }
+
+ --ret;
+
+ mrb_assert(ret < (info->files + info->flen));
+ mrb_assert((*ret)->start_pos <= pc &&
+ pc < (((ret + 1 - info->files) < info->flen)
+ ? (*(ret+1))->start_pos : info->pc_count));
+
+ return *ret;
+}
+
+static mrb_debug_line_type
+select_line_type(uint32_t pc_count, uint16_t line_count)
+{
+ return (sizeof(uint16_t) * pc_count) < (sizeof(mrb_irep_debug_info_line) * line_count)
+ ? mrb_debug_line_ary : mrb_debug_line_flat_map;
+}
+
+char const*
+mrb_get_filename(mrb_irep* irep, uint32_t pc)
+{
+ mrb_irep_debug_info_file* f = NULL;
+ if (irep) {
+ if (!irep->debug_info) { return irep->filename; }
+ else if ((f = get_file(irep->debug_info, pc))) {
+ return f->filename;
+ }
+ }
+ return NULL;
+}
+
+int32_t
+mrb_get_line(mrb_irep* irep, uint32_t const pc)
+{
+ mrb_irep_debug_info_file* f = NULL;
+ if (irep) {
+ if (!irep->debug_info) {
+ return irep->lines? irep->lines[pc] : -1;
+ }
+ else if ((f = get_file(irep->debug_info, pc))) {
+ switch(f->line_type) {
+ case mrb_debug_line_ary:
+ mrb_assert(pc < (f->start_pos + f->line_entry_count));
+ return f->line_ary[pc];
+
+ case mrb_debug_line_flat_map: {
+ // get upper bound
+ mrb_irep_debug_info_line* ret = f->line_flat_map;
+ int32_t count = f->line_entry_count;
+ while (count > 0) {
+ int32_t const step = count / 2;
+ mrb_irep_debug_info_line* const it = ret + step;
+ if (!(pc < it->start_pos)) {
+ ret = it + 1;
+ count -= step + 1;
+ } else { count = step; }
+ }
+
+ --ret;
+
+ mrb_assert((ret - f->line_flat_map) < f->line_entry_count);
+ mrb_assert(ret->start_pos <= pc &&
+ pc < (((ret + 1 - f->line_flat_map) < f->line_entry_count)
+ ? (ret+1)->start_pos : irep->debug_info->pc_count));
+
+ return ret->line;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+mrb_irep_debug_info*
+mrb_debug_info_alloc(mrb_state* mrb, mrb_irep* irep)
+{
+ static mrb_irep_debug_info const initial = { 0, 0, NULL };
+ mrb_assert(!irep->debug_info);
+
+ mrb_irep_debug_info* const ret = (mrb_irep_debug_info*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info));
+ *ret = initial;
+ irep->debug_info = ret;
+ return ret;
+}
+
+mrb_irep_debug_info_file*
+mrb_debug_info_append_file(mrb_state* mrb, mrb_irep* irep,
+ uint32_t const start_pos, uint32_t const end_pos)
+{
+ if (!irep->debug_info) { return NULL; }
+
+ mrb_assert(irep->filename);
+ mrb_assert(irep->lines);
+
+ mrb_irep_debug_info* info = irep->debug_info;
+
+ if (info->flen > 0 && strcmp(irep->filename, info->files[info->flen - 1]->filename) == 0) {
+ return NULL;
+ }
+
+ mrb_irep_debug_info_file* const ret =
+ (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file));
+ info->files =
+ (mrb_irep_debug_info_file*)info->files
+ ? mrb_realloc(mrb, info->files, sizeof(mrb_irep_debug_info_file*) * (info->flen + 1))
+ : mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file*));
+ info->files[info->flen++] = ret;
+
+ uint32_t const file_pc_count = end_pos - start_pos;
+
+ ret->start_pos = start_pos;
+ info->pc_count = end_pos;
+
+ size_t const fn_len = strlen(irep->filename);
+ ret->filename_sym = mrb_intern2(mrb, irep->filename, fn_len);
+ size_t len = 0;
+ ret->filename = mrb_sym2name_len(mrb, ret->filename_sym, &len);
+
+ ret->line_type = select_line_type(
+ file_pc_count, irep->lines[end_pos - 1] - irep->lines[0] + 1);
+ ret->line_ptr = NULL;
+
+ switch(ret->line_type) {
+ case mrb_debug_line_ary:
+ ret->line_entry_count = file_pc_count;
+ ret->line_ary = mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count);
+ for(uint32_t i = 0; i < file_pc_count; ++i) {
+ ret->line_ary[i] = irep->lines[start_pos + i];
+ }
+ break;
+
+ case mrb_debug_line_flat_map: {
+ ret->line_flat_map = mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1);
+ ret->line_entry_count = 0;
+ uint16_t prev_line = 0;
+ for(uint32_t i = 0; i < file_pc_count; ++i) {
+ if(irep->lines[start_pos + i] == prev_line) { continue; }
+
+ ret->line_flat_map = mrb_realloc(
+ mrb, ret->line_flat_map,
+ sizeof(mrb_irep_debug_info_line) * (ret->line_entry_count + 1));
+ mrb_irep_debug_info_line const m = { start_pos + i, irep->lines[start_pos + i] };
+ ret->line_flat_map[ret->line_entry_count] = m;
+
+ // update
+ ++ret->line_entry_count;
+ prev_line = irep->lines[start_pos + i];
+ }
+ } break;
+
+ default: mrb_assert(0); break;
+ }
+
+ return ret;
+}
+
+void
+mrb_debug_info_free(mrb_state* mrb, mrb_irep_debug_info* d)
+{
+ if(!d) { return; }
+
+ for(uint32_t i = 0; i < d->flen; ++i) {
+ mrb_assert(d->files[i]);
+ mrb_free(mrb, d->files[i]->line_ptr);
+ mrb_free(mrb, d->files[i]);
+ }
+ mrb_free(mrb, d->files);
+ mrb_free(mrb, d);
+}
diff --git a/src/dump.c b/src/dump.c
index 72ca9e0c3..92b1b011a 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -11,6 +11,8 @@
#include "mruby/string.h"
#include "mruby/irep.h"
#include "mruby/numeric.h"
+#include "mruby/debug.h"
+#include "mruby/array.h"
static size_t get_irep_record_size(mrb_state *mrb, mrb_irep *irep);
@@ -257,7 +259,7 @@ mrb_write_eof(mrb_state *mrb, uint8_t *bin)
static int
mrb_write_section_irep_header(mrb_state *mrb, uint32_t section_size, uint16_t nirep, uint16_t sirep, uint8_t *bin)
-{
+{
struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin;
memcpy(header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(header->section_identify));
@@ -300,7 +302,7 @@ mrb_write_section_irep(mrb_state *mrb, size_t start_index, uint8_t *bin)
static int
mrb_write_section_lineno_header(mrb_state *mrb, uint32_t section_size, uint16_t nirep, uint16_t sirep, uint8_t *bin)
-{
+{
struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin;
// TODO
@@ -313,7 +315,7 @@ mrb_write_section_lineno_header(mrb_state *mrb, uint32_t section_size, uint16_t
}
static size_t
-get_debug_record_size(mrb_state *mrb, mrb_irep *irep)
+get_lineno_record_size(mrb_state *mrb, mrb_irep *irep)
{
size_t size = 0;
@@ -388,9 +390,152 @@ mrb_write_section_lineno(mrb_state *mrb, size_t start_index, uint8_t *bin)
return MRB_DUMP_OK;
}
+static size_t
+get_debug_record_size(mrb_state* mrb, mrb_irep *irep) {
+ (void)mrb;
+ size_t ret = 0;
+
+ ret += sizeof(uint32_t); // record size
+ ret += sizeof(uint16_t); // file count
+
+ for(uint32_t f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ mrb_irep_debug_info_file const* file = irep->debug_info->files[f_idx];
+
+ ret += sizeof(uint32_t); // position
+ ret += sizeof(uint16_t); // filename index
+
+ // lines
+ ret += sizeof(uint32_t); // entry count
+ ret += sizeof(uint8_t); // line type
+ switch(file->line_type) {
+ case mrb_debug_line_ary:
+ ret += sizeof(uint16_t) * file->line_entry_count;
+ break;
+
+ case mrb_debug_line_flat_map:
+ ret += (sizeof(uint32_t) + sizeof(uint16_t)) * file->line_entry_count;
+ break;
+
+ default: mrb_assert(0); break;
+ }
+ }
+
+ return ret;
+}
+
+static int
+find_filename_index(mrb_value const ary, mrb_sym s) {
+ for(mrb_int i = 0; i < RARRAY_LEN(ary); ++i) {
+ mrb_assert(mrb_symbol_p(RARRAY_PTR(ary)[i]));
+ if(mrb_symbol(RARRAY_PTR(ary)[i]) == s) { return i; }
+ }
+ return -1;
+}
+
+static int
+write_debug_record(mrb_state* mrb, mrb_irep *irep, uint8_t * const bin, mrb_value filenames)
+{
+ uint8_t *cur = bin + sizeof(uint32_t); // skip record size
+
+ cur += uint16_to_bin(irep->debug_info->flen, cur); // file count
+ for(uint32_t f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ mrb_irep_debug_info_file const* file = irep->debug_info->files[f_idx];
+
+ // position
+ cur += uint32_to_bin(file->start_pos, cur);
+
+ // filename index
+ int const filename_idx = find_filename_index(filenames, file->filename_sym);
+ mrb_assert(filename_idx != -1);
+ cur += uint16_to_bin(filename_idx, cur);
+
+ // lines
+ cur += uint32_to_bin(file->line_entry_count, cur);
+ cur += uint8_to_bin(file->line_type, cur);
+ switch(file->line_type) {
+ case mrb_debug_line_ary: {
+ for(size_t l = 0; l < file->line_entry_count; ++l) {
+ cur += uint16_to_bin(file->line_ary[l], cur);
+ }
+ } break;
+
+ case mrb_debug_line_flat_map:
+ for(uint32_t line = 0; line < file->line_entry_count; ++line) {
+ cur += uint32_to_bin(file->line_flat_map[line].start_pos, cur);
+ cur += uint16_to_bin(file->line_flat_map[line].line, cur);
+ }
+ break;
+
+ default: mrb_assert(0); break;
+ }
+ }
+
+ size_t const ret = cur - bin;
+ uint32_to_bin(ret, bin);
+
+ mrb_assert((cur - bin) == (int)get_debug_record_size(mrb, irep));
+
+ return ret;
+}
+
+static int
+mrb_write_section_debug(mrb_state* mrb, size_t start_index, uint8_t *cur)
+{
+ uint32_t section_size = 0;
+ uint8_t* const bin = cur;
+
+ if (mrb == NULL || start_index >= mrb->irep_len || cur == NULL) {
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+
+ struct rite_section_debug_header* header = (struct rite_section_debug_header*)bin;
+ cur += sizeof(struct rite_section_debug_header);
+ section_size += sizeof(struct rite_section_debug_header);
+
+ // filename table
+ mrb_value const filenames = mrb_ary_new(mrb);
+ uint8_t* const filenames_len = cur;
+ cur += sizeof(uint16_t);
+ section_size += sizeof(uint16_t);
+ for (size_t irep_i = start_index; irep_i < mrb->irep_len; ++irep_i) {
+ mrb_irep_debug_info const* debug_info = mrb->irep[irep_i]->debug_info;
+
+ for(size_t file_i = 0; file_i < debug_info->flen; ++file_i) {
+ mrb_irep_debug_info_file const* file = debug_info->files[file_i];
+ if(find_filename_index(filenames, file->filename_sym) != -1) continue;
+
+ // register filename
+ mrb_ary_push(mrb, filenames, mrb_symbol_value(file->filename_sym));
+
+ // filename
+ uint16_t const fn_len = strlen(file->filename);
+ cur += uint16_to_bin(fn_len, cur);
+ memcpy(cur, file->filename, fn_len);
+ cur += fn_len;
+
+ section_size += sizeof(uint16_t) + fn_len;
+ }
+ }
+ uint16_to_bin(RARRAY_LEN(filenames), filenames_len);
+
+ // records
+ for (size_t i = start_index; i < mrb->irep_len; ++i) {
+ uint32_t rlen = write_debug_record(mrb, mrb->irep[i], cur, filenames);
+ cur += rlen;
+ section_size += rlen;
+ }
+
+ memcpy(header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(header->section_identify));
+ uint32_to_bin(section_size, header->section_size);
+ uint16_to_bin(mrb->irep_len - start_index, header->nirep);
+ uint16_to_bin(start_index, header->sirep);
+
+ return MRB_DUMP_OK;
+}
+
static int
write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t* bin)
-{
+{
struct rite_binary_header *header = (struct rite_binary_header*)bin;
uint16_t crc;
size_t offset;
@@ -400,7 +545,7 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t* bin)
memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name));
memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version));
uint32_to_bin(binary_size, header->binary_size);
-
+
offset = (&(header->binary_crc[0]) - bin) + sizeof(uint16_t);
crc = calc_crc_16_ccitt(bin + offset, binary_size - offset, 0);
uint16_to_bin(crc, header->binary_crc);
@@ -408,6 +553,13 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t* bin)
return MRB_DUMP_OK;
}
+mrb_bool is_debug_info_defined(mrb_state* mrb, size_t const start_index) {
+ for (size_t i = start_index; i < mrb->irep_len; ++i) {
+ if (!mrb->irep[i]->debug_info) { return 0; }
+ }
+ return 1;
+}
+
static int
mrb_dump_irep(mrb_state *mrb, size_t start_index, int debug_info, uint8_t **bin, size_t *bin_size)
{
@@ -418,6 +570,8 @@ mrb_dump_irep(mrb_state *mrb, size_t start_index, int debug_info, uint8_t **bin,
size_t irep_no;
uint8_t *cur = NULL;
+ mrb_bool const debug_info_defined = is_debug_info_defined(mrb, start_index);
+
if (mrb == NULL || start_index >= mrb->irep_len) {
*bin = NULL;
return MRB_DUMP_GENERAL_FAILURE;
@@ -431,11 +585,39 @@ mrb_dump_irep(mrb_state *mrb, size_t start_index, int debug_info, uint8_t **bin,
/* DEBUG section size */
if (debug_info) {
- section_lineno_size += sizeof(struct rite_section_lineno_header);
- for (irep_no = start_index; irep_no < mrb->irep_len; irep_no++) {
- section_lineno_size += get_debug_record_size(mrb, mrb->irep[irep_no]);
+ if (debug_info_defined) {
+ section_lineno_size += sizeof(struct rite_section_debug_header);
+
+ // filename table
+ mrb_value const filenames = mrb_ary_new(mrb);
+ // filename table size
+ section_lineno_size += sizeof(uint16_t);
+ for (size_t irep_i = start_index; irep_i < mrb->irep_len; ++irep_i) {
+ mrb_irep_debug_info const* di = mrb->irep[irep_i]->debug_info;
+
+ for(size_t file_i = 0; file_i < di->flen; ++file_i) {
+ mrb_irep_debug_info_file const* file = di->files[file_i];
+ if(find_filename_index(filenames, file->filename_sym) != -1) continue;
+
+ // register filename
+ mrb_ary_push(mrb, filenames, mrb_symbol_value(file->filename_sym));
+ // filename
+ section_lineno_size += sizeof(uint16_t) + strlen(file->filename);
+ }
+ }
+
+ for(irep_no = start_index; irep_no < mrb->irep_len; ++irep_no) {
+ section_lineno_size += get_debug_record_size(mrb, mrb->irep[irep_no]);
+ }
+ section_size += section_lineno_size;
+ }
+ else {
+ section_lineno_size += sizeof(struct rite_section_lineno_header);
+ for (irep_no = start_index; irep_no < mrb->irep_len; irep_no++) {
+ section_lineno_size += get_lineno_record_size(mrb, mrb->irep[irep_no]);
+ }
+ section_size += section_lineno_size;
}
- section_size += section_lineno_size;
}
*bin_size += sizeof(struct rite_binary_header) + section_size + sizeof(struct rite_binary_footer);
@@ -450,16 +632,25 @@ mrb_dump_irep(mrb_state *mrb, size_t start_index, int debug_info, uint8_t **bin,
if (result != MRB_DUMP_OK) {
goto error_exit;
}
-
+
cur += section_irep_size;
-
+
/* write DEBUG section */
if (debug_info) {
- result = mrb_write_section_lineno(mrb, start_index, cur);
- if (result != MRB_DUMP_OK) {
- goto error_exit;
+ if(debug_info_defined) {
+ result = mrb_write_section_debug(mrb, start_index, cur);
+ if(result != MRB_DUMP_OK) {
+ goto error_exit;
+ }
+ cur += section_lineno_size;
+ }
+ else {
+ result = mrb_write_section_lineno(mrb, start_index, cur);
+ if (result != MRB_DUMP_OK) {
+ goto error_exit;
+ }
+ cur += section_lineno_size;
}
- cur += section_lineno_size;
}
mrb_write_eof(mrb, cur);
diff --git a/src/error.c b/src/error.c
index f7d41c2e2..4b5eab397 100644
--- a/src/error.c
+++ b/src/error.c
@@ -15,6 +15,7 @@
#include "mruby/proc.h"
#include "mruby/string.h"
#include "mruby/variable.h"
+#include "mruby/debug.h"
#include "error.h"
mrb_value
@@ -198,9 +199,11 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc)
if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
mrb_irep *irep = ci->proc->body.irep;
- if (irep->filename && irep->lines && irep->iseq <= pc && pc < irep->iseq + irep->ilen) {
- mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "file", 4), mrb_str_new_cstr(mrb, irep->filename));
- mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "line", 4), mrb_fixnum_value(irep->lines[pc - irep->iseq - 1]));
+ int32_t const line = mrb_get_line(irep, pc - irep->iseq - 1);
+ char const* file = mrb_get_filename(irep, pc - irep->iseq - 1);
+ if(line != -1 && file) {
+ mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "file", 4), mrb_str_new_cstr(mrb, file));
+ mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "line", 4), mrb_fixnum_value(line));
return;
}
}
diff --git a/src/load.c b/src/load.c
index 092ddbde8..3bdf39e73 100644
--- a/src/load.c
+++ b/src/load.c
@@ -16,6 +16,8 @@
#include "mruby/irep.h"
#include "mruby/proc.h"
#include "mruby/string.h"
+#include "mruby/debug.h"
+#include "mruby/array.h"
#if !defined(_WIN32) && SIZE_MAX < UINT32_MAX
# define SIZE_ERROR_MUL(x, y) ((x) > SIZE_MAX / (y))
@@ -299,6 +301,97 @@ error_exit:
return result;
}
+static int read_rite_debug_record(mrb_state* mrb, uint8_t const *start, size_t irepno, uint32_t *len, mrb_value const filenames) {
+ uint8_t const* bin = start;
+
+ mrb_irep* const irep = mrb->irep[irepno];
+
+ if(irep->debug_info) { return MRB_DUMP_INVALID_IREP; }
+
+ irep->debug_info = (mrb_irep_debug_info*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info));
+ irep->debug_info->pc_count = irep->ilen;
+
+ size_t const record_size = bin_to_uint32(bin); bin += sizeof(uint32_t);
+
+ irep->debug_info->flen = bin_to_uint16(bin);
+ irep->debug_info->files = (mrb_irep_debug_info_file**)mrb_malloc(mrb, sizeof(mrb_irep_debug_info*) * irep->debug_info->flen);
+ bin += sizeof(uint16_t);
+
+ for (uint16_t f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
+ mrb_irep_debug_info_file* const file = (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file));
+ irep->debug_info->files[f_idx] = file;
+
+ file->start_pos = bin_to_uint32(bin); bin += sizeof(uint32_t);
+
+ // filename
+ file->filename_sym = mrb_symbol(RARRAY_PTR(filenames)[bin_to_uint16(bin)]);
+ size_t len = 0;
+ file->filename = mrb_sym2name_len(mrb, file->filename_sym, &len);
+ bin += sizeof(uint16_t);
+
+ file->line_entry_count = bin_to_uint32(bin); bin += sizeof(uint32_t);
+ file->line_type = bin_to_uint8(bin); bin += sizeof(uint8_t);
+ switch(file->line_type) {
+ case mrb_debug_line_ary:
+ file->line_ary = mrb_malloc(mrb, sizeof(uint16_t) * file->line_entry_count);
+ for(size_t l = 0; l < file->line_entry_count; ++l) {
+ file->line_ary[l] = bin_to_uint16(bin); bin += sizeof(uint16_t);
+ }
+ break;
+
+ case mrb_debug_line_flat_map:
+ file->line_flat_map = mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * file->line_entry_count);
+ for(size_t l = 0; l < file->line_entry_count; ++l) {
+ file->line_flat_map[l].start_pos = bin_to_uint32(bin); bin += sizeof(uint32_t);
+ file->line_flat_map[l].line = bin_to_uint16(bin); bin += sizeof(uint16_t);
+ }
+ break;
+
+ default: return MRB_DUMP_GENERAL_FAILURE;
+ }
+ }
+
+ if((long)record_size != (bin - start)) {
+ return MRB_DUMP_GENERAL_FAILURE;
+ }
+
+ *len = bin - start;
+
+ return MRB_DUMP_OK;
+}
+
+static int
+read_rite_section_debug(mrb_state* mrb, const uint8_t* start, size_t sirep)
+{
+ uint8_t const* bin = start;
+ struct rite_section_debug_header const* header = (struct rite_section_debug_header const*)bin;
+ bin += sizeof(struct rite_section_debug_header);
+
+ uint16_t const nirep = bin_to_uint16(header->nirep);
+
+ uint16_t const filenames_len = bin_to_uint16(bin);
+ mrb_value const filenames = mrb_ary_new_capa(mrb, filenames_len);
+ bin += sizeof(uint16_t);
+ for(uint16_t i = 0; i < filenames_len; ++i) {
+ uint16_t const f_len = bin_to_uint16(bin);
+ bin += sizeof(uint16_t);
+ mrb_ary_push(mrb, filenames, mrb_symbol_value(mrb_intern2(mrb, (char const*)bin, f_len)));
+ bin += f_len;
+ }
+
+ for(uint16_t i = sirep; i < (sirep + nirep); ++i) {
+ uint32_t len = 0;
+ int result = read_rite_debug_record(mrb, bin, i, &len, filenames);
+ if (result != MRB_DUMP_OK) { return result; }
+ bin += len;
+ }
+
+ if ((bin - start) != bin_to_uint32(header->section_size)) {
+ return MRB_DUMP_GENERAL_FAILURE;
+ }
+
+ return sirep + bin_to_uint16(header->sirep);
+}
static int
read_rite_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc)
@@ -364,6 +457,12 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
return result;
}
}
+ else if (memcmp(section_header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(section_header->section_identify)) == 0) {
+ result = read_rite_section_debug(mrb, bin, sirep);
+ if (result < MRB_DUMP_OK) {
+ return result;
+ }
+ }
bin += bin_to_uint32(section_header->section_size);
} while (memcmp(section_header->section_identify, RITE_BINARY_EOF, sizeof(section_header->section_identify)) != 0);
@@ -566,7 +665,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp)
/* You don't need use SIZE_ERROR as block_size is enough small. */
for (i = 0; i < block_fallback_count; i++,block_size >>= 1){
buf = mrb_malloc_simple(mrb, block_size);
- if (buf) break;
+ if (buf) break;
}
if (!buf) {
return MRB_DUMP_GENERAL_FAILURE;
@@ -608,6 +707,19 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp)
return result;
}
}
+ else if (memcmp(section_header.section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(section_header.section_identify)) == 0) {
+ uint8_t* const bin = mrb_malloc(mrb, section_size);
+ fseek(fp, fpos, SEEK_SET);
+ if(fread((char*)bin, section_size, 1, fp) != section_size) {
+ mrb_free(mrb, bin);
+ return MRB_DUMP_READ_FAULT;
+ }
+ result = read_rite_section_debug(mrb, bin, sirep);
+ mrb_free(mrb, bin);
+ if (result < MRB_DUMP_OK) {
+ return result;
+ }
+ }
fseek(fp, fpos + section_size, SEEK_SET);
} while (memcmp(section_header.section_identify, RITE_BINARY_EOF, sizeof(section_header.section_identify)) != 0);
diff --git a/src/parse.y b/src/parse.y
index bbad88949..9ebcd5d98 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -120,6 +120,7 @@ cons_gen(parser_state *p, node *car, node *cdr)
c->car = car;
c->cdr = cdr;
c->lineno = p->lineno;
+ c->filename = p->filename;
return c;
}
#define cons(a,b) cons_gen(p,(a),(b))
@@ -5179,6 +5180,13 @@ mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*func)(struct mrb_parser
c->partial_data = data;
}
+void
+mrb_parser_set_filename(struct mrb_parser_state* p, char const* f)
+{
+ p->filename = mrbc_filename(p->mrb, p->cxt, f);
+ p->lineno = 1;
+}
+
#ifdef ENABLE_STDIO
parser_state*
mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c)
diff --git a/src/state.c b/src/state.c
index 5dcc4a40a..9a9f07787 100644
--- a/src/state.c
+++ b/src/state.c
@@ -10,6 +10,7 @@
#include "mruby/class.h"
#include "mruby/irep.h"
#include "mruby/variable.h"
+#include "mruby/debug.h"
void mrb_init_heap(mrb_state*);
void mrb_init_core(mrb_state*);
@@ -115,6 +116,8 @@ mrb_irep_free(mrb_state *mrb, struct mrb_irep *irep)
mrb_free(mrb, (void *)irep->filename);
mrb_free(mrb, irep->lines);
mrb_free(mrb, irep);
+
+ mrb_debug_info_free(mrb, irep->debug_info);
}
void