Object* CallSite::empty_cache(STATE, CallSite* call_site, CallFrame* call_frame, Arguments& args) { Object* const recv = args.recv(); Class* const recv_class = recv->direct_class(state); LookupData lookup(call_frame->self(), recv->lookup_begin(state), G(sym_public)); Dispatch dis(call_site->name()); if(!dis.resolve(state, call_site->name(), lookup)) { if(!lookup_method_missing(state, call_frame, args, dis, call_frame->self(), recv->lookup_begin(state))) { return NULL; } } state->vm()->metrics().machine.methods_invoked++; call_site->update(state, recv_class, dis); Executable* meth = dis.method; Module* mod = dis.module; if(meth->custom_call_site_p()) { CallSiteInformation info(call_site->executable(), call_site->ip()); state->set_call_site_information(&info); Object* res = meth->execute(state, call_frame, meth, mod, args); state->set_call_site_information(NULL); return res; } else { return meth->execute(state, call_frame, meth, mod, args); } }
Object* CallSite::empty_cache_super(STATE, CallSite* call_site, CallFrame* call_frame, Arguments& args) { Symbol* original_name = call_frame->original_name(); if(call_site->name_ != original_name) { call_site->name_ = original_name; args.set_name(call_site->name_); } Object* const recv = args.recv(); Class* const recv_class = recv->direct_class(state); Module* const start = call_frame->module()->superclass(); LookupData lookup(call_frame->self(), start, G(sym_private)); Dispatch dis(call_site->name()); if(start->nil_p() || !dis.resolve(state, call_site->name(), lookup)) { LookupData missing_lookup(call_frame->self(), recv->lookup_begin(state), G(sym_private)); Dispatch missing_dis(G(sym_method_missing)); if(!missing_dis.resolve(state, G(sym_method_missing), missing_lookup)) { std::ostringstream msg; msg << "no method_missing for "; msg << recv_class->to_string(state); msg << "#" << call_site->name()->to_string(state); Exception::internal_error(state, call_frame, msg.str().c_str()); return 0; } args.unshift(state, call_site->name()); dis.method = missing_dis.method; dis.module = missing_dis.module; dis.method_missing = eSuper; state->vm()->set_method_missing_reason(dis.method_missing); state->vm()->global_cache()->add_seen(state, call_site->name()); } state->vm()->metrics().machine.methods_invoked++; call_site->update(state, recv_class, dis); Executable* meth = dis.method; Module* mod = dis.module; if(meth->custom_call_site_p()) { CallSiteInformation info(call_site->executable(), call_site->ip()); state->set_call_site_information(&info); Object* res = meth->execute(state, call_frame, meth, mod, args); state->set_call_site_information(NULL); return res; } else { return meth->execute(state, call_frame, meth, mod, args); } }
Object* CallSite::empty_cache_super(STATE, CallSite* call_site, CallFrame* call_frame, Arguments& args) { Symbol* original_name = call_frame->original_name(); if(call_site->name_ != original_name) { call_site->name_ = original_name; args.set_name(call_site->name_); } Object* const recv = args.recv(); Class* const recv_class = recv->lookup_begin(state); Module* const start = call_frame->module()->superclass(); LookupData lookup(call_frame->self(), start, G(sym_private)); Dispatch dis(call_site->name()); if(start->nil_p() || !dis.resolve(state, call_site->name(), lookup)) { LookupData missing_lookup(call_frame->self(), recv_class, G(sym_private)); Dispatch missing_dis(G(sym_method_missing)); missing_dis.resolve(state, G(sym_method_missing), missing_lookup); if(missing_dis.method_missing != eNone) { Exception::internal_error(state, call_frame, "no method_missing"); return 0; } args.unshift(state, call_site->name()); dis.method = missing_dis.method; dis.module = missing_dis.module; dis.method_missing = eSuper; state->vm()->set_method_missing_reason(dis.method_missing); } call_site->update(state, recv_class, dis); Executable* meth = dis.method; Module* mod = dis.module; if(meth->custom_call_site_p()) { CallSiteInformation info(call_site->executable(), call_site->ip()); state->set_call_site_information(&info); Object* res = meth->execute(state, call_frame, meth, mod, args); state->set_call_site_information(NULL); return res; } else { return meth->execute(state, call_frame, meth, mod, args); } }
Object* InlineCache::empty_cache(STATE, InlineCache* cache, CallFrame* call_frame, Arguments& args) { args.set_name(cache->name); Object* const recv = args.recv(); Class* const recv_class = recv->lookup_begin(state); MethodCacheEntry* mce = 0; MethodMissingReason reason = cache->fill_public(state, call_frame->self(), cache->name, recv_class, mce); if(reason != eNone) { state->vm()->set_method_missing_reason(reason); if(!cache->fill_method_missing(state, recv_class, mce)) { Exception::internal_error(state, call_frame, "no method_missing"); return 0; } args.unshift(state, cache->name); cache->execute_backend_ = check_cache_mm; } else { if(recv->fixnum_p()) { cache->execute_backend_ = check_cache_fixnum; } else if(recv->symbol_p()) { cache->execute_backend_ = check_cache_symbol; } else if(recv->reference_p()) { cache->execute_backend_ = check_cache_reference; } else { cache->execute_backend_ = check_cache; } } // Make sure we sync here, so the MethodCacheEntry mce is // guaranteed completely initialized. Otherwise another thread // might see an incompletely initialized MethodCacheEntry. atomic::memory_barrier(); cache->cache_ = mce; cache->update_seen_classes(mce); call_frame->cm->write_barrier(state, mce); Executable* meth = mce->method(); Module* mod = mce->stored_module(); return meth->execute(state, call_frame, meth, mod, args); }
Object* InlineCache::empty_cache_super(STATE, InlineCache* cache, CallFrame* call_frame, Arguments& args) { Symbol* original_name = call_frame->original_name(); if(cache->name != original_name) { cache->name = original_name; } args.set_name(cache->name); Object* const recv = args.recv(); Class* const recv_class = recv->lookup_begin(state); MethodCacheEntry* mce = 0; Module* const start = call_frame->module()->superclass(); if(start->nil_p() || !cache->fill_private(state, cache->name, start, recv_class, mce)) { state->vm()->set_method_missing_reason(eSuper); // Don't use start when looking up method_missing! // Always completely redispatch for method_missing. // github#157 if(!cache->fill_method_missing(state, recv_class, mce)) { Exception::internal_error(state, call_frame, "no method_missing"); return 0; } args.unshift(state, cache->name); cache->execute_backend_ = check_cache_super_mm; } else { cache->execute_backend_ = check_cache_super; } // Make sure we sync here, so the MethodCacheEntry mce is // guaranteed completely initialized. Otherwise another thread // might see an incompletely initialized MethodCacheEntry. atomic::memory_barrier(); cache->cache_ = mce; cache->update_seen_classes(mce); call_frame->cm->write_barrier(state, mce); Executable* meth = mce->method(); Module* mod = mce->stored_module(); return meth->execute(state, call_frame, meth, mod, args); }
Object* InlineCache::check_cache(STATE, InlineCache* cache, CallFrame* call_frame, Arguments& args) { MethodCacheEntry* mce = cache->cache_; args.set_name(cache->name); if(likely(mce && mce->receiver_class() == args.recv()->lookup_begin(state))) { Executable* meth = mce->method(); Module* mod = mce->stored_module(); return meth->execute(state, call_frame, meth, mod, args); } return cache->initialize(state, call_frame, args); }
Object* PolyInlineCache::check_cache(STATE, CallSite* call_site, Arguments& args) { Class* const recv_class = args.recv()->direct_class(state); PolyInlineCache* cache = static_cast<PolyInlineCache*>(call_site); InlineCacheEntry* entry = cache->get_entry(recv_class); if(likely(entry)) { Executable* meth = entry->method(); Module* mod = entry->stored_module(); entry->hit(); state->vm()->metrics().machine.methods_invoked++; return meth->execute(state, meth, mod, args); } return cache->fallback(state, args); }
Object* InlineCache::check_cache_super_mm(STATE, InlineCache* cache, CallFrame* call_frame, Arguments& args) { MethodCacheEntry* mce = cache->cache_; Symbol* current_name = call_frame->original_name(); args.set_name(cache->name); if(likely(mce && mce->receiver_class() == args.recv()->lookup_begin(state) && current_name == cache->name)) { args.unshift(state, cache->name); Executable* meth = mce->method(); Module* mod = mce->stored_module(); return meth->execute(state, call_frame, meth, mod, args); } cache->name = current_name; return cache->initialize(state, call_frame, args); }
Object* InlineCache::check_cache_reference(STATE, InlineCache* cache, CallFrame* call_frame, Arguments& args) { MethodCacheEntry* mce = cache->cache_; args.set_name(cache->name); Object* const recv = args.recv(); if(likely(mce && recv->reference_p() && recv->reference_class() == mce->receiver_class())) { Executable* meth = mce->method(); Module* mod = mce->stored_module(); // if(mce->execute) { // return mce->execute(state, call_frame, meth, mod, args); // } return meth->execute(state, call_frame, meth, mod, args); } return cache->initialize(state, call_frame, args); }