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()); }
void InterpretedIC::cleanup() { if (is_empty()) return; // Nothing to cleanup switch (send_type()) { case Bytecodes::accessor_send: // fall through case Bytecodes::primitive_send: // fall through case Bytecodes::predicted_send: // fall through case Bytecodes::interpreted_send: { // check if the interpreted send should be replaced by a compiled send klassOop receiver_klass = klassOop(second_word()); assert(receiver_klass->is_klass(), "receiver klass must be a klass"); methodOop method = methodOop(first_word()); assert(method->is_method(), "first word in interpreter IC must be method"); if (!Bytecodes::is_super_send(send_code())) { // super sends cannot be handled since the sending method holder is unknown at this point. LookupKey key(receiver_klass, selector()); LookupResult result = lookupCache::lookup(&key); if (!result.matches(method)) { replace(result, receiver_klass); } } } break; case Bytecodes::compiled_send: { // check if the current compiled send is valid klassOop receiver_klass = klassOop(second_word()); assert(receiver_klass->is_klass(), "receiver klass must be a klass"); jumpTableEntry* entry = (jumpTableEntry*) first_word(); nmethod* nm = entry->method(); LookupResult result = lookupCache::lookup(&nm->key); if (!result.matches(nm)) { replace(result, receiver_klass); } } break; case Bytecodes::megamorphic_send: // Note that with the current definition of is_empty() // this will not be called for normal megamorphic sends // since they store only the selector. { klassOop receiver_klass = klassOop(second_word()); if (first_word()->is_smi()) { jumpTableEntry* entry = (jumpTableEntry*) first_word(); nmethod* nm = entry->method(); LookupResult result = lookupCache::lookup(&nm->key); if (!result.matches(nm)) { replace(result, receiver_klass); } } else { methodOop method = methodOop(first_word()); assert(method->is_method(), "first word in interpreter IC must be method"); if (!Bytecodes::is_super_send(send_code())) { // super sends cannot be handled since the sending method holder is unknown at this point. LookupKey key(receiver_klass, selector()); LookupResult result = lookupCache::lookup(&key); if (!result.matches(method)) { replace(result, receiver_klass); } } } } break; case Bytecodes::polymorphic_send: { // %implementation note: // when cleaning up we can always preserve the old pic since the // the only transitions are: // (compiled -> compiled) // (compiled -> interpreted) // (interpreted -> compiled) // in case of a super send we do not have to cleanup because // no nmethods are compiled for super sends. if (!Bytecodes::is_super_send(send_code())) { objArrayOop pic = pic_array(); for (int index = pic->length(); index > 0; index -= 2) { klassOop klass = klassOop(pic->obj_at(index)); assert(klass->is_klass(), "receiver klass must be klass"); oop first = pic->obj_at(index-1); if (first->is_smi()) { jumpTableEntry* entry = (jumpTableEntry*) first; nmethod* nm = entry->method(); LookupResult result = lookupCache::lookup(&nm->key); if (!result.matches(nm)) { pic->obj_at_put(index-1, result.value()); } } else { methodOop method = methodOop(first); assert(method->is_method(), "first word in interpreter IC must be method"); LookupKey key(klass, selector()); LookupResult result = lookupCache::lookup(&key); if (!result.matches(method)) { pic->obj_at_put(index-1, result.value()); } } } } } } }