8007986: GrowableArray should implement binary search

Binary search method for GrowableArray

Reviewed-by: vlivanov, jrose
This commit is contained in:
Roland Westrelin 2016-02-23 17:59:27 +01:00
parent 0e31a18fd1
commit 449c65bf50
7 changed files with 62 additions and 145 deletions

View File

@ -41,58 +41,37 @@ ciConstantPoolCache::ciConstantPoolCache(Arena* arena,
_keys = new (arena) GrowableArray<int>(arena, expected_size, 0, 0);
}
int ciConstantPoolCache::key_compare(const int& key, const int& elt) {
if (key < elt) return -1;
else if (key > elt) return 1;
else return 0;
}
// ------------------------------------------------------------------
// ciConstantPoolCache::get
//
// Get the entry at some index
void* ciConstantPoolCache::get(int index) {
ASSERT_IN_VM;
int pos = find(index);
if (pos >= _keys->length() ||
_keys->at(pos) != index) {
bool found = false;
int pos = _keys->find_sorted<int, ciConstantPoolCache::key_compare>(index, found);
if (!found) {
// This element is not present in the cache.
return NULL;
}
return _elements->at(pos);
}
// ------------------------------------------------------------------
// ciConstantPoolCache::find
//
// Use binary search to find the position of this index in the cache.
// If there is no entry in the cache corresponding to this oop, return
// the position at which the index would be inserted.
int ciConstantPoolCache::find(int key) {
int min = 0;
int max = _keys->length()-1;
while (max >= min) {
int mid = (max + min) / 2;
int value = _keys->at(mid);
if (value < key) {
min = mid + 1;
} else if (value > key) {
max = mid - 1;
} else {
return mid;
}
}
return min;
}
// ------------------------------------------------------------------
// ciConstantPoolCache::insert
//
// Insert a ciObject into the table at some index.
void ciConstantPoolCache::insert(int index, void* elem) {
int i;
int pos = find(index);
for (i = _keys->length()-1; i >= pos; i--) {
_keys->at_put_grow(i+1, _keys->at(i));
_elements->at_put_grow(i+1, _elements->at(i));
}
_keys->at_put_grow(pos, index);
_elements->at_put_grow(pos, elem);
bool found = false;
int pos = _keys->find_sorted<int, ciConstantPoolCache::key_compare>(index, found);
assert(!found, "duplicate");
_keys->insert_before(pos, index);
_elements->insert_before(pos, elem);
}
// ------------------------------------------------------------------

View File

@ -38,7 +38,7 @@ private:
GrowableArray<int>* _keys;
GrowableArray<void*>* _elements;
int find(int index);
static int key_compare(const int& key, const int& elt);
public:
ciConstantPoolCache(Arena* arena, int expected_size);

View File

@ -260,6 +260,13 @@ ciObject* ciObjectFactory::get(oop key) {
return new_object;
}
int ciObjectFactory::metadata_compare(Metadata* const& key, ciMetadata* const& elt) {
Metadata* value = elt->constant_encoding();
if (key < value) return -1;
else if (key > value) return 1;
else return 0;
}
// ------------------------------------------------------------------
// ciObjectFactory::get_metadata
//
@ -280,7 +287,8 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) {
}
#endif // ASSERT
int len = _ci_metadata->length();
int index = find(key, _ci_metadata);
bool found = false;
int index = _ci_metadata->find_sorted<Metadata*, ciObjectFactory::metadata_compare>(key, found);
#ifdef ASSERT
if (CIObjectFactoryVerify) {
for (int i=0; i<_ci_metadata->length(); i++) {
@ -290,7 +298,8 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) {
}
}
#endif
if (!is_found_at(index, key, _ci_metadata)) {
if (!found) {
// The ciMetadata does not yet exist. Create it and insert it
// into the cache.
ciMetadata* new_object = create_new_metadata(key);
@ -300,10 +309,10 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) {
if (len != _ci_metadata->length()) {
// creating the new object has recursively entered new objects
// into the table. We need to recompute our index.
index = find(key, _ci_metadata);
index = _ci_metadata->find_sorted<Metadata*, ciObjectFactory::metadata_compare>(key, found);
}
assert(!is_found_at(index, key, _ci_metadata), "no double insert");
insert(index, new_object, _ci_metadata);
assert(!found, "no double insert");
_ci_metadata->insert_before(index, new_object);
return new_object;
}
return _ci_metadata->at(index)->as_metadata();
@ -655,60 +664,6 @@ void ciObjectFactory::init_ident_of(ciBaseObject* obj) {
obj->set_ident(_next_ident++);
}
// ------------------------------------------------------------------
// ciObjectFactory::find
//
// Use binary search to find the position of this oop in the cache.
// If there is no entry in the cache corresponding to this oop, return
// the position at which the oop should be inserted.
int ciObjectFactory::find(Metadata* key, GrowableArray<ciMetadata*>* objects) {
int min = 0;
int max = objects->length()-1;
// print_contents();
while (max >= min) {
int mid = (max + min) / 2;
Metadata* value = objects->at(mid)->constant_encoding();
if (value < key) {
min = mid + 1;
} else if (value > key) {
max = mid - 1;
} else {
return mid;
}
}
return min;
}
// ------------------------------------------------------------------
// ciObjectFactory::is_found_at
//
// Verify that the binary seach found the given key.
bool ciObjectFactory::is_found_at(int index, Metadata* key, GrowableArray<ciMetadata*>* objects) {
return (index < objects->length() &&
objects->at(index)->constant_encoding() == key);
}
// ------------------------------------------------------------------
// ciObjectFactory::insert
//
// Insert a ciObject into the table at some index.
void ciObjectFactory::insert(int index, ciMetadata* obj, GrowableArray<ciMetadata*>* objects) {
int len = objects->length();
if (len == index) {
objects->append(obj);
} else {
objects->append(objects->at(len-1));
int pos;
for (pos = len-2; pos >= index; pos--) {
objects->at_put(pos+1,objects->at(pos));
}
objects->at_put(index, obj);
}
}
static ciObjectFactory::NonPermObject* emptyBucket = NULL;
// ------------------------------------------------------------------

View File

@ -68,9 +68,7 @@ private:
NonPermObject* _non_perm_bucket[NON_PERM_BUCKETS];
int _non_perm_count;
int find(Metadata* key, GrowableArray<ciMetadata*>* objects);
bool is_found_at(int index, Metadata* key, GrowableArray<ciMetadata*>* objects);
void insert(int index, ciMetadata* obj, GrowableArray<ciMetadata*>* objects);
static int metadata_compare(Metadata* const& key, ciMetadata* const& elt);
ciObject* create_new_object(oop o);
ciMetadata* create_new_metadata(Metadata* o);

View File

@ -88,7 +88,27 @@ MachConstantBaseNode* Compile::mach_constant_base_node() {
// Return the index at which m must be inserted (or already exists).
// The sort order is by the address of the ciMethod, with is_virtual as minor key.
int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual) {
class IntrinsicDescPair {
private:
ciMethod* _m;
bool _is_virtual;
public:
IntrinsicDescPair(ciMethod* m, bool is_virtual) : _m(m), _is_virtual(is_virtual) {}
static int compare(IntrinsicDescPair* const& key, CallGenerator* const& elt) {
ciMethod* m= elt->method();
ciMethod* key_m = key->_m;
if (key_m < m) return -1;
else if (key_m > m) return 1;
else {
bool is_virtual = elt->is_virtual();
bool key_virtual = key->_is_virtual;
if (key_virtual < is_virtual) return -1;
else if (key_virtual > is_virtual) return 1;
else return 0;
}
}
};
int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual, bool& found) {
#ifdef ASSERT
for (int i = 1; i < _intrinsics->length(); i++) {
CallGenerator* cg1 = _intrinsics->at(i-1);
@ -99,63 +119,28 @@ int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual) {
"compiler intrinsics list must stay sorted");
}
#endif
// Binary search sorted list, in decreasing intervals [lo, hi].
int lo = 0, hi = _intrinsics->length()-1;
while (lo <= hi) {
int mid = (uint)(hi + lo) / 2;
ciMethod* mid_m = _intrinsics->at(mid)->method();
if (m < mid_m) {
hi = mid-1;
} else if (m > mid_m) {
lo = mid+1;
} else {
// look at minor sort key
bool mid_virt = _intrinsics->at(mid)->is_virtual();
if (is_virtual < mid_virt) {
hi = mid-1;
} else if (is_virtual > mid_virt) {
lo = mid+1;
} else {
return mid; // exact match
}
}
}
return lo; // inexact match
IntrinsicDescPair pair(m, is_virtual);
return _intrinsics->find_sorted<IntrinsicDescPair*, IntrinsicDescPair::compare>(&pair, found);
}
void Compile::register_intrinsic(CallGenerator* cg) {
if (_intrinsics == NULL) {
_intrinsics = new (comp_arena())GrowableArray<CallGenerator*>(comp_arena(), 60, 0, NULL);
}
// This code is stolen from ciObjectFactory::insert.
// Really, GrowableArray should have methods for
// insert_at, remove_at, and binary_search.
int len = _intrinsics->length();
int index = intrinsic_insertion_index(cg->method(), cg->is_virtual());
if (index == len) {
_intrinsics->append(cg);
} else {
#ifdef ASSERT
CallGenerator* oldcg = _intrinsics->at(index);
assert(oldcg->method() != cg->method() || oldcg->is_virtual() != cg->is_virtual(), "don't register twice");
#endif
_intrinsics->append(_intrinsics->at(len-1));
int pos;
for (pos = len-2; pos >= index; pos--) {
_intrinsics->at_put(pos+1,_intrinsics->at(pos));
}
_intrinsics->at_put(index, cg);
}
bool found = false;
int index = intrinsic_insertion_index(cg->method(), cg->is_virtual(), found);
assert(!found, "registering twice");
_intrinsics->insert_before(index, cg);
assert(find_intrinsic(cg->method(), cg->is_virtual()) == cg, "registration worked");
}
CallGenerator* Compile::find_intrinsic(ciMethod* m, bool is_virtual) {
assert(m->is_loaded(), "don't try this on unloaded methods");
if (_intrinsics != NULL) {
int index = intrinsic_insertion_index(m, is_virtual);
if (index < _intrinsics->length()
&& _intrinsics->at(index)->method() == m
&& _intrinsics->at(index)->is_virtual() == is_virtual) {
bool found = false;
int index = intrinsic_insertion_index(m, is_virtual, found);
if (found) {
return _intrinsics->at(index);
}
}

View File

@ -1250,7 +1250,7 @@ class Compile : public Phase {
// Intrinsic setup.
void register_library_intrinsics(); // initializer
CallGenerator* make_vm_intrinsic(ciMethod* m, bool is_virtual); // constructor
int intrinsic_insertion_index(ciMethod* m, bool is_virtual); // helper
int intrinsic_insertion_index(ciMethod* m, bool is_virtual, bool& found); // helper
CallGenerator* find_intrinsic(ciMethod* m, bool is_virtual); // query fn
void register_intrinsic(CallGenerator* cg); // update fn

View File

@ -396,7 +396,7 @@ template<class E> class GrowableArray : public GenericGrowableArray {
int max = length() - 1;
while (max >= min) {
int mid = (max + min) / 2;
int mid = (int)(((uint)max + min) / 2);
E value = at(mid);
int diff = compare(key, value);
if (diff > 0) {