static void prepare_singleton_class(mrb_state *mrb, struct RBasic *o) { struct RClass *sc, *c; if (o->c->tt == MRB_TT_SCLASS) return; sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); sc->mt = 0; sc->iv = 0; if (o->tt == MRB_TT_CLASS) { c = (struct RClass*)o; if (!c->super) { sc->super = mrb->class_class; } else { sc->super = c->super->c; } } else if (o->tt == MRB_TT_SCLASS) { c = (struct RClass*)o; make_metaclass(mrb, c->super); sc->super = c->super->c; } else { sc->super = o->c; } o->c = sc; mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc); mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o); mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern(mrb, "__attached__"), mrb_obj_value(o)); }
/* * call-seq: * fiber.resume(args, ...) -> obj * * Resumes the fiber from the point at which the last <code>Fiber.yield</code> * was called, or starts running it if it is the first call to * <code>resume</code>. Arguments passed to resume will be the value of * the <code>Fiber.yield</code> expression or will be passed as block * parameters to the fiber's block if this is the first <code>resume</code>. * * Alternatively, when resume is called it evaluates to the arguments passed * to the next <code>Fiber.yield</code> statement inside the fiber's block * or to the block value if it runs to completion without any * <code>Fiber.yield</code> */ static mrb_value fiber_resume(mrb_state *mrb, mrb_value self) { struct mrb_context *c = fiber_check(mrb, self); mrb_value *a; int len; mrb_callinfo *ci; for (ci = c->ci; ci >= c->cibase; ci--) { if (ci->acc < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "can't cross C function boundary"); } } if (c->status == MRB_FIBER_RESUMED) { mrb_raise(mrb, E_RUNTIME_ERROR, "double resume"); } if (c->status == MRB_FIBER_TERMINATED) { mrb_raise(mrb, E_RUNTIME_ERROR, "resuming dead fiber"); } mrb_get_args(mrb, "*", &a, &len); mrb->c->status = MRB_FIBER_RESUMED; if (c->status == MRB_FIBER_CREATED) { mrb_value *b = c->stack+1; mrb_value *e = b + len; while (b<e) { *b++ = *a++; } c->cibase->argc = len; c->prev = mrb->c; if (c->prev->fib) mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib); mrb_write_barrier(mrb, (struct RBasic*)c->fib); c->status = MRB_FIBER_RUNNING; mrb->c = c; MARK_CONTEXT_MODIFY(c); return c->ci->proc->env->stack[0]; } MARK_CONTEXT_MODIFY(c); c->prev = mrb->c; if (c->prev->fib) mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib); mrb_write_barrier(mrb, (struct RBasic*)c->fib); c->status = MRB_FIBER_RUNNING; mrb->c = c; return fiber_result(mrb, a, len); }
static mrb_value fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume) { struct mrb_context *c = fiber_check(mrb, self); mrb_callinfo *ci; for (ci = c->ci; ci >= c->cibase; ci--) { if (ci->acc < 0) { mrb_raise(mrb, E_FIBER_ERROR, "can't cross C function boundary"); } } if (resume && c->status == MRB_FIBER_TRANSFERRED) { mrb_raise(mrb, E_FIBER_ERROR, "resuming transfered fiber"); } if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMING) { mrb_raise(mrb, E_FIBER_ERROR, "double resume"); } if (c->status == MRB_FIBER_TERMINATED) { mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber"); } mrb->c->status = resume ? MRB_FIBER_RESUMING : MRB_FIBER_TRANSFERRED; c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c); if (c->status == MRB_FIBER_CREATED) { mrb_value *b = c->stack+1; mrb_value *e = b + len; while (b<e) { *b++ = *a++; } c->cibase->argc = len; if (c->prev->fib) mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib); mrb_write_barrier(mrb, (struct RBasic*)c->fib); c->status = MRB_FIBER_RUNNING; mrb->c = c; MARK_CONTEXT_MODIFY(c); return c->ci->proc->env->stack[0]; } MARK_CONTEXT_MODIFY(c); if (c->prev->fib) mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib); mrb_write_barrier(mrb, (struct RBasic*)c->fib); c->status = MRB_FIBER_RUNNING; mrb->c = c; return fiber_result(mrb, a, len); }
static struct RClass* boot_defclass(mrb_state *mrb, struct RClass *super) { struct RClass *c; c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class); c->super = super ? super : mrb->object_class; mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super); c->mt = kh_init(mt, mrb); return c; }
static void make_metaclass(mrb_state *mrb, struct RClass *c) { struct RClass *sc; if (c->c->tt == MRB_TT_SCLASS) { return; } sc = mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); sc->mt = 0; if (!c->super) { sc->super = mrb->class_class; } else { sc->super = c->super->c; } c->c = sc; mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)sc); mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)sc->super); }
void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { struct RClass *ic; ic = mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class); ic->c = m; ic->mt = m->mt; ic->iv = m->iv; ic->super = c->super; c->super = ic; mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)ic); }
void mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RProc *p) { khash_t(mt) *h = c->mt; khiter_t k; if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, h, mid); kh_value(h, k) = p; if (p) { mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p); } }
static struct RClass * mrb_singleton_class_ptr(mrb_state *mrb, struct RClass *c) { struct RClass *sc; if (c->tt == MRB_TT_SCLASS) { return c; } sc = mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); sc->mt = 0; sc->super = c; mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)c); return sc; }
void mrb_define_method_vm(mrb_state *mrb, struct RClass *c, mrb_sym name, mrb_value body) { khash_t(mt) *h = c->mt; khiter_t k; struct RProc *p; if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, h, name); p = mrb_proc_ptr(body); kh_value(h, k) = p; if (p) { mrb_field_write_barrier(mrb, (struct RBasic *)c, (struct RBasic *)p); } }
void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { struct RClass *ins_pos; ins_pos = c; while (m) { struct RClass *p = c, *ic; int superclass_seen = 0; if (c->mt == m->mt) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } while (p) { if (c != p && p->tt == MRB_TT_CLASS) { superclass_seen = 1; } else if (p->mt == m->mt){ if (p->tt == MRB_TT_ICLASS && !superclass_seen) { ins_pos = p; } goto skip; } p = p->super; } ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class); if (m->tt == MRB_TT_ICLASS) { ic->c = m->c; } else { ic->c = m; } ic->mt = m->mt; ic->iv = m->iv; ic->super = ins_pos->super; ins_pos->super = ic; mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic); ins_pos = ic; skip: m = m->super; } }
/* * call-seq: * obj.clone -> an_object * * Produces a shallow copy of <i>obj</i>---the instance variables of * <i>obj</i> are copied, but not the objects they reference. Copies * the frozen state of <i>obj</i>. See also the discussion * under <code>Object#dup</code>. * * class Klass * attr_accessor :str * end * s1 = Klass.new #=> #<Klass:0x401b3a38> * s1.str = "Hello" #=> "Hello" * s2 = s1.clone #=> #<Klass:0x401b3998 @str="Hello"> * s2.str[1,4] = "i" #=> "i" * s1.inspect #=> "#<Klass:0x401b3a38 @str=\"Hi\">" * s2.inspect #=> "#<Klass:0x401b3998 @str=\"Hi\">" * * This method may have class-specific behavior. If so, that * behavior will be documented under the #+initialize_copy+ method of * the class. * * Some Class(True False Nil Symbol Fixnum Float) Object cannot clone. */ MRB_API mrb_value mrb_obj_clone(mrb_state *mrb, mrb_value self) { struct RObject *p; mrb_value clone; if (mrb_immediate_p(self)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self); } if (mrb_type(self) == MRB_TT_SCLASS) { mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class"); } p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self)); p->c = mrb_singleton_class_clone(mrb, self); mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)p->c); clone = mrb_obj_value(p); init_copy(mrb, clone, self); return clone; }
MRB_API struct RProc * mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const mrb_value *argv) { struct RProc *p = mrb_proc_new_cfunc(mrb, func); struct REnv *e; int i; p->env = e = env_new(mrb, argc); mrb_field_write_barrier(mrb, (struct RBasic *)p, (struct RBasic *)p->env); MRB_ENV_UNSHARE_STACK(e); e->stack = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * argc); if (argv) { for (i = 0; i < argc; ++i) { e->stack[i] = argv[i]; } } else { for (i = 0; i < argc; ++i) { SET_NIL_VALUE(e->stack[i]); } } return p; }
void test_mrb_field_write_barrier(void) { mrb_state *mrb = mrb_open(); struct RBasic *obj, *value; puts("test_mrb_field_write_barrier"); mrb->is_generational_gc_mode = FALSE; obj = mrb_basic_ptr(mrb_ary_new(mrb)); value = mrb_basic_ptr(mrb_str_new_lit(mrb, "value")); paint_black(obj); paint_partial_white(mrb,value); puts(" in GC_STATE_MARK"); mrb->gc_state = GC_STATE_MARK; mrb_field_write_barrier(mrb, obj, value); mrb_assert(is_gray(value)); puts(" in GC_STATE_SWEEP"); paint_partial_white(mrb,value); mrb->gc_state = GC_STATE_SWEEP; mrb_field_write_barrier(mrb, obj, value); mrb_assert(obj->color & mrb->current_white_part); mrb_assert(value->color & mrb->current_white_part); puts(" fail with black"); mrb->gc_state = GC_STATE_MARK; paint_white(obj); paint_partial_white(mrb,value); mrb_field_write_barrier(mrb, obj, value); mrb_assert(obj->color & mrb->current_white_part); puts(" fail with gray"); mrb->gc_state = GC_STATE_MARK; paint_black(obj); paint_gray(value); mrb_field_write_barrier(mrb, obj, value); mrb_assert(is_gray(value)); { puts("test_mrb_field_write_barrier_value"); obj = mrb_basic_ptr(mrb_ary_new(mrb)); mrb_value value = mrb_str_new_lit(mrb, "value"); paint_black(obj); paint_partial_white(mrb, mrb_basic_ptr(value)); mrb->gc_state = GC_STATE_MARK; mrb_field_write_barrier_value(mrb, obj, value); mrb_assert(is_gray(mrb_basic_ptr(value))); } mrb_close(mrb); }
static struct RProc* create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, const char *file, mrb_int line) { mrbc_context *cxt; struct mrb_parser_state *p; struct RProc *proc; struct REnv *e; mrb_callinfo *ci = &mrb->c->ci[-1]; /* callinfo of eval caller */ struct RClass *target_class = NULL; int bidx; if (!mrb_nil_p(binding)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "Binding of eval must be nil."); } cxt = mrbc_context_new(mrb); cxt->lineno = (short)line; mrbc_filename(mrb, cxt, file ? file : "(eval)"); cxt->capture_errors = TRUE; cxt->no_optimize = TRUE; p = mrb_parse_nstring(mrb, s, len, cxt); /* only occur when memory ran out */ if (!p) { mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to create parser state."); } if (0 < p->nerr) { /* parse error */ mrb_value str; if (file) { str = mrb_format(mrb, " file %S line %S: %S", mrb_str_new_cstr(mrb, file), mrb_fixnum_value(p->error_buffer[0].lineno), mrb_str_new_cstr(mrb, p->error_buffer[0].message)); } else { str = mrb_format(mrb, " line %S: %S", mrb_fixnum_value(p->error_buffer[0].lineno), mrb_str_new_cstr(mrb, p->error_buffer[0].message)); } mrb_parser_free(p); mrbc_context_free(mrb, cxt); mrb_exc_raise(mrb, mrb_exc_new_str(mrb, E_SYNTAX_ERROR, str)); } proc = mrb_generate_code(mrb, p); if (proc == NULL) { /* codegen error */ mrb_parser_free(p); mrbc_context_free(mrb, cxt); mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error"); } target_class = MRB_PROC_TARGET_CLASS(ci->proc); if (!MRB_PROC_CFUNC_P(ci->proc)) { if (ci->env) { e = ci->env; } else { e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)target_class); e->mid = ci->mid; e->stack = ci[1].stackent; e->cxt = mrb->c; MRB_ENV_SET_STACK_LEN(e, ci->proc->body.irep->nlocals); bidx = ci->argc; if (ci->argc < 0) bidx = 2; else bidx += 1; MRB_ENV_SET_BIDX(e, bidx); ci->env = e; } proc->e.env = e; proc->flags |= MRB_PROC_ENVSET; mrb_field_write_barrier(mrb, (struct RBasic*)proc, (struct RBasic*)e); } proc->upper = ci->proc; mrb->c->ci->target_class = target_class; patch_irep(mrb, proc->body.irep, 0, proc->body.irep); /* mrb_codedump_all(mrb, proc); */ mrb_parser_free(p); mrbc_context_free(mrb, cxt); return proc; }