예제 #1
0
파일: class.cpp 프로젝트: KensoDev/rubinius
  /* Look at this class and it's superclass contents (which includes
   * included modules) and calculate out how to allocate the slots.
   *
   * This locks the class so that construction is serialized.
   */
  void Class::auto_pack(STATE, GCToken gct) {
    Class* self = this;
    OnStack<1> os(state, self);

    hard_lock(state, gct);

    // If another thread did this work while we were waiting on the lock,
    // don't redo it.
    if(self->type_info_->type == PackedObject::type) {
      hard_unlock(state, gct);
      return;
    }

    size_t slots = 0;

    LookupTable* lt = LookupTable::create(state);

    // If autopacking is enabled, figure out how many slots to use.
    if(state->shared().config.gc_autopack) {
      Module* mod = self;

      int slot = 0;

      while(!mod->nil_p()) {
        Array* info = 0;

        if(Class* cls = try_as<Class>(mod)) {
          info = cls->seen_ivars();
        } else if(IncludedModule* im = try_as<IncludedModule>(mod)) {
          info = im->module()->seen_ivars();
        }

        if(info && !info->nil_p()) {
          for(size_t i = 0; i < info->size(); i++) {
            if(Symbol* sym = try_as<Symbol>(info->get(state, i))) {
              bool found = false;
              lt->fetch(state, sym, &found);

              if(!found) {
                lt->store(state, sym, Fixnum::from(slot++));
              }
            }

            // Limit the number of packed ivars to 25.
            if(slot > 25) break;
          }
        }

        mod = mod->superclass();
      }
      slots = lt->entries()->to_native();
    }

    packed_size_ = sizeof(Object) + (slots * sizeof(Object*));
    self->packed_ivar_info(state, lt);

    self->set_object_type(state, PackedObject::type);

    self->hard_unlock(state, gct);
  }
예제 #2
0
  void test_fetch_returns_given_when_not_found() {
    TS_ASSERT_EQUALS(as<Integer>(tbl->entries())->to_native(), 0);
    tbl->store(state, cNil, Fixnum::from(47));
    TS_ASSERT_EQUALS(as<Integer>(tbl->entries())->to_native(), 1);

    Object* out = tbl->fetch(state, cTrue, cUndef);
    TS_ASSERT_EQUALS(cUndef, out);
  }
예제 #3
0
  void test_fetch_returns_found() {
    TS_ASSERT_EQUALS(as<Integer>(tbl->entries())->to_native(), 0);
    tbl->store(state, Qnil, Fixnum::from(47));
    TS_ASSERT_EQUALS(as<Integer>(tbl->entries())->to_native(), 1);

    Object* out = tbl->fetch(state, Qnil, Qundef);
    TS_ASSERT_EQUALS(as<Integer>(out)->to_native(), 47);
  }
  void test_to_lookuptable() {
    LookupTable* lt;
    Object* key = Fixnum::from(1);
    Object* val = Fixnum::from(2);

    tbl->put(state, 2, key);
    tbl->put(state, 3, val);
    lt = tbl->to_lookuptable(state);

    TS_ASSERT_EQUALS(lt->fetch(state, key), val);
  }
예제 #5
0
  Object* CallFrame::find_breakpoint(STATE) {
    if(!compiled_code) return 0;

    LookupTable* tbl = compiled_code->breakpoints();
    if(tbl->nil_p()) return 0;

    bool found = false;

    Object* obj = tbl->fetch(state, Fixnum::from(ip()), &found);
    if(found) return obj;

    return 0;
  }
예제 #6
0
  Object* PackedObject::set_packed_ivar(STATE, Symbol* sym, Object* val) {
    LookupTable* tbl = this->reference_class()->packed_ivar_info();
    bool found = false;

    Fixnum* which = try_as<Fixnum>(tbl->fetch(state, sym, &found));
    if(!found) {
      return set_table_ivar(state, sym, val);
    }

    body_as_array()[which->to_native()] = val;
    if(val->reference_p()) write_barrier(state, val);
    return val;
  }
예제 #7
0
  Object* PackedObject::packed_ivar_defined(STATE, Symbol* sym) {
    LookupTable* tbl = this->reference_class()->packed_ivar_info();
    bool found = false;

    Fixnum* which = try_as<Fixnum>(tbl->fetch(state, sym, &found));
    if(!found) {
      return table_ivar_defined(state, sym);
    }

    Object* obj = body_as_array()[which->to_native()];
    if(obj == Qundef) return Qfalse;
    return Qtrue;
  }
예제 #8
0
  Object* PackedObject::get_packed_ivar(STATE, Symbol* sym) {
    LookupTable* tbl = this->reference_class()->packed_ivar_info();
    assert(tbl && !tbl->nil_p());

    Fixnum* which = try_as<Fixnum>(tbl->fetch(state, sym));
    if(!which) {
      return get_table_ivar(state, sym);
    }

    Object* obj = body_as_array()[which->to_native()];
    if(obj == Qundef) return Qnil;
    return obj;
  }
