From fa401f37dffe7bde27e562065dfd24381d5237cc Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 18 Jun 2024 12:08:57 +0000 Subject: [PATCH] 8333805: Replaying compilation with null static final fields results in a crash Reviewed-by: thartmann, dlong --- src/hotspot/share/ci/ciInstanceKlass.cpp | 10 ++- src/hotspot/share/ci/ciReplay.cpp | 87 ++++++++++--------- .../ciReplay/TestNullStaticField.java | 82 +++++++++++++++++ 3 files changed, 135 insertions(+), 44 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/ciReplay/TestNullStaticField.java diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index fa084e2287f..240bb25ae3a 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -661,7 +661,8 @@ class StaticFinalFieldPrinter : public FieldClosure { ResourceMark rm; oop mirror = fd->field_holder()->java_mirror(); _out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii()); - switch (fd->field_type()) { + BasicType field_type = fd->field_type(); + switch (field_type) { case T_BYTE: _out->print_cr("%d", mirror->byte_field(fd->offset())); break; case T_BOOLEAN: _out->print_cr("%d", mirror->bool_field(fd->offset())); break; case T_SHORT: _out->print_cr("%d", mirror->short_field(fd->offset())); break; @@ -682,9 +683,12 @@ class StaticFinalFieldPrinter : public FieldClosure { case T_OBJECT: { oop value = mirror->obj_field_acquire(fd->offset()); if (value == nullptr) { - _out->print_cr("null"); + if (field_type == T_ARRAY) { + _out->print("%d", -1); + } + _out->cr(); } else if (value->is_instance()) { - assert(fd->field_type() == T_OBJECT, ""); + assert(field_type == T_OBJECT, ""); if (value->is_a(vmClasses::String_klass())) { const char* ascii_value = java_lang_String::as_quoted_ascii(value); _out->print_cr("\"%s\"", (ascii_value != nullptr) ? ascii_value : ""); diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 5fa30f86411..3ed71806b07 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -1056,46 +1056,48 @@ class CompileReplay : public StackObj { int length = parse_int("array length"); oop value = nullptr; - if (field_signature[1] == JVM_SIGNATURE_ARRAY) { - // multi dimensional array - ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK); - if (kelem == nullptr) { - return; - } - int rank = 0; - while (field_signature[rank] == JVM_SIGNATURE_ARRAY) { - rank++; - } - jint* dims = NEW_RESOURCE_ARRAY(jint, rank); - dims[0] = length; - for (int i = 1; i < rank; i++) { - dims[i] = 1; // These aren't relevant to the compiler - } - value = kelem->multi_allocate(rank, dims, CHECK); - } else { - if (strcmp(field_signature, "[B") == 0) { - value = oopFactory::new_byteArray(length, CHECK); - } else if (strcmp(field_signature, "[Z") == 0) { - value = oopFactory::new_boolArray(length, CHECK); - } else if (strcmp(field_signature, "[C") == 0) { - value = oopFactory::new_charArray(length, CHECK); - } else if (strcmp(field_signature, "[S") == 0) { - value = oopFactory::new_shortArray(length, CHECK); - } else if (strcmp(field_signature, "[F") == 0) { - value = oopFactory::new_floatArray(length, CHECK); - } else if (strcmp(field_signature, "[D") == 0) { - value = oopFactory::new_doubleArray(length, CHECK); - } else if (strcmp(field_signature, "[I") == 0) { - value = oopFactory::new_intArray(length, CHECK); - } else if (strcmp(field_signature, "[J") == 0) { - value = oopFactory::new_longArray(length, CHECK); - } else if (field_signature[0] == JVM_SIGNATURE_ARRAY && - field_signature[1] == JVM_SIGNATURE_CLASS) { - parse_klass(CHECK); // eat up the array class name - Klass* kelem = resolve_klass(field_signature + 1, CHECK); - value = oopFactory::new_objArray(kelem, length, CHECK); + if (length != -1) { + if (field_signature[1] == JVM_SIGNATURE_ARRAY) { + // multi dimensional array + ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK); + if (kelem == nullptr) { + return; + } + int rank = 0; + while (field_signature[rank] == JVM_SIGNATURE_ARRAY) { + rank++; + } + jint* dims = NEW_RESOURCE_ARRAY(jint, rank); + dims[0] = length; + for (int i = 1; i < rank; i++) { + dims[i] = 1; // These aren't relevant to the compiler + } + value = kelem->multi_allocate(rank, dims, CHECK); } else { - report_error("unhandled array staticfield"); + if (strcmp(field_signature, "[B") == 0) { + value = oopFactory::new_byteArray(length, CHECK); + } else if (strcmp(field_signature, "[Z") == 0) { + value = oopFactory::new_boolArray(length, CHECK); + } else if (strcmp(field_signature, "[C") == 0) { + value = oopFactory::new_charArray(length, CHECK); + } else if (strcmp(field_signature, "[S") == 0) { + value = oopFactory::new_shortArray(length, CHECK); + } else if (strcmp(field_signature, "[F") == 0) { + value = oopFactory::new_floatArray(length, CHECK); + } else if (strcmp(field_signature, "[D") == 0) { + value = oopFactory::new_doubleArray(length, CHECK); + } else if (strcmp(field_signature, "[I") == 0) { + value = oopFactory::new_intArray(length, CHECK); + } else if (strcmp(field_signature, "[J") == 0) { + value = oopFactory::new_longArray(length, CHECK); + } else if (field_signature[0] == JVM_SIGNATURE_ARRAY && + field_signature[1] == JVM_SIGNATURE_CLASS) { + Klass* actual_array_klass = parse_klass(CHECK); + Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); + value = oopFactory::new_objArray(kelem, length, CHECK); + } else { + report_error("unhandled array staticfield"); + } } } java_mirror->obj_field_put(fd.offset(), value); @@ -1133,8 +1135,11 @@ class CompileReplay : public StackObj { Handle value = java_lang_String::create_from_str(string_value, CHECK); java_mirror->obj_field_put(fd.offset(), value()); } else if (field_signature[0] == JVM_SIGNATURE_CLASS) { - Klass* k = resolve_klass(string_value, CHECK); - oop value = InstanceKlass::cast(k)->allocate_instance(CHECK); + oop value = nullptr; + if (string_value != nullptr) { + Klass* k = resolve_klass(string_value, CHECK); + value = InstanceKlass::cast(k)->allocate_instance(CHECK); + } java_mirror->obj_field_put(fd.offset(), value); } else { report_error("unhandled staticfield"); diff --git a/test/hotspot/jtreg/compiler/ciReplay/TestNullStaticField.java b/test/hotspot/jtreg/compiler/ciReplay/TestNullStaticField.java new file mode 100644 index 00000000000..47a78ad5e44 --- /dev/null +++ b/test/hotspot/jtreg/compiler/ciReplay/TestNullStaticField.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. 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. + */ + +/* + * @test + * @bug 8333805 + * @library / /test/lib + * @summary Replaying compilation with null static final fields results in a crash + * @requires vm.flightRecorder != true & vm.compMode != "Xint" & vm.compMode != "Xcomp" & vm.debug == true & vm.compiler2.enabled + * @modules java.base/jdk.internal.misc + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.ciReplay.TestNullStaticField + */ + +package compiler.ciReplay; + +public class TestNullStaticField extends DumpReplayBase { + + public static void main(String[] args) { + new TestNullStaticField().runTest(TIERED_DISABLED_VM_OPTION); + } + + @Override + public void testAction() { + positiveTest(TIERED_DISABLED_VM_OPTION, "-XX:+ReplayIgnoreInitErrors"); + } + + @Override + public String getTestClass() { + return TestClassNullStaticField.class.getName(); + } + +} + +class TestClassNullStaticField { + + static final Object[] staticNullArrayField = null; + static final Object[][] staticNullMultiArrayField = null; + static final Object staticNullObjectField = null; + static final String staticNullStringField = null; + static final int[] staticNullIntArrayField = null; + static final Object[] staticNotNullArrayField = new A[10]; + static final Object[][] staticNotNullMultiArrayField = new A[10][10]; + static final Object staticNotNullObjectField = new A(); + static final String staticNotNullStringField = "Not null"; + static final int[] staticNotNullIntArrayField = new int[10]; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(); + } + } + public static void test() { + + } + + private static class A { + } +} +