oop* InterpretedIC::inline_cache_miss() { NoGCVerifier noGC; // get ic info frame f = DeltaProcess::active()->last_frame(); InterpretedIC* ic = f.current_interpretedIC(); Bytecodes::Code send_code = ic->send_code(); oop receiver = ic->argument_spec() == Bytecodes::args_only // Are we at a self or super send? ? f.receiver() // yes: take receiver of frame : f.expr(ic->nof_arguments()); // no: take receiver pushed before the arguments // do the lookup klassOop klass = receiver->klass(); LookupResult result = Bytecodes::is_super_send(send_code) ? interpreter_super_lookup(ic->selector()) : interpreter_normal_lookup(klass, ic->selector()); // tracing if (TraceInlineCacheMiss) { std->print("IC miss, "); trace_inline_cache_miss(ic, klass, result); } // handle the lookup result if (!result.is_empty()) { update_inline_cache(ic, &f, ic->send_code(), klass, result); return NULL; } else { return cacheMissResult(does_not_understand(receiver, ic, &f), ic->nof_arguments() + (ic->argument_spec() == Bytecodes::args_only ? 0 : 1))->objs(1); } }
void InterpretedIC::inline_cache_miss() { NoGCVerifier noGC; // get ic info frame f = DeltaProcess::active()->last_frame(); InterpretedIC* ic = f.current_interpretedIC(); Bytecodes::Code send_code = ic->send_code(); oop receiver = ic->argument_spec() == Bytecodes::args_only // Are we at a self or super send? ? f.receiver() // yes: take receiver of frame : f.expr(ic->nof_arguments()); // no: take receiver pushed before the arguments // do the lookup klassOop klass = receiver->klass(); LookupResult result = Bytecodes::is_super_send(send_code) ? interpreter_super_lookup(ic->selector()) : interpreter_normal_lookup(klass, ic->selector()); // tracing if (TraceMessageSend) std->print_cr("inline cache miss"); if (TraceLookup) trace_inline_cache_miss(ic, klass, result); // handle the lookup result if (!result.is_empty()) update_inline_cache(ic, &f, send_code, klass, result); else { does_not_understand(receiver, ic, &f); // If the program continues we'll redo the inline_cache_miss if (!have_nlr_through_C) inline_cache_miss(); } }
LookupResult lookup(klassOop klass, symbolOop selector) { if (!match(klass, selector)) { _result = interpreter_normal_lookup(klass, selector); if (!_result.is_empty()) { _key.initialize(klass, selector); } } return _result; }
oop InterpretedIC::does_not_understand(oop receiver, InterpretedIC* ic, frame* f) { memOop msg; symbolOop sel; { // message not understood... BlockScavenge bs; // make sure that no scavenge happens klassOop msgKlass = klassOop(Universe::find_global("Message")); oop obj = msgKlass->klass_part()->allocateObject(); assert(obj->is_mem(), "just checkin'..."); msg = memOop(obj); int nofArgs = ic->selector()->number_of_arguments(); objArrayOop args = oopFactory::new_objArray(nofArgs); for (int i = 1; i <= nofArgs; i++) { args->obj_at_put(i, f->expr(nofArgs - i)); } // for now: assume instance variables are there... // later: should check this or use a VM interface: // msg->set_receiver(recv); // msg->set_selector(ic->selector()); // msg->set_arguments(args); msg->raw_at_put(2, receiver); msg->raw_at_put(3, ic->selector()); msg->raw_at_put(4, args); sel = oopFactory::new_symbol("doesNotUnderstand:"); if (interpreter_normal_lookup(receiver->klass(), sel).is_empty()) { // doesNotUnderstand: not found ==> process error { ResourceMark rm; std->print("LOOKUP ERROR\n"); sel->print_value(); std->print(" not found\n"); } if (DeltaProcess::active()->is_scheduler()) { DeltaProcess::active()->trace_stack(); fatal("lookup error in scheduler"); } else { DeltaProcess::active()->suspend(::lookup_error); } ShouldNotReachHere(); } } // return marked result of doesNotUnderstand: message return Delta::call(receiver, sel, msg); // Solution: use an nmethod-like stub-routine called from // within a (possibly one-element) PIC (in order to keep // the method selector in the IC. That stub does the // Delta:call and pops the right number of arguments // taken from the selector (the no. of arguments from // the selector can be optimized). }
void InterpretedIC_Iterator::init_iteration() { _pic = NULL; _index = 0; // determine initial state switch (_ic->send_type()) { case Bytecodes::interpreted_send: if (_ic->is_empty()) { // anamorphic call site (has never been executed => no type information) _number_of_targets = 0; _info = anamorphic; } else { // monomorphic call site _number_of_targets = 1; _info = monomorphic; set_klass(_ic->second_word()); set_method(_ic->first_word()); } break; case Bytecodes::compiled_send : _number_of_targets = 1; _info = monomorphic; set_klass(_ic->second_word()); assert(_ic->first_word()->is_smi(), "must have jumpTableEntry"); set_method(_ic->first_word()); assert(is_compiled(), "bad type"); break; case Bytecodes::accessor_send : // fall through case Bytecodes::primitive_send : _number_of_targets = 1; _info = monomorphic; set_klass(_ic->second_word()); set_method(_ic->first_word()); assert(is_interpreted(), "bad type"); break; case Bytecodes::megamorphic_send: // no type information stored _number_of_targets = 0; _info = megamorphic; break; case Bytecodes::polymorphic_send: // information on many types _pic = objArrayOop(_ic->second_word()); _number_of_targets = _pic->length() / 2; _info = polymorphic; set_klass(_pic->obj_at(2)); set_method(_pic->obj_at(1)); break; case Bytecodes::predicted_send: if (_ic->is_empty() || _ic->second_word() == smiKlassObj) { _number_of_targets = 1; _info = monomorphic; } else { _number_of_targets = 2; _info = polymorphic; } set_klass(smiKlassObj); set_method(interpreter_normal_lookup(smiKlassObj, selector()).value()); assert(_method != NULL && _method->is_mem(), "this method must be there"); break; default: ShouldNotReachHere(); } assert((number_of_targets() > 1) == (_info == polymorphic), "inconsistency"); }