* [PATCH 1/2] compile.c (iseq_calc_param_size): hoist out of iseq_set_arguments
@ 2014-11-26 8:02 Eric Wong
2014-11-26 8:02 ` [PATCH 2/2] wip - rb_iseq_load fix v4 Eric Wong
0 siblings, 1 reply; 2+ messages in thread
From: Eric Wong @ 2014-11-26 8:02 UTC (permalink / raw)
To: spew
This will be reused for iseq loading.
---
compile.c | 70 ++++++++++++++++++++++++++++++++++-----------------------------
1 file changed, 38 insertions(+), 32 deletions(-)
diff --git a/compile.c b/compile.c
index 7a73ddf..5dc4787 100644
--- a/compile.c
+++ b/compile.c
@@ -1120,6 +1120,43 @@ get_dyna_var_idx(rb_iseq_t *iseq, ID id, int *level, int *ls)
return idx;
}
+static void
+iseq_calc_param_size(rb_iseq_t *iseq)
+{
+ if (iseq->param.flags.has_opt ||
+ iseq->param.flags.has_post ||
+ iseq->param.flags.has_rest ||
+ iseq->param.flags.has_block ||
+ iseq->param.flags.has_kw ||
+ iseq->param.flags.has_kwrest) {
+
+ if (iseq->param.flags.has_block) {
+ iseq->param.size = iseq->param.block_start + 1;
+ }
+ else if (iseq->param.flags.has_kwrest) {
+ iseq->param.size = iseq->param.keyword->rest_start + 1;
+ }
+ else if (iseq->param.flags.has_kw) {
+ iseq->param.size = iseq->param.keyword->bits_start + 1;
+ }
+ else if (iseq->param.flags.has_post) {
+ iseq->param.size = iseq->param.post_start + iseq->param.post_num;
+ }
+ else if (iseq->param.flags.has_rest) {
+ iseq->param.size = iseq->param.rest_start + 1;
+ }
+ else if (iseq->param.flags.has_opt) {
+ iseq->param.size = iseq->param.lead_num + iseq->param.opt_num;
+ }
+ else {
+ rb_bug("unreachable");
+ }
+ }
+ else {
+ iseq->param.size = iseq->param.lead_num;
+ }
+}
+
static int
iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
{
@@ -1267,38 +1304,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
iseq->param.flags.has_block = TRUE;
}
- if (iseq->param.flags.has_opt ||
- iseq->param.flags.has_post ||
- iseq->param.flags.has_rest ||
- iseq->param.flags.has_block ||
- iseq->param.flags.has_kw ||
- iseq->param.flags.has_kwrest) {
-
- if (iseq->param.flags.has_block) {
- iseq->param.size = iseq->param.block_start + 1;
- }
- else if (iseq->param.flags.has_kwrest) {
- iseq->param.size = iseq->param.keyword->rest_start + 1;
- }
- else if (iseq->param.flags.has_kw) {
- iseq->param.size = iseq->param.keyword->bits_start + 1;
- }
- else if (iseq->param.flags.has_post) {
- iseq->param.size = iseq->param.post_start + iseq->param.post_num;
- }
- else if (iseq->param.flags.has_rest) {
- iseq->param.size = iseq->param.rest_start + 1;
- }
- else if (iseq->param.flags.has_opt) {
- iseq->param.size = iseq->param.lead_num + iseq->param.opt_num;
- }
- else {
- rb_bug("unreachable");
- }
- }
- else {
- iseq->param.size = iseq->param.lead_num;
- }
+ iseq_calc_param_size(iseq);
if (iseq->type == ISEQ_TYPE_BLOCK) {
if (iseq->param.flags.has_opt == FALSE &&
--
EW
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH 2/2] wip - rb_iseq_load fix v4
2014-11-26 8:02 [PATCH 1/2] compile.c (iseq_calc_param_size): hoist out of iseq_set_arguments Eric Wong
@ 2014-11-26 8:02 ` Eric Wong
0 siblings, 0 replies; 2+ messages in thread
From: Eric Wong @ 2014-11-26 8:02 UTC (permalink / raw)
To: spew
---
compile.c | 218 +++++++++++++++++++++++++--------
ext/-test-/iseq_load/extconf.rb | 1 +
ext/-test-/iseq_load/iseq_load.c | 21 ++++
iseq.c | 61 ++++++---
iseq.h | 3 +-
test/-ext-/iseq_load/test_iseq_load.rb | 95 ++++++++++++++
6 files changed, 331 insertions(+), 68 deletions(-)
create mode 100644 ext/-test-/iseq_load/extconf.rb
create mode 100644 ext/-test-/iseq_load/iseq_load.c
create mode 100644 test/-ext-/iseq_load/test_iseq_load.rb
diff --git a/compile.c b/compile.c
index 5dc4787..8c32e1f 100644
--- a/compile.c
+++ b/compile.c
@@ -5734,7 +5734,7 @@ iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
lstart = register_label(iseq, labels_table, ptr[2]);
lend = register_label(iseq, labels_table, ptr[3]);
lcont = register_label(iseq, labels_table, ptr[4]);
- sp = NUM2INT(ptr[5]);
+ sp = NUM2UINT(ptr[5]);
(void)sp;
@@ -5790,14 +5790,25 @@ iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern("flag")));
VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern("orig_argc")));
VALUE vblock = rb_hash_aref(op, ID2SYM(rb_intern("blockptr")));
+ VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern("kw_arg")));
if (!NIL_P(vmid)) mid = SYM2ID(vmid);
if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
if (!NIL_P(vblock)) block = iseq_build_load_iseq(iseq, vblock);
- }
- /* TODO: support keywords */
+ if (!NIL_P(vkw_arg)) {
+ int i;
+ int len = RARRAY_LENINT(vkw_arg);
+ size_t n = sizeof(rb_call_info_kw_arg_t) + sizeof(ID) * (len - 1);
+
+ kw_arg = xmalloc(n);
+ kw_arg->keyword_len = len;
+ for (i = 0; i < len; i++) {
+ kw_arg->keywords[i] = SYM2ID(RARRAY_AREF(vkw_arg, i));
+ }
+ }
+ }
return (VALUE)new_callinfo(iseq, mid, orig_argc, block, flag, kw_arg);
}
@@ -5898,16 +5909,21 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
case TS_CDHASH:
{
int i;
+ VALUE map = rb_hash_new();
+
+ rb_hash_tbl_raw(map)->type = &cdhash_type;
op = rb_convert_type(op, T_ARRAY, "Array", "to_ary");
op = rb_ary_dup(op);
for (i=0; i<RARRAY_LEN(op); i+=2) {
- VALUE sym = rb_ary_entry(op, i+1);
+ VALUE key = RARRAY_AREF(op, i);
+ VALUE sym = RARRAY_AREF(op, i+1);
LABEL *label =
register_label(iseq, labels_table, sym);
- rb_ary_store(op, i+1, (VALUE)label | 1);
+ rb_hash_aset(map, key, (VALUE)label | 1);
}
- argv[j] = op;
- iseq_add_mark_object_compile_time(iseq, op);
+ RB_GC_GUARD(op);
+ argv[j] = map;
+ iseq_add_mark_object_compile_time(iseq, map);
}
break;
default:
@@ -5930,74 +5946,180 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
}
#define CHECK_ARRAY(v) rb_convert_type((v), T_ARRAY, "Array", "to_ary")
-#define CHECK_STRING(v) rb_convert_type((v), T_STRING, "String", "to_str")
#define CHECK_SYMBOL(v) rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
-static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
+
+static int
+int_param(int *dst, VALUE param, VALUE sym)
+{
+ VALUE val = rb_hash_aref(param, sym);
+ switch (TYPE(val)) {
+ case T_NIL:
+ return FALSE;
+ case T_FIXNUM:
+ *dst = FIX2INT(val);
+ return TRUE;
+ default:
+ rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
+ sym, val);
+ }
+ return FALSE;
+}
+
+static void
+iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
+{
+ int i, j;
+ int len = RARRAY_LENINT(keywords);
+ int default_len;
+ VALUE key, sym, default_val;
+
+ iseq->param.flags.has_kw = TRUE;
+
+ iseq->param.keyword = ZALLOC(struct rb_iseq_param_keyword);
+ iseq->param.keyword->num = len;
+#define SYM(s) ID2SYM(rb_intern(#s))
+ (void)int_param(&iseq->param.keyword->bits_start, params, SYM(kwbits));
+ i = iseq->param.keyword->bits_start - iseq->param.keyword->num;
+ iseq->param.keyword->table = &iseq->local_table[i];
+
+ if (int_param(&iseq->param.keyword->rest_start, params, SYM(kwrest))) {
+ iseq->param.flags.has_kwrest = TRUE;
+ }
+#undef SYM
+
+ /* required args */
+ for (i = 0; i < len; i++) {
+ VALUE val = RARRAY_AREF(keywords, i);
+
+ if (!SYMBOL_P(val)) {
+ goto default_values;
+ }
+ iseq->param.keyword->table[i] = SYM2ID(val);
+ iseq->param.keyword->required_num++;
+ }
+
+default_values: /* note: we intentionally preserve `i' from previous loop */
+ default_len = len - i;
+ if (default_len == 0) {
+ return;
+ }
+
+ iseq->param.keyword->default_values = ALLOC_N(VALUE, default_len);
+
+ for (j = 0; i < len; i++, j++) {
+ key = RARRAY_AREF(keywords, i);
+ CHECK_ARRAY(key);
+
+ switch (RARRAY_LEN(key)) {
+ case 1:
+ sym = RARRAY_AREF(key, 0);
+ default_val = Qundef;
+ break;
+ case 2:
+ sym = RARRAY_AREF(key, 0);
+ default_val = RARRAY_AREF(key, 1);
+ break;
+ default:
+ rb_raise(rb_eTypeError,
+ "keyword default has unsupported len %+"PRIsVALUE,
+ key);
+ }
+ iseq->param.keyword->table[i] = SYM2ID(sym);
+ iseq->param.keyword->default_values[j] = default_val;
+ }
+}
VALUE
-rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
+rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
VALUE exception, VALUE body)
{
- int i;
+#define SYM(s) ID2SYM(rb_intern(#s))
+ int i, len;
ID *tbl;
struct st_table *labels_table = st_init_numtable();
+ VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
+ VALUE keywords = rb_hash_aref(params, SYM(keyword));
+ VALUE sym_arg_rest = ID2SYM(rb_intern("#arg_rest"));
DECL_ANCHOR(anchor);
INIT_ANCHOR(anchor);
- iseq->local_table_size = RARRAY_LENINT(locals);
+ len = RARRAY_LENINT(locals);
+ iseq->local_table_size = len;
iseq->local_table = tbl = (ID *)ALLOC_N(ID, iseq->local_table_size);
iseq->local_size = iseq->local_table_size + 1;
- for (i=0; i<RARRAY_LEN(locals); i++) {
+ for (i = 0; i < len; i++) {
VALUE lv = RARRAY_AREF(locals, i);
- tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
- }
- /* args */
- if (FIXNUM_P(args)) {
- iseq->param.size = iseq->param.lead_num = FIX2INT(args);
- iseq->param.flags.has_lead = TRUE;
- }
- else {
- int i = 0;
- VALUE argc = CHECK_INTEGER(rb_ary_entry(args, i++));
- VALUE arg_opt_labels = CHECK_ARRAY(rb_ary_entry(args, i++));
- VALUE arg_post_num = CHECK_INTEGER(rb_ary_entry(args, i++));
- VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++));
- VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++));
- VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++));
-
- iseq->param.lead_num = FIX2INT(argc);
- iseq->param.rest_start = FIX2INT(arg_rest);
- iseq->param.post_num = FIX2INT(arg_post_num);
- iseq->param.post_start = FIX2INT(arg_post_start);
- iseq->param.block_start = FIX2INT(arg_block);
- iseq->param.opt_num = RARRAY_LENINT(arg_opt_labels) - 1;
- iseq->param.opt_table = (VALUE *)ALLOC_N(VALUE, iseq->param.opt_num + 1);
-
- if (iseq->param.flags.has_block) {
- iseq->param.size = iseq->param.block_start + 1;
- }
- else if (iseq->param.flags.has_post) {
- iseq->param.size = iseq->param.post_start + iseq->param.post_num;
- }
- else if (iseq->param.flags.has_rest) {
- iseq->param.size = iseq->param.rest_start + 1;
+ if (sym_arg_rest == lv) {
+ tbl[i] = 0;
}
else {
- iseq->param.size = iseq->param.lead_num + iseq->param.opt_num;
+ tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
}
+ }
+
+#define MISC_PARAM(D,F) do { \
+ if (!int_param(D, misc, SYM(F))) { \
+ rb_raise(rb_eTypeError, "misc field missing: %s", #F); \
+ } } while (0)
+ MISC_PARAM(&iseq->local_size, local_size);
+ /* iseq->stack_size and iseq->param.size are calculated */
+#undef MISC_PARAM
+
+#define INT_PARAM(F) int_param(&iseq->param.F, params, SYM(F))
+ if (INT_PARAM(lead_num)) iseq->param.flags.has_lead = TRUE;
+ if (INT_PARAM(post_num)) iseq->param.flags.has_post = TRUE;
+ if (INT_PARAM(post_start)) iseq->param.flags.has_post = TRUE;
+ if (INT_PARAM(rest_start)) iseq->param.flags.has_rest = TRUE;
+ if (INT_PARAM(block_start)) iseq->param.flags.has_block = TRUE;
+#undef INT_PARAM
+
+ switch (TYPE(arg_opt_labels)) {
+ case T_ARRAY:
+ len = RARRAY_LENINT(arg_opt_labels);
+ iseq->param.flags.has_opt = !!(len - 1 >= 0);
- for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) {
- iseq->param.opt_table[i] = (VALUE)register_label(iseq, labels_table, rb_ary_entry(arg_opt_labels, i));
+ if (iseq->param.flags.has_opt) {
+ iseq->param.opt_num = len - 1;
+ iseq->param.opt_table = (VALUE *)ALLOC_N(VALUE, len);
+
+ for (i = 0; i < len; i++) {
+ VALUE ent = RARRAY_AREF(arg_opt_labels, i);
+ LABEL *label = register_label(iseq, labels_table, ent);
+
+ iseq->param.opt_table[i] = (VALUE)label;
+ }
}
+ case T_NIL:
+ break;
+ default:
+ rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
+ arg_opt_labels);
+ }
+
+ switch (TYPE(keywords)) {
+ case T_ARRAY:
+ iseq_build_kw(iseq, params, keywords);
+ case T_NIL:
+ break;
+ default:
+ rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
+ keywords);
+ }
+
+ if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
+ iseq->param.flags.ambiguous_param0 = TRUE;
}
+#undef SYM
+ iseq_calc_param_size(iseq);
/* exception */
iseq_build_from_ary_exception(iseq, labels_table, exception);
/* body */
iseq_build_from_ary_body(iseq, anchor, body, labels_table);
+
return iseq->self;
}
diff --git a/ext/-test-/iseq_load/extconf.rb b/ext/-test-/iseq_load/extconf.rb
new file mode 100644
index 0000000..860f30b
--- /dev/null
+++ b/ext/-test-/iseq_load/extconf.rb
@@ -0,0 +1 @@
+create_makefile("-test-/iseq_load/iseq_load")
diff --git a/ext/-test-/iseq_load/iseq_load.c b/ext/-test-/iseq_load/iseq_load.c
new file mode 100644
index 0000000..ffdde34
--- /dev/null
+++ b/ext/-test-/iseq_load/iseq_load.c
@@ -0,0 +1,21 @@
+#include <ruby.h>
+
+VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt);
+
+static VALUE
+iseq_load(int argc, VALUE *argv, VALUE self)
+{
+ VALUE data, opt = Qnil;
+
+ rb_scan_args(argc, argv, "11", &data, &opt);
+
+ return rb_iseq_load(data, 0, opt);
+}
+
+void
+Init_iseq_load(void)
+{
+ VALUE rb_cISeq = rb_eval_string("RubyVM::InstructionSequence");
+
+ rb_define_singleton_method(rb_cISeq, "iseq_load", iseq_load, -1);
+}
diff --git a/iseq.c b/iseq.c
index dfe9874..48793ab 100644
--- a/iseq.c
+++ b/iseq.c
@@ -466,6 +466,7 @@ rb_iseq_new_with_bopt(NODE *node, VALUE name, VALUE path, VALUE absolute_path, V
}
#define CHECK_ARRAY(v) rb_convert_type((v), T_ARRAY, "Array", "to_ary")
+#define CHECK_HASH(v) rb_convert_type((v), T_HASH, "Hash", "to_hash")
#define CHECK_STRING(v) rb_convert_type((v), T_STRING, "String", "to_str")
#define CHECK_SYMBOL(v) rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
@@ -504,7 +505,7 @@ iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
VALUE magic, version1, version2, format_type, misc;
VALUE name, path, absolute_path, first_lineno;
- VALUE type, body, locals, args, exception;
+ VALUE type, body, locals, params, exception;
st_data_t iseq_type;
rb_iseq_t *iseq;
@@ -522,8 +523,8 @@ iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
version1 = CHECK_INTEGER(rb_ary_entry(data, i++));
version2 = CHECK_INTEGER(rb_ary_entry(data, i++));
format_type = CHECK_INTEGER(rb_ary_entry(data, i++));
- misc = rb_ary_entry(data, i++); /* TODO */
- ((void)magic, (void)version1, (void)version2, (void)format_type, (void)misc);
+ misc = CHECK_HASH(rb_ary_entry(data, i++));
+ ((void)magic, (void)version1, (void)version2, (void)format_type);
name = CHECK_STRING(rb_ary_entry(data, i++));
path = CHECK_STRING(rb_ary_entry(data, i++));
@@ -533,12 +534,7 @@ iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
type = CHECK_SYMBOL(rb_ary_entry(data, i++));
locals = CHECK_ARRAY(rb_ary_entry(data, i++));
-
- args = rb_ary_entry(data, i++);
- if (FIXNUM_P(args) || (args = CHECK_ARRAY(args))) {
- /* */
- }
-
+ params = CHECK_HASH(rb_ary_entry(data, i++));
exception = CHECK_ARRAY(rb_ary_entry(data, i++));
body = CHECK_ARRAY(rb_ary_entry(data, i++));
@@ -556,10 +552,11 @@ iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
}
make_compile_option(&option, opt);
+
prepare_iseq_build(iseq, name, path, absolute_path, first_lineno,
parent, (enum iseq_type)iseq_type, 0, &option);
- rb_iseq_build_from_ary(iseq, locals, args, exception, body);
+ rb_iseq_build_from_ary(iseq, misc, locals, params, exception, body);
cleanup_iseq_build(iseq);
return iseqval;
@@ -1726,16 +1723,21 @@ iseq_data_to_ary(rb_iseq_t *iseq)
/* params */
{
- VALUE arg_opt_labels = rb_ary_new();
int j;
- for (j=0; j < iseq->param.opt_num; j++) {
- rb_ary_push(arg_opt_labels, register_label(labels_table, iseq->param.opt_table[j]));
- }
+ if (iseq->param.flags.has_opt) {
+ int len = iseq->param.opt_num + 1;
+ VALUE arg_opt_labels = rb_ary_new2(len);
+
+ for (j = 0; j < len; j++) {
+ VALUE l = register_label(labels_table, iseq->param.opt_table[j]);
+ rb_ary_push(arg_opt_labels, l);
+ }
+ rb_hash_aset(params, ID2SYM(rb_intern("opt")), arg_opt_labels);
+ }
/* commit */
if (iseq->param.flags.has_lead) rb_hash_aset(params, ID2SYM(rb_intern("lead_num")), INT2FIX(iseq->param.lead_num));
- if (iseq->param.flags.has_opt) rb_hash_aset(params, ID2SYM(rb_intern("opt")), arg_opt_labels);
if (iseq->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_num")), INT2FIX(iseq->param.post_num));
if (iseq->param.flags.has_post) rb_hash_aset(params, ID2SYM(rb_intern("post_start")), INT2FIX(iseq->param.post_start));
if (iseq->param.flags.has_rest) rb_hash_aset(params, ID2SYM(rb_intern("rest_start")), INT2FIX(iseq->param.rest_start));
@@ -1753,9 +1755,15 @@ iseq_data_to_ary(rb_iseq_t *iseq)
}
rb_ary_push(keywords, key);
}
+
+ rb_hash_aset(params, ID2SYM(rb_intern("kwbits")),
+ INT2FIX(iseq->param.keyword->bits_start));
rb_hash_aset(params, ID2SYM(rb_intern("keyword")), keywords);
+ if (iseq->param.flags.has_kwrest) {
+ rb_hash_aset(params, ID2SYM(rb_intern("kwrest")),
+ INT2FIX(iseq->param.keyword->rest_start));
+ }
}
- if (iseq->param.flags.has_kwrest) rb_hash_aset(params, ID2SYM(rb_intern("kwrest")), INT2FIX(iseq->param.keyword->rest_start));
if (iseq->param.flags.ambiguous_param0) rb_hash_aset(params, ID2SYM(rb_intern("ambiguous_param0")), Qtrue);
}
@@ -1811,10 +1819,25 @@ iseq_data_to_ary(rb_iseq_t *iseq)
{
rb_call_info_t *ci = (rb_call_info_t *)*seq;
VALUE e = rb_hash_new();
+ int orig_argc = ci->orig_argc;
+
rb_hash_aset(e, ID2SYM(rb_intern("mid")), ci->mid ? ID2SYM(ci->mid) : Qnil);
- rb_hash_aset(e, ID2SYM(rb_intern("flag")), ULONG2NUM(ci->flag));
- rb_hash_aset(e, ID2SYM(rb_intern("orig_argc")), INT2FIX(ci->orig_argc));
+ rb_hash_aset(e, ID2SYM(rb_intern("flag")), UINT2NUM(ci->flag));
rb_hash_aset(e, ID2SYM(rb_intern("blockptr")), ci->blockiseq ? iseq_data_to_ary(ci->blockiseq) : Qnil);
+
+ if (ci->kw_arg) {
+ int i;
+ VALUE kw = rb_ary_new2((long)ci->kw_arg->keyword_len);
+
+ orig_argc -= ci->kw_arg->keyword_len;
+ for (i = 0; i < ci->kw_arg->keyword_len; i++) {
+ rb_ary_push(kw, ID2SYM(ci->kw_arg->keywords[i]));
+ }
+ rb_hash_aset(e, ID2SYM(rb_intern("kw_arg")), kw);
+ }
+
+ rb_hash_aset(e, ID2SYM(rb_intern("orig_argc")),
+ INT2FIX(orig_argc));
rb_ary_push(ary, e);
}
break;
@@ -1864,7 +1887,7 @@ iseq_data_to_ary(rb_iseq_t *iseq)
rb_ary_push(ary, register_label(labels_table, entry->start));
rb_ary_push(ary, register_label(labels_table, entry->end));
rb_ary_push(ary, register_label(labels_table, entry->cont));
- rb_ary_push(ary, INT2FIX(entry->sp));
+ rb_ary_push(ary, UINT2NUM(entry->sp));
rb_ary_push(exception, ary);
}
diff --git a/iseq.h b/iseq.h
index bf3a714..2dec515 100644
--- a/iseq.h
+++ b/iseq.h
@@ -18,7 +18,8 @@ RUBY_SYMBOL_EXPORT_BEGIN
VALUE rb_iseq_compile_node(VALUE self, NODE *node);
int rb_iseq_translate_threaded_code(rb_iseq_t *iseq);
VALUE *rb_iseq_original_iseq(rb_iseq_t *iseq);
-VALUE rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
+VALUE rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc,
+ VALUE locals, VALUE args,
VALUE exception, VALUE body);
/* iseq.c */
diff --git a/test/-ext-/iseq_load/test_iseq_load.rb b/test/-ext-/iseq_load/test_iseq_load.rb
new file mode 100644
index 0000000..1ba3e5e
--- /dev/null
+++ b/test/-ext-/iseq_load/test_iseq_load.rb
@@ -0,0 +1,95 @@
+require 'test/unit'
+
+class TestIseqLoad < Test::Unit::TestCase
+ require '-test-/iseq_load/iseq_load'
+ ISeq = RubyVM::InstructionSequence
+
+ def test_roundtrip_bug8543
+ iseq = ISeq.compile <<-'EOF'
+puts "tralivali"
+def funct(a, b, foo = :bar, kw: :wut)
+ p [ foo, kw ]
+ a**b
+end
+3.times { |i| puts "Hello, world#{funct(2,i)}!" }
+def m(opt = :only)
+ p opt
+end
+def r(req)
+ p req
+end
+def b(&blk)
+ yield
+end
+m
+r :r
+b { :hi }
+CONST = "HI"
+module RubyTestIseqLoad
+ module B
+ OMG = proc { :foo }
+
+ def catch_throw
+ catch :omg do
+ throw :omg if $THROW
+ end
+ end
+ end
+end
+
+begin
+ kablooey! if $PUKE
+rescue => e
+ raise e if $REALLY_RAISE
+end while true
+
+def user_mask(target)
+ target.each_char.inject(0) do |mask, chr|
+ case chr
+ when "u"
+ mask | 04700
+ when "g"
+ mask | 02070
+ when "o"
+ mask | 01007
+ when "a"
+ mask | 07777
+ else
+ raise ArgumentError, "invalid `who' symbol in file mode: #{chr}"
+ end
+ end
+end
+ EOF
+
+ orig = iseq.to_a.freeze
+ loaded = ISeq.iseq_load(orig.dup)
+ assert_equal orig, loaded.to_a
+
+ f = File.expand_path(__FILE__)
+ 3.times { f = File.dirname(f) }
+ Dir[File.join(f, 'ruby', '*.rb')].each do |f|
+ # f = $(top_srcdir)/test/ruby/test_keyword.rb
+ # f = File.join(f, 'ruby', 'test_keyword.rb')
+ # warn f
+ next if f =~ /settracefunc/
+ next unless f =~ /test_io\.rb/
+ iseq = ISeq.compile_file(f)
+ orig = iseq.to_a.freeze
+
+ # the one round-trip is not sufficient because useless jump insns
+ # get added after peephole optimization [ruby-core:66467]
+ # So we must dump + load again to ensure the useless jump insns are gone
+ loaded = ISeq.iseq_load(orig.dup)
+ require 'pp'
+ PP.pp loaded.to_a, $stderr
+ next
+ loaded_again = ISeq.iseq_load(loaded.to_a)
+ warn loaded.to_a.inspect
+ next
+ x = diff loaded_again.to_a, loaded.to_a
+ warn x
+ next
+ assert_equal loaded_again.to_a, loaded.to_a
+ end
+ end
+end
--
EW
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2014-11-26 8:02 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-26 8:02 [PATCH 1/2] compile.c (iseq_calc_param_size): hoist out of iseq_set_arguments Eric Wong
2014-11-26 8:02 ` [PATCH 2/2] wip - rb_iseq_load fix v4 Eric Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).