8336999: Verification for resource area allocated data structures in C2
Reviewed-by: chagedorn, kvn
This commit is contained in:
parent
90641a601c
commit
657c0bddf9
@ -132,6 +132,7 @@ class CompileReplay : public StackObj {
|
||||
char* _bufptr;
|
||||
char* _buffer;
|
||||
int _buffer_length;
|
||||
ReallocMark _nesting; // Safety checks for arena reallocation
|
||||
|
||||
// "compile" data
|
||||
ciKlass* _iklass;
|
||||
@ -601,6 +602,7 @@ class CompileReplay : public StackObj {
|
||||
int buffer_pos = 0;
|
||||
while(c != EOF) {
|
||||
if (buffer_pos + 1 >= _buffer_length) {
|
||||
_nesting.check(); // Check if a reallocation in the resource arena is safe
|
||||
int new_length = _buffer_length * 2;
|
||||
// Next call will throw error in case of OOM.
|
||||
_buffer = REALLOC_RESOURCE_ARRAY(char, _buffer, _buffer_length, new_length);
|
||||
|
@ -48,6 +48,10 @@ void VectorSet::init(Arena* arena) {
|
||||
|
||||
// Expand the existing set to a bigger size
|
||||
void VectorSet::grow(uint new_word_capacity) {
|
||||
_nesting.check(_set_arena); // Check if a potential reallocation in the arena is safe
|
||||
if (new_word_capacity < _size) {
|
||||
return; // No need to grow
|
||||
}
|
||||
assert(new_word_capacity < (1U << 30), "");
|
||||
uint x = next_power_of_2(new_word_capacity);
|
||||
if (x > _data_size) {
|
||||
|
@ -46,6 +46,7 @@ private:
|
||||
// Allocated words
|
||||
uint _data_size;
|
||||
Arena* _set_arena;
|
||||
ReallocMark _nesting; // Safety checks for arena reallocation
|
||||
|
||||
void init(Arena* arena);
|
||||
// Grow vector to required word capacity
|
||||
@ -77,10 +78,7 @@ public:
|
||||
//
|
||||
bool test_set(uint elem) {
|
||||
uint32_t word = elem >> word_bits;
|
||||
if (word >= _size) {
|
||||
// Then grow
|
||||
grow(word);
|
||||
}
|
||||
grow(word);
|
||||
uint32_t mask = 1U << (elem & bit_mask);
|
||||
uint32_t data = _data[word];
|
||||
_data[word] = data | mask;
|
||||
@ -109,9 +107,7 @@ public:
|
||||
// Fast inlined set
|
||||
void set(uint elem) {
|
||||
uint32_t word = elem >> word_bits;
|
||||
if (word >= _size) {
|
||||
grow(word);
|
||||
}
|
||||
grow(word);
|
||||
uint32_t mask = 1U << (elem & bit_mask);
|
||||
_data[word] |= mask;
|
||||
}
|
||||
|
@ -237,9 +237,10 @@ ReallocMark::ReallocMark() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void ReallocMark::check() {
|
||||
void ReallocMark::check(Arena* arena) {
|
||||
#ifdef ASSERT
|
||||
if (_nesting != Thread::current()->resource_area()->nesting()) {
|
||||
if ((arena == nullptr || arena == Thread::current()->resource_area()) &&
|
||||
_nesting != Thread::current()->resource_area()->nesting()) {
|
||||
fatal("allocation bug: array could grow within nested ResourceMark");
|
||||
}
|
||||
#endif
|
||||
|
@ -556,8 +556,8 @@ protected:
|
||||
NOT_PRODUCT(int _nesting;)
|
||||
|
||||
public:
|
||||
ReallocMark() PRODUCT_RETURN;
|
||||
void check() PRODUCT_RETURN;
|
||||
ReallocMark() PRODUCT_RETURN;
|
||||
void check(Arena* arena = nullptr) PRODUCT_RETURN;
|
||||
};
|
||||
|
||||
// Uses mmapped memory for all allocations. All allocations are initially
|
||||
|
@ -39,7 +39,10 @@
|
||||
#include "utilities/powerOfTwo.hpp"
|
||||
|
||||
void Block_Array::grow( uint i ) {
|
||||
assert(i >= Max(), "must be an overflow");
|
||||
_nesting.check(_arena); // Check if a potential reallocation in the arena is safe
|
||||
if (i < Max()) {
|
||||
return; // No need to grow
|
||||
}
|
||||
debug_only(_limit = i+1);
|
||||
if( i < _size ) return;
|
||||
if( !_size ) {
|
||||
@ -374,6 +377,7 @@ void Block::dump(const PhaseCFG* cfg) const {
|
||||
PhaseCFG::PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher)
|
||||
: Phase(CFG)
|
||||
, _root(root)
|
||||
, _blocks(arena)
|
||||
, _block_arena(arena)
|
||||
, _regalloc(nullptr)
|
||||
, _scheduling_for_pressure(false)
|
||||
@ -1417,7 +1421,7 @@ UnionFind::UnionFind( uint max ) : _cnt(max), _max(max), _indices(NEW_RESOURCE_A
|
||||
}
|
||||
|
||||
void UnionFind::extend( uint from_idx, uint to_idx ) {
|
||||
_nesting.check();
|
||||
_nesting.check(); // Check if a potential reallocation in the resource arena is safe
|
||||
if( from_idx >= _max ) {
|
||||
uint size = 16;
|
||||
while( size <= from_idx ) size <<=1;
|
||||
|
@ -51,6 +51,7 @@ class Block_Array : public ArenaObj {
|
||||
uint _size; // allocated size, as opposed to formal limit
|
||||
debug_only(uint _limit;) // limit to formal domain
|
||||
Arena *_arena; // Arena to allocate in
|
||||
ReallocMark _nesting; // Safety checks for arena reallocation
|
||||
protected:
|
||||
Block **_blocks;
|
||||
void grow( uint i ); // Grow array node to fit
|
||||
@ -68,7 +69,7 @@ public:
|
||||
Block *operator[] ( uint i ) const // Lookup, or assert for not mapped
|
||||
{ assert( i < Max(), "oob" ); return _blocks[i]; }
|
||||
// Extend the mapping: index i maps to Block *n.
|
||||
void map( uint i, Block *n ) { if( i>=Max() ) grow(i); _blocks[i] = n; }
|
||||
void map( uint i, Block *n ) { grow(i); _blocks[i] = n; }
|
||||
uint Max() const { debug_only(return _limit); return _size; }
|
||||
};
|
||||
|
||||
@ -77,7 +78,9 @@ class Block_List : public Block_Array {
|
||||
friend class VMStructs;
|
||||
public:
|
||||
uint _cnt;
|
||||
Block_List() : Block_Array(Thread::current()->resource_area()), _cnt(0) {}
|
||||
Block_List() : Block_List(Thread::current()->resource_area()) { }
|
||||
Block_List(Arena* a) : Block_Array(a), _cnt(0) { }
|
||||
|
||||
void push( Block *b ) { map(_cnt++,b); }
|
||||
Block *pop() { return _blocks[--_cnt]; }
|
||||
Block *rpop() { Block *b = _blocks[0]; _blocks[0]=_blocks[--_cnt]; return b;}
|
||||
@ -655,7 +658,7 @@ class PhaseCFG : public Phase {
|
||||
class UnionFind : public ResourceObj {
|
||||
uint _cnt, _max;
|
||||
uint* _indices;
|
||||
ReallocMark _nesting; // assertion check for reallocations
|
||||
ReallocMark _nesting; // Safety checks for arena reallocation
|
||||
public:
|
||||
UnionFind( uint max );
|
||||
void reset( uint max ); // Reset to identity map for [0..max]
|
||||
|
@ -61,9 +61,6 @@ struct Tarjan {
|
||||
// Compute the dominator tree of the CFG. The CFG must already have been
|
||||
// constructed. This is the Lengauer & Tarjan O(E-alpha(E,V)) algorithm.
|
||||
void PhaseCFG::build_dominator_tree() {
|
||||
// Pre-grow the blocks array, prior to the ResourceMark kicking in
|
||||
_blocks.map(number_of_blocks(), nullptr);
|
||||
|
||||
ResourceMark rm;
|
||||
// Setup mappings from my Graph to Tarjan's stuff and back
|
||||
// Note: Tarjan uses 1-based arrays
|
||||
|
@ -5248,6 +5248,7 @@ bool IdealLoopTree::verify_tree(IdealLoopTree* loop_verify) const {
|
||||
|
||||
//------------------------------set_idom---------------------------------------
|
||||
void PhaseIdealLoop::set_idom(Node* d, Node* n, uint dom_depth) {
|
||||
_nesting.check(); // Check if a potential reallocation in the resource arena is safe
|
||||
uint idx = d->_idx;
|
||||
if (idx >= _idom_size) {
|
||||
uint newsize = next_power_of_2(idx);
|
||||
|
@ -841,6 +841,8 @@ class PhaseIdealLoop : public PhaseTransform {
|
||||
uint *_preorders;
|
||||
uint _max_preorder;
|
||||
|
||||
ReallocMark _nesting; // Safety checks for arena reallocation
|
||||
|
||||
const PhaseIdealLoop* _verify_me;
|
||||
bool _verify_only;
|
||||
|
||||
@ -853,6 +855,7 @@ class PhaseIdealLoop : public PhaseTransform {
|
||||
|
||||
// Allocate _preorders[] array
|
||||
void reallocate_preorders() {
|
||||
_nesting.check(); // Check if a potential re-allocation in the resource arena is safe
|
||||
if ( _max_preorder < C->unique() ) {
|
||||
_preorders = REALLOC_RESOURCE_ARRAY(uint, _preorders, _max_preorder, C->unique());
|
||||
_max_preorder = C->unique();
|
||||
@ -863,6 +866,7 @@ class PhaseIdealLoop : public PhaseTransform {
|
||||
// Check to grow _preorders[] array for the case when build_loop_tree_impl()
|
||||
// adds new nodes.
|
||||
void check_grow_preorders( ) {
|
||||
_nesting.check(); // Check if a potential re-allocation in the resource arena is safe
|
||||
if ( _max_preorder < C->unique() ) {
|
||||
uint newsize = _max_preorder<<1; // double size of array
|
||||
_preorders = REALLOC_RESOURCE_ARRAY(uint, _preorders, _max_preorder, newsize);
|
||||
|
@ -2766,6 +2766,10 @@ const RegMask &Node::in_RegMask(uint) const {
|
||||
}
|
||||
|
||||
void Node_Array::grow(uint i) {
|
||||
_nesting.check(_a); // Check if a potential reallocation in the arena is safe
|
||||
if (i < _max) {
|
||||
return; // No need to grow
|
||||
}
|
||||
assert(_max > 0, "invariant");
|
||||
uint old = _max;
|
||||
_max = next_power_of_2(i);
|
||||
@ -2973,6 +2977,10 @@ void Unique_Node_List::remove_useless_nodes(VectorSet &useful) {
|
||||
|
||||
//=============================================================================
|
||||
void Node_Stack::grow() {
|
||||
_nesting.check(_a); // Check if a potential reallocation in the arena is safe
|
||||
if (_inode_top < _inode_max) {
|
||||
return; // No need to grow
|
||||
}
|
||||
size_t old_top = pointer_delta(_inode_top,_inodes,sizeof(INode)); // save _top
|
||||
size_t old_max = pointer_delta(_inode_max,_inodes,sizeof(INode));
|
||||
size_t max = old_max << 1; // max * 2
|
||||
|
@ -1596,6 +1596,8 @@ protected:
|
||||
Arena* _a; // Arena to allocate in
|
||||
uint _max;
|
||||
Node** _nodes;
|
||||
ReallocMark _nesting; // Safety checks for arena reallocation
|
||||
|
||||
void grow( uint i ); // Grow array node to fit
|
||||
public:
|
||||
Node_Array(Arena* a, uint max = OptoNodeListSize) : _a(a), _max(max) {
|
||||
@ -1614,7 +1616,7 @@ public:
|
||||
Node* at(uint i) const { assert(i<_max,"oob"); return _nodes[i]; }
|
||||
Node** adr() { return _nodes; }
|
||||
// Extend the mapping: index i maps to Node *n.
|
||||
void map( uint i, Node *n ) { if( i>=_max ) grow(i); _nodes[i] = n; }
|
||||
void map( uint i, Node *n ) { grow(i); _nodes[i] = n; }
|
||||
void insert( uint i, Node *n );
|
||||
void remove( uint i ); // Remove, preserving order
|
||||
// Clear all entries in _nodes to null but keep storage
|
||||
@ -1844,6 +1846,7 @@ protected:
|
||||
INode *_inode_max; // End of _inodes == _inodes + _max
|
||||
INode *_inodes; // Array storage for the stack
|
||||
Arena *_a; // Arena to allocate in
|
||||
ReallocMark _nesting; // Safety checks for arena reallocation
|
||||
void grow();
|
||||
public:
|
||||
Node_Stack(int size) {
|
||||
@ -1867,7 +1870,7 @@ public:
|
||||
}
|
||||
void push(Node *n, uint i) {
|
||||
++_inode_top;
|
||||
if (_inode_top >= _inode_max) grow();
|
||||
grow();
|
||||
INode *top = _inode_top; // optimization
|
||||
top->node = n;
|
||||
top->indx = i;
|
||||
|
@ -2351,6 +2351,7 @@ void Node::replace_by(Node *new_node) {
|
||||
//=============================================================================
|
||||
//-----------------------------------------------------------------------------
|
||||
void Type_Array::grow( uint i ) {
|
||||
assert(_a == Compile::current()->comp_arena(), "Should be allocated in comp_arena");
|
||||
if( !_max ) {
|
||||
_max = 1;
|
||||
_types = (const Type**)_a->Amalloc( _max * sizeof(Type*) );
|
||||
|
@ -184,7 +184,7 @@ void PhaseVector::scalarize_vbox_node(VectorBoxNode* vec_box) {
|
||||
// Process merged VBAs
|
||||
|
||||
if (EnableVectorAggressiveReboxing) {
|
||||
Unique_Node_List calls(C->comp_arena());
|
||||
Unique_Node_List calls;
|
||||
for (DUIterator_Fast imax, i = vec_box->fast_outs(imax); i < imax; i++) {
|
||||
Node* use = vec_box->fast_out(i);
|
||||
if (use->is_CallJava()) {
|
||||
@ -238,9 +238,9 @@ void PhaseVector::scalarize_vbox_node(VectorBoxNode* vec_box) {
|
||||
}
|
||||
|
||||
// Process debug uses at safepoints
|
||||
Unique_Node_List safepoints(C->comp_arena());
|
||||
Unique_Node_List safepoints;
|
||||
|
||||
Unique_Node_List worklist(C->comp_arena());
|
||||
Unique_Node_List worklist;
|
||||
worklist.push(vec_box);
|
||||
while (worklist.size() > 0) {
|
||||
Node* n = worklist.pop();
|
||||
|
Loading…
x
Reference in New Issue
Block a user