Skip to content

Commit d7b7c17

Browse files
committed
8335409: Can't allocate and retain memory from resource area in frame::oops_interpreted_do oop closure after 8329665
Reviewed-by: shade Backport-of: 7ab96c7
1 parent 5162e1a commit d7b7c17

File tree

3 files changed

+35
-49
lines changed

3 files changed

+35
-49
lines changed

src/hotspot/share/interpreter/oopMapCache.cpp

Lines changed: 24 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,6 @@ class OopMapCacheEntry: private InterpreterOopMap {
6666
public:
6767
OopMapCacheEntry() : InterpreterOopMap() {
6868
_next = nullptr;
69-
#ifdef ASSERT
70-
_resource_allocate_bit_mask = false;
71-
#endif
7269
}
7370
};
7471

@@ -177,9 +174,13 @@ class VerifyClosure : public OffsetClosure {
177174

178175
InterpreterOopMap::InterpreterOopMap() {
179176
initialize();
180-
#ifdef ASSERT
181-
_resource_allocate_bit_mask = true;
182-
#endif
177+
}
178+
179+
InterpreterOopMap::~InterpreterOopMap() {
180+
if (has_valid_mask() && mask_size() > small_mask_limit) {
181+
assert(_bit_mask[0] != 0, "should have pointer to C heap");
182+
FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]);
183+
}
183184
}
184185

