Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8244339: [lworld] JIT support for inline types with abstract class supertypes #33

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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
@@ -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;
}
@@ -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;
}

@@ -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;
@@ -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;

@@ -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() {
@@ -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();
@@ -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);
@@ -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_(); {
@@ -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
@@ -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 {

}

@@ -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
@@ -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;
@@ -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
@@ -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;
@@ -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
@@ -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;
@@ -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
@@ -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;

@@ -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
@@ -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;
@@ -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;
}