/* 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); }
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); }
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); }
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; }
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; }
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; }
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; }
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)); }
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); } } } }
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); }
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); }
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); } } } }
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; }
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; }
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; }