8142386: Octane crashes with assert(is_Load())
authorroland
Tue, 17 Nov 2015 12:00:16 +0100
changeset 34189 d5a8eb423f77
parent 34188 e6c7861d438d
child 34190 eaee778f0fdf
child 34192 6da4892d7cd5
8142386: Octane crashes with assert(is_Load()) Summary: Unsafe access to an array is wrongly marked as mismatched Reviewed-by: vlivanov, thartmann
hotspot/src/share/vm/opto/graphKit.cpp
hotspot/src/share/vm/opto/library_call.cpp
hotspot/src/share/vm/opto/memnode.cpp
hotspot/src/share/vm/opto/memnode.hpp
hotspot/test/compiler/intrinsics/unsafe/TestUnsafeMismatchedArrayFieldAccess.java
--- a/hotspot/src/share/vm/opto/graphKit.cpp	Tue Nov 17 08:59:21 2015 +0100
+++ b/hotspot/src/share/vm/opto/graphKit.cpp	Tue Nov 17 12:00:16 2015 +0100
@@ -1468,17 +1468,11 @@
   Node* mem = memory(adr_idx);
   Node* ld;
   if (require_atomic_access && bt == T_LONG) {
-    ld = LoadLNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency);
+    ld = LoadLNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency, unaligned, mismatched);
   } else if (require_atomic_access && bt == T_DOUBLE) {
-    ld = LoadDNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency);
+    ld = LoadDNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency, unaligned, mismatched);
   } else {
-    ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency);
-  }
-  if (unaligned) {
-    ld->as_Load()->set_unaligned_access();
-  }
-  if (mismatched) {
-    ld->as_Load()->set_mismatched_access();
+    ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency, unaligned, mismatched);
   }
   ld = _gvn.transform(ld);
   if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) {
--- a/hotspot/src/share/vm/opto/library_call.cpp	Tue Nov 17 08:59:21 2015 +0100
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Tue Nov 17 12:00:16 2015 +0100
@@ -2588,6 +2588,10 @@
     } else {
       bt = alias_type->field()->type()->basic_type();
     }
+    if (bt == T_ARRAY) {
+      // accessing an array field with getObject is not a mismatch
+      bt = T_OBJECT;
+    }
     if (bt != type) {
       mismatched = true;
     }
--- a/hotspot/src/share/vm/opto/memnode.cpp	Tue Nov 17 08:59:21 2015 +0100
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Tue Nov 17 12:00:16 2015 +0100
@@ -761,7 +761,8 @@
 
 //----------------------------LoadNode::make-----------------------------------
 // Polymorphic factory method:
-Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypePtr* adr_type, const Type *rt, BasicType bt, MemOrd mo, ControlDependency control_dependency) {
+Node *LoadNode::make(PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const TypePtr* adr_type, const Type *rt, BasicType bt, MemOrd mo,
+                     ControlDependency control_dependency, bool unaligned, bool mismatched) {
   Compile* C = gvn.C;
 
   // sanity check the alias category against the created node type
@@ -776,40 +777,68 @@
           // oop will be recorded in oop map if load crosses safepoint
           rt->isa_oopptr() || is_immutable_value(adr),
           "raw memory operations should have control edge");
+  LoadNode* load = NULL;
   switch (bt) {
-  case T_BOOLEAN: return new LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency);
-  case T_BYTE:    return new LoadBNode (ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency);
-  case T_INT:     return new LoadINode (ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency);
-  case T_CHAR:    return new LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency);
-  case T_SHORT:   return new LoadSNode (ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency);
-  case T_LONG:    return new LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency);
-  case T_FLOAT:   return new LoadFNode (ctl, mem, adr, adr_type, rt,            mo, control_dependency);
-  case T_DOUBLE:  return new LoadDNode (ctl, mem, adr, adr_type, rt,            mo, control_dependency);
-  case T_ADDRESS: return new LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(),  mo, control_dependency);
+  case T_BOOLEAN: load = new LoadUBNode(ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency); break;
+  case T_BYTE:    load = new LoadBNode (ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency); break;
+  case T_INT:     load = new LoadINode (ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency); break;
+  case T_CHAR:    load = new LoadUSNode(ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency); break;
+  case T_SHORT:   load = new LoadSNode (ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency); break;
+  case T_LONG:    load = new LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency); break;
+  case T_FLOAT:   load = new LoadFNode (ctl, mem, adr, adr_type, rt,            mo, control_dependency); break;
+  case T_DOUBLE:  load = new LoadDNode (ctl, mem, adr, adr_type, rt,            mo, control_dependency); break;
+  case T_ADDRESS: load = new LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(),  mo, control_dependency); break;
   case T_OBJECT:
 #ifdef _LP64
     if (adr->bottom_type()->is_ptr_to_narrowoop()) {
-      Node* load  = gvn.transform(new LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo, control_dependency));
-      return new DecodeNNode(load, load->bottom_type()->make_ptr());
+      load = new LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo, control_dependency);
     } else
 #endif
     {
       assert(!adr->bottom_type()->is_ptr_to_narrowoop() && !adr->bottom_type()->is_ptr_to_narrowklass(), "should have got back a narrow oop");
-      return new LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo, control_dependency);
+      load = new LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr(), mo, control_dependency);
     }
+    break;
+  }
+  assert(load != NULL, "LoadNode should have been created");
+  if (unaligned) {
+    load->set_unaligned_access();
   }
-  ShouldNotReachHere();
-  return (LoadNode*)NULL;
+  if (mismatched) {
+    load->set_mismatched_access();
+  }
+  if (load->Opcode() == Op_LoadN) {
+    Node* ld = gvn.transform(load);
+    return new DecodeNNode(ld, ld->bottom_type()->make_ptr());
+  }
+
+  return load;
 }
 
-LoadLNode* LoadLNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) {
+LoadLNode* LoadLNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo,
+                                  ControlDependency control_dependency, bool unaligned, bool mismatched) {
   bool require_atomic = true;
-  return new LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency, require_atomic);
+  LoadLNode* load = new LoadLNode(ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency, require_atomic);
+  if (unaligned) {
+    load->set_unaligned_access();
+  }
+  if (mismatched) {
+    load->set_mismatched_access();
+  }
+  return load;
 }
 
-LoadDNode* LoadDNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo, ControlDependency control_dependency) {
+LoadDNode* LoadDNode::make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type, const Type* rt, MemOrd mo,
+                                  ControlDependency control_dependency, bool unaligned, bool mismatched) {
   bool require_atomic = true;
-  return new LoadDNode(ctl, mem, adr, adr_type, rt, mo, control_dependency, require_atomic);
+  LoadDNode* load = new LoadDNode(ctl, mem, adr, adr_type, rt, mo, control_dependency, require_atomic);
+  if (unaligned) {
+    load->set_unaligned_access();
+  }
+  if (mismatched) {
+    load->set_mismatched_access();
+  }
+  return load;
 }
 
 
--- a/hotspot/src/share/vm/opto/memnode.hpp	Tue Nov 17 08:59:21 2015 +0100
+++ b/hotspot/src/share/vm/opto/memnode.hpp	Tue Nov 17 12:00:16 2015 +0100
@@ -198,9 +198,10 @@
   }
 
   // Polymorphic factory method:
-   static Node* make(PhaseGVN& gvn, Node *c, Node *mem, Node *adr,
-                     const TypePtr* at, const Type *rt, BasicType bt,
-                     MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest);
+  static Node* make(PhaseGVN& gvn, Node *c, Node *mem, Node *adr,
+                    const TypePtr* at, const Type *rt, BasicType bt,
+                    MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest,
+                    bool unaligned = false, bool mismatched = false);
 
   virtual uint hash()   const;  // Check the type
 
@@ -375,7 +376,8 @@
   virtual BasicType memory_type() const { return T_LONG; }
   bool require_atomic_access() const { return _require_atomic_access; }
   static LoadLNode* make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type,
-                                const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest);
+                                const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest,
+                                bool unaligned = false, bool mismatched = false);
 #ifndef PRODUCT
   virtual void dump_spec(outputStream *st) const {
     LoadNode::dump_spec(st);
@@ -426,7 +428,8 @@
   virtual BasicType memory_type() const { return T_DOUBLE; }
   bool require_atomic_access() const { return _require_atomic_access; }
   static LoadDNode* make_atomic(Node* ctl, Node* mem, Node* adr, const TypePtr* adr_type,
-                                const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest);
+                                const Type* rt, MemOrd mo, ControlDependency control_dependency = DependsOnlyOnTest,
+                                bool unaligned = false, bool mismatched = false);
 #ifndef PRODUCT
   virtual void dump_spec(outputStream *st) const {
     LoadNode::dump_spec(st);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeMismatchedArrayFieldAccess.java	Tue Nov 17 12:00:16 2015 +0100
@@ -0,0 +1,65 @@
+/*
+ * 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 8142386
+ * @library /testlibrary /test/lib
+ * @summary Unsafe access to an array is wrongly marked as mismatched
+ * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:-TieredCompilation TestUnsafeMismatchedArrayFieldAccess
+ *
+ */
+
+import java.lang.reflect.*;
+import jdk.test.lib.Utils;
+import sun.misc.Unsafe;
+
+public class TestUnsafeMismatchedArrayFieldAccess {
+
+    private static final Unsafe UNSAFE = Utils.getUnsafe();
+
+    static {
+        try {
+            array_offset = UNSAFE.objectFieldOffset(TestUnsafeMismatchedArrayFieldAccess.class.getDeclaredField("array"));
+        }
+        catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    int[] array;
+    static final long array_offset;
+
+    void m() {
+        UNSAFE.getObject(this, array_offset);
+    }
+
+    static public void main(String[] args) {
+        TestUnsafeMismatchedArrayFieldAccess test = new TestUnsafeMismatchedArrayFieldAccess();
+
+        for (int i = 0; i < 20000; i++) {
+            test.m();
+        }
+    }
+}