--- old/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp 2019-05-28 10:11:04.000000000 +0200 +++ new/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp 2019-05-28 10:10:59.000000000 +0200 @@ -1360,7 +1360,7 @@ if (idx < n->outcnt()) { Node* u = n->raw_out(idx); Node* c = phase->ctrl_or_self(u); - if (phase->is_dominator(call, c) && phase->is_dominator(c, projs.fallthrough_proj)) { + if (phase->is_dominator(call, c) && phase->is_dominator(c, projs->fallthrough_proj)) { stack.set_index(idx+1); assert(!u->is_CFG(), ""); stack.push(u, 0); --- old/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp 2019-05-28 10:11:09.000000000 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp 2019-05-28 10:11:04.000000000 +0200 @@ -927,7 +927,7 @@ T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); - oop fwd = (oop) ShenandoahBrooksPointer::get_raw_unchecked(obj); + oop fwd = (oop) ShenandoahForwarding::get_forwardee_raw_unchecked(obj); if (!oopDesc::equals_raw(obj, fwd)) { ShenandoahAsserts::print_failure(ShenandoahAsserts::_safe_all, obj, p, NULL, "Verify Roots", "Should not be forwarded", __FILE__, __LINE__); --- old/src/hotspot/share/opto/compile.cpp 2019-05-28 10:11:14.000000000 +0200 +++ new/src/hotspot/share/opto/compile.cpp 2019-05-28 10:11:09.000000000 +0200 @@ -4304,11 +4304,6 @@ ciType* superelem = superk; if (superelem->is_array_klass()) { ciArrayKlass* ak = superelem->as_array_klass(); - // Do not fold the subtype check to an array klass pointer comparison for [V? arrays. - // [V is a subtype of [V? but the klass for [V is not equal to the klass for [V?. Perform a full test. - if (ak->is_obj_array_klass() && !ak->storage_properties().is_null_free() && ak->element_klass()->is_valuetype()) { - return SSC_full_test; - } superelem = superelem->as_array_klass()->base_element_type(); } @@ -4322,6 +4317,11 @@ } } + // Do not fold the subtype check to an array klass pointer comparison for [V? arrays. + // [V is a subtype of [V? but the klass for [V is not equal to the klass for [V?. Perform a full test. + if (superk->is_obj_array_klass() && !superk->as_array_klass()->storage_properties().is_null_free() && superk->as_array_klass()->element_klass()->is_valuetype()) { + return SSC_full_test; + } // If casting to an instance klass, it must have no subtypes if (superk->is_interface()) { // Cannot trust interfaces yet. --- old/src/hotspot/share/opto/escape.cpp 2019-05-28 10:11:19.000000000 +0200 +++ new/src/hotspot/share/opto/escape.cpp 2019-05-28 10:11:14.000000000 +0200 @@ -1730,7 +1730,7 @@ if (ptn->is_JavaObject() && ptn != jobj) { // Mark all objects. jobj->set_scalar_replaceable(false); - ptn->set_scalar_replaceable(false); + ptn->set_scalar_replaceable(false); } } if (!jobj->scalar_replaceable()) { --- old/src/hotspot/share/opto/graphKit.cpp 2019-05-28 10:11:24.000000000 +0200 +++ new/src/hotspot/share/opto/graphKit.cpp 2019-05-28 10:11:19.000000000 +0200 @@ -3624,7 +3624,7 @@ 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(); + can_be_flattened = elem->is_java_lang_Object() || elem->is_interface() || (elem->is_valuetype() && !klass->as_array_klass()->storage_properties().is_null_free()); } if (xklass || (klass->is_array_klass() && !can_be_flattened)) { jint lhelper = klass->layout_helper(); @@ -4014,7 +4014,7 @@ Node* default_value = NULL; Node* raw_default_value = NULL; int props_shift = UseCompressedClassPointers ? oopDesc::narrow_storage_props_shift : oopDesc::wide_storage_props_shift; - if (ary_ptr != NULL) { + if (ary_ptr != NULL && ary_ptr->klass_is_exact()) { // Array type is known elem = ary_ptr->elem(); ciArrayKlass* ary_klass = ary_ptr->klass()->as_array_klass(); @@ -4035,7 +4035,8 @@ } } - if (EnableValhalla && (elem == NULL || (elem_klass != NULL && elem_klass->is_java_lang_Object() && !ary_type->klass_is_exact()))) { + if (EnableValhalla && (elem == NULL || (elem_klass != NULL && (elem_klass->is_java_lang_Object() || elem_klass->is_valuetype()) && + !ary_type->klass_is_exact()))) { // Array type is not known, compute default value and storage properties for initialization. assert(raw_default_value == NULL && storage_properties == NULL, "shouldn't be set yet"); assert(elem_mirror != NULL, "should not be null"); --- old/src/hotspot/share/opto/macroArrayCopy.cpp 2019-05-28 10:11:29.000000000 +0200 +++ new/src/hotspot/share/opto/macroArrayCopy.cpp 2019-05-28 10:11:24.000000000 +0200 @@ -1282,11 +1282,25 @@ if (top_src != NULL && top_src->klass() != NULL) { src_elem = top_src->klass()->as_array_klass()->element_type()->basic_type(); } - if (src_elem == T_ARRAY || (src_elem == T_VALUETYPE && top_src->klass()->is_obj_array_klass())) { + if (src_elem == T_ARRAY) { src_elem = T_OBJECT; + } else if (src_elem == T_VALUETYPE && top_src->klass()->is_obj_array_klass()) { + ciObjArrayKlass* array_klass = top_src->klass()->as_obj_array_klass(); + if (array_klass->storage_properties().is_null_free()) { + src_elem = T_OBJECT; + } else { + src_elem = T_CONFLICT; // either flattened or not + } } - if (dest_elem == T_ARRAY || (dest_elem == T_VALUETYPE && top_dest->klass()->is_obj_array_klass())) { + if (dest_elem == T_ARRAY) { dest_elem = T_OBJECT; + } else if (dest_elem == T_VALUETYPE && top_dest->klass()->is_obj_array_klass()) { + ciObjArrayKlass* array_klass = top_dest->klass()->as_obj_array_klass(); + if (array_klass->storage_properties().is_null_free()) { + dest_elem = T_OBJECT; + } else { + dest_elem = T_CONFLICT; // either flattened or not + } } if (ac->is_arraycopy_validated() && --- old/src/hotspot/share/opto/memnode.cpp 2019-05-28 10:11:34.000000000 +0200 +++ new/src/hotspot/share/opto/memnode.cpp 2019-05-28 10:11:29.000000000 +0200 @@ -2261,11 +2261,7 @@ ciArrayKlass* ak = tary_klass->as_array_klass(); // Do not fold klass loads from [V?. The runtime type might be [V due to [V <: [V? // and the klass for [V is not equal to the klass for [V?. - if (!tary->is_known_instance() && ak->is_obj_array_klass() && - !ak->storage_properties().is_null_free() && ak->element_klass()->is_valuetype()) { - // Fall back to Object array - ak = ciArrayKlass::make(phase->C->env()->Object_klass()); - } else if (tary->klass_is_exact()) { + if (tary->klass_is_exact()) { return TypeKlassPtr::make(tary_klass); } @@ -2277,7 +2273,7 @@ if (base_k->is_loaded() && base_k->is_instance_klass()) { ciInstanceKlass *ik = base_k->as_instance_klass(); // See if we can become precise: no subklasses and no interface - if (!ik->is_interface() && !ik->has_subklass()) { + if (!ik->is_interface() && !ik->has_subklass() && (!ik->is_valuetype() || ak->storage_properties().is_null_free())) { //assert(!UseExactTypes, "this code should be useless with exact types"); // Add a dependence; if any subclass added we need to recompile if (!ik->is_final()) { --- old/src/hotspot/share/opto/parse2.cpp 2019-05-28 10:11:39.000000000 +0200 +++ new/src/hotspot/share/opto/parse2.cpp 2019-05-28 10:11:34.000000000 +0200 @@ -73,7 +73,7 @@ // Load from non-flattened but flattenable value type array (elements can never be null) bt = T_VALUETYPE; } else if (ValueArrayFlatten && elemptr != NULL && elemptr->can_be_value_type() && - (!ary_t->klass_is_exact() || (elemptr->is_valuetypeptr() && elemptr->value_klass()->flatten_array()))) { + ((!elemptr->is_valuetypeptr() && !ary_t->klass_is_exact()) || (elemptr->is_valuetypeptr() && elemptr->value_klass()->flatten_array()))) { // Cannot statically determine if array is flattened, emit runtime check IdealKit ideal(this); IdealVariable res(ideal); --- old/src/hotspot/share/opto/type.cpp 2019-05-28 10:11:44.000000000 +0200 +++ new/src/hotspot/share/opto/type.cpp 2019-05-28 10:11:40.000000000 +0200 @@ -2364,8 +2364,15 @@ tinst = _elem->make_ptr()->isa_instptr(); else tinst = _elem->isa_instptr(); - if (tinst) - return tklass->as_instance_klass()->is_final(); + if (tinst) { + if (tklass->as_instance_klass()->is_final()) { + if (tinst->is_valuetypeptr() && (tinst->ptr() == TypePtr::BotPTR || tinst->ptr() == TypePtr::TopPTR)) { + return false; + } + return true; + } + return false; + } const TypeAryPtr* tap; if (_elem->isa_narrowoop()) tap = _elem->make_ptr()->isa_aryptr(); @@ -3449,7 +3456,7 @@ if (null_free && etype->is_valuetypeptr()) { etype = etype->join_speculative(TypePtr::NOTNULL)->is_oopptr(); } - bool xk = etype->klass_is_exact(); + bool xk = etype->klass_is_exact() && (!etype->is_valuetypeptr() || null_free); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS); // 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 @@ -4348,7 +4355,7 @@ int instance_id, const TypePtr* speculative, int inline_depth) { assert(!(k == NULL && ary->_elem->isa_int()), "integral arrays must be pre-equipped with a class"); - if (!xk) xk = ary->ary_must_be_exact(); + if (!xk) xk = ary->ary_must_be_exact(); assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed"); if (!UseExactTypes) xk = (ptr == Constant); return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, field_offset, instance_id, false, speculative, inline_depth))->hashcons(); --- old/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableArrays.java 2019-05-28 10:11:49.000000000 +0200 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableArrays.java 2019-05-28 10:11:44.000000000 +0200 @@ -505,14 +505,26 @@ va2[i] = testValue1; } MyValue1?[] result1 = test18(va1); - MyValue1?[] result2 = test18(va2); if (len > 0) { Asserts.assertEQ(result1[0], null); - Asserts.assertEQ(result2[0].hash(), va2[0].hash()); } for (int i = 1; i < len; ++i) { Asserts.assertEQ(result1[i].hash(), va1[i].hash()); - Asserts.assertEQ(result2[i].hash(), va2[i].hash()); + } + // make sure we do deopt: GraphKit::new_array assumes an + // array of references + for (int j = 0; j < 10; j++) { + MyValue1?[] result2 = test18(va2); + + for (int i = 0; i < len; ++i) { + Asserts.assertEQ(result2[i].hash(), va2[i].hash()); + } + } + if (compile_and_run_again_if_deoptimized(warmup, "TestNullableArrays::test18")) { + MyValue1?[] result2 = test18(va2); + for (int i = 0; i < len; ++i) { + Asserts.assertEQ(result2[i].hash(), va2[i].hash()); + } } }