diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index c5f15b3..ea5ed87 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -237,7 +237,13 @@ CompiledIC::CompiledIC(RelocIterator* iter) initialize_from_iter(iter); } -bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, TRAPS) { +// This function may fail for two reasons: either due to running out of vtable +// stubs, or due to running out of IC stubs in an attempted transition to a +// transitional state. The needs_ic_stub_refill value will be set if the failure +// was due to running out of IC stubs, in which case the caller will refill IC +// stubs and retry. +bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, + bool& needs_ic_stub_refill, TRAPS) { assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); assert(!is_optimized(), "cannot set an optimized virtual call to megamorphic"); assert(is_call_to_compiled() || is_call_to_interpreted(), "going directly to megamorphic?"); @@ -259,7 +265,11 @@ bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod CompiledICHolder* holder = new CompiledICHolder(call_info->resolved_method()->method_holder(), call_info->resolved_klass(), false); holder->claim(); - InlineCacheBuffer::create_transition_stub(this, holder, entry); + if (!InlineCacheBuffer::create_transition_stub(this, holder, entry)) { + delete holder; + needs_ic_stub_refill = true; + return false; + } } else { assert(call_info->call_kind() == CallInfo::vtable_call, "either itable or vtable"); // Can be different than selected_method->vtable_index(), due to package-private etc. @@ -269,7 +279,10 @@ bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod if (entry == NULL) { return false; } - InlineCacheBuffer::create_transition_stub(this, NULL, entry); + if (!InlineCacheBuffer::create_transition_stub(this, NULL, entry)) { + needs_ic_stub_refill = true; + return false; + } } if (TraceICs) { @@ -350,7 +363,7 @@ bool CompiledIC::is_call_to_interpreted() const { return is_call_to_interpreted; } -void CompiledIC::set_to_clean(bool in_use) { +bool CompiledIC::set_to_clean(bool in_use) { assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); if (TraceInlineCacheClearing || TraceICs) { tty->print_cr("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address())); @@ -373,7 +386,9 @@ void CompiledIC::set_to_clean(bool in_use) { } } else { // Unsafe transition - create stub. - InlineCacheBuffer::create_transition_stub(this, NULL, entry); + if (!InlineCacheBuffer::create_transition_stub(this, NULL, entry)) { + return false; + } } // We can't check this anymore. With lazy deopt we could have already // cleaned this IC entry before we even return. This is possible if @@ -382,6 +397,7 @@ void CompiledIC::set_to_clean(bool in_use) { // race because the IC entry was complete when we safepointed so // cleaning it immediately is harmless. // assert(is_clean(), "sanity check"); + return true; } bool CompiledIC::is_clean() const { @@ -393,7 +409,7 @@ bool CompiledIC::is_clean() const { return is_clean; } -void CompiledIC::set_to_monomorphic(CompiledICInfo& info) { +bool CompiledIC::set_to_monomorphic(CompiledICInfo& info) { assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); // Updating a cache to the wrong entry can cause bugs that are very hard // to track down - if cache entry gets invalid - we just clean it. In @@ -430,7 +446,11 @@ void CompiledIC::set_to_monomorphic(CompiledICInfo& info) { } } else { // Call via method-klass-holder - InlineCacheBuffer::create_transition_stub(this, info.claim_cached_icholder(), info.entry()); + CompiledICHolder* holder = info.claim_cached_icholder(); + if (!InlineCacheBuffer::create_transition_stub(this, holder, info.entry())) { + delete holder; + return false; + } if (TraceICs) { ResourceMark rm(thread); tty->print_cr ("IC@" INTPTR_FORMAT ": monomorphic to interpreter via icholder ", p2i(instruction_address())); @@ -450,7 +470,9 @@ void CompiledIC::set_to_monomorphic(CompiledICInfo& info) { (!is_in_transition_state() && (info.is_optimized() || static_bound || is_clean())); if (!safe) { - InlineCacheBuffer::create_transition_stub(this, info.cached_metadata(), info.entry()); + if (!InlineCacheBuffer::create_transition_stub(this, info.cached_metadata(), info.entry())) { + return false; + } } else { if (is_optimized()) { set_ic_destination(info.entry()); @@ -475,6 +497,7 @@ void CompiledIC::set_to_monomorphic(CompiledICInfo& info) { // race because the IC entry was complete when we safepointed so // cleaning it immediately is harmless. // assert(is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); + return true; } @@ -575,7 +598,7 @@ void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site, const Com // ---------------------------------------------------------------------------- -void CompiledStaticCall::set_to_clean(bool in_use) { +bool CompiledStaticCall::set_to_clean(bool in_use) { // in_use is unused but needed to match template function in CompiledMethod assert(CompiledICLocker::is_safe(instruction_address()), "mt unsafe call"); // Reset call site @@ -585,6 +608,7 @@ void CompiledStaticCall::set_to_clean(bool in_use) { // Do not reset stub here: It is too expensive to call find_stub. // Instead, rely on caller (nmethod::clear_inline_caches) to clear // both the call and its stub. + return true; } bool CompiledStaticCall::is_clean() const {