185186
bool InterpreterOopMap::is_empty() const {
@@ -399,37 +400,24 @@ void OopMapCacheEntry::deallocate(OopMapCacheEntry* const entry) {
399400

400401
// Implementation of OopMapCache
401402

402-
void InterpreterOopMap::resource_copy(OopMapCacheEntry* from) {
403-
assert(_resource_allocate_bit_mask,
404-
"Should not resource allocate the _bit_mask");
405-
assert(from->has_valid_mask(),
406-
"Cannot copy entry with an invalid mask");
403+
void InterpreterOopMap::copy_from(const OopMapCacheEntry* src) {
404+
// The expectation is that this InterpreterOopMap is recently created
405+
// and empty. It is used to get a copy of a cached entry.
406+
assert(!has_valid_mask(), "InterpreterOopMap object can only be filled once");
407+
assert(src->has_valid_mask(), "Cannot copy entry with an invalid mask");
407408

408-
set_method(from->method());
409-
set_bci(from->bci());
410-
set_mask_size(from->mask_size());
411-
set_expression_stack_size(from->expression_stack_size());
412-
_num_oops = from->num_oops();
409+
set_method(src->method());
410+
set_bci(src->bci());
411+
set_mask_size(src->mask_size());
412+
set_expression_stack_size(src->expression_stack_size());
413+
_num_oops = src->num_oops();
413414

414415
// Is the bit mask contained in the entry?
415-
if (from->mask_size() <= small_mask_limit) {
416-
memcpy((void *)_bit_mask, (void *)from->_bit_mask,
417-
mask_word_size() * BytesPerWord);
416+
if (src->mask_size() <= small_mask_limit) {
417+
memcpy(_bit_mask, src->_bit_mask, mask_word_size() * BytesPerWord);
418418
} else {
419-
// The expectation is that this InterpreterOopMap is a recently created
420-
// and empty. It is used to get a copy of a cached entry.
421-
// If the bit mask has a value, it should be in the
422-
// resource area.
423-
assert(_bit_mask[0] == 0 ||
424-
Thread::current()->resource_area()->contains((void*)_bit_mask[0]),
425-
"The bit mask should have been allocated from a resource area");
426-
// Allocate the bit_mask from a Resource area for performance. Allocating
427-
// from the C heap as is done for OopMapCache has a significant
428-
// performance impact.
429-
_bit_mask[0] = (uintptr_t) NEW_RESOURCE_ARRAY(uintptr_t, mask_word_size());
430-
assert(_bit_mask[0] != 0, "bit mask was not allocated");
431-
memcpy((void*) _bit_mask[0], (void*) from->_bit_mask[0],
432-
mask_word_size() * BytesPerWord);
419+
_bit_mask[0] = (uintptr_t) NEW_C_HEAP_ARRAY(uintptr_t, mask_word_size(), mtClass);
420+
memcpy((void*) _bit_mask[0], (void*) src->_bit_mask[0], mask_word_size() * BytesPerWord);
433421
}
434422
}
435423

@@ -516,7 +504,7 @@ void OopMapCache::lookup(const methodHandle& method,
516504
for (int i = 0; i < _probe_depth; i++) {
517505
OopMapCacheEntry *entry = entry_at(probe + i);
518506
if (entry != nullptr && !entry->is_empty() && entry->match(method, bci)) {
519-
entry_for->resource_copy(entry);
507+
entry_for->copy_from(entry);
520508
assert(!entry_for->is_empty(), "A non-empty oop map should be returned");
521509
log_debug(interpreter, oopmap)("- found at hash %d", probe + i);
522510
return;
@@ -530,7 +518,7 @@ void OopMapCache::lookup(const methodHandle& method,
530518
OopMapCacheEntry* tmp = NEW_C_HEAP_OBJ(OopMapCacheEntry, mtClass);
531519
tmp->initialize();
532520
tmp->fill(method, bci);
533-
entry_for->resource_copy(tmp);
521+
entry_for->copy_from(tmp);
534522

535523
if (method->should_not_be_cached()) {
536524
// It is either not safe or not a good idea to cache this Method*
@@ -631,7 +619,7 @@ void OopMapCache::compute_one_oop_map(const methodHandle& method, int bci, Inter
631619
tmp->initialize();
632620
tmp->fill(method, bci);
633621
if (tmp->has_valid_mask()) {
634-
entry->resource_copy(tmp);
622+
entry->copy_from(tmp);
635623
}
636624
OopMapCacheEntry::deallocate(tmp);
637625
}

src/hotspot/share/interpreter/oopMapCache.hpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,14 @@
3636
// OopMapCache's are allocated lazily per InstanceKlass.
3737

3838
// The oopMap (InterpreterOopMap) is stored as a bit mask. If the
39-
// bit_mask can fit into two words it is stored in
39+
// bit_mask can fit into four words it is stored in
4040
// the _bit_mask array, otherwise it is allocated on the heap.
4141
// For OopMapCacheEntry the bit_mask is allocated in the C heap
4242
// because these entries persist between garbage collections.
43-
// For InterpreterOopMap the bit_mask is allocated in
44-
// a resource area for better performance. InterpreterOopMap
45-
// should only be created and deleted during same garbage collection.
43+
// For InterpreterOopMap the bit_mask is allocated in the C heap
44+
// to avoid issues with allocations from the resource area that have
45+
// to live accross the oop closure. InterpreterOopMap should only be
46+
// created and deleted during the same garbage collection.
4647
//
4748
// If ENABBLE_ZAP_DEAD_LOCALS is defined, two bits are used
4849
// per entry instead of one. In all cases,
@@ -95,9 +96,6 @@ class InterpreterOopMap: ResourceObj {
9596
// access it without using trickery in
9697
// method bit_mask().
9798
int _num_oops;
98-
#ifdef ASSERT
99-
bool _resource_allocate_bit_mask;
100-
#endif
10199

102100
// access methods
103101
Method* method() const { return _method; }
@@ -128,12 +126,13 @@ class InterpreterOopMap: ResourceObj {
128126

129127
public:
130128
InterpreterOopMap();
129+
~InterpreterOopMap();
131130

132-
// Copy the OopMapCacheEntry in parameter "from" into this
133-
// InterpreterOopMap. If the _bit_mask[0] in "from" points to
134-
// allocated space (i.e., the bit mask was to large to hold
135-
// in-line), allocate the space from a Resource area.
136-
void resource_copy(OopMapCacheEntry* from);
131+
// Copy the OopMapCacheEntry in parameter "src" into this
132+
// InterpreterOopMap. If the _bit_mask[0] in "src" points to
133+
// allocated space (i.e., the bit mask was too large to hold
134+
// in-line), allocate the space from the C heap.
135+
void copy_from(const OopMapCacheEntry* src);
137136

138137
void iterate_oop(OffsetClosure* oop_closure) const;
139138
void print() const;

src/hotspot/share/runtime/frame.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,6 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer
947947
InterpreterFrameClosure blk(this, max_locals, m->max_stack(), f);
948948

949949
// process locals & expression stack
950-
ResourceMark rm(thread);
951950
InterpreterOopMap mask;
952951
if (query_oop_map_cache) {
953952
m->mask_for(m, bci, &mask);

0 commit comments

Comments
 (0)