Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,21 @@
*/
package com.oracle.svm.core.fieldvaluetransformer;

import org.graalvm.nativeimage.hosted.FieldValueTransformer;

import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.util.JVMCIFieldValueTransformer;

import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaType;

/**
* Implements the field value transformation semantics of {@link Kind#ArrayBaseOffset}.
*/
public record ArrayBaseOffsetFieldValueTransformer(Class<?> targetClass, JavaKind returnKind) implements FieldValueTransformer {
public record ArrayBaseOffsetFieldValueTransformer(ResolvedJavaType targetClass, JavaKind returnKind) implements JVMCIFieldValueTransformer {

@Override
public Object transform(Object receiver, Object originalValue) {
return FieldOffsetFieldValueTransformer.box(returnKind, ConfigurationValues.getObjectLayout().getArrayBaseOffset(JavaKind.fromJavaClass(targetClass.getComponentType())));
public JavaConstant transform(JavaConstant receiver, JavaConstant originalValue) {
return FieldOffsetFieldValueTransformer.constant(returnKind, ConfigurationValues.getObjectLayout().getArrayBaseOffset(targetClass.getComponentType().getJavaKind()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,21 @@
*/
package com.oracle.svm.core.fieldvaluetransformer;

import org.graalvm.nativeimage.hosted.FieldValueTransformer;

import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.util.JVMCIFieldValueTransformer;

import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaType;

/**
* Implements the field value transformation semantics of {@link Kind#ArrayIndexScale}.
*/
public record ArrayIndexScaleFieldValueTransformer(Class<?> targetClass, JavaKind returnKind) implements FieldValueTransformer {
public record ArrayIndexScaleFieldValueTransformer(ResolvedJavaType targetClass, JavaKind returnKind) implements JVMCIFieldValueTransformer {

@Override
public Object transform(Object receiver, Object originalValue) {
return FieldOffsetFieldValueTransformer.box(returnKind, ConfigurationValues.getObjectLayout().getArrayIndexScale(JavaKind.fromJavaClass(targetClass.getComponentType())));
public JavaConstant transform(JavaConstant receiver, JavaConstant originalValue) {
return FieldOffsetFieldValueTransformer.constant(returnKind, ConfigurationValues.getObjectLayout().getArrayIndexScale(targetClass.getComponentType().getJavaKind()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,21 @@
*/
package com.oracle.svm.core.fieldvaluetransformer;

import org.graalvm.nativeimage.hosted.FieldValueTransformer;

import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.util.JVMCIFieldValueTransformer;

import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaType;

/**
* Implements the field value transformation semantics of {@link Kind#ArrayIndexShift}.
*/
public record ArrayIndexShiftFieldValueTransformer(Class<?> targetClass, JavaKind returnKind) implements FieldValueTransformer {
public record ArrayIndexShiftFieldValueTransformer(ResolvedJavaType targetClass, JavaKind returnKind) implements JVMCIFieldValueTransformer {

@Override
public Object transform(Object receiver, Object originalValue) {
return FieldOffsetFieldValueTransformer.box(returnKind, ConfigurationValues.getObjectLayout().getArrayIndexShift(JavaKind.fromJavaClass(targetClass.getComponentType())));
public JavaConstant transform(JavaConstant receiver, JavaConstant originalValue) {
return FieldOffsetFieldValueTransformer.constant(returnKind, ConfigurationValues.getObjectLayout().getArrayIndexShift(targetClass.getComponentType().getJavaKind()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
*/
package com.oracle.svm.core.fieldvaluetransformer;

import org.graalvm.nativeimage.hosted.FieldValueTransformer;

import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.JVMCIFieldValueTransformer;

import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.ResolvedJavaField;

/**
Expand All @@ -37,25 +37,25 @@
* When that value is the {@link #defaultValueForField default value for the field}, this
* transformer implements the field value transformation semantics of {@link Kind#Reset}.
*/
public record ConstantValueFieldValueTransformer(Object value) implements FieldValueTransformer {
public record ConstantValueFieldValueTransformer(JavaConstant value) implements JVMCIFieldValueTransformer {

public static FieldValueTransformer defaultValueForField(ResolvedJavaField field) {
public static JVMCIFieldValueTransformer defaultValueForField(ResolvedJavaField field) {
return new ConstantValueFieldValueTransformer(switch (field.getType().getJavaKind()) {
case Byte -> Byte.valueOf((byte) 0);
case Boolean -> Boolean.valueOf(false);
case Short -> Short.valueOf((short) 0);
case Char -> Character.valueOf((char) 0);
case Int -> Integer.valueOf(0);
case Long -> Long.valueOf(0);
case Float -> Float.valueOf(0);
case Double -> Double.valueOf(0);
case Object -> null;
case Byte -> JavaConstant.forByte((byte) 0);
case Boolean -> JavaConstant.FALSE;
case Short -> JavaConstant.forShort((short) 0);
case Char -> JavaConstant.forChar((char) 0);
case Int -> JavaConstant.INT_0;
case Long -> JavaConstant.LONG_0;
case Float -> JavaConstant.FLOAT_0;
case Double -> JavaConstant.DOUBLE_0;
case Object -> JavaConstant.NULL_POINTER;
default -> throw VMError.shouldNotReachHere(String.valueOf(field));
});
}

@Override
public Object transform(Object receiver, Object originalValue) {
public JavaConstant transform(JavaConstant receiver, JavaConstant originalValue) {
return value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ static Object box(JavaKind returnKind, int value) {
}
}

static JavaConstant constant(JavaKind returnKind, int value) {
return switch (returnKind) {
case Int -> JavaConstant.forInt(value);
case Long -> JavaConstant.forLong(value);
default -> throw VMError.shouldNotReachHere("Unexpected kind: " + returnKind);
};
}

@Override
public ValueNode intrinsify(CoreProviders providers, JavaConstant receiver) {
return FieldOffsetNode.create(returnKind, providers.getMetaAccess().lookupJavaField(targetField));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,65 @@
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.hosted.FieldValueTransformer;

import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.spi.CoreProviders;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.GraalAccess;

import jdk.graal.compiler.api.replacements.SnippetReflectionProvider;
import jdk.vm.ci.meta.JavaConstant;

/**
* Temporary implementation of {@link JVMCIFieldValueTransformerWithAvailability}, that falls back
* to {@link FieldValueTransformer}. Usages should be migrated to
* {@link JVMCIFieldValueTransformerWithAvailability} (GR-72015).
*/
@Platforms(Platform.HOSTED_ONLY.class)
public interface FieldValueTransformerWithAvailability extends FieldValueTransformer {
public interface FieldValueTransformerWithAvailability extends FieldValueTransformer, JVMCIFieldValueTransformerWithAvailability {

/**
* Returns true when the value for this custom computation is available.
*/
@Override
boolean isAvailable();

@Override
Object transform(Object receiver, Object originalValue);

@Override
default JavaConstant transform(JavaConstant receiver, JavaConstant originalValue) {
return transformAndConvert(this, receiver, originalValue);
}

/**
* Optionally provide a Graal IR node to intrinsify the field access before the static analysis.
* This allows the compiler to optimize field values that are not available yet, as long as
* there is a dedicated high-level node available.
* Transform a field value using a {@linkplain FieldValueTransformer core reflection based field
* value transformer}. The {@link JavaConstant} inputs are unwrapped, the returned
* {@link Object} is wrapped. This is only a temporary helper. Eventually, core reflection based
* field value transformers will be executed via {@link com.oracle.graal.vmaccess.VMAccess}.
*/
@SuppressWarnings("unused")
default ValueNode intrinsify(CoreProviders providers, JavaConstant receiver) {
return null;
static JavaConstant transformAndConvert(FieldValueTransformer fieldValueTransformer, JavaConstant receiver, JavaConstant originalValue) {
SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection();
VMError.guarantee(originalValue != null, "Original value should not be `null`. Use `JavaConstant.NULL_POINTER`.");
VMError.guarantee(receiver == null || !receiver.isNull(), "Receiver should not be a boxed `null` (`JavaConstant.isNull()`) for static fields. Use `null`instead");
Object reflectionReceiver = toObject(receiver);
Object reflectionOriginalValue = toObject(originalValue);
Object newObject = fieldValueTransformer.transform(reflectionReceiver, reflectionOriginalValue);
if (newObject == null) {
return JavaConstant.NULL_POINTER;
}
if (newObject instanceof JavaConstantWrapper constantWrapper) {
return constantWrapper.constant();
}
return originalSnippetReflection.forObject(newObject);
}

private static Object toObject(JavaConstant javaConstant) {
if (javaConstant == null || javaConstant.isNull()) {
return null;
}
if (javaConstant.getJavaKind().isObject()) {
SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection();
return originalSnippetReflection.asObject(Object.class, javaConstant);
}
return javaConstant.asBoxedPrimitive();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2025, 2025, 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
* 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.svm.core.fieldvaluetransformer;

import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;

import com.oracle.svm.util.JVMCIFieldValueTransformer;

import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.spi.CoreProviders;
import jdk.vm.ci.meta.JavaConstant;

@Platforms(Platform.HOSTED_ONLY.class)
public interface JVMCIFieldValueTransformerWithAvailability extends JVMCIFieldValueTransformer {

/**
* Returns true when the value for this custom computation is available.
*/
@Override
boolean isAvailable();

// remove this override once GR-72015 is fixed.
@Override
JavaConstant transform(JavaConstant receiver, JavaConstant originalValue);

/**
* Optionally provide a Graal IR node to intrinsify the field access before the static analysis.
* This allows the compiler to optimize field values that are not available yet, as long as
* there is a dedicated high-level node available.
*/
@SuppressWarnings("unused")
default ValueNode intrinsify(CoreProviders providers, JavaConstant receiver) {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,30 @@
*/
package com.oracle.svm.core.fieldvaluetransformer;

import java.lang.reflect.Array;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.GraalAccess;
import com.oracle.svm.util.JVMCIFieldValueTransformer;
import com.oracle.svm.util.JVMCIReflectionUtil;

import org.graalvm.nativeimage.hosted.FieldValueTransformer;
import jdk.graal.compiler.phases.util.Providers;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.MetaAccessProvider;

/**
* Reset an array field to a new empty array of the same type and length.
*/
public final class NewEmptyArrayFieldValueTransformer implements FieldValueTransformer {
public static final FieldValueTransformer INSTANCE = new NewEmptyArrayFieldValueTransformer();
public final class NewEmptyArrayFieldValueTransformer implements JVMCIFieldValueTransformer {
public static final JVMCIFieldValueTransformer INSTANCE = new NewEmptyArrayFieldValueTransformer();

@Override
public Object transform(Object receiver, Object originalValue) {
if (originalValue == null) {
return null;
public JavaConstant transform(JavaConstant receiver, JavaConstant originalValue) {
if (originalValue.isNull()) {
return JavaConstant.NULL_POINTER;
}
int originalLength = Array.getLength(originalValue);
return Array.newInstance(originalValue.getClass().getComponentType(), originalLength);
Providers originalProviders = GraalAccess.getOriginalProviders();
MetaAccessProvider metaAccess = originalProviders.getMetaAccess();
Integer originalLength = originalProviders.getConstantReflection().readArrayLength(originalValue);
VMError.guarantee(originalLength != null, "Original value is not an array or the array length is not known");
return JVMCIReflectionUtil.newArrayInstance(metaAccess.lookupJavaType(originalValue).getComponentType(), originalLength);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,24 @@
*/
package com.oracle.svm.core.fieldvaluetransformer;

import org.graalvm.nativeimage.hosted.FieldValueTransformer;

import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
import com.oracle.svm.util.ReflectionUtil;
import com.oracle.svm.util.JVMCIFieldValueTransformer;
import com.oracle.svm.util.JVMCIReflectionUtil;

import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.ResolvedJavaType;

/**
* Implements the field value transformation semantics of {@link Kind#NewInstance} and
* {@link Kind#NewInstanceWhenNotNull}.
*/
public record NewInstanceOfFixedClassFieldValueTransformer(Class<?> clazz, boolean onlyIfOriginalNotNull) implements FieldValueTransformer {
public record NewInstanceOfFixedClassFieldValueTransformer(ResolvedJavaType type, boolean onlyIfOriginalNotNull) implements JVMCIFieldValueTransformer {

@Override
public Object transform(Object receiver, Object originalValue) {
if (onlyIfOriginalNotNull && originalValue == null) {
return null;
public JavaConstant transform(JavaConstant receiver, JavaConstant originalValue) {
if (onlyIfOriginalNotNull && originalValue.isNull()) {
return JavaConstant.NULL_POINTER;
}
return ReflectionUtil.newInstance(clazz);
return JVMCIReflectionUtil.newInstance(type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
import com.oracle.svm.core.annotate.Delete;
import com.oracle.svm.core.reflect.SubstrateAccessor;

/**
* Should be migrated to JVMCI (GR-71897).
*/
public interface ReflectionSubstitutionSupport {

static ReflectionSubstitutionSupport singleton() {
Expand Down
Loading