8192025: Less referential references
authorkbarrett
Thu, 18 Jan 2018 22:17:11 -0500
changeset 49786 7444101401b2
parent 49785 1ea962cb6575
child 49787 99b627637911
8192025: Less referential references Reviewed-by: coleenp, eosterlund, mchung, ahgross, rhalade
src/hotspot/share/classfile/javaClasses.cpp
src/hotspot/share/classfile/javaClasses.hpp
src/hotspot/share/classfile/javaClasses.inline.hpp
src/hotspot/share/classfile/systemDictionary.cpp
src/hotspot/share/classfile/systemDictionary.hpp
src/hotspot/share/classfile/vmSymbols.hpp
src/hotspot/share/oops/klass.cpp
src/hotspot/share/prims/jvm.cpp
--- a/src/hotspot/share/classfile/javaClasses.cpp	Wed Jan 17 22:24:46 2018 -0800
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Thu Jan 18 22:17:11 2018 -0500
@@ -3556,6 +3556,34 @@
   base->long_field_put(static_clock_offset, value);
 }
 
+// Support for java_lang_ref_ReferenceQueue
+
+oop java_lang_ref_ReferenceQueue::NULL_queue() {
+  InstanceKlass* ik = SystemDictionary::ReferenceQueue_klass();
+  oop mirror = ik->java_mirror();
+  return mirror->obj_field(static_NULL_queue_offset);
+}
+
+oop java_lang_ref_ReferenceQueue::ENQUEUED_queue() {
+  InstanceKlass* ik = SystemDictionary::ReferenceQueue_klass();
+  oop mirror = ik->java_mirror();
+  return mirror->obj_field(static_ENQUEUED_queue_offset);
+}
+
+void java_lang_ref_ReferenceQueue::compute_offsets() {
+  InstanceKlass* k = SystemDictionary::ReferenceQueue_klass();
+  compute_offset(static_NULL_queue_offset,
+                 k,
+                 vmSymbols::referencequeue_null_name(),
+                 vmSymbols::referencequeue_signature(),
+                 true /* is_static */);
+  compute_offset(static_ENQUEUED_queue_offset,
+                 k,
+                 vmSymbols::referencequeue_enqueued_name(),
+                 vmSymbols::referencequeue_signature(),
+                 true /* is_static */);
+}
+
 // Support for java_lang_invoke_DirectMethodHandle
 
 int java_lang_invoke_DirectMethodHandle::_member_offset;
@@ -4193,6 +4221,8 @@
 int java_lang_ref_Reference::queue_offset;
 int java_lang_ref_Reference::next_offset;
 int java_lang_ref_Reference::discovered_offset;
+int java_lang_ref_ReferenceQueue::static_NULL_queue_offset;
+int java_lang_ref_ReferenceQueue::static_ENQUEUED_queue_offset;
 int java_lang_ref_SoftReference::timestamp_offset;
 int java_lang_ref_SoftReference::static_clock_offset;
 int java_lang_ClassLoader::parent_offset;
@@ -4437,6 +4467,7 @@
   java_lang_StackTraceElement::compute_offsets();
   java_lang_StackFrameInfo::compute_offsets();
   java_lang_LiveStackFrameInfo::compute_offsets();
+  java_lang_ref_ReferenceQueue::compute_offsets();
 
   // generated interpreter code wants to know about the offsets we just computed:
   AbstractAssembler::update_delayed_values();
--- a/src/hotspot/share/classfile/javaClasses.hpp	Wed Jan 17 22:24:46 2018 -0800
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Thu Jan 18 22:17:11 2018 -0500
@@ -921,6 +921,8 @@
   static inline void set_discovered(oop ref, oop value);
   static inline void set_discovered_raw(oop ref, oop value);
   static inline HeapWord* discovered_addr_raw(oop ref);
+  static inline oop queue(oop ref);
+  static inline void set_queue(oop ref, oop value);
   static bool is_referent_field(oop obj, ptrdiff_t offset);
   static inline bool is_phantom(oop ref);
 };
@@ -944,6 +946,20 @@
   static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 };
 
+// Interface to java.lang.ref.ReferenceQueue objects
+
+class java_lang_ref_ReferenceQueue: public AllStatic {
+public:
+  static int static_NULL_queue_offset;
+  static int static_ENQUEUED_queue_offset;
+
+  // Accessors
+  static oop NULL_queue();
+  static oop ENQUEUED_queue();
+
+  static void compute_offsets();
+};
+
 // Interface to java.lang.invoke.MethodHandle objects
 
 class MethodHandleEntry;
