changeset 7527:69b4f6a4044a

Merge
author jwilhelm
date Mon, 08 Dec 2014 18:52:03 +0100
parents e2457e3f8c0e b1e0ed4ff875
children 3bc090d366bf
files src/share/vm/memory/cardTableModRefBS.cpp
diffstat 8 files changed, 237 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/classfile/classFileParser.cpp	Fri Dec 05 16:36:07 2014 -0800
+++ b/src/share/vm/classfile/classFileParser.cpp	Mon Dec 08 18:52:03 2014 +0100
@@ -3108,21 +3108,39 @@
   }
 }
 
-// Transfer ownership of metadata allocated to the InstanceKlass.
-void ClassFileParser::apply_parsed_class_metadata(
-                                            instanceKlassHandle this_klass,
-                                            int java_fields_count, TRAPS) {
-  // Assign annotations if needed
-  if (_annotations != NULL || _type_annotations != NULL ||
-      _fields_annotations != NULL || _fields_type_annotations != NULL) {
+// Create the Annotations object that will
+// hold the annotations array for the Klass.
+void ClassFileParser::create_combined_annotations(TRAPS) {
+    if (_annotations == NULL &&
+        _type_annotations == NULL &&
+        _fields_annotations == NULL &&
+        _fields_type_annotations == NULL) {
+      // Don't create the Annotations object unnecessarily.
+      return;
+    }
+
     Annotations* annotations = Annotations::allocate(_loader_data, CHECK);
     annotations->set_class_annotations(_annotations);
     annotations->set_class_type_annotations(_type_annotations);
     annotations->set_fields_annotations(_fields_annotations);
     annotations->set_fields_type_annotations(_fields_type_annotations);
-    this_klass->set_annotations(annotations);
-  }
-
+
+    // This is the Annotations object that will be
+    // assigned to InstanceKlass being constructed.
+    _combined_annotations = annotations;
+
+    // The annotations arrays below has been transfered the
+    // _combined_annotations so these fields can now be cleared.
+    _annotations             = NULL;
+    _type_annotations        = NULL;
+    _fields_annotations      = NULL;
+    _fields_type_annotations = NULL;
+}
+
+// Transfer ownership of metadata allocated to the InstanceKlass.
+void ClassFileParser::apply_parsed_class_metadata(
+                                            instanceKlassHandle this_klass,
+                                            int java_fields_count, TRAPS) {
   _cp->set_pool_holder(this_klass());
   this_klass->set_constants(_cp);
   this_klass->set_fields(_fields, java_fields_count);
@@ -3130,6 +3148,7 @@
   this_klass->set_inner_classes(_inner_classes);
   this_klass->set_local_interfaces(_local_interfaces);
   this_klass->set_transitive_interfaces(_transitive_interfaces);
+  this_klass->set_annotations(_combined_annotations);
 
   // Clear out these fields so they don't get deallocated by the destructor
   clear_class_metadata();
@@ -4002,6 +4021,10 @@
     ClassAnnotationCollector parsed_annotations;
     parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle));
 
+    // Finalize the Annotations metadata object,
+    // now that all annotation arrays have been created.
+    create_combined_annotations(CHECK_(nullHandle));
+
     // Make sure this is the end of class file stream
     guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle));
 
@@ -4302,10 +4325,27 @@
   InstanceKlass::deallocate_interfaces(_loader_data, _super_klass(),
                                        _local_interfaces, _transitive_interfaces);
 
-  MetadataFactory::free_array<u1>(_loader_data, _annotations);
-  MetadataFactory::free_array<u1>(_loader_data, _type_annotations);
-  Annotations::free_contents(_loader_data, _fields_annotations);
-  Annotations::free_contents(_loader_data, _fields_type_annotations);
+  if (_combined_annotations != NULL) {
+    // After all annotations arrays have been created, they are installed into the
+    // Annotations object that will be assigned to the InstanceKlass being created.
+
+    // Deallocate the Annotations object and the installed annotations arrays.
+    _combined_annotations->deallocate_contents(_loader_data);
+
+    // If the _combined_annotations pointer is non-NULL,
+    // then the other annotations fields should have been cleared.
+    assert(_annotations             == NULL, "Should have been cleared");
+    assert(_type_annotations        == NULL, "Should have been cleared");
+    assert(_fields_annotations      == NULL, "Should have been cleared");
+    assert(_fields_type_annotations == NULL, "Should have been cleared");
+  } else {
+    // If the annotations arrays were not installed into the Annotations object,
+    // then they have to be deallocated explicitly.
+    MetadataFactory::free_array<u1>(_loader_data, _annotations);
+    MetadataFactory::free_array<u1>(_loader_data, _type_annotations);
+    Annotations::free_contents(_loader_data, _fields_annotations);
+    Annotations::free_contents(_loader_data, _fields_type_annotations);
+  }
 
   clear_class_metadata();
 
--- a/src/share/vm/classfile/classFileParser.hpp	Fri Dec 05 16:36:07 2014 -0800
+++ b/src/share/vm/classfile/classFileParser.hpp	Mon Dec 08 18:52:03 2014 +0100
@@ -75,6 +75,7 @@
   Array<u2>*       _inner_classes;
   Array<Klass*>*   _local_interfaces;
   Array<Klass*>*   _transitive_interfaces;
+  Annotations*     _combined_annotations;
   AnnotationArray* _annotations;
   AnnotationArray* _type_annotations;
   Array<AnnotationArray*>* _fields_annotations;
@@ -86,6 +87,8 @@
   void set_class_generic_signature_index(u2 x) { _generic_signature_index = x; }
   void set_class_sde_buffer(char* x, int len)  { _sde_buffer = x; _sde_length = len; }
 
+  void create_combined_annotations(TRAPS);
+
   void init_parsed_class_attributes(ClassLoaderData* loader_data) {
     _loader_data = loader_data;
     _synthetic_flag = false;
@@ -110,6 +113,7 @@
     _inner_classes = NULL;
     _local_interfaces = NULL;
     _transitive_interfaces = NULL;
+    _combined_annotations = NULL;
     _annotations = _type_annotations = NULL;
     _fields_annotations = _fields_type_annotations = NULL;
   }
--- a/src/share/vm/gc_implementation/shared/gcTrace.cpp	Fri Dec 05 16:36:07 2014 -0800
+++ b/src/share/vm/gc_implementation/shared/gcTrace.cpp	Mon Dec 08 18:52:03 2014 +0100
@@ -172,6 +172,27 @@
   _tenuring_threshold = tenuring_threshold;
 }
 
+bool YoungGCTracer::should_report_promotion_in_new_plab_event() const {
+  return should_send_promotion_in_new_plab_event();
+}
+
+bool YoungGCTracer::should_report_promotion_outside_plab_event() const {
+  return should_send_promotion_outside_plab_event();
+}
+
+void YoungGCTracer::report_promotion_in_new_plab_event(Klass* klass, size_t obj_size,
+                                                       uint age, bool tenured,
+                                                       size_t plab_size) const {
+  assert_set_gc_id();
+  send_promotion_in_new_plab_event(klass, obj_size, age, tenured, plab_size);
+}
+
+void YoungGCTracer::report_promotion_outside_plab_event(Klass* klass, size_t obj_size,
+                                                        uint age, bool tenured) const {
+  assert_set_gc_id();
+  send_promotion_outside_plab_event(klass, obj_size, age, tenured);
+}
+
 void OldGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) {
   assert_set_gc_id();
 
--- a/src/share/vm/gc_implementation/shared/gcTrace.hpp	Fri Dec 05 16:36:07 2014 -0800
+++ b/src/share/vm/gc_implementation/shared/gcTrace.hpp	Mon Dec 08 18:52:03 2014 +0100
@@ -156,9 +156,38 @@
   void report_promotion_failed(const PromotionFailedInfo& pf_info);
   void report_tenuring_threshold(const uint tenuring_threshold);
 
+  /*
+   * Methods for reporting Promotion in new or outside PLAB Events.
+   *
+   * The object age is always required as it is not certain that the mark word
+   * of the oop can be trusted at this stage.
+   *
+   * obj_size is the size of the promoted object in bytes.
+   *
+   * tenured should be true if the object has been promoted to the old
+   * space during this GC, if the object is copied to survivor space
+   * from young space or survivor space (aging) tenured should be false.
+   *
+   * plab_size is the size of the newly allocated PLAB in bytes.
+   */
+  bool should_report_promotion_in_new_plab_event() const;
+  bool should_report_promotion_outside_plab_event() const;
+  void report_promotion_in_new_plab_event(Klass* klass, size_t obj_size,
+                                          uint age, bool tenured,
+                                          size_t plab_size) const;
+  void report_promotion_outside_plab_event(Klass* klass, size_t obj_size,
+                                           uint age, bool tenured) const;
+
  private:
   void send_young_gc_event() const;
   void send_promotion_failed_event(const PromotionFailedInfo& pf_info) const;
+  bool should_send_promotion_in_new_plab_event() const;
+  bool should_send_promotion_outside_plab_event() const;
+  void send_promotion_in_new_plab_event(Klass* klass, size_t obj_size,
+                                        uint age, bool tenured,
+                                        size_t plab_size) const;
+  void send_promotion_outside_plab_event(Klass* klass, size_t obj_size,
+                                         uint age, bool tenured) const;
 };
 
 class OldGCTracer : public GCTracer {
--- a/src/share/vm/gc_implementation/shared/gcTraceSend.cpp	Fri Dec 05 16:36:07 2014 -0800
+++ b/src/share/vm/gc_implementation/shared/gcTraceSend.cpp	Mon Dec 08 18:52:03 2014 +0100
@@ -111,6 +111,44 @@
   }
 }
 
+bool YoungGCTracer::should_send_promotion_in_new_plab_event() const {
+  return EventPromoteObjectInNewPLAB::is_enabled();
+}
+
+bool YoungGCTracer::should_send_promotion_outside_plab_event() const {
+  return EventPromoteObjectOutsidePLAB::is_enabled();
+}
+
+void YoungGCTracer::send_promotion_in_new_plab_event(Klass* klass, size_t obj_size,
+                                                     uint age, bool tenured,
+                                                     size_t plab_size) const {
+
+  EventPromoteObjectInNewPLAB event;
+  if (event.should_commit()) {
+    event.set_gcId(_shared_gc_info.gc_id().id());
+    event.set_class(klass);
+    event.set_objectSize(obj_size);
+    event.set_tenured(tenured);
+    event.set_tenuringAge(age);
+    event.set_plabSize(plab_size);
+    event.commit();
+  }
+}
+
+void YoungGCTracer::send_promotion_outside_plab_event(Klass* klass, size_t obj_size,
+                                                      uint age, bool tenured) const {
+
+  EventPromoteObjectOutsidePLAB event;
+  if (event.should_commit()) {
+    event.set_gcId(_shared_gc_info.gc_id().id());
+    event.set_class(klass);
+    event.set_objectSize(obj_size);
+    event.set_tenured(tenured);
+    event.set_tenuringAge(age);
+    event.commit();
+  }
+}
+
 void OldGCTracer::send_old_gc_event() const {
   EventGCOldGarbageCollection e(UNTIMED);
   if (e.should_commit()) {
--- a/src/share/vm/memory/cardTableModRefBS.cpp	Fri Dec 05 16:36:07 2014 -0800
+++ b/src/share/vm/memory/cardTableModRefBS.cpp	Mon Dec 08 18:52:03 2014 +0100
@@ -275,29 +275,26 @@
     // the new_end_aligned does not intrude onto the committed
     // space of another region.
     int ri = 0;
-    for (ri = 0; ri < _cur_covered_regions; ri++) {
-      if (ri != ind) {
-        if (_committed[ri].contains(new_end_aligned)) {
-          // The prior check included in the assert
-          // (new_end_aligned >= _committed[ri].start())
-          // is redundant with the "contains" test.
-          // Any region containing the new end
-          // should start at or beyond the region found (ind)
-          // for the new end (committed regions are not expected to
-          // be proper subsets of other committed regions).
-          assert(_committed[ri].start() >= _committed[ind].start(),
-                 "New end of committed region is inconsistent");
-          new_end_aligned = _committed[ri].start();
-          // new_end_aligned can be equal to the start of its
-          // committed region (i.e., of "ind") if a second
-          // region following "ind" also start at the same location
-          // as "ind".
-          assert(new_end_aligned >= _committed[ind].start(),
-            "New end of committed region is before start");
-          debug_only(collided = true;)
-          // Should only collide with 1 region
-          break;
-        }
+    for (ri = ind + 1; ri < _cur_covered_regions; ri++) {
+      if (new_end_aligned > _committed[ri].start()) {
+        assert(new_end_aligned <= _committed[ri].end(),
+               "An earlier committed region can't cover a later committed region");
+        // Any region containing the new end
+        // should start at or beyond the region found (ind)
+        // for the new end (committed regions are not expected to
+        // be proper subsets of other committed regions).
+        assert(_committed[ri].start() >= _committed[ind].start(),
+               "New end of committed region is inconsistent");
+        new_end_aligned = _committed[ri].start();
+        // new_end_aligned can be equal to the start of its
+        // committed region (i.e., of "ind") if a second
+        // region following "ind" also start at the same location
+        // as "ind".
+        assert(new_end_aligned >= _committed[ind].start(),
+          "New end of committed region is before start");
+        debug_only(collided = true;)
+        // Should only collide with 1 region
+        break;
       }
     }
 #ifdef ASSERT
--- a/src/share/vm/trace/trace.xml	Fri Dec 05 16:36:07 2014 -0800
+++ b/src/share/vm/trace/trace.xml	Mon Dec 08 18:52:03 2014 +0100
@@ -314,6 +314,28 @@
       <value type="BYTES64" field="totalSize" label="Total Size" />
     </event>
 
+    <!-- Promotion events, Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. -->
+    <event id="PromoteObjectInNewPLAB" path="vm/gc/detailed/object_promotion_in_new_PLAB" label="Promotion in new PLAB"
+        description="Object survived scavenge and was copied to a new Promotion Local Allocation Buffer (PLAB). Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects." 
+           has_thread="true" has_stacktrace="false" is_instant="true">
+      <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" description="ID of GC during which the object was promoted"/>
+      <value type="CLASS" field="class" label="Class" description="Class of promoted object"/>
+      <value type="BYTES64" field="objectSize" label="Object Size" description="Size of promoted object"/>
+      <value type="UINT" field="tenuringAge" label="Object Tenuring Age" description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0."/>
+      <value type="BOOLEAN" field="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space"/>
+      <value type="BYTES64" field="plabSize" label="PLAB Size" description="Size of the allocated PLAB to which the object was copied"/>
+    </event>
+    
+    <event id="PromoteObjectOutsidePLAB" path="vm/gc/detailed/object_promotion_outside_PLAB" label="Promotion outside PLAB"
+        description="Object survived scavenge and was copied directly to the heap. Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects." 
+           has_thread="true" has_stacktrace="false" is_instant="true">
+      <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" description="ID of GC during which the object was promoted"/>
+      <value type="CLASS" field="class" label="Class" description="Class of promoted object"/>
+      <value type="BYTES64" field="objectSize" label="Object Size" description="Size of promoted object"/>
+      <value type="UINT" field="tenuringAge" label="Object Tenuring Age" description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0."/>
+      <value type="BOOLEAN" field="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space"/>
+    </event>
+
     <event id="PromotionFailed" path="vm/gc/detailed/promotion_failed" label="Promotion Failed" is_instant="true"
            description="Promotion of an object failed">
       <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/gc/TestCardTablePageCommits.java	Mon Dec 08 18:52:03 2014 +0100
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2014, 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
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*/
+
+import com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.ProcessTools;
+import com.oracle.java.testlibrary.Platform;
+
+/*
+ * @test TestCardTablePageCommits
+ * @key gc
+ * @bug 8059066
+ * @summary Tests that the card table does not commit the same page twice
+ * @library /testlibrary
+ * @run driver TestCardTablePageCommits
+ */
+public class TestCardTablePageCommits {
+    public static void main(String args[]) throws Exception {
+        // The test is run with a small heap to make sure all pages in the card
+        // table gets committed. Need 8 MB heap to trigger the bug on SPARC
+        // because of 8kB pages, assume 4 KB pages for all other CPUs.
+        String Xmx = Platform.isSparc() ? "-Xmx8m" : "-Xmx4m";
+
+        String[] opts = {Xmx, "-XX:NativeMemoryTracking=detail", "-XX:+UseParallelGC", "-version"};
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(opts);
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldHaveExitValue(0);
+    }
+}