Пример #1
0
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));
}
Пример #2
0
/*
 *  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);
}
Пример #3
0
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);
}
Пример #4
0
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;
}
Пример #5
0
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);
}
Пример #6
0
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);
}
Пример #7
0
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);
  }
}
Пример #8
0
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;
}
Пример #9
0
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);
  }
}
Пример #10
0
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;
  }
}
Пример #11
0
/*
 *  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;
}
Пример #12
0
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;
}
Пример #13
0
Файл: gc.c Проект: anehing/mruby
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);
}
Пример #14
0
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;
}