From 90c944fefe4a7827c08a8e6a81f137c3157a749b Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 2 Oct 2024 07:11:10 +0000 Subject: [PATCH] 8340824: C2: Memory for TypeInterfaces not reclaimed by hashcons() Reviewed-by: vlivanov, qamai --- src/hotspot/share/opto/type.cpp | 143 ++++++++++++++++---------------- src/hotspot/share/opto/type.hpp | 10 +-- 2 files changed, 78 insertions(+), 75 deletions(-) diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 967b4a815d0..73f852c0f04 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -3260,23 +3260,28 @@ void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const { // Convenience common pre-built type. const TypeOopPtr *TypeOopPtr::BOTTOM; -TypeInterfaces::TypeInterfaces() - : Type(Interfaces), _list(Compile::current()->type_arena(), 0, 0, nullptr), +TypeInterfaces::TypeInterfaces(ciInstanceKlass** interfaces_base, int nb_interfaces) + : Type(Interfaces), _interfaces(interfaces_base, nb_interfaces), _hash(0), _exact_klass(nullptr) { - DEBUG_ONLY(_initialized = true); -} - -TypeInterfaces::TypeInterfaces(GrowableArray* interfaces) - : Type(Interfaces), _list(Compile::current()->type_arena(), interfaces->length(), 0, nullptr), - _hash(0), _exact_klass(nullptr) { - for (int i = 0; i < interfaces->length(); i++) { - add(interfaces->at(i)); - } + _interfaces.sort(compare); initialize(); } const TypeInterfaces* TypeInterfaces::make(GrowableArray* interfaces) { - TypeInterfaces* result = (interfaces == nullptr) ? new TypeInterfaces() : new TypeInterfaces(interfaces); + // hashcons() can only delete the last thing that was allocated: to + // make sure all memory for the newly created TypeInterfaces can be + // freed if an identical one exists, allocate space for the array of + // interfaces right after the TypeInterfaces object so that they + // form a contiguous piece of memory. + int nb_interfaces = interfaces == nullptr ? 0 : interfaces->length(); + size_t total_size = sizeof(TypeInterfaces) + nb_interfaces * sizeof(ciInstanceKlass*); + + void* allocated_mem = operator new(total_size); + ciInstanceKlass** interfaces_base = (ciInstanceKlass**)((char*)allocated_mem + sizeof(TypeInterfaces)); + for (int i = 0; i < nb_interfaces; ++i) { + interfaces_base[i] = interfaces->at(i); + } + TypeInterfaces* result = ::new (allocated_mem) TypeInterfaces(interfaces_base, nb_interfaces); return (const TypeInterfaces*)result->hashcons(); } @@ -3295,20 +3300,18 @@ int TypeInterfaces::compare(ciInstanceKlass* const& k1, ciInstanceKlass* const& return 0; } -void TypeInterfaces::add(ciInstanceKlass* interface) { - assert(interface->is_interface(), "for interfaces only"); - _list.insert_sorted(interface); - verify(); +int TypeInterfaces::compare(ciInstanceKlass** k1, ciInstanceKlass** k2) { + return compare(*k1, *k2); } bool TypeInterfaces::eq(const Type* t) const { const TypeInterfaces* other = (const TypeInterfaces*)t; - if (_list.length() != other->_list.length()) { + if (_interfaces.length() != other->_interfaces.length()) { return false; } - for (int i = 0; i < _list.length(); i++) { - ciKlass* k1 = _list.at(i); - ciKlass* k2 = other->_list.at(i); + for (int i = 0; i < _interfaces.length(); i++) { + ciKlass* k1 = _interfaces.at(i); + ciKlass* k2 = other->_interfaces.at(i); if (!k1->equals(k2)) { return false; } @@ -3319,12 +3322,12 @@ bool TypeInterfaces::eq(const Type* t) const { bool TypeInterfaces::eq(ciInstanceKlass* k) const { assert(k->is_loaded(), "should be loaded"); GrowableArray* interfaces = k->transitive_interfaces(); - if (_list.length() != interfaces->length()) { + if (_interfaces.length() != interfaces->length()) { return false; } for (int i = 0; i < interfaces->length(); i++) { bool found = false; - _list.find_sorted(interfaces->at(i), found); + _interfaces.find_sorted(interfaces->at(i), found); if (!found) { return false; } @@ -3344,8 +3347,8 @@ const Type* TypeInterfaces::xdual() const { void TypeInterfaces::compute_hash() { uint hash = 0; - for (int i = 0; i < _list.length(); i++) { - ciKlass* k = _list.at(i); + for (int i = 0; i < _interfaces.length(); i++) { + ciKlass* k = _interfaces.at(i); hash += k->hash(); } _hash = hash; @@ -3356,13 +3359,13 @@ static int compare_interfaces(ciInstanceKlass** k1, ciInstanceKlass** k2) { } void TypeInterfaces::dump(outputStream* st) const { - if (_list.length() == 0) { + if (_interfaces.length() == 0) { return; } ResourceMark rm; st->print(" ("); GrowableArray interfaces; - interfaces.appendAll(&_list); + interfaces.appendAll(&_interfaces); // Sort the interfaces so they are listed in the same order from one run to the other of the same compilation interfaces.sort(compare_interfaces); for (int i = 0; i < interfaces.length(); i++) { @@ -3377,9 +3380,9 @@ void TypeInterfaces::dump(outputStream* st) const { #ifdef ASSERT void TypeInterfaces::verify() const { - for (int i = 1; i < _list.length(); i++) { - ciInstanceKlass* k1 = _list.at(i-1); - ciInstanceKlass* k2 = _list.at(i); + for (int i = 1; i < _interfaces.length(); i++) { + ciInstanceKlass* k1 = _interfaces.at(i-1); + ciInstanceKlass* k2 = _interfaces.at(i); assert(compare(k2, k1) > 0, "should be ordered"); assert(k1 != k2, "no duplicate"); } @@ -3390,23 +3393,23 @@ const TypeInterfaces* TypeInterfaces::union_with(const TypeInterfaces* other) co GrowableArray result_list; int i = 0; int j = 0; - while (i < _list.length() || j < other->_list.length()) { - while (i < _list.length() && - (j >= other->_list.length() || - compare(_list.at(i), other->_list.at(j)) < 0)) { - result_list.push(_list.at(i)); + while (i < _interfaces.length() || j < other->_interfaces.length()) { + while (i < _interfaces.length() && + (j >= other->_interfaces.length() || + compare(_interfaces.at(i), other->_interfaces.at(j)) < 0)) { + result_list.push(_interfaces.at(i)); i++; } - while (j < other->_list.length() && - (i >= _list.length() || - compare(other->_list.at(j), _list.at(i)) < 0)) { - result_list.push(other->_list.at(j)); + while (j < other->_interfaces.length() && + (i >= _interfaces.length() || + compare(other->_interfaces.at(j), _interfaces.at(i)) < 0)) { + result_list.push(other->_interfaces.at(j)); j++; } - if (i < _list.length() && - j < other->_list.length() && - _list.at(i) == other->_list.at(j)) { - result_list.push(_list.at(i)); + if (i < _interfaces.length() && + j < other->_interfaces.length() && + _interfaces.at(i) == other->_interfaces.at(j)) { + result_list.push(_interfaces.at(i)); i++; j++; } @@ -3414,14 +3417,14 @@ const TypeInterfaces* TypeInterfaces::union_with(const TypeInterfaces* other) co const TypeInterfaces* result = TypeInterfaces::make(&result_list); #ifdef ASSERT result->verify(); - for (int i = 0; i < _list.length(); i++) { - assert(result->_list.contains(_list.at(i)), "missing"); + for (int i = 0; i < _interfaces.length(); i++) { + assert(result->_interfaces.contains(_interfaces.at(i)), "missing"); } - for (int i = 0; i < other->_list.length(); i++) { - assert(result->_list.contains(other->_list.at(i)), "missing"); + for (int i = 0; i < other->_interfaces.length(); i++) { + assert(result->_interfaces.contains(other->_interfaces.at(i)), "missing"); } - for (int i = 0; i < result->_list.length(); i++) { - assert(_list.contains(result->_list.at(i)) || other->_list.contains(result->_list.at(i)), "missing"); + for (int i = 0; i < result->_interfaces.length(); i++) { + assert(_interfaces.contains(result->_interfaces.at(i)) || other->_interfaces.contains(result->_interfaces.at(i)), "missing"); } #endif return result; @@ -3431,21 +3434,21 @@ const TypeInterfaces* TypeInterfaces::intersection_with(const TypeInterfaces* ot GrowableArray result_list; int i = 0; int j = 0; - while (i < _list.length() || j < other->_list.length()) { - while (i < _list.length() && - (j >= other->_list.length() || - compare(_list.at(i), other->_list.at(j)) < 0)) { + while (i < _interfaces.length() || j < other->_interfaces.length()) { + while (i < _interfaces.length() && + (j >= other->_interfaces.length() || + compare(_interfaces.at(i), other->_interfaces.at(j)) < 0)) { i++; } - while (j < other->_list.length() && - (i >= _list.length() || - compare(other->_list.at(j), _list.at(i)) < 0)) { + while (j < other->_interfaces.length() && + (i >= _interfaces.length() || + compare(other->_interfaces.at(j), _interfaces.at(i)) < 0)) { j++; } - if (i < _list.length() && - j < other->_list.length() && - _list.at(i) == other->_list.at(j)) { - result_list.push(_list.at(i)); + if (i < _interfaces.length() && + j < other->_interfaces.length() && + _interfaces.at(i) == other->_interfaces.at(j)) { + result_list.push(_interfaces.at(i)); i++; j++; } @@ -3453,14 +3456,14 @@ const TypeInterfaces* TypeInterfaces::intersection_with(const TypeInterfaces* ot const TypeInterfaces* result = TypeInterfaces::make(&result_list); #ifdef ASSERT result->verify(); - for (int i = 0; i < _list.length(); i++) { - assert(!other->_list.contains(_list.at(i)) || result->_list.contains(_list.at(i)), "missing"); + for (int i = 0; i < _interfaces.length(); i++) { + assert(!other->_interfaces.contains(_interfaces.at(i)) || result->_interfaces.contains(_interfaces.at(i)), "missing"); } - for (int i = 0; i < other->_list.length(); i++) { - assert(!_list.contains(other->_list.at(i)) || result->_list.contains(other->_list.at(i)), "missing"); + for (int i = 0; i < other->_interfaces.length(); i++) { + assert(!_interfaces.contains(other->_interfaces.at(i)) || result->_interfaces.contains(other->_interfaces.at(i)), "missing"); } - for (int i = 0; i < result->_list.length(); i++) { - assert(_list.contains(result->_list.at(i)) && other->_list.contains(result->_list.at(i)), "missing"); + for (int i = 0; i < result->_interfaces.length(); i++) { + assert(_interfaces.contains(result->_interfaces.at(i)) && other->_interfaces.contains(result->_interfaces.at(i)), "missing"); } #endif return result; @@ -3473,13 +3476,13 @@ ciInstanceKlass* TypeInterfaces::exact_klass() const { } void TypeInterfaces::compute_exact_klass() { - if (_list.length() == 0) { + if (_interfaces.length() == 0) { _exact_klass = nullptr; return; } ciInstanceKlass* res = nullptr; - for (int i = 0; i < _list.length(); i++) { - ciInstanceKlass* interface = _list.at(i); + for (int i = 0; i < _interfaces.length(); i++) { + ciInstanceKlass* interface = _interfaces.at(i); if (eq(interface)) { assert(res == nullptr, ""); res = interface; @@ -3490,8 +3493,8 @@ void TypeInterfaces::compute_exact_klass() { #ifdef ASSERT void TypeInterfaces::verify_is_loaded() const { - for (int i = 0; i < _list.length(); i++) { - ciKlass* interface = _list.at(i); + for (int i = 0; i < _interfaces.length(); i++) { + ciKlass* interface = _interfaces.at(i); assert(interface->is_loaded(), "Interface not loaded"); } } diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index b9883d51391..902155e975d 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -877,19 +877,18 @@ public: // Set of implemented interfaces. Referenced from TypeOopPtr and TypeKlassPtr. class TypeInterfaces : public Type { private: - GrowableArray _list; + GrowableArrayFromArray _interfaces; uint _hash; ciInstanceKlass* _exact_klass; DEBUG_ONLY(bool _initialized;) void initialize(); - void add(ciInstanceKlass* interface); void verify() const NOT_DEBUG_RETURN; void compute_hash(); void compute_exact_klass(); - TypeInterfaces(); - TypeInterfaces(GrowableArray* interfaces); + + TypeInterfaces(ciInstanceKlass** interfaces_base, int nb_interfaces); NONCOPYABLE(TypeInterfaces); public: @@ -904,12 +903,13 @@ public: bool contains(const TypeInterfaces* other) const { return intersection_with(other)->eq(other); } - bool empty() const { return _list.length() == 0; } + bool empty() const { return _interfaces.length() == 0; } ciInstanceKlass* exact_klass() const; void verify_is_loaded() const NOT_DEBUG_RETURN; static int compare(ciInstanceKlass* const& k1, ciInstanceKlass* const& k2); + static int compare(ciInstanceKlass** k1, ciInstanceKlass** k2); const Type* xmeet(const Type* t) const;