changeset 17375:44b83285b645

Deduplicate constant oops during code installation
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Wed, 08 Oct 2014 11:50:00 -0700
parents 9928ad27a80e
children b888ded3ee42
files src/share/vm/code/oopRecorder.cpp src/share/vm/code/oopRecorder.hpp src/share/vm/graal/graalCodeInstaller.cpp src/share/vm/utilities/growableArray.hpp
diffstat 4 files changed, 138 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- 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<Metadata*>;
 template class ValueRecorder<jobject>;
+
+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<oop, sort_oop_by_address>(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();
+}
+
--- 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<ObjectEntry> _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<jobject>      _oops;
   ValueRecorder<Metadata*>    _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;
   }
--- 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()) {
--- 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 <int compare(E, E)> E find_insert_binary(E key) {
+    bool found;
+    int location = find_binary<E, compare>(key, found);
+    if (!found) {
+      assert(location <= length(), "out of range");
+      insert_binary(location, key);
+    }
+    return at(location);
+  }
+
+  template <typename K, int compare(K, E)> 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).