/* -*- c -*- */ /* 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); { rb_control_frame_t *cfp = push_frame(th, 0, FRAME_MAGIC_CFUNC, recv, (VALUE) blockptr, 0, GET_SP(), 0, 1); cfp->method_id = id; cfp->method_klass = klass; reg_cfp->sp -= num + 1; val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num, reg_cfp->sp + 1); if (reg_cfp != th->cfp + 1) { SDR2(reg_cfp); SDR2(th->cfp-5); rb_bug("cfp consistency error - send"); th->cfp = reg_cfp; } pop_frame(th); } EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); } MACRO macro_eval_invoke_func(niseqval, recv, klass, blockptr, num) { rb_iseq_t *niseq; VALUE *sp = GET_SP(); VALUE *rsp = sp - num - 1; int opt_pc = 0, clear_local_size, i; /* TODO: eliminate it */ GetISeqPtr(niseqval, niseq); clear_local_size = niseq->local_size - num; /* simple (only mandatory) arguments */ if (niseq->arg_simple) { if (niseq->argc != num) { rb_raise(rb_eArgError, "%d - wrong number of arguments (%lu for %d)", 0, (unsigned long)num, niseq->argc); } } else { /* optional arguments */ if (niseq->arg_opts) { int iseq_argc = niseq->argc; int opts = niseq->arg_opts - 1; if (num < iseq_argc || (niseq->arg_rest == -1 && num > iseq_argc + opts)) { if (0) { printf("num: %lu, iseq_argc: %d, opts: %d\n", (unsigned long)num, iseq_argc, opts); } rb_raise(rb_eArgError, "%d - wrong number of arguments (%lu for %d)", 1, (unsigned long)num, iseq_argc); } if (0) printf("num: %lu, opts: %d, iseq_argc: %d\n", (unsigned long)num, opts, iseq_argc); if (num - iseq_argc < opts) { opt_pc = niseq->arg_opt_tbl[num - iseq_argc]; sp += opts - (num - iseq_argc); num += opts - (num - iseq_argc); clear_local_size = niseq->local_size - (iseq_argc + opts); } else { opt_pc = niseq->arg_opt_tbl[opts]; } } /* rest argument */ if (niseq->arg_rest != -1) { int rest = niseq->arg_rest - 1 /* spec val */; int pack_size = num - rest; if (0) { printf("num: %lu, rest: %d, ps: %d\n", (unsigned long)num, rest, pack_size); } if (pack_size < 0) { rb_raise(rb_eArgError, "%d - wrong number of arguments (%lu for %d)", 2, (unsigned long)num, rest - niseq->arg_opts); } /* * def m(x, y, z, *a) (rest: 3) => * x, y, z, a, b, c (num: 6, pack_size = 3) * => x, y, z, [a,b,c] (num: 4) */ rsp[rest + 1] = rb_ary_new4(pack_size, &rsp[rest + 1]); sp = &rsp[rest + 1 + 1]; num = rest + 1; clear_local_size = niseq->local_size - (rest + 1); } /* block argument */ if (niseq->arg_block != -1) { VALUE arg_block_val = Qnil; if (!((num == niseq->arg_rest) || (niseq->arg_opts && num == niseq->argc + niseq->arg_opts - 1) || num == niseq->argc)) { if (0) printf("num: %d, rest: %d, opts: %d, argc: %d\n", num, niseq->arg_rest, niseq->arg_opts, niseq->argc); rb_raise(rb_eArgError, "%d - wrong number of arguments (%lu for %d)", 3, (unsigned long)num, niseq->argc); } if (blockptr) { /* make Proc object */ if (blockptr->proc == 0) { rb_proc_t *proc; reg_cfp->sp = sp; arg_block_val = th_make_proc(th, GET_CFP(), blockptr); GetProcPtr(arg_block_val, proc); blockptr = &proc->block; } else { arg_block_val = blockptr->proc; } } rsp[1 + niseq->arg_block - 1] = arg_block_val; sp++; clear_local_size--; } } /* stack overflow check */ if (CHECK_STACK_OVERFLOW(th, GET_CFP(), niseq->stack_max + 0x100)) { rb_exc_raise(sysstack_error); } if (flag & VM_CALL_TAILCALL_BIT) { /* copy arguments */ VALUE *p_rsp, *p_sp; reg_cfp = ++th->cfp; p_rsp = th->cfp->sp; for (i=0; i < (sp - rsp); i++) { p_rsp[i] = rsp[i]; } sp -= rsp - p_rsp; for (i = 0; i < clear_local_size; i++) { *sp++ = Qnil; } push_frame(th, niseq, FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, niseq->iseq_encoded + opt_pc, sp, 0, 0); } else { for (i = 0; i < clear_local_size; i++) { *sp++ = Qnil; } push_frame(th, niseq, FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, niseq->iseq_encoded + opt_pc, sp, 0, 0); reg_cfp->sp = rsp; } RESTORE_REGS(); } MACRO macro_eval_invoke_method(recv, klass, id, num, mn, blockptr) { /* method missing */ if (mn == 0) { /* temporarily */ if (id == idMethodMissing) { rb_bug("method missing"); } else { int stat = 0; if (flag & VM_CALL_VCALL_BIT) { stat |= NOEX_VCALL; } if (flag & VM_CALL_SUPER_BIT) { stat |= NOEX_SUPER; } val = eval_method_missing(th, id, recv, num, blockptr, stat); } } else if (!(flag & VM_CALL_FCALL_BIT) && (mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) { int stat = NOEX_PRIVATE; if (flag & VM_CALL_VCALL_BIT) { stat |= NOEX_VCALL; } val = eval_method_missing(th, id, recv, num, blockptr, stat); } else if ((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) { VALUE defined_class = mn->nd_clss; if (TYPE(defined_class) == T_ICLASS) { defined_class = RBASIC(defined_class)->klass; } if (!rb_obj_is_kind_of(GET_SELF(), rb_class_real(defined_class))) { val = eval_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED); } else { goto INSN_LABEL(normal_method_dispatch); } } else { NODE *node; INSN_LABEL(normal_method_dispatch): node = mn->nd_body; switch (nd_type(node)) { case RUBY_VM_METHOD_NODE:{ macro_eval_invoke_func(node->nd_body, recv, klass, blockptr, num); NEXT_INSN(); } case NODE_CFUNC:{ macro_eval_invoke_cfunc(num, id, recv, klass, node, blockptr); break; } case NODE_ATTRSET:{ val = rb_ivar_set(recv, node->nd_vid, TOPN(0)); POPN(2); break; } case NODE_IVAR:{ val = rb_ivar_get(recv, node->nd_vid); POP(); break; } case NODE_BMETHOD:{ VALUE *argv = GET_SP() - num; val = th_invoke_bmethod(th, id, node->nd_cval, recv, klass, num, argv); INC_SP(-num-1); break; } case NODE_ZSUPER:{ klass = RCLASS(mn->nd_clss)->super; mn = rb_method_node(klass, id); if (mn != 0) { goto INSN_LABEL(normal_method_dispatch); } else { goto LABEL_IS_SC(start_method_dispatch); } } default:{ printf("node: %s\n", ruby_node_name(nd_type(node))); rb_bug("eval_invoke_method: unreachable"); /* unreachable */ break; } } } }