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(); for(i = 0; i < num; i++) { MethodTableBucket* entry = try_as<MethodTableBucket>(values_->at(state, i)); while(entry) { dup->store(state, entry->name(), entry->method_id(), entry->method(), entry->scope(), entry->serial(), entry->visibility()); entry = try_as<MethodTableBucket>(entry->next()); } } return dup; }
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* method_id, Object* method, Object* scope, Fixnum* serial, Symbol* visibility) { check_frozen(state); utilities::thread::SpinLock::LockGuard lg(lock_); if(!method->nil_p()) { if(Alias* stored_alias = try_as<Alias>(method)) { lock_.unlock(); Object* res = alias(state, name, visibility, stored_alias->original_name(), stored_alias->original_exec(), stored_alias->original_module()); lock_.lock(); return res; } } 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, method_id); entry->method(state, method); entry->scope(state, scope); entry->serial(state, serial); entry->visibility(state, visibility); return name; } last = entry; entry = try_as<MethodTableBucket>(entry->next()); } if(last) { last->next(state, MethodTableBucket::create( state, name, method_id, method, scope, serial, visibility)); } else { values_->put(state, bin, MethodTableBucket::create( state, name, method_id, method, scope, serial, visibility)); } entries(state, Fixnum::from(num_entries + 1)); return name; }
MethodTableBucket* MethodTableBucket::create(STATE, Symbol* name, Object* method_id, Object* method, Object* scope, Fixnum* serial, Symbol* vis) { MethodTableBucket *entry = state->new_object<MethodTableBucket>(G(methtblbucket)); entry->name(state, name); entry->method_id(state, method_id); entry->method(state, method); entry->scope(state, scope); entry->serial(state, serial); entry->visibility(state, vis); return entry; }