8342826: Improve performance of oopDesc::klass() after JDK-8305895

Reviewed-by: coleenp, shade, mli
This commit is contained in:
Roman Kennke 2024-11-15 21:21:03 +00:00
parent c388455d0a
commit 276251c44a
7 changed files with 202 additions and 39 deletions

@ -0,0 +1,50 @@
/*
* Copyright Amazon.com Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "oops/markWord.hpp"
#include "oops/objLayout.hpp"
#include "runtime/globals.hpp"
#include "utilities/debug.hpp"
ObjLayout::Mode ObjLayout::_klass_mode = ObjLayout::Undefined;
int ObjLayout::_oop_base_offset_in_bytes = 0;
bool ObjLayout::_oop_has_klass_gap = false;
void ObjLayout::initialize() {
assert(_klass_mode == Undefined, "ObjLayout initialized twice");
if (UseCompactObjectHeaders) {
_klass_mode = Compact;
_oop_base_offset_in_bytes = sizeof(markWord);
_oop_has_klass_gap = false;
} else if (UseCompressedClassPointers) {
_klass_mode = Compressed;
_oop_base_offset_in_bytes = sizeof(markWord) + sizeof(narrowKlass);
_oop_has_klass_gap = true;
} else {
_klass_mode = Uncompressed;
_oop_base_offset_in_bytes = sizeof(markWord) + sizeof(Klass*);
_oop_has_klass_gap = false;
}
}

@ -0,0 +1,66 @@
/*
* Copyright Amazon.com Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_OOPS_OBJLAYOUT_HPP
#define SHARE_OOPS_OBJLAYOUT_HPP
/*
* This class helps to avoid loading more than one flag in some
* operations that require checking UseCompressedClassPointers,
* UseCompactObjectHeaders and possibly more.
*
* This is important on some performance critical paths, e.g. where
* the Klass* is accessed frequently, especially by GC oop iterators
* and stack-trace builders.
*/
class ObjLayout {
public:
enum Mode {
// +UseCompactObjectHeaders (implies +UseCompressedClassPointers)
Compact,
// +UseCompressedClassPointers (-UseCompactObjectHeaders)
Compressed,
// -UseCompressedClassPointers (-UseCompactObjectHeaders)
Uncompressed,
// Not yet initialized
Undefined
};
private:
static Mode _klass_mode;
static int _oop_base_offset_in_bytes;
static bool _oop_has_klass_gap;
public:
static void initialize();
static inline Mode klass_mode();
static inline int oop_base_offset_in_bytes() {
return _oop_base_offset_in_bytes;
}
static inline bool oop_has_klass_gap() {
return _oop_has_klass_gap;
}
};
#endif // SHARE_OOPS_OBJLAYOUT_HPP

