summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--bootstraptest/test_method.rb58
-rw-r--r--vm_insnhelper.c15
3 files changed, 79 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index e687321c67..78d6ea9d4d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Tue Nov 13 17:28:47 2012 Koichi Sasada <ko1@atdot.net>
+
+ * vm_insnhelper.c (vm_caller_setup_args): save and restore
+ ci->argc and ci->blockptr before and after method invocations
+ because these method dispatches override call_info.
+
+ * bootstraptest/test_method.rb: add tests for this fix.
+
Tue Nov 13 16:38:02 2012 NARUSE, Yui <naruse@ruby-lang.org>
* common.mk (dmyprobes.h): always create for make dist.
diff --git a/bootstraptest/test_method.rb b/bootstraptest/test_method.rb
index d6b8c0ea24..ed22608aea 100644
--- a/bootstraptest/test_method.rb
+++ b/bootstraptest/test_method.rb
@@ -1204,3 +1204,61 @@ assert_equal 'ok', %q{
'ok'
end
}
+
+assert_equal 'DC', %q{
+ $result = []
+
+ class C
+ def foo *args
+ $result << 'C'
+ end
+ end
+ class D
+ def foo *args
+ $result << 'D'
+ end
+ end
+
+ o1 = $o1 = C.new
+ o2 = $o2 = D.new
+
+ args = Object.new
+ def args.to_a
+ test1 $o2, nil
+ []
+ end
+ def test1 o, args
+ o.foo(*args)
+ end
+ test1 o1, args
+ $result.join
+}
+
+assert_equal 'DC', %q{
+ $result = []
+
+ class C
+ def foo *args
+ $result << 'C'
+ end
+ end
+ class D
+ def foo *args
+ $result << 'D'
+ end
+ end
+
+ o1 = $o1 = C.new
+ o2 = $o2 = D.new
+
+ block = Object.new
+ def block.to_proc
+ test2 $o2, %w(a, b, c), nil
+ Proc.new{}
+ end
+ def test2 o, args, block
+ o.foo(*args, &block)
+ end
+ test2 o1, [], block
+ $result.join
+}
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 32b0851320..3e1ca3866c 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1036,6 +1036,12 @@ vm_base_ptr(rb_control_frame_t *cfp)
static void
vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
{
+#define SAVE_RESTORE_CI(expr, ci) do { \
+ int saved_argc = (ci)->argc; rb_block_t *saved_blockptr = (ci)->blockptr; /* save */ \
+ expr; \
+ (ci)->argc = saved_argc; (ci)->blockptr = saved_blockptr; /* restore */ \
+} while (0)
+
if (UNLIKELY(ci->flag & VM_CALL_ARGS_BLOCKARG)) {
rb_proc_t *po;
VALUE proc;
@@ -1044,7 +1050,10 @@ vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_inf
if (proc != Qnil) {
if (!rb_obj_is_proc(proc)) {
- VALUE b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
+ VALUE b;
+
+ SAVE_RESTORE_CI(b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"), ci);
+
if (NIL_P(b) || !rb_obj_is_proc(b)) {
rb_raise(rb_eTypeError,
"wrong argument type %s (expected Proc)",
@@ -1069,7 +1078,9 @@ vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_inf
VALUE ary = *(cfp->sp - 1);
VALUE *ptr;
int i;
- VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a");
+ VALUE tmp;
+
+ SAVE_RESTORE_CI(tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"), ci);
if (NIL_P(tmp)) {
/* do nothing */