--- old/src/hotspot/cpu/x86/templateTable_x86.cpp 2019-05-03 16:28:57.970939715 +0200 +++ new/src/hotspot/cpu/x86/templateTable_x86.cpp 2019-05-03 16:28:57.382929505 +0200 @@ -370,7 +370,7 @@ // get type __ movzbl(rdx, Address(rax, rbx, Address::times_1, tags_offset)); - __ andl(rdx, ~JVM_CONSTANT_QDESC_BIT); + __ andl(rdx, ~JVM_CONSTANT_QDescBit); // unresolved class - get the resolved class __ cmpl(rdx, JVM_CONSTANT_UnresolvedClass); @@ -4469,7 +4469,7 @@ __ movzbl(rdx, Address(rdx, rbx, Address::times_1, Array::base_offset_in_bytes())); - __ andl (rdx, ~JVM_CONSTANT_QDESC_BIT); + __ andl (rdx, ~JVM_CONSTANT_QDescBit); __ cmpl(rdx, JVM_CONSTANT_Class); __ jcc(Assembler::equal, quicked); __ push(atos); // save receiver for result, and for GC @@ -4525,8 +4525,8 @@ __ movzbl(rcx, Address(rdx, rbx, Address::times_1, Array::base_offset_in_bytes())); - __ andl (rcx, JVM_CONSTANT_QDESC_BIT); - __ cmpl(rcx, JVM_CONSTANT_QDESC_BIT); + __ andl (rcx, JVM_CONSTANT_QDescBit); + __ cmpl(rcx, JVM_CONSTANT_QDescBit); __ jcc(Assembler::notEqual, done); __ jump(ExternalAddress(Interpreter::_throw_NullPointerException_entry)); } @@ -4547,7 +4547,7 @@ __ movzbl(rdx, Address(rdx, rbx, Address::times_1, Array::base_offset_in_bytes())); - __ andl (rdx, ~JVM_CONSTANT_QDESC_BIT); + __ andl (rdx, ~JVM_CONSTANT_QDescBit); __ cmpl(rdx, JVM_CONSTANT_Class); __ jcc(Assembler::equal, quicked); --- old/src/hotspot/share/classfile/classFileParser.cpp 2019-05-03 16:28:59.286962566 +0200 +++ new/src/hotspot/share/classfile/classFileParser.cpp 2019-05-03 16:28:58.638951314 +0200 @@ -501,7 +501,7 @@ Symbol* const name = cp->symbol_at(class_index); const unsigned int name_len = name->utf8_length(); - if (name->is_Q_signature() || name->is_Q_array_signature()) { + if (name->is_Q_signature()) { cp->unresolved_qdescriptor_at_put(index, class_index, num_klasses++); } else { cp->unresolved_klass_at_put(index, class_index, num_klasses++); --- old/src/hotspot/share/interpreter/interpreterRuntime.cpp 2019-05-03 16:29:00.622985766 +0200 +++ new/src/hotspot/share/interpreter/interpreterRuntime.cpp 2019-05-03 16:28:59.982974653 +0200 @@ -482,7 +482,7 @@ ConstantPool* constants = last_frame.method()->constants(); int i = last_frame.get_index_u2(Bytecodes::_multianewarray); Klass* klass = constants->klass_at(i, CHECK); - bool is_qtype = constants->tag_at(i).is_Qdescriptor_klass(); + bool is_qtype = klass->name()->is_Q_array_signature(); int nof_dims = last_frame.number_of_dimensions(); assert(klass->is_klass(), "not a class"); assert(nof_dims >= 1, "multianewarray rank must be nonzero"); --- old/src/hotspot/share/oops/constantPool.cpp 2019-05-03 16:29:01.839006882 +0200 +++ new/src/hotspot/share/oops/constantPool.cpp 2019-05-03 16:29:01.234996393 +0200 @@ -235,7 +235,7 @@ // The interpreter assumes when the tag is stored, the klass is resolved // and the Klass* non-NULL, so we need hardware store ordering here. - jbyte qdesc_bit = (name->is_Q_signature() || name->is_Q_array_signature()) ? (jbyte)JVM_CONSTANT_QDESC_BIT : 0; + jbyte qdesc_bit = (name->is_Q_signature()) ? (jbyte) JVM_CONSTANT_QDescBit : 0; if (k != NULL) { release_tag_at_put(class_index, JVM_CONSTANT_Class | qdesc_bit); } else { @@ -253,7 +253,7 @@ // The interpreter assumes when the tag is stored, the klass is resolved // and the Klass* non-NULL, so we need hardware store ordering here. - assert(!(k->name()->is_Q_signature() || k->name()->is_Q_array_signature()), "Q-type without JVM_CONSTANT_QDESC_BIT"); + assert(!k->name()->is_Q_signature(), "Q-type without JVM_CONSTANT_QDescBit"); release_tag_at_put(class_index, JVM_CONSTANT_Class); } @@ -551,7 +551,7 @@ // hardware store ordering here. jbyte tag = JVM_CONSTANT_Class; if (this_cp->tag_at(which).is_Qdescriptor_klass()) { - tag |= JVM_CONSTANT_QDESC_BIT; + tag |= JVM_CONSTANT_QDescBit; } this_cp->release_tag_at_put(which, tag); return k; @@ -1989,7 +1989,7 @@ ent_size = 2; break; } - case (JVM_CONSTANT_Class | JVM_CONSTANT_QDESC_BIT): { + case (JVM_CONSTANT_Class | JVM_CONSTANT_QDescBit): { idx1 = Bytes::get_Java_u2(bytes); printf("qclass #%03d", idx1); ent_size = 2; @@ -2037,7 +2037,7 @@ printf("UnresolvedClass: %s", WARN_MSG); break; } - case (JVM_CONSTANT_UnresolvedClass | JVM_CONSTANT_QDESC_BIT): { + case (JVM_CONSTANT_UnresolvedClass | JVM_CONSTANT_QDescBit): { printf("UnresolvedQClass: %s", WARN_MSG); break; } --- old/src/hotspot/share/oops/constantPool.hpp 2019-05-03 16:29:03.531036263 +0200 +++ new/src/hotspot/share/oops/constantPool.hpp 2019-05-03 16:29:02.923025705 +0200 @@ -282,7 +282,7 @@ void klass_at_put(int class_index, Klass* k); void unresolved_qdescriptor_at_put(int which, int name_index, int resolved_klass_index) { - release_tag_at_put(which, JVM_CONSTANT_UnresolvedClass | (jbyte)JVM_CONSTANT_QDESC_BIT); + release_tag_at_put(which, JVM_CONSTANT_UnresolvedClass | (jbyte) JVM_CONSTANT_QDescBit); assert((name_index & 0xffff0000) == 0, "must be"); assert((resolved_klass_index & 0xffff0000) == 0, "must be"); --- old/src/hotspot/share/oops/objArrayKlass.cpp 2019-05-03 16:29:05.143064256 +0200 +++ new/src/hotspot/share/oops/objArrayKlass.cpp 2019-05-03 16:29:04.543053837 +0200 @@ -59,7 +59,17 @@ int n, Klass* element_klass, TRAPS) { // Eagerly allocate the direct array supertype. Klass* super_klass = NULL; - if (!Universe::is_bootstrapping() || SystemDictionary::Object_klass_loaded()) { + if (storage_props.is_null_free()) { + assert(!Universe::is_bootstrapping(), "Need bootstrap"); + // Arrange null ok as direct super + super_klass = element_klass->array_klass_or_null(ArrayStorageProperties::empty, n); + if (super_klass == NULL) { // allocate super...need to drop the lock + MutexUnlocker mu(MultiArray_lock); + element_klass->array_klass(ArrayStorageProperties::empty, n, CHECK_NULL); + // retry, start from the beginning since lock dropped... + return element_klass->array_klass(storage_props, n, CHECK_NULL); + } + } else if (!Universe::is_bootstrapping() || SystemDictionary::Object_klass_loaded()) { Klass* element_super = element_klass->super(); if (element_super != NULL) { // The element type has a direct super. E.g., String[] has direct super of Object[]. --- old/src/hotspot/share/oops/valueArrayKlass.cpp 2019-05-03 16:29:06.399086066 +0200 +++ new/src/hotspot/share/oops/valueArrayKlass.cpp 2019-05-03 16:29:05.719074258 +0200 @@ -81,9 +81,7 @@ _element_klass = k; } -ValueArrayKlass* ValueArrayKlass::allocate_klass(Klass* element_klass, - Symbol* name, - TRAPS) { +ValueArrayKlass* ValueArrayKlass::allocate_klass(Klass* element_klass, TRAPS) { assert(ValueArrayFlatten, "Flatten array required"); assert(ValueKlass::cast(element_klass)->is_atomic() || (!ValueArrayAtomicAccess), "Atomic by-default"); @@ -93,45 +91,18 @@ * TODO refactor any remaining commonality */ - // Eagerly allocate the direct array supertype. - Klass* super_klass = NULL; - if (!Universe::is_bootstrapping() || SystemDictionary::Object_klass_loaded()) { - Klass* element_super = element_klass->super(); - if (element_super != NULL) { - // The element type has a direct super. E.g., String[] has direct super of Object[]. - super_klass = element_super->array_klass_or_null(ArrayStorageProperties::empty); - bool supers_exist = super_klass != NULL; - // Also, see if the element has secondary supertypes. - // We need an array type for each. - Array* element_supers = element_klass->secondary_supers(); - for( int i = element_supers->length()-1; i >= 0; i-- ) { - Klass* elem_super = element_supers->at(i); - if (elem_super->array_klass_or_null(ArrayStorageProperties::empty) == NULL) { - supers_exist = false; - break; - } - } - if (!supers_exist) { - // Oops. Not allocated yet. Back out, allocate it, and retry. - Klass* ek = NULL; - { - MutexUnlocker mu(MultiArray_lock); - super_klass = element_super->array_klass(CHECK_0); - for( int i = element_supers->length()-1; i >= 0; i-- ) { - Klass* elem_super = element_supers->at(i); - elem_super->array_klass(CHECK_0); - } - // Now retry from the beginning - ek = element_klass->array_klass(ArrayStorageProperties::flattened_and_null_free, 1, CHECK_0); - } // re-lock - return ValueArrayKlass::cast(ek); - } - } else { - ShouldNotReachHere(); // Value array klass cannot be the object array klass - } + // Eagerly allocate the direct array supertype, which would be "[L;" for this "[Q;" + Klass* super_klass = element_klass->array_klass_or_null(ArrayStorageProperties::empty); + if (super_klass == NULL) { + MutexUnlocker mu(MultiArray_lock); + // allocate super...need to drop the lock + element_klass->array_klass(ArrayStorageProperties::empty, 1, CHECK_NULL); + // retry, start from the beginning since lock dropped... + Klass* ak = element_klass->array_klass(ArrayStorageProperties::flattened_and_null_free, 1, CHECK_NULL); + return ValueArrayKlass::cast(ak); } - + Symbol* name = ArrayKlass::create_element_klass_array_name(true, element_klass, CHECK_NULL); ClassLoaderData* loader_data = element_klass->class_loader_data(); int size = ArrayKlass::static_size(ValueArrayKlass::header_size()); ValueArrayKlass* vak = new (loader_data, size, THREAD) ValueArrayKlass(element_klass, name); @@ -145,8 +116,7 @@ ValueArrayKlass* ValueArrayKlass::allocate_klass(ArrayStorageProperties storage_props, Klass* element_klass, TRAPS) { assert(storage_props.is_flattened(), "Expected flat storage"); - Symbol* name = ArrayKlass::create_element_klass_array_name(true, element_klass, CHECK_NULL); - return allocate_klass(element_klass, name, THREAD); + return allocate_klass(element_klass, THREAD); } void ValueArrayKlass::initialize(TRAPS) { --- old/src/hotspot/share/oops/valueArrayKlass.hpp 2019-05-03 16:29:07.623107321 +0200 +++ new/src/hotspot/share/oops/valueArrayKlass.hpp 2019-05-03 16:29:06.975096068 +0200 @@ -43,7 +43,7 @@ // Constructor ValueArrayKlass(Klass* element_klass, Symbol* name); - static ValueArrayKlass* allocate_klass(Klass* element_klass, Symbol* name, TRAPS); + static ValueArrayKlass* allocate_klass(Klass* element_klass, TRAPS); protected: // Returns the ArrayKlass for n'th dimension. Klass* array_klass_impl(ArrayStorageProperties storage_props, bool or_null, int n, TRAPS); --- old/src/hotspot/share/utilities/constantTag.cpp 2019-05-03 16:29:09.039131911 +0200 +++ new/src/hotspot/share/utilities/constantTag.cpp 2019-05-03 16:29:08.359120102 +0200 @@ -106,7 +106,7 @@ return "Invalid index"; case JVM_CONSTANT_Class : return "Class"; - case (JVM_CONSTANT_Class | (jbyte)JVM_CONSTANT_QDESC_BIT): + case (JVM_CONSTANT_Class | (jbyte)JVM_CONSTANT_QDescBit): return "Q-Descriptor"; case JVM_CONSTANT_Fieldref : return "Field"; --- old/src/hotspot/share/utilities/constantTag.hpp 2019-05-03 16:29:10.247152887 +0200 +++ new/src/hotspot/share/utilities/constantTag.hpp 2019-05-03 16:29:09.615141912 +0200 @@ -46,11 +46,11 @@ JVM_CONSTANT_MethodHandleInError = 104, // Error tag due to resolution error JVM_CONSTANT_MethodTypeInError = 105, // Error tag due to resolution error JVM_CONSTANT_DynamicInError = 106, // Error tag due to resolution error - JVM_CONSTANT_InternalMax = 106 // Last implementation tag + JVM_CONSTANT_InternalMax = 106, // Last implementation tag + // internal constant tag flags + JVM_CONSTANT_QDescBit = (1 << 7) // Separate bit, encode Q type descriptors }; -#define JVM_CONSTANT_QDESC_BIT (1 << 7) - class constantTag { private: jbyte _tag; @@ -78,7 +78,7 @@ } bool is_Qdescriptor_klass() const { - return (_tag & JVM_CONSTANT_QDESC_BIT) != 0; + return (_tag & JVM_CONSTANT_QDescBit) != 0; } bool is_method_handle_in_error() const { @@ -121,11 +121,11 @@ _tag = JVM_CONSTANT_Invalid; } constantTag(jbyte tag) { - jbyte entry_tag = tag & ~JVM_CONSTANT_QDESC_BIT; - assert((((tag & JVM_CONSTANT_QDESC_BIT) == 0) && (entry_tag >= 0 && entry_tag <= JVM_CONSTANT_NameAndType) || + jbyte entry_tag = tag & ~JVM_CONSTANT_QDescBit; + assert((((tag & JVM_CONSTANT_QDescBit) == 0) && (entry_tag >= 0 && entry_tag <= JVM_CONSTANT_NameAndType) || (entry_tag >= JVM_CONSTANT_MethodHandle && entry_tag <= JVM_CONSTANT_InvokeDynamic) || (entry_tag >= JVM_CONSTANT_InternalMin && entry_tag <= JVM_CONSTANT_InternalMax)) - || (((tag & JVM_CONSTANT_QDESC_BIT) != 0) && (entry_tag == JVM_CONSTANT_Class || + || (((tag & JVM_CONSTANT_QDescBit) != 0) && (entry_tag == JVM_CONSTANT_Class || entry_tag == JVM_CONSTANT_UnresolvedClass || entry_tag == JVM_CONSTANT_UnresolvedClassInError || entry_tag == JVM_CONSTANT_ClassIndex)) , "Invalid constant tag"); @@ -146,7 +146,7 @@ return constantTag(); } - jbyte value() const { return _tag & ~JVM_CONSTANT_QDESC_BIT; } + jbyte value() const { return _tag & ~JVM_CONSTANT_QDescBit; } jbyte tag() const { return _tag; } jbyte error_value() const; jbyte non_error_value() const; --- old/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java 2019-05-03 16:29:11.443173656 +0200 +++ new/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java 2019-05-03 16:29:10.799162472 +0200 @@ -253,6 +253,7 @@ MyInt[] myInts = new MyInt[1]; assertTrue(myInts instanceof Object[]); assertTrue(myInts instanceof Comparable[]); + assertTrue(myInts instanceof MyInt?[]); Class cls = MyInt.class.asValueType(); assertTrue(cls.isValue()); @@ -271,15 +272,30 @@ MyOtherInt[][] matrix = new MyOtherInt[1][1]; assertTrue(matrix[0] instanceof MyOtherInt[]); assertTrue(matrix[0] instanceof SomeSecondaryType[]); + assertTrue(matrix[0] instanceof MyOtherInt?[]); // Box types vs Inline... MyInt?[] myValueRefs = new MyInt?[1]; - // JDK-8222974 - //assertTrue(myValueRefs instanceof MyInt?[]); - assertFalse(myValueRefs instanceof MyInt[]); + assertTrue(myValueRefs instanceof MyInt?[]); assertTrue(myValueRefs instanceof Object[]); assertTrue(myValueRefs instanceof Comparable[]); assertFalse(myValueRefs instanceof MyInt[]); + + MyInt?[][] myMdValueRefs = new MyInt?[1][1]; + assertTrue(myMdValueRefs[0] instanceof MyInt?[]); + assertTrue(myMdValueRefs[0] instanceof Object[]); + assertTrue(myMdValueRefs[0] instanceof Comparable[]); + assertFalse(myMdValueRefs[0] instanceof MyInt[]); + + // Did we break checkcast... + MyInt?[] va1 = (MyInt?[])null; + MyInt?[] va2 = null; + MyInt?[][] va3 = (MyInt?[][])null; + MyInt?[][][] va4 = (MyInt?[][][])null; + MyInt[] va5 = null; + MyInt[] va6 = (MyInt[])null; + MyInt[][] va7 = (MyInt[][])null; + MyInt[][][] va8 = (MyInt[][][])null; } --- old/test/langtools/tools/javac/valhalla/lworld-values/ArrayRelationsTest.java 2019-05-03 16:29:12.631194286 +0200 +++ new/test/langtools/tools/javac/valhalla/lworld-values/ArrayRelationsTest.java 2019-05-03 16:29:11.999183312 +0200 @@ -86,15 +86,13 @@ la = new ArrayRelationsTest? [10]; - // NOTE: The following line should trigger a CCE, but doesn't ATM - this will - // start failing when the VM is fixed. Flip the condition then. cce = false; try { qa = (ArrayRelationsTest[]) la; } catch (ClassCastException c) { cce = true; } - if (cce) { // <----- Flip this condition. + if (!cce) { throw new AssertionError("Unexpected CCE behavior"); } }