Skip to content

Commit 9581954

Browse files
author
normal
committed
mostly fix rb_iseq_load
This allows reporters commenters of [Feature #8543] to load instruction sequences directly. Some test cases are still failing but documented in test/-ext-/iseq_load/test_iseq_load.rb. * compile.c (rb_iseq_build_from_exception): entry->sp is unsigned (iseq_build_callinfo_from_hash): account for kw_arg (iseq_build_from_ary_body): update for r35459 (CHECK_STRING, CHECK_INTEGER): remove unused checks (int_param): new function for checking new `params' hash (iseq_build_kw): new function for loading rb_iseq_param_keyword (rb_iseq_build_from_ary): account for `misc' entry and general structure changes [Feature #8543] * iseq.c (CHECK_HASH): new macro (for `misc' and `param' entries) (iseq_load): account for `misc' and `params' hashes (iseq_data_to_ary): add final opt to arg_opt_labels, fix kw support, account for unsigned entry->sp * ext/-test-/iseq_load/iseq_load.c: new ext for test * ext/-test-/iseq_load/extconf.rb: ditto * test/-ext-/iseq_load/test_iseq_load.rb: new test git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48705 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent 0c662b3 commit 9581954

File tree

7 files changed

+352
-67
lines changed

7 files changed

+352
-67
lines changed

ChangeLog

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
Thu Dec 4 07:06:02 2014 Eric Wong <[email protected]>
2+
3+
* compile.c (rb_iseq_build_from_exception): entry->sp is unsigned
4+
(iseq_build_callinfo_from_hash): account for kw_arg
5+
(iseq_build_from_ary_body): update for r35459
6+
(CHECK_STRING, CHECK_INTEGER): remove unused checks
7+
(int_param): new function for checking new `params' hash
8+
(iseq_build_kw): new function for loading rb_iseq_param_keyword
9+
(rb_iseq_build_from_ary): account for `misc' entry and general
10+
structure changes
11+
[Feature #8543]
12+
* iseq.c (CHECK_HASH): new macro (for `misc' and `param' entries)
13+
(iseq_load): account for `misc' and `params' hashes
14+
(iseq_data_to_ary): add final opt to arg_opt_labels,
15+
fix kw support, account for unsigned entry->sp
16+
* ext/-test-/iseq_load/iseq_load.c: new ext for test
17+
* ext/-test-/iseq_load/extconf.rb: ditto
18+
* test/-ext-/iseq_load/test_iseq_load.rb: new test
19+
120
Thu Dec 4 06:56:57 2014 Eric Wong <[email protected]>
221

322
* iseq.c (iseq_free): avoid segfault on incomplete iseq

compile.c

Lines changed: 176 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5732,7 +5732,7 @@ iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
57325732
VALUE v, type, eiseqval;
57335733
const VALUE *ptr;
57345734
LABEL *lstart, *lend, *lcont;
5735-
int sp;
5735+
unsigned int sp;
57365736

57375737
v = rb_convert_type(RARRAY_AREF(exception, i), T_ARRAY,
57385738
"Array", "to_ary");
@@ -5751,7 +5751,7 @@ iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
57515751
lstart = register_label(iseq, labels_table, ptr[2]);
57525752
lend = register_label(iseq, labels_table, ptr[3]);
57535753
lcont = register_label(iseq, labels_table, ptr[4]);
5754-
sp = NUM2INT(ptr[5]);
5754+
sp = NUM2UINT(ptr[5]);
57555755

57565756
(void)sp;
57575757

@@ -5807,14 +5807,25 @@ iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
58075807
VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern("flag")));
58085808
VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern("orig_argc")));
58095809
VALUE vblock = rb_hash_aref(op, ID2SYM(rb_intern("blockptr")));
5810+
VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern("kw_arg")));
58105811

58115812
if (!NIL_P(vmid)) mid = SYM2ID(vmid);
58125813
if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
58135814
if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
58145815
if (!NIL_P(vblock)) block = iseq_build_load_iseq(iseq, vblock);
5815-
}
58165816

