8140001: _allocateInstance intrinsic does not throw InstantiationException for abstract classes and interfaces
authorvlivanov
Fri, 15 Jan 2016 21:56:40 +0300
changeset 35567 4b293ebd9ef9
parent 35566 034e1bc6f382
child 35568 8dfb205a2886
8140001: _allocateInstance intrinsic does not throw InstantiationException for abstract classes and interfaces Reviewed-by: kvn, shade
hotspot/src/share/vm/ci/ciInstanceKlass.hpp
hotspot/src/share/vm/opto/escape.cpp
hotspot/src/share/vm/opto/graphKit.cpp
hotspot/test/runtime/Unsafe/AllocateInstance.java
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp	Fri Jan 15 16:36:43 2016 +0300
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp	Fri Jan 15 21:56:40 2016 +0300
@@ -174,7 +174,6 @@
       return 2;
     }
   }
-
   bool has_default_methods()  {
     assert(is_loaded(), "must be loaded");
     return _has_default_methods;
@@ -261,6 +260,11 @@
     return NULL;
   }
 
+  bool can_be_instantiated() {
+    assert(is_loaded(), "must be loaded");
+    return !is_interface() && !is_abstract();
+  }
+
   // Dump the current state of this klass for compilation replay.
   virtual void dump_replay_data(outputStream* out);
 };
--- a/hotspot/src/share/vm/opto/escape.cpp	Fri Jan 15 16:36:43 2016 +0300
+++ b/hotspot/src/share/vm/opto/escape.cpp	Fri Jan 15 21:56:40 2016 +0300
@@ -810,6 +810,7 @@
       if (cik->is_subclass_of(_compile->env()->Thread_klass()) ||
           cik->is_subclass_of(_compile->env()->Reference_klass()) ||
          !cik->is_instance_klass() || // StressReflectiveCode
+         !cik->as_instance_klass()->can_be_instantiated() ||
           cik->as_instance_klass()->has_finalizer()) {
         es = PointsToNode::GlobalEscape;
       }
--- a/hotspot/src/share/vm/opto/graphKit.cpp	Fri Jan 15 16:36:43 2016 +0300
+++ b/hotspot/src/share/vm/opto/graphKit.cpp	Fri Jan 15 21:56:40 2016 +0300
@@ -3407,8 +3407,7 @@
   if (layout_is_con) {
     assert(!StressReflectiveCode, "stress mode does not use these paths");
     bool must_go_slow = Klass::layout_helper_needs_slow_path(layout_con);
-    initial_slow_test = must_go_slow? intcon(1): extra_slow_test;
-
+    initial_slow_test = must_go_slow ? intcon(1) : extra_slow_test;
   } else {   // reflective case
     // This reflective path is used by Unsafe.allocateInstance.
     // (It may be stress-tested by specifying StressReflectiveCode.)
--- a/hotspot/test/runtime/Unsafe/AllocateInstance.java	Fri Jan 15 16:36:43 2016 +0300
+++ b/hotspot/test/runtime/Unsafe/AllocateInstance.java	Fri Jan 15 21:56:40 2016 +0300
@@ -35,21 +35,7 @@
 import static jdk.test.lib.Asserts.*;
 
 public class AllocateInstance {
-    public static void main(String args[]) throws Exception {
-        Unsafe unsafe = Utils.getUnsafe();
-
-        // allocateInstance() should not result in a call to the constructor
-        TestClass tc = (TestClass)unsafe.allocateInstance(TestClass.class);
-        assertFalse(tc.calledConstructor);
-
-        // allocateInstance() on an abstract class should result in an InstantiationException
-        try {
-            AbstractClass ac = (AbstractClass)unsafe.allocateInstance(AbstractClass.class);
-            throw new RuntimeException("Did not get expected InstantiationException");
-        } catch (InstantiationException e) {
-            // Expected
-        }
-    }
+    static final Unsafe UNSAFE = Utils.getUnsafe();
 
     class TestClass {
         public boolean calledConstructor = false;
@@ -59,7 +45,41 @@
         }
     }
 
+    static void testConstructorCall() throws InstantiationException {
+        // allocateInstance() should not result in a call to the constructor
+        TestClass tc = (TestClass)UNSAFE.allocateInstance(TestClass.class);
+        assertFalse(tc.calledConstructor);
+    }
+
     abstract class AbstractClass {
         public AbstractClass() {}
     }
+
+    static void testAbstractClass() {
+        try {
+            AbstractClass ac = (AbstractClass) UNSAFE.allocateInstance(AbstractClass.class);
+            throw new AssertionError("Should throw InstantiationException for an abstract class");
+        } catch (InstantiationException e) {
+            // Expected
+        }
+    }
+
+    interface AnInterface {}
+
+    static void testInterface() {
+        try {
+            AnInterface ai = (AnInterface) UNSAFE.allocateInstance(AnInterface.class);
+            throw new AssertionError("Should throw InstantiationException for an interface");
+        } catch (InstantiationException e) {
+            // Expected
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+        for (int i = 0; i < 20_000; i++) {
+            testConstructorCall();
+            testAbstractClass();
+            testInterface();
+        }
+    }
 }