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

ruby-changes:47243

From: nobu <ko1@a...>
Date: Tue, 18 Jul 2017 17:31:14 +0900 (JST)
Subject: [ruby-changes:47243] nobu:r59358 (trunk): vm_eval.c: rb_lambda_call

nobu	2017-07-18 17:31:02 +0900 (Tue, 18 Jul 2017)

  New Revision: 59358

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

  Log:
    vm_eval.c: rb_lambda_call
    
    * enum.c (enum_collect): make the block arity same as the given
      block.  [Bug #13391]
    
    * internal.h (vm_ifunc): store arity instead of unused id.
    
    * proc.c (rb_vm_block_min_max_arity): return ifunc arity.
    
    * vm_eval.c (rb_lambda_call): call method with lambda block.

  Modified files:
    trunk/enum.c
    trunk/internal.h
    trunk/proc.c
    trunk/test/ruby/test_enum.rb
    trunk/vm_eval.c
Index: internal.h
===================================================================
--- internal.h	(revision 59357)
+++ internal.h	(revision 59358)
@@ -906,15 +906,30 @@ struct vm_throw_data { https://github.com/ruby/ruby/blob/trunk/internal.h#L906
 
 /* IFUNC */
 
+struct vm_ifunc_argc {
+#if SIZEOF_INT * 2 > SIZEOF_VALUE
+    int min: (SIZEOF_VALUE * CHAR_BIT) / 2;
+    int max: (SIZEOF_VALUE * CHAR_BIT) / 2;
+#else
+    int min, max;
+#endif
+};
+
 struct vm_ifunc {
     VALUE flags;
     VALUE reserved;
     VALUE (*func)(ANYARGS);
     const void *data;
-    ID id;
+    struct vm_ifunc_argc argc;
 };
 
 #define IFUNC_NEW(a, b, c) ((struct vm_ifunc *)rb_imemo_new(imemo_ifunc, (VALUE)(a), (VALUE)(b), (VALUE)(c), 0))
+struct vm_ifunc *rb_vm_ifunc_new(VALUE (*func)(ANYARGS), const void *data, int min_argc, int max_argc);
+static inline struct vm_ifunc *
+rb_vm_ifunc_proc_new(VALUE (*func)(ANYARGS), const void *data)
+{
+    return rb_vm_ifunc_new(func, data, 0, UNLIMITED_ARGUMENTS);
+}
 
 /* MEMO */
 
@@ -1479,7 +1494,7 @@ st_index_t rb_hash_proc(st_index_t hash, https://github.com/ruby/ruby/blob/trunk/internal.h#L1494
 int rb_block_arity(void);
 int rb_block_min_max_arity(int *max);
 VALUE rb_func_proc_new(rb_block_call_func_t func, VALUE val);
-VALUE rb_func_lambda_new(rb_block_call_func_t func, VALUE val);
+VALUE rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc);
 
 /* process.c */
 #define RB_MAX_GROUPS (65536)
@@ -1743,6 +1758,9 @@ VALUE rb_check_funcall_with_hook(VALUE r https://github.com/ruby/ruby/blob/trunk/internal.h#L1758
 VALUE rb_check_funcall_default(VALUE, ID, int, const VALUE *, VALUE);
 VALUE rb_yield_1(VALUE val);
 VALUE rb_yield_force_blockarg(VALUE values);
+VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
+		     rb_block_call_func_t bl_proc, int min_argc, int max_argc,
+		     VALUE data2);
 
 /* vm_insnhelper.c */
 VALUE rb_equal_opt(VALUE obj1, VALUE obj2);
Index: enum.c
===================================================================
--- enum.c	(revision 59357)
+++ enum.c	(revision 59358)
@@ -494,11 +494,13 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/enum.c#L494
 enum_collect(VALUE obj)
 {
     VALUE ary;
+    int min_argc, max_argc;
 
     RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
 
     ary = rb_ary_new();
-    rb_block_call(obj, id_each, 0, 0, collect_i, ary);
+    min_argc = rb_block_min_max_arity(&max_argc);
+    rb_lambda_call(obj, id_each, 0, 0, collect_i, min_argc, max_argc, ary);
 
     return ary;
 }
Index: test/ruby/test_enum.rb
===================================================================
--- test/ruby/test_enum.rb	(revision 59357)
+++ test/ruby/test_enum.rb	(revision 59358)
@@ -837,6 +837,10 @@ class TestEnumerable < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enum.rb#L837
     lambda2 = ->(x, i) { [x.upcase, i] }
     assert_equal([['A',0], ['B',1], ['C',2], ['D',3], ['E',4]],
       @obj.each_with_index.map(&lambda2))
+
+    hash = { a: 'hoge', b: 'fuga' }
+    lambda = -> (k, v) { "#{k}:#{v}" }
+    assert_equal ["a:hoge", "b:fuga"], hash.map(&lambda)
   end
 
   def test_flat_map
Index: proc.c
===================================================================
--- proc.c	(revision 59357)
+++ proc.c	(revision 59358)
@@ -637,16 +637,47 @@ sym_proc_new(VALUE klass, VALUE sym) https://github.com/ruby/ruby/blob/trunk/proc.c#L637
     return procval;
 }
 
+struct vm_ifunc *
+rb_vm_ifunc_new(VALUE (*func)(ANYARGS), const void *data, int min_argc, int max_argc)
+{
+    union {
+	struct vm_ifunc_argc argc;
+	VALUE packed;
+    } arity;
+
+    if (min_argc < UNLIMITED_ARGUMENTS ||
+#if SIZEOF_INT * 2 > SIZEOF_VALUE
+	min_argc >= (int)(1U << (SIZEOF_VALUE * CHAR_BIT) / 2) ||
+#endif
+	0) {
+	rb_raise(rb_eRangeError, "minimum argument number out of range: %d",
+		 min_argc);
+    }
+    if (max_argc < UNLIMITED_ARGUMENTS ||
+#if SIZEOF_INT * 2 > SIZEOF_VALUE
+	max_argc >= (int)(1U << (SIZEOF_VALUE * CHAR_BIT) / 2) ||
+#endif
+	0) {
+	rb_raise(rb_eRangeError, "maximum argument number out of range: %d",
+		 max_argc);
+    }
+    arity.argc.min = min_argc;
+    arity.argc.max = max_argc;
+    return IFUNC_NEW(func, data, arity.packed);
+}
+
 VALUE
 rb_func_proc_new(rb_block_call_func_t func, VALUE val)
 {
-    return cfunc_proc_new(rb_cProc, (VALUE)IFUNC_NEW(func, val, 0), 0);
+    struct vm_ifunc *ifunc = rb_vm_ifunc_proc_new(func, (void *)val);
+    return cfunc_proc_new(rb_cProc, (VALUE)ifunc, 0);
 }
 
 VALUE
-rb_func_lambda_new(rb_block_call_func_t func, VALUE val)
+rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc)
 {
-    return cfunc_proc_new(rb_cProc, (VALUE)IFUNC_NEW(func, val, 0), 1);
+    struct vm_ifunc *ifunc = rb_vm_ifunc_new(func, (void *)val, min_argc, max_argc);
+    return cfunc_proc_new(rb_cProc, (VALUE)ifunc, 1);
 }
 
 static const char proc_without_block[] = "tried to create Proc object without a block";
@@ -946,8 +977,9 @@ rb_vm_block_min_max_arity(const struct r https://github.com/ruby/ruby/blob/trunk/proc.c#L977
 		/* e.g. method(:foo).to_proc.arity */
 		return method_min_max_arity((VALUE)ifunc->data, max);
 	    }
+	    *max = ifunc->argc.max;
+	    return ifunc->argc.min;
 	}
-	/* fall through */
       case block_type_symbol:
 	break;
     }
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 59357)
+++ vm_eval.c	(revision 59358)
@@ -1159,7 +1159,7 @@ rb_iterate(VALUE (* it_proc)(VALUE), VAL https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1159
 	   VALUE (* bl_proc)(ANYARGS), VALUE data2)
 {
     return rb_iterate0(it_proc, data1,
-		       bl_proc ? IFUNC_NEW(bl_proc, data2, rb_frame_this_func()) : 0,
+		       bl_proc ? rb_vm_ifunc_proc_new(bl_proc, (void *)data2) : 0,
 		       GET_THREAD());
 }
 
@@ -1192,6 +1192,23 @@ rb_block_call(VALUE obj, ID mid, int arg https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1192
     return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2);
 }
 
+VALUE
+rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
+	       rb_block_call_func_t bl_proc, int min_argc, int max_argc,
+	       VALUE data2)
+{
+    struct iter_method_arg arg;
+    struct vm_ifunc *block;
+
+    if (!bl_proc) rb_raise(rb_eArgError, "NULL lambda function");
+    arg.obj = obj;
+    arg.mid = mid;
+    arg.argc = argc;
+    arg.argv = argv;
+    block = rb_vm_ifunc_new(bl_proc, (void *)data2, min_argc, max_argc);
+    return rb_iterate0(iterate_method, (VALUE)&arg, block, GET_THREAD());
+}
+
 static VALUE
 iterate_check_method(VALUE obj)
 {

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

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