Executable* MethodTable::remove(STATE, Symbol* name) { hashval bin; MethodTableBucket* entry; MethodTableBucket* last = NULL; size_t num_entries = entries_->to_native(); size_t num_bins = bins_->to_native(); if(min_density_p(num_entries, num_bins) && (num_bins >> 1) >= METHODTABLE_MIN_SIZE) { redistribute(state, num_bins >>= 1); } bin = find_bin(key_hash(name), num_bins); entry = try_as<MethodTableBucket>(values_->at(state, bin)); while(entry) { if(entry->name() == name) { Executable* val = entry->method(); if(last) { last->next(state, entry->next()); } else { values_->put(state, bin, entry->next()); } entries(state, Fixnum::from(entries_->to_native() - 1)); return val; } last = entry; entry = try_as<MethodTableBucket>(entry->next()); } return reinterpret_cast<Executable*>(Qnil); }
void MethodTable::redistribute(STATE, size_t size) { size_t num = bins_->to_native(); Tuple* new_values = Tuple::create(state, size); for(size_t i = 0; i < num; i++) { MethodTableBucket* entry = try_as<MethodTableBucket>(values_->at(state, i)); while(entry) { MethodTableBucket* link = try_as<MethodTableBucket>(entry->next()); entry->next(state, nil<MethodTableBucket>()); size_t bin = find_bin(key_hash(entry->name()), size); MethodTableBucket* slot = try_as<MethodTableBucket>(new_values->at(state, bin)); if(slot) { slot->append(state, entry); } else { new_values->put(state, bin, entry); } entry = link; } } values(state, new_values); bins(state, Fixnum::from(size)); }
Object* MethodTable::alias(STATE, Symbol* name, Symbol* vis, Symbol* orig_name, Object* orig_method, Module* orig_mod) { check_frozen(state); utilities::thread::SpinLock::LockGuard lg(lock_); Executable* orig_exec; if(Alias* alias = try_as<Alias>(orig_method)) { orig_exec = alias->original_exec(); orig_mod = alias->original_module(); orig_name = alias->original_name(); } else if(orig_method->nil_p()) { orig_exec = nil<Executable>(); } else { orig_exec = as<Executable>(orig_method); } Alias* method = Alias::create(state, orig_name, orig_mod, orig_exec); native_int num_entries = entries_->to_native(); native_int num_bins = bins_->to_native(); if(max_density_p(num_entries, num_bins)) { redistribute(state, num_bins <<= 1); } native_int bin = find_bin(key_hash(name), num_bins); MethodTableBucket* entry = try_as<MethodTableBucket>(values_->at(state, bin)); MethodTableBucket* last = NULL; while(entry) { if(entry->name() == name) { entry->method_id(state, nil<String>()); entry->method(state, method); entry->scope(state, cNil); entry->serial(state, Fixnum::from(0)); entry->visibility(state, vis); return name; } last = entry; entry = try_as<MethodTableBucket>(entry->next()); } if(last) { last->next(state, MethodTableBucket::create( state, name, nil<String>(), method, cNil, Fixnum::from(0), vis)); } else { values_->put(state, bin, MethodTableBucket::create( state, name, nil<String>(), method, cNil, Fixnum::from(0), vis)); } entries(state, Fixnum::from(num_entries + 1)); return name; }
Object* MethodTable::store(STATE, Symbol* name, Object* exec, Symbol* vis) { check_frozen(state); utilities::thread::SpinLock::LockGuard lg(lock_); Executable* method; if(exec->nil_p()) { method = nil<Executable>(); } else { if(Alias* stored_alias = try_as<Alias>(exec)) { lock_.unlock(); Object* res = alias(state, name, vis, stored_alias->original_name(), stored_alias->original_exec(), stored_alias->original_module()); lock_.lock(); return res; } else { method = as<Executable>(exec); } } native_int num_entries = entries_->to_native(); native_int num_bins = bins_->to_native(); if(max_density_p(num_entries, num_bins)) { redistribute(state, num_bins <<= 1); } native_int bin = find_bin(key_hash(name), num_bins); MethodTableBucket* entry = try_as<MethodTableBucket>(values_->at(state, bin)); MethodTableBucket* last = NULL; while(entry) { if(entry->name() == name) { entry->method(state, method); entry->visibility(state, vis); return name; } last = entry; entry = try_as<MethodTableBucket>(entry->next()); } if(last) { last->next(state, MethodTableBucket::create(state, name, method, vis)); } else { values_->put(state, bin, MethodTableBucket::create(state, name, method, vis)); } entries(state, Fixnum::from(num_entries + 1)); return name; }
Object* MethodTableBucket::append(STATE, MethodTableBucket* nxt) { MethodTableBucket* cur = try_as<MethodTableBucket>(this->next()); MethodTableBucket* last = this; while(cur) { last = cur; cur = try_as<MethodTableBucket>(cur->next()); } last->next(state, nxt); return nxt; }
MethodTable* MethodTable::duplicate(STATE) { size_t size, i; MethodTable* dup = 0; utilities::thread::SpinLock::LockGuard lg(lock_); size = bins_->to_native(); dup = MethodTable::create(state, size); // Allow for subclassing. dup->klass(state, class_object(state)); size_t num = bins_->to_native(); MethodTableBucket* entry = 0; for(i = 0; i < num; i++) { entry = try_as<MethodTableBucket>(values_->at(state, i)); while(entry) { dup->store(state, entry->name(), entry->method(), entry->visibility()); entry = try_as<MethodTableBucket>(entry->next()); } } return dup; }
void MethodTable::Info::show(STATE, Object* self, int level) { MethodTable* tbl = as<MethodTable>(self); size_t size = tbl->bins()->to_native(); if(size == 0) { class_info(state, self, true); return; } class_info(state, self); std::cout << ": " << size << std::endl; indent(++level); for(size_t i = 0; i < size; i++) { MethodTableBucket* entry = try_as<MethodTableBucket>(tbl->values()->at(state, i)); while(entry) { if(Symbol* sym = try_as<Symbol>(entry->name())) { std::cout << ":" << sym->debug_str(state); } else if(Fixnum* fix = try_as<Fixnum>(entry->name())) { std::cout << fix->to_native(); } entry = try_as<MethodTableBucket>(entry->next()); } if(i < size - 1) std::cout << ", "; } std::cout << std::endl; close_body(level); }
Object* MethodTable::store(STATE, Symbol* name, Object* exec, Symbol* vis) { unsigned int num_entries, num_bins, bin; MethodTableBucket* entry; MethodTableBucket* last = NULL; Executable* method; if(exec->nil_p()) { method = reinterpret_cast<Executable*>(Qnil); } else { if(Alias* alias = try_as<Alias>(exec)) { method = alias->original_exec(); } else { method = as<Executable>(exec); } } num_entries = entries_->to_native(); num_bins = bins_->to_native(); if(max_density_p(num_entries, num_bins)) { redistribute(state, num_bins <<= 1); } bin = find_bin(key_hash(name), num_bins); entry = try_as<MethodTableBucket>(values_->at(state, bin)); while(entry) { if(entry->name() == name) { entry->method(state, method); entry->visibility(state, vis); return name; } last = entry; entry = try_as<MethodTableBucket>(entry->next()); } if(last) { last->next(state, MethodTableBucket::create(state, name, method, vis)); } else { values_->put(state, bin, MethodTableBucket::create(state, name, method, vis)); } entries(state, Fixnum::from(num_entries + 1)); return name; }
Object* MethodTable::alias(STATE, Symbol* name, Symbol* vis, Symbol* orig_name, Executable* orig_method, Module* orig_mod) { unsigned int num_entries, num_bins, bin; MethodTableBucket* entry; MethodTableBucket* last = NULL; if(Alias* alias = try_as<Alias>(orig_method)) { orig_method = alias->original_exec(); orig_mod = alias->original_module(); orig_name = alias->original_name(); } Alias* method = Alias::create(state, orig_name, orig_mod, orig_method); num_entries = entries_->to_native(); num_bins = bins_->to_native(); if(max_density_p(num_entries, num_bins)) { redistribute(state, num_bins <<= 1); } bin = find_bin(key_hash(name), num_bins); entry = try_as<MethodTableBucket>(values_->at(state, bin)); while(entry) { if(entry->name() == name) { entry->method(state, method); entry->visibility(state, vis); return name; } last = entry; entry = try_as<MethodTableBucket>(entry->next()); } if(last) { last->next(state, MethodTableBucket::create(state, name, method, vis)); } else { values_->put(state, bin, MethodTableBucket::create(state, name, method, vis)); } entries(state, Fixnum::from(num_entries + 1)); return name; }
Executable* MethodTable::remove(STATE, Symbol* name) { check_frozen(state); utilities::thread::SpinLock::LockGuard lg(lock_); native_int num_entries = entries_->to_native(); native_int num_bins = bins_->to_native(); if(min_density_p(num_entries, num_bins) && (num_bins >> 1) >= METHODTABLE_MIN_SIZE) { redistribute(state, num_bins >>= 1); } native_int bin = find_bin(key_hash(name), num_bins); MethodTableBucket* entry = try_as<MethodTableBucket>(values_->at(state, bin)); MethodTableBucket* last = NULL; while(entry) { if(entry->name() == name) { Executable* val = entry->method(); if(last) { last->next(state, entry->next()); } else { values_->put(state, bin, entry->next()); } entries(state, Fixnum::from(entries_->to_native() - 1)); return val; } last = entry; entry = try_as<MethodTableBucket>(entry->next()); } return nil<Executable>(); }
MethodTableBucket* MethodTable::find_entry(Symbol* name) { unsigned int bin; bin = find_bin(key_hash(name), bins_->to_native()); MethodTableBucket *entry = try_as<MethodTableBucket>(values_->at(bin)); while(entry) { if(entry->name() == name) { return entry; } entry = try_as<MethodTableBucket>(entry->next()); } return 0; }
MethodTableBucket* MethodTable::find_entry(Symbol* name) { unsigned int bin; utilities::thread::SpinLock::LockGuard lg(lock_); bin = find_bin(key_hash(name), bins_->to_native()); MethodTableBucket *entry = try_as<MethodTableBucket>(values_->at(bin)); while(entry) { if(entry->name() == name) { return entry; } entry = try_as<MethodTableBucket>(entry->next()); } return 0; }
Array* MethodTable::collect(STATE, MethodTable* tbl, Object* (*action)(STATE, MethodTableBucket*)) { size_t i, j; Tuple* values; MethodTableBucket* entry; Array* ary = Array::create(state, tbl->entries()->to_native()); size_t num_bins = tbl->bins()->to_native(); values = tbl->values(); for(i = j = 0; i < num_bins; i++) { entry = try_as<MethodTableBucket>(values->at(state, i)); while(entry) { ary->set(state, j++, action(state, entry)); entry = try_as<MethodTableBucket>(entry->next()); } } return ary; }