# HG changeset patch # User Tom Rodriguez # Date 1412794200 25200 # Node ID 44b83285b64534af9df97df6bc123d17eae482d0 # Parent 9928ad27a80e00fc2b30d3b23a15e08f74eff370 Deduplicate constant oops during code installation diff -r 9928ad27a80e -r 44b83285b645 src/share/vm/code/oopRecorder.cpp --- a/src/share/vm/code/oopRecorder.cpp Wed Oct 08 11:48:00 2014 -0700 +++ b/src/share/vm/code/oopRecorder.cpp Wed Oct 08 11:50:00 2014 -0700 @@ -165,3 +165,49 @@ // Explicitly instantiate these types template class ValueRecorder; template class ValueRecorder; + +oop ObjectLookup::ObjectEntry::oop_value() { return JNIHandles::resolve(_value); } + +ObjectLookup::ObjectLookup(): _gc_count(Universe::heap()->total_collections()), _values(4) {} + +void ObjectLookup::maybe_resort() { + // The values are kept sorted by address which may be invalidated + // after a GC, so resort if a GC has occurred since last time. + if (_gc_count != Universe::heap()->total_collections()) { + _gc_count = Universe::heap()->total_collections(); + _values.sort(sort_by_address); + } +} + +int ObjectLookup::sort_by_address(oop a, oop b) { + if (b > a) return 1; + if (a > b) return -1; + return 0; +} + +int ObjectLookup::sort_by_address(ObjectEntry* a, ObjectEntry* b) { + return sort_by_address(a->oop_value(), b->oop_value()); +} + +int ObjectLookup::sort_oop_by_address(oop a, ObjectEntry b) { + return sort_by_address(a, b.oop_value()); +} + +int ObjectLookup::find_index(jobject handle, OopRecorder* oop_recorder) { + if (handle == NULL) { + return 0; + } + oop object = JNIHandles::resolve(handle); + maybe_resort(); + bool found; + int location = _values.find_binary(object, found); + if (!found) { + assert(location <= _values.length(), "out of range"); + jobject handle = JNIHandles::make_local(object); + ObjectEntry r(handle, oop_recorder->allocate_oop_index(handle)); + _values.insert_binary(location, r); + return r.index(); + } + return _values.at(location).index(); +} + diff -r 9928ad27a80e -r 44b83285b645 src/share/vm/code/oopRecorder.hpp --- a/src/share/vm/code/oopRecorder.hpp Wed Oct 08 11:48:00 2014 -0700 +++ b/src/share/vm/code/oopRecorder.hpp Wed Oct 08 11:50:00 2014 -0700 @@ -146,12 +146,51 @@ #endif }; +class OopRecorder; + +class ObjectLookup : public ResourceObj { + private: + class ObjectEntry { + private: + jobject _value; + int _index; + + public: + ObjectEntry(jobject value, int index): _value(value), _index(index) {} + ObjectEntry() {} + oop oop_value(); // { return JNIHandles::resolve(_value); } + int index() { return _index; } + }; + + GrowableArray _values; + unsigned int _gc_count; + + // Utility sort functions + static int sort_by_address(oop a, oop b); + static int sort_by_address(ObjectEntry* a, ObjectEntry* b); + static int sort_oop_by_address(oop a, ObjectEntry b); + + public: + ObjectLookup(); + + // Resort list if a GC has occurred since the last sort + void maybe_resort(); + int find_index(jobject object, OopRecorder* oop_recorder); +}; + class OopRecorder : public ResourceObj { private: ValueRecorder _oops; ValueRecorder _metadata; + ObjectLookup* _object_lookup; public: - OopRecorder(Arena* arena = NULL): _oops(arena), _metadata(arena) {} + OopRecorder(Arena* arena = NULL, bool deduplicate = false): _oops(arena), _metadata(arena) { + if (deduplicate) { + _object_lookup = new ObjectLookup(); + } else { + _object_lookup = NULL; + } + } void check_for_duplicates(int index, jobject h) NOT_DEBUG_RETURN; @@ -159,7 +198,7 @@ return _oops.allocate_index(h); } int find_index(jobject h) { - int result = _oops.find_index(h); + int result = _object_lookup != NULL ? _object_lookup->find_index(h, this) : _oops.find_index(h); check_for_duplicates(result, h); return result; } diff -r 9928ad27a80e -r 44b83285b645 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Wed Oct 08 11:48:00 2014 -0700 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Wed Oct 08 11:50:00 2014 -0700 @@ -370,7 +370,7 @@ } void CodeInstaller::initialize_assumptions(oop compiled_code) { - _oop_recorder = new OopRecorder(&_arena); + _oop_recorder = new OopRecorder(&_arena, true); _dependencies = new Dependencies(&_arena, _oop_recorder); Handle assumptions_handle = CompilationResult::assumptions(HotSpotCompiledCode::comp(compiled_code)); if (!assumptions_handle.is_null()) { diff -r 9928ad27a80e -r 44b83285b645 src/share/vm/utilities/growableArray.hpp --- a/src/share/vm/utilities/growableArray.hpp Wed Oct 08 11:48:00 2014 -0700 +++ b/src/share/vm/utilities/growableArray.hpp Wed Oct 08 11:50:00 2014 -0700 @@ -360,6 +360,56 @@ void sort(int f(E*,E*), int stride) { qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f); } + + // Binary search and insertion utility. Search array for element + // matching key according to the static compare function. Insert + // that element is not already in the list. Assumes the list is + // already sorted according to compare function. + template E find_insert_binary(E key) { + bool found; + int location = find_binary(key, found); + if (!found) { + assert(location <= length(), "out of range"); + insert_binary(location, key); + } + return at(location); + } + + template int find_binary(K key, bool& found) { + found = false; + int min = 0; + int max = length() - 1; + + while (max >= min) { + int mid = (max + min) / 2; + E value = at(mid); + int diff = compare(key, value); + if (diff > 0) { + min = mid + 1; + } else if (diff < 0) { + max = mid - 1; + } else { + found = true; + return mid; + } + } + return min; + } + + // Insert a new element at location, moving values as needed. + void insert_binary(int location, E element) { + int len = length(); + if (len == location) { + append(element); + } else { + append(at(len-1)); + int pos; + for (pos = len-2; pos >= location; pos--) { + at_put(pos+1, at(pos)); + } + at_put(location, element); + } + } }; // Global GrowableArray methods (one instance in the library per each 'E' type).