예제 #9
0
  void Transcoding::declare(STATE, const char* from, const char* to, const char* lib) {
    LookupTable* map = Encoding::transcoding_map(state);
    Object* obj = map->fetch(state, encoding_symbol(state, from));
    LookupTable* table;

    if(obj->nil_p()) {
      table = LookupTable::create(state);
      map->store(state, encoding_symbol(state, from), table);
    } else {
      table = as<LookupTable>(obj);
    }

    table->store(state, encoding_symbol(state, to), String::create(state, lib));
  }
예제 #10
0
  void PackedObject::add_packed_ivars(STATE, Array* ary) {
    LookupTable* tbl = this->reference_class()->packed_ivar_info();

    LookupTable::iterator i(tbl);

    while(i.advance()) {
      Object* key = i.key();
      if(Fixnum* which = try_as<Fixnum>(tbl->fetch(state, key))) {
        if(body_as_array()[which->to_native()] != Qundef) {
          ary->append(state, key);
        }
      }
    }
  }
예제 #11
0
  void test_remove() {
    Object* k = Fixnum::from(47);
    tbl->store(state, k, cTrue);

    Object* out = tbl->find(state, k);
    TS_ASSERT_EQUALS(out, cTrue);

    out = tbl->remove(state, k);
    TS_ASSERT_EQUALS(out, cTrue);
    TS_ASSERT_EQUALS(as<Integer>(tbl->entries())->to_native(), 0);

    out = tbl->fetch(state, k);
    TS_ASSERT_EQUALS(out, cNil);
  }
예제 #12
0
  void Transcoding::define(STATE, OnigTranscodingType* tr) {
    LookupTable* map = Encoding::transcoding_map(state);
    Object* obj = map->fetch(state, encoding_symbol(state, tr->src_encoding));
    LookupTable* table;

    if(obj->nil_p()) {
      table = LookupTable::create(state);
      map->store(state, encoding_symbol(state, tr->src_encoding), table);
    } else {
      table = as<LookupTable>(obj);
    }

    Transcoding* t = Transcoding::create(state, tr);
    table->store(state, encoding_symbol(state, tr->dst_encoding), t);
  }
예제 #13
0
  void PackedObject::add_packed_ivars(STATE, Array* ary) {
    LookupTable* tbl = this->reference_class()->packed_ivar_info();
    assert(tbl && !tbl->nil_p());

    Array* keys = tbl->all_keys(state);

    for(size_t i = 0; i < keys->size(); i++) {
      Object* key = keys->get(state, i);
      if(Fixnum* which = try_as<Fixnum>(tbl->fetch(state, key))) {
        if(body_as_array()[which->to_native()] != Qundef) {
          ary->append(state, key);
        }
      }
    }
  }
예제 #14
0
  Object* PackedObject::packed_ivar_delete(STATE, Symbol* sym, bool* removed) {
    LookupTable* tbl = this->reference_class()->packed_ivar_info();
    bool found = false;

    Fixnum* which = try_as<Fixnum>(tbl->fetch(state, sym, &found));
    if(!found) {
      return del_table_ivar(state, sym, removed);
    }

    if(removed) *removed = true;

    Object* val = body_as_array()[which->to_native()];
    body_as_array()[which->to_native()] = Qundef;

    return val;
  }
예제 #15
0
  VALUE rb_protect_inspect(VALUE (*func)(VALUE a, VALUE b), VALUE h_obj, VALUE h_arg) {
    NativeMethodEnvironment* env = NativeMethodEnvironment::get();
    STATE = env->state();

    Thread* thr = Thread::current(state);
    LookupTable* rectbl = thr->recursive_objects();

    Object* obj = env->get_object(h_obj);

    Object* id = obj->id(state);

    bool found = false;
    rectbl->fetch(state, id, &found);

    if(found) {
      return (*func)(h_obj, h_arg);
    }

    rectbl->store(state, id, cTrue);

    VALUE ret = Qnil;

    ExceptionPoint ep(env);
    PLACE_EXCEPTION_POINT(ep);

    bool unwinding = false;

    if(unlikely(ep.jumped_to())) {
      unwinding = true;
    } else {
      ret = (*func)(h_obj, h_arg);
    }

    ep.pop(env);

    // Get the thread and table again, the GC might have fun.
    thr = Thread::current(state);
    rectbl = thr->recursive_objects();
    obj = env->get_object(h_obj);
    id = obj->id(state);

    rectbl->remove(state, id);

    if(unwinding) env->current_ep()->return_to(env);

    return ret;
  }
예제 #16
0
  VALUE rb_inspecting_p(VALUE h_obj) {
    NativeMethodEnvironment* env = NativeMethodEnvironment::get();
    STATE = env->state();

    Thread* thr = Thread::current(state);
    LookupTable* rectbl = thr->recursive_objects();

    Object* obj = env->get_object(h_obj);

    Object* id = obj->id(state);

    bool found = false;
    rectbl->fetch(state, id, &found);

    if(found) return Qtrue;
    return Qfalse;
  }