From 5675cdbd418509bdb1abbc4442a681b808ed35e8 Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 3 Feb 2006 09:15:42 +0000 Subject: [PATCH] * eval.c: unify ruby_class (for method definition) and ruby_cbase (for constant reference). * eval.c (rb_call0): use TMP_ALLOC() instead of allocating a temporary array object. * eval.c (eval): need not to protect $SAFE value. [ruby-core:07177] * error.c (Init_Exception): change NameError to direct subclass of Exception so that default rescue do not handle it silently. * struct.c (rb_struct_select): update RDoc description. [ruby-core:7254] * numeric.c (int_upto): return an enumerator if no block is attached to the method. * numeric.c (int_downto): ditto. * numeric.c (int_dotimes): ditto. * enum.c (enum_first): new method Enumerable#first to take first n element from an enumerable. * enum.c (enum_group_by): new method Enumerable#group_by that groups enumerable values according to their block values. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9880 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 36 ++ enum.c | 144 ++++- enumerator.c | 44 +- env.h | 9 +- error.c | 2 +- eval.c | 906 +++++++++++++++---------------- ext/dbm/dbm.c | 24 +- ext/gdbm/gdbm.c | 11 +- ext/iconv/iconv.c | 2 +- ext/openssl/ossl_asn1.c | 2 +- ext/openssl/ossl_config.c | 2 +- ext/openssl/ossl_pkcs7.c | 4 +- ext/openssl/ossl_ssl.c | 2 +- ext/openssl/ossl_x509name.c | 2 +- ext/sdbm/init.c | 11 +- ext/socket/socket.c | 2 +- ext/syck/rubyext.c | 6 +- ext/win32ole/win32ole.c | 2 +- io.c | 2 +- lib/optparse.rb | 4 +- node.h | 2 +- numeric.c | 3 + parse.y | 2 +- ruby.h | 1 + struct.c | 8 +- test/ruby/envutil.rb | 9 +- test/webrick/test_filehandler.rb | 6 +- 27 files changed, 657 insertions(+), 591 deletions(-) diff --git a/ChangeLog b/ChangeLog index 66d1310e0e..72e29de447 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Fri Feb 3 17:57:02 2006 Yukihiro Matsumoto + + * eval.c: unify ruby_class (for method definition) and ruby_cbase + (for constant reference). + Fri Feb 3 15:02:10 2006 Hirokazu Yamamoto * ext/syck/syck.c (syck_move_tokens): should reset p->cursor or etc @@ -15,6 +20,17 @@ Thu Feb 2 17:13:01 2006 NAKAMURA Usaku * lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser#get_tk): added support of :'string' style Symbol. +Thu Feb 2 16:01:24 2006 Yukihiro Matsumoto + + * eval.c (rb_call0): use TMP_ALLOC() instead of allocating + a temporary array object. + + * eval.c (eval): need not to protect $SAFE value. + [ruby-core:07177] + + * error.c (Init_Exception): change NameError to direct subclass of + Exception so that default rescue do not handle it silently. + Thu Feb 2 14:45:53 2006 Ville Mattila * configure.in: The isinf is not regognized by autoconf @@ -29,6 +45,11 @@ Wed Feb 1 22:01:47 2006 Hirokazu Yamamoto * ruby.c (set_arg0): if use setenv(3), environ space cannot be used for altering argv[0]. +Tue Jan 31 14:46:28 2006 Yukihiro Matsumoto + + * struct.c (rb_struct_select): update RDoc description. + [ruby-core:7254] + Tue Jan 31 11:58:51 2006 Hidetoshi NAGAI * ext/tk/lib/multi-tk.rb: add MultiTkIp#eval and bg_eval. @@ -36,6 +57,21 @@ Tue Jan 31 11:58:51 2006 Hidetoshi NAGAI * ext/tk/lib/tk/namespace.rb: TkNamespace#eval was enbugged at the last commit. Now it will return a proper object. +Tue Jan 31 08:07:02 2006 Yukihiro Matsumoto + + * numeric.c (int_upto): return an enumerator if no block is + attached to the method. + + * numeric.c (int_downto): ditto. + + * numeric.c (int_dotimes): ditto. + + * enum.c (enum_first): new method Enumerable#first to take first n + element from an enumerable. + + * enum.c (enum_group_by): new method Enumerable#group_by that + groups enumerable values according to their block values. + Tue Jan 31 00:08:22 2006 Hirokazu Yamamoto * ext/syck/rubyext.c (syck_resolver_transfer): workaround for SEGV. diff --git a/enum.c b/enum.c index cec178fd1c..1cefb6db18 100644 --- a/enum.c +++ b/enum.c @@ -17,12 +17,6 @@ VALUE rb_mEnumerable; static ID id_each, id_eqq, id_cmp; -VALUE -rb_each(VALUE obj) -{ - return rb_funcall(obj, id_each, 0, 0); -} - static VALUE grep_i(VALUE i, VALUE *arg) { @@ -68,7 +62,7 @@ enum_grep(VALUE obj, VALUE pat) arg[0] = pat; arg[1] = ary; - rb_iterate(rb_each, obj, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg); + rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg); return ary; } @@ -117,13 +111,13 @@ enum_count(int argc, VALUE *argv, VALUE obj) rb_scan_args(argc, argv, "1", &item); args[0] = item; args[1] = 0; - rb_iterate(rb_each, obj, count_i, (VALUE)&args); + rb_block_call(obj, id_each, 0, 0, count_i, (VALUE)&args); return INT2NUM(args[1]); } else { long n = 0; - rb_iterate(rb_each, obj, count_iter_i, (VALUE)&n); + rb_block_call(obj, id_each, 0, 0, count_iter_i, (VALUE)&n); return INT2NUM(n); } } @@ -161,7 +155,7 @@ enum_find(int argc, VALUE *argv, VALUE obj) rb_scan_args(argc, argv, "01", &if_none); RETURN_ENUMERATOR(obj, argc, argv); - rb_iterate(rb_each, obj, find_i, (VALUE)&memo); + rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)&memo); if (memo != Qundef) { return memo; } @@ -201,7 +195,7 @@ enum_find_all(VALUE obj) RETURN_ENUMERATOR(obj, 0, 0); ary = rb_ary_new(); - rb_iterate(rb_each, obj, find_all_i, ary); + rb_block_call(obj, id_each, 0, 0, find_all_i, ary); return ary; } @@ -234,7 +228,7 @@ enum_reject(VALUE obj) RETURN_ENUMERATOR(obj, 0, 0); ary = rb_ary_new(); - rb_iterate(rb_each, obj, reject_i, ary); + rb_block_call(obj, id_each, 0, 0, reject_i, ary); return ary; } @@ -276,7 +270,7 @@ enum_collect(VALUE obj) RETURN_ENUMERATOR(obj, 0, 0); ary = rb_ary_new(); - rb_iterate(rb_each, obj, collect_i, ary); + rb_block_call(obj, id_each, 0, 0, collect_i, ary); return ary; } @@ -296,7 +290,7 @@ enum_to_a(VALUE obj) { VALUE ary = rb_ary_new(); - rb_iterate(rb_each, obj, collect_all, ary); + rb_block_call(obj, id_each, 0, 0, collect_all, ary); return ary; } @@ -351,7 +345,7 @@ enum_inject(int argc, VALUE *argv, VALUE obj) if (rb_scan_args(argc, argv, "01", &memo) == 0) memo = Qundef; - rb_iterate(rb_each, obj, inject_i, (VALUE)&memo); + rb_block_call(obj, id_each, 0, 0, inject_i, (VALUE)&memo); if (memo == Qundef) return Qnil; return memo; } @@ -389,11 +383,103 @@ enum_partition(VALUE obj) ary[0] = rb_ary_new(); ary[1] = rb_ary_new(); - rb_iterate(rb_each, obj, partition_i, (VALUE)ary); + rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)ary); return rb_assoc_new(ary[0], ary[1]); } +static VALUE +group_by_i(VALUE i, VALUE hash) +{ + VALUE group = rb_yield(i); + VALUE values; + + values = rb_hash_aref(hash, group); + if (NIL_P(values)) { + values = rb_ary_new3(1, i); + rb_hash_aset(hash, group, values); + } + else { + rb_ary_push(values, i); + } + return Qnil; +} + +/* + * call-seq: + * enum.group_by {| obj | block } => a_hash + * + * Returns a hash, which keys are evaluated result from the + * block, and values are arrays of elements in enum + * corresponding to the key. + * + * (1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]} + * + */ + +static VALUE +enum_group_by(VALUE obj) +{ + VALUE hash; + + RETURN_ENUMERATOR(obj, 0, 0); + + hash = rb_hash_new(); + rb_block_call(obj, id_each, 0, 0, group_by_i, hash); + + return hash; +} + +static VALUE +first_i(VALUE i, VALUE *ary) +{ + if (NIL_P(ary[0])) { + ary[1] = i; + rb_iter_break(); + } + else { + long n = NUM2LONG(ary[0]); + + if (n <= 0) { + rb_iter_break(); + } + rb_ary_push(ary[1], i); + n--; + ary[0] = INT2NUM(n); + } + return Qnil; +} + +/* + * call-seq: + * enum.first -> obj or nil + * enum.first(n) -> an_array + * + * Returns the first element, or the first +n+ elements, of the enumerable. + * If the enumerable is empty, the first form returns nil, and the + * second form returns an empty array. + * + */ + +static VALUE +enum_first(int argc, VALUE *argv, VALUE obj) +{ + VALUE n, ary[2]; + + rb_scan_args(argc, argv, "01", &n); + + if (NIL_P(n)) { + ary[0] = ary[1] = Qnil; + } + else { + ary[0] = n; + ary[1] = rb_ary_new2(NUM2LONG(n)); + } + rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)ary); + + return ary[1]; +} + /* * call-seq: * enum.sort => array @@ -525,7 +611,7 @@ enum_sort_by(VALUE obj) ary = rb_ary_new(); } RBASIC(ary)->klass = 0; - rb_iterate(rb_each, obj, sort_by_i, ary); + rb_block_call(obj, id_each, 0, 0, sort_by_i, ary); if (RARRAY(ary)->len > 1) { ruby_qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp, 0); } @@ -581,7 +667,7 @@ enum_all(VALUE obj) { VALUE result = Qtrue; - rb_iterate(rb_each, obj, rb_block_given_p() ? all_iter_i : all_i, (VALUE)&result); + rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? all_iter_i : all_i, (VALUE)&result); return result; } @@ -628,7 +714,7 @@ enum_any(VALUE obj) { VALUE result = Qfalse; - rb_iterate(rb_each, obj, rb_block_given_p() ? any_iter_i : any_i, (VALUE)&result); + rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? any_iter_i : any_i, (VALUE)&result); return result; } @@ -681,7 +767,7 @@ enum_one(VALUE obj) { VALUE result = Qundef; - rb_iterate(rb_each, obj, rb_block_given_p() ? one_iter_i : one_i, (VALUE)&result); + rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? one_iter_i : one_i, (VALUE)&result); if (result == Qundef) return Qfalse; return result; } @@ -726,7 +812,7 @@ enum_none(VALUE obj) { VALUE result = Qtrue; - rb_iterate(rb_each, obj, rb_block_given_p() ? none_iter_i : none_i, (VALUE)&result); + rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? none_iter_i : none_i, (VALUE)&result); return result; } @@ -784,7 +870,7 @@ enum_min(VALUE obj) { VALUE result = Qundef; - rb_iterate(rb_each, obj, rb_block_given_p() ? min_ii : min_i, (VALUE)&result); + rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? min_ii : min_i, (VALUE)&result); if (result == Qundef) return Qnil; return result; } @@ -842,7 +928,7 @@ enum_max(VALUE obj) { VALUE result = Qundef; - rb_iterate(rb_each, obj, rb_block_given_p() ? max_ii : max_i, (VALUE)&result); + rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? max_ii : max_i, (VALUE)&result); if (result == Qundef) return Qnil; return result; } @@ -884,7 +970,7 @@ enum_min_by(VALUE obj) memo[0] = Qundef; memo[1] = Qnil; - rb_iterate(rb_each, obj, min_by_i, (VALUE)memo); + rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo); return memo[1]; } @@ -925,7 +1011,7 @@ enum_max_by(VALUE obj) memo[0] = Qundef; memo[1] = Qnil; - rb_iterate(rb_each, obj, max_by_i, (VALUE)memo); + rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo); return memo[1]; } @@ -959,7 +1045,7 @@ enum_member(VALUE obj, VALUE val) memo[0] = val; memo[1] = Qfalse; - rb_iterate(rb_each, obj, member_i, (VALUE)memo); + rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo); return memo[1]; } @@ -993,7 +1079,7 @@ enum_each_with_index(VALUE obj) RETURN_ENUMERATOR(obj, 0, 0); - rb_iterate(rb_each, obj, each_with_index_i, (VALUE)&memo); + rb_block_call(obj, id_each, 0, 0, each_with_index_i, (VALUE)&memo); return obj; } @@ -1057,7 +1143,7 @@ enum_zip(int argc, VALUE *argv, VALUE obj) memo[0] = result; memo[1] = rb_ary_new4(argc, argv); memo[2] = 0; - rb_iterate(rb_each, obj, zip_i, (VALUE)memo); + rb_block_call(obj, id_each, 0, 0, zip_i, (VALUE)memo); return result; } @@ -1094,6 +1180,8 @@ Init_Enumerable(void) rb_define_method(rb_mEnumerable,"map", enum_collect, 0); rb_define_method(rb_mEnumerable,"inject", enum_inject, -1); rb_define_method(rb_mEnumerable,"partition", enum_partition, 0); + rb_define_method(rb_mEnumerable,"group_by", enum_group_by, 0); + rb_define_method(rb_mEnumerable,"first", enum_first, -1); rb_define_method(rb_mEnumerable,"all?", enum_all, 0); rb_define_method(rb_mEnumerable,"any?", enum_any, 0); rb_define_method(rb_mEnumerable,"one?", enum_one, 0); diff --git a/enumerator.c b/enumerator.c index 7b3af9f66b..3321e71dbe 100644 --- a/enumerator.c +++ b/enumerator.c @@ -32,18 +32,6 @@ proc_call(VALUE proc, VALUE args) return rb_proc_call(proc, args); } -static VALUE -method_call(VALUE method, VALUE args) -{ - int argc = 0; - VALUE *argv = 0; - if (args) { - argc = RARRAY(args)->len; - argv = RARRAY(args)->ptr; - } - return rb_method_call(argc, argv, method); -} - struct enumerator { VALUE method; VALUE proc; @@ -168,7 +156,7 @@ enum_each_slice(VALUE obj, VALUE n) args[0] = rb_ary_new2(size); args[1] = (VALUE)size; - rb_iterate(rb_each, obj, each_slice_i, (VALUE)args); + rb_block_call(obj, rb_intern("each"), 0, 0, each_slice_i, (VALUE)args); ary = args[0]; if (RARRAY(ary)->len > 0) rb_yield(ary); @@ -235,7 +223,7 @@ enum_each_cons(VALUE obj, VALUE n) args[0] = rb_ary_new2(size); args[1] = (VALUE)size; - rb_iterate(rb_each, obj, each_cons_i, (VALUE)args); + rb_block_call(obj, rb_intern("each"), 0, 0, each_cons_i, (VALUE)args); return Qnil; } @@ -315,14 +303,6 @@ rb_enumeratorize(VALUE obj, VALUE meth, int argc, VALUE *argv) return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv); } -static VALUE -enumerator_iter(VALUE memo) -{ - struct enumerator *e = (struct enumerator *)memo; - - return method_call(e->method, e->args); -} - /* * call-seq: * enum.each {...} @@ -335,8 +315,14 @@ static VALUE enumerator_each(VALUE obj) { struct enumerator *e = enumerator_ptr(obj); + int argc = 0; + VALUE *argv = 0; - return rb_iterate(enumerator_iter, (VALUE)e, e->iter, (VALUE)e); + if (e->args) { + argc = RARRAY(e->args)->len; + argv = RARRAY(e->args)->ptr; + } + return rb_block_call(e->method, rb_intern("call"), argc, argv, e->iter, (VALUE)e); } static VALUE @@ -360,9 +346,17 @@ enumerator_with_index(VALUE obj) { struct enumerator *e = enumerator_ptr(obj); VALUE memo = 0; + int argc = 0; + VALUE *argv = 0; - return rb_iterate(enumerator_iter, (VALUE)e, - enumerator_with_index_i, (VALUE)&memo); + if (e->args) { + argc = RARRAY(e->args)->len; + argv = RARRAY(e->args)->ptr; + } + return rb_block_call(e->method, rb_intern("call"), argc, argv, e->iter, (VALUE)e); + + return rb_block_call(e->method, rb_intern("call"), argc, argv, + enumerator_with_index_i, (VALUE)&memo); } void diff --git a/env.h b/env.h index 9f14c2c65f..68346172db 100644 --- a/env.h +++ b/env.h @@ -22,7 +22,7 @@ RUBY_EXTERN struct FRAME { struct FRAME *prev; struct FRAME *tmp; struct RNode *node; - int iter; + struct BLOCK *block; int flags; unsigned long uniq; } *ruby_frame; @@ -45,8 +45,8 @@ RUBY_EXTERN struct SCOPE { #define SCOPE_DONT_RECYCLE 4 RUBY_EXTERN int ruby_in_eval; - -RUBY_EXTERN VALUE ruby_class; +VALUE ruby_current_class_object(void); +#define ruby_class ruby_current_class_object() struct RVarmap { struct RBasic super; @@ -72,7 +72,6 @@ struct BLOCK { struct SCOPE *scope; VALUE klass; struct RNode *cref; - int iter; int vmode; int flags; int uniq; @@ -80,8 +79,6 @@ struct BLOCK { VALUE orig_thread; VALUE wrapper; VALUE block_obj; - struct BLOCK *outer; - struct BLOCK *prev; }; #define BLOCK_D_SCOPE 1 diff --git a/error.c b/error.c index 74a78345b9..76c8829aeb 100644 --- a/error.c +++ b/error.c @@ -961,7 +961,7 @@ Init_Exception(void) rb_eIndexError = rb_define_class("IndexError", rb_eStandardError); rb_eKeyError = rb_define_class("KeyError", rb_eIndexError); rb_eRangeError = rb_define_class("RangeError", rb_eStandardError); - rb_eNameError = rb_define_class("NameError", rb_eStandardError); + rb_eNameError = rb_define_class("NameError", rb_eException); rb_define_method(rb_eNameError, "initialize", name_err_initialize, -1); rb_define_method(rb_eNameError, "name", name_err_name, 0); rb_define_method(rb_eNameError, "to_s", name_err_to_s, 0); diff --git a/eval.c b/eval.c index 11dea38408..33e82af971 100644 --- a/eval.c +++ b/eval.c @@ -240,8 +240,7 @@ static VALUE proc_invoke(VALUE,VALUE,VALUE,VALUE); static VALUE proc_lambda(void); static VALUE rb_f_binding(VALUE); static void rb_f_END(void); -static VALUE rb_f_block_given_p(void); -static VALUE block_pass(VALUE,NODE*); +static struct BLOCK *passing_block(VALUE,struct BLOCK*); static VALUE rb_cMethod; static VALUE rb_cUnboundMethod; static VALUE umethod_bind(VALUE, VALUE); @@ -721,13 +720,13 @@ static struct SCOPE *top_scope; static unsigned long frame_unique = 0; -#define PUSH_FRAME() do { \ +#define PUSH_FRAME(link) do { \ struct FRAME _frame; \ _frame.prev = ruby_frame; \ _frame.tmp = 0; \ _frame.node = ruby_current_node; \ - _frame.iter = ruby_iter->iter; \ _frame.argc = 0; \ + _frame.block = (link)?ruby_frame->block:0;\ _frame.flags = 0; \ _frame.uniq = frame_unique++; \ ruby_frame = &_frame @@ -737,22 +736,17 @@ static unsigned long frame_unique = 0; ruby_frame = _frame.prev; \ } while (0) -static struct BLOCK *ruby_block; static unsigned long block_unique = 0; -#define PUSH_BLOCK(v,b) do { \ +#define PUSH_BLOCK(v,iv,b) do { \ struct BLOCK _block; \ - _block.var = (v); \ + _block.var = (iv); \ _block.body = (b); \ _block.self = self; \ _block.frame = *ruby_frame; \ - _block.klass = ruby_class; \ _block.cref = ruby_cref; \ _block.frame.node = ruby_current_node;\ _block.scope = ruby_scope; \ - _block.prev = ruby_block; \ - _block.outer = ruby_block; \ - _block.iter = ruby_iter->iter; \ _block.vmode = scope_vmode; \ _block.flags = BLOCK_D_SCOPE; \ _block.dyna_vars = ruby_dyna_vars; \ @@ -762,11 +756,9 @@ static unsigned long block_unique = 0; if (b) { \ prot_tag->blkid = _block.uniq; \ } \ - ruby_block = &_block + (v) = &_block -#define POP_BLOCK() \ - ruby_block = _block.prev; \ -} while (0) +#define POP_BLOCK() } while (0) struct RVarmap *ruby_dyna_vars; #define PUSH_VARS() do { \ @@ -897,31 +889,9 @@ rb_svar(int cnt) return &ruby_scope->local_vars[cnt]; } -struct iter { - int iter; - struct iter *prev; -}; -static struct iter *ruby_iter; - -#define ITER_NOT 0 -#define ITER_PRE 1 -#define ITER_CUR 2 -#define ITER_PAS 3 - -#define PUSH_ITER(i) do { \ - struct iter _iter; \ - _iter.prev = ruby_iter; \ - _iter.iter = (i); \ - ruby_iter = &_iter - -#define POP_ITER() \ - ruby_iter = _iter.prev; \ -} while (0) - struct tag { rb_jmpbuf_t buf; struct FRAME *frame; - struct iter *iter; VALUE tag; VALUE retval; struct SCOPE *scope; @@ -935,7 +905,6 @@ static struct tag *prot_tag; struct tag _tag; \ _tag.retval = Qnil; \ _tag.frame = ruby_frame; \ - _tag.iter = ruby_iter; \ _tag.prev = prot_tag; \ _tag.scope = ruby_scope; \ _tag.tag = ptag; \ @@ -955,7 +924,6 @@ static struct tag *prot_tag; #define JUMP_TAG(st) do { \ ruby_frame = prot_tag->frame; \ - ruby_iter = prot_tag->iter; \ ruby_longjmp(prot_tag->buf,(st)); \ } while (0) @@ -977,16 +945,8 @@ static struct tag *prot_tag; #define TAG_THREAD 0xa #define TAG_MASK 0xf -VALUE ruby_class; static VALUE ruby_wrapper; /* security wrapper */ -#define PUSH_CLASS(c) do { \ - VALUE _class = ruby_class; \ - ruby_class = (c) - -#define POP_CLASS() ruby_class = _class; \ -} while (0) - static NODE *ruby_cref = 0; static NODE *top_cref; #define PUSH_CREF(c) ruby_cref = NEW_NODE(NODE_CREF,(c),0,ruby_cref) @@ -1031,7 +991,6 @@ struct ruby_env { struct FRAME *frame; struct SCOPE *scope; struct BLOCK *block; - struct iter *iter; struct tag *tag; NODE *cref; }; @@ -1067,7 +1026,7 @@ typedef enum calling_scope { CALLING_SUPER, } calling_scope_t; -static VALUE rb_call(VALUE,VALUE,ID,int,const VALUE*,calling_scope_t); +static VALUE rb_call(VALUE,VALUE,ID,int,const VALUE*,struct BLOCK*,calling_scope_t); static VALUE module_setup(VALUE,NODE*); static VALUE massign(VALUE,NODE*,VALUE,int); @@ -1304,7 +1263,6 @@ ruby_init(void) { static int initialized = 0; static struct FRAME frame; - static struct iter iter; int state; if (initialized) @@ -1315,7 +1273,6 @@ ruby_init(void) #endif ruby_frame = top_frame = &frame; - ruby_iter = &iter; #ifdef __MACOS__ rb_origenviron = 0; @@ -1333,7 +1290,6 @@ ruby_init(void) PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { rb_call_inits(); - ruby_class = rb_cObject; ruby_frame->self = ruby_top_self; top_cref = rb_node_newnode(NODE_CREF,rb_cObject,0,0); ruby_cref = top_cref; @@ -1506,7 +1462,6 @@ ruby_cleanup(int ex) ruby_safe_level = 0; Init_stack((void*)&state); PUSH_THREAD_TAG(); - PUSH_ITER(ITER_NOT); if ((state = EXEC_TAG()) == 0) { ruby_finalize_0(); if (ruby_errinfo) err = ruby_errinfo; @@ -1519,7 +1474,6 @@ ruby_cleanup(int ex) else if (ex == 0) { ex = state; } - POP_ITER(); ruby_errinfo = err; ex = error_handle(ex); ruby_finalize_1(); @@ -1540,7 +1494,6 @@ ruby_exec_internal(void) int state; PUSH_THREAD_TAG(); - PUSH_ITER(ITER_NOT); /* default visibility is private at toplevel */ SCOPE_SET(SCOPE_PRIVATE); if ((state = EXEC_TAG()) == 0) { @@ -1549,7 +1502,6 @@ ruby_exec_internal(void) else if (state == TAG_THREAD) { rb_thread_start_1(); } - POP_ITER(); POP_THREAD_TAG(); return state; } @@ -1627,15 +1579,14 @@ rb_eval_string_wrap(const char *str, int *state) VALUE wrapper = ruby_wrapper; VALUE val; - PUSH_CLASS(ruby_wrapper = rb_module_new()); ruby_top_self = rb_obj_clone(ruby_top_self); rb_extend_object(ruby_top_self, ruby_wrapper); - PUSH_FRAME(); + PUSH_FRAME(Qfalse); ruby_frame->callee = 0; ruby_frame->this_func = 0; ruby_frame->this_class = 0; ruby_frame->self = self; - PUSH_CREF(ruby_wrapper); + PUSH_CREF(ruby_wrapper = rb_module_new()); PUSH_SCOPE(); val = rb_eval_string_protect(str, &status); @@ -1643,7 +1594,6 @@ rb_eval_string_wrap(const char *str, int *state) POP_SCOPE(); POP_FRAME(); - POP_CLASS(); ruby_wrapper = wrapper; if (state) { *state = status; @@ -1748,7 +1698,6 @@ rb_eval_cmd(VALUE cmd, VALUE arg, int level) level = 4; } if (TYPE(cmd) != T_STRING) { - PUSH_ITER(ITER_NOT); PUSH_TAG(PROT_NONE); ruby_safe_level = level; if ((state = EXEC_TAG()) == 0) { @@ -1756,14 +1705,13 @@ rb_eval_cmd(VALUE cmd, VALUE arg, int level) } ruby_safe_level = safe; POP_TAG(); - POP_ITER(); if (state) JUMP_TAG(state); return val; } saved_scope = ruby_scope; ruby_scope = top_scope; - PUSH_FRAME(); + PUSH_FRAME(Qfalse); ruby_frame->callee = 0; ruby_frame->this_func = 0; ruby_frame->this_class = 0; @@ -1788,6 +1736,11 @@ rb_eval_cmd(VALUE cmd, VALUE arg, int level) } #define ruby_cbase (ruby_cref->nd_clss) +VALUE +ruby_current_class_object() +{ + return ruby_cbase; +} static VALUE ev_const_defined(NODE *cref, ID id, VALUE self) @@ -2175,22 +2128,6 @@ copy_node_scope(NODE *node, NODE *rval) #define SETUP_ARGS(anode) SETUP_ARGS0(anode, anode->nd_alen) -#define BEGIN_CALLARGS do {\ - struct BLOCK *tmp_block = ruby_block;\ - int tmp_iter = ruby_iter->iter;\ - switch (tmp_iter) {\ - case ITER_PRE:\ - ruby_block = ruby_block->outer;\ - case ITER_PAS:\ - tmp_iter = ITER_NOT;\ - }\ - PUSH_ITER(tmp_iter) - -#define END_CALLARGS \ - ruby_block = tmp_block;\ - POP_ITER();\ -} while (0) - #define MATCH_DATA *rb_svar(node->nd_cnt) static const char* is_defined(VALUE, NODE*, char*, int); @@ -2556,10 +2493,9 @@ call_trace_func(rb_event_t event, NODE *node, VALUE self, ID id, VALUE klass /* } tracing = 1; prev = ruby_frame; - PUSH_FRAME(); + PUSH_FRAME(Qfalse); *ruby_frame = *prev; ruby_frame->prev = prev; - ruby_frame->iter = 0; /* blocks not available anyway */ if (node) { ruby_current_node = node; @@ -2717,6 +2653,9 @@ NORETURN(static void return_jump(VALUE)); NORETURN(static void break_jump(VALUE)); NORETURN(static void unknown_node(NODE * volatile)); +static VALUE call_super(int, const VALUE*, struct BLOCK*); +static VALUE call_super_0(VALUE, VALUE, ID mid, int argc, const VALUE*, struct BLOCK *); + static void unknown_node(NODE *volatile node) { @@ -2765,7 +2704,11 @@ rb_eval(VALUE self, NODE *n) goto again; case NODE_POSTEXE: + PUSH_FRAME(Qtrue); + PUSH_BLOCK(ruby_frame->block, 0, node->nd_body); rb_f_END(); + POP_BLOCK(); + POP_FRAME(); nd_set_type(node, NODE_NIL); /* exec just once */ result = Qnil; break; @@ -3003,72 +2946,17 @@ rb_eval(VALUE self, NODE *n) if (state) JUMP_TAG(state); RETURN(result); - case NODE_BLOCK_PASS: - result = block_pass(self, node); - break; - case NODE_LAMBDA: PUSH_TAG(PROT_LOOP); - PUSH_BLOCK(node->nd_var, node->nd_body); - + PUSH_FRAME(Qtrue); + PUSH_BLOCK(ruby_frame->block, node->nd_var, node->nd_body); state = EXEC_TAG(); - PUSH_ITER(ITER_PRE); - ruby_iter->iter = ruby_frame->iter = ITER_CUR; result = proc_lambda(); - POP_ITER(); POP_BLOCK(); + POP_FRAME(); POP_TAG(); break; - case NODE_ITER: - case NODE_FOR: - { - PUSH_TAG(PROT_LOOP); - PUSH_BLOCK(node->nd_var, node->nd_body); - - state = EXEC_TAG(); - if (state == 0) { - iter_retry: - PUSH_ITER(ITER_PRE); - if (nd_type(node) == NODE_ITER) { - result = rb_eval(self, node->nd_iter); - } - else if (nd_type(node) == NODE_LAMBDA) { - ruby_iter->iter = ruby_frame->iter = ITER_CUR; - result = rb_block_proc(); - } - else { - VALUE recv; - - _block.flags &= ~BLOCK_D_SCOPE; - BEGIN_CALLARGS; - recv = rb_eval(self, node->nd_iter); - END_CALLARGS; - ruby_current_node = node; - SET_CURRENT_SOURCE(); - result = rb_call(CLASS_OF(recv),recv,each,0,0,CALLING_NORMAL); - } - POP_ITER(); - } - else if (state == TAG_BREAK && TAG_DST()) { - result = prot_tag->retval; - state = 0; - } - else if (state == TAG_RETRY && ruby_block == &_block) { - state = 0; - goto iter_retry; - } - POP_BLOCK(); - POP_TAG(); - switch (state) { - case 0: - break; - default: - JUMP_TAG(state); - } - } - break; - case NODE_BREAK: break_jump(rb_eval(self, node->nd_stts)); break; @@ -3275,7 +3163,6 @@ rb_eval(VALUE self, NODE *n) calling_scope_t scope; TMP_PROTECT; - BEGIN_CALLARGS; if (node->nd_recv == (NODE *)1) { recv = self; scope = CALLING_FCALL; @@ -3285,29 +3172,167 @@ rb_eval(VALUE self, NODE *n) scope = CALLING_NORMAL; } SETUP_ARGS(node->nd_args); - END_CALLARGS; ruby_current_node = node; SET_CURRENT_SOURCE(); - rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope); + rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0,scope); result = argv[argc-1]; } break; + case NODE_FOR: + { + VALUE recv; + int state; + struct BLOCK *block; + + PUSH_TAG(PROT_LOOP); + PUSH_BLOCK(block, node->nd_var, node->nd_body); + state = EXEC_TAG(); + if (state == 0) { + for_retry: + block->flags &= ~BLOCK_D_SCOPE; + recv = rb_eval(self, node->nd_iter); + ruby_current_node = node; + SET_CURRENT_SOURCE(); + result = rb_call(CLASS_OF(recv),recv,each,0,0,block,CALLING_NORMAL); + } + else if (state == TAG_BREAK && TAG_DST()) { + result = prot_tag->retval; + state = 0; + } + else if (state == TAG_RETRY) { + state = 0; + goto for_retry; + } + POP_BLOCK(); + POP_TAG(); + if (state) JUMP_TAG(state); + } + break; + + case NODE_BLOCK_PASS: + { + VALUE recv = self; + calling_scope_t scope; + NODE *bpass = node; + + PUSH_TAG(PROT_LOOP); + node = node->nd_iter; /* should be NODE_CALL */ + switch (nd_type(node)) { + case NODE_CALL: + scope = CALLING_NORMAL; break; + case NODE_FCALL: + scope = CALLING_FCALL; break; + case NODE_VCALL: + scope = CALLING_VCALL; break; + case NODE_SUPER: + scope = CALLING_SUPER; break; + default: + /* error! */ + unknown_node(node); + } + state = EXEC_TAG(); + if (state == 0) { + struct BLOCK *block, _block; + int argc; VALUE *argv; /* used in SETUP_ARGS */ + TMP_PROTECT; + + block_pass_retry: + if (scope == CALLING_NORMAL) { + recv = rb_eval(self, node->nd_recv); + } + SETUP_ARGS(node->nd_args); + block = passing_block(rb_eval(self, bpass->nd_body), &_block); + ruby_current_node = node; + SET_CURRENT_SOURCE(); + if (scope == CALLING_SUPER) { + result = call_super(argc, argv, block); + } + else { + result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,block,scope); + } + } + else if (state == TAG_BREAK && TAG_DST()) { + result = prot_tag->retval; + state = 0; + } + else if (state == TAG_RETRY) { + state = 0; + goto block_pass_retry; + } + POP_TAG(); + if (state) JUMP_TAG(state); + } + break; + + case NODE_ITER: + { + VALUE recv = self; + calling_scope_t scope; + struct BLOCK *block; + + PUSH_TAG(PROT_LOOP); + PUSH_BLOCK(block, node->nd_var, node->nd_body); + node = node->nd_iter; /* should be NODE_CALL */ + switch (nd_type(node)) { + case NODE_CALL: + scope = CALLING_NORMAL; break; + case NODE_FCALL: + scope = CALLING_FCALL; break; + case NODE_VCALL: + scope = CALLING_VCALL; break; + case NODE_SUPER: + scope = CALLING_SUPER; break; + default: + /* error! */ + unknown_node(node); + } + state = EXEC_TAG(); + if (state == 0) { + int argc; VALUE *argv; /* used in SETUP_ARGS */ + TMP_PROTECT; + + iter_retry: + if (scope == CALLING_NORMAL) { + recv = rb_eval(self, node->nd_recv); + } + SETUP_ARGS(node->nd_args); + ruby_current_node = node; + SET_CURRENT_SOURCE(); + if (scope == CALLING_SUPER) { + result = call_super(argc, argv, block); + } + else { + result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,block,scope); + } + } + else if (state == TAG_BREAK && TAG_DST()) { + result = prot_tag->retval; + state = 0; + } + else if (state == TAG_RETRY) { + state = 0; + goto iter_retry; + } + POP_BLOCK(); + POP_TAG(); + if (state) JUMP_TAG(state); + } + break; + case NODE_CALL: { VALUE recv; int argc; VALUE *argv; /* used in SETUP_ARGS */ TMP_PROTECT; - BEGIN_CALLARGS; recv = rb_eval(self, node->nd_recv); SETUP_ARGS(node->nd_args); - END_CALLARGS; ruby_current_node = node; SET_CURRENT_SOURCE(); - result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,CALLING_NORMAL); + result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0,CALLING_NORMAL); } break; @@ -3316,19 +3341,17 @@ rb_eval(VALUE self, NODE *n) int argc; VALUE *argv; /* used in SETUP_ARGS */ TMP_PROTECT; - BEGIN_CALLARGS; SETUP_ARGS(node->nd_args); - END_CALLARGS; ruby_current_node = node; SET_CURRENT_SOURCE(); - result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,CALLING_FCALL); + result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,0,CALLING_FCALL); } break; case NODE_VCALL: SET_CURRENT_SOURCE(); - result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,CALLING_VCALL); + result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,0,CALLING_VCALL); break; case NODE_SUPER: @@ -3363,9 +3386,7 @@ rb_eval(VALUE self, NODE *n) } } else { - BEGIN_CALLARGS; SETUP_ARGS(node->nd_args); - END_CALLARGS; ruby_current_node = node; } @@ -3757,20 +3778,20 @@ rb_eval(VALUE self, NODE *n) VALUE origin; int noex; - if (NIL_P(ruby_class)) { + if (NIL_P(ruby_cbase)) { rb_raise(rb_eTypeError, "no class/module to add method"); } - if (ruby_class == rb_cObject && node->nd_mid == init) { + if (ruby_cbase == rb_cObject && node->nd_mid == init) { rb_warn("redefining Object#initialize may cause infinite loop"); } if (node->nd_mid == __id__ || node->nd_mid == __send__) { rb_warn("redefining `%s' may cause serious problem", rb_id2name(node->nd_mid)); } - rb_frozen_class_p(ruby_class); - body = search_method(ruby_class, node->nd_mid, &origin); + rb_frozen_class_p(ruby_cbase); + body = search_method(ruby_cbase, node->nd_mid, &origin); if (body){ - if (RTEST(ruby_verbose) && ruby_class == origin && body->nd_cnt == 0 && body->nd_body) { + if (RTEST(ruby_verbose) && ruby_cbase == origin && body->nd_cnt == 0 && body->nd_body) { rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid)); } } @@ -3784,14 +3805,14 @@ rb_eval(VALUE self, NODE *n) else { noex = NOEX_PUBLIC; } - if (body && origin == ruby_class && body->nd_body == 0) { + if (body && origin == ruby_cbase && body->nd_body == 0) { noex |= NOEX_NOSUPER; } defn = copy_node_scope(node->nd_defn, ruby_cref); - rb_add_method(ruby_class, node->nd_mid, defn, noex); + rb_add_method(ruby_cbase, node->nd_mid, defn, noex); if (scope_vmode == SCOPE_MODFUNC) { - rb_add_method(rb_singleton_class(ruby_class), + rb_add_method(rb_singleton_class(ruby_cbase), node->nd_mid, defn, NOEX_PUBLIC); } result = Qnil; @@ -3832,18 +3853,18 @@ rb_eval(VALUE self, NODE *n) break; case NODE_UNDEF: - if (NIL_P(ruby_class)) { + if (NIL_P(ruby_cbase)) { rb_raise(rb_eTypeError, "no class to undef method"); } - rb_undef(ruby_class, rb_to_id(rb_eval(self, node->u2.node))); + rb_undef(ruby_cbase, rb_to_id(rb_eval(self, node->u2.node))); result = Qnil; break; case NODE_ALIAS: - if (NIL_P(ruby_class)) { + if (NIL_P(ruby_cbase)) { rb_raise(rb_eTypeError, "no class to make alias"); } - rb_alias(ruby_class, rb_to_id(rb_eval(self, node->u1.node)), + rb_alias(ruby_cbase, rb_to_id(rb_eval(self, node->u1.node)), rb_to_id(rb_eval(self, node->u2.node))); result = Qnil; break; @@ -4001,7 +4022,6 @@ module_setup(VALUE module, NODE *n) frame.tmp = ruby_frame; ruby_frame = &frame; - PUSH_CLASS(module); PUSH_SCOPE(); PUSH_VARS(); @@ -4028,7 +4048,6 @@ module_setup(VALUE module, NODE *n) POP_CREF(); POP_VARS(); POP_SCOPE(); - POP_CLASS(); ruby_frame = frame.tmp; EXEC_EVENT_HOOK(RUBY_EVENT_END, n, 0, ruby_frame->this_func, @@ -4546,7 +4565,7 @@ static void rb_raise_jump(VALUE mesg) { if (ruby_frame != top_frame) { - PUSH_FRAME(); /* fake frame */ + PUSH_FRAME(Qfalse); /* fake frame */ *ruby_frame = *_frame.prev->prev; rb_longjmp(TAG_RAISE, mesg); POP_FRAME(); @@ -4563,8 +4582,7 @@ rb_jump_tag(int tag) int rb_block_given_p(void) { - if (ruby_frame->iter == ITER_CUR && ruby_block) - return Qtrue; + if (ruby_frame->block) return Qtrue; return Qfalse; } @@ -4599,7 +4617,7 @@ rb_iterator_p(void) static VALUE rb_f_block_given_p(void) { - if (ruby_frame->prev && ruby_frame->prev->iter == ITER_CUR && ruby_block) + if (ruby_frame->prev && ruby_frame->prev->block) return Qtrue; return Qfalse; } @@ -4711,7 +4729,7 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags, int avalue) rb_need_block(); PUSH_VARS(); - block = ruby_block; + block = ruby_frame->block; frame = block->frame; frame.prev = ruby_frame; frame.node = cnode; @@ -4724,7 +4742,6 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags, int avalue) ruby_scope = block->scope; old_vmode = scope_vmode; scope_vmode = (flags & YIELD_PUBLIC_DEF) ? SCOPE_PUBLIC : block->vmode; - ruby_block = block->prev; if (block->flags & BLOCK_D_SCOPE) { /* put place holder for dynamic (in-block) local variables */ ruby_dyna_vars = new_dvar(0, 0, block->dyna_vars); @@ -4733,8 +4750,8 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags, int avalue) /* FOR does not introduce new scope */ ruby_dyna_vars = block->dyna_vars; } - PUSH_CLASS(klass ? klass : block->klass); - if (!klass) { + if (klass) PUSH_CREF(klass); + else { self = block->self; } node = block->body; @@ -4832,7 +4849,6 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags, int avalue) } ruby_current_node = node; - PUSH_ITER(block->iter); PUSH_TAG(lambda ? PROT_NONE : PROT_YIELD); if ((state = EXEC_TAG()) == 0) { redo: @@ -4853,13 +4869,9 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags, int avalue) struct BLOCK *data, _block; Data_Get_Struct(block->block_obj, struct BLOCK, data); _block = *data; - _block.outer = ruby_block; _block.uniq = block_unique++; - ruby_block = &_block; - PUSH_ITER(ITER_PRE); - ruby_frame->iter = ITER_CUR; + ruby_frame->block = &_block; result = (*node->nd_cfnc)(val, node->nd_tval, self); - POP_ITER(); } else { result = (*node->nd_cfnc)(val, node->nd_tval, self); @@ -4892,9 +4904,7 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags, int avalue) } } POP_TAG(); - POP_ITER(); pop_state: - POP_CLASS(); if (ruby_dyna_vars && (block->flags & BLOCK_D_SCOPE) && !FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE)) { struct RVarmap *vars = ruby_dyna_vars; @@ -4910,7 +4920,6 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags, int avalue) } } POP_VARS(); - ruby_block = block; ruby_frame = ruby_frame->prev; ruby_cref = (NODE*)old_cref; ruby_wrapper = old_wrapper; @@ -4926,7 +4935,7 @@ rb_yield_0(VALUE val, VALUE self, VALUE klass /* OK */, int flags, int avalue) struct tag *tt = prot_tag; while (tt) { - if (tt->tag == PROT_LOOP && tt->blkid == ruby_block->uniq) { + if (tt->tag == PROT_LOOP && tt->blkid == block->uniq) { tt->dst = (VALUE)tt->frame->uniq; tt->retval = result; JUMP_TAG(TAG_BREAK); @@ -5125,7 +5134,7 @@ assign(VALUE self, NODE *lhs, VALUE val, int pcall) /* attr set */ ruby_current_node = lhs; SET_CURRENT_SOURCE(); - rb_call(CLASS_OF(recv), recv, lhs->nd_mid, 1, &val, scope); + rb_call(CLASS_OF(recv), recv, lhs->nd_mid, 1, &val, 0, scope); } else { /* array set */ @@ -5136,7 +5145,7 @@ assign(VALUE self, NODE *lhs, VALUE val, int pcall) ruby_current_node = lhs; SET_CURRENT_SOURCE(); rb_call(CLASS_OF(recv), recv, lhs->nd_mid, - RARRAY(args)->len, RARRAY(args)->ptr, scope); + RARRAY(args)->len, RARRAY(args)->ptr, 0, scope); } } break; @@ -5155,12 +5164,12 @@ rb_iterate(VALUE (*it_proc)(VALUE), VALUE data1, VALUE (*bl_proc)(ANYARGS), VALU NODE *node = NEW_IFUNC(bl_proc, data2); VALUE self = ruby_top_self; - PUSH_ITER(ITER_PRE); PUSH_TAG(PROT_LOOP); - PUSH_BLOCK(0, node); + PUSH_FRAME(Qtrue); + PUSH_BLOCK(ruby_frame->block, 0, node); state = EXEC_TAG(); if (state == 0) { - iter_retry: + iter_retry: retval = (*it_proc)(data1); } else if (state == TAG_BREAK && TAG_DST()) { @@ -5172,8 +5181,8 @@ rb_iterate(VALUE (*it_proc)(VALUE), VALUE data1, VALUE (*bl_proc)(ANYARGS), VALU goto iter_retry; } POP_BLOCK(); + POP_FRAME(); POP_TAG(); - POP_ITER(); switch (state) { case 0: @@ -5184,6 +5193,42 @@ rb_iterate(VALUE (*it_proc)(VALUE), VALUE data1, VALUE (*bl_proc)(ANYARGS), VALU return retval; } +struct iter_method_arg { + VALUE obj; + ID mid; + int argc; + VALUE *argv; +}; + +static VALUE +iterate_method(VALUE obj) +{ + struct iter_method_arg *arg; + + arg = (struct iter_method_arg*)obj; + return rb_call(CLASS_OF(arg->obj), arg->obj, arg->mid, arg->argc, arg->argv, + ruby_frame->block, CALLING_FCALL); +} + +VALUE +rb_block_call(VALUE obj, ID mid, int argc, VALUE *argv, VALUE (*bl_proc)(ANYARGS), VALUE data2) +{ + struct iter_method_arg arg; + + arg.obj = obj; + arg.mid = mid; + arg.argc = argc; + arg.argv = argv; + return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2); +} + +VALUE +rb_each(VALUE obj) +{ + return rb_call(CLASS_OF(obj), obj, rb_intern("each"), 0, 0, + ruby_frame->block, CALLING_FCALL); +} + static int handle_rescue(VALUE self, NODE *node) { @@ -5194,10 +5239,7 @@ handle_rescue(VALUE self, NODE *node) return rb_obj_is_kind_of(ruby_errinfo, rb_eStandardError); } - BEGIN_CALLARGS; SETUP_ARGS(node->nd_args); - END_CALLARGS; - while (argc--) { if (!rb_obj_is_kind_of(argv[0], rb_cModule)) { rb_raise(rb_eTypeError, "class or module required for rescue clause"); @@ -5442,14 +5484,16 @@ rb_method_missing(int argc, const VALUE *argv, VALUE obj) } static VALUE -method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int call_status) +method_missing(VALUE obj, ID id, int argc, const VALUE *argv, + struct BLOCK *block, int call_status) { VALUE *nargv; last_call_status = call_status; if (id == missing) { - PUSH_FRAME(); + PUSH_FRAME(Qfalse); + ruby_frame->block = block; rb_method_missing(argc, argv, obj); POP_FRAME(); } @@ -5461,7 +5505,7 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int call_status) nargv[0] = ID2SYM(id); MEMCPY(nargv+1, argv, VALUE, argc); - return rb_funcall2(obj, missing, argc+1, nargv); + return rb_call(CLASS_OF(obj), obj, missing, argc+1, nargv, block, CALLING_FCALL); } static inline VALUE @@ -5620,49 +5664,46 @@ formal_assign(VALUE recv, NODE *node, int argc, const VALUE *argv, VALUE *local_ return i; } +#define PUSH_METHOD_FRAME() \ + PUSH_FRAME(Qfalse);\ + ruby_frame->callee = id;\ + ruby_frame->this_func = oid;\ + ruby_frame->this_class = (flags & NOEX_NOSUPER)?0:klass;\ + ruby_frame->self = recv;\ + ruby_frame->argc = argc;\ + ruby_frame->block = block;\ + ruby_frame->flags = (flags & NOEX_RECV) ? FRAME_FUNC : 0;\ + static VALUE rb_call0(VALUE klass, VALUE recv, ID id, ID oid, - int argc /* OK */, const VALUE *argv /* OK */, NODE *volatile body, int flags) + int argc /* OK */, const VALUE *argv /* OK */, + struct BLOCK *block, + NODE *volatile body, int flags) { NODE *b2; /* OK */ volatile VALUE result = Qnil; - int itr; static int tick; volatile VALUE args; volatile int safe = -1; TMP_PROTECT; - switch (ruby_iter->iter) { - case ITER_PRE: - case ITER_PAS: - itr = ITER_CUR; - break; - case ITER_CUR: - default: - itr = ITER_NOT; - break; - } - if ((++tick & 0xff) == 0) { CHECK_INTS; /* better than nothing */ stack_check(); rb_gc_finalize_deferred(); } if (argc < 0) { - argc = -argc-1; - args = rb_ary_concat(rb_ary_new4(argc, argv), splat_value(argv[argc])); - argc = RARRAY(args)->len; - argv = RARRAY(args)->ptr; - } - PUSH_ITER(itr); - PUSH_FRAME(); - ruby_frame->callee = id; - ruby_frame->this_func = oid; - ruby_frame->this_class = (flags & NOEX_NOSUPER)?0:klass; - ruby_frame->self = recv; - ruby_frame->argc = argc; - ruby_frame->flags = (flags & NOEX_RECV) ? FRAME_FUNC : 0; + VALUE tmp; + VALUE *nargv; + argc = -argc-1; + tmp = splat_value(argv[argc]); + nargv = TMP_ALLOC(argc + RARRAY(tmp)->len); + MEMCPY(nargv, argv, VALUE, argc); + MEMCPY(nargv+argc, RARRAY(tmp)->ptr, VALUE, RARRAY(tmp)->len); + argc += RARRAY(tmp)->len; + argv = nargv; + } switch (nd_type(body)) { case NODE_CFUNC: { @@ -5672,6 +5713,7 @@ rb_call0(VALUE klass, VALUE recv, ID id, ID oid, rb_bug("bad argc (%d) specified for `%s(%s)'", len, rb_class2name(klass), rb_id2name(id)); } + PUSH_METHOD_FRAME(); if (event_hooks) { int state; @@ -5690,6 +5732,7 @@ rb_call0(VALUE klass, VALUE recv, ID id, ID oid, else { result = call_cfunc(body->nd_cfnc, recv, len, argc, argv); } + POP_FRAME(); } break; @@ -5708,12 +5751,14 @@ rb_call0(VALUE klass, VALUE recv, ID id, ID oid, break; case NODE_ZSUPER: /* visibility override */ - result = rb_call_super(argc, argv); + result = call_super_0(klass, recv, oid, argc, argv, block); break; case NODE_BMETHOD: + PUSH_METHOD_FRAME(); ruby_frame->flags |= FRAME_DMETH; result = proc_invoke(body->nd_cval, rb_ary_new4(argc, argv), recv, klass); + POP_FRAME(); break; case NODE_SCOPE: @@ -5722,12 +5767,12 @@ rb_call0(VALUE klass, VALUE recv, ID id, ID oid, VALUE *local_vars; /* OK */ NODE *saved_cref = 0; + PUSH_METHOD_FRAME(); PUSH_SCOPE(); if (body->nd_rval) { saved_cref = ruby_cref; ruby_cref = (NODE*)body->nd_rval; } - PUSH_CLASS(ruby_cbase); if (body->nd_tbl) { local_vars = TMP_ALLOC(body->nd_tbl[0]+1); *local_vars++ = (VALUE)body; @@ -5777,13 +5822,13 @@ rb_call0(VALUE klass, VALUE recv, ID id, ID oid, } POP_TAG(); POP_VARS(); - POP_CLASS(); POP_SCOPE(); ruby_cref = saved_cref; if (safe >= 0) ruby_safe_level = safe; if (event_hooks) { EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, body, recv, id, klass); } + POP_FRAME(); switch (state) { case 0: break; @@ -5807,14 +5852,13 @@ rb_call0(VALUE klass, VALUE recv, ID id, ID oid, unknown_node(body); break; } - POP_FRAME(); - POP_ITER(); return result; } static VALUE rb_call(VALUE klass, VALUE recv, ID mid, - int argc /* OK */, const VALUE *argv /* OK */, calling_scope_t scope) + int argc /* OK */, const VALUE *argv /* OK */, struct BLOCK *block, + calling_scope_t scope) { NODE *body; /* OK */ int noex; @@ -5823,13 +5867,14 @@ rb_call(VALUE klass, VALUE recv, ID mid, if (!klass) { rb_raise(rb_eNotImpError, "method `%s' called on terminated object (%p)", - rb_id2name(mid), recv); + rb_id2name(mid), (void*)recv); } /* is it in the method cache? */ ent = cache + EXPR1(klass, mid); if (ent->mid == mid && ent->klass == klass) { if (!ent->method) - return method_missing(recv, mid, argc, argv, scope==CALLING_VCALL?CSTAT_VCALL:0); + return method_missing(recv, mid, argc, argv, block, + scope==CALLING_VCALL?CSTAT_VCALL:0); klass = ent->origin; id = ent->mid0; noex = ent->noex; @@ -5837,15 +5882,15 @@ rb_call(VALUE klass, VALUE recv, ID mid, } else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) { if (scope == CALLING_SUPER) { - return method_missing(recv, mid, argc, argv, CSTAT_SUPER); + return method_missing(recv, mid, argc, argv, block, CSTAT_SUPER); } - return method_missing(recv, mid, argc, argv, scope==CALLING_VCALL?CSTAT_VCALL:0); + return method_missing(recv, mid, argc, argv, block, scope==CALLING_VCALL?CSTAT_VCALL:0); } if (mid != missing && scope == CALLING_NORMAL) { /* receiver specified form for private method */ if (noex & NOEX_PRIVATE) - return method_missing(recv, mid, argc, argv, CSTAT_PRIV); + return method_missing(recv, mid, argc, argv, block, CSTAT_PRIV); /* self must be kind of a specified form for protected method */ if (noex & NOEX_PROTECTED) { @@ -5855,13 +5900,13 @@ rb_call(VALUE klass, VALUE recv, ID mid, defined_class = RBASIC(defined_class)->klass; } if (!rb_obj_is_kind_of(ruby_frame->self, rb_class_real(defined_class))) - return method_missing(recv, mid, argc, argv, CSTAT_PROT); + return method_missing(recv, mid, argc, argv, block, CSTAT_PROT); } } if (scope > CALLING_NORMAL) { /* pass receiver info */ noex |= NOEX_RECV; } - return rb_call0(klass, recv, mid, id, argc, argv, body, noex); + return rb_call0(klass, recv, mid, id, argc, argv, block, body, noex); } VALUE @@ -5873,7 +5918,7 @@ rb_apply(VALUE recv, ID mid, VALUE args) argc = RARRAY(args)->len; /* Assigns LONG, but argc is INT */ argv = ALLOCA_N(VALUE, argc); MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc); - return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALLING_FCALL); + return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 0, CALLING_FCALL); } static VALUE @@ -5884,9 +5929,8 @@ send_funcall(int argc, VALUE *argv, VALUE recv, calling_scope_t scope) if (argc == 0) rb_raise(rb_eArgError, "no method name given"); vid = *argv++; argc--; - PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT); - vid = rb_call(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, scope); - POP_ITER(); + vid = rb_call(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, + ruby_frame->block, scope); return vid; } @@ -5917,8 +5961,14 @@ send_funcall(int argc, VALUE *argv, VALUE recv, calling_scope_t scope) static VALUE rb_f_send(int argc, VALUE *argv, VALUE recv) { - calling_scope_t scope = (ruby_frame->flags & FRAME_FUNC) ? CALLING_FCALL : CALLING_NORMAL; + calling_scope_t scope; + if (ruby_frame->flags & FRAME_FUNC) { + scope = CALLING_FCALL; + } + else { + scope = CALLING_NORMAL; + } return send_funcall(argc, argv, recv, scope); } @@ -5961,42 +6011,47 @@ rb_funcall(VALUE recv, ID mid, int n, ...) argv = 0; } - return rb_call(CLASS_OF(recv), recv, mid, n, argv, CALLING_FCALL); + return rb_call(CLASS_OF(recv), recv, mid, n, argv, 0, CALLING_FCALL); } VALUE rb_funcall2(VALUE recv, ID mid, int argc, const VALUE *argv) { - return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALLING_FCALL); + return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 0, CALLING_FCALL); } VALUE rb_funcall3(VALUE recv, ID mid, int argc, const VALUE *argv) { - return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALLING_NORMAL); + return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 0, CALLING_NORMAL); +} + +static VALUE +call_super_0(VALUE klass, VALUE self, ID mid, + int argc, const VALUE *argv, struct BLOCK *block) +{ + if (RCLASS(klass)->super == 0) { + return method_missing(self, mid, argc, argv, block, CSTAT_SUPER); + } + + return rb_call(RCLASS(klass)->super, self, mid, argc, argv, block, CALLING_SUPER); +} + +static VALUE +call_super(int argc, const VALUE *argv, struct BLOCK *block) +{ + if (ruby_frame->this_class == 0) { + rb_name_error(ruby_frame->callee, "calling `super' from `%s' is prohibited", + rb_id2name(ruby_frame->this_func)); + } + return call_super_0(ruby_frame->this_class, ruby_frame->self, + ruby_frame->this_func, argc, argv, block); } VALUE rb_call_super(int argc, const VALUE *argv) { - VALUE result, self, klass; - - if (ruby_frame->this_class == 0) { - rb_name_error(ruby_frame->callee, "calling `super' from `%s' is prohibited", - rb_id2name(ruby_frame->this_func)); - } - - self = ruby_frame->self; - klass = ruby_frame->this_class; - if (RCLASS(klass)->super == 0) { - return method_missing(self, ruby_frame->this_func, argc, argv, CSTAT_SUPER); - } - - PUSH_ITER(ruby_iter->iter ? ITER_PRE : ITER_NOT); - result = rb_call(RCLASS(klass)->super, self, ruby_frame->this_func, argc, argv, CALLING_SUPER); - POP_ITER(); - - return result; + return call_super(argc, argv, ruby_frame->block); } static VALUE @@ -6137,14 +6192,12 @@ eval(VALUE self, VALUE src, VALUE scope, const char *file, int line) struct BLOCK *data = NULL; volatile VALUE result = Qnil; struct SCOPE * volatile old_scope; - struct BLOCK * volatile old_block; struct RVarmap * volatile old_dyna_vars; VALUE volatile old_cref; int volatile old_vmode; volatile VALUE old_wrapper; struct FRAME frame; NODE *nodesave = ruby_current_node; - volatile int iter = ruby_frame->iter; volatile int safe = ruby_safe_level; int state; @@ -6161,8 +6214,6 @@ eval(VALUE self, VALUE src, VALUE scope, const char *file, int line) ruby_frame = &(frame); old_scope = ruby_scope; ruby_scope = data->scope; - old_block = ruby_block; - ruby_block = data->prev; old_dyna_vars = ruby_dyna_vars; ruby_dyna_vars = data->dyna_vars; old_vmode = scope_vmode; @@ -6178,22 +6229,15 @@ eval(VALUE self, VALUE src, VALUE scope, const char *file, int line) } self = data->self; - ruby_frame->iter = data->iter; - } - else { - if (ruby_frame->prev) { - ruby_frame->iter = ruby_frame->prev->iter; - } } if (file == 0) { ruby_set_current_source(); file = ruby_sourcefile; line = ruby_sourceline; } - PUSH_CLASS(ruby_cbase); ruby_in_eval++; - if (TYPE(ruby_class) == T_ICLASS) { - ruby_class = RBASIC(ruby_class)->klass; + if (TYPE(ruby_cbase) == T_ICLASS) { + ruby_cbase = RBASIC(ruby_cbase)->klass; } PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { @@ -6211,9 +6255,7 @@ eval(VALUE self, VALUE src, VALUE scope, const char *file, int line) result = eval_node(self, node); } POP_TAG(); - POP_CLASS(); ruby_in_eval--; - ruby_safe_level = safe; if (!NIL_P(scope)) { int dont_recycle = ruby_scope->flags & SCOPE_DONT_RECYCLE; @@ -6221,7 +6263,6 @@ eval(VALUE self, VALUE src, VALUE scope, const char *file, int line) ruby_cref = (NODE*)old_cref; ruby_frame = frame.tmp; ruby_scope = old_scope; - ruby_block = old_block; ruby_dyna_vars = old_dyna_vars; data->vmode = scope_vmode; /* write back visibility mode */ scope_vmode = old_vmode; @@ -6238,9 +6279,6 @@ eval(VALUE self, VALUE src, VALUE scope, const char *file, int line) } } } - else { - ruby_frame->iter = iter; - } ruby_current_node = nodesave; ruby_set_current_source(); if (state) { @@ -6315,7 +6353,7 @@ rb_f_eval(int argc, VALUE *argv, VALUE self) VALUE val; prev = ruby_frame; - PUSH_FRAME(); + PUSH_FRAME(Qfalse); *ruby_frame = *prev->prev; ruby_frame->prev = prev; val = eval(self, src, scope, file, line); @@ -6328,23 +6366,20 @@ rb_f_eval(int argc, VALUE *argv, VALUE self) /* function to call func under the specified class/module context */ static VALUE -exec_under(VALUE (*func) (VALUE), VALUE under, VALUE cbase, VALUE args) +exec_under(VALUE (*func) (VALUE), VALUE under, VALUE args) { VALUE val = Qnil; /* OK */ int state; int mode; struct FRAME *f = ruby_frame; - PUSH_CLASS(under); - PUSH_FRAME(); + PUSH_CREF(under); + PUSH_FRAME(Qtrue); ruby_frame->self = f->self; ruby_frame->callee = f->callee; ruby_frame->this_func = f->this_func; ruby_frame->this_class = f->this_class; ruby_frame->argc = f->argc; - if (cbase) { - PUSH_CREF(cbase); - } mode = scope_vmode; SCOPE_SET(SCOPE_PUBLIC); @@ -6353,10 +6388,9 @@ exec_under(VALUE (*func) (VALUE), VALUE under, VALUE cbase, VALUE args) val = (*func)(args); } POP_TAG(); - if (cbase) POP_CREF(); + POP_CREF(); SCOPE_SET(mode); POP_FRAME(); - POP_CLASS(); if (state) JUMP_TAG(state); return val; @@ -6390,7 +6424,7 @@ eval_under(VALUE under, VALUE self, VALUE src, const char *file, int line) args[1] = src; args[2] = (VALUE)file; args[3] = (VALUE)line; - return exec_under(eval_under_i, under, under, (VALUE)args); + return exec_under(eval_under_i, under, (VALUE)args); } static VALUE @@ -6402,7 +6436,7 @@ yield_under_i(VALUE arg) avalue = Qfalse; args[0] = args[1]; } - return rb_yield_0(args[0], args[1], ruby_class, YIELD_PUBLIC_DEF, avalue); + return rb_yield_0(args[0], args[1], ruby_cbase, YIELD_PUBLIC_DEF, avalue); } /* block eval under the class/module context */ @@ -6412,7 +6446,7 @@ yield_under(VALUE under, VALUE self, VALUE values) VALUE args[4]; args[0] = values; args[1] = self; - return exec_under(yield_under_i, under, 0, (VALUE)args); + return exec_under(yield_under_i, under, (VALUE)args); } static VALUE @@ -6605,22 +6639,19 @@ rb_load(VALUE fname, int wrap) ruby_errinfo = Qnil; /* ensure */ PUSH_VARS(); - PUSH_CLASS(ruby_wrapper); ruby_cref = top_cref; if (!wrap) { rb_secure(4); /* should alter global state */ - ruby_class = rb_cObject; ruby_wrapper = 0; } else { /* load in anonymous module as toplevel */ - ruby_class = ruby_wrapper = rb_module_new(); + ruby_wrapper = rb_module_new(); self = rb_obj_clone(ruby_top_self); rb_extend_object(self, ruby_wrapper); PUSH_CREF(ruby_wrapper); } - PUSH_ITER(ITER_NOT); - PUSH_FRAME(); + PUSH_FRAME(Qfalse); ruby_frame->callee = 0; ruby_frame->this_func = 0; ruby_frame->this_class = 0; @@ -6659,7 +6690,7 @@ rb_load(VALUE fname, int wrap) ruby_current_node = last_node; ruby_sourcefile = 0; ruby_set_current_source(); - if (ruby_scope->flags == SCOPE_ALLOCA && ruby_class == rb_cObject) { + if (ruby_scope->flags == SCOPE_ALLOCA && ruby_cbase == rb_cObject) { if (ruby_scope->local_tbl) /* toplevel was empty */ free(ruby_scope->local_tbl); } @@ -6668,8 +6699,6 @@ rb_load(VALUE fname, int wrap) ruby_cref = saved_cref; POP_SCOPE(); POP_FRAME(); - POP_ITER(); - POP_CLASS(); POP_VARS(); ruby_wrapper = wrapper; if (ruby_nerrs > 0) { @@ -7319,9 +7348,7 @@ rb_mod_include(int argc, VALUE *argv, VALUE module) void rb_obj_call_init(VALUE obj, int argc, VALUE *argv) { - PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT); - rb_funcall2(obj, init, argc, argv); - POP_ITER(); + rb_call(CLASS_OF(obj), obj, init, argc, argv, ruby_frame->block, CALLING_FCALL); } void @@ -7545,8 +7572,7 @@ rb_mark_end_proc(void) static void call_end_proc(VALUE data) { - PUSH_ITER(ITER_NOT); - PUSH_FRAME(); + PUSH_FRAME(Qfalse); ruby_frame->self = ruby_frame->prev->self; ruby_frame->node = 0; ruby_frame->callee = 0; @@ -7554,15 +7580,12 @@ call_end_proc(VALUE data) ruby_frame->this_class = 0; proc_invoke(data, rb_ary_new2(0), Qundef, 0); POP_FRAME(); - POP_ITER(); } static void rb_f_END(void) { - PUSH_FRAME(); - ruby_frame->argc = 0; - ruby_frame->iter = ITER_CUR; + PUSH_FRAME(Qfalse); rb_set_end_proc(call_end_proc, rb_block_proc()); POP_FRAME(); } @@ -7884,7 +7907,7 @@ blk_mark(struct BLOCK *data) rb_gc_mark((VALUE)data->cref); rb_gc_mark(data->wrapper); rb_gc_mark(data->block_obj); - data = data->prev; + data = data->frame.block; } } @@ -7909,7 +7932,7 @@ blk_free(struct BLOCK *data) while (data) { frame_free(&data->frame); tmp = data; - data = data->prev; + data = data->frame.block; free(tmp); } } @@ -7930,23 +7953,28 @@ frame_dup(struct FRAME *frame) } static void -blk_copy_prev(struct BLOCK *block) +dvar_nail_down(struct RVarmap *vars) +{ + while (vars) { + if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; + FL_SET(vars, DVAR_DONT_RECYCLE); + vars = vars->next; + } +} + +static void +blk_nail_down(struct BLOCK *block) { struct BLOCK *tmp; - struct RVarmap* vars; - while (block->prev) { + dvar_nail_down(block->dyna_vars); + while (block->frame.block) { tmp = ALLOC_N(struct BLOCK, 1); - MEMCPY(tmp, block->prev, struct BLOCK, 1); + MEMCPY(tmp, block->frame.block, struct BLOCK, 1); scope_dup(tmp->scope); frame_dup(&tmp->frame); - - for (vars = tmp->dyna_vars; vars; vars = vars->next) { - if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; - FL_SET(vars, DVAR_DONT_RECYCLE); - } - - block->prev = tmp; + dvar_nail_down(tmp->dyna_vars); + block->frame.block = tmp; block = tmp; } } @@ -7957,13 +7985,7 @@ blk_dup(struct BLOCK *dup, struct BLOCK *orig) { MEMCPY(dup, orig, struct BLOCK, 1); frame_dup(&dup->frame); - - if (dup->iter) { - blk_copy_prev(dup); - } - else { - dup->prev = 0; - } + blk_nail_down(dup); } /* @@ -7980,6 +8002,7 @@ proc_clone(VALUE self) bind = Data_Make_Struct(rb_obj_class(self),struct BLOCK,blk_mark,blk_free,data); CLONESETUP(bind, self); blk_dup(data, orig); + if (orig->block_obj) data->block_obj = bind; return bind; } @@ -8020,39 +8043,26 @@ proc_dup(VALUE self) static VALUE rb_f_binding(VALUE self) { - struct BLOCK *data, *p; - struct RVarmap *vars; + struct BLOCK *data; VALUE bind; - PUSH_BLOCK(0,0); + PUSH_FRAME(Qtrue); + PUSH_BLOCK(ruby_frame->block,0,0); bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data); - *data = *ruby_block; + *data = *ruby_frame->block; data->orig_thread = rb_thread_current(); data->wrapper = ruby_wrapper; - data->iter = rb_f_block_given_p(); frame_dup(&data->frame); if (ruby_frame->prev) { data->frame.callee = ruby_frame->prev->callee; data->frame.this_func = ruby_frame->prev->this_func; data->frame.this_class = ruby_frame->prev->this_class; } - - if (data->iter) { - blk_copy_prev(data); - } - else { - data->prev = 0; - } - - for (p = data; p; p = p->prev) { - for (vars = p->dyna_vars; vars; vars = vars->next) { - if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; - FL_SET(vars, DVAR_DONT_RECYCLE); - } - } + blk_nail_down(data); scope_dup(data->scope); POP_BLOCK(); + POP_FRAME(); return bind; } @@ -8094,12 +8104,14 @@ bind_eval(int argc, VALUE *argv, VALUE bind) #define SAFE_LEVEL_MAX PROC_TMASK #define proc_safe_level_p(data) (RBASIC(data)->flags & PROC_SAFE_SAVED) +#define proc_delete_safe_level(data) FL_UNSET(data, PROC_SAFE_SAVED) static void proc_save_safe_level(VALUE data) { int safe = ruby_safe_level; if (safe > PROC_TMAX) safe = PROC_TMAX; + FL_UNSET(data, PROC_TMASK); FL_SET(data, (safe << PROC_TSHIFT) & PROC_TMASK); FL_SET(data, PROC_SAFE_SAVED); } @@ -8118,55 +8130,48 @@ proc_set_safe_level(VALUE data) } static VALUE -proc_alloc(VALUE klass, int proc) +proc_alloc(VALUE klass, int lambda) { volatile VALUE block; - struct BLOCK *data, *p; - struct RVarmap *vars; + struct FRAME *frame = ruby_frame; + struct BLOCK *data; if (!rb_block_given_p() && !rb_f_block_given_p()) { rb_raise(rb_eArgError, "tried to create Proc object without a block"); } - if (proc && !rb_block_given_p()) { + if (!lambda) { + if (!rb_block_given_p()) { + frame = ruby_frame->prev; + } + else { + if (frame->block->block_obj) { + VALUE obj = frame->block->block_obj; + if (CLASS_OF(obj) != klass) { + obj = proc_clone(obj); + RBASIC(obj)->klass = klass; + } + return obj; + } + } + } + else if (!rb_block_given_p()) { rb_warn("tried to create Proc object without a block"); } - - if (!proc && ruby_block->block_obj) { - VALUE obj = ruby_block->block_obj; - if (CLASS_OF(obj) != klass) { - obj = proc_clone(obj); - RBASIC(obj)->klass = klass; - } - return obj; - } block = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data); - *data = *ruby_block; + *data = *frame->block; data->orig_thread = rb_thread_current(); data->wrapper = ruby_wrapper; - data->iter = data->prev?Qtrue:Qfalse; data->block_obj = block; frame_dup(&data->frame); - if (data->iter) { - blk_copy_prev(data); - } - else { - data->prev = 0; - } - - for (p = data; p; p = p->prev) { - for (vars = p->dyna_vars; vars; vars = vars->next) { - if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; - FL_SET(vars, DVAR_DONT_RECYCLE); - } - } + blk_nail_down(data); scope_dup(data->scope); proc_save_safe_level(block); - if (proc) { + if (lambda) { data->flags |= BLOCK_LAMBDA; } else { - ruby_block->block_obj = block; + frame->block->block_obj = block; } return block; @@ -8247,7 +8252,6 @@ block_orphan(struct BLOCK *data) static VALUE proc_invoke(VALUE proc, VALUE args /* OK */, VALUE self, VALUE klass) { - struct BLOCK * volatile old_block; struct BLOCK _block; struct BLOCK *data; volatile VALUE result = Qundef; @@ -8273,12 +8277,12 @@ proc_invoke(VALUE proc, VALUE args /* OK */, VALUE self, VALUE klass) ruby_wrapper = data->wrapper; ruby_dyna_vars = data->dyna_vars; /* PUSH BLOCK from data */ - old_block = ruby_block; _block = *data; _block.block_obj = bvar; if (self != Qundef) _block.frame.self = self; if (klass) _block.frame.this_class = klass; _block.frame.argc = RARRAY(tmp)->len; + if (ruby_frame->flags & FRAME_DMETH) if (_block.frame.argc && (ruby_frame->flags & FRAME_DMETH)) { NEWOBJ(scope, struct SCOPE); OBJSETUP(scope, tmp, T_SCOPE); @@ -8286,10 +8290,8 @@ proc_invoke(VALUE proc, VALUE args /* OK */, VALUE self, VALUE klass) scope->local_vars = _block.scope->local_vars; _block.scope = scope; } - ruby_block = &_block; - - PUSH_ITER(ITER_CUR); - ruby_frame->iter = ITER_CUR; + /* modify current frame */ + ruby_frame->block = &_block; PUSH_TAG((pcall&YIELD_LAMBDA_CALL) ? PROT_LAMBDA : PROT_NONE); state = EXEC_TAG(); if (state == 0) { @@ -8301,11 +8303,10 @@ proc_invoke(VALUE proc, VALUE args /* OK */, VALUE self, VALUE klass) result = prot_tag->retval; } POP_TAG(); - POP_ITER(); - ruby_block = old_block; ruby_wrapper = old_wrapper; POP_VARS(); - ruby_safe_level = safe; + if (proc_safe_level_p(proc)) + ruby_safe_level = safe; switch (state) { case 0: @@ -8555,13 +8556,7 @@ proc_binding(VALUE proc) bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data); MEMCPY(data, orig, struct BLOCK, 1); frame_dup(&data->frame); - - if (data->iter) { - blk_copy_prev(data); - } - else { - data->prev = 0; - } + blk_nail_down(data); return bind; } @@ -8578,9 +8573,7 @@ rb_block_pass(VALUE (*func) (VALUE), VALUE arg, VALUE proc) volatile int safe = ruby_safe_level; if (NIL_P(proc)) { - PUSH_ITER(ITER_NOT); result = (*func)(arg); - POP_ITER(); return result; } if (!rb_obj_is_proc(proc)) { @@ -8597,25 +8590,17 @@ rb_block_pass(VALUE (*func) (VALUE), VALUE arg, VALUE proc) rb_raise(rb_eSecurityError, "Insecure: tainted block value"); } - if (ruby_block && ruby_block->block_obj == proc) { - PUSH_ITER(ITER_PAS); - result = (*func)(arg); - POP_ITER(); - return result; + if (ruby_frame->block && ruby_frame->block->block_obj == proc) { + return (*func)(arg); } Data_Get_Struct(proc, struct BLOCK, data); orphan = block_orphan(data); - /* PUSH BLOCK from data */ + PUSH_FRAME(Qtrue); _block = *data; - _block.outer = ruby_block; if (orphan) _block.uniq = block_unique++; - ruby_block = &_block; - PUSH_ITER(ITER_PRE); - if (ruby_frame->iter == ITER_NOT) - ruby_frame->iter = ITER_PRE; - + ruby_frame->block = &_block; PUSH_TAG(PROT_LOOP); state = EXEC_TAG(); if (state == 0) { @@ -8634,8 +8619,7 @@ rb_block_pass(VALUE (*func) (VALUE), VALUE arg, VALUE proc) goto retry; } POP_TAG(); - POP_ITER(); - ruby_block = _block.outer; + POP_FRAME(); if (proc_safe_level_p(proc)) ruby_safe_level = safe; switch (state) {/* escape from orphan block */ @@ -8657,20 +8641,35 @@ struct block_arg { NODE *iter; }; -static VALUE -call_block(struct block_arg *arg) +static struct BLOCK * +passing_block(VALUE proc, struct BLOCK *blockp) { - return rb_eval(arg->self, arg->iter); -} + VALUE b; + struct BLOCK *data; + volatile int orphan; -static VALUE -block_pass(VALUE self, NODE *node) -{ - struct block_arg arg; - arg.self = self; - arg.iter = node->nd_iter; - return rb_block_pass((VALUE (*)(VALUE))call_block, - (VALUE)&arg, rb_eval(self, node->nd_body)); + if (NIL_P(proc)) return 0; + if (!rb_obj_is_proc(proc)) { + b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); + if (!rb_obj_is_proc(b)) { + rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)", + rb_obj_classname(proc)); + } + proc = b; + } + + if (ruby_safe_level >= 1 && OBJ_TAINTED(proc) && + ruby_safe_level > proc_get_safe_level(proc)) { + rb_raise(rb_eSecurityError, "Insecure: tainted block value"); + } + + Data_Get_Struct(proc, struct BLOCK, data); + orphan = block_orphan(data); + if (!orphan) return data; + + *blockp = *data; + if (orphan) blockp->uniq = block_unique++; + return blockp; } static void @@ -8944,9 +8943,8 @@ rb_method_call(int argc, VALUE *argv, VALUE method) else { safe = data->safe_level; } - PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT); - result = rb_call0(data->klass,data->recv,data->id,data->oid,argc,argv,data->body,safe); - POP_ITER(); + result = rb_call0(data->klass,data->recv,data->id,data->oid, + argc,argv,ruby_frame->block,data->body,safe); return result; } @@ -9230,13 +9228,8 @@ mproc(VALUE method) { VALUE proc; - /* emulate ruby's method call */ - PUSH_ITER(ITER_CUR); - PUSH_FRAME(); proc = rb_block_proc(); - POP_FRAME(); - POP_ITER(); - + proc_delete_safe_level(proc); return proc; } @@ -9380,7 +9373,7 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod) struct BLOCK *block; body = proc_clone(body); - proc_save_safe_level(body); + proc_delete_safe_level(body); Data_Get_Struct(body, struct BLOCK, block); block->frame.callee = id; block->frame.this_func = id; @@ -9761,7 +9754,6 @@ struct thread { struct BLOCK *block; struct iter *iter; struct tag *tag; - VALUE klass; VALUE wrapper; NODE *cref; struct ruby_env *anchor; @@ -9892,9 +9884,7 @@ rb_trap_eval(VALUE cmd, int sig, int safe) arg[2] = (VALUE)safe; THREAD_COPY_STATUS(curr_thread, &save); rb_thread_ready(curr_thread); - PUSH_ITER(ITER_NOT); val = rb_protect(run_trap_eval, (VALUE)&arg, &state); - POP_ITER(); THREAD_COPY_STATUS(&save, curr_thread); if (state) { @@ -9980,7 +9970,6 @@ thread_mark(rb_thread_t th) rb_gc_mark(th->thread); if (th->join) rb_gc_mark(th->join->thread); - rb_gc_mark(th->klass); rb_gc_mark(th->wrapper); rb_gc_mark((VALUE)th->cref); @@ -10027,7 +10016,7 @@ thread_mark(rb_thread_t th) while (block) { block = ADJ(block); rb_gc_mark_frame(&block->frame); - block = block->prev; + block = block->frame.block; } } @@ -10182,14 +10171,11 @@ rb_thread_save_context(rb_thread_t th) th->frame = ruby_frame; th->scope = ruby_scope; ruby_scope->flags |= SCOPE_DONT_RECYCLE; - th->klass = ruby_class; th->wrapper = ruby_wrapper; th->cref = ruby_cref; th->dyna_vars = ruby_dyna_vars; - th->block = ruby_block; th->flags &= THREAD_FLAGS_MASK; th->flags |= (rb_trap_immediate<<8) | scope_vmode; - th->iter = ruby_iter; th->tag = prot_tag; th->tracing = tracing; th->errinfo = ruby_errinfo; @@ -10263,13 +10249,10 @@ rb_thread_restore_context_0(rb_thread_t th, int exit, void *vp) rb_trap_immediate = 0; /* inhibit interrupts from here */ ruby_frame = th->frame; ruby_scope = th->scope; - ruby_class = th->klass; ruby_wrapper = th->wrapper; ruby_cref = th->cref; ruby_dyna_vars = th->dyna_vars; - ruby_block = th->block; scope_vmode = th->flags&SCOPE_MASK; - ruby_iter = th->iter; prot_tag = th->tag; tracing = th->tracing; ruby_errinfo = th->errinfo; @@ -10436,7 +10419,7 @@ rb_thread_deadlock(void) char msg[21+SIZEOF_LONG*2]; VALUE e; - sprintf(msg, "Thread(%p): deadlock", curr_thread->thread); + sprintf(msg, "Thread(%p): deadlock", (void*)curr_thread->thread); e = rb_exc_new2(rb_eFatal, msg); if (curr_thread == main_thread) { rb_exc_raise(e); @@ -10963,10 +10946,10 @@ rb_thread_join(rb_thread_t th, double limit) if (!rb_thread_dead(th)) { if (th == curr_thread) rb_raise(rb_eThreadError, "thread %p tried to join itself", - th->thread); + (void*)th->thread); if ((th->wait_for & WAIT_JOIN) && th->join == curr_thread) rb_raise(rb_eThreadError, "Thread#join: deadlock %p - mutual join(%p)", - curr_thread->thread, th->thread); + (void*)curr_thread->thread, (void*)th->thread); if (curr_thread->status == THREAD_TO_KILL) last_status = THREAD_TO_KILL; if (limit == 0) return Qfalse; @@ -11582,12 +11565,10 @@ rb_thread_group(VALUE thread) \ th->frame = 0;\ th->scope = 0;\ - th->klass = 0;\ th->wrapper = 0;\ th->cref = ruby_cref;\ th->dyna_vars = ruby_dyna_vars;\ th->block = 0;\ - th->iter = 0;\ th->tag = 0;\ th->tracing = 0;\ th->errinfo = Qnil;\ @@ -11717,9 +11698,7 @@ push_thread_anchor(struct ruby_env *ip) { ip->tag = prot_tag; ip->frame = ruby_frame; - ip->block = ruby_block; ip->scope = ruby_scope; - ip->iter = ruby_iter; ip->cref = ruby_cref; ip->prev = curr_thread->anchor; curr_thread->anchor = ip; @@ -11791,12 +11770,8 @@ rb_thread_start_0(VALUE (*fn)(ANYARGS), VALUE arg, rb_thread_t th) ruby_longjmp((prot_tag = ip->tag)->buf, TAG_THREAD); } - if (ruby_block) { /* should nail down higher blocks */ - struct BLOCK dummy; - - dummy.prev = ruby_block; - blk_copy_prev(&dummy); - saved_block = ruby_block = dummy.prev; + if (ruby_frame->block) { /* should nail down higher blocks */ + blk_nail_down(ruby_frame->block); } scope_dup(ruby_scope); @@ -11881,15 +11856,12 @@ rb_thread_start_1(void) int state; ruby_frame = ip->frame; - ruby_block = ip->block; ruby_scope = ip->scope; - ruby_iter = ip->iter; ruby_cref = ip->cref; ruby_dyna_vars = ((struct BLOCK *)DATA_PTR(proc))->dyna_vars; - PUSH_FRAME(); + PUSH_FRAME(Qtrue); *ruby_frame = *ip->frame; ruby_frame->prev = ip->frame; - ruby_frame->iter = ITER_CUR; PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { if (THREAD_SAVE_CONTEXT(th) == 0) { @@ -11923,7 +11895,7 @@ rb_thread_yield(VALUE arg, rb_thread_t th) { const ID *tbl; - scope_dup(ruby_block->scope); + scope_dup(ruby_frame->block->scope); tbl = ruby_scope->local_tbl; if (tbl) { @@ -11936,7 +11908,7 @@ rb_thread_yield(VALUE arg, rb_thread_t th) } rb_dvar_push('_', Qnil); rb_dvar_push('~', Qnil); - ruby_block->dyna_vars = ruby_dyna_vars; + ruby_frame->block->dyna_vars = ruby_dyna_vars; return rb_yield_0(arg, 0, 0, YIELD_LAMBDA_CALL, Qtrue); } @@ -12519,7 +12491,7 @@ rb_thread_inspect(VALUE thread) const char *status = thread_status_name(th->status); VALUE str; - str = rb_sprintf("#<%s:%p %s>", cname, thread, status); + str = rb_sprintf("#<%s:%p %s>", cname, (void*)thread, status); OBJ_INFECT(str, thread); return str; @@ -12999,16 +12971,12 @@ rb_f_catch(VALUE dmy, VALUE tag) return val; } -static VALUE -catch_i(VALUE tag) -{ - return rb_funcall(Qnil, rb_intern("catch"), 1, tag); -} - VALUE rb_catch(const char *tag, VALUE (*func)(ANYARGS), VALUE data) { - return rb_iterate((VALUE(*)(VALUE))catch_i, ID2SYM(rb_intern(tag)), func, data); + VALUE vtag = ID2SYM(rb_intern(tag)); + + return rb_block_call(Qnil, rb_intern("catch"), 1, &vtag, func, data); } /* diff --git a/ext/dbm/dbm.c b/ext/dbm/dbm.c index 5573cb415d..6e03e0eeeb 100644 --- a/ext/dbm/dbm.c +++ b/ext/dbm/dbm.c @@ -426,20 +426,10 @@ fdbm_invert(obj) return hash; } -static VALUE each_pair _((VALUE)); +static VALUE fdbm_store(VALUE,VALUE,VALUE); static VALUE -each_pair(obj) - VALUE obj; -{ - return rb_funcall(obj, rb_intern("each_pair"), 0, 0); -} - -static VALUE fdbm_store _((VALUE,VALUE,VALUE)); - -static VALUE -update_i(pair, dbm) - VALUE pair, dbm; +update_i(VALUE pair, VALUE dbm) { Check_Type(pair, T_ARRAY); if (RARRAY(pair)->len < 2) { @@ -450,19 +440,17 @@ update_i(pair, dbm) } static VALUE -fdbm_update(obj, other) - VALUE obj, other; +fdbm_update(VALUE obj, VALUE other) { - rb_iterate(each_pair, other, update_i, obj); + rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj); return obj; } static VALUE -fdbm_replace(obj, other) - VALUE obj, other; +fdbm_replace(VALUE obj, VALUE other) { fdbm_clear(obj); - rb_iterate(each_pair, other, update_i, obj); + rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj); return obj; } diff --git a/ext/gdbm/gdbm.c b/ext/gdbm/gdbm.c index a5d86e70af..cb59ff3c1e 100644 --- a/ext/gdbm/gdbm.c +++ b/ext/gdbm/gdbm.c @@ -530,13 +530,6 @@ fgdbm_invert(obj) static VALUE each_pair _((VALUE)); -static VALUE -each_pair(obj) - VALUE obj; -{ - return rb_funcall(obj, rb_intern("each_pair"), 0, 0); -} - static VALUE fgdbm_store _((VALUE,VALUE,VALUE)); static VALUE @@ -555,7 +548,7 @@ static VALUE fgdbm_update(obj, other) VALUE obj, other; { - rb_iterate(each_pair, other, update_i, obj); + rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj); return obj; } @@ -564,7 +557,7 @@ fgdbm_replace(obj, other) VALUE obj, other; { fgdbm_clear(obj); - rb_iterate(each_pair, other, update_i, obj); + rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj); return obj; } diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index cebbd912fe..37224d884b 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -522,7 +522,7 @@ get_iconv_opt(struct rb_iconv_opt_t *opt, VALUE options) opt->transliterate = Qundef; opt->discard_ilseq = Qundef; if (!NIL_P(options)) { - rb_iterate(rb_each, options, get_iconv_opt_i, (VALUE)opt); + rb_block_call(options, rb_intern("each"), 0, 0, get_iconv_opt_i, (VALUE)opt); } } diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index 8d6bd014ca..e374964211 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -678,7 +678,7 @@ static VALUE join_der(VALUE enumerable) { VALUE str = rb_str_new(0, 0); - rb_iterate(rb_each, enumerable, join_der_i, str); + rb_block_call(enumerable, rb_intern("each"), 0, 0, join_der_i, str); return str; } diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c index ef89fdfe0d..bf2db6b00e 100644 --- a/ext/openssl/ossl_config.c +++ b/ext/openssl/ossl_config.c @@ -246,7 +246,7 @@ static VALUE ossl_config_set_section(VALUE self, VALUE section, VALUE hash) { VALUE arg[2] = { self, section }; - rb_iterate(rb_each, hash, set_conf_section_i, (VALUE)arg); + rb_block_call(hash, rb_intern("each"), 0, 0, set_conf_section_i, (VALUE)arg); return hash; } diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c index 38a7dce7a2..0f6ffc0277 100644 --- a/ext/openssl/ossl_pkcs7.c +++ b/ext/openssl/ossl_pkcs7.c @@ -583,7 +583,7 @@ ossl_pkcs7_set_certificates(VALUE self, VALUE ary) certs = pkcs7_get_certs_or_crls(self, 1); while((cert = sk_X509_pop(certs))) X509_free(cert); - rb_iterate(rb_each, ary, ossl_pkcs7_set_certs_i, self); + rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_certs_i, self); return ary; } @@ -623,7 +623,7 @@ ossl_pkcs7_set_crls(VALUE self, VALUE ary) crls = pkcs7_get_certs_or_crls(self, 0); while((crl = sk_X509_CRL_pop(crls))) X509_CRL_free(crl); - rb_iterate(rb_each, ary, ossl_pkcs7_set_crls_i, self); + rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_crls_i, self); return ary; } diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 30ab5bdfe1..aab64771b4 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -324,7 +324,7 @@ ossl_sslctx_setup(VALUE self) val = ossl_sslctx_get_extra_cert(self); if(!NIL_P(val)){ - rb_iterate(rb_each, val, ossl_sslctx_add_extra_chain_cert_i, self); + rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self); } /* private key may be bundled in certificate file. */ diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c index 989e28a7e6..ece8bb8cef 100644 --- a/ext/openssl/ossl_x509name.c +++ b/ext/openssl/ossl_x509name.c @@ -125,7 +125,7 @@ ossl_x509name_initialize(int argc, VALUE *argv, VALUE self) VALUE args; if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE; args = rb_ary_new3(2, self, template); - rb_iterate(rb_each, tmp, ossl_x509name_init_i, args); + rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args); } else{ unsigned char *p; diff --git a/ext/sdbm/init.c b/ext/sdbm/init.c index f3e215e8d6..9311a7237d 100644 --- a/ext/sdbm/init.c +++ b/ext/sdbm/init.c @@ -406,13 +406,6 @@ fsdbm_invert(obj) static VALUE each_pair _((VALUE)); -static VALUE -each_pair(obj) - VALUE obj; -{ - return rb_funcall(obj, rb_intern("each_pair"), 0, 0); -} - static VALUE fsdbm_store _((VALUE,VALUE,VALUE)); static VALUE @@ -431,7 +424,7 @@ static VALUE fsdbm_update(obj, other) VALUE obj, other; { - rb_iterate(each_pair, other, update_i, obj); + rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj); return obj; } @@ -440,7 +433,7 @@ fsdbm_replace(obj, other) VALUE obj, other; { fsdbm_clear(obj); - rb_iterate(each_pair, other, update_i, obj); + rb_block_call(other, rb_intern("each_pair"), 0, 0, update_i, obj); return obj; } diff --git a/ext/socket/socket.c b/ext/socket/socket.c index d315526203..c29d4bc759 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -70,7 +70,7 @@ #endif #include "sockport.h" -static int do_not_reverse_lookup = 1; +static int do_not_reverse_lookup = 0; #define FMODE_NOREVLOOKUP 0x100 VALUE rb_cBasicSocket; diff --git a/ext/syck/rubyext.c b/ext/syck/rubyext.c index 078de4f78d..150ae14fca 100644 --- a/ext/syck/rubyext.c +++ b/ext/syck/rubyext.c @@ -571,7 +571,7 @@ yaml_org_handler( n, ref ) VALUE dup = rb_funcall( tmph, s_dup, 0 ); tmp = rb_ary_reverse( tmp ); rb_ary_push( tmp, obj ); - rb_iterate( rb_each, tmp, syck_merge_i, dup ); + rb_block_call(tmp, rb_intern("each"), 0, 0, syck_merge_i, dup); obj = dup; skip_aset = 1; } @@ -1006,7 +1006,7 @@ syck_resolver_node_import( self, node ) VALUE dup = rb_funcall( end, s_dup, 0 ); v = rb_ary_reverse( v ); rb_ary_push( v, obj ); - rb_iterate( rb_each, v, syck_merge_i, dup ); + rb_block_call(v, rb_intern("each"), 0, 0, syck_merge_i, dup); obj = dup; skip_aset = 1; } @@ -1175,7 +1175,7 @@ syck_resolver_transfer( self, type, val ) } else if ( !NIL_P( obj ) && rb_obj_is_instance_of( val, rb_cHash ) ) { - rb_iterate( rb_each, val, syck_set_ivars, obj ); + rb_block_call(val, rb_intern("each"), 0, 0, syck_set_ivars, obj); } } else diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c index fde5d2d456..2e6b49e9c3 100644 --- a/ext/win32ole/win32ole.c +++ b/ext/win32ole/win32ole.c @@ -2218,7 +2218,7 @@ ole_invoke(argc, argv, self, wFlags) op.dp.cArgs = cNamedArgs + argc - 2; op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1); op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs); - rb_iterate(rb_each, param, hash2named_arg, (VALUE)&op); + rb_block_call(param, rb_intern("each"), 0, 0, hash2named_arg, (VALUE)&op); pDispID = ALLOCA_N(DISPID, cNamedArgs + 1); op.pNamedArgs[0] = ole_mb2wc(StringValuePtr(cmd), -1); diff --git a/io.c b/io.c index 8e0a4e78f3..44e2a11211 100644 --- a/io.c +++ b/io.c @@ -5241,7 +5241,7 @@ argf_each_line(int argc, VALUE *argv, VALUE self) if (TYPE(current_file) != T_FILE) { for (;;) { if (!next_argv()) return argf; - rb_iterate(rb_each, current_file, rb_yield, 0); + rb_block_call(current_file, rb_intern("each"), 0, 0, rb_yield, 0); next_p = 1; } } diff --git a/lib/optparse.rb b/lib/optparse.rb index 0850ffd15e..6d1daeb6a0 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -1457,8 +1457,8 @@ class OptionParser : (({block})) yielded with the found value when succeeded. =end #'#"#`# - def search(id, k) - visit(:search, id, k) do |k| + def search(id, key) + visit(:search, id, key) do |k| return k unless block_given? return yield(k) end diff --git a/node.h b/node.h index 5022ac0995..7ee49317c1 100644 --- a/node.h +++ b/node.h @@ -336,7 +336,7 @@ typedef struct RNode { #define NEW_ERRINFO() NEW_NODE(NODE_ERRINFO,0,0,0) #define NEW_DEFINED(e) NEW_NODE(NODE_DEFINED,e,0,0) #define NEW_PREEXE(b) NEW_SCOPE(b) -#define NEW_POSTEXE() NEW_NODE(NODE_POSTEXE,0,0,0) +#define NEW_POSTEXE(b) NEW_NODE(NODE_POSTEXE,0,b,0) #define NEW_BMETHOD(b) NEW_NODE(NODE_BMETHOD,0,0,b) #define NEW_ATTRASGN(r,m,a) NEW_NODE(NODE_ATTRASGN,r,m,a) #define NEW_PRELUDE(p,b) NEW_NODE(NODE_PRELUDE,p,b,0) diff --git a/numeric.c b/numeric.c index b036d06421..3a0536e10b 100644 --- a/numeric.c +++ b/numeric.c @@ -2672,6 +2672,7 @@ fix_size(VALUE fix) static VALUE int_upto(VALUE from, VALUE to) { + RETURN_ENUMERATOR(from, 1, &to); if (FIXNUM_P(from) && FIXNUM_P(to)) { long i, end; @@ -2710,6 +2711,7 @@ int_upto(VALUE from, VALUE to) static VALUE int_downto(VALUE from, VALUE to) { + RETURN_ENUMERATOR(from, 1, &to); if (FIXNUM_P(from) && FIXNUM_P(to)) { long i, end; @@ -2749,6 +2751,7 @@ int_downto(VALUE from, VALUE to) static VALUE int_dotimes(VALUE num) { + RETURN_ENUMERATOR(num, 0, 0); if (FIXNUM_P(num)) { long i, end; diff --git a/parse.y b/parse.y index 2b8af2f279..41de56b9d5 100644 --- a/parse.y +++ b/parse.y @@ -867,7 +867,7 @@ stmt : kALIAS fitem {lex_state = EXPR_FNAME;} fitem rb_warn("END in method; use at_exit"); } - $$ = NEW_ITER(0, NEW_POSTEXE(), $3); + $$ = NEW_POSTEXE($3); /*% if (in_def || in_single) { rb_warn0("END in method; use at_exit"); diff --git a/ruby.h b/ruby.h index 50ebea3d29..7a91b87d32 100644 --- a/ruby.h +++ b/ruby.h @@ -575,6 +575,7 @@ VALUE rb_yield_splat(VALUE); int rb_block_given_p(void); void rb_need_block(void); VALUE rb_iterate(VALUE(*)(VALUE),VALUE,VALUE(*)(ANYARGS),VALUE); +VALUE rb_iterate_method(VALUE,ID,VALUE,VALUE(*)(ANYARGS),VALUE); VALUE rb_rescue(VALUE(*)(ANYARGS),VALUE,VALUE(*)(ANYARGS),VALUE); VALUE rb_rescue2(VALUE(*)(ANYARGS),VALUE,VALUE(*)(ANYARGS),VALUE,...); VALUE rb_ensure(VALUE(*)(ANYARGS),VALUE,VALUE(*)(ANYARGS),VALUE); diff --git a/struct.c b/struct.c index 1cc4d38b08..9a709082f7 100644 --- a/struct.c +++ b/struct.c @@ -667,21 +667,15 @@ rb_struct_values_at(int argc, VALUE *argv, VALUE s) /* * call-seq: - * struct.select(fixnum, ... ) => array * struct.select {|i| block } => array * - * The first form returns an array containing the elements in - * struct corresponding to the given indices. The second - * form invokes the block passing in successive elements from + * Invokes the block passing in successive elements from * struct, returning an array containing those elements * for which the block returns a true value (equivalent to * Enumerable#select). * * Lots = Struct.new(:a, :b, :c, :d, :e, :f) * l = Lots.new(11, 22, 33, 44, 55, 66) - * l.select(1, 3, 5) #=> [22, 44, 66] - * l.select(0, 2, 4) #=> [11, 33, 55] - * l.select(-1, -3, -5) #=> [66, 44, 22] * l.select {|v| (v % 2).zero? } #=> [22, 44, 66] */ diff --git a/test/ruby/envutil.rb b/test/ruby/envutil.rb index cd9ad3c858..cf7f6e9887 100644 --- a/test/ruby/envutil.rb +++ b/test/ruby/envutil.rb @@ -1,11 +1,18 @@ module EnvUtil def rubybin + unless ENV["RUBYOPT"] + + end if ruby = ENV["RUBY"] return ruby end ruby = "ruby" + rubyexe = ruby+".exe" 3.times do - if File.exist? ruby or File.exist? ruby+".exe" + if File.exist? ruby and File.executable? ruby and !File.directory? ruby + return File.expand_path(ruby) + end + if File.exist? rubyexe and File.executable? rubyexe return File.expand_path(ruby) end ruby = File.join("..", ruby) diff --git a/test/webrick/test_filehandler.rb b/test/webrick/test_filehandler.rb index 703fde4d9a..64b2fcf231 100644 --- a/test/webrick/test_filehandler.rb +++ b/test/webrick/test_filehandler.rb @@ -9,7 +9,11 @@ class WEBrick::TestFileHandler < Test::Unit::TestCase end def get_res_body(res) - return res.body.read rescue res.body + if defined? res.body.read + res.body.read + else + res.body + end end def make_range_request(range_spec)