8199406: Performance drop with Java JDK 1.8.0_162-b32
Summary: Improve the nmethod unloading times by optimizing the search for an itable stub in VtableStubs array
Reviewed-by: kvn, coleenp, tschatzl
--- a/src/hotspot/share/code/codeBlob.cpp Fri Mar 30 07:47:20 2018 -0700
+++ b/src/hotspot/share/code/codeBlob.cpp Fri Mar 30 18:46:14 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -294,6 +294,28 @@
return blob;
}
+VtableBlob::VtableBlob(const char* name, int size) :
+ BufferBlob(name, size) {
+}
+
+VtableBlob* VtableBlob::create(const char* name, int buffer_size) {
+ ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
+
+ VtableBlob* blob = NULL;
+ unsigned int size = sizeof(VtableBlob);
+ // align the size to CodeEntryAlignment
+ size = align_code_offset(size);
+ size += align_up(buffer_size, oopSize);
+ assert(name != NULL, "must provide a name");
+ {
+ MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+ blob = new (size) VtableBlob(name, size);
+ }
+ // Track memory usage statistic after releasing CodeCache_lock
+ MemoryService::track_code_cache_memory_usage();
+
+ return blob;
+}
//----------------------------------------------------------------------------------------------------
// Implementation of MethodHandlesAdapterBlob
--- a/src/hotspot/share/code/codeBlob.hpp Fri Mar 30 07:47:20 2018 -0700
+++ b/src/hotspot/share/code/codeBlob.hpp Fri Mar 30 18:46:14 2018 +0000
@@ -58,6 +58,7 @@
// RuntimeBlob : Non-compiled method code; generated glue code
// BufferBlob : Used for non-relocatable code such as interpreter, stubroutines, etc.
// AdapterBlob : Used to hold C2I/I2C adapters
+// VtableBlob : Used for holding vtable chunks
// MethodHandlesAdapterBlob : Used to hold MethodHandles adapters
// RuntimeStub : Call to VM runtime methods
// SingletonBlob : Super-class for all blobs that exist in only one instance
@@ -132,6 +133,7 @@
virtual bool is_exception_stub() const { return false; }
virtual bool is_safepoint_stub() const { return false; }
virtual bool is_adapter_blob() const { return false; }
+ virtual bool is_vtable_blob() const { return false; }
virtual bool is_method_handles_adapter_blob() const { return false; }
virtual bool is_aot() const { return false; }
virtual bool is_compiled() const { return false; }
@@ -380,6 +382,7 @@
class BufferBlob: public RuntimeBlob {
friend class VMStructs;
friend class AdapterBlob;
+ friend class VtableBlob;
friend class MethodHandlesAdapterBlob;
friend class WhiteBox;
@@ -425,6 +428,18 @@
virtual bool is_adapter_blob() const { return true; }
};
+//---------------------------------------------------------------------------------------------------
+class VtableBlob: public BufferBlob {
+private:
+ VtableBlob(const char*, int);
+
+public:
+ // Creation
+ static VtableBlob* create(const char* name, int buffer_size);
+
+ // Typing
+ virtual bool is_vtable_blob() const { return true; }
+};
//----------------------------------------------------------------------------------------------------
// MethodHandlesAdapterBlob: used to hold MethodHandles adapters
--- a/src/hotspot/share/code/compiledIC.cpp Fri Mar 30 07:47:20 2018 -0700
+++ b/src/hotspot/share/code/compiledIC.cpp Fri Mar 30 18:46:14 2018 +0000
@@ -235,7 +235,7 @@
assert(k->verify_itable_index(itable_index), "sanity check");
#endif //ASSERT
CompiledICHolder* holder = new CompiledICHolder(call_info->resolved_method()->method_holder(),
- call_info->resolved_klass());
+ call_info->resolved_klass(), false);
holder->claim();
InlineCacheBuffer::create_transition_stub(this, holder, entry);
} else {
@@ -273,7 +273,7 @@
assert(!is_optimized(), "an optimized call cannot be megamorphic");
// Cannot rely on cached_value. It is either an interface or a method.
- return VtableStubs::is_entry_point(ic_destination());
+ return VtableStubs::entry_point(ic_destination()) != NULL;
}
bool CompiledIC::is_call_to_compiled() const {
@@ -525,9 +525,11 @@
return true;
}
// itable stubs also use CompiledICHolder
- if (VtableStubs::is_entry_point(entry) && VtableStubs::stub_containing(entry)->is_itable_stub()) {
- return true;
+ if (cb != NULL && cb->is_vtable_blob()) {
+ VtableStub* s = VtableStubs::entry_point(entry);
+ return (s != NULL) && s->is_itable_stub();
}
+
return false;
}
--- a/src/hotspot/share/code/vtableStubs.cpp Fri Mar 30 07:47:20 2018 -0700
+++ b/src/hotspot/share/code/vtableStubs.cpp Fri Mar 30 18:46:14 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -60,7 +60,7 @@
// There is a dependency on the name of the blob in src/share/vm/prims/jvmtiCodeBlobEvents.cpp
// If changing the name, update the other file accordingly.
- BufferBlob* blob = BufferBlob::create("vtable chunks", bytes);
+ VtableBlob* blob = VtableBlob::create("vtable chunks", bytes);
if (blob == NULL) {
return NULL;
}
@@ -167,17 +167,18 @@
_number_of_vtable_stubs++;
}
-
-bool VtableStubs::is_entry_point(address pc) {
+VtableStub* VtableStubs::entry_point(address pc) {
MutexLocker ml(VtableStubs_lock);
VtableStub* stub = (VtableStub*)(pc - VtableStub::entry_offset());
uint hash = VtableStubs::hash(stub->is_vtable_stub(), stub->index());
VtableStub* s;
for (s = _table[hash]; s != NULL && s != stub; s = s->next()) {}
- return s == stub;
+ if (s == stub) {
+ return s;
+ }
+ return NULL;
}
-
bool VtableStubs::contains(address pc) {
// simple solution for now - we may want to use
// a faster way if this function is called often
--- a/src/hotspot/share/code/vtableStubs.hpp Fri Mar 30 07:47:20 2018 -0700
+++ b/src/hotspot/share/code/vtableStubs.hpp Fri Mar 30 18:46:14 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -126,7 +126,7 @@
public:
static address find_vtable_stub(int vtable_index) { return find_stub(true, vtable_index); }
static address find_itable_stub(int itable_index) { return find_stub(false, itable_index); }
- static bool is_entry_point(address pc); // is pc a vtable stub entry point?
+ static VtableStub* entry_point(address pc); // vtable stub entry point for a pc
static bool contains(address pc); // is pc within any stub?
static VtableStub* stub_containing(address pc); // stub containing pc or NULL
static int number_of_vtable_stubs() { return _number_of_vtable_stubs; }
--- a/src/hotspot/share/oops/compiledICHolder.cpp Fri Mar 30 07:47:20 2018 -0700
+++ b/src/hotspot/share/oops/compiledICHolder.cpp Fri Mar 30 18:46:14 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,16 +24,14 @@
#include "precompiled.hpp"
#include "oops/compiledICHolder.hpp"
-#include "oops/klass.hpp"
-#include "oops/method.hpp"
#include "runtime/atomic.hpp"
volatile int CompiledICHolder::_live_count;
volatile int CompiledICHolder::_live_not_claimed_count;
-CompiledICHolder::CompiledICHolder(Metadata* metadata, Klass* klass)
- : _holder_metadata(metadata), _holder_klass(klass) {
+CompiledICHolder::CompiledICHolder(Metadata* metadata, Klass* klass, bool is_method)
+ : _holder_metadata(metadata), _holder_klass(klass), _is_metadata_method(is_method) {
#ifdef ASSERT
Atomic::inc(&_live_count);
Atomic::inc(&_live_not_claimed_count);
@@ -47,22 +45,6 @@
}
#endif // ASSERT
-bool CompiledICHolder::is_loader_alive(BoolObjectClosure* is_alive) {
- if (_holder_metadata->is_method()) {
- if (!((Method*)_holder_metadata)->method_holder()->is_loader_alive(is_alive)) {
- return false;
- }
- } else if (_holder_metadata->is_klass()) {
- if (!((Klass*)_holder_metadata)->is_loader_alive(is_alive)) {
- return false;
- }
- }
- if (!_holder_klass->is_loader_alive(is_alive)) {
- return false;
- }
- return true;
-}
-
// Printing
void CompiledICHolder::print_on(outputStream* st) const {
--- a/src/hotspot/share/oops/compiledICHolder.hpp Fri Mar 30 07:47:20 2018 -0700
+++ b/src/hotspot/share/oops/compiledICHolder.hpp Fri Mar 30 18:46:14 2018 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,8 @@
#include "oops/oop.hpp"
#include "utilities/macros.hpp"
+#include "oops/klass.hpp"
+#include "oops/method.hpp"
// A CompiledICHolder* is a helper object for the inline cache implementation.
// It holds:
@@ -49,10 +51,11 @@
Metadata* _holder_metadata;
Klass* _holder_klass; // to avoid name conflict with oopDesc::_klass
CompiledICHolder* _next;
+ bool _is_metadata_method;
public:
// Constructor
- CompiledICHolder(Metadata* metadata, Klass* klass);
+ CompiledICHolder(Metadata* metadata, Klass* klass, bool is_method = true);
~CompiledICHolder() NOT_DEBUG_RETURN;
static int live_count() { return _live_count; }
@@ -71,7 +74,16 @@
CompiledICHolder* next() { return _next; }
void set_next(CompiledICHolder* n) { _next = n; }
- bool is_loader_alive(BoolObjectClosure* is_alive);
+ inline bool is_loader_alive(BoolObjectClosure* is_alive) {
+ Klass* k = _is_metadata_method ? ((Method*)_holder_metadata)->method_holder() : (Klass*)_holder_metadata;
+ if (!k->is_loader_alive(is_alive)) {
+ return false;
+ }
+ if (!_holder_klass->is_loader_alive(is_alive)) {
+ return false;
+ }
+ return true;
+ }
// Verify
void verify_on(outputStream* st);