--- old/src/hotspot/share/ci/ciTypeFlow.cpp 2019-03-14 15:03:02.638347903 +0100 +++ new/src/hotspot/share/ci/ciTypeFlow.cpp 2019-03-14 15:03:02.506347397 +0100 @@ -273,6 +273,12 @@ ciType* ciTypeFlow::StateVector::type_meet_internal(ciType* t1, ciType* t2, ciTypeFlow* analyzer) { assert(t1 != t2, "checked in caller"); + // Unwrap the types after gathering nullness information + bool never_null1 = t1->is_never_null(); + bool never_null2 = t2->is_never_null(); + t1 = t1->unwrap(); + t2 = t2->unwrap(); + if (t1->equals(top_type())) { return t2; } else if (t2->equals(top_type())) { @@ -295,12 +301,6 @@ return bottom_type(); } - // Unwrap the types after gathering nullness information - bool never_null1 = t1->is_never_null(); - bool never_null2 = t2->is_never_null(); - t1 = t1->unwrap(); - t2 = t2->unwrap(); - // Both types are non-top non-primitive types. That is, // both types are either instanceKlasses or arrayKlasses. ciKlass* object_klass = analyzer->env()->Object_klass(); @@ -628,10 +628,9 @@ pop_object(); do_null_assert(klass); } else { - pop_object(); - if (str->is_klass_never_null()) { + ciType* type = pop_value(); + if (klass->is_valuetype() && (str->is_klass_never_null() || type->is_never_null())) { // Casting to a Q-Type contains a NULL check - assert(klass->is_valuetype(), "must be a value type"); push(outer()->mark_as_never_null(klass)); } else { push_object(klass); --- old/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java 2019-03-14 15:03:03.010349330 +0100 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java 2019-03-14 15:03:02.870348794 +0100 @@ -675,4 +675,25 @@ // Expected } } + + @DontInline + public void test25_callee(MyValue1 val) { } + + // Test that when checkcasting from .box to .val and back to .box we + // keep track of the information that the value can never be null. + @Test(failOn = ALLOC + STORE) + public int test25(boolean b, MyValue1.box vt1, MyValue1.val vt2) { + vt1 = (MyValue1.val)vt1; + Object obj = b ? vt1 : vt2; // We should not allocate here + test25_callee(vt1); + return ((MyValue1)obj).x; + } + + @DontCompile + public void test25_verifier(boolean warmup) { + int res = test25(true, testValue1, testValue1); + Asserts.assertEquals(res, testValue1.x); + res = test25(false, testValue1, testValue1); + Asserts.assertEquals(res, testValue1.x); + } }