--- old/src/hotspot/share/c1/c1_GraphBuilder.cpp 2019-03-11 16:11:22.507308346 -0700 +++ new/src/hotspot/share/c1/c1_GraphBuilder.cpp 2019-03-11 16:11:22.267299742 -0700 @@ -1716,7 +1716,7 @@ } LoadField* load_field = new LoadField(append(obj), offset, field, true, state_before, needs_patching); - if (field->is_q_type()) { + if (field->is_flattenable()) { load_field->set_never_null(true); } push(type, append(load_field)); --- old/src/hotspot/share/c1/c1_LIRGenerator.cpp 2019-03-11 16:11:23.167332005 -0700 +++ new/src/hotspot/share/c1/c1_LIRGenerator.cpp 2019-03-11 16:11:22.927323402 -0700 @@ -1543,7 +1543,7 @@ if (x->needs_null_check() && (needs_patching || MacroAssembler::needs_explicit_null_check(x->offset()))) { - if (needs_patching && x->field()->is_q_type()) { + if (needs_patching && x->field()->is_flattenable()) { // We are storing a field of type "QT;" into holder class H, but H is not yet // loaded. (If H had been loaded, then T must also have already been loaded // due to the "Q" signature, and needs_patching would be false). @@ -1871,7 +1871,7 @@ return _barrier_set->resolve(this, decorators, obj); } -Value LIRGenerator::q_type_load_field_prolog(LoadField* x, CodeEmitInfo* info) { +Value LIRGenerator::flattenable_load_field_prolog(LoadField* x, CodeEmitInfo* info) { ciField* field = x->field(); ciInstanceKlass* holder = field->holder(); Value default_value = NULL; @@ -1884,6 +1884,7 @@ bool need_default = false; if (field->is_static()) { // (1) holder is unloaded -- no problem: it will be loaded by patching, and field offset will be determined. + // No check needed here. if (field_type_unloaded) { // (2) field type is unloaded -- problem: we don't know what the default value is. Let's deopt. @@ -1893,7 +1894,8 @@ need_default = true; } - // (3) field is not flattenable -- we don't care: static fields are never flattened. + // (3) field is not flattened -- we don't care: static fields are never flattened. + // No check needed here. } else { if (!holder->is_loaded()) { // (1) holder is unloaded -- problem: we needed the field offset back in GraphBuilder::access_field() @@ -1901,17 +1903,16 @@ // type was loaded at compilation time). deopt = true; } else if (field_type_unloaded) { - // (2) field type is unloaded -- problem: we don't whether it's flattened or not. Let's deopt + // (2) field type is unloaded -- problem: we don't know whether it's flattened or not. Let's deopt deopt = true; } else if (!field->is_flattened()) { - // (3) field is not flattenable -- need default value in cases of uninitialized field + // (3) field is not flattened -- need default value in cases of uninitialized field need_default = true; } } - assert(!(deopt && need_default), "cannot both be true"); - if (deopt) { + assert(!need_default, "deopt and need_default cannot both be true"); assert(x->needs_patching(), "must be"); assert(info != NULL, "must be"); CodeStub* stub = new DeoptimizeStub(new CodeEmitInfo(info), @@ -1974,8 +1975,8 @@ #endif Value default_value = NULL; - if (x->field()->is_q_type()) { - default_value = q_type_load_field_prolog(x, info); + if (x->field()->is_flattenable()) { + default_value = flattenable_load_field_prolog(x, info); } bool stress_deopt = StressLoopInvariantCodeMotion && info && info->deoptimize_on_exception(); --- old/src/hotspot/share/c1/c1_LIRGenerator.hpp 2019-03-11 16:11:23.823355521 -0700 +++ new/src/hotspot/share/c1/c1_LIRGenerator.hpp 2019-03-11 16:11:23.587347061 -0700 @@ -266,7 +266,7 @@ void do_update_CRC32C(Intrinsic* x); void do_vectorizedMismatch(Intrinsic* x); - Value q_type_load_field_prolog(LoadField* x, CodeEmitInfo* info); + Value flattenable_load_field_prolog(LoadField* x, CodeEmitInfo* info); void access_flattened_array(bool is_load, LIRItem& array, LIRItem& index, LIRItem& obj_item); bool needs_flattened_array_store_check(StoreIndexed* x); void check_flattened_array(LIRItem& array, CodeStub* slow_path); --- old/src/hotspot/share/ci/ciField.cpp 2019-03-11 16:11:24.447377889 -0700 +++ new/src/hotspot/share/ci/ciField.cpp 2019-03-11 16:11:24.207369287 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, 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 @@ -101,6 +101,9 @@ } _name = (ciSymbol*)ciEnv::current(THREAD)->get_symbol(name); + + // this is needed if the field class is not yet loaded. + _is_flattenable = _signature->is_Q_signature(); // Get the field's declared holder. // --- old/src/hotspot/share/ci/ciField.hpp 2019-03-11 16:11:25.075400402 -0700 +++ new/src/hotspot/share/ci/ciField.hpp 2019-03-11 16:11:24.831391655 -0700 @@ -202,12 +202,6 @@ klass_name == ciSymbol::java_lang_Long_LongCache())); } - bool is_q_type() const { - // Cannot use (type()->basic_type() == T_VALUETYPE) -- if the class is not loaded, - // type() is an unloaded ciInstanceKlass! - return signature()->char_at(0) == 'Q'; - } - // Debugging output void print(); void print_name_on(outputStream* st); --- old/src/hotspot/share/ci/ciSymbol.cpp 2019-03-11 16:11:25.683422196 -0700 +++ new/src/hotspot/share/ci/ciSymbol.cpp 2019-03-11 16:11:25.443413594 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, 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 @@ -105,6 +105,12 @@ } // ------------------------------------------------------------------ +// ciSymbol::is_Q_signature +bool ciSymbol::is_Q_signature() { + GUARDED_VM_ENTRY(return get_symbol()->is_Q_signature();) +} + +// ------------------------------------------------------------------ // ciSymbol::print_impl // // Implementation of the print method --- old/src/hotspot/share/ci/ciSymbol.hpp 2019-03-11 16:11:26.311444708 -0700 +++ new/src/hotspot/share/ci/ciSymbol.hpp 2019-03-11 16:11:26.071436105 -0700 @@ -84,6 +84,8 @@ // Tests if the symbol starts with the given prefix. bool starts_with(const char* prefix, int len) const; + bool is_Q_signature(); + // Determines where the symbol contains the given substring. int index_of_at(int i, const char* str, int len) const; --- old/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeField.java 2019-03-11 16:11:26.923466646 -0700 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeField.java 2019-03-11 16:11:26.683458044 -0700 @@ -21,39 +21,41 @@ * questions. */ +package compiler.valhalla.valuetypes; +import jdk.test.lib.Asserts; + /** * @test - * @library /test/lib + * @library /testlibrary /test/lib /compiler/whitebox / * @summary Test the handling of fields of unloaded value classes. * @compile -XDallowWithFieldOperator hack/GetUnresolvedValueFieldWrongSignature.java * @compile -XDallowWithFieldOperator TestUnloadedValueTypeField.java - * @run main/othervm -XX:+EnableValhalla -Xcomp -XX:+Inline - * -XX:CompileCommand=compileonly,TestUnloadedValueTypeField::test1 - * -XX:CompileCommand=print,TestUnloadedValueTypeField::test1 - * -XX:CompileCommand=compileonly,TestUnloadedValueTypeField::test2 - * -XX:CompileCommand=compileonly,GetUnresolvedValueFieldWrongSignature::test3 - * -XX:CompileCommand=compileonly,TestUnloadedValueTypeField::test4 - * -XX:CompileCommand=compileonly,TestUnloadedValueTypeField::test5 - * -XX:CompileCommand=compileonly,TestUnloadedValueTypeField::test11 - * -XX:CompileCommand=compileonly,TestUnloadedValueTypeField::test12 - * TestUnloadedValueTypeField + * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform + * @run main/othervm/timeout=120 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions + * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+EnableValhalla + * compiler.valhalla.valuetypes.ValueTypeTest + * compiler.valhalla.valuetypes.TestUnloadedValueTypeField */ -import jdk.test.lib.Asserts; +public class TestUnloadedValueTypeField extends compiler.valhalla.valuetypes.ValueTypeTest { + public static void main(String[] args) throws Throwable { + TestUnloadedValueTypeField test = new TestUnloadedValueTypeField(); + test.run(args); + } + + static final String[][] scenarios = { + {}, + {"-XX:ValueFieldMaxFlatSize=0"} + }; -public class TestUnloadedValueTypeField { - static final int WARMUP_LOOPS = 10000; - static public void main(String[] args) { - // instance fields - test1_verifier(); - test2_verifier(); - test3_verifier(); - test4_verifier(); - test5_verifier(); - - // static fields - test11_verifier(); - test12_verifier(); + @Override + public int getNumScenarios() { + return scenarios.length; + } + + @Override + public String[] getVMParameters(int scenario) { + return scenarios[scenario]; } // Test case 1: @@ -85,7 +87,8 @@ return MyValue1.make(); } - static int test1(MyValue1Holder holder) { + @Test + public int test1(MyValue1Holder holder) { if (holder != null) { return holder.v.foo + 1; } else { @@ -93,14 +96,13 @@ } } - static void test1_verifier() { - for (int i=0; i