예제 #1
0
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());
}
예제 #2
0
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());
              }
            }
          }
        }
      }
  }
}