Permalink
Browse files

Use the proper method (!!) when inlining.

Wow, this was a crappy bug. If the IC had 2 classes, we used
cache_->method, but that might not have had been the method for the
dominating class! Oops.
  • Loading branch information...
1 parent 14d173f commit cf84c91c5f8aab3934f72df503fe5329be3b020d Evan Phoenix committed Jul 15, 2009
Showing with 76 additions and 9 deletions.
  1. +16 −0 vm/builtin/methodtable.cpp
  2. +1 −0 vm/builtin/methodtable.hpp
  3. +13 −0 vm/builtin/module.cpp
  4. +2 −0 vm/builtin/module.hpp
  5. +17 −6 vm/llvm/inline.cpp
  6. +22 −3 vm/llvm/jit_operations.hpp
  7. +5 −0 vm/ontology.cpp
View
@@ -149,6 +149,22 @@ namespace rubinius {
return 0;
}
+ 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::lookup(STATE, Symbol* name) {
if(MethodTableBucket* bucket = find_entry(state, name)) {
return bucket;
@@ -73,6 +73,7 @@ namespace rubinius {
void redistribute(STATE, size_t size);
MethodTableBucket* find_entry(STATE, Symbol* name);
+ MethodTableBucket* find_entry(Symbol* name);
// Ruby.primitive :methodtable_lookup
MethodTableBucket* lookup(STATE, Symbol* name);
View
@@ -95,6 +95,19 @@ namespace rubinius {
state->global_cache->clear(this, name);
}
+ Executable* Module::find_method(Symbol* name) {
+ MethodTableBucket* buk;
+ Module* mod = this;
+
+ do {
+ buk = mod->method_table()->find_entry(name);
+ if(buk) return buk->method();
+ mod = mod->superclass();
+ } while(!mod->nil_p());
+
+ return NULL;
+ }
+
void Module::Info::show(STATE, Object* self, int level) {
Module* mod = as<Module>(self);
View
@@ -54,6 +54,8 @@ namespace rubinius {
void add_method(STATE, Symbol* name, Executable* exec, Symbol* vis = 0);
+ Executable* find_method(Symbol* name);
+
class Info : public TypeInfo {
public:
BASIC_TYPEINFO(TypeInfo)
View
@@ -4,6 +4,8 @@
#include "llvm/inline.hpp"
#include "llvm/jit_workhorse.hpp"
+#include "builtin/methodtable.hpp"
+
namespace rubinius {
bool Inliner::consider() {
Class* klass = cache_->dominating_class();
@@ -25,7 +27,16 @@ namespace rubinius {
// If the cache has a dominating class, inline!
AccessManagedMemory memguard(ops_.state());
- Executable* meth = cache_->method;
+
+ Executable* meth = klass->find_method(cache_->name);
+ if(!meth) {
+ if(ops_.state()->config().jit_inline_debug) {
+ std::cerr << "NOT inlining: "
+ << ops_.state()->symbol_cstr(cache_->name)
+ << ". Inliner error, method missing.\n";
+ }
+ return false;
+ }
if(AccessVariable* acc = try_as<AccessVariable>(meth)) {
if(acc->write()->true_p()) {
@@ -37,7 +48,7 @@ namespace rubinius {
VMMethod* vmm = cm->backend_method_;
if(!cm->primitive()->nil_p()) {
- if(!inline_primitive(klass, cm, cache_->method->execute)) return false;
+ if(!inline_primitive(klass, cm, meth->execute)) return false;
} else if(detect_trivial_method(cm)) {
inline_trivial_method(klass, cm);
} else if(ops_.state()->config().jit_inline_generic) {
@@ -75,7 +86,7 @@ namespace rubinius {
<< ops_.state()->symbol_cstr(cm->name())
<< " into "
<< ops_.state()->symbol_cstr(ops_.vmmethod()->original->name())
- << "\n";
+ << " (" << ops_.state()->symbol_cstr(klass->name()) << ")\n";
}
NoAccessManagedMemory unmemguard(ops_.state());
@@ -96,9 +107,9 @@ namespace rubinius {
} else {
if(ops_.state()->config().jit_inline_debug) {
std::cerr << "NOT inlining: "
- << ops_.state()->symbol_cstr(cm->scope()->module()->name())
+ << ops_.state()->symbol_cstr(klass->name())
<< "#"
- << ops_.state()->symbol_cstr(cm->name())
+ << ops_.state()->symbol_cstr(cache_->name)
<< " into "
<< ops_.state()->symbol_cstr(ops_.vmmethod()->original->name())
<< ". unhandled executable type\n";
@@ -128,7 +139,7 @@ namespace rubinius {
}
break;
case InstructionSequence::insn_meta_push_0:
- // case InstructionSequence::insn_meta_push_1:
+ case InstructionSequence::insn_meta_push_1:
case InstructionSequence::insn_meta_push_2:
case InstructionSequence::insn_meta_push_neg_1:
case InstructionSequence::insn_push_self:
View
@@ -247,6 +247,10 @@ namespace rubinius {
return create_equal(lint, zero, "is_fixnum");
}
+ Value* check_is_immediate(Value* obj, Object* imm) {
+ return create_equal(obj, constant(imm), "is_immediate");
+ }
+
void verify_guard(Value* cmp, BasicBlock* failure) {
BasicBlock* cont = new_block("guarded_body");
create_conditional_branch(cont, failure, cmp);
@@ -257,12 +261,27 @@ namespace rubinius {
}
void check_class(Value* obj, Class* klass, BasicBlock* failure) {
- if(klass->instance_type()->to_native() == rubinius::Symbol::type) {
+ object_type type = (object_type)klass->instance_type()->to_native();
+
+ switch(type) {
+ case rubinius::Symbol::type:
verify_guard(check_is_symbol(obj), failure);
- } else if(klass->instance_type()->to_native() == rubinius::Fixnum::type) {
+ break;
+ case rubinius::Fixnum::type:
verify_guard(check_is_fixnum(obj), failure);
- } else {
+ break;
+ case NilType:
+ verify_guard(check_is_immediate(obj, Qnil), failure);
+ break;
+ case TrueType:
+ verify_guard(check_is_immediate(obj, Qtrue), failure);
+ break;
+ case FalseType:
+ verify_guard(check_is_immediate(obj, Qfalse), failure);
+ break;
+ default:
check_reference_class(obj, klass->class_id(), failure);
+ break;
}
}
View
@@ -172,8 +172,13 @@ namespace rubinius {
void VM::initialize_builtin_classes() {
// Create the immediate classes.
GO(nil_class).set(new_class("NilClass"));
+ G(nil_class)->set_object_type(state, NilType);
+
GO(true_class).set(new_class("TrueClass"));
+ G(true_class)->set_object_type(state, TrueType);
+
GO(false_class).set(new_class("FalseClass"));
+ G(false_class)->set_object_type(state, FalseType);
Class* numeric = new_class("Numeric");
GO(numeric).set(numeric);

0 comments on commit cf84c91

Please sign in to comment.