8140001: _allocateInstance intrinsic does not throw InstantiationException for abstract classes and interfaces

Reviewed-by: kvn, shade
This commit is contained in:
Vladimir Ivanov 2016-01-15 21:56:40 +03:00
parent 4b3b8b4f59
commit 28046ae321
4 changed files with 42 additions and 18 deletions

View File

@ -174,7 +174,6 @@ public:
return 2;
}
}
bool has_default_methods() {
assert(is_loaded(), "must be loaded");
return _has_default_methods;
@ -261,6 +260,11 @@ public:
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);
};

View File

@ -810,6 +810,7 @@ void ConnectionGraph::add_call_node(CallNode* call) {
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;
}

View File

@ -3407,8 +3407,7 @@ Node* GraphKit::new_instance(Node* klass_node,
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.)

View File

@ -35,21 +35,7 @@ import sun.misc.Unsafe;
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 @@ public class AllocateInstance {
}
}
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();
}
}
}