9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #include "precompiled.hpp"
27 #include "memory/metaspace/chunkManager.hpp"
28 #include "memory/metaspace/counters.hpp"
29 #include "memory/metaspace/metaspaceArena.hpp"
30 #include "memory/metaspace/metaspaceArenaGrowthPolicy.hpp"
31 #include "memory/metaspace/metaspaceSettings.hpp"
32 #include "memory/metaspace/metaspaceStatistics.hpp"
33 #include "runtime/mutexLocker.hpp"
34 #include "utilities/debug.hpp"
35 #include "utilities/globalDefinitions.hpp"
36 //#define LOG_PLEASE
37 #include "metaspaceGtestCommon.hpp"
38 #include "metaspaceGtestContexts.hpp"
39 #include "metaspaceGtestSparseArray.hpp"
40
41 using metaspace::ArenaGrowthPolicy;
42 using metaspace::ChunkManager;
43 using metaspace::IntCounter;
44 using metaspace::MemRangeCounter;
45 using metaspace::MetaspaceArena;
46 using metaspace::SizeAtomicCounter;
47 using metaspace::ArenaStats;
48 using metaspace::InUseChunkStats;
49
50 // Little randomness helper
51 static bool fifty_fifty() {
52 return IntRange(100).random_value() < 50;
53 }
54
55 // See metaspaceArena.cpp : needed for predicting commit sizes.
56 namespace metaspace {
57 extern size_t get_raw_word_size_for_requested_word_size(size_t net_word_size);
58 }
59
60 // A MetaspaceArenaTestBed contains a single MetaspaceArena and its lock.
61 // It keeps track of allocations done from this MetaspaceArena.
62 class MetaspaceArenaTestBed : public CHeapObj<mtInternal> {
63
64 MetaspaceArena* _arena;
65
66 Mutex* _lock;
67
68 const SizeRange _allocation_range;
69 size_t _size_of_last_failed_allocation;
70
71 // We keep track of all allocations done thru the MetaspaceArena to
72 // later check for overwriters.
73 struct allocation_t {
74 allocation_t* next;
75 MetaWord* p; // NULL if deallocated
76 size_t word_size;
77 void mark() {
78 mark_range(p, word_size);
79 }
80 void verify() const {
81 if (p != NULL) {
82 check_marked_range(p, word_size);
83 }
84 }
85 };
86
87 allocation_t* _allocations;
88
89 // We count how much we did allocate and deallocate
90 MemRangeCounter _alloc_count;
91 MemRangeCounter _dealloc_count;
92
93 // Check statistics returned by MetaspaceArena::add_to_statistics() against what
94 // we know we allocated. This is a bit flaky since MetaspaceArena has internal
95 // overhead.
96 void verify_arena_statistics() const {
97
98 ArenaStats stats;
99 _arena->add_to_statistics(&stats);
100 InUseChunkStats in_use_stats = stats.totals();
101
102 assert(_dealloc_count.total_size() <= _alloc_count.total_size() &&
103 _dealloc_count.count() <= _alloc_count.count(), "Sanity");
104
105 // Check consistency of stats
106 ASSERT_GE(in_use_stats._word_size, in_use_stats._committed_words);
107 ASSERT_EQ(in_use_stats._committed_words,
108 in_use_stats._used_words + in_use_stats._free_words + in_use_stats._waste_words);
109 ASSERT_GE(in_use_stats._used_words, stats._free_blocks_word_size);
110
111 // Note: reasons why the outside alloc counter and the inside used counter can differ:
112 // - alignment/padding of allocations
113 // - inside used counter contains blocks in free list
114 // - free block list splinter threshold
115 // - if +MetaspaceGuardAllocations, guard costs
116
117 // Since what we deallocated may have been given back to us in a following allocation,
118 // we only know fore sure we allocated what we did not give back.
119 const size_t at_least_allocated = _alloc_count.total_size() - _dealloc_count.total_size();
120
121 // At most we allocated this:
122 const size_t max_word_overhead_per_alloc =
123 4 + (metaspace::Settings::use_allocation_guard() ? 4 : 0);
124 const size_t at_most_allocated = _alloc_count.total_size() + max_word_overhead_per_alloc * _alloc_count.count();
125
126 ASSERT_LE(at_least_allocated, in_use_stats._used_words - stats._free_blocks_word_size);
127 ASSERT_GE(at_most_allocated, in_use_stats._used_words - stats._free_blocks_word_size);
128
129 }
130
131 public:
132
133 MetaspaceArena* arena() { return _arena; }
134
135 MetaspaceArenaTestBed(ChunkManager* cm, const ArenaGrowthPolicy* alloc_sequence,
136 SizeAtomicCounter* used_words_counter, SizeRange allocation_range) :
137 _arena(NULL),
138 _lock(NULL),
139 _allocation_range(allocation_range),
140 _size_of_last_failed_allocation(0),
141 _allocations(NULL),
142 _alloc_count(),
143 _dealloc_count()
144 {
145 _lock = new Mutex(Monitor::nosafepoint, "gtest-MetaspaceArenaTestBed_lock");
146 // Lock during space creation, since this is what happens in the VM too
147 // (see ClassLoaderData::metaspace_non_null(), which we mimick here).
148 MutexLocker ml(_lock, Mutex::_no_safepoint_check_flag);
149 _arena = new MetaspaceArena(cm, alloc_sequence, _lock, used_words_counter, "gtest-MetaspaceArenaTestBed-sm");
150 }
151
152 ~MetaspaceArenaTestBed() {
153
154 verify_arena_statistics();
155
156 allocation_t* a = _allocations;
157 while (a != NULL) {
158 allocation_t* b = a->next;
159 a->verify();
160 FREE_C_HEAP_OBJ(a);
161 a = b;
162 }
163
164 DEBUG_ONLY(_arena->verify();)
165
166 // Delete MetaspaceArena. That should clean up all metaspace.
167 delete _arena;
168 delete _lock;
169
170 }
171
172 size_t words_allocated() const { return _alloc_count.total_size(); }
173 int num_allocations() const { return _alloc_count.count(); }
174
175 size_t size_of_last_failed_allocation() const { return _size_of_last_failed_allocation; }
176
177 // Allocate a random amount. Return false if the allocation failed.
178 bool checked_random_allocate() {
179 size_t word_size = 1 + _allocation_range.random_value();
180 MetaWord* p = _arena->allocate(word_size);
181 if (p != NULL) {
182 EXPECT_TRUE(is_aligned(p, sizeof(MetaWord)));
183 allocation_t* a = NEW_C_HEAP_OBJ(allocation_t, mtInternal);
184 a->word_size = word_size;
185 a->p = p;
186 a->mark();
187 a->next = _allocations;
188 _allocations = a;
189 _alloc_count.add(word_size);
190 if ((_alloc_count.count() % 20) == 0) {
191 verify_arena_statistics();
192 DEBUG_ONLY(_arena->verify();)
193 }
194 return true;
195 } else {
196 _size_of_last_failed_allocation = word_size;
197 }
198 return false;
199 }
200
201 // Deallocate a random allocation
202 void checked_random_deallocate() {
203 allocation_t* a = _allocations;
204 while (a && a->p != NULL && os::random() % 10 != 0) {
205 a = a->next;
206 }
207 if (a != NULL && a->p != NULL) {
208 a->verify();
209 _arena->deallocate(a->p, a->word_size);
210 _dealloc_count.add(a->word_size);
212 if ((_dealloc_count.count() % 20) == 0) {
213 verify_arena_statistics();
214 DEBUG_ONLY(_arena->verify();)
215 }
216 }
217 }
218
219 }; // End: MetaspaceArenaTestBed
220
221 class MetaspaceArenaTest {
222
223 MetaspaceGtestContext _context;
224
225 SizeAtomicCounter _used_words_counter;
226
227 SparseArray<MetaspaceArenaTestBed*> _testbeds;
228 IntCounter _num_beds;
229
230 //////// Bed creation, destruction ///////
231
232 void create_new_test_bed_at(int slotindex, const ArenaGrowthPolicy* growth_policy, SizeRange allocation_range) {
233 DEBUG_ONLY(_testbeds.check_slot_is_null(slotindex));
234 MetaspaceArenaTestBed* bed = new MetaspaceArenaTestBed(&_context.cm(), growth_policy,
235 &_used_words_counter, allocation_range);
236 _testbeds.set_at(slotindex, bed);
237 _num_beds.increment();
238 }
239
240 void create_random_test_bed_at(int slotindex) {
241 SizeRange allocation_range(1, 100); // randomize too?
242 const ArenaGrowthPolicy* growth_policy = ArenaGrowthPolicy::policy_for_space_type(
243 (fifty_fifty() ? Metaspace::StandardMetaspaceType : Metaspace::ReflectionMetaspaceType),
244 fifty_fifty());
245 create_new_test_bed_at(slotindex, growth_policy, allocation_range);
246 }
247
248 // Randomly create a random test bed at a random slot, and return its slot index
249 // (returns false if we reached max number of test beds)
250 bool create_random_test_bed() {
251 const int slot = _testbeds.random_null_slot_index();
252 if (slot != -1) {
253 create_random_test_bed_at(slot);
254 }
255 return slot;
256 }
257
258 // Create test beds for all slots
259 void create_all_test_beds() {
260 for (int slot = 0; slot < _testbeds.size(); slot++) {
261 if (_testbeds.slot_is_null(slot)) {
262 create_random_test_bed_at(slot);
263 }
264 }
265 }
266
267 void delete_test_bed_at(int slotindex) {
268 DEBUG_ONLY(_testbeds.check_slot_is_not_null(slotindex));
269 MetaspaceArenaTestBed* bed = _testbeds.at(slotindex);
270 delete bed; // This will return all its memory to the chunk manager
271 _testbeds.set_at(slotindex, NULL);
272 _num_beds.decrement();
273 }
274
275 // Randomly delete a random test bed at a random slot
276 // Return false if there are no test beds to delete.
277 bool delete_random_test_bed() {
278 const int slotindex = _testbeds.random_non_null_slot_index();
279 if (slotindex != -1) {
280 delete_test_bed_at(slotindex);
281 return true;
282 }
283 return false;
284 }
285
286 // Delete all test beds.
287 void delete_all_test_beds() {
288 for (int slot = _testbeds.first_non_null_slot(); slot != -1; slot = _testbeds.next_non_null_slot(slot)) {
289 delete_test_bed_at(slot);
290 }
291 }
292
293 //////// Allocating metaspace from test beds ///////
294
295 bool random_allocate_from_testbed(int slotindex) {
296 DEBUG_ONLY(_testbeds.check_slot_is_not_null(slotindex);)
297 MetaspaceArenaTestBed* bed = _testbeds.at(slotindex);
298 bool success = bed->checked_random_allocate();
299 if (success == false) {
300 // We must have hit a limit.
301 EXPECT_LT(_context.commit_limiter().possible_expansion_words(),
302 metaspace::get_raw_word_size_for_requested_word_size(bed->size_of_last_failed_allocation()));
303 }
304 return success;
305 }
306
307 // Allocate multiple times random sizes from a single MetaspaceArena.
308 bool random_allocate_multiple_times_from_testbed(int slotindex, int num_allocations) {
309 bool success = true;
310 int n = 0;
311 while (success && n < num_allocations) {
312 success = random_allocate_from_testbed(slotindex);
313 n++;
314 }
315 return success;
316 }
317
318 // Allocate multiple times random sizes from a single random MetaspaceArena.
319 bool random_allocate_random_times_from_random_testbed() {
320 int slot = _testbeds.random_non_null_slot_index();
321 bool success = false;
322 if (slot != -1) {
|
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #include "precompiled.hpp"
27 #include "memory/metaspace/chunkManager.hpp"
28 #include "memory/metaspace/counters.hpp"
29 #include "memory/metaspace/metaspaceAlignment.hpp"
30 #include "memory/metaspace/metaspaceArena.hpp"
31 #include "memory/metaspace/metaspaceArenaGrowthPolicy.hpp"
32 #include "memory/metaspace/metaspaceSettings.hpp"
33 #include "memory/metaspace/metaspaceStatistics.hpp"
34 #include "runtime/mutexLocker.hpp"
35 #include "utilities/debug.hpp"
36 #include "utilities/globalDefinitions.hpp"
37 //#define LOG_PLEASE
38 #include "metaspaceGtestCommon.hpp"
39 #include "metaspaceGtestContexts.hpp"
40 #include "metaspaceGtestSparseArray.hpp"
41
42 using metaspace::ArenaGrowthPolicy;
43 using metaspace::ChunkManager;
44 using metaspace::IntCounter;
45 using metaspace::MemRangeCounter;
46 using metaspace::MetaspaceArena;
47 using metaspace::SizeAtomicCounter;
48 using metaspace::ArenaStats;
49 using metaspace::InUseChunkStats;
50
51 // Little randomness helper
52 static bool fifty_fifty() {
53 return IntRange(100).random_value() < 50;
54 }
55
56 // A MetaspaceArenaTestBed contains a single MetaspaceArena and its lock.
57 // It keeps track of allocations done from this MetaspaceArena.
58 class MetaspaceArenaTestBed : public CHeapObj<mtInternal> {
59
60 const SizeRange _allocation_range;
61 const int _alignment_words;
62
63 MetaspaceArena* _arena;
64 Mutex* _lock;
65 size_t _size_of_last_failed_allocation;
66
67 // We keep track of all allocations done thru the MetaspaceArena to
68 // later check for overwriters.
69 struct allocation_t {
70 allocation_t* next;
71 MetaWord* p; // NULL if deallocated
72 size_t word_size;
73 void mark() {
74 mark_range(p, word_size);
75 }
76 void verify() const {
77 if (p != NULL) {
78 check_marked_range(p, word_size);
79 }
80 }
81 };
82
83 allocation_t* _allocations;
84
85 // We count how much we did allocate and deallocate
86 MemRangeCounter _alloc_count_net; // net used bytes
87 MemRangeCounter _alloc_count_raw; // net used bytes + internal overhead
88 MemRangeCounter _dealloc_count;
89
90 // Check statistics returned by MetaspaceArena::add_to_statistics() against what
91 // we know we allocated. This is a bit flaky since MetaspaceArena has internal
92 // overhead.
93 void verify_arena_statistics() const {
94
95 ArenaStats stats;
96 _arena->add_to_statistics(&stats);
97 InUseChunkStats in_use_stats = stats.totals();
98
99 assert(_dealloc_count.total_size() <= _alloc_count_net.total_size() &&
100 _dealloc_count.count() <= _alloc_count_net.count(), "Sanity");
101
102 // Check consistency of stats
103 ASSERT_GE(in_use_stats._word_size, in_use_stats._committed_words);
104 ASSERT_EQ(in_use_stats._committed_words,
105 in_use_stats._used_words + in_use_stats._free_words + in_use_stats._waste_words);
106 ASSERT_GE(in_use_stats._used_words, stats._free_blocks_word_size);
107
108 // Note: reasons why the outside alloc counter and the inside used counter can differ:
109 // - alignment/padding of allocations
110 // - inside used counter contains blocks in free list
111 // - free block list splinter threshold
112 // - if +MetaspaceGuardAllocations, guard costs
113
114 // Since what we deallocated may have been given back to us in a following allocation,
115 // we only know fore sure we allocated what we did not give back.
116 const size_t at_least_allocated = _alloc_count_net.total_size() - _dealloc_count.total_size();
117
118 // At most we allocated this:
119 size_t max_word_overhead_per_alloc = align_up(4, _alignment_words);
120 // Guard fences come as a separate, secondary block
121 if (metaspace::Settings::use_allocation_guard()) {
122 max_word_overhead_per_alloc *= 2;
123 }
124 const size_t at_most_allocated = _alloc_count_raw.total_size() + max_word_overhead_per_alloc * _alloc_count_raw.count();
125
126 ASSERT_LE(at_least_allocated, in_use_stats._used_words - stats._free_blocks_word_size);
127 ASSERT_GE(at_most_allocated, in_use_stats._used_words - stats._free_blocks_word_size);
128 }
129
130 public:
131
132 MetaspaceArena* arena() { return _arena; }
133
134 MetaspaceArenaTestBed(ChunkManager* cm, const ArenaGrowthPolicy* alloc_sequence, int alignment_words,
135 SizeAtomicCounter* used_words_counter, SizeRange allocation_range) :
136 _allocation_range(allocation_range),
137 _alignment_words(alignment_words),
138 _arena(NULL),
139 _lock(NULL),
140 _size_of_last_failed_allocation(0),
141 _allocations(NULL),
142 _alloc_count_net(),
143 _dealloc_count()
144 {
145 _lock = new Mutex(Monitor::nosafepoint, "gtest-MetaspaceArenaTestBed_lock");
146 // Lock during space creation, since this is what happens in the VM too
147 // (see ClassLoaderData::metaspace_non_null(), which we mimick here).
148 MutexLocker ml(_lock, Mutex::_no_safepoint_check_flag);
149 _arena = new MetaspaceArena(cm, alloc_sequence, alignment_words, _lock, used_words_counter, "gtest-MetaspaceArenaTestBed-sm");
150 }
151
152 ~MetaspaceArenaTestBed() {
153
154 verify_arena_statistics();
155
156 allocation_t* a = _allocations;
157 while (a != NULL) {
158 allocation_t* b = a->next;
159 a->verify();
160 FREE_C_HEAP_OBJ(a);
161 a = b;
162 }
163
164 DEBUG_ONLY(_arena->verify();)
165
166 // Delete MetaspaceArena. That should clean up all metaspace.
167 delete _arena;
168 delete _lock;
169
170 }
171
172 size_t words_allocated() const { return _alloc_count_net.total_size(); }
173 int num_allocations() const { return _alloc_count_net.count(); }
174
175 size_t size_of_last_failed_allocation() const { return _size_of_last_failed_allocation; }
176
177 size_t calc_expected_usage_for_allocated_words(size_t word_size) {
178 return metaspace::get_raw_word_size_for_requested_word_size(word_size, _alignment_words);
179 }
180
181 // Allocate a random amount. Return false if the allocation failed.
182 bool checked_random_allocate() {
183 size_t word_size = 1 + _allocation_range.random_value();
184 MetaWord* p = _arena->allocate(word_size);
185 if (p != NULL) {
186 EXPECT_TRUE(is_aligned(p, _alignment_words * BytesPerWord));
187 allocation_t* a = NEW_C_HEAP_OBJ(allocation_t, mtInternal);
188 a->word_size = word_size;
189 a->p = p;
190 a->mark();
191 a->next = _allocations;
192 _allocations = a;
193 _alloc_count_net.add(word_size);
194 _alloc_count_raw.add(calc_expected_usage_for_allocated_words(word_size));
195 if ((_alloc_count_net.count() % 20) == 0) {
196 verify_arena_statistics();
197 DEBUG_ONLY(_arena->verify();)
198 }
199 return true;
200 } else {
201 _size_of_last_failed_allocation = word_size;
202 }
203 return false;
204 }
205
206 // Deallocate a random allocation
207 void checked_random_deallocate() {
208 allocation_t* a = _allocations;
209 while (a && a->p != NULL && os::random() % 10 != 0) {
210 a = a->next;
211 }
212 if (a != NULL && a->p != NULL) {
213 a->verify();
214 _arena->deallocate(a->p, a->word_size);
215 _dealloc_count.add(a->word_size);
217 if ((_dealloc_count.count() % 20) == 0) {
218 verify_arena_statistics();
219 DEBUG_ONLY(_arena->verify();)
220 }
221 }
222 }
223
224 }; // End: MetaspaceArenaTestBed
225
226 class MetaspaceArenaTest {
227
228 MetaspaceGtestContext _context;
229
230 SizeAtomicCounter _used_words_counter;
231
232 SparseArray<MetaspaceArenaTestBed*> _testbeds;
233 IntCounter _num_beds;
234
235 //////// Bed creation, destruction ///////
236
237 void create_new_test_bed_at(int slotindex, const ArenaGrowthPolicy* growth_policy, int alignment_words, SizeRange allocation_range) {
238 DEBUG_ONLY(_testbeds.check_slot_is_null(slotindex));
239 MetaspaceArenaTestBed* bed = new MetaspaceArenaTestBed(&_context.cm(), growth_policy, alignment_words,
240 &_used_words_counter, allocation_range);
241 _testbeds.set_at(slotindex, bed);
242 _num_beds.increment();
243 }
244
245 void create_random_test_bed_at(int slotindex) {
246 SizeRange allocation_range(1, 100); // randomize too?
247 const ArenaGrowthPolicy* growth_policy = ArenaGrowthPolicy::policy_for_space_type(
248 (fifty_fifty() ? Metaspace::StandardMetaspaceType : Metaspace::ReflectionMetaspaceType),
249 fifty_fifty());
250 const int alignment_bytes =
251 1 << IntRange(metaspace::LogMetaspaceMinimalAlignment,
252 metaspace::LogMetaspaceMinimalAlignment + 7).random_value(); // zw 8 byte and 1K
253 create_new_test_bed_at(slotindex, growth_policy, alignment_bytes / BytesPerWord, allocation_range);
254 }
255
256 // Randomly create a random test bed at a random slot, and return its slot index
257 // (returns false if we reached max number of test beds)
258 bool create_random_test_bed() {
259 const int slot = _testbeds.random_null_slot_index();
260 if (slot != -1) {
261 create_random_test_bed_at(slot);
262 }
263 return slot;
264 }
265
266 void delete_test_bed_at(int slotindex) {
267 DEBUG_ONLY(_testbeds.check_slot_is_not_null(slotindex));
268 MetaspaceArenaTestBed* bed = _testbeds.at(slotindex);
269 delete bed; // This will return all its memory to the chunk manager
270 _testbeds.set_at(slotindex, NULL);
271 _num_beds.decrement();
272 }
273
274 // Randomly delete a random test bed at a random slot
275 // Return false if there are no test beds to delete.
276 bool delete_random_test_bed() {
277 const int slotindex = _testbeds.random_non_null_slot_index();
278 if (slotindex != -1) {
279 delete_test_bed_at(slotindex);
280 return true;
281 }
282 return false;
283 }
284
285 // Delete all test beds.
286 void delete_all_test_beds() {
287 for (int slot = _testbeds.first_non_null_slot(); slot != -1; slot = _testbeds.next_non_null_slot(slot)) {
288 delete_test_bed_at(slot);
289 }
290 }
291
292 //////// Allocating metaspace from test beds ///////
293
294 bool random_allocate_from_testbed(int slotindex) {
295 DEBUG_ONLY(_testbeds.check_slot_is_not_null(slotindex);)
296 MetaspaceArenaTestBed* bed = _testbeds.at(slotindex);
297 bool success = bed->checked_random_allocate();
298 if (success == false) {
299 // We must have hit a limit.
300 EXPECT_LT(_context.commit_limiter().possible_expansion_words(),
301 bed->calc_expected_usage_for_allocated_words(bed->size_of_last_failed_allocation()));
302 }
303 return success;
304 }
305
306 // Allocate multiple times random sizes from a single MetaspaceArena.
307 bool random_allocate_multiple_times_from_testbed(int slotindex, int num_allocations) {
308 bool success = true;
309 int n = 0;
310 while (success && n < num_allocations) {
311 success = random_allocate_from_testbed(slotindex);
312 n++;
313 }
314 return success;
315 }
316
317 // Allocate multiple times random sizes from a single random MetaspaceArena.
318 bool random_allocate_random_times_from_random_testbed() {
319 int slot = _testbeds.random_non_null_slot_index();
320 bool success = false;
321 if (slot != -1) {
|