8007986: GrowableArray should implement binary search
Summary: binary search method for GrowableArray
Reviewed-by: vlivanov, jrose
--- a/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp Tue Feb 23 17:55:20 2016 +0300
+++ b/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp Tue Feb 23 17:59:27 2016 +0100
@@ -41,15 +41,21 @@
_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;
}
@@ -57,42 +63,15 @@
}
// ------------------------------------------------------------------
-// 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);
}
// ------------------------------------------------------------------
--- a/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp Tue Feb 23 17:55:20 2016 +0300
+++ b/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp Tue Feb 23 17:59:27 2016 +0100
@@ -38,7 +38,7 @@
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);
--- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp Tue Feb 23 17:55:20 2016 +0300
+++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp Tue Feb 23 17:59:27 2016 +0100
@@ -260,6 +260,13 @@
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 @@
}
#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 @@
}
}
#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 @@
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 @@
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;
// ------------------------------------------------------------------
--- a/hotspot/src/share/vm/ci/ciObjectFactory.hpp Tue Feb 23 17:55:20 2016 +0300
+++ b/hotspot/src/share/vm/ci/ciObjectFactory.hpp Tue Feb 23 17:59:27 2016 +0100
@@ -68,9 +68,7 @@
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);
--- a/hotspot/src/share/vm/opto/compile.cpp Tue Feb 23 17:55:20 2016 +0300
+++ b/hotspot/src/share/vm/opto/compile.cpp Tue Feb 23 17:59:27 2016 +0100
@@ -88,7 +88,27 @@
// 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 @@
"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);
}
}
--- a/hotspot/src/share/vm/opto/compile.hpp Tue Feb 23 17:55:20 2016 +0300
+++ b/hotspot/src/share/vm/opto/compile.hpp Tue Feb 23 17:59:27 2016 +0100
@@ -1250,7 +1250,7 @@
// 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
--- a/hotspot/src/share/vm/utilities/growableArray.hpp Tue Feb 23 17:55:20 2016 +0300
+++ b/hotspot/src/share/vm/utilities/growableArray.hpp Tue Feb 23 17:59:27 2016 +0100
@@ -396,7 +396,7 @@
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) {