Skip to content

Commit 98af189

Browse files
committed
8366456: Allow AllocFailStrategy for RBTree
Reviewed-by: cnorrbin, aboldtch
1 parent 7f0cd64 commit 98af189

File tree

2 files changed

+46
-26
lines changed

2 files changed

+46
-26
lines changed

src/hotspot/share/utilities/rbTree.hpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
// used for extra validation can optionally be provided. This should return:
6262
// - true if a < b
6363
// - false otherwise
64-
// ALLOCATOR must check for oom and exit, as RBTree does not handle the allocation failing.
6564
// K needs to be of a type that is trivially destructible.
6665
// The tree will call a value's destructor when its node is removed.
6766
// Nodes are address stable and will not change during its lifetime.
@@ -468,13 +467,17 @@ class RBTree : public AbstractRBTree<K, RBNode<K, V>, COMPARATOR> {
468467

469468
RBNode<K, V>* allocate_node(const K& key) {
470469
void* node_place = _allocator.allocate(sizeof(RBNode<K, V>));
471-
assert(node_place != nullptr, "rb-tree allocator must exit on failure");
470+
if (node_place == nullptr) {
471+
return nullptr;
472+
}
472473
return new (node_place) RBNode<K, V>(key);
473474
}
474475

475476
RBNode<K, V>* allocate_node(const K& key, const V& val) {
476477
void* node_place = _allocator.allocate(sizeof(RBNode<K, V>));
477-
assert(node_place != nullptr, "rb-tree allocator must exit on failure");
478+
if (node_place == nullptr) {
479+
return nullptr;
480+
}
478481
return new (node_place) RBNode<K, V>(key, val);
479482
}
480483

@@ -485,16 +488,21 @@ class RBTree : public AbstractRBTree<K, RBNode<K, V>, COMPARATOR> {
485488

486489
// Inserts a node with the given key/value into the tree,
487490
// if the key already exist, the value is updated instead.
488-
void upsert(const K& key, const V& val, const RBNode<K, V>* hint_node = nullptr) {
491+
// Returns false if and only if allocation of a new node failed.
492+
bool upsert(const K& key, const V& val, const RBNode<K, V>* hint_node = nullptr) {
489493
Cursor node_cursor = cursor(key, hint_node);
490494
RBNode<K, V>* node = node_cursor.node();
491495
if (node != nullptr) {
492496
node->set_val(val);
493-
return;
497+
return true;
494498
}
495499

496500
node = allocate_node(key, val);
501+
if (node == nullptr) {
502+
return false;
503+
}
497504
insert_at_cursor(node, node_cursor);
505+
return true;
498506
}
499507

500508
// Finds the value of the node associated with the given key.
@@ -545,12 +553,12 @@ class RBTree : public AbstractRBTree<K, RBNode<K, V>, COMPARATOR> {
545553
}
546554
};
547555

548-
template <MemTag mem_tag>
556+
template <MemTag mem_tag, AllocFailType strategy>
549557
class RBTreeCHeapAllocator {
550558
public:
551559
void* allocate(size_t sz) {
552560
void* allocation = os::malloc(sz, mem_tag);
553-
if (allocation == nullptr) {
561+
if (allocation == nullptr && strategy == AllocFailStrategy::EXIT_OOM) {
554562
vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR,
555563
"red-black tree failed allocation");
556564
}
@@ -560,8 +568,8 @@ class RBTreeCHeapAllocator {
560568
void free(void* ptr) { os::free(ptr); }
561569
};
562570

563-
template <typename K, typename V, typename COMPARATOR, MemTag mem_tag>
564-
using RBTreeCHeap = RBTree<K, V, COMPARATOR, RBTreeCHeapAllocator<mem_tag>>;
571+
template <typename K, typename V, typename COMPARATOR, MemTag mem_tag, AllocFailType strategy = AllocFailStrategy::EXIT_OOM>
572+
using RBTreeCHeap = RBTree<K, V, COMPARATOR, RBTreeCHeapAllocator<mem_tag, strategy>>;
565573

566574
template <typename K, typename COMPARATOR>
567575
using IntrusiveRBTree = AbstractRBTree<K, IntrusiveRBNode, COMPARATOR>;

test/hotspot/gtest/utilities/test_rbtree.cpp

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -986,23 +986,23 @@ struct IntCmp {
986986
};
987987

988988
TEST_VM(RBTreeTestNonFixture, TestPrintIntegerTree) {
989-
typedef RBTree<int, unsigned, IntCmp, RBTreeCHeapAllocator<mtTest> > TreeType;
990-
TreeType tree;
991-
const int i1 = 82924;
992-
const char* const s1 = "[82924] = 1";
993-
const int i2 = -13591;
994-
const char* const s2 = "[-13591] = 2";
995-
const int i3 = 0;
996-
const char* const s3 = "[0] = 3";
997-
tree.upsert(i1, 1U);
998-
tree.upsert(i2, 2U);
999-
tree.upsert(i3, 3U);
1000-
stringStream ss;
1001-
tree.print_on(&ss);
1002-
const char* const N = nullptr;
1003-
ASSERT_NE(strstr(ss.base(), s1), N);
1004-
ASSERT_NE(strstr(ss.base(), s2), N);
1005-
ASSERT_NE(strstr(ss.base(), s3), N);
989+
using TreeType = RBTreeCHeap<int, unsigned, IntCmp, mtTest>;
990+
TreeType tree;
991+
const int i1 = 82924;
992+
const char* const s1 = "[82924] = 1";
993+
const int i2 = -13591;
994+
const char* const s2 = "[-13591] = 2";
995+
const int i3 = 0;
996+
const char* const s3 = "[0] = 3";
997+
tree.upsert(i1, 1U);
998+
tree.upsert(i2, 2U);
999+
tree.upsert(i3, 3U);
1000+
stringStream ss;
1001+
tree.print_on(&ss);
1002+
const char* const N = nullptr;
1003+
ASSERT_NE(strstr(ss.base(), s1), N);
1004+
ASSERT_NE(strstr(ss.base(), s2), N);
1005+
ASSERT_NE(strstr(ss.base(), s3), N);
10061006
}
10071007

10081008
TEST_VM_F(RBTreeTest, IntrusiveTest) {
@@ -1079,3 +1079,15 @@ TEST_VM_F(RBTreeTest, VerifyItThroughStressTest) {
10791079
}
10801080
}
10811081

1082+
struct OomAllocator {
1083+
void* allocate(size_t sz) {
1084+
return nullptr;
1085+
}
1086+
void free(void* ptr) {}
1087+
};
1088+
TEST_VM_F(RBTreeTest, AllocatorMayReturnNull) {
1089+
RBTree<int, int, Cmp, OomAllocator> rbtree;
1090+
bool success = rbtree.upsert(5, 5);
1091+
EXPECT_EQ(false, success);
1092+
// The test didn't exit the VM, so it was succesful.
1093+
}

0 commit comments

Comments
 (0)