static VALUE vm_make_proc_from_block(rb_thread_t *th, rb_block_t *block) { if (!block->proc) { block->proc = rb_vm_make_proc(th, block, rb_cProc); } return block->proc; }
static VALUE proc_new(VALUE klass, int is_lambda) { VALUE procval = Qnil; rb_thread_t *th = GET_THREAD(); rb_control_frame_t *cfp = th->cfp; rb_block_t *block; if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0 && !RUBY_VM_CLASS_SPECIAL_P(cfp->lfp[0])) { block = GC_GUARDED_PTR_REF(cfp->lfp[0]); } else { cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); if ((GC_GUARDED_PTR_REF(cfp->lfp[0])) != 0 && !RUBY_VM_CLASS_SPECIAL_P(cfp->lfp[0])) { block = GC_GUARDED_PTR_REF(cfp->lfp[0]); if (is_lambda) { rb_warn("tried to create Proc object without a block"); } } else { rb_raise(rb_eArgError, "tried to create Proc object without a block"); } } procval = block->proc; if (procval) { if (RBASIC(procval)->klass == klass) { return procval; } else { VALUE newprocval = proc_dup(procval); RBASIC(newprocval)->klass = klass; return newprocval; } } procval = rb_vm_make_proc(th, block, klass); if (is_lambda) { rb_proc_t *proc; GetProcPtr(procval, proc); proc->is_lambda = Qtrue; } return procval; }
static VALUE vm_make_proc_from_block(rb_thread_t *th, rb_block_t *block) { VALUE proc = block->proc; if (block->proc) { return block->proc; } proc = rb_vm_make_proc(th, block, rb_cProc); block->proc = proc; return proc; }
static inline VALUE vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, VALUE self, int argc, const VALUE *argv, const rb_block_t *blockargptr) { NODE *ifunc = (NODE *) block->iseq; VALUE val, arg, blockarg; int lambda = block_proc_is_lambda(block->proc); if (lambda) { arg = rb_ary_new4(argc, argv); } else if (argc == 0) { arg = Qnil; } else { arg = argv[0]; } if (blockargptr) { if (blockargptr->proc) { blockarg = blockargptr->proc; } else { blockarg = rb_vm_make_proc(th, blockargptr, rb_cProc); } } else { blockarg = Qnil; } vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, self, (VALUE)block->dfp, 0, th->cfp->sp, block->lfp, 1); if (blockargptr) { th->cfp->lfp[0] = GC_GUARDED_PTR((VALUE)blockargptr); } val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg); th->cfp++; return val; }
static inline void args_setup_block_parameter(rb_thread_t *th, struct rb_calling_info *calling, VALUE *locals) { VALUE blockval = Qnil; const rb_block_t *blockptr = calling->blockptr; if (blockptr) { /* make Proc object */ if (blockptr->proc == 0) { rb_proc_t *proc; blockval = rb_vm_make_proc(th, blockptr, rb_cProc); GetProcPtr(blockval, proc); calling->blockptr = &proc->block; } else if (SYMBOL_P(blockptr->proc)) { blockval = rb_sym_to_proc(blockptr->proc); } else { blockval = blockptr->proc; } } *locals = blockval; }
static inline int vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq, int orig_argc, VALUE *argv, const rb_block_t *blockptr) { int i; int argc = orig_argc; const int m = iseq->argc; VALUE ary, arg0; int opt_pc = 0; th->mark_stack_len = argc; /* * yield [1, 2] * => {|a|} => a = [1, 2] * => {|a, b|} => a, b = [1, 2] */ arg0 = argv[0]; if (!(iseq->arg_simple & 0x02) && /* exclude {|a|} */ (m + iseq->arg_post_len) > 0 && /* this process is meaningful */ argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */ th->mark_stack_len = argc = RARRAY_LENINT(ary); CHECK_STACK_OVERFLOW(th->cfp, argc); MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc); } else { argv[0] = arg0; } for (i=argc; i<m; i++) { argv[i] = Qnil; } if (iseq->arg_rest == -1 && iseq->arg_opts == 0) { const int arg_size = iseq->arg_size; if (arg_size < argc) { /* * yield 1, 2 * => {|a|} # truncate */ th->mark_stack_len = argc = arg_size; } } else { int r = iseq->arg_rest; if (iseq->arg_post_len || iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */ opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv); } else { if (argc < r) { /* yield 1 * => {|a, b, *r|} */ for (i=argc; i<r; i++) { argv[i] = Qnil; } argv[r] = rb_ary_new(); } else { argv[r] = rb_ary_new4(argc-r, &argv[r]); } } th->mark_stack_len = iseq->arg_size; } /* {|&b|} */ if (iseq->arg_block != -1) { VALUE procval = Qnil; if (blockptr) { if (blockptr->proc == 0) { procval = rb_vm_make_proc(th, blockptr, rb_cProc); } else { procval = blockptr->proc; } } argv[iseq->arg_block] = procval; } th->mark_stack_len = 0; return opt_pc; }
static inline int vm_callee_setup_arg_complex(rb_thread_t *th, const rb_iseq_t * iseq, int orig_argc, VALUE * orig_argv, const rb_block_t **block) { const int m = iseq->argc; int argc = orig_argc; VALUE *argv = orig_argv; rb_num_t opt_pc = 0; th->mark_stack_len = argc + iseq->arg_size; /* mandatory */ if (argc < (m + iseq->arg_post_len)) { /* check with post arg */ argument_error(iseq, argc, m + iseq->arg_post_len); } argv += m; argc -= m; /* post arguments */ if (iseq->arg_post_len) { if (!(orig_argc < iseq->arg_post_start)) { VALUE *new_argv = ALLOCA_N(VALUE, argc); MEMCPY(new_argv, argv, VALUE, argc); argv = new_argv; } MEMCPY(&orig_argv[iseq->arg_post_start], &argv[argc -= iseq->arg_post_len], VALUE, iseq->arg_post_len); } /* opt arguments */ if (iseq->arg_opts) { const int opts = iseq->arg_opts - 1 /* no opt */; if (iseq->arg_rest == -1 && argc > opts) { argument_error(iseq, orig_argc, m + opts + iseq->arg_post_len); } if (argc > opts) { argc -= opts; argv += opts; opt_pc = iseq->arg_opt_table[opts]; /* no opt */ } else { int i; for (i = argc; i<opts; i++) { orig_argv[i + m] = Qnil; } opt_pc = iseq->arg_opt_table[argc]; argc = 0; } } /* rest arguments */ if (iseq->arg_rest != -1) { orig_argv[iseq->arg_rest] = rb_ary_new4(argc, argv); argc = 0; } /* block arguments */ if (block && iseq->arg_block != -1) { VALUE blockval = Qnil; const rb_block_t *blockptr = *block; if (argc != 0) { argument_error(iseq, orig_argc, m + iseq->arg_post_len); } if (blockptr) { /* make Proc object */ if (blockptr->proc == 0) { rb_proc_t *proc; blockval = rb_vm_make_proc(th, blockptr, rb_cProc); GetProcPtr(blockval, proc); *block = &proc->block; } else { blockval = blockptr->proc; } } orig_argv[iseq->arg_block] = blockval; /* Proc or nil */ } th->mark_stack_len = 0; return (int)opt_pc; }