< prev index next >

src/hotspot/share/code/compiledIC.cpp

Print this page
*** 199,43 ***
  void CompiledIC::set_to_clean() {
    log_debug(inlinecache)("IC@" INTPTR_FORMAT ": set to clean", p2i(_call->instruction_address()));
    _call->set_destination_mt_safe(SharedRuntime::get_resolve_virtual_call_stub());
  }
  
! void CompiledIC::set_to_monomorphic() {
    assert(data()->is_initialized(), "must be initialized");
    Method* method = data()->speculated_method();
    nmethod* code = method->code();
    address entry;
    bool to_compiled = code != nullptr && code->is_in_use() && !code->is_unloading();
  
    if (to_compiled) {
!     entry = code->entry_point();
    } else {
!     entry = method->get_c2i_unverified_entry();
    }
  
    log_trace(inlinecache)("IC@" INTPTR_FORMAT ": monomorphic to %s: %s",
                           p2i(_call->instruction_address()),
                           to_compiled ? "compiled" : "interpreter",
                           method->print_value_string());
  
    _call->set_destination_mt_safe(entry);
  }
  
! void CompiledIC::set_to_megamorphic(CallInfo* call_info) {
    assert(data()->is_initialized(), "must be initialized");
  
    address entry;
    if (call_info->call_kind() == CallInfo::direct_call) {
      // C1 sometimes compiles a callsite before the target method is loaded, resulting in
      // dynamically bound callsites that should really be statically bound. However, the
      // target method might not have a vtable or itable. We just wait for better code to arrive
      return;
    } else if (call_info->call_kind() == CallInfo::itable_call) {
      int itable_index = call_info->itable_index();
!     entry = VtableStubs::find_itable_stub(itable_index);
      if (entry == nullptr) {
        return;
      }
  #ifdef ASSERT
      int index = call_info->resolved_method()->itable_index();
--- 199,43 ---
  void CompiledIC::set_to_clean() {
    log_debug(inlinecache)("IC@" INTPTR_FORMAT ": set to clean", p2i(_call->instruction_address()));
    _call->set_destination_mt_safe(SharedRuntime::get_resolve_virtual_call_stub());
  }
  
! void CompiledIC::set_to_monomorphic(bool caller_is_c1) {
    assert(data()->is_initialized(), "must be initialized");
    Method* method = data()->speculated_method();
    nmethod* code = method->code();
    address entry;
    bool to_compiled = code != nullptr && code->is_in_use() && !code->is_unloading();
  
    if (to_compiled) {
!     entry = caller_is_c1 ? code->inline_entry_point() : code->entry_point();
    } else {
!     entry = caller_is_c1 ? method->get_c2i_unverified_inline_entry() : method->get_c2i_unverified_entry();
    }
  
    log_trace(inlinecache)("IC@" INTPTR_FORMAT ": monomorphic to %s: %s",
                           p2i(_call->instruction_address()),
                           to_compiled ? "compiled" : "interpreter",
                           method->print_value_string());
  
    _call->set_destination_mt_safe(entry);
  }
  
! void CompiledIC::set_to_megamorphic(CallInfo* call_info, bool caller_is_c1) {
    assert(data()->is_initialized(), "must be initialized");
  
    address entry;
    if (call_info->call_kind() == CallInfo::direct_call) {
      // C1 sometimes compiles a callsite before the target method is loaded, resulting in
      // dynamically bound callsites that should really be statically bound. However, the
      // target method might not have a vtable or itable. We just wait for better code to arrive
      return;
    } else if (call_info->call_kind() == CallInfo::itable_call) {
      int itable_index = call_info->itable_index();
!     entry = VtableStubs::find_itable_stub(itable_index, caller_is_c1);
      if (entry == nullptr) {
        return;
      }
  #ifdef ASSERT
      int index = call_info->resolved_method()->itable_index();

*** 246,11 ***
    } else {
      assert(call_info->call_kind() == CallInfo::vtable_call, "what else?");
      // Can be different than selected_method->vtable_index(), due to package-private etc.
      int vtable_index = call_info->vtable_index();
      assert(call_info->resolved_klass()->verify_vtable_index(vtable_index), "sanity check");
!     entry = VtableStubs::find_vtable_stub(vtable_index);
      if (entry == nullptr) {
        return;
      }
    }
  
--- 246,11 ---
    } else {
      assert(call_info->call_kind() == CallInfo::vtable_call, "what else?");
      // Can be different than selected_method->vtable_index(), due to package-private etc.
      int vtable_index = call_info->vtable_index();
      assert(call_info->resolved_klass()->verify_vtable_index(vtable_index), "sanity check");
!     entry = VtableStubs::find_vtable_stub(vtable_index, caller_is_c1);
      if (entry == nullptr) {
        return;
      }
    }
  

*** 259,11 ***
  
    _call->set_destination_mt_safe(entry);
    assert(is_megamorphic(), "sanity check");
  }
  
! void CompiledIC::update(CallInfo* call_info, Klass* receiver_klass) {
    // If this is the first time we fix the inline cache, we ensure it's initialized
    ensure_initialized(call_info, receiver_klass);
  
    if (is_megamorphic()) {
      // Terminal state for the inline cache
--- 259,11 ---
  
    _call->set_destination_mt_safe(entry);
    assert(is_megamorphic(), "sanity check");
  }
  
! void CompiledIC::update(CallInfo* call_info, Klass* receiver_klass, bool caller_is_c1) {
    // If this is the first time we fix the inline cache, we ensure it's initialized
    ensure_initialized(call_info, receiver_klass);
  
    if (is_megamorphic()) {
      // Terminal state for the inline cache

*** 271,15 ***
    }
  
    if (is_speculated_klass(receiver_klass)) {
      // If the speculated class matches the receiver klass, we can speculate that will
      // continue to be the case with a monomorphic inline cache
!     set_to_monomorphic();
    } else {
      // If the dynamic type speculation fails, we try to transform to a megamorphic state
      // for the inline cache using stubs to dispatch in tables
!     set_to_megamorphic(call_info);
    }
  }
  
  bool CompiledIC::is_clean() const {
    return destination() == SharedRuntime::get_resolve_virtual_call_stub();
--- 271,15 ---
    }
  
    if (is_speculated_klass(receiver_klass)) {
      // If the speculated class matches the receiver klass, we can speculate that will
      // continue to be the case with a monomorphic inline cache
!     set_to_monomorphic(caller_is_c1);
    } else {
      // If the dynamic type speculation fails, we try to transform to a megamorphic state
      // for the inline cache using stubs to dispatch in tables
!     set_to_megamorphic(call_info, caller_is_c1);
    }
  }
  
  bool CompiledIC::is_clean() const {
    return destination() == SharedRuntime::get_resolve_virtual_call_stub();

*** 288,11 ***
  bool CompiledIC::is_monomorphic() const {
    return !is_clean() && !is_megamorphic();
  }
  
  bool CompiledIC::is_megamorphic() const {
!   return VtableStubs::entry_point(destination()) != nullptr;;
  }
  
  bool CompiledIC::is_speculated_klass(Klass* receiver_klass) {
    return data()->speculated_klass() == receiver_klass;
  }
--- 288,11 ---
  bool CompiledIC::is_monomorphic() const {
    return !is_clean() && !is_megamorphic();
  }
  
  bool CompiledIC::is_megamorphic() const {
!   return VtableStubs::entry_point(destination()) != nullptr;
  }
  
  bool CompiledIC::is_speculated_klass(Klass* receiver_klass) {
    return data()->speculated_klass() == receiver_klass;
  }

*** 340,28 ***
    assert(is_clean(), "should be clean after cleaning");
  
    log_debug(inlinecache)("DC@" INTPTR_FORMAT ": set to clean", p2i(_call->instruction_address()));
  }
  
! void CompiledDirectCall::set(const methodHandle& callee_method) {
    nmethod* code = callee_method->code();
    nmethod* caller = CodeCache::find_nmethod(instruction_address());
    assert(caller != nullptr, "did not find caller nmethod");
  
    bool to_interp_cont_enter = caller->method()->is_continuation_enter_intrinsic() &&
                                ContinuationEntry::is_interpreted_call(instruction_address());
  
    bool to_compiled = !to_interp_cont_enter && code != nullptr && code->is_in_use() && !code->is_unloading();
  
    if (to_compiled) {
!     _call->set_destination_mt_safe(code->verified_entry_point());
      assert(is_call_to_compiled(), "should be compiled after set to compiled");
    } else {
      // Patch call site to C2I adapter if code is deoptimized or unloaded.
      // We also need to patch the static call stub to set the rmethod register
      // to the callee_method so the c2i adapter knows how to build the frame
!     set_to_interpreted(callee_method, callee_method->get_c2i_entry());
      assert(is_call_to_interpreted(), "should be interpreted after set to interpreted");
    }
  
    log_trace(inlinecache)("DC@" INTPTR_FORMAT ": set to %s: %s: " INTPTR_FORMAT,
                           p2i(_call->instruction_address()),
--- 340,28 ---
    assert(is_clean(), "should be clean after cleaning");
  
    log_debug(inlinecache)("DC@" INTPTR_FORMAT ": set to clean", p2i(_call->instruction_address()));
  }
  
! void CompiledDirectCall::set(const methodHandle& callee_method, bool caller_is_c1) {
    nmethod* code = callee_method->code();
    nmethod* caller = CodeCache::find_nmethod(instruction_address());
    assert(caller != nullptr, "did not find caller nmethod");
  
    bool to_interp_cont_enter = caller->method()->is_continuation_enter_intrinsic() &&
                                ContinuationEntry::is_interpreted_call(instruction_address());
  
    bool to_compiled = !to_interp_cont_enter && code != nullptr && code->is_in_use() && !code->is_unloading();
  
    if (to_compiled) {
!     _call->set_destination_mt_safe(caller_is_c1 ? code->verified_inline_entry_point() : code->verified_entry_point());
      assert(is_call_to_compiled(), "should be compiled after set to compiled");
    } else {
      // Patch call site to C2I adapter if code is deoptimized or unloaded.
      // We also need to patch the static call stub to set the rmethod register
      // to the callee_method so the c2i adapter knows how to build the frame
!     set_to_interpreted(callee_method, caller_is_c1 ? callee_method->get_c2i_inline_entry() : callee_method->get_c2i_entry());
      assert(is_call_to_interpreted(), "should be interpreted after set to interpreted");
    }
  
    log_trace(inlinecache)("DC@" INTPTR_FORMAT ": set to %s: %s: " INTPTR_FORMAT,
                           p2i(_call->instruction_address()),
< prev index next >