VALUE
rb_iseq_disasm(VALUE self)
{
rb_iseq_t *iseqdat = iseq_check(self); /* TODO: rename to iseq */
VALUE *iseq;
VALUE str = rb_str_new(0, 0);
VALUE child = rb_ary_new();
unsigned int size;
int i;
long l;
ID *tbl;
size_t n;
enum {header_minlen = 72};
rb_secure(1);
size = iseqdat->iseq_size;
rb_str_cat2(str, "== disasm: ");
rb_str_concat(str, iseq_inspect(iseqdat->self));
if ((l = RSTRING_LEN(str)) < header_minlen) {
rb_str_resize(str, header_minlen);
memset(RSTRING_PTR(str) + l, '=', header_minlen - l);
}
rb_str_cat2(str, "\n");
/* show catch table information */
if (iseqdat->catch_table) {
rb_str_cat2(str, "== catch table\n");
}
if (iseqdat->catch_table) for (i = 0; i < iseqdat->catch_table->size; i++) {
struct iseq_catch_table_entry *entry = &iseqdat->catch_table->entries[i];
rb_str_catf(str,
"| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
catch_type((int)entry->type), (int)entry->start,
(int)entry->end, (int)entry->sp, (int)entry->cont);
if (entry->iseq) {
rb_str_concat(str, rb_iseq_disasm(entry->iseq));
}
}
if (iseqdat->catch_table) {
rb_str_cat2(str, "|-------------------------------------"
"-----------------------------------\n");
}
/* show local table information */
tbl = iseqdat->local_table;
if (tbl) {
rb_str_catf(str,
"local table (size: %d, argc: %d "
"[opts: %d, rest: %d, post: %d, block: %d, kw: %d@%d, kwrest: %d])\n",
iseqdat->local_size,
iseqdat->param.lead_num,
iseqdat->param.opt_num,
iseqdat->param.flags.has_rest ? iseqdat->param.rest_start : -1,
iseqdat->param.post_num,
iseqdat->param.flags.has_block ? iseqdat->param.block_start : -1,
iseqdat->param.flags.has_kw ? iseqdat->param.keyword->num : -1,
iseqdat->param.flags.has_kw ? iseqdat->param.keyword->required_num : -1,
iseqdat->param.flags.has_kwrest ? iseqdat->param.keyword->rest_start : -1);
for (i = 0; i < iseqdat->local_table_size; i++) {
long width;
VALUE name = id_to_name(tbl[i], 0);
char argi[0x100] = "";
char opti[0x100] = "";
if (iseqdat->param.flags.has_opt) {
int argc = iseqdat->param.lead_num;
int opts = iseqdat->param.opt_num;
if (i >= argc && i < argc + opts) {
snprintf(opti, sizeof(opti), "Opt=%"PRIdVALUE,
iseqdat->param.opt_table[i - argc]);
}
}
snprintf(argi, sizeof(argi), "%s%s%s%s%s", /* arg, opts, rest, post block */
iseqdat->param.lead_num > i ? "Arg" : "",
opti,
(iseqdat->param.flags.has_rest && iseqdat->param.rest_start == i) ? "Rest" : "",
(iseqdat->param.flags.has_post && iseqdat->param.post_start <= i && i < iseqdat->param.post_start + iseqdat->param.post_num) ? "Post" : "",
(iseqdat->param.flags.has_block && iseqdat->param.block_start == i) ? "Block" : "");
rb_str_catf(str, "[%2d] ", iseqdat->local_size - i);
width = RSTRING_LEN(str) + 11;
if (name)
rb_str_append(str, name);
else
rb_str_cat2(str, "?");
if (*argi) rb_str_catf(str, "<%s>", argi);
if ((width -= RSTRING_LEN(str)) > 0) rb_str_catf(str, "%*s", (int)width, "");
}
rb_str_cat2(str, "\n");
}
/* show each line */
iseq = rb_iseq_original_iseq(iseqdat);
for (n = 0; n < size;) {
n += rb_iseq_disasm_insn(str, iseq, n, iseqdat, child);
}
for (i = 0; i < RARRAY_LEN(child); i++) {
VALUE isv = rb_ary_entry(child, i);
rb_str_concat(str, rb_iseq_disasm(isv));
}
return str;
}