Object* System::vm_check_super_callable(STATE, CallFrame* call_frame) { if(call_frame->native_method_p()) return Qtrue; Module* mod = call_frame->module()->superclass(); MethodTableBucket* entry; Symbol* sym = call_frame->original_name(); while(!mod->nil_p()) { entry = mod->method_table()->find_entry(state, sym); if(entry) { if(entry->undef_p(state)) return Qfalse; // It's callable, ok, but see if we should see if it's just a stub // to change the visibility of another method. if(!entry->method()->nil_p()) { return Qtrue; } } mod = mod->superclass(); } return Qfalse; }
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; }
Object* System::vm_check_callable(STATE, Object* obj, Symbol* sym, Object* self) { Module* mod = obj->lookup_begin(state); MethodTableBucket* entry; bool skip_vis_check = false; while(!mod->nil_p()) { entry = mod->method_table()->find_entry(state, sym); if(entry) { if(entry->undef_p(state)) return Qfalse; if(!skip_vis_check) { if(entry->private_p(state)) return Qfalse; if(entry->protected_p(state)) { if(!self->kind_of_p(state, mod)) return Qfalse; } } // It's callable, ok, but see if we should see if it's just a stub // to change the visibility of another method. if(entry->method()->nil_p()) { skip_vis_check = true; } else { return Qtrue; } } mod = mod->superclass(); } return Qfalse; }
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::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, Executable* method, Symbol* vis) { MethodTableBucket *entry = state->new_object<MethodTableBucket>(G(methtblbucket)); entry->name(state, name); entry->method(state, method); entry->visibility(state, vis); return entry; }
bool InlineCache::fill_private(STATE, Symbol* name, Module* start) { MethodTableBucket* entry; Module* module = start; // Check the global cache first! GlobalCache::cache_entry* global_entry = state->global_cache->lookup(module, name); if(global_entry && !global_entry->method_missing) { this->method = global_entry->method; this->module = global_entry->module; return true; } do { entry = module->method_table()->find_entry(state, name); /* Nothing, there? Ok, keep looking. */ if(entry) { /* A 'false' method means to terminate method lookup. * (eg. undef_method) */ if(entry->undef_p(state)) return false; /* The method was callable, but we need to keep looking * for the implementation, so make the invocation bypass all further * visibility checks. * * This is pretty much always where a subclass marks a superclass * method as public. We don't move the method, we just put this * marker into the method table. */ if(!entry->method()->nil_p()) { this->method = entry->method(); this->module = module; state->global_cache->retain(state, start, name, this->module, this->method, false, !entry->public_p(state)); return true; } } module = module->superclass(); /* No more places to look, we couldn't find it. */ if(module->nil_p()) return false; } while(1); // Shouldn't be here! rubinius::abort(); }
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; }
Executable* Module::find_method(Symbol* name, Module** defined_in) { Module* mod = this; do { MethodTableBucket* buk = mod->method_table()->find_entry(name); if(buk) { if(defined_in) *defined_in = mod; return buk->method(); } mod = mod->superclass(); } while(!mod->nil_p()); return NULL; }
bool InlineCache::fill_method_missing(STATE, Class* klass, MethodCacheEntry*& mce) { MethodTableBucket* entry; Module* module = klass; Symbol* name = G(sym_method_missing); do { entry = module->method_table()->find_entry(state, name); /* Nothing, there? Ok, keep looking. */ if(entry) { /* A 'false' method means to terminate method lookup. * (eg. undef_method) */ if(entry->undef_p(state)) return false; /* The method was callable, but we need to keep looking * for the implementation, so make the invocation bypass all further * visibility checks. * * This is pretty much always where a subclass marks a superclass * method as public. We don't move the method, we just put this * marker into the method table. */ if(!entry->method()->nil_p()) { if(Alias* alias = try_as<Alias>(entry->method())) { mce = MethodCacheEntry::create(state, klass, alias->original_module(), alias->original_exec()); } else { mce = MethodCacheEntry::create(state, klass, module, entry->method()); } return true; } } module = module->superclass(); /* No more places to look, we couldn't find it. */ if(module->nil_p()) return false; } while(1); // Shouldn't be here! rubinius::bug("Control flow bug in method lookup"); }
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); }
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; }
MethodTable* MethodTable::duplicate(STATE) { size_t size, i; MethodTable *dup; size = bins_->to_native(); dup = MethodTable::create(state, size); // Allow for subclassing. dup->klass(state, class_object(state)); size_t num = entries_->to_native(); Array* entries = all_entries(state); for(i = 0; i < num; i++) { MethodTableBucket* entry = as<MethodTableBucket>(entries->get(state, i)); dup->store(state, entry->name(), entry->method(), entry->visibility()); } return dup; }
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; }
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)); }
bool InlineCache::fill_method_missing(STATE, Module* module) { MethodTableBucket* entry; Symbol* name = G(sym_method_missing); do { entry = module->method_table()->find_entry(state, name); /* Nothing, there? Ok, keep looking. */ if(entry) { /* A 'false' method means to terminate method lookup. * (eg. undef_method) */ if(entry->undef_p(state)) return false; /* The method was callable, but we need to keep looking * for the implementation, so make the invocation bypass all further * visibility checks. * * This is pretty much always where a subclass marks a superclass * method as public. We don't move the method, we just put this * marker into the method table. */ if(!entry->method()->nil_p()) { this->method = entry->method(); this->module = module; return true; } } module = module->superclass(); /* No more places to look, we couldn't find it. */ if(module->nil_p()) return false; } while(1); // Shouldn't be here! rubinius::abort(); }
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; }
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; }
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; }
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>(); }
static bool hierarchy_resolve(STATE, Symbol* name, Dispatch& msg, LookupData& lookup, bool* was_private) { Module* module = lookup.from; MethodTableBucket* entry; bool skip_vis_check = false; do { entry = module->method_table()->find_entry(state, name); /* Nothing, there? Ok, keep looking. */ if(!entry) goto keep_looking; /* A 'false' method means to terminate method lookup. * (eg. undef_method) */ if(entry->undef_p(state)) return false; /* If this was a private send, then we can handle use * any method seen. */ if(lookup.priv || skip_vis_check) { /* nil means that the actual method object is 'up' from here */ if(entry->method()->nil_p()) goto keep_looking; *was_private = entry->private_p(state); if(Alias* alias = try_as<Alias>(entry->method())) { msg.method = alias->original_exec(); msg.module = alias->original_module(); } else { msg.method = entry->method(); msg.module = module; } break; } else { /* The method is private, but this wasn't a private send. */ if(entry->private_p(state)) { return false; } else if(entry->protected_p(state)) { /* The method is protected, but it's not being called from * the same module */ if(!lookup.recv->kind_of_p(state, module)) { return false; } } /* The method was callable, but we need to keep looking * for the implementation, so make the invocation bypass all further * visibility checks */ if(entry->method()->nil_p()) { skip_vis_check = true; goto keep_looking; } if(Alias* alias = try_as<Alias>(entry->method())) { msg.method = alias->original_exec(); msg.module = alias->original_module(); } else { msg.method = entry->method(); msg.module = module; } break; } keep_looking: module = module->superclass(); /* No more places to look, we couldn't find it. */ if(module->nil_p()) return false; } while(1); return true; }
MethodMissingReason InlineCache::fill_public(STATE, Object* self, Symbol* name) { MethodTableBucket* entry; Module* module = klass_; // Check the global cache first! GlobalCache::cache_entry* global_entry = state->global_cache->lookup(module, name); if(global_entry && global_entry->is_public && !global_entry->method_missing) { this->method = global_entry->method; this->module = global_entry->module; return eNone; } bool skip_vis_check = false; do { entry = module->method_table()->find_entry(state, name); /* Nothing, there? Ok, keep looking. */ if(entry) { /* A 'false' method means to terminate method lookup. * (eg. undef_method) */ if(entry->undef_p(state)) return eNormal; if(!skip_vis_check) { /* The method is private, but this wasn't a private send. */ if(entry->private_p(state)) { return ePrivate; } else if(entry->protected_p(state)) { /* The method is protected, but it's not being called from * the same module */ if(!self->kind_of_p(state, module)) { return eProtected; } } } /* The method was callable, but we need to keep looking * for the implementation, so make the invocation bypass all further * visibility checks. * * This is pretty much always where a subclass marks a superclass * method as public. We don't move the method, we just put this * marker into the method table. */ if(entry->method()->nil_p()) { skip_vis_check = true; } else { this->method = entry->method(); this->module = module; state->global_cache->retain(state, klass_, name, this->module, this->method, false, !entry->public_p(state)); return eNone; } } module = module->superclass(); /* No more places to look, we couldn't find it. */ if(module->nil_p()) return eNormal; } while(1); // Shouldn't be here! rubinius::abort(); }
static bool hierarchy_resolve(STATE, Symbol* name, Dispatch& msg, LookupData& lookup) { Module* module = lookup.from; MethodTableBucket* entry; bool skip_vis_check = false; do { if(module != module->origin()) { module = module->superclass(); } entry = module->method_table()->find_entry(state, name); /* Nothing, there? Ok, keep looking. */ if(!entry) goto keep_looking; /* A 'false' method means to terminate method lookup. * (eg. undef_method) */ if(entry->undef_p(state)) { msg.method_missing = eNormal; return false; } /* If this was a private send, then we can handle use * any method seen. */ if(lookup.min_visibility == G(sym_private) || skip_vis_check) { /* The method was callable, but we need to keep looking * for the implementation, so make the invocation bypass all further * visibility checks. If we are skipping visibility checks we * shouldn't update visibility anymore because the implementation * might have a different visibility than the original lookup. */ if(!skip_vis_check) { msg.visibility = entry->visibility(); } if(entry->method()->nil_p() && entry->method_id()->nil_p()) { // TODO: fix using method() == cNil for this // if(entry->method()->nil_p()) { skip_vis_check = true; goto keep_looking; } if(Alias* alias = try_as<Alias>(entry->method())) { if(alias->original_exec()->nil_p()) { name = alias->original_name(); msg.visibility = entry->visibility(); skip_vis_check = true; } else { msg.method = alias->original_exec(); msg.module = alias->original_module(); } } else { msg.method = entry->get_method(state); msg.module = module; } if(msg.method) return true; } else { /* The method is private, but this wasn't a private send. */ if(entry->private_p(state)) { msg.method_missing = ePrivate; return false; } else if(entry->protected_p(state)) { /* The method is protected, but it's not being called from * the same module, or we only want public methods. */ Module* check_mod; if(IncludedModule* im = try_as<IncludedModule>(module)) { check_mod = im->module(); } else { check_mod = module; } if(lookup.min_visibility == G(sym_public) && !lookup.recv->kind_of_p(state, check_mod)) { msg.method_missing = eProtected; return false; } } /* The method was callable, but we need to keep looking * for the implementation, so make the invocation bypass all further * visibility checks. If we are skipping visibility checks we * shouldn't update visibility anymore because the implementation * might have a different visibility than the original lookup. */ if(!skip_vis_check) { msg.visibility = entry->visibility(); } if(entry->method()->nil_p() && entry->method_id()->nil_p()) { // TODO: fix using method() == cNil for this // if(entry->method()->nil_p()) { skip_vis_check = true; goto keep_looking; } if(Alias* alias = try_as<Alias>(entry->method())) { if(alias->original_exec()->nil_p()) { name = alias->original_name(); msg.visibility = entry->visibility(); skip_vis_check = true; } else { msg.method = alias->original_exec(); msg.module = alias->original_module(); } } else { msg.method = entry->get_method(state); msg.module = module; } if(msg.method) return true; } keep_looking: module = module->superclass(); /* No more places to look, we couldn't find it. */ if(module->nil_p()) { msg.method_missing = eNormal; return false; } } while(1); rubinius::bug("Control flow bug in method lookup"); }
MethodMissingReason InlineCache::fill_public(STATE, Object* self, Symbol* name) { MethodTableBucket* entry; Module* module = klass_; // Check the global cache first! GlobalCache::cache_entry* global_entry = state->global_cache()->lookup(module, name); if(global_entry && global_entry->is_public && !global_entry->method_missing) { this->method = global_entry->method; this->module = global_entry->module; return eNone; } bool skip_vis_check = false; MethodTableBucket* vis_entry = 0; Symbol* target_name = name; do { entry = module->method_table()->find_entry(state, target_name); /* Nothing, there? Ok, keep looking. */ if(entry) { /* A 'false' method means to terminate method lookup. * (eg. undef_method) */ if(entry->undef_p(state)) return eNormal; if(!skip_vis_check) { /* The method is private, but this wasn't a private send. */ if(entry->private_p(state)) { return ePrivate; } else if(entry->protected_p(state)) { /* The method is protected, but it's not being called from * the same module */ Module* check_mod; if(IncludedModule* im = try_as<IncludedModule>(module)) { check_mod = im->module(); } else { check_mod = module; } if(!self->kind_of_p(state, check_mod)) { return eProtected; } } } /* The method was callable, but we need to keep looking * for the implementation, so make the invocation bypass all further * visibility checks. * * This is pretty much always where a subclass marks a superclass * method as public. We don't move the method, we just put this * marker into the method table. */ if(entry->method()->nil_p()) { vis_entry = entry; skip_vis_check = true; } else { Module* use_module; Executable* use_exec; if(Alias* alias = try_as<Alias>(entry->method())) { // Same check as above, allow an alias to be for a superclass // method. if(alias->original_exec()->nil_p()) { vis_entry = entry; skip_vis_check = true; use_exec = 0; target_name = alias->original_name(); } else { use_exec = alias->original_exec(); use_module = alias->original_module(); } } else { use_module = module; use_exec = entry->method(); } if(use_exec) { this->module = use_module; this->method = use_exec; if(!vis_entry) vis_entry = entry; state->global_cache()->retain(state, klass_, name, this->module, this->method, false, !vis_entry->public_p(state)); return eNone; } } } module = module->superclass(); /* No more places to look, we couldn't find it. */ if(module->nil_p()) return eNormal; } while(1); // Shouldn't be here! rubinius::abort(); }
bool InlineCache::fill_private(STATE, Symbol* name, Module* start, Class* klass, MethodCacheEntry*& mce) { MethodTableBucket* entry; Module* module = start; // Check the global cache first! mce = state->vm()->global_cache()->lookup_private(state, start, klass, name); if(mce) return true; MethodTableBucket* vis_entry = 0; do { entry = module->method_table()->find_entry(state, name); /* Nothing, there? Ok, keep looking. */ if(entry) { /* A 'false' method means to terminate method lookup. * (eg. undef_method) */ if(entry->undef_p(state)) return false; /* The method was callable, but we need to keep looking * for the implementation, so make the invocation bypass all further * visibility checks. * * This is pretty much always where a subclass marks a superclass * method as public. We don't move the method, we just put this * marker into the method table. */ if(!entry->method()->nil_p()) { if(Alias* alias = try_as<Alias>(entry->method())) { mce = MethodCacheEntry::create(state, klass, alias->original_module(), alias->original_exec()); } else { mce = MethodCacheEntry::create(state, klass, module, entry->method()); } if(!vis_entry) vis_entry = entry; state->vm()->global_cache()->retain(state, start, name, mce->stored_module(), mce->method(), false, !vis_entry->public_p(state)); return true; } else { // Remember this entry as defining the visibility vis_entry = entry; } } module = module->superclass(); /* No more places to look, we couldn't find it. */ if(module->nil_p()) return false; } while(1); // Shouldn't be here! rubinius::bug("Control flow bug in method lookup"); }