[前][次][番号順一覧][スレッド一覧]

ruby-changes:36624

From: normal <ko1@a...>
Date: Thu, 4 Dec 2014 07:17:14 +0900 (JST)
Subject: [ruby-changes:36624] normal:r48705 (trunk): mostly fix rb_iseq_load

normal	2014-12-04 07:16:58 +0900 (Thu, 04 Dec 2014)

  New Revision: 48705

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=48705

  Log:
    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

  Added directories:
    trunk/ext/-test-/iseq_load/
    trunk/test/-ext-/iseq_load/
  Added files:
    trunk/ext/-test-/iseq_load/extconf.rb
    trunk/ext/-test-/iseq_load/iseq_load.c
    trunk/test/-ext-/iseq_load/test_iseq_load.rb
  Modified files:
    trunk/ChangeLog
    trunk/compile.c
    trunk/iseq.c
    trunk/iseq.h
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 48704)
+++ ChangeLog	(revision 48705)
@@ -1,3 +1,22 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Dec  4 07:06:02 2014  Eric Wong  <e@8...>
+
+	* 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
+
 Thu Dec  4 06:56:57 2014  Eric Wong  <e@8...>
 
 	* iseq.c (iseq_free): avoid segfault on incomplete iseq
Index: iseq.c
===================================================================
--- iseq.c	(revision 48704)
+++ iseq.c	(revision 48705)
@@ -468,6 +468,7 @@ rb_iseq_new_with_bopt(NODE *node, VALUE https://github.com/ruby/ruby/blob/trunk/iseq.c#L468
 }
 
 #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;}
@@ -506,7 +507,7 @@ iseq_load(VALUE self, VALUE data, VALUE https://github.com/ruby/ruby/blob/trunk/iseq.c#L507
 
     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;
@@ -524,8 +525,8 @@ iseq_load(VALUE self, VALUE data, VALUE https://github.com/ruby/ruby/blob/trunk/iseq.c#L525
     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++));
@@ -535,12 +536,7 @@ iseq_load(VALUE self, VALUE data, VALUE https://github.com/ruby/ruby/blob/trunk/iseq.c#L536
 
     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++));
 
@@ -558,10 +554,11 @@ iseq_load(VALUE self, VALUE data, VALUE https://github.com/ruby/ruby/blob/trunk/iseq.c#L554
     }
 
     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;
@@ -1733,16 +1730,21 @@ iseq_data_to_ary(rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1730
 
     /* 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));
@@ -1760,6 +1762,9 @@ iseq_data_to_ary(rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1762
 		}
 		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));
@@ -1818,10 +1823,25 @@ iseq_data_to_ary(rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1823
 		{
 		    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;
@@ -1871,7 +1891,7 @@ iseq_data_to_ary(rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L1891
 	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);
     }
 
Index: iseq.h
===================================================================
--- iseq.h	(revision 48704)
+++ iseq.h	(revision 48705)
@@ -18,7 +18,8 @@ RUBY_SYMBOL_EXPORT_BEGIN https://github.com/ruby/ruby/blob/trunk/iseq.h#L18
 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 */
Index: compile.c
===================================================================
--- compile.c	(revision 48704)
+++ compile.c	(revision 48705)
@@ -5732,7 +5732,7 @@ iseq_build_from_ary_exception(rb_iseq_t https://github.com/ruby/ruby/blob/trunk/compile.c#L5732
 	VALUE v, type, eiseqval;
 	const VALUE *ptr;
 	LABEL *lstart, *lend, *lcont;
-	int sp;
+	unsigned int sp;
 
 	v = rb_convert_type(RARRAY_AREF(exception, i), T_ARRAY,
 					 "Array", "to_ary");
@@ -5751,7 +5751,7 @@ iseq_build_from_ary_exception(rb_iseq_t https://github.com/ruby/ruby/blob/trunk/compile.c#L5751
 	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;
 
@@ -5807,14 +5807,25 @@ iseq_build_callinfo_from_hash(rb_iseq_t https://github.com/ruby/ruby/blob/trunk/compile.c#L5807
 	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);
 }
@@ -5915,16 +5926,21 @@ iseq_build_from_ary_body(rb_iseq_t *iseq https://github.com/ruby/ruby/blob/trunk/compile.c#L5926
 		      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:
@@ -5947,68 +5963,180 @@ iseq_build_from_ary_body(rb_iseq_t *iseq https://github.com/ruby/ruby/blob/trunk/compile.c#L5963
 }
 
 #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];
+#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));
+
+	if (sym_arg_rest == lv) {
+	    tbl[i] = 0;
+	}
+	else {
+	    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);
+#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;
     }
-    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 (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);
+
+	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);
 
-	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;
-	}
-	else {
-	    iseq->param.size = iseq->param.lead_num + iseq->param.opt_num;
+		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;
+    }
+
+    if (int_param(&i, params, SYM(kwrest))) {
+        if (!iseq->param.keyword) {
+          iseq->param.keyword = ZALLOC(struct rb_iseq_param_keyword);
+        }
+        iseq->param.keyword->rest_start = i;
+        iseq->param.flags.has_kwrest = TRUE;
 
-	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));
-	}
     }
+#undef SYM
+    iseq_calc_param_size(iseq);
 
     /* exception */
     iseq_build_from_ary_exception(iseq, labels_table, exception);
Index: ext/-test-/iseq_load/iseq_load.c
===================================================================
--- ext/-test-/iseq_load/iseq_load.c	(revision 0)
+++ ext/-test-/iseq_load/iseq_load.c	(revision 48705)
@@ -0,0 +1,21 @@ https://github.com/ruby/ruby/blob/trunk/ext/-test-/iseq_load/iseq_load.c#L1
+#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);
+}
Index: ext/-test-/iseq_load/extconf.rb
===================================================================
--- ext/-test-/iseq_load/extconf.rb	(revision 0)
+++ ext/-test-/iseq_load/extconf.rb	(revision 48705)
@@ -0,0 +1 @@
+create_makefile("-test-/iseq_load/iseq_load")
Index: test/-ext-/iseq_load/test_iseq_load.rb
===================================================================
--- test/-ext-/iseq_load/test_iseq_load.rb	(revision 0)
+++ test/-ext-/iseq_load/test_iseq_load.rb	(revision 48705)
@@ -0,0 +1,95 @@ https://github.com/ruby/ruby/blob/trunk/test/-ext-/iseq_load/test_iseq_load.rb#L1
+require 'test/unit'
+
+class TestIseqLoad < Test::Unit::TestCase
+  require '-test-/iseq_load/iseq_load'
+  ISeq = RubyVM::InstructionSequence
+
+  def test_bug8543
+    assert_iseq_roundtrip <<-'end;'
+      puts "tralivali"
+      def funct(a, b)
+        a**b
+      end
+      3.times { |i| puts "Hello, world#{funct(2,i)}!" }
+    end;
+  end
+
+  def test_case_when
+    assert_iseq_roundtrip <<-'end;'
+      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
+    end;
+  end
+
+  def test_splatsplat
+    assert_iseq_roundtrip('def splatsplat(**); end')
+  end
+
+  def test_hidden
+    assert_iseq_roundtrip('def x(a, (b (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]