void mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) { struct RClass *c = mrb->ci->proc->target_class; if (!c) c = mrb->ci->target_class; while (c) { if (c->iv) { iv_tbl *t = c->iv; if (iv_get(mrb, t, sym, NULL)) { mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, t, sym, v); return; } } c = c->super; } c = mrb->ci->target_class; if (!c->iv) { c->iv = iv_new(mrb); } mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, c->iv, sym, v); }
void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_value v) { struct RClass * cls = c; while (c) { if (c->iv) { iv_tbl *t = c->iv; if (iv_get(mrb, t, sym, NULL)) { mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, t, sym, v); return; } } c = c->super; } if (!cls->iv) { cls->iv = iv_new(mrb); } mrb_write_barrier(mrb, (struct RBasic*)cls); iv_put(mrb, cls->iv, sym, v); }
void test_mrb_write_barrier(void) { mrb_state *mrb = mrb_open(); struct RBasic *obj; puts("test_mrb_write_barrier"); obj = mrb_basic_ptr(mrb_ary_new(mrb)); paint_black(obj); puts(" in GC_STATE_MARK"); mrb->gc_state = GC_STATE_MARK; mrb_write_barrier(mrb, obj); mrb_assert(is_gray(obj)); mrb_assert(mrb->atomic_gray_list == obj); puts(" fail with gray"); paint_gray(obj); mrb_write_barrier(mrb, obj); mrb_assert(is_gray(obj)); mrb_close(mrb); }
/* * 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); }
/* * call-seq: * fiber.transfer(args, ...) -> obj * * Transfers control to receiver fiber of the method call. * Unlike <code>resume</code> the receiver wouldn't be pushed to call * stack of fibers. Instead it will switch to the call stack of * transferring fiber. * When resuming a fiber that was transferred to another fiber it would * cause double resume error. Though when the fiber is re-transferred * and <code>Fiber.yield</code> is called, the fiber would be resumable. */ static mrb_value fiber_transfer(mrb_state *mrb, mrb_value self) { struct mrb_context *c = fiber_check(mrb, self); mrb_value* a; mrb_int len; fiber_check_cfunc(mrb, mrb->c); mrb_get_args(mrb, "*", &a, &len); if (c == mrb->root_c) { mrb->c->status = MRB_FIBER_TRANSFERRED; mrb->c = c; c->status = MRB_FIBER_RUNNING; MARK_CONTEXT_MODIFY(c); mrb_write_barrier(mrb, (struct RBasic*)c->fib); return fiber_result(mrb, a, len); } if (c == mrb->c) { return fiber_result(mrb, a, len); } return fiber_switch(mrb, self, len, a, FALSE, FALSE); }
mrb_value mrb_ary_unshift_m(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); mrb_value *vals; int len; mrb_get_args(mrb, "*", &vals, &len); if ((a->flags & MRB_ARY_SHARED) && a->aux.shared->refcnt == 1 /* shared only referenced from this array */ && a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ { a->ptr -= len; } else { ary_modify(mrb, a); if (len == 0) return self; if (a->aux.capa < a->len + len) ary_expand_capa(mrb, a, a->len + len); memmove(a->ptr + len, a->ptr, sizeof(mrb_value)*a->len); } memcpy(a->ptr, vals, sizeof(mrb_value)*len); a->len += len; mrb_write_barrier(mrb, (struct RBasic*)a); return self; }
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); }
MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) { struct RClass * cls = c; while (c) { if (c->iv) { iv_tbl *t = c->iv; if (iv_get(mrb, t, sym, NULL)) { mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, t, sym, v); return; } } c = c->super; } if (cls && cls->tt == MRB_TT_SCLASS) { mrb_value klass; klass = mrb_obj_iv_get(mrb, (struct RObject*)cls, mrb_intern_lit(mrb, "__attached__")); switch (mrb_type(klass)) { case MRB_TT_CLASS: case MRB_TT_MODULE: case MRB_TT_SCLASS: c = mrb_class_ptr(klass); break; default: c = cls; break; } } else{ c = cls; } if (!c->iv) { c->iv = iv_new(mrb); } mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, c->iv, sym, v); }
static void uvset(mrb_state *mrb, int up, int idx, mrb_value v) { struct REnv *e = uvenv(mrb, up); if (!e) return; e->stack[idx] = v; mrb_write_barrier(mrb, (struct RBasic*)e); }
static void mrb_struct_modify(mrb_state *mrb, mrb_value strct) { if (MRB_FROZEN_P(mrb_basic_ptr(strct))) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen struct"); } mrb_write_barrier(mrb, mrb_basic_ptr(strct)); }
static void ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len) { ary_modify(mrb, a); if (ARY_CAPA(a) < len) ary_expand_capa(mrb, a, len); array_copy(ARY_PTR(a), argv, len); mrb_write_barrier(mrb, (struct RBasic*)a); ARY_SET_LEN(a, len); }
static void ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, int len) { ary_modify(mrb, a); if (a->aux.capa < len) ary_expand_capa(mrb, a, len); memcpy(a->ptr, argv, sizeof(mrb_value)*len); mrb_write_barrier(mrb, (struct RBasic*)a); a->len = len; }
static void ary_concat(mrb_state *mrb, struct RArray *a, mrb_value *ptr, int blen) { int len = a->len + blen; ary_modify(mrb, a); if (a->aux.capa < len) ary_expand_capa(mrb, a, len); memcpy(a->ptr+a->len, ptr, sizeof(mrb_value)*blen); mrb_write_barrier(mrb, (struct RBasic*)a); a->len = len; }
void mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem) /* mrb_ary_push */ { struct RArray *a = mrb_ary_ptr(ary); ary_modify(mrb, a); if (a->len == a->aux.capa) ary_expand_capa(mrb, a, a->len + 1); a->ptr[a->len++] = elem; mrb_write_barrier(mrb, (struct RBasic*)a); }
void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t = obj->iv; if (!t) { t = obj->iv = iv_new(mrb); } mrb_write_barrier(mrb, (struct RBasic*)obj); iv_put(mrb, t, sym, v); }
static void ary_replace(mrb_state *mrb, struct RArray *a, struct RArray *b) { mrb_int len = ARY_LEN(b); ary_modify_check(mrb, a); if (a == b) return; if (ARY_SHARED_P(a)) { mrb_ary_decref(mrb, a->as.heap.aux.shared); a->as.heap.aux.capa = 0; a->as.heap.len = 0; a->as.heap.ptr = NULL; ARY_UNSET_SHARED_FLAG(a); } if (ARY_SHARED_P(b)) { shared_b: if (ARY_EMBED_P(a)) { ARY_UNSET_EMBED_FLAG(a); } else { mrb_free(mrb, a->as.heap.ptr); } a->as.heap.ptr = b->as.heap.ptr; a->as.heap.len = len; a->as.heap.aux.shared = b->as.heap.aux.shared; a->as.heap.aux.shared->refcnt++; ARY_SET_SHARED_FLAG(a); mrb_write_barrier(mrb, (struct RBasic*)a); return; } if (!MRB_FROZEN_P(b) && len > ARY_REPLACE_SHARED_MIN) { ary_make_shared(mrb, b); goto shared_b; } if (ARY_CAPA(a) < len) ary_expand_capa(mrb, a, len); array_copy(ARY_PTR(a), ARY_PTR(b), len); mrb_write_barrier(mrb, (struct RBasic*)a); ARY_SET_LEN(a, len); }
MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t = obj->iv; if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_RUNTIME_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } if (!t) { t = obj->iv = iv_new(mrb); } mrb_write_barrier(mrb, (struct RBasic*)obj); iv_put(mrb, t, sym, v); }
void mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t = obj->iv; if (!t) { t = obj->iv = iv_new(mrb); } else if (iv_get(mrb, t, sym, &v)) { return; } mrb_write_barrier(mrb, (struct RBasic*)obj); iv_put(mrb, t, sym, v); }
MRB_API void mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src) { struct RObject *d = mrb_obj_ptr(dest); struct RObject *s = mrb_obj_ptr(src); if (d->iv) { iv_free(mrb, d->iv); d->iv = 0; } if (s->iv) { mrb_write_barrier(mrb, (struct RBasic*)d); d->iv = iv_copy(mrb, s->iv); } }
MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t; if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); } t = obj->iv; iv_put(mrb, t, sym, v); mrb_write_barrier(mrb, (struct RBasic*)obj); }
static mrb_value fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume, mrb_bool vmexec) { struct mrb_context *c = fiber_check(mrb, self); struct mrb_context *old_c = mrb->c; mrb_value value; fiber_check_cfunc(mrb, c); if (resume && c->status == MRB_FIBER_TRANSFERRED) { mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber"); } if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMED) { mrb_raise(mrb, E_FIBER_ERROR, "double resume (fib)"); } if (c->status == MRB_FIBER_TERMINATED) { mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber"); } mrb->c->status = resume ? MRB_FIBER_RESUMED : 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; value = c->stack[0] = c->ci->proc->env->stack[0]; } else { value = fiber_result(mrb, a, len); } mrb_write_barrier(mrb, (struct RBasic*)c->fib); c->status = MRB_FIBER_RUNNING; mrb->c = c; if (vmexec) { c->vmexec = TRUE; value = mrb_vm_exec(mrb, c->ci[-1].proc, c->ci->pc); mrb->c = old_c; } else { MARK_CONTEXT_MODIFY(c); } return value; }
static void ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2) { mrb_int len; if (ARY_LEN(a2) > ARY_MAX_SIZE - ARY_LEN(a)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } len = ARY_LEN(a) + ARY_LEN(a2); ary_modify(mrb, a); if (ARY_CAPA(a) < len) { ary_expand_capa(mrb, a, len); } array_copy(ARY_PTR(a)+ARY_LEN(a), ARY_PTR(a2), ARY_LEN(a2)); mrb_write_barrier(mrb, (struct RBasic*)a); ARY_SET_LEN(a, len); }
void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) /* mrb_hash_aset */ { khash_t(ht) *h; khiter_t k; mrb_hash_modify(mrb, hash); h = RHASH_TBL(hash); k = kh_get(ht, h, key); if (k == kh_end(h)) { /* expand */ k = kh_put(ht, h, KEY(key)); } kh_value(h, k) = val; mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash)); return; }
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--; }
static mrb_value mrb_ary_push_m(mrb_state *mrb, mrb_value self) { mrb_value *argv; mrb_int len, len2, alen; struct RArray *a; mrb_get_args(mrb, "*!", &argv, &alen); a = mrb_ary_ptr(self); ary_modify(mrb, a); len = ARY_LEN(a); len2 = len + alen; if (ARY_CAPA(a) < len2) { ary_expand_capa(mrb, a, len2); } array_copy(ARY_PTR(a)+len, argv, alen); ARY_SET_LEN(a, len2); mrb_write_barrier(mrb, (struct RBasic*)a); return self; }
/* mrb_fiber_yield() must be called as `return mrb_fiber_yield(...)` */ MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a) { struct mrb_context *c = mrb->c; if (!c->prev) { mrb_raise(mrb, E_FIBER_ERROR, "can't yield from root fiber"); } c->prev->status = MRB_FIBER_RUNNING; c->status = MRB_FIBER_SUSPENDED; mrb->c = c->prev; c->prev = NULL; if (c->vmexec) { c->vmexec = FALSE; mrb->c->ci->acc = CI_ACC_RESUMED; } mrb_write_barrier(mrb, (struct RBasic*)c->fib); MARK_CONTEXT_MODIFY(mrb->c); return fiber_result(mrb, a, len); }
void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) { khash_t(ht) *h; khiter_t k; mrb_hash_modify(mrb, hash); h = RHASH_TBL(hash); if (!h) h = RHASH_TBL(hash) = kh_init(ht, mrb); k = kh_get(ht, mrb, h, key); if (k == kh_end(h)) { /* expand */ int ai = mrb_gc_arena_save(mrb); k = kh_put(ht, mrb, h, KEY(key)); mrb_gc_arena_restore(mrb, ai); } kh_value(h, k) = val; mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash)); return; }
void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) /* rb_ary_store */ { struct RArray *a = mrb_ary_ptr(ary); ary_modify(mrb, a); /* range check */ if (n < 0) { n += a->len; if (n < 0) { mrb_raise(mrb, E_INDEX_ERROR, "index %ld out of array", n - a->len); } } if (a->len <= (int)n) { if (a->aux.capa <= (int)n) ary_expand_capa(mrb, a, n + 1); ary_fill_with_nil(a->ptr + a->len, n + 1 - a->len); a->len = n + 1; } a->ptr[n] = val; mrb_write_barrier(mrb, (struct RBasic*)a); }
/* self = [1,2,3] item = 0 self.unshift item p self #=> [0, 1, 2, 3] */ mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item) { struct RArray *a = mrb_ary_ptr(self); if ((a->flags & MRB_ARY_SHARED) && a->aux.shared->refcnt == 1 /* shared only referenced from this array */ && a->ptr - a->aux.shared->ptr >= 1) /* there's room for unshifted item */ { a->ptr--; a->ptr[0] = item; } else { ary_modify(mrb, a); if (a->aux.capa < a->len + 1) ary_expand_capa(mrb, a, a->len + 1); memmove(a->ptr + 1, a->ptr, sizeof(mrb_value)*a->len); a->ptr[0] = item; } a->len++; mrb_write_barrier(mrb, (struct RBasic*)a); return self; }
MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a) { struct mrb_context *c = mrb->c; 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 (!c->prev) { mrb_raise(mrb, E_FIBER_ERROR, "can't yield from root fiber"); } c->prev->status = MRB_FIBER_RUNNING; c->status = MRB_FIBER_SUSPENDED; mrb->c = c->prev; c->prev = NULL; MARK_CONTEXT_MODIFY(mrb->c); mrb_write_barrier(mrb, (struct RBasic*)c->fib); return fiber_result(mrb, a, len); }