From 72d0f43791bf8708e95baab494d9cd623100c0e6 Mon Sep 17 00:00:00 2001 From: Christian Humer Date: Tue, 22 Apr 2025 20:40:55 +0200 Subject: [PATCH 1/2] Refactor frame immutable field read intrinsics and fix them for native-image hosts. --- .../host/InjectImmutableFrameFieldsPhase.java | 102 -------------- .../truffle/host/TruffleKnownHostTypes.java | 4 - .../hotspot/HotSpotTruffleCompilerImpl.java | 11 +- ...TruffleCommunityCompilerConfiguration.java | 11 +- .../TruffleGraphBuilderPlugins.java | 1 - .../TruffleInvocationPlugins.java | 126 ++++++++++++++++-- .../svm/truffle/TruffleBaseFeature.java | 6 - .../api/bytecode/BytecodeDSLAccess.java | 4 +- .../truffle/api/impl/FrameWithoutBoxing.java | 21 ++- .../truffle/runtime/OptimizedCallTarget.java | 6 +- 10 files changed, 145 insertions(+), 147 deletions(-) delete mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/InjectImmutableFrameFieldsPhase.java diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/InjectImmutableFrameFieldsPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/InjectImmutableFrameFieldsPhase.java deleted file mode 100644 index d8a3ce373041..000000000000 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/InjectImmutableFrameFieldsPhase.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2022, 2024, 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 jdk.graal.compiler.truffle.host; - -import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.java.LoadFieldNode; -import jdk.graal.compiler.options.Option; -import jdk.graal.compiler.options.OptionKey; -import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.phases.BasePhase; -import jdk.graal.compiler.phases.PhaseSuite; -import jdk.graal.compiler.phases.common.HighTierLoweringPhase; -import jdk.graal.compiler.phases.tiers.HighTierContext; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaType; - -/** - * This phase should ideally already be done using a node plugin when creating the graph. - */ -public final class InjectImmutableFrameFieldsPhase extends BasePhase { - - public static class Options { - @Option(help = "Whether Truffle should mark final frame fields as immutable.")// - public static final OptionKey TruffleImmutableFrameFields = new OptionKey<>(true); - } - - InjectImmutableFrameFieldsPhase() { - } - - @Override - protected void run(StructuredGraph graph, HighTierContext context) { - TruffleHostEnvironment env = TruffleHostEnvironment.get(graph.method()); - if (env == null) { - return; - } - ResolvedJavaType frameType = env.types().FrameWithoutBoxing; - ResolvedJavaType frameDescriptorType = env.types().FrameDescriptor; - for (Node node : graph.getNodes()) { - if (node instanceof LoadFieldNode) { - LoadFieldNode fieldNode = (LoadFieldNode) node; - if ((isForcedImmutable(env, fieldNode.field(), frameType) || isForcedImmutable(env, fieldNode.field(), frameDescriptorType)) && - !fieldNode.getLocationIdentity().isImmutable()) { - graph.replaceFixedWithFixed(fieldNode, graph.add(LoadFieldNode.createOverrideImmutable(fieldNode))); - } - } - } - } - - private static boolean isForcedImmutable(TruffleHostEnvironment env, ResolvedJavaField field, ResolvedJavaType frameType) { - if (env == null) { - return false; - } - if (field.isStatic()) { - return false; - } - if (!field.isFinal()) { - return false; - } - if (field.isVolatile()) { - /* - * Do not handle volatile fields. - */ - return false; - } - if (!field.getDeclaringClass().equals(frameType)) { - return false; - } - return true; - } - - public static void install(PhaseSuite highTier, OptionValues options) { - // before lowering phase. - if (Options.TruffleImmutableFrameFields.getValue(options)) { - var phase = highTier.findPhase(HighTierLoweringPhase.class); - phase.previous(); - phase.add(new InjectImmutableFrameFieldsPhase()); - } - } -} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleKnownHostTypes.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleKnownHostTypes.java index ecd7dad0df73..8af808c93f59 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleKnownHostTypes.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleKnownHostTypes.java @@ -40,11 +40,7 @@ public final class TruffleKnownHostTypes extends AbstractKnownTruffleTypes { // Checkstyle: stop field name check - // truffle.api.frame - public final ResolvedJavaType FrameDescriptor = lookupTypeCached("com.oracle.truffle.api.frame.FrameDescriptor"); - // truffle.api.impl - public final ResolvedJavaType FrameWithoutBoxing = lookupType("com.oracle.truffle.api.impl.FrameWithoutBoxing"); public final ResolvedJavaType OptimizedCallTarget = lookupTypeCached("com.oracle.truffle.runtime.OptimizedCallTarget"); public final ResolvedJavaMethod OptimizedCallTarget_call = findMethod(OptimizedCallTarget, "call", lookupType(Object[].class)); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java index 81db62ebc7f3..ad99e1387c99 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java @@ -36,9 +36,6 @@ import java.util.concurrent.ThreadFactory; import java.util.function.Supplier; -import jdk.graal.compiler.core.GraalCompiler; -import jdk.graal.compiler.hotspot.HotSpotGraalServiceThread; -import jdk.graal.compiler.truffle.host.TruffleHostEnvironment.TruffleRuntimeScope; import org.graalvm.collections.EconomicMap; import com.oracle.truffle.compiler.TruffleCompilable; @@ -50,6 +47,7 @@ import jdk.graal.compiler.api.runtime.GraalJVMCICompiler; import jdk.graal.compiler.code.CompilationResult; import jdk.graal.compiler.core.CompilationWrapper.ExceptionAction; +import jdk.graal.compiler.core.GraalCompiler; import jdk.graal.compiler.core.common.CompilationIdentifier; import jdk.graal.compiler.core.target.Backend; import jdk.graal.compiler.debug.DebugContext; @@ -66,6 +64,7 @@ import jdk.graal.compiler.hotspot.HotSpotGraalCompilerFactory; import jdk.graal.compiler.hotspot.HotSpotGraalOptionValues; import jdk.graal.compiler.hotspot.HotSpotGraalRuntimeProvider; +import jdk.graal.compiler.hotspot.HotSpotGraalServiceThread; import jdk.graal.compiler.hotspot.HotSpotGraalServices; import jdk.graal.compiler.hotspot.HotSpotGraphBuilderInstance; import jdk.graal.compiler.hotspot.meta.HotSpotLoweringProvider; @@ -100,7 +99,7 @@ import jdk.graal.compiler.truffle.TruffleCompilerImpl; import jdk.graal.compiler.truffle.TruffleTierConfiguration; import jdk.graal.compiler.truffle.host.HostInliningPhase; -import jdk.graal.compiler.truffle.host.InjectImmutableFrameFieldsPhase; +import jdk.graal.compiler.truffle.host.TruffleHostEnvironment.TruffleRuntimeScope; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.CompiledCode; import jdk.vm.ci.code.InstalledCode; @@ -153,9 +152,7 @@ public static HotSpotTruffleCompilerImpl create(final TruffleCompilerRuntime run /* * Host inlining is not necessary for Truffle guest compilation so disable it. */ - options = new OptionValues(options, - HostInliningPhase.Options.TruffleHostInlining, Boolean.FALSE, - InjectImmutableFrameFieldsPhase.Options.TruffleImmutableFrameFields, Boolean.FALSE); + options = new OptionValues(options, HostInliningPhase.Options.TruffleHostInlining, Boolean.FALSE); HotSpotGraalRuntimeProvider graalRuntime = (HotSpotGraalRuntimeProvider) getCompiler(options).getGraalRuntime(); SnippetReflectionProvider snippetReflection = graalRuntime.getRequiredCapability(SnippetReflectionProvider.class); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleCommunityCompilerConfiguration.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleCommunityCompilerConfiguration.java index 4a56cf4d972e..c9dda52d465d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleCommunityCompilerConfiguration.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleCommunityCompilerConfiguration.java @@ -24,21 +24,19 @@ */ package jdk.graal.compiler.truffle.hotspot; +import java.util.function.Supplier; + +import com.oracle.truffle.compiler.TruffleCompilerRuntime; + import jdk.graal.compiler.core.phases.CommunityCompilerConfiguration; import jdk.graal.compiler.core.phases.HighTier; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; import jdk.graal.compiler.nodes.spi.Replacements; import jdk.graal.compiler.options.OptionValues; -import jdk.graal.compiler.truffle.host.InjectImmutableFrameFieldsPhase; import jdk.graal.compiler.truffle.host.HostInliningPhase; import jdk.graal.compiler.truffle.substitutions.TruffleInvocationPlugins; - -import com.oracle.truffle.compiler.TruffleCompilerRuntime; - import jdk.vm.ci.code.Architecture; -import java.util.function.Supplier; - /** * Central place to register Truffle related compiler phases and plugins for host Java compilation * on HotSpot. @@ -63,7 +61,6 @@ public HighTier createHighTier(OptionValues options) { public static void installCommunityHighTier(OptionValues options, HighTier defaultHighTier) { HostInliningPhase.install(defaultHighTier, options); - InjectImmutableFrameFieldsPhase.install(defaultHighTier, options); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleGraphBuilderPlugins.java index e1241a74112f..574b737bdd35 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleGraphBuilderPlugins.java @@ -579,7 +579,6 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec public static void registerFrameWithoutBoxingPlugins(InvocationPlugins plugins, KnownTruffleTypes types, boolean canDelayIntrinsification) { Registration r = new Registration(plugins, new ResolvedJavaSymbol(types.FrameWithoutBoxing)); registerFrameMethods(r, types); - registerUnsafeCast(r, types, canDelayIntrinsification); registerUnsafeLoadStorePlugins(r, canDelayIntrinsification, null, JavaKind.Long, JavaKind.Object); registerFrameAccessors(r, types, JavaKind.Object); registerFrameAccessors(r, types, JavaKind.Long); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleInvocationPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleInvocationPlugins.java index fc315a6593ad..f3bfd4196407 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleInvocationPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleInvocationPlugins.java @@ -35,25 +35,32 @@ import jdk.graal.compiler.core.common.Stride; import jdk.graal.compiler.core.common.StrideUtil; +import jdk.graal.compiler.core.common.calc.CanonicalCondition; import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.core.common.type.TypeReference; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.lir.gen.LIRGeneratorTool.ArrayIndexOfVariant; import jdk.graal.compiler.nodes.ComputeObjectAddressNode; +import jdk.graal.compiler.nodes.ConditionAnchorNode; import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.LogicConstantNode; +import jdk.graal.compiler.nodes.LogicNode; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.PiNode; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.calc.AddNode; +import jdk.graal.compiler.nodes.calc.CompareNode; import jdk.graal.compiler.nodes.calc.LeftShiftNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.InlineOnlyInvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; +import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.RequiredInvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins.OptionalLazySymbol; +import jdk.graal.compiler.nodes.java.LoadFieldNode; import jdk.graal.compiler.nodes.spi.Replacements; import jdk.graal.compiler.replacements.InvocationPluginHelper; import jdk.graal.compiler.replacements.nodes.ArrayCopyWithConversionsNode; @@ -64,11 +71,13 @@ import jdk.graal.compiler.replacements.nodes.CalcStringAttributesMacroNode; import jdk.graal.compiler.replacements.nodes.MacroNode; import jdk.graal.compiler.replacements.nodes.VectorizedHashCodeNode; +import jdk.graal.compiler.truffle.substitutions.TruffleGraphBuilderPlugins.Options; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -83,32 +92,125 @@ public static void register(Architecture architecture, InvocationPlugins plugins registerTStringPlugins(plugins, replacements, architecture); registerArrayUtilsPlugins(plugins, replacements); } + registerFramePlugins(plugins, replacements); registerBytecodePlugins(plugins, replacements); } + private static void registerFramePlugins(InvocationPlugins plugins, Replacements replacements) { + plugins.registerIntrinsificationPredicate(t -> t.getName().equals("Lcom/oracle/truffle/api/impl/FrameWithoutBoxing;")); + InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins, "com.oracle.truffle.api.impl.FrameWithoutBoxing", replacements); + r.register(new RequiredInvocationPlugin("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, boolean.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull, + ValueNode isExactType) { + if (!clazz.isConstant() || !nonNull.isConstant() || !isExactType.isConstant()) { + b.push(JavaKind.Object, object); + return true; + } + if (!Options.TruffleTrustedTypeCast.getValue(b.getOptions())) { + b.push(JavaKind.Object, object); + return true; + } + ConstantReflectionProvider constantReflection = b.getConstantReflection(); + ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant()); + if (javaType == null) { + b.push(JavaKind.Object, object); + return true; + } + + TypeReference type; + if (isExactType.asJavaConstant().asInt() != 0) { + assert javaType.isConcrete() || javaType.isArray() : "exact type is not a concrete class: " + javaType; + type = TypeReference.createExactTrusted(javaType); + } else { + type = TypeReference.createTrusted(b.getAssumptions(), javaType); + } + + boolean trustedNonNull = nonNull.asJavaConstant().asInt() != 0 && Options.TruffleTrustedNonNullCast.getValue(b.getOptions()); + Stamp piStamp = StampFactory.object(type, trustedNonNull); + + ConditionAnchorNode valueAnchorNode = null; + if (condition.isConstant() && condition.asJavaConstant().asInt() == 1) { + // Nothing to do. + } else { + boolean skipAnchor = false; + LogicNode compareNode = CompareNode.createCompareNode(object.graph(), CanonicalCondition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), constantReflection, + NodeView.DEFAULT); + if (compareNode instanceof LogicConstantNode) { + LogicConstantNode logicConstantNode = (LogicConstantNode) compareNode; + if (logicConstantNode.getValue()) { + skipAnchor = true; + } + } + if (!skipAnchor) { + valueAnchorNode = b.add(new ConditionAnchorNode(compareNode)); + } + } + + ValueNode loadNode = makeReadImmutable(b, object); + b.addPush(JavaKind.Object, PiNode.create(loadNode, piStamp, valueAnchorNode)); + return true; + } + + @Override + public boolean inlineOnly() { + return true; + } + + @Override + public boolean isOptional() { + return true; + } + }); + } + + private static ValueNode makeReadImmutable(GraphBuilderContext b, ValueNode object) { + ValueNode loadNode = object; + if (loadNode instanceof LoadFieldNode cast && canBeImmutable(cast.field())) { + loadNode = b.add(LoadFieldNode.createOverrideImmutable(cast)); + } + return loadNode; + } + + private static boolean canBeImmutable(ResolvedJavaField field) { + if (field.isStatic()) { + return false; + } + if (!field.isFinal()) { + return false; + } + if (field.isVolatile()) { + /* + * Do not handle volatile fields. + */ + return false; + } + return true; + } + private static void registerBytecodePlugins(InvocationPlugins plugins, Replacements replacements) { plugins.registerIntrinsificationPredicate(t -> t.getName().equals("Lcom/oracle/truffle/api/bytecode/BytecodeDSLUncheckedAccess;")); InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins, "com.oracle.truffle.api.bytecode.BytecodeDSLUncheckedAccess", replacements); - r.register(new InvocationPlugin("uncheckedCast", Receiver.class, Object.class, Class.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode clazz) { - if (clazz.isConstant()) { - ConstantReflectionProvider constantReflection = b.getConstantReflection(); - ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant()); - if (javaType == null) { - b.push(JavaKind.Object, object); - } else { - TypeReference type = TypeReference.createTrustedWithoutAssumptions(javaType); - Stamp piStamp = StampFactory.object(type, true); - b.addPush(JavaKind.Object, PiNode.create(object, piStamp, null)); - } + if (!clazz.isConstant()) { + b.push(JavaKind.Object, object); return true; - } else { + } + ConstantReflectionProvider constantReflection = b.getConstantReflection(); + ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant()); + if (javaType == null) { b.push(JavaKind.Object, object); return true; } + + TypeReference type = TypeReference.createTrustedWithoutAssumptions(javaType); + Stamp piStamp = StampFactory.object(type, true); + b.addPush(JavaKind.Object, PiNode.create(makeReadImmutable(b, object), piStamp, null)); + + return true; } @Override diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java index 0eaeb9171033..2fa292fd376b 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java @@ -101,7 +101,6 @@ import com.oracle.svm.core.heap.Pod; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.HostedOptionKey; -import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.reflect.target.ReflectionSubstitutionSupport; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; @@ -155,7 +154,6 @@ import jdk.graal.compiler.options.Option; import jdk.graal.compiler.phases.tiers.Suites; import jdk.graal.compiler.phases.util.Providers; -import jdk.graal.compiler.truffle.host.InjectImmutableFrameFieldsPhase; import jdk.graal.compiler.truffle.host.TruffleHostEnvironment; import jdk.graal.compiler.truffle.substitutions.TruffleInvocationPlugins; import jdk.internal.misc.Unsafe; @@ -184,7 +182,6 @@ private static MethodHandle findVersionGetComponent() { } private static final String NATIVE_IMAGE_FILELIST_FILE_NAME = "native-image-resources.filelist"; - private static final Version NEXT_POLYGLOT_VERSION_UPDATE = Version.create(29, 1); private static final int MAX_JDK_VERSION = 29; @@ -785,9 +782,6 @@ public void registerGraalPhases(Providers providers, Suites suites, boolean host * Please keep this code in sync with the HotSpot configuration in * TruffleCommunityCompilerConfiguration. */ - if (hosted) { - InjectImmutableFrameFieldsPhase.install(suites.getHighTier(), HostedOptionValues.singleton()); - } } @Override diff --git a/truffle/src/com.oracle.truffle.api.bytecode/src/com/oracle/truffle/api/bytecode/BytecodeDSLAccess.java b/truffle/src/com.oracle.truffle.api.bytecode/src/com/oracle/truffle/api/bytecode/BytecodeDSLAccess.java index d11a7cd242e8..2c7fb851daf7 100644 --- a/truffle/src/com.oracle.truffle.api.bytecode/src/com/oracle/truffle/api/bytecode/BytecodeDSLAccess.java +++ b/truffle/src/com.oracle.truffle.api.bytecode/src/com/oracle/truffle/api/bytecode/BytecodeDSLAccess.java @@ -131,7 +131,9 @@ private static BytecodeDSLAccess createUnsafe() { public abstract void writeObject(T[] arr, int index, T value); /** - * Casts a value to the given class. Also assumes non-null. + * Casts a value to the given class. Also assumes non-null. If used in the form + * uncheckedCast(this.field, ...) and the field is a final field, then the field will get + * transformed into an immutable field read. * * @since 24.2 */ diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java index ebc1029e7581..de0c5fa02fa3 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/FrameWithoutBoxing.java @@ -215,7 +215,7 @@ void reset() { @Override public Object[] getArguments() { - return unsafeCast(arguments, Object[].class, true, true, true); + return unsafeCast(this.arguments, Object[].class, true, true, true); } @Override @@ -236,7 +236,7 @@ private static int narrow(long value) { @Override public FrameDescriptor getFrameDescriptor() { - return unsafeCast(descriptor, FrameDescriptor.class, true, true, false); + return unsafeCast(this.descriptor, FrameDescriptor.class, true, true, false); } private static FrameSlotTypeException frameSlotTypeException(int slot, byte expectedTag, byte actualTag) throws FrameSlotTypeException { @@ -267,6 +267,17 @@ byte unsafeGetTag(int slotIndex) { return unsafeGetIndexedTag(slotIndex); } + /** + * Intrinsifiable compiler directive to tighten the type information for {@code value}. This + * method is intrinsified for host and guest compilation. If used in the form + * unsafeCast(this.field, ...) and the field is a final field, then the field will get + * transformed into an immutable field read. + * + * @param type the type the compiler should assume for {@code value} + * @param condition the condition that guards the assumptions expressed by this directive + * @param nonNull the nullness info the compiler should assume for {@code value} + * @param exact if {@code true}, the compiler should assume exact type info + */ @SuppressWarnings({"unchecked", "unused"}) private static T unsafeCast(Object value, Class type, boolean condition, boolean nonNull, boolean exact) { return (T) value; @@ -368,7 +379,7 @@ public Object getValue(int slot) { } private Object[] getIndexedLocals() { - return unsafeCast(indexedLocals, Object[].class, true, true, true); + return unsafeCast(this.indexedLocals, Object[].class, true, true, true); } private long[] getIndexedPrimitiveLocals() { @@ -376,7 +387,7 @@ private long[] getIndexedPrimitiveLocals() { } private byte[] getIndexedTags() { - return unsafeCast(indexedTags, byte[].class, true, true, true); + return unsafeCast(this.indexedTags, byte[].class, true, true, true); } @Override @@ -659,7 +670,7 @@ public void swap(int first, int second) { } private void verifyIndexedSet(int slot, byte tag) { - assert (indexedTags[slot] & STATIC_TAG) == 0 : UNEXPECTED_NON_STATIC_WRITE; + assert (getIndexedTags()[slot] & STATIC_TAG) == 0 : UNEXPECTED_NON_STATIC_WRITE; // this may raise an AIOOBE getIndexedTags()[slot] = tag; } diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedCallTarget.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedCallTarget.java index fd335c79359c..76091e3b3fcc 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedCallTarget.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedCallTarget.java @@ -1257,7 +1257,8 @@ public final String toString() { } /** - * Intrinsifiable compiler directive to tighten the type information for {@code args}. + * Intrinsifiable compiler directive to tighten the type information for {@code args}. This + * intrinsic only applies during runtime compilation. * * @param length the length of {@code args} that is guaranteed to be final at compile time */ @@ -1266,7 +1267,8 @@ static final Object[] castArrayFixedLength(Object[] args, int length) { } /** - * Intrinsifiable compiler directive to tighten the type information for {@code value}. + * Intrinsifiable compiler directive to tighten the type information for {@code value}. This + * intrinsic only applies during runtime compilation. * * @param type the type the compiler should assume for {@code value} * @param condition the condition that guards the assumptions expressed by this directive From 942b27838bbbece2881daa1a06b58654dfe1b5a2 Mon Sep 17 00:00:00 2001 From: Christian Humer Date: Wed, 23 Apr 2025 12:51:51 +0200 Subject: [PATCH 2/2] Cleanup invocation plugins. --- .../graphbuilderconf/InvocationPlugin.java | 12 +++++++ .../TruffleInvocationPlugins.java | 32 ++++--------------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/InvocationPlugin.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/InvocationPlugin.java index b807423be54b..b386a054ec0c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/InvocationPlugin.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/InvocationPlugin.java @@ -518,4 +518,16 @@ public final boolean inlineOnly() { return true; } } + + public abstract static class OptionalInlineOnlyInvocationPlugin extends OptionalInvocationPlugin { + + public OptionalInlineOnlyInvocationPlugin(String name, Type... argumentTypes) { + super(name, argumentTypes); + } + + @Override + public final boolean inlineOnly() { + return true; + } + } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleInvocationPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleInvocationPlugins.java index f3bfd4196407..3e565f454c06 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleInvocationPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/substitutions/TruffleInvocationPlugins.java @@ -56,8 +56,8 @@ import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.InlineOnlyInvocationPlugin; +import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.OptionalInlineOnlyInvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; -import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.RequiredInvocationPlugin; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins.OptionalLazySymbol; import jdk.graal.compiler.nodes.java.LoadFieldNode; @@ -99,7 +99,7 @@ public static void register(Architecture architecture, InvocationPlugins plugins private static void registerFramePlugins(InvocationPlugins plugins, Replacements replacements) { plugins.registerIntrinsificationPredicate(t -> t.getName().equals("Lcom/oracle/truffle/api/impl/FrameWithoutBoxing;")); InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins, "com.oracle.truffle.api.impl.FrameWithoutBoxing", replacements); - r.register(new RequiredInvocationPlugin("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, boolean.class) { + r.register(new OptionalInlineOnlyInvocationPlugin("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, boolean.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull, ValueNode isExactType) { @@ -147,24 +147,14 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } } - ValueNode loadNode = makeReadImmutable(b, object); + ValueNode loadNode = isTrustedImmutable(b, object); b.addPush(JavaKind.Object, PiNode.create(loadNode, piStamp, valueAnchorNode)); return true; } - - @Override - public boolean inlineOnly() { - return true; - } - - @Override - public boolean isOptional() { - return true; - } }); } - private static ValueNode makeReadImmutable(GraphBuilderContext b, ValueNode object) { + private static ValueNode isTrustedImmutable(GraphBuilderContext b, ValueNode object) { ValueNode loadNode = object; if (loadNode instanceof LoadFieldNode cast && canBeImmutable(cast.field())) { loadNode = b.add(LoadFieldNode.createOverrideImmutable(cast)); @@ -191,7 +181,7 @@ private static boolean canBeImmutable(ResolvedJavaField field) { private static void registerBytecodePlugins(InvocationPlugins plugins, Replacements replacements) { plugins.registerIntrinsificationPredicate(t -> t.getName().equals("Lcom/oracle/truffle/api/bytecode/BytecodeDSLUncheckedAccess;")); InvocationPlugins.Registration r = new InvocationPlugins.Registration(plugins, "com.oracle.truffle.api.bytecode.BytecodeDSLUncheckedAccess", replacements); - r.register(new InvocationPlugin("uncheckedCast", Receiver.class, Object.class, Class.class) { + r.register(new OptionalInlineOnlyInvocationPlugin("uncheckedCast", Receiver.class, Object.class, Class.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode clazz) { @@ -208,20 +198,10 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec TypeReference type = TypeReference.createTrustedWithoutAssumptions(javaType); Stamp piStamp = StampFactory.object(type, true); - b.addPush(JavaKind.Object, PiNode.create(makeReadImmutable(b, object), piStamp, null)); + b.addPush(JavaKind.Object, PiNode.create(isTrustedImmutable(b, object), piStamp, null)); return true; } - - @Override - public boolean inlineOnly() { - return true; - } - - @Override - public boolean isOptional() { - return true; - } }); }