--- a/src/hotspot/share/code/compiledIC.cpp Wed Dec 05 17:33:01 2018 +0000
+++ b/src/hotspot/share/code/compiledIC.cpp Wed Dec 05 15:57:26 2018 +0100
@@ -237,7 +237,13 @@
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 @@
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 @@
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 @@
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 @@
}
} 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 @@
// 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 @@
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 @@
}
} 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 @@
(!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 @@
// 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 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 @@
// 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 {