@ -0,0 +1,48 @@
/*
* Copyright Amazon.com Inc. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_OOPS_OBJLAYOUT_INLINE_HPP
#define SHARE_OOPS_OBJLAYOUT_INLINE_HPP
#include "oops/objLayout.hpp"
inline ObjLayout::Mode ObjLayout::klass_mode() {
#ifdef ASSERT
assert(_klass_mode != Undefined, "KlassMode not yet initialized");
if (UseCompactObjectHeaders) {
assert(_klass_mode == Compact, "Klass mode does not match flags");
} else if (UseCompressedClassPointers) {
assert(_klass_mode == Compressed, "Klass mode does not match flags");
} else {
assert(_klass_mode == Uncompressed, "Klass mode does not match flags");
}
#endif
#ifdef _LP64
return _klass_mode;
#else
return Uncompressed;
#endif
}
#endif // SHARE_OOPS_OBJLAYOUT_INLINE_HPP

@ -152,10 +152,6 @@ bool oopDesc::is_array_noinline() const { return is_array(); }
bool oopDesc::is_objArray_noinline() const { return is_objArray(); }
bool oopDesc::is_typeArray_noinline() const { return is_typeArray(); }
bool oopDesc::has_klass_gap() {
return UseCompressedClassPointers && !UseCompactObjectHeaders;
}
#if INCLUDE_CDS_JAVA_HEAP
void oopDesc::set_narrow_klass(narrowKlass nk) {
assert(CDSConfig::is_dumping_heap(), "Used by CDS only. Do not abuse!");

@ -31,6 +31,7 @@
#include "oops/accessDecorators.hpp"
#include "oops/markWord.hpp"
#include "oops/metadata.hpp"
#include "oops/objLayout.hpp"
#include "runtime/atomic.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
@ -324,7 +325,9 @@ class oopDesc {
inline bool mark_must_be_preserved() const;
inline bool mark_must_be_preserved(markWord m) const;
static bool has_klass_gap();
inline static bool has_klass_gap() {
return ObjLayout::oop_has_klass_gap();
}
// for code generation
static int mark_offset_in_bytes() { return (int)offset_of(oopDesc, _mark); }
@ -346,15 +349,7 @@ class oopDesc {
}
static int base_offset_in_bytes() {
if (UseCompactObjectHeaders) {
// With compact headers, the Klass* field is not used for the Klass*
// and is used for the object fields instead.
return sizeof(markWord);
} else if (UseCompressedClassPointers) {
return sizeof(markWord) + sizeof(narrowKlass);
} else {
return sizeof(markWord) + sizeof(Klass*);
}
return ObjLayout::oop_base_offset_in_bytes();
}
// for error reporting

@ -34,6 +34,7 @@
#include "oops/arrayOop.hpp"
#include "oops/compressedKlass.inline.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/objLayout.inline.hpp"
#include "oops/markWord.inline.hpp"
#include "oops/oopsHierarchy.hpp"
#include "runtime/atomic.hpp"
@ -95,43 +96,48 @@ void oopDesc::init_mark() {
}
Klass* oopDesc::klass() const {
if (UseCompactObjectHeaders) {
return mark().klass();
} else if (UseCompressedClassPointers) {
return CompressedKlassPointers::decode_not_null(_metadata._compressed_klass);
} else {
return _metadata._klass;
switch (ObjLayout::klass_mode()) {
case ObjLayout::Compact:
return mark().klass();
case ObjLayout::Compressed:
return CompressedKlassPointers::decode_not_null(_metadata._compressed_klass);
default:
return _metadata._klass;
}
}
Klass* oopDesc::klass_or_null() const {
if (UseCompactObjectHeaders) {
return mark().klass_or_null();
} else if (UseCompressedClassPointers) {
return CompressedKlassPointers::decode(_metadata._compressed_klass);
} else {
return _metadata._klass;
switch (ObjLayout::klass_mode()) {
case ObjLayout::Compact:
return mark().klass_or_null();
case ObjLayout::Compressed:
return CompressedKlassPointers::decode(_metadata._compressed_klass);
default:
return _metadata._klass;
}
}
Klass* oopDesc::klass_or_null_acquire() const {
if (UseCompactObjectHeaders) {
return mark_acquire().klass();
} else if (UseCompressedClassPointers) {
narrowKlass narrow_klass = Atomic::load_acquire(&_metadata._compressed_klass);
return CompressedKlassPointers::decode(narrow_klass);
} else {
return Atomic::load_acquire(&_metadata._klass);
switch (ObjLayout::klass_mode()) {
case ObjLayout::Compact:
return mark_acquire().klass();
case ObjLayout::Compressed: {
narrowKlass narrow_klass = Atomic::load_acquire(&_metadata._compressed_klass);
return CompressedKlassPointers::decode(narrow_klass);
}
default:
return Atomic::load_acquire(&_metadata._klass);
}
}
Klass* oopDesc::klass_without_asserts() const {
if (UseCompactObjectHeaders) {
return mark().klass_without_asserts();
} else if (UseCompressedClassPointers) {
return CompressedKlassPointers::decode_without_asserts(_metadata._compressed_klass);
} else {
return _metadata._klass;
switch (ObjLayout::klass_mode()) {
case ObjLayout::Compact:
return mark().klass_without_asserts();
case ObjLayout::Compressed:
return CompressedKlassPointers::decode_without_asserts(_metadata._compressed_klass);
default:
return _metadata._klass;
}
}

@ -46,6 +46,7 @@
#include "nmt/nmtCommon.hpp"
#include "oops/compressedKlass.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/objLayout.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiAgentList.hpp"
#include "prims/jvmtiExport.hpp"
@ -3673,6 +3674,7 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) {
if (UseCompactObjectHeaders && !UseCompressedClassPointers) {
FLAG_SET_DEFAULT(UseCompressedClassPointers, true);
}
ObjLayout::initialize();
#endif
return JNI_OK;