From c253f9f8c19d9f7065caf65fa56a49aa511362ea Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 14 Apr 2023 13:08:53 -0700 Subject: [PATCH 1/2] Use JVMCI API for retrieving ConstantValue attributes --- .../heap/StandaloneImageHeapScanner.java | 8 +- .../StandaloneConstantReflectionProvider.java | 10 +- .../UninitializedStaticFieldValueReader.java | 125 ------------------ .../svm/hosted/ameta/ReadableJavaField.java | 13 +- 4 files changed, 23 insertions(+), 133 deletions(-) delete mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/UninitializedStaticFieldValueReader.java diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java index b793cde998bb..82cd850156da 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java @@ -35,11 +35,11 @@ import com.oracle.graal.pointsto.heap.value.ValueSupplier; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.graal.pointsto.meta.UninitializedStaticFieldValueReader; import com.oracle.graal.pointsto.util.AnalysisError; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaField; public class StandaloneImageHeapScanner extends ImageHeapScanner { private ClassLoader classLoader; @@ -65,7 +65,11 @@ protected Class getClass(String className) { protected ValueSupplier readHostedFieldValue(AnalysisField field, JavaConstant receiver) { ValueSupplier ret = super.readHostedFieldValue(field, receiver); if (ret.get() == null && field.isStatic()) { - JavaConstant constant = UninitializedStaticFieldValueReader.readUninitializedStaticValue(field.wrapped, value -> universe.getSnippetReflection().forObject(value)); + ResolvedJavaField wrappedField = field.getWrapped(); + JavaConstant constant = wrappedField.getConstantValue(); + if (constant == null) { + constant = JavaConstant.defaultForKind(wrappedField.getJavaKind()); + } return ValueSupplier.eagerValue(constant); } else { return ret; diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/meta/StandaloneConstantReflectionProvider.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/meta/StandaloneConstantReflectionProvider.java index 36a43f144d2f..dc6ad698955a 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/meta/StandaloneConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/meta/StandaloneConstantReflectionProvider.java @@ -29,7 +29,6 @@ import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.graal.pointsto.meta.UninitializedStaticFieldValueReader; import com.oracle.graal.pointsto.standalone.StandaloneHost; import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; @@ -50,10 +49,13 @@ public StandaloneConstantReflectionProvider(AnalysisUniverse universe, HotSpotJV @Override public final JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) { - AnalysisField analysisField = (AnalysisField) field; - JavaConstant ret = universe.lookup(super.readFieldValue(analysisField.wrapped, universe.toHosted(receiver))); + ResolvedJavaField wrappedField = ((AnalysisField) field).getWrapped(); + JavaConstant ret = universe.lookup(super.readFieldValue(wrappedField, universe.toHosted(receiver))); if (ret == null) { - ret = UninitializedStaticFieldValueReader.readUninitializedStaticValue(analysisField.wrapped, value -> universe.getSnippetReflection().forObject(value)); + ret = wrappedField.getConstantValue(); + if (ret == null) { + ret = JavaConstant.defaultForKind(wrappedField.getJavaKind()); + } } return ret; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/UninitializedStaticFieldValueReader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/UninitializedStaticFieldValueReader.java deleted file mode 100644 index ae509ea5fefd..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/UninitializedStaticFieldValueReader.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2022, 2022, Alibaba Group Holding Limited. 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package com.oracle.graal.pointsto.meta; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.function.Function; - -import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; -import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; -import com.oracle.graal.pointsto.util.AnalysisError; - -import jdk.internal.misc.Unsafe; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaField; - -public class UninitializedStaticFieldValueReader { - /* - * Static fields of classes that are initialized at run time have the default (uninitialized) - * value in the image heap. But there is one important exception: - * - * Fields that are static final and either primitive or of type String are initialized using the - * ConstantValue attribute of the class file, not using a class initializer. While we have class - * initializers available at run time, we no longer have the class files. So we need to preserve - * the values from the ConstantValue attribute in a different form. The easiest way is to just - * have these values as the default value of the static field in the image heap. - * - * Unfortunately, JVMCI does not allow us to access the default value: since the class is still - * uninitialized in the image generator, the JVMCI methods to read the field do not return a - * value. But the Java HotSpot VM actually already has the fields initialized to the values - * defined in the ConstantValue attributes. So reading the field via Unsafe actually produces - * the correct value that we want. - * - * Another complication are classes that are re-initialized at run time, i.e., initialized both - * during image generation and at run time. We must not return a value for a field that is - * initialized by a class initializer (that could be an arbitrary and wrong value from the image - * generator). Fortunately, the ConstantValue attribute is only used for static final fields of - * primitive types or the String type. By limiting the Unsafe read to these narrow cases, it is - * pretty likely (although not guaranteed) that we are not returning an unintended value for a - * class that is re-initialized at run time. - * - * GR-41856 should provide a proper JVMCI API to read the ConstantValue attribute of a field, - * which then makes this method unnecessary. - */ - public static JavaConstant readUninitializedStaticValue(ResolvedJavaField field, Function function) { - AnalysisError.guarantee(!(field instanceof AnalysisField), "must have been unwrapped"); - JavaKind kind = field.getJavaKind(); - - boolean canHaveConstantValueAttribute = kind.isPrimitive() || field.getType().getName().equals("Ljava/lang/String;"); - if (!canHaveConstantValueAttribute || !field.isFinal()) { - return JavaConstant.defaultForKind(kind); - } - - assert Modifier.isStatic(field.getModifiers()); - - /* On HotSpot the base of a static field is the Class object. */ - Object base = OriginalClassProvider.getJavaClass(field.getDeclaringClass()); - long offset = field.getOffset(); - - /* - * We cannot rely on the reflectionField because it can be null if there is some incomplete - * classpath issue or the field is either missing or hidden from reflection. However we can - * still use it to double check our assumptions. - */ - Field reflectionField = OriginalFieldProvider.getJavaField(field); - if (reflectionField != null) { - assert kind == JavaKind.fromJavaClass(reflectionField.getType()); - - Object reflectionFieldBase = Unsafe.getUnsafe().staticFieldBase(reflectionField); - long reflectionFieldOffset = Unsafe.getUnsafe().staticFieldOffset(reflectionField); - - AnalysisError.guarantee(reflectionFieldBase == base && reflectionFieldOffset == offset); - } - - switch (kind) { - case Boolean: - return JavaConstant.forBoolean(Unsafe.getUnsafe().getBoolean(base, offset)); - case Byte: - return JavaConstant.forByte(Unsafe.getUnsafe().getByte(base, offset)); - case Char: - return JavaConstant.forChar(Unsafe.getUnsafe().getChar(base, offset)); - case Short: - return JavaConstant.forShort(Unsafe.getUnsafe().getShort(base, offset)); - case Int: - return JavaConstant.forInt(Unsafe.getUnsafe().getInt(base, offset)); - case Long: - return JavaConstant.forLong(Unsafe.getUnsafe().getLong(base, offset)); - case Float: - return JavaConstant.forFloat(Unsafe.getUnsafe().getFloat(base, offset)); - case Double: - return JavaConstant.forDouble(Unsafe.getUnsafe().getDouble(base, offset)); - case Object: - Object value = Unsafe.getUnsafe().getObject(base, offset); - assert value == null || value instanceof String : "String is currently the only specified object type for the ConstantValue class file attribute"; - return function.apply(value); - default: - throw AnalysisError.shouldNotReachHereUnexpectedInput(kind); - } - } -} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java index 0657556e52aa..faa04224c354 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/ReadableJavaField.java @@ -25,7 +25,6 @@ package com.oracle.svm.hosted.ameta; import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.UninitializedStaticFieldValueReader; import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability.ValueAvailability; @@ -62,7 +61,17 @@ static JavaConstant readFieldValue(MetaAccessProvider metaAccess, ClassInitializ * is initialized in the hosting HotSpot VM can still be initialized at run time. */ if (field.isStatic()) { - return UninitializedStaticFieldValueReader.readUninitializedStaticValue(field, value -> GraalAccess.getOriginalSnippetReflection().forObject(value)); + /* + * Use the value from the constant pool attribute for the static field. That is the + * value before the class initializer is executed. + */ + JavaConstant constantValue = field.getConstantValue(); + if (constantValue != null) { + return constantValue; + } else { + return JavaConstant.defaultForKind(field.getJavaKind()); + } + } else { /* * Classes that are initialized at run time must not have instances in the image From 3c9ec52c797343307ed16d13bb5fa6872cf709fd Mon Sep 17 00:00:00 2001 From: Christian Wimmer Date: Fri, 14 Apr 2023 14:20:54 -0700 Subject: [PATCH 2/2] Update oraclejdk17 version for gates --- common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.json b/common.json index 217cbe78d0c1..c995b23c2e5e 100644 --- a/common.json +++ b/common.json @@ -10,7 +10,7 @@ "jdks": { "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "9", "release": true, "platformspecific": true, "extrabundles": ["static-libs"] }, - "oraclejdk17": {"name": "jpg-jdk", "version": "17.0.6", "build_id": "9", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, + "oraclejdk17": {"name": "jpg-jdk", "version": "17.0.7", "build_id": "8", "release": true, "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.0-b10", "platformspecific": true }, "labsjdk-ce-17Debug": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.0-b10-debug", "platformspecific": true }, "labsjdk-ce-17-llvm": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.0-b10-sulong", "platformspecific": true },