Merge
authorjwilhelm
Tue, 08 Sep 2015 16:10:37 +0200
changeset 32734 7029a3eb3008
parent 32467 23b29549f8d1 (diff)
parent 32626 5d1d9327219c (current diff)
child 32735 c6063d028c3c
Merge
hotspot/src/share/vm/classfile/imageDecompressor.cpp
hotspot/src/share/vm/classfile/imageDecompressor.hpp
hotspot/src/share/vm/classfile/imageFile.cpp
hotspot/src/share/vm/classfile/imageFile.hpp
hotspot/src/share/vm/utilities/endian.cpp
hotspot/src/share/vm/utilities/endian.hpp
hotspot/test/runtime/modules/ImageFile/ImageAttributeOffsetsTest.java
hotspot/test/runtime/modules/ImageFile/ImageCloseTest.java
hotspot/test/runtime/modules/ImageFile/ImageFileHeaderTest.java
hotspot/test/runtime/modules/ImageFile/ImageFindAttributesTest.java
hotspot/test/runtime/modules/ImageFile/ImageGetAttributesTest.java
hotspot/test/runtime/modules/ImageFile/ImageGetDataAddressTest.java
hotspot/test/runtime/modules/ImageFile/ImageGetIndexAddressTest.java
hotspot/test/runtime/modules/ImageFile/ImageGetStringBytesTest.java
hotspot/test/runtime/modules/ImageFile/ImageOpenTest.java
hotspot/test/runtime/modules/ImageFile/ImageReadTest.java
hotspot/test/runtime/modules/ImageFile/LocationConstants.java
--- a/hotspot/src/share/vm/code/codeCache.cpp	Mon Sep 07 20:03:56 2015 +0200
+++ b/hotspot/src/share/vm/code/codeCache.cpp	Tue Sep 08 16:10:37 2015 +0200
@@ -745,13 +745,12 @@
 
 void CodeCache::gc_epilogue() {
   assert_locked_or_safepoint(CodeCache_lock);
-  NMethodIterator iter;
-  while(iter.next()) {
-    nmethod* nm = iter.method();
-    if (!nm->is_zombie()) {
-      if (needs_cache_clean()) {
-        // Clean ICs of unloaded nmethods as well because they may reference other
-        // unloaded nmethods that may be flushed earlier in the sweeper cycle.
+  NOT_DEBUG(if (needs_cache_clean())) {
+    NMethodIterator iter;
+    while(iter.next_alive()) {
+      nmethod* nm = iter.method();
+      assert(!nm->is_unloaded(), "Tautology");
+      DEBUG_ONLY(if (needs_cache_clean())) {
         nm->cleanup_inline_caches();
       }
       DEBUG_ONLY(nm->verify());
--- a/hotspot/src/share/vm/code/compiledIC.cpp	Mon Sep 07 20:03:56 2015 +0200
+++ b/hotspot/src/share/vm/code/compiledIC.cpp	Tue Sep 08 16:10:37 2015 +0200
@@ -287,6 +287,7 @@
   assert( is_c1_method ||
          !is_monomorphic ||
          is_optimized() ||
+         !caller->is_alive() ||
          (cached_metadata() != NULL && cached_metadata()->is_klass()), "sanity check");
 #endif // ASSERT
   return is_monomorphic;
@@ -321,7 +322,7 @@
 }
 
 
-void CompiledIC::set_to_clean() {
+void CompiledIC::set_to_clean(bool in_use) {
   assert(SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->is_locked() , "MT-unsafe call");
   if (TraceInlineCacheClearing || TraceICs) {
     tty->print_cr("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address()));
@@ -337,7 +338,7 @@
 
   // A zombie transition will always be safe, since the metadata has already been set to NULL, so
   // we only need to patch the destination
-  bool safe_transition = is_optimized() || SafepointSynchronize::is_at_safepoint();
+  bool safe_transition = !in_use || is_optimized() || SafepointSynchronize::is_at_safepoint();
 
   if (safe_transition) {
     // Kill any leftover stub we might have too
--- a/hotspot/src/share/vm/code/compiledIC.hpp	Mon Sep 07 20:03:56 2015 +0200
+++ b/hotspot/src/share/vm/code/compiledIC.hpp	Tue Sep 08 16:10:37 2015 +0200
@@ -214,7 +214,7 @@
   //
   // They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full.
   //
-  void set_to_clean();
+  void set_to_clean(bool in_use = true);
   void set_to_monomorphic(CompiledICInfo& info);
   void clear_ic_stub();
 
--- a/hotspot/src/share/vm/code/nmethod.cpp	Mon Sep 07 20:03:56 2015 +0200
+++ b/hotspot/src/share/vm/code/nmethod.cpp	Tue Sep 08 16:10:37 2015 +0200
@@ -1050,7 +1050,7 @@
         if( cb != NULL && cb->is_nmethod() ) {
           nmethod* nm = (nmethod*)cb;
           // Clean inline caches pointing to zombie, non-entrant and unloaded methods
-          if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean();
+          if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(is_alive());
         }
         break;
       }
@@ -1150,7 +1150,7 @@
 // Tell if a non-entrant method can be converted to a zombie (i.e.,
 // there are no activations on the stack, not in use by the VM,
 // and not in use by the ServiceThread)
-bool nmethod::can_not_entrant_be_converted() {
+bool nmethod::can_convert_to_zombie() {
   assert(is_not_entrant(), "must be a non-entrant method");
 
   // Since the nmethod sweeper only does partial sweep the sweeper's traversal
--- a/hotspot/src/share/vm/code/nmethod.hpp	Mon Sep 07 20:03:56 2015 +0200
+++ b/hotspot/src/share/vm/code/nmethod.hpp	Tue Sep 08 16:10:37 2015 +0200
@@ -577,7 +577,7 @@
 
   // See comment at definition of _last_seen_on_stack
   void mark_as_seen_on_stack();
-  bool can_not_entrant_be_converted();
+  bool can_convert_to_zombie();
 
   // Evolution support. We make old (discarded) compiled methods point to new Method*s.
   void set_method(Method* method) { _method = method; }
--- a/hotspot/src/share/vm/opto/loopopts.cpp	Mon Sep 07 20:03:56 2015 +0200
+++ b/hotspot/src/share/vm/opto/loopopts.cpp	Tue Sep 08 16:10:37 2015 +0200
@@ -673,8 +673,7 @@
 Node* PhaseIdealLoop::try_move_store_before_loop(Node* n, Node *n_ctrl) {
   // Store has to be first in the loop body
   IdealLoopTree *n_loop = get_loop(n_ctrl);
-  if (n->is_Store() && n_loop != _ltree_root && n_loop->is_loop()) {
-    assert(n->in(0), "store should have control set");
+  if (n->is_Store() && n_loop != _ltree_root && n_loop->is_loop() && n->in(0) != NULL) {
     Node* address = n->in(MemNode::Address);
     Node* value = n->in(MemNode::ValueIn);
     Node* mem = n->in(MemNode::Memory);
@@ -748,8 +747,7 @@
 
 // Try moving a store out of a loop, right after the loop
 void PhaseIdealLoop::try_move_store_after_loop(Node* n) {
-  if (n->is_Store()) {
-    assert(n->in(0), "store should have control set");
+  if (n->is_Store() && n->in(0) != NULL) {
     Node *n_ctrl = get_ctrl(n);
     IdealLoopTree *n_loop = get_loop(n_ctrl);
     // Store must be in a loop
--- a/hotspot/src/share/vm/opto/stringopts.cpp	Mon Sep 07 20:03:56 2015 +0200
+++ b/hotspot/src/share/vm/opto/stringopts.cpp	Tue Sep 08 16:10:37 2015 +0200
@@ -1576,51 +1576,58 @@
 
   Node* result;
   if (!kit.stopped()) {
+    Node* char_array = NULL;
+    if (sc->num_arguments() == 1 &&
+          (sc->mode(0) == StringConcat::StringMode ||
+           sc->mode(0) == StringConcat::StringNullCheckMode)) {
+      // Handle the case when there is only a single String argument.
+      // In this case, we can just pull the value from the String itself.
+      char_array = kit.load_String_value(kit.control(), sc->argument(0));
+    } else {
+      // length now contains the number of characters needed for the
+      // char[] so create a new AllocateArray for the char[]
+      {
+        PreserveReexecuteState preexecs(&kit);
+        // The original jvms is for an allocation of either a String or
+        // StringBuffer so no stack adjustment is necessary for proper
+        // reexecution.  If we deoptimize in the slow path the bytecode
+        // will be reexecuted and the char[] allocation will be thrown away.
+        kit.jvms()->set_should_reexecute(true);
+        char_array = kit.new_array(__ makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_CHAR))),
+                                   length, 1);
+      }
 
-    // length now contains the number of characters needed for the
-    // char[] so create a new AllocateArray for the char[]
-    Node* char_array = NULL;
-    {
-      PreserveReexecuteState preexecs(&kit);
-      // The original jvms is for an allocation of either a String or
-      // StringBuffer so no stack adjustment is necessary for proper
-      // reexecution.  If we deoptimize in the slow path the bytecode
-      // will be reexecuted and the char[] allocation will be thrown away.
-      kit.jvms()->set_should_reexecute(true);
-      char_array = kit.new_array(__ makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_CHAR))),
-                                 length, 1);
-    }
-
-    // Mark the allocation so that zeroing is skipped since the code
-    // below will overwrite the entire array
-    AllocateArrayNode* char_alloc = AllocateArrayNode::Ideal_array_allocation(char_array, _gvn);
-    char_alloc->maybe_set_complete(_gvn);
+      // Mark the allocation so that zeroing is skipped since the code
+      // below will overwrite the entire array
+      AllocateArrayNode* char_alloc = AllocateArrayNode::Ideal_array_allocation(char_array, _gvn);
+      char_alloc->maybe_set_complete(_gvn);
 
-    // Now copy the string representations into the final char[]
-    Node* start = __ intcon(0);
-    for (int argi = 0; argi < sc->num_arguments(); argi++) {
-      Node* arg = sc->argument(argi);
-      switch (sc->mode(argi)) {
-        case StringConcat::IntMode: {
-          Node* end = __ AddI(start, string_sizes->in(argi));
-          // getChars words backwards so pass the ending point as well as the start
-          int_getChars(kit, arg, char_array, start, end);
-          start = end;
-          break;
+      // Now copy the string representations into the final char[]
+      Node* start = __ intcon(0);
+      for (int argi = 0; argi < sc->num_arguments(); argi++) {
+        Node* arg = sc->argument(argi);
+        switch (sc->mode(argi)) {
+          case StringConcat::IntMode: {
+            Node* end = __ AddI(start, string_sizes->in(argi));
+            // getChars words backwards so pass the ending point as well as the start
+            int_getChars(kit, arg, char_array, start, end);
+            start = end;
+            break;
+          }
+          case StringConcat::StringNullCheckMode:
+          case StringConcat::StringMode: {
+            start = copy_string(kit, arg, char_array, start);
+            break;
+          }
+          case StringConcat::CharMode: {
+            __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR),
+                               arg, T_CHAR, char_adr_idx, MemNode::unordered);
+            start = __ AddI(start, __ intcon(1));
+            break;
+          }
+          default:
+            ShouldNotReachHere();
         }
-        case StringConcat::StringNullCheckMode:
-        case StringConcat::StringMode: {
-          start = copy_string(kit, arg, char_array, start);
-          break;
-        }
-        case StringConcat::CharMode: {
-          __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR),
-                             arg, T_CHAR, char_adr_idx, MemNode::unordered);
-          start = __ AddI(start, __ intcon(1));
-          break;
-        }
-        default:
-          ShouldNotReachHere();
       }
     }
 
--- a/hotspot/src/share/vm/runtime/sweeper.cpp	Mon Sep 07 20:03:56 2015 +0200
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp	Tue Sep 08 16:10:37 2015 +0200
@@ -611,7 +611,7 @@
   } else if (nm->is_not_entrant()) {
     // If there are no current activations of this method on the
     // stack we can safely convert it to a zombie method
-    if (nm->can_not_entrant_be_converted()) {
+    if (nm->can_convert_to_zombie()) {
       // Clear ICStubs to prevent back patching stubs of zombie or unloaded
       // nmethods during the next safepoint (see ICStub::finalize).
       {
@@ -645,6 +645,12 @@
       assert(result == None, "sanity");
       result = Flushed;
     } else {
+      {
+        // Clean ICs of unloaded nmethods as well because they may reference other
+        // unloaded nmethods that may be flushed earlier in the sweeper cycle.
+        MutexLocker cl(CompiledIC_lock);
+        nm->cleanup_inline_caches();
+      }
       // Code cache state change is tracked in make_zombie()
       nm->make_zombie();
       SWEEP(nm);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/TestMoveStoresOutOfLoopsStoreNoCtrl.java	Tue Sep 08 16:10:37 2015 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+/*
+ * @test
+ * @bug 8134288
+ * @summary Store nodes may not have a control if used to update profiling
+ * @run main/othervm -XX:-ProfileInterpreter -XX:-TieredCompilation -XX:-BackgroundCompilation TestMoveStoresOutOfLoopsStoreNoCtrl
+ *
+ */
+
+public class TestMoveStoresOutOfLoopsStoreNoCtrl {
+
+    static void test(boolean flag) {
+        for (int i = 0; i < 20000; i++) {
+            if (flag) {
+                int j = 0;
+                do {
+                    j++;
+                } while(j < 10);
+            }
+        }
+    }
+
+    static public void main(String[] args) {
+        test(false);
+    }
+
+}