5817-
/* TODO: support keywords */
5817+
if (!NIL_P(vkw_arg)) {
5818+
int i;
5819+
int len = RARRAY_LENINT(vkw_arg);
5820+
size_t n = sizeof(rb_call_info_kw_arg_t) + sizeof(ID) * (len - 1);
5821+
5822+
kw_arg = xmalloc(n);
5823+
kw_arg->keyword_len = len;
5824+
for (i = 0; i < len; i++) {
5825+
kw_arg->keywords[i] = SYM2ID(RARRAY_AREF(vkw_arg, i));
5826+
}
5827+
}
5828+
}
58185829

58195830
return (VALUE)new_callinfo(iseq, mid, orig_argc, block, flag, kw_arg);
58205831
}
@@ -5915,16 +5926,21 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
59155926
case TS_CDHASH:
59165927
{
59175928
int i;
5929+
VALUE map = rb_hash_new();
5930+
5931+
rb_hash_tbl_raw(map)->type = &cdhash_type;
59185932
op = rb_convert_type(op, T_ARRAY, "Array", "to_ary");
59195933
op = rb_ary_dup(op);
59205934
for (i=0; i<RARRAY_LEN(op); i+=2) {
5921-
VALUE sym = rb_ary_entry(op, i+1);
5935+
VALUE key = RARRAY_AREF(op, i);
5936+
VALUE sym = RARRAY_AREF(op, i+1);
59225937
LABEL *label =
59235938
register_label(iseq, labels_table, sym);
5924-
rb_ary_store(op, i+1, (VALUE)label | 1);
5939+
rb_hash_aset(map, key, (VALUE)label | 1);
59255940
}
5926-
argv[j] = op;
5927-
iseq_add_mark_object_compile_time(iseq, op);
5941+
RB_GC_GUARD(op);
5942+
argv[j] = map;
5943+
iseq_add_mark_object_compile_time(iseq, map);
59285944
}
59295945
break;
59305946
default:
@@ -5947,68 +5963,180 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
59475963
}
59485964

59495965
#define CHECK_ARRAY(v) rb_convert_type((v), T_ARRAY, "Array", "to_ary")
5950-
#define CHECK_STRING(v) rb_convert_type((v), T_STRING, "String", "to_str")
59515966
#define CHECK_SYMBOL(v) rb_convert_type((v), T_SYMBOL, "Symbol", "to_sym")
5952-
static inline VALUE CHECK_INTEGER(VALUE v) {(void)NUM2LONG(v); return v;}
5967+
5968+
static int
5969+
int_param(int *dst, VALUE param, VALUE sym)
5970+
{
5971+
VALUE val = rb_hash_aref(param, sym);
5972+
switch (TYPE(val)) {
5973+
case T_NIL:
5974+
return FALSE;
5975+
case T_FIXNUM:
5976+
*dst = FIX2INT(val);
5977+
return TRUE;
5978+
default:
5979+
rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
5980+
sym, val);
5981+
}
5982+
return FALSE;
5983+
}
5984+
5985+
static void
5986+
iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
5987+
{
5988+
int i, j;
5989+
int len = RARRAY_LENINT(keywords);
5990+
int default_len;
5991+
VALUE key, sym, default_val;
5992+
5993+
iseq->param.flags.has_kw = TRUE;
5994+
5995+
iseq->param.keyword = ZALLOC(struct rb_iseq_param_keyword);
5996+
iseq->param.keyword->num = len;
5997+
#define SYM(s) ID2SYM(rb_intern(#s))
5998+
(void)int_param(&iseq->param.keyword->bits_start, params, SYM(kwbits));
5999+
i = iseq->param.keyword->bits_start - iseq->param.keyword->num;
6000+
iseq->param.keyword->table = &iseq->local_table[i];
6001+
#undef SYM
6002+
6003+
/* required args */
6004+
for (i = 0; i < len; i++) {
6005+
VALUE val = RARRAY_AREF(keywords, i);
6006+
6007+
if (!SYMBOL_P(val)) {
6008+
goto default_values;
6009+
}
6010+
iseq->param.keyword->table[i] = SYM2ID(val);
6011+
iseq->param.keyword->required_num++;
6012+
}
6013+
6014+
default_values: /* note: we intentionally preserve `i' from previous loop */
6015+
default_len = len - i;
6016+
if (default_len == 0) {
6017+
return;
6018+
}
6019+
6020+
iseq->param.keyword->default_values = ALLOC_N(VALUE, default_len);
6021+
6022+
for (j = 0; i < len; i++, j++) {
6023+
key = RARRAY_AREF(keywords, i);
6024+
CHECK_ARRAY(key);
6025+
6026+
switch (RARRAY_LEN(key)) {
6027+
case 1:
6028+
sym = RARRAY_AREF(key, 0);
6029+
default_val = Qundef;
6030+
break;
6031+
case 2:
6032+
sym = RARRAY_AREF(key, 0);
6033+
default_val = RARRAY_AREF(key, 1);
6034+
break;
6035+
default:
6036+
rb_raise(rb_eTypeError,
6037+
"keyword default has unsupported len %+"PRIsVALUE,
6038+
key);
6039+
}
6040+
iseq->param.keyword->table[i] = SYM2ID(sym);
6041+
iseq->param.keyword->default_values[j] = default_val;
6042+
}
6043+
}
59536044

59546045
VALUE
5955-
rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
6046+
rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
59566047
VALUE exception, VALUE body)
59576048
{
5958-
int i;
6049+
#define SYM(s) ID2SYM(rb_intern(#s))
6050+
int i, len;
59596051
ID *tbl;
59606052
struct st_table *labels_table = st_init_numtable();
6053+
VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
6054+
VALUE keywords = rb_hash_aref(params, SYM(keyword));
6055+
VALUE sym_arg_rest = ID2SYM(rb_intern("#arg_rest"));
59616056
DECL_ANCHOR(anchor);
59626057
INIT_ANCHOR(anchor);
59636058

5964-
iseq->local_table_size = RARRAY_LENINT(locals);
6059+
len = RARRAY_LENINT(locals);
6060+
iseq->local_table_size = len;
59656061
iseq->local_table = tbl = (ID *)ALLOC_N(ID, iseq->local_table_size);
59666062
iseq->local_size = iseq->local_table_size + 1;
59676063

5968-
for (i=0; i<RARRAY_LEN(locals); i++) {
6064+
for (i = 0; i < len; i++) {
59696065
VALUE lv = RARRAY_AREF(locals, i);
5970-
tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
6066+
6067+
if (sym_arg_rest == lv) {
6068+
tbl[i] = 0;
6069+
}
6070+
else {
6071+
tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
6072+
}
59716073
}
59726074

5973-
/* args */
5974-
if (FIXNUM_P(args)) {
5975-
iseq->param.size = iseq->param.lead_num = FIX2INT(args);
6075+
#define MISC_PARAM(D,F) do { \
6076+
if (!int_param(D, misc, SYM(F))) { \
6077+
rb_raise(rb_eTypeError, "misc field missing: %s", #F); \
6078+
} } while (0)
6079+
MISC_PARAM(&iseq->local_size, local_size);
6080+
/* iseq->stack_size and iseq->param.size are calculated */
6081+
#undef MISC_PARAM
6082+
6083+
#define INT_PARAM(F) int_param(&iseq->param.F, params, SYM(F))
6084+
if (INT_PARAM(lead_num)) {
59766085
iseq->param.flags.has_lead = TRUE;
59776086
}
5978-
else {
5979-
int i = 0;
5980-
VALUE argc = CHECK_INTEGER(rb_ary_entry(args, i++));
5981-
VALUE arg_opt_labels = CHECK_ARRAY(rb_ary_entry(args, i++));
5982-
VALUE arg_post_num = CHECK_INTEGER(rb_ary_entry(args, i++));
5983-
VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++));
5984-
VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++));
5985-
VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++));
5986-
5987-
iseq->param.lead_num = FIX2INT(argc);
5988-
iseq->param.rest_start = FIX2INT(arg_rest);
5989-
iseq->param.post_num = FIX2INT(arg_post_num);
5990-
iseq->param.post_start = FIX2INT(arg_post_start);
5991-
iseq->param.block_start = FIX2INT(arg_block);
5992-
iseq->param.opt_num = RARRAY_LENINT(arg_opt_labels) - 1;
5993-
iseq->param.opt_table = (VALUE *)ALLOC_N(VALUE, iseq->param.opt_num + 1);
6087+
if (INT_PARAM(post_num)) iseq->param.flags.has_post = TRUE;
6088+
if (INT_PARAM(post_start)) iseq->param.flags.has_post = TRUE;
6089+
if (INT_PARAM(rest_start)) iseq->param.flags.has_rest = TRUE;
6090+
if (INT_PARAM(block_start)) iseq->param.flags.has_block = TRUE;
6091+
#undef INT_PARAM
59946092

5995-
if (iseq->param.flags.has_block) {
5996-
iseq->param.size = iseq->param.block_start + 1;
5997-
}
5998-
else if (iseq->param.flags.has_post) {
5999-
iseq->param.size = iseq->param.post_start + iseq->param.post_num;
6000-
}
6001-
else if (iseq->param.flags.has_rest) {
6002-
iseq->param.size = iseq->param.rest_start + 1;
6003-
}
6004-
else {
6005-
iseq->param.size = iseq->param.lead_num + iseq->param.opt_num;
6006-
}
6093+
switch (TYPE(arg_opt_labels)) {
6094+
case T_ARRAY:
6095+
len = RARRAY_LENINT(arg_opt_labels);
6096+
iseq->param.flags.has_opt = !!(len - 1 >= 0);
6097+
6098+
if (iseq->param.flags.has_opt) {
6099+
iseq->param.opt_num = len - 1;
6100+
iseq->param.opt_table = (VALUE *)ALLOC_N(VALUE, len);
6101+
6102+
for (i = 0; i < len; i++) {
6103+
VALUE ent = RARRAY_AREF(arg_opt_labels, i);
6104+
LABEL *label = register_label(iseq, labels_table, ent);
60076105

6008-
for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) {
6009-
iseq->param.opt_table[i] = (VALUE)register_label(iseq, labels_table, rb_ary_entry(arg_opt_labels, i));
6106+
iseq->param.opt_table[i] = (VALUE)label;
6107+
}
60106108
}
6109+
case T_NIL:
6110+
break;
6111+
default:
6112+
rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
6113+
arg_opt_labels);
6114+
}
6115+
6116+
switch (TYPE(keywords)) {
6117+
case T_ARRAY:
6118+
iseq_build_kw(iseq, params, keywords);
6119+
case T_NIL:
6120+
break;
6121+
default:
6122+
rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
6123+
keywords);
6124+
}
6125+
6126+
if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
6127+
iseq->param.flags.ambiguous_param0 = TRUE;
6128+
}
6129+
6130+
if (int_param(&i, params, SYM(kwrest))) {
6131+
if (!iseq->param.keyword) {
6132+
iseq->param.keyword = ZALLOC(struct rb_iseq_param_keyword);
6133+
}
6134+
iseq->param.keyword->rest_start = i;
6135+
iseq->param.flags.has_kwrest = TRUE;
6136+
60116137
}
6138+
#undef SYM
6139+
iseq_calc_param_size(iseq);
60126140

60136141
/* exception */
60146142
iseq_build_from_ary_exception(iseq, labels_table, exception);

ext/-test-/iseq_load/extconf.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
create_makefile("-test-/iseq_load/iseq_load")

ext/-test-/iseq_load/iseq_load.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <ruby.h>
2+
3+
VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt);
4+
5+
static VALUE
6+
iseq_load(int argc, VALUE *argv, VALUE self)
7+
{
8+
VALUE data, opt = Qnil;
9+
10+
rb_scan_args(argc, argv, "11", &data, &opt);
11+
12+
return rb_iseq_load(data, 0, opt);
13+
}
14+
15+
void
16+
Init_iseq_load(void)
17+
{
18+
VALUE rb_cISeq = rb_eval_string("RubyVM::InstructionSequence");
19+
20+
rb_define_singleton_method(rb_cISeq, "iseq_load", iseq_load, -1);
21+
}

0 commit comments

Comments
 (0)