Skip to content

Commit

Permalink
8244339: [lworld] JIT support for inline types with abstract class su…
Browse files Browse the repository at this point in the history
…pertypes
  • Loading branch information
TobiHartmann committed May 4, 2020
1 parent 7502797 commit 6742fab
Show file tree
Hide file tree
Showing 18 changed files with 998 additions and 99 deletions.
7 changes: 2 additions & 5 deletions src/hotspot/share/c1/c1_GraphBuilder.cpp
Expand Up @@ -1292,11 +1292,8 @@ void GraphBuilder::if_node(Value x, If::Condition cond, Value y, ValueStack* sta
if (left_klass == NULL || right_klass == NULL) {
// The klass is still unloaded, or came from a Phi node. Go slow case;
subst_check = true;
} else if (left_klass->is_java_lang_Object() || left_klass->is_interface() ||
right_klass->is_java_lang_Object() || right_klass->is_interface()) {
// Either operand may be a value object, but we're not sure. Go slow case;
subst_check = true;
} else if (left_klass->is_valuetype() || right_klass->is_valuetype()) {
} else if (left_klass->can_be_value_klass() || right_klass->can_be_value_klass()) {
// Either operand may be a value object, but we're not sure. Go slow case;
subst_check = true;
} else {
// No need to do substitutability check
Expand Down
22 changes: 7 additions & 15 deletions src/hotspot/share/c1/c1_Instruction.cpp
Expand Up @@ -144,19 +144,16 @@ bool Instruction::maybe_flattened_array() {
ciType* type = declared_type();
if (type != NULL) {
if (type->is_obj_array_klass()) {
// Check for array covariance. One of the following declared types may be a flattened array:
// Due to array covariance, the runtime type might be a flattened array.
ciKlass* element_klass = type->as_obj_array_klass()->element_klass();
if (!element_klass->is_loaded() ||
element_klass->is_java_lang_Object() || // (ValueType[] <: Object[])
element_klass->is_interface() || // (ValueType[] <: <any interface>[])
(element_klass->is_valuetype() && element_klass->as_value_klass()->flatten_array())) { // (ValueType[] <: ValueType?[])
if (element_klass->can_be_value_klass() && (!element_klass->is_valuetype() || element_klass->as_value_klass()->flatten_array())) {
// We will add a runtime check for flat-ness.
return true;
}
} else if (type->is_value_array_klass()) {
ciKlass* element_klass = type->as_value_array_klass()->element_klass();
if (!element_klass->is_loaded() ||
(element_klass->is_valuetype() && element_klass->as_value_klass()->flatten_array())) { // (ValueType[] <: ValueType?[])
(element_klass->is_valuetype() && element_klass->as_value_klass()->flatten_array())) {
// We will add a runtime check for flat-ness.
return true;
}
Expand All @@ -170,30 +167,25 @@ bool Instruction::maybe_flattened_array() {
return true;
}
}

return false;
}

bool Instruction::maybe_null_free_array() {
ciType* type = declared_type();
if (type != NULL) {
if (type->is_obj_array_klass()) {
// Check for array covariance. One of the following declared types may be a null-free array:
// Due to array covariance, the runtime type might be a null-free array.
ciKlass* element_klass = type->as_obj_array_klass()->element_klass();
if (!element_klass->is_loaded() ||
element_klass->is_java_lang_Object() || // (ValueType[] <: Object[])
element_klass->is_interface() || // (ValueType[] <: <any interface>[])
element_klass->is_valuetype()) { // (ValueType[] <: ValueType?[])
// We will add a runtime check for flat-ness.
if (element_klass->can_be_value_klass()) {
// We will add a runtime check for null-free-ness.
return true;
}
}
} else {
// Type info gets lost during Phi merging (Phi, IfOp, etc), but we might be storing into a
// flattened array, so we should do a runtime check.
// null-free array, so we should do a runtime check.
return true;
}

return false;
}

Expand Down
5 changes: 1 addition & 4 deletions src/hotspot/share/c1/c1_LIRGenerator.cpp
Expand Up @@ -1693,10 +1693,7 @@ bool LIRGenerator::needs_flattened_array_store_check(StoreIndexed* x) {
ciType* type = x->value()->declared_type();
if (type != NULL && type->is_klass()) {
ciKlass* klass = type->as_klass();
if (klass->is_loaded() &&
!(klass->is_valuetype() && klass->as_value_klass()->flatten_array()) &&
!klass->is_java_lang_Object() &&
!klass->is_interface()) {
if (!klass->can_be_value_klass() || (klass->is_valuetype() && !klass->as_value_klass()->flatten_array())) {
// This is known to be a non-flattenable object. If the array is flattened,
// it will be caught by the code generated by array_store_check().
return false;
Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/share/ci/ciInstanceKlass.hpp
Expand Up @@ -259,6 +259,10 @@ class ciInstanceKlass : public ciKlass {
return (impl != this ? impl : NULL);
}

virtual bool can_be_value_klass(bool is_exact = false) {
return EnableValhalla && (!is_loaded() || is_valuetype() || ((is_java_lang_Object() || is_interface() || (is_abstract() && !has_nonstatic_fields())) && !is_exact));
}

// Is the defining class loader of this class the default loader?
bool uses_default_loader() const;

Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/ci/ciKlass.hpp
Expand Up @@ -110,7 +110,7 @@ class ciKlass : public ciType {
}

virtual bool can_be_value_klass(bool is_exact = false) {
return EnableValhalla && (!is_loaded() || is_valuetype() || ((is_java_lang_Object() || is_interface()) && !is_exact));
return false;
}

virtual bool can_be_value_array_klass() {
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/opto/graphKit.cpp
Expand Up @@ -3822,7 +3822,7 @@ Node* GraphKit::get_layout_helper(Node* klass_node, jint& constant_value) {
bool can_be_flattened = false;
if (ValueArrayFlatten && klass->is_obj_array_klass()) {
ciKlass* elem = klass->as_obj_array_klass()->element_klass();
can_be_flattened = elem->is_java_lang_Object() || elem->is_interface() || (elem->is_valuetype() && !klass->as_array_klass()->storage_properties().is_null_free());
can_be_flattened = elem->can_be_value_klass() && (!elem->is_valuetype() || elem->as_value_klass()->flatten_array());
}
if (xklass || (klass->is_array_klass() && !can_be_flattened)) {
jint lhelper = klass->layout_helper();
Expand Down
7 changes: 2 additions & 5 deletions src/hotspot/share/opto/parse2.cpp
Expand Up @@ -91,9 +91,8 @@ void Parse::array_load(BasicType bt) {
// Load from non-flattened but flattenable value type array (elements can never be null)
bt = T_VALUETYPE;
} else if (!ary_t->is_not_flat()) {
assert(is_reference_type(bt), "");
// Cannot statically determine if array is flattened, emit runtime check
assert(ValueArrayFlatten && elemptr->can_be_value_type() && !ary_t->klass_is_exact() && !ary_t->is_not_null_free() &&
assert(ValueArrayFlatten && is_reference_type(bt) && elemptr->can_be_value_type() && !ary_t->klass_is_exact() && !ary_t->is_not_null_free() &&
(!elemptr->is_valuetypeptr() || elemptr->value_klass()->flatten_array()), "array can't be flattened");
Node* ctl = control();
IdealKit ideal(this);
Expand Down Expand Up @@ -184,12 +183,10 @@ void Parse::array_load(BasicType bt) {
alloc_obj->set_req(0, control());
alloc_obj = _gvn.transform(alloc_obj);

const Type* unknown_value = TypeInstPtr::BOTTOM->cast_to_flat_array();

const Type* unknown_value = elemptr->is_instptr()->cast_to_flat_array();
alloc_obj = _gvn.transform(new CheckCastPPNode(control(), alloc_obj, unknown_value));

ideal.sync_kit(this);

ideal.set(res, alloc_obj);
}
} ideal.else_(); {
Expand Down
11 changes: 8 additions & 3 deletions src/hotspot/share/opto/type.cpp
Expand Up @@ -3482,16 +3482,21 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_
return TypeInstPtr::make(TypePtr::BotPTR, klass, klass_is_exact, NULL, Offset(0), klass->flatten_array());
} else if (klass->is_obj_array_klass()) {
// Element is an object or value array. Recursively call ourself.
const TypeOopPtr* etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), false, try_for_exact);
const TypeOopPtr* etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), /* klass_change= */ false, try_for_exact);
bool null_free = klass->is_loaded() && klass->as_array_klass()->storage_properties().is_null_free();
if (null_free) {
assert(etype->is_valuetypeptr(), "must be a valuetypeptr");
etype = etype->join_speculative(TypePtr::NOTNULL)->is_oopptr();
}
// [V? has a subtype: [V. So even though V is final, [V? is not exact.
bool xk = etype->klass_is_exact() && (!etype->is_valuetypeptr() || null_free);
bool not_null_free = !etype->can_be_value_type() || xk;
bool not_flat = !ValueArrayFlatten || not_null_free || (etype->is_valuetypeptr() && !etype->value_klass()->flatten_array());

// Use exact element type to determine null-free/flattened properties
const TypeOopPtr* exact_etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), /* klass_change= */ true, try_for_exact);
bool not_null_free = !exact_etype->can_be_value_type();
assert(!(not_null_free && null_free), "inconsistent null-free information");
bool not_flat = !ValueArrayFlatten || not_null_free || (exact_etype->is_valuetypeptr() && !exact_etype->value_klass()->flatten_array());

const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, false, not_flat, not_null_free);
// We used to pass NotNull in here, asserting that the sub-arrays
// are all not-null. This is not true in generally, as code can
Expand Down
29 changes: 29 additions & 0 deletions test/hotspot/jtreg/compiler/valhalla/valuetypes/MyAbstract.java
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2020, 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.
*/

package compiler.valhalla.valuetypes;

public abstract class MyAbstract implements MyInterface {

}

4 changes: 2 additions & 2 deletions test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue1.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
Expand All @@ -23,7 +23,7 @@

package compiler.valhalla.valuetypes;

public final inline class MyValue1 implements MyInterface {
public final inline class MyValue1 extends MyAbstract {
static int s;
static final long sf = ValueTypeTest.rL;
final int x;
Expand Down
4 changes: 2 additions & 2 deletions test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue2.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
Expand Down Expand Up @@ -57,7 +57,7 @@ public static MyValue2Inline createWithFieldsInline(boolean b, long c) {
}
}

public final inline class MyValue2 implements MyInterface {
public final inline class MyValue2 extends MyAbstract {
final int x;
final byte y;
final MyValue2Inline v1;
Expand Down
4 changes: 2 additions & 2 deletions test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue3.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
Expand Down Expand Up @@ -62,7 +62,7 @@ public static MyValue3Inline createWithFieldsInline(float f7, double f8) {

// Value type definition to stress test return of a value in registers
// (uses all registers of calling convention on x86_64)
public final inline class MyValue3 implements MyInterface {
public final inline class MyValue3 extends MyAbstract {
final char c;
final byte bb;
final short s;
Expand Down
4 changes: 2 additions & 2 deletions test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue4.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
Expand All @@ -24,7 +24,7 @@
package compiler.valhalla.valuetypes;

// Value type definition with too many fields to return in registers
final inline class MyValue4 implements MyInterface {
final inline class MyValue4 extends MyAbstract {
final MyValue3 v1;
final MyValue3 v2;

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
Expand Down Expand Up @@ -2081,7 +2081,7 @@ public void test87_verifier(boolean warmup) {
}
}

// Additional correcntess tests to make sure we have the required null checks
// Additional correctness tests to make sure we have the required null checks
@Test()
public void test88(Object[] array, Integer v) {
array[0] = v;
Expand Down
Expand Up @@ -107,17 +107,17 @@ public Class<?> test3(Class<?> cls) {

public void test3_verifier(boolean warmup) {
Asserts.assertTrue(test3(Object.class) == null, "test3_1 failed");
Asserts.assertTrue(test3(MyValue1.class.asIndirectType()) == Object.class, "test3_2 failed");
Asserts.assertTrue(test3(MyValue1.class.asPrimaryType()) == Object.class, "test3_3 failed");
Asserts.assertTrue(test3(MyValue1.class.asIndirectType()) == MyAbstract.class, "test3_2 failed");
Asserts.assertTrue(test3(MyValue1.class.asPrimaryType()) == MyAbstract.class, "test3_3 failed");
Asserts.assertTrue(test3(Class.class) == Object.class, "test3_4 failed");
}

// Verify that Class::getSuperclass checks with statically known classes are folded
@Test(failOn = LOADK)
public boolean test4() {
boolean check1 = Object.class.getSuperclass() == null;
boolean check2 = MyValue1.class.asIndirectType().getSuperclass() == Object.class;
boolean check3 = MyValue1.class.asPrimaryType().getSuperclass() == Object.class;
boolean check2 = MyValue1.class.asIndirectType().getSuperclass() == MyAbstract.class;
boolean check3 = MyValue1.class.asPrimaryType().getSuperclass() == MyAbstract.class;
boolean check4 = Class.class.getSuperclass() == Object.class;
return check1 && check2 && check3 && check4;
}
Expand Down

0 comments on commit 6742fab

Please sign in to comment.