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]); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); } 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 (block->proc) { return block->proc; } /* TODO: check more (cfp limit, called via cfunc, etc) */ while (cfp->dfp != block->dfp) { cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); } 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 && RBASIC(procval)->klass == klass) { return procval; } procval = vm_make_proc(th, cfp, block, klass); if (is_lambda) { rb_proc_t *proc; GetProcPtr(procval, proc); proc->is_lambda = Qtrue; } return procval; }
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; }
VALUE rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass) { VALUE procval, envval, blockprocval = 0; rb_proc_t *proc; rb_control_frame_t *cfp = RUBY_VM_GET_CFP_FROM_BLOCK_PTR(block); if (block->proc) { rb_bug("rb_vm_make_proc: Proc value is already created."); } if (GC_GUARDED_PTR_REF(cfp->lfp[0])) { rb_proc_t *p; blockprocval = vm_make_proc_from_block( th, (rb_block_t *)GC_GUARDED_PTR_REF(*cfp->lfp)); GetProcPtr(blockprocval, p); *cfp->lfp = GC_GUARDED_PTR(&p->block); } envval = rb_vm_make_env_object(th, cfp); if (PROCDEBUG) { check_env_value(envval); } procval = rb_proc_alloc(klass); GetProcPtr(procval, proc); proc->blockprocval = blockprocval; proc->block.self = block->self; proc->block.lfp = block->lfp; proc->block.dfp = block->dfp; proc->block.iseq = block->iseq; proc->block.proc = procval; proc->envval = envval; proc->safe_level = th->safe_level; if (VMDEBUG) { if (th->stack < block->dfp && block->dfp < th->stack + th->stack_size) { rb_bug("invalid ptr: block->dfp"); } if (th->stack < block->lfp && block->lfp < th->stack + th->stack_size) { rb_bug("invalid ptr: block->lfp"); } } return procval; }
VALUE yarv_invoke_Array_each_special_block(VALUE ary) { rb_thread_t *th = GET_THREAD(); rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]); if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) { VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq, build_Array_each_node); rb_iseq_t *tsiseq; VALUE argv[2]; if (tsiseqval) { VALUE val; rb_block_t block = *orig_block; GetISeqPtr(tsiseqval, tsiseq); block.iseq = tsiseq; th->cfp->lfp[0] = GC_GUARDED_PTR(&block); argv[0] = 0; argv[1] = ary; val = th_invoke_yield(th, 2, argv); if (val == Qundef) { return ary; } else { return val; } } } return Qundef; }
VALUE yarv_invoke_Range_each_special_block(VALUE range, VALUE beg, VALUE end, int excl) { rb_thread_t *th = GET_THREAD(); rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]); if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) { void *builder = excl ? build_Range_each_node_LT : build_Range_each_node_LE; VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq, builder); rb_iseq_t *tsiseq; VALUE argv[2]; if (tsiseqval) { VALUE val; rb_block_t block = *orig_block; GetISeqPtr(tsiseqval, tsiseq); block.iseq = tsiseq; th->cfp->lfp[0] = GC_GUARDED_PTR(&block); argv[0] = beg; argv[1] = end; val = th_invoke_yield(th, 2, argv); if (val == Qundef) { return range; } else { return val; } } } return Qundef; }
VALUE yarv_invoke_Integer_times_special_block(VALUE num) { rb_thread_t *th = GET_THREAD(); rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]); if (orig_block && BUILTIN_TYPE(orig_block->iseq) != T_NODE) { VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq, build_Integer_times_node); rb_iseq_t *tsiseq; VALUE argv[2], val; if (tsiseqval) { rb_block_t block = *orig_block; GetISeqPtr(tsiseqval, tsiseq); block.iseq = tsiseq; th->cfp->lfp[0] = GC_GUARDED_PTR(&block); argv[0] = INT2FIX(0); argv[1] = num; val = th_invoke_yield(th, 2, argv); if (val == Qundef) { return num; } else { return val; } } } return Qundef; }
void rb_vmdebug_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp) { #if 0 VALUE *sp = cfp->sp, *ep = cfp->ep; VALUE *p, *st, *t; fprintf(stderr, "-- stack frame ------------\n"); for (p = st = th->stack; p < sp; p++) { fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p); t = (VALUE *)*p; if (th->stack <= t && t < sp) { fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF(t) - th->stack)); } if (p == ep) fprintf(stderr, " <- ep"); fprintf(stderr, "\n"); } #endif fprintf(stderr, "-- Control frame information " "-----------------------------------------------\n"); while ((void *)cfp < (void *)(th->stack + th->stack_size)) { control_frame_dump(th, cfp); cfp++; } fprintf(stderr, "\n"); }
static VALUE collect_caller_bindings(rb_thread_t *th) { struct collect_caller_bindings_data data; VALUE result; int i; data.ary = rb_ary_new(); backtrace_each(th, collect_caller_bindings_init, collect_caller_bindings_iseq, collect_caller_bindings_cfunc, &data); result = rb_ary_reverse(data.ary); /* bindings should be created from top of frame */ for (i=0; i<RARRAY_LEN(result); i++) { VALUE entry = rb_ary_entry(result, i); VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING); if (!NIL_P(cfp_val)) { rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val); rb_ary_store(entry, CALLER_BINDING_BINDING, rb_binding_new_with_cfp(th, cfp)); } } return result; }
static void vm_iter_break(rb_thread_t *th) { rb_control_frame_t *cfp = th->cfp; VALUE *dfp = GC_GUARDED_PTR_REF(*cfp->dfp); th->state = TAG_BREAK; th->errinfo = (VALUE)NEW_THROW_OBJECT(Qnil, (VALUE)dfp, TAG_BREAK); TH_JUMP_TAG(th, TAG_BREAK); }
static inline const rb_block_t * check_block(rb_thread_t *th) { const rb_block_t *blockptr = GC_GUARDED_PTR_REF(th->cfp->lfp[0]); if (blockptr == 0) { rb_vm_localjump_error("no block given", Qnil, 0); } return blockptr; }
VALUE rb_f_block_given_p(void) { rb_thread_t *th = GET_THREAD(); rb_control_frame_t *cfp = th->cfp; cfp = vm_get_ruby_level_caller_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)); if (cfp != 0 && (cfp->lfp[0] & 0x02) == 0 && GC_GUARDED_PTR_REF(cfp->lfp[0])) { return Qtrue; } else { return Qfalse; } }
static VALUE yield_under(VALUE under, VALUE self, VALUE values) { rb_thread_t *th = GET_THREAD(); rb_block_t block, *blockptr; NODE *cref = vm_cref_push(th, under, NOEX_PUBLIC); if ((blockptr = GC_GUARDED_PTR_REF(th->cfp->lfp[0])) != 0) { block = *blockptr; block.self = self; th->cfp->lfp[0] = GC_GUARDED_PTR(&block); } if (values == Qundef) { return vm_yield_with_cref(th, 0, 0, cref); } else { return vm_yield_with_cref(th, RARRAY_LEN(values), RARRAY_PTR(values), cref); } }
static VALUE rb_f_local_variables(void) { VALUE ary = rb_ary_new(); rb_thread_t *th = GET_THREAD(); rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp)); int i; while (cfp) { if (cfp->iseq) { for (i = 0; i < cfp->iseq->local_table_size; i++) { ID lid = cfp->iseq->local_table[i]; if (lid) { const char *vname = rb_id2name(lid); /* should skip temporary variable */ if (vname) { rb_ary_push(ary, ID2SYM(lid)); } } } } if (cfp->lfp != cfp->dfp) { /* block */ VALUE *dfp = GC_GUARDED_PTR_REF(cfp->dfp[0]); if (vm_collect_local_variables_in_heap(th, dfp, ary)) { break; } else { while (cfp->dfp != dfp) { cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); } } } else { break; } } return ary; }
void rb_vmdebug_stack_dump_raw(rb_thread_t *th, rb_control_frame_t *cfp) { #if 0 VALUE *sp = cfp->sp, *bp = cfp->bp; VALUE *lfp = cfp->lfp; VALUE *dfp = cfp->dfp; VALUE *p, *st, *t; fprintf(stderr, "-- stack frame ------------\n"); for (p = st = th->stack; p < sp; p++) { fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p); t = (VALUE *)*p; if (th->stack <= t && t < sp) { fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF(t) - th->stack)); } if (p == lfp) fprintf(stderr, " <- lfp"); if (p == dfp) fprintf(stderr, " <- dfp"); if (p == bp) fprintf(stderr, " <- bp"); /* should not be */ fprintf(stderr, "\n"); } #endif fprintf(stderr, "-- control frame ----------\n"); while ((void *)cfp < (void *)(th->stack + th->stack_size)) { control_frame_dump(th, cfp); cfp++; } fprintf(stderr, "---------------------------\n"); }
static VALUE vm_make_env_each(rb_thread_t * const th, rb_control_frame_t * const cfp, VALUE *envptr, VALUE * const endptr) { VALUE envval, penvval = 0; rb_env_t *env; VALUE *nenvptr; int i, local_size; if (ENV_IN_HEAP_P(th, envptr)) { return ENV_VAL(envptr); } if (envptr != endptr) { VALUE *penvptr = GC_GUARDED_PTR_REF(*envptr); rb_control_frame_t *pcfp = cfp; if (ENV_IN_HEAP_P(th, penvptr)) { penvval = ENV_VAL(penvptr); } else { while (pcfp->dfp != penvptr) { pcfp++; if (pcfp->dfp == 0) { SDR(); rb_bug("invalid dfp"); } } penvval = vm_make_env_each(th, pcfp, penvptr, endptr); cfp->lfp = pcfp->lfp; *envptr = GC_GUARDED_PTR(pcfp->dfp); } } /* allocate env */ envval = env_alloc(); GetEnvPtr(envval, env); if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { local_size = 2; } else { local_size = cfp->iseq->local_size; } env->env_size = local_size + 1 + 2; env->local_size = local_size; env->env = ALLOC_N(VALUE, env->env_size); env->prev_envval = penvval; for (i = 0; i <= local_size; i++) { env->env[i] = envptr[-local_size + i]; #if 0 fprintf(stderr, "%2d ", &envptr[-local_size + i] - th->stack); dp(env->env[i]); if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { /* clear value stack for GC */ envptr[-local_size + i] = 0; } #endif } *envptr = envval; /* GC mark */ nenvptr = &env->env[i - 1]; nenvptr[1] = envval; /* frame self */ nenvptr[2] = penvval; /* frame prev env object */ /* reset lfp/dfp in cfp */ cfp->dfp = nenvptr; if (envptr == endptr) { cfp->lfp = nenvptr; } /* as Binding */ env->block.self = cfp->self; env->block.lfp = cfp->lfp; env->block.dfp = cfp->dfp; env->block.iseq = cfp->iseq; if (!RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { /* TODO */ env->block.iseq = 0; } return envval; }