--- a/src/hotspot/share/classfile/javaClasses.inline.hpp	Wed Jan 17 22:24:46 2018 -0800
+++ b/src/hotspot/share/classfile/javaClasses.inline.hpp	Thu Jan 18 22:17:11 2018 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -127,6 +127,12 @@
 HeapWord* java_lang_ref_Reference::discovered_addr_raw(oop ref) {
   return ref->obj_field_addr_raw<HeapWord>(discovered_offset);
 }
+oop java_lang_ref_Reference::queue(oop ref) {
+  return ref->obj_field(queue_offset);
+}
+void java_lang_ref_Reference::set_queue(oop ref, oop value) {
+  return ref->obj_field_put(queue_offset, value);
+}
 bool java_lang_ref_Reference::is_phantom(oop ref) {
   return InstanceKlass::cast(ref->klass())->reference_type() == REF_PHANTOM;
 }
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Wed Jan 17 22:24:46 2018 -0800
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Thu Jan 18 22:17:11 2018 -0500
@@ -2113,6 +2113,8 @@
   InstanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL);
   InstanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM);
 
+  initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(ReferenceQueue_klass), scan, CHECK);
+
   // JSR 292 classes
   WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
   WKID jsr292_group_end   = WK_KLASS_ENUM_NAME(VolatileCallSite_klass);
--- a/src/hotspot/share/classfile/systemDictionary.hpp	Wed Jan 17 22:24:46 2018 -0800
+++ b/src/hotspot/share/classfile/systemDictionary.hpp	Thu Jan 18 22:17:11 2018 -0500
@@ -136,6 +136,7 @@
   do_klass(FinalReference_klass,                        java_lang_ref_FinalReference,              Pre                 ) \
   do_klass(PhantomReference_klass,                      java_lang_ref_PhantomReference,            Pre                 ) \
   do_klass(Finalizer_klass,                             java_lang_ref_Finalizer,                   Pre                 ) \
+  do_klass(ReferenceQueue_klass,                        java_lang_ref_ReferenceQueue,              Pre                 ) \
                                                                                                                          \
   do_klass(Thread_klass,                                java_lang_Thread,                          Pre                 ) \
   do_klass(ThreadGroup_klass,                           java_lang_ThreadGroup,                     Pre                 ) \
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Wed Jan 17 22:24:46 2018 -0800
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Thu Jan 18 22:17:11 2018 -0500
@@ -86,6 +86,7 @@
   template(java_lang_ref_FinalReference,              "java/lang/ref/FinalReference")             \
   template(java_lang_ref_PhantomReference,            "java/lang/ref/PhantomReference")           \
   template(java_lang_ref_Finalizer,                   "java/lang/ref/Finalizer")                  \
+  template(java_lang_ref_ReferenceQueue,              "java/lang/ref/ReferenceQueue")             \
   template(java_lang_reflect_AccessibleObject,        "java/lang/reflect/AccessibleObject")       \
   template(java_lang_reflect_Method,                  "java/lang/reflect/Method")                 \
   template(java_lang_reflect_Constructor,             "java/lang/reflect/Constructor")            \
@@ -438,6 +439,8 @@
   template(module_entry_name,                         "module_entry")                             \
   template(resolved_references_name,                  "<resolved_references>")                    \
   template(init_lock_name,                            "<init_lock>")                              \
+  template(referencequeue_null_name,                  "NULL")                                     \
+  template(referencequeue_enqueued_name,              "ENQUEUED")                                 \
                                                                                                   \
   /* name symbols needed by intrinsics */                                                         \
   VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, template, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \
@@ -531,6 +534,7 @@
   template(string_signature,                          "Ljava/lang/String;")                                       \
   template(string_array_signature,                    "[Ljava/lang/String;")                                      \
   template(reference_signature,                       "Ljava/lang/ref/Reference;")                                \
+  template(referencequeue_signature,                  "Ljava/lang/ref/ReferenceQueue;")                           \
   template(sun_misc_Cleaner_signature,                "Lsun/misc/Cleaner;")                                       \
   template(executable_signature,                      "Ljava/lang/reflect/Executable;")                           \
   template(module_signature,                          "Ljava/lang/Module;")                                       \
--- a/src/hotspot/share/oops/klass.cpp	Wed Jan 17 22:24:46 2018 -0800
+++ b/src/hotspot/share/oops/klass.cpp	Thu Jan 18 22:17:11 2018 -0500
@@ -62,11 +62,13 @@
 }
 
 void Klass::set_is_cloneable() {
-  if (name() != vmSymbols::java_lang_invoke_MemberName()) {
-    _access_flags.set_is_cloneable_fast();
-  } else {
+  if (name() == vmSymbols::java_lang_invoke_MemberName()) {
     assert(is_final(), "no subclasses allowed");
     // MemberName cloning should not be intrinsified and always happen in JVM_Clone.
+  } else if (is_instance_klass() && InstanceKlass::cast(this)->reference_type() != REF_NONE) {
+    // Reference cloning should not be intrinsified and always happen in JVM_Clone.
+  } else {
+    _access_flags.set_is_cloneable_fast();
   }
 }
 
--- a/src/hotspot/share/prims/jvm.cpp	Wed Jan 17 22:24:46 2018 -0800
+++ b/src/hotspot/share/prims/jvm.cpp	Thu Jan 18 22:17:11 2018 -0500
@@ -38,6 +38,7 @@
 #include "gc/shared/collectedHeap.inline.hpp"
 #include "interpreter/bytecode.hpp"
 #include "memory/oopFactory.hpp"
+#include "memory/referenceType.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
 #include "oops/access.inline.hpp"
@@ -629,6 +630,35 @@
 JVM_END
 
 
+template<DecoratorSet decorators>
+static void fixup_clone_referent(oop src, oop new_obj) {
+  typedef HeapAccess<decorators> RefAccess;
+  const int ref_offset = java_lang_ref_Reference::referent_offset;
+  oop referent = RefAccess::oop_load_at(src, ref_offset);
+  RefAccess::oop_store_at(new_obj, ref_offset, referent);
+}
+
+static void fixup_cloned_reference(ReferenceType ref_type, oop src, oop clone) {
+  // Kludge: After unbarriered clone, re-copy the referent with
+  // correct barriers. This works for current collectors, but won't
+  // work for ZGC and maybe other future collectors or variants of
+  // existing ones (like G1 with concurrent reference processing).
+  if (ref_type == REF_PHANTOM) {
+    fixup_clone_referent<ON_PHANTOM_OOP_REF>(src, clone);
+  } else {
+    fixup_clone_referent<ON_WEAK_OOP_REF>(src, clone);
+  }
+  if ((java_lang_ref_Reference::next(clone) != NULL) ||
+      (java_lang_ref_Reference::queue(clone) == java_lang_ref_ReferenceQueue::ENQUEUED_queue())) {
+    // If the source has been enqueued or is being enqueued, don't
+    // register the clone with a queue.
+    java_lang_ref_Reference::set_queue(clone, java_lang_ref_ReferenceQueue::NULL_queue());
+  }
+  // discovered and next are list links; the clone is not in those lists.
+  java_lang_ref_Reference::set_discovered(clone, NULL);
+  java_lang_ref_Reference::set_next(clone, NULL);
+}
+
 JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
   JVMWrapper("JVM_Clone");
   Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
@@ -654,17 +684,28 @@
   }
 
   // Make shallow object copy
+  ReferenceType ref_type = REF_NONE;
   const int size = obj->size();
   oop new_obj_oop = NULL;
   if (obj->is_array()) {
     const int length = ((arrayOop)obj())->length();
     new_obj_oop = CollectedHeap::array_allocate(klass, size, length, CHECK_NULL);
   } else {
+    ref_type = InstanceKlass::cast(klass)->reference_type();
+    assert((ref_type == REF_NONE) ==
+           !klass->is_subclass_of(SystemDictionary::Reference_klass()),
+           "invariant");
     new_obj_oop = CollectedHeap::obj_allocate(klass, size, CHECK_NULL);
   }
 
   HeapAccess<>::clone(obj(), new_obj_oop, size);
 
+  // If cloning a Reference, set Reference fields to a safe state.
+  // Fixup must be completed before any safepoint.
+  if (ref_type != REF_NONE) {
+    fixup_cloned_reference(ref_type, obj(), new_obj_oop);
+  }
+
   Handle new_obj(THREAD, new_obj_oop);
   // Caution: this involves a java upcall, so the clone should be
   // "gc-robust" by this stage.