mrb_value mrb_cfunc_env_get(mrb_state *mrb, mrb_int idx) { struct RProc *p = mrb->c->ci->proc; struct REnv *e = p->env; if (!MRB_PROC_CFUNC_P(p)) { mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from non-cfunc proc."); } if (!e) { mrb_raise(mrb, E_TYPE_ERROR, "Can't get cfunc env from cfunc Proc without REnv."); } if (idx < 0 || MRB_ENV_STACK_LEN(e) <= idx) { mrb_raisef(mrb, E_INDEX_ERROR, "Env index out of range: %S (expected: 0 <= index < %S)", mrb_fixnum_value(idx), mrb_fixnum_value(MRB_ENV_STACK_LEN(e))); } return e->stack[idx]; }
/* * call-seq: * block_given? -> true or false * iterator? -> true or false * * Returns <code>true</code> if <code>yield</code> would execute a * block in the current context. The <code>iterator?</code> form * is mildly deprecated. * * def try * if block_given? * yield * else * "no block" * end * end * try #=> "no block" * try { "hello" } #=> "hello" * try do "hello" end #=> "hello" */ static mrb_value mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) { mrb_callinfo *ci = &mrb->c->ci[-1]; mrb_callinfo *cibase = mrb->c->cibase; mrb_value *bp; struct RProc *p; if (ci <= cibase) { /* toplevel does not have block */ return mrb_false_value(); } p = ci->proc; /* search method/class/module proc */ while (p) { if (MRB_PROC_SCOPE_P(p)) break; p = p->upper; } if (p == NULL) return mrb_false_value(); /* search ci corresponding to proc */ while (cibase < ci) { if (ci->proc == p) break; ci--; } if (ci == cibase) { return mrb_false_value(); } else if (ci->env) { struct REnv *e = ci->env; int bidx; /* top-level does not have block slot (always false) */ if (e->stack == mrb->c->stbase) return mrb_false_value(); /* use saved block arg position */ bidx = MRB_ENV_BIDX(e); /* bidx may be useless (e.g. define_method) */ if (bidx >= MRB_ENV_STACK_LEN(e)) return mrb_false_value(); bp = &e->stack[bidx]; } else { bp = ci[1].stackent+1; if (ci->argc >= 0) { bp += ci->argc; } else { bp++; } } if (mrb_nil_p(*bp)) return mrb_false_value(); return mrb_true_value(); }
static inline void closure_setup(mrb_state *mrb, struct RProc *p, int nlocals) { struct REnv *e; if (!mrb->c->ci->env) { e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)mrb->c->ci->proc->env); MRB_ENV_STACK_LEN(e)= (unsigned int)nlocals; e->mid = mrb->c->ci->mid; e->cioff = mrb->c->ci - mrb->c->cibase; e->stack = mrb->c->stack; mrb->c->ci->env = e; } else { e = mrb->c->ci->env; } p->env = e; }
static void cipop(mrb_state *mrb) { struct mrb_context *c = mrb->c; if (c->ci->env) { struct REnv *e = c->ci->env; size_t len = (size_t)MRB_ENV_STACK_LEN(e); mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len); MRB_ENV_UNSHARE_STACK(e); if (len > 0) { stack_copy(p, e->stack, len); } e->stack = p; mrb_write_barrier(mrb, (struct RBasic *)e); } c->ci--; }
struct RProc * mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t f, mrb_int argc, const mrb_value *argv) { struct RProc *p; struct REnv *e; int ai, i; p = mrb_proc_new_cfunc(mrb, f); ai = mrb_gc_arena_save(mrb); e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL); p->env = e; mrb_gc_arena_restore(mrb, ai); MRB_ENV_UNSHARE_STACK(e); MRB_ENV_STACK_LEN(e) = argc; e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc); for (i = 0; i < argc; ++i) { e->stack[i] = argv[i]; } return p; }
static void gc_mark_children(mrb_state *mrb, struct RBasic *obj) { mrb_assert(is_gray(obj)); paint_black(obj); mrb->gray_list = obj->gcnext; mrb_gc_mark(mrb, (struct RBasic*)obj->c); switch (obj->tt) { case MRB_TT_ICLASS: mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super); break; case MRB_TT_CLASS: case MRB_TT_MODULE: case MRB_TT_SCLASS: { struct RClass *c = (struct RClass*)obj; mrb_gc_mark_mt(mrb, c); mrb_gc_mark(mrb, (struct RBasic*)c->super); } /* fall through */ case MRB_TT_OBJECT: case MRB_TT_DATA: mrb_gc_mark_iv(mrb, (struct RObject*)obj); break; case MRB_TT_PROC: { struct RProc *p = (struct RProc*)obj; mrb_gc_mark(mrb, (struct RBasic*)p->env); mrb_gc_mark(mrb, (struct RBasic*)p->target_class); } break; case MRB_TT_ENV: { struct REnv *e = (struct REnv*)obj; if (!MRB_ENV_STACK_SHARED_P(e)) { int i, len; len = (int)MRB_ENV_STACK_LEN(e); for (i=0; i<len; i++) { mrb_gc_mark_value(mrb, e->stack[i]); } } } break; case MRB_TT_FIBER: { struct mrb_context *c = ((struct RFiber*)obj)->cxt; if (c) mark_context(mrb, c); } break; case MRB_TT_ARRAY: { struct RArray *a = (struct RArray*)obj; size_t i, e; for (i=0,e=a->len; i<e; i++) { mrb_gc_mark_value(mrb, a->ptr[i]); } } break; case MRB_TT_HASH: mrb_gc_mark_iv(mrb, (struct RObject*)obj); mrb_gc_mark_hash(mrb, (struct RHash*)obj); break; case MRB_TT_STRING: break; case MRB_TT_RANGE: { struct RRange *r = (struct RRange*)obj; if (r->edges) { mrb_gc_mark_value(mrb, r->edges->beg); mrb_gc_mark_value(mrb, r->edges->end); } } break; default: break; } }
static size_t gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) { size_t children = 0; gc_mark_children(mrb, gc, obj); switch (obj->tt) { case MRB_TT_ICLASS: children++; break; case MRB_TT_CLASS: case MRB_TT_SCLASS: case MRB_TT_MODULE: { struct RClass *c = (struct RClass*)obj; children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj); children += mrb_gc_mark_mt_size(mrb, c); children++; } break; case MRB_TT_OBJECT: case MRB_TT_DATA: case MRB_TT_EXCEPTION: children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj); break; case MRB_TT_ENV: children += MRB_ENV_STACK_LEN(obj); break; case MRB_TT_FIBER: { struct mrb_context *c = ((struct RFiber*)obj)->cxt; size_t i; mrb_callinfo *ci; if (!c) break; /* mark stack */ i = c->stack - c->stbase; if (c->ci) i += c->ci->nregs; if (c->stbase + i > c->stend) i = c->stend - c->stbase; children += i; /* mark ensure stack */ children += c->eidx; /* mark closure */ if (c->cibase) { for (i=0, ci = c->cibase; ci <= c->ci; i++, ci++) ; } children += i; } break; case MRB_TT_ARRAY: { struct RArray *a = (struct RArray*)obj; children += ARY_LEN(a); } break; case MRB_TT_HASH: children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj); children += mrb_gc_mark_hash_size(mrb, (struct RHash*)obj); break; case MRB_TT_PROC: case MRB_TT_RANGE: children+=2; break; default: break; } return children; }
static void gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) { mrb_assert(is_gray(obj)); paint_black(obj); gc->gray_list = obj->gcnext; mrb_gc_mark(mrb, (struct RBasic*)obj->c); switch (obj->tt) { case MRB_TT_ICLASS: { struct RClass *c = (struct RClass*)obj; if (MRB_FLAG_TEST(c, MRB_FLAG_IS_ORIGIN)) mrb_gc_mark_mt(mrb, c); mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super); } break; case MRB_TT_CLASS: case MRB_TT_MODULE: case MRB_TT_SCLASS: { struct RClass *c = (struct RClass*)obj; mrb_gc_mark_mt(mrb, c); mrb_gc_mark(mrb, (struct RBasic*)c->super); } /* fall through */ case MRB_TT_OBJECT: case MRB_TT_DATA: case MRB_TT_EXCEPTION: mrb_gc_mark_iv(mrb, (struct RObject*)obj); break; case MRB_TT_PROC: { struct RProc *p = (struct RProc*)obj; mrb_gc_mark(mrb, (struct RBasic*)p->upper); mrb_gc_mark(mrb, (struct RBasic*)p->e.env); } break; case MRB_TT_ENV: { struct REnv *e = (struct REnv*)obj; mrb_int i, len; if (MRB_ENV_STACK_SHARED_P(e) && e->cxt && e->cxt->fib) { mrb_gc_mark(mrb, (struct RBasic*)e->cxt->fib); } len = MRB_ENV_STACK_LEN(e); for (i=0; i<len; i++) { mrb_gc_mark_value(mrb, e->stack[i]); } } break; case MRB_TT_FIBER: { struct mrb_context *c = ((struct RFiber*)obj)->cxt; if (c) mark_context(mrb, c); } break; case MRB_TT_ARRAY: { struct RArray *a = (struct RArray*)obj; size_t i, e; for (i=0,e=ARY_LEN(a); i<e; i++) { mrb_gc_mark_value(mrb, ARY_PTR(a)[i]); } } break; case MRB_TT_HASH: mrb_gc_mark_iv(mrb, (struct RObject*)obj); mrb_gc_mark_hash(mrb, (struct RHash*)obj); break; case MRB_TT_STRING: if (RSTR_FSHARED_P(obj) && !RSTR_NOFREE_P(obj)) { struct RString *s = (struct RString*)obj; mrb_gc_mark(mrb, (struct RBasic*)s->as.heap.aux.fshared); } break; case MRB_TT_RANGE: { struct RRange *r = (struct RRange*)obj; if (r->edges) { mrb_gc_mark_value(mrb, r->edges->beg); mrb_gc_mark_value(mrb, r->edges->end); } } break; default: break; } }