diff --git a/ChangeLog b/ChangeLog index 5b818b9793..09f2f8dc6a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Sun Jun 24 17:28:52 2007 Koichi Sasada + + * insnhelper.h: change CHECK_STACK_OVERFLOW() to throw exception. + + * vm.c (caller_setup_arg), vm_macro.def: remove + macro_eval_setup_send_arguments and add caller_setup_arg(). + + * insns.def: ditto. + + * bootstraptest/test_method.rb: add splat arg tests. + Sun Jun 24 16:35:46 2007 Nobuyoshi Nakada * proc.c (proc_to_s): used a variable before initialized. diff --git a/bootstraptest/test_method.rb b/bootstraptest/test_method.rb index 342803e21b..faf3d4bc58 100644 --- a/bootstraptest/test_method.rb +++ b/bootstraptest/test_method.rb @@ -318,6 +318,33 @@ assert_equal '1', %q( class C; def m() 7 end; private :m end assert_equal '1', %q( class C; def m() 1 end; private :m end C.new.funcall(:m) ) +# splat and block arguments +assert_equal %q{[[[:x, :y, :z], NilClass], [[1, :x, :y, :z], NilClass], [[1, 2, :x, :y, :z], NilClass], [[:obj], NilClass], [[1, :obj], NilClass], [[1, 2, :obj], NilClass], [[], Proc], [[1], Proc], [[1, 2], Proc], [[], Proc], [[1], Proc], [[1, 2], Proc], [[:x, :y, :z], Proc], [[1, :x, :y, :z], Proc], [[1, 2, :x, :y, :z], Proc]]}, %q{ +def m(*args, &b) + $result << [args, b.class] +end +$result = [] +ary = [:x, :y, :z] +obj = :obj +b = Proc.new{} + +m(*ary) +m(1,*ary) +m(1,2,*ary) +m(*obj) +m(1,*obj) +m(1,2,*obj) +m(){} +m(1){} +m(1,2){} +m(&b) +m(1,&b) +m(1,2,&b) +m(*ary,&b) +m(1,*ary,&b) +m(1,2,*ary,&b) +$result +} # post test assert_equal %q{[1, 2, :o1, :o2, [], 3, 4, NilClass, nil, nil]}, %q{ diff --git a/insnhelper.h b/insnhelper.h index eb6b3ef21b..2eb071df5f 100644 --- a/insnhelper.h +++ b/insnhelper.h @@ -127,8 +127,11 @@ #define GET_BLOCK_PTR() \ ((rb_block_t *)(GC_GUARDED_PTR_REF(GET_LFP()[0]))) -#define CHECK_STACK_OVERFLOW(th, cfp, margin) \ - (((VALUE *)(cfp)->sp) + (margin) >= ((VALUE *)cfp)) +#define CHECK_STACK_OVERFLOW(cfp, margin) do \ + if (((VALUE *)(cfp)->sp) + (margin) >= ((VALUE *)cfp)) { \ + rb_exc_raise(sysstack_error); \ + } \ +while (0) /**********************************************************/ /* deal with control flow 3: exception */ diff --git a/insns.def b/insns.def index 91607ef952..792c8d40f1 100644 --- a/insns.def +++ b/insns.def @@ -1156,11 +1156,11 @@ send VALUE recv; VALUE klass; rb_block_t *blockptr = 0; - rb_num_t num = op_argc; + rb_num_t num; rb_num_t flag = op_flag; ID id = op_id; - macro_eval_setup_send_arguments(num, blockptr, flag, blockiseq); + num = caller_setup_args(th, GET_CFP(), flag, op_argc, blockiseq, &blockptr); if (flag & VM_CALL_FCALL_BIT) { /* method(...) */ @@ -1298,9 +1298,8 @@ invokesuper /* TODO: */ rb_bug("..."); #else - tmp_num = op_argc; tmp_blockptr = 0; - macro_eval_setup_send_arguments(tmp_num, tmp_blockptr, flag, blockiseq); + tmp_num = caller_setup_args(th, GET_CFP(), flag, op_argc, blockiseq, &tmp_blockptr); if (!tmp_blockptr && !(flag & VM_CALL_ARGS_BLOCKARG_BIT)) { tmp_blockptr = GET_BLOCK_PTR(); } @@ -1329,25 +1328,7 @@ invokeblock iseq = block->iseq; if (BUILTIN_TYPE(iseq) != T_NODE) { - if (flag & VM_CALL_ARGS_SPLAT_BIT) { - VALUE ary = TOPN(0); - ary = rb_check_convert_type(ary, T_ARRAY, "Array", "to_splat"); - - if (NIL_P(ary)) { - /* not a [BUG] */ - } - else { - VALUE *ptr = RARRAY_PTR(ary); - VALUE *dst = GET_SP() - 1; - int i, len = RARRAY_LEN(ary); - - for (i = 0; i < len; i++) { - dst[i] = ptr[i]; - } - argc += i - 1; - INC_SP(i - 1); - } - } + argc = caller_setup_args(th, GET_CFP(), flag, argc, 0, 0); DEC_SP(argc); argc = th_yield_setup_args(th, iseq, argc, GET_SP(), diff --git a/vm.c b/vm.c index 376b5efc15..f4e37d28a7 100644 --- a/vm.c +++ b/vm.c @@ -282,6 +282,68 @@ callee_setup_arg(rb_thread_t *th, rb_iseq_t *iseq, } } +static inline int +caller_setup_args(rb_thread_t *th, rb_control_frame_t *cfp, + VALUE flag, int argc, rb_iseq_t *blockiseq, rb_block_t **block) +{ + rb_block_t *blockptr = 0; + + if (flag & VM_CALL_ARGS_BLOCKARG_BIT) { + rb_proc_t *po; + VALUE proc; + + proc = *(--cfp->sp); + + if (proc != Qnil) { + if (!rb_obj_is_proc(proc)) { + proc = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); + if (!rb_obj_is_proc(proc)) { + rb_raise(rb_eTypeError, + "wrong argument type %s (expected Proc)", + rb_obj_classname(proc)); + } + } + GetProcPtr(proc, po); + blockptr = &po->block; + RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc; + *block = blockptr; + } + } + else if (blockiseq) { + blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); + blockptr->iseq = blockiseq; + blockptr->proc = 0; + *block = blockptr; + } + + /* expand top of stack? */ + if (flag & VM_CALL_ARGS_SPLAT_BIT) { + VALUE ary = *(cfp->sp - 1); + VALUE *ptr, *dst; + int i; + VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_splat"); + + if (NIL_P(tmp)) { + /* do nothing */ + } + else { + int len = RARRAY_LEN(tmp); + ptr = RARRAY_PTR(tmp); + cfp->sp -= 1; + + CHECK_STACK_OVERFLOW(cfp, len); + + for (i = 0; i < len; i++) { + *cfp->sp++ = ptr[i]; + } + argc += i-1; + } + } + + return argc; +} + + /* Env */ static void diff --git a/vm_macro.def b/vm_macro.def index 99351efdc5..0d635c55fe 100644 --- a/vm_macro.def +++ b/vm_macro.def @@ -2,57 +2,6 @@ /* do not use C++ style comment */ /* */ -MACRO macro_eval_setup_send_arguments(num, blockptr, flag, blockiseq) -{ - if (flag & VM_CALL_ARGS_BLOCKARG_BIT) { - rb_proc_t *po; - VALUE proc; - - proc = TOPN(0); - if (proc != Qnil) { - if (!rb_obj_is_proc(proc)) { - proc = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); - if (!rb_obj_is_proc(proc)) { - rb_raise(rb_eTypeError, - "wrong argument type %s (expected Proc)", - rb_obj_classname(proc)); - } - } - GetProcPtr(proc, po); - blockptr = &po->block; - RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp)->proc = proc; - } - INC_SP(-1); - } - else if (blockiseq) { - blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp); - blockptr->iseq = blockiseq; - blockptr->proc = 0; - } - - /* expand top of stack? */ - if (flag & VM_CALL_ARGS_SPLAT_BIT) { - VALUE ary = TOPN(0); - VALUE *ptr, *dst; - int i; - VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_splat"); - - if (NIL_P(tmp)) { - tmp = rb_ary_new3(1, ary); - } - ary = tmp; - - ptr = RARRAY_PTR(ary); - dst = GET_SP() - 1; - for (i = 0; i < RARRAY_LEN(ary); i++) { - dst[i] = ptr[i]; - } - num += i - 1; - INC_SP(i - 1); - } -} - - MACRO macro_eval_invoke_cfunc(num, id, recv, klass, mn, blockptr) { EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); @@ -93,9 +42,7 @@ MACRO macro_eval_invoke_func(niseqval, recv, klass, blockptr, num) sp = rsp + niseq->arg_size; /* stack overflow check */ - if (CHECK_STACK_OVERFLOW(th, GET_CFP(), niseq->stack_max + 0x100)) { - rb_exc_raise(sysstack_error); - } + CHECK_STACK_OVERFLOW(GET_CFP(), niseq->stack_max + 0x10); if (flag & VM_CALL_TAILCALL_BIT) { /* copy arguments */