void InterpretedIC::replace(LookupResult result, klassOop receiver_klass) { // IC entries before modification - used for loging only Bytecodes::Code code_before = send_code(); oop word1_before = first_word(); oop word2_before = second_word(); int transition = 0; // modify IC guarantee(word2_before == receiver_klass, "klass should be the same"); if (result.is_empty()) { clear(); transition = 1; } else if (result.is_method()) { if (send_type() == Bytecodes::megamorphic_send) { set(send_code(), result.method(), receiver_klass); transition = 2; } else { // Please Fix this Robert // implement set_monomorphic(klass, method) clear(); transition = 3; } } else { if (send_type() == Bytecodes::megamorphic_send) { set(send_code(), oop(result.entry()), receiver_klass); transition = 4; } else { assert(result.is_entry(), "must be jump table entry"); // a jump table entry of a nmethod is found so let's update the current send set(Bytecodes::compiled_send_code_for(send_code()), oop(result.entry()), receiver_klass); transition = 5; } } // IC entries after modification - used for loging only Bytecodes::Code code_after = send_code(); oop word1_after = first_word(); oop word2_after = second_word(); // log modification LOG_EVENT3("InterpretedIC::replace: IC at 0x%x: entry for klass 0x%x replaced (transition %d)", this, receiver_klass, transition); LOG_EVENT3(" from (%s, 0x%x, 0x%x)", Bytecodes::name(code_before), word1_before, word2_before); LOG_EVENT3(" to (%s, 0x%x, 0x%x)", Bytecodes::name(code_after ), word1_after , word2_after ); }
void InterpretedIC::update_inline_cache(InterpretedIC* ic, frame* f, Bytecodes::Code send_code, klassOop klass, LookupResult result) { // update inline cache if (ic->is_empty() && ic->send_type() != Bytecodes::megamorphic_send) { // fill ic for the first time Bytecodes::Code new_send_code = Bytecodes::halt; if (result.is_entry()) { methodOop method = result.method(); if (UseAccessMethods && Bytecodes::has_access_send_code(send_code) && method->is_accessMethod()) { // access method found ==> switch to access send new_send_code = Bytecodes::access_send_code_for(send_code); ic->set(new_send_code, method, klass); } else if (UsePredictedMethods && Bytecodes::has_predicted_send_code(send_code) && method->is_special_primitiveMethod()) { // predictable method found ==> switch to predicted send // NB: ic of predicted send should be empty so that the compiler knows whether another type occurred or not // i.e., {predicted + empty} --> 1 class, {predicted + nonempty} --> 2 klasses (polymorphic) // but: this actually doesn't work (yet?) since the interpreter fills the ic on any failure (e.g. overflow) new_send_code = method->special_primitive_code(); method = methodOop(ic->selector()); // ic must stay empty klass = NULL; // ic must stay empty ic->set(new_send_code, method, klass); } else { // jump table entry found ==> switch to compiled send new_send_code = Bytecodes::compiled_send_code_for(send_code); ic->set(new_send_code, oop(result.entry()->entry_point()), klass); } } else { // methodOop found methodOop method = result.method(); if (UseAccessMethods && Bytecodes::has_access_send_code(send_code) && method->is_accessMethod()) { // access method found ==> switch to access send new_send_code = Bytecodes::access_send_code_for(send_code); } else if (UsePredictedMethods && Bytecodes::has_predicted_send_code(send_code) && method->is_special_primitiveMethod()) { // predictable method found ==> switch to predicted send // NB: ic of predicted send should be empty so that the compiler knows whether another type occurred or not // i.e., {predicted + empty} --> 1 class, {predicted + nonempty} --> 2 klasses (polymorphic) // but: this actually doesn't work (yet?) since the interpreter fills the ic on any failure (e.g. overflow) new_send_code = method->special_primitive_code(); method = methodOop(ic->selector()); // ic must stay empty klass = NULL; // ic must stay empty } else if (UsePrimitiveMethods && method->is_primitiveMethod()) { // primitive method found ==> switch to primitive send new_send_code = Bytecodes::primitive_send_code_for(send_code); Unimplemented(); // take this out when all primitive send bytecodes implemented } else { // normal interpreted send ==> do not change new_send_code = send_code; assert(new_send_code == Bytecodes::original_send_code_for(send_code), "bytecode should not change"); } assert(new_send_code != Bytecodes::halt, "new_send_code not set"); ic->set(new_send_code, method, klass); } } else { // ic not empty switch (ic->send_type()) { // monomorphic send case Bytecodes::accessor_send : // fall through case Bytecodes::predicted_send : // fall through case Bytecodes::compiled_send : // fall through case Bytecodes::interpreted_send: { // switch to polymorphic send with 2 entries objArrayOop pic = Interpreter_PICs::allocate(2); Interpreter_PICs::set_first(pic, ic->first_word(), ic->second_word()); Interpreter_PICs::set_second(pic, result.value(), klass); ic->set(Bytecodes::polymorphic_send_code_for(send_code), ic->selector(), pic); break; } // polymorphic send case Bytecodes::polymorphic_send: { objArrayOop old_pic = ic->pic_array(); objArrayOop new_pic = Interpreter_PICs::extend(old_pic); // add an entry to the PIC if appropriate if (new_pic == NULL) { // switch to megamorphic send if (Bytecodes::is_super_send(send_code)) { ic->set(Bytecodes::megamorphic_send_code_for(send_code), result.value(), klass); } else { ic->set(Bytecodes::megamorphic_send_code_for(send_code), ic->selector(), NULL); } } else { // still a polymorphic send, add entry and set ic to new_pic Interpreter_PICs::set_last(new_pic, result.value(), klass); ic->set(send_code, ic->selector(), new_pic); } // recycle old pic Interpreter_PICs::deallocate(old_pic); break; } // megamorphic send case Bytecodes::megamorphic_send: { if (Bytecodes::is_super_send(send_code)) { ic->set(send_code, result.value(), klass); } break; } default: ShouldNotReachHere(); } } // redo send (reset instruction pointer) f->set_hp(ic->send_code_addr()); }