diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index 6be13578a177..c51b9d5131ab 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -38,7 +38,6 @@ import java.util.List; import java.util.Map; -import jdk.graal.compiler.serviceprovider.LibGraalService; import org.graalvm.word.LocationIdentity; import jdk.graal.compiler.core.common.CompressEncoding; @@ -70,6 +69,7 @@ import jdk.graal.compiler.hotspot.nodes.HotSpotDirectCallTargetNode; import jdk.graal.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode; import jdk.graal.compiler.hotspot.nodes.KlassBeingInitializedCheckNode; +import jdk.graal.compiler.hotspot.nodes.KlassFullyInitializedCheckNode; import jdk.graal.compiler.hotspot.nodes.VMErrorNode; import jdk.graal.compiler.hotspot.nodes.VirtualThreadUpdateJFRNode; import jdk.graal.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp; @@ -203,6 +203,7 @@ import jdk.graal.compiler.replacements.nodes.CStringConstant; import jdk.graal.compiler.replacements.nodes.LogNode; import jdk.graal.compiler.serviceprovider.GraalServices; +import jdk.graal.compiler.serviceprovider.LibGraalService; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.hotspot.HotSpotCallingConventionType; @@ -252,7 +253,7 @@ void initialize(HotSpotProviders providers, public interface Extensions { /** * Gets the extensions provided by this object. - * + *

* In the context of service caching done when building a libgraal image, implementations of * this method must return a new value each time to avoid sharing extensions between * different {@link DefaultHotSpotLoweringProvider}s. @@ -549,6 +550,10 @@ private boolean lowerWithoutDelegation(Node n, LoweringTool tool) { if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { getAllocationSnippets().lower((KlassBeingInitializedCheckNode) n, tool); } + } else if (n instanceof KlassFullyInitializedCheckNode) { + if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { + getAllocationSnippets().lower((KlassFullyInitializedCheckNode) n, tool); + } } else if (n instanceof FastNotifyNode) { if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { objectSnippets.lower(n, tool); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index c97523fe6261..c0d634dc6575 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -77,6 +77,7 @@ import jdk.graal.compiler.hotspot.nodes.CurrentJavaThreadNode; import jdk.graal.compiler.hotspot.nodes.HotSpotLoadReservedReferenceNode; import jdk.graal.compiler.hotspot.nodes.HotSpotStoreReservedReferenceNode; +import jdk.graal.compiler.hotspot.nodes.KlassFullyInitializedCheckNode; import jdk.graal.compiler.hotspot.replacements.CallSiteTargetNode; import jdk.graal.compiler.hotspot.replacements.DigestBaseSnippets; import jdk.graal.compiler.hotspot.replacements.FastNotifyNode; @@ -140,6 +141,7 @@ import jdk.graal.compiler.nodes.java.DynamicNewInstanceNode; import jdk.graal.compiler.nodes.java.DynamicNewInstanceWithExceptionNode; import jdk.graal.compiler.nodes.java.NewArrayNode; +import jdk.graal.compiler.nodes.java.ValidateNewInstanceClassNode; import jdk.graal.compiler.nodes.memory.address.AddressNode; import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; import jdk.graal.compiler.nodes.spi.Replacements; @@ -534,16 +536,18 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } /* Emits a null-check for the otherwise unused receiver. */ unsafe.get(true); + + ValidateNewInstanceClassNode clazzLegal = b.add(new ValidateNewInstanceClassNode(clazz)); /* - * Note that the provided clazz might not be initialized. The HotSpot lowering - * snippet for DynamicNewInstanceNode performs the necessary class initialization - * check. Such a DynamicNewInstanceNode is also never constant folded to a - * NewInstanceNode. + * Note that the provided clazz might not be initialized. The lowering snippet for + * KlassFullyInitializedCheckNode performs the necessary initialization check. */ + b.add(new KlassFullyInitializedCheckNode(clazzLegal)); + if (b.currentBlockCatchesOOM()) { - DynamicNewInstanceWithExceptionNode.createAndPush(b, clazz, true); + b.addPush(JavaKind.Object, new DynamicNewInstanceWithExceptionNode(clazzLegal, true)); } else { - DynamicNewInstanceNode.createAndPush(b, clazz, true); + b.addPush(JavaKind.Object, new DynamicNewInstanceNode(clazzLegal, true)); } return true; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/KlassBeingInitializedCheckNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/KlassBeingInitializedCheckNode.java index c94475ccc139..74ad79ae0ec8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/KlassBeingInitializedCheckNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/KlassBeingInitializedCheckNode.java @@ -27,15 +27,19 @@ import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_4; import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_16; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.nodeinfo.InputType; import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.DeoptimizingFixedWithNextNode; import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.memory.SingleMemoryKill; import jdk.graal.compiler.nodes.spi.Lowerable; -@NodeInfo(cycles = CYCLES_4, size = SIZE_16) -public class KlassBeingInitializedCheckNode extends DeoptimizingFixedWithNextNode implements Lowerable { +@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_4, size = SIZE_16) +public class KlassBeingInitializedCheckNode extends DeoptimizingFixedWithNextNode implements Lowerable, SingleMemoryKill { public static final NodeClass TYPE = NodeClass.create(KlassBeingInitializedCheckNode.class); @Input protected ValueNode klass; @@ -45,6 +49,15 @@ public KlassBeingInitializedCheckNode(ValueNode klass) { this.klass = klass; } + @Override + public LocationIdentity getKilledLocationIdentity() { + /* + * Since JDK-8338379, reading the class init state requires an ACQUIRE barrier, which orders + * memory accesses + */ + return LocationIdentity.ANY_LOCATION; + } + public ValueNode getKlass() { return klass; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/KlassFullyInitializedCheckNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/KlassFullyInitializedCheckNode.java new file mode 100644 index 000000000000..472783ddc59d --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/nodes/KlassFullyInitializedCheckNode.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 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.hotspot.nodes; + +import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_4; +import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_16; + +import org.graalvm.word.LocationIdentity; + +import jdk.graal.compiler.core.common.type.AbstractPointerStamp; +import jdk.graal.compiler.core.common.type.Stamp; +import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.nodeinfo.InputType; +import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodes.DeoptimizingFixedWithNextNode; +import jdk.graal.compiler.nodes.NodeView; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.memory.SingleMemoryKill; +import jdk.graal.compiler.nodes.spi.Lowerable; + +/** + * Checks that the input {@link Class}'s hub is either null or has been fully initialized, or + * deoptimizes otherwise. + */ +@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_4, size = SIZE_16) +public class KlassFullyInitializedCheckNode extends DeoptimizingFixedWithNextNode implements Lowerable, SingleMemoryKill { + public static final NodeClass TYPE = NodeClass.create(KlassFullyInitializedCheckNode.class); + + @Input protected ValueNode klass; + + public KlassFullyInitializedCheckNode(ValueNode klassNonNull) { + super(TYPE, StampFactory.forVoid()); + Stamp inputStamp = klassNonNull.stamp(NodeView.DEFAULT); + assert inputStamp instanceof AbstractPointerStamp : klassNonNull + " has wrong input stamp type for klass init state check: " + inputStamp; + assert ((AbstractPointerStamp) inputStamp).nonNull() : klassNonNull + " must have non-null stamp: " + inputStamp; + this.klass = klassNonNull; + } + + @Override + public LocationIdentity getKilledLocationIdentity() { + /* + * Since JDK-8338379, reading the class init state requires an ACQUIRE barrier, which orders + * memory accesses + */ + return LocationIdentity.ANY_LOCATION; + } + + public ValueNode getKlass() { + return klass; + } + + @Override + public boolean canDeoptimize() { + return true; + } + +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java index b6ff0fce93d5..7091b81a87d2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java @@ -88,6 +88,7 @@ import jdk.graal.compiler.hotspot.meta.HotSpotProviders; import jdk.graal.compiler.hotspot.meta.HotSpotRegistersProvider; import jdk.graal.compiler.hotspot.nodes.KlassBeingInitializedCheckNode; +import jdk.graal.compiler.hotspot.nodes.KlassFullyInitializedCheckNode; import jdk.graal.compiler.hotspot.nodes.type.KlassPointerStamp; import jdk.graal.compiler.hotspot.word.KlassPointer; import jdk.graal.compiler.nodes.ConstantNode; @@ -179,25 +180,21 @@ public Object allocateInstanceDynamic(@NonNullParameter Class type, KlassPointer hub = ClassGetHubNode.readClass(type); if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) { KlassPointer nonNullHub = ClassGetHubNode.piCastNonNull(hub, SnippetAnchorNode.anchor()); - - if (probability(VERY_FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(nonNullHub))) { - int layoutHelper = readLayoutHelper(nonNullHub); + // klass initialization check was already performed by KlassFullyInitializedCheckNode + int layoutHelper = readLayoutHelper(nonNullHub); + /* + * src/share/vm/oops/klass.hpp: For instances, layout helper is a positive number, the + * instance size. This size is already passed through align_object_size and scaled to + * bytes. The low order bit is set if instances of this class cannot be allocated using + * the fastpath. + */ + if (probability(FAST_PATH_PROBABILITY, (layoutHelper & 1) == 0)) { /* - * src/share/vm/oops/klass.hpp: For instances, layout helper is a positive number, - * the instance size. This size is already passed through align_object_size and - * scaled to bytes. The low order bit is set if instances of this class cannot be - * allocated using the fastpath. + * FIXME(je,ds): we should actually pass typeContext instead of "" but late binding + * of parameters is not yet supported by the GraphBuilderPlugin system. */ - if (probability(FAST_PATH_PROBABILITY, (layoutHelper & 1) == 0)) { - /* - * FIXME(je,ds): we should actually pass typeContext instead of "" but late - * binding of parameters is not yet supported by the GraphBuilderPlugin system. - */ - UnsignedWord size = WordFactory.unsigned(layoutHelper); - return allocateInstanceImpl(nonNullHub.asWord(), size, false, fillContents, emitMemoryBarrier, false, profilingData, withException); - } - } else { - DeoptimizeNode.deopt(None, RuntimeConstraint); + UnsignedWord size = WordFactory.unsigned(layoutHelper); + return allocateInstanceImpl(nonNullHub.asWord(), size, false, fillContents, emitMemoryBarrier, false, profilingData, withException); } } return PiNode.piCastToSnippetReplaceeStamp(dynamicNewInstanceStub(type, withException)); @@ -297,6 +294,17 @@ private void verifyHeap() { } } + @Snippet + private static void klassFullyInitializedCheck(@NonNullParameter Class klass) { + KlassPointer hub = ClassGetHubNode.readClass(klass); + if (probability(VERY_FAST_PATH_PROBABILITY, !hub.isNull())) { + KlassPointer nonNullHub = ClassGetHubNode.piCastNonNull(hub, SnippetAnchorNode.anchor()); + if (probability(DEOPT_PROBABILITY, !isInstanceKlassFullyInitialized(nonNullHub))) { + DeoptimizeNode.deopt(None, RuntimeConstraint); + } + } + } + @Snippet private void threadBeingInitializedCheck(KlassPointer klass) { int state = readInstanceKlassInitState(klass); @@ -548,6 +556,7 @@ public static class Templates extends AbstractTemplates { private final SnippetInfo newmultiarray; private final SnippetInfo verifyHeap; private final SnippetInfo threadBeingInitializedCheck; + private final SnippetInfo klassFullyInitializedCheck; @SuppressWarnings("this-escape") public Templates(HotSpotAllocationSnippets receiver, OptionValues options, SnippetCounter.Group.Factory groupFactory, HotSpotProviders providers, @@ -623,6 +632,12 @@ public Templates(HotSpotAllocationSnippets receiver, OptionValues options, Snipp receiver, CLASS_INIT_STATE_LOCATION, CLASS_INIT_THREAD_LOCATION); + klassFullyInitializedCheck = snippet(providers, + HotSpotAllocationSnippets.class, + "klassFullyInitializedCheck", + MARK_WORD_LOCATION, + HUB_WRITE_LOCATION, + CLASS_INIT_STATE_LOCATION); } private HotSpotAllocationProfilingData getProfilingData(OptionValues localOptions, String path, ResolvedJavaType type) { @@ -899,6 +914,13 @@ public void lower(KlassBeingInitializedCheckNode node, LoweringTool tool) { template(tool, node, args).instantiate(tool.getMetaAccess(), node, DEFAULT_REPLACER, args); } + public void lower(KlassFullyInitializedCheckNode node, LoweringTool tool) { + Arguments args = new Arguments(klassFullyInitializedCheck, node.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("klass", node.getKlass()); + + template(tool, node, args).instantiate(tool.getMetaAccess(), node, DEFAULT_REPLACER, args); + } + private static HotSpotResolvedObjectType lookupArrayClass(LoweringTool tool, JavaKind kind) { return HotSpotAllocationSnippets.lookupArrayClass(tool.getMetaAccess(), kind); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java index 978a9692e909..9a2ac7629edd 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java @@ -847,7 +847,7 @@ public static boolean isInstanceKlassFullyInitialized(KlassPointer hub) { } static byte readInstanceKlassInitState(KlassPointer hub) { - return hub.readByte(instanceKlassInitStateOffset(INJECTED_VMCONFIG), CLASS_INIT_STATE_LOCATION); + return hub.readByteVolatile(instanceKlassInitStateOffset(INJECTED_VMCONFIG), CLASS_INIT_STATE_LOCATION); } static Word readInstanceKlassInitThread(KlassPointer hub) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/MetaspacePointer.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/MetaspacePointer.java index 974da797ceab..9a1e4b826022 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/MetaspacePointer.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/word/MetaspacePointer.java @@ -27,15 +27,16 @@ import static jdk.graal.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.FROM_POINTER; import static jdk.graal.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.IS_NULL; -import jdk.graal.compiler.core.common.memory.BarrierType; -import jdk.graal.compiler.word.Word; -import jdk.graal.compiler.word.Word.Opcode; -import jdk.graal.compiler.word.Word.Operation; import org.graalvm.word.LocationIdentity; import org.graalvm.word.SignedWord; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordBase; +import jdk.graal.compiler.core.common.memory.BarrierType; +import jdk.graal.compiler.word.Word; +import jdk.graal.compiler.word.Word.Opcode; +import jdk.graal.compiler.word.Word.Operation; + /** * Marker type for a metaspace pointer. */ @@ -281,6 +282,16 @@ public abstract class MetaspacePointer { @Operation(opcode = Opcode.READ_POINTER) public abstract Object readObject(int offset, LocationIdentity locationIdentity); + /** + * Reads the memory at address {@code (this + offset)} in accordance with volatile semantics. + * Both the base address and offset are in bytes. + * + * @param offset the signed offset for the memory access + * @return the result of the memory access + */ + @Operation(opcode = Opcode.READ_POINTER_VOLATILE) + public abstract byte readByteVolatile(int offset, LocationIdentity locationIdentity); + /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in * bytes. diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/DynamicNewInstanceNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/DynamicNewInstanceNode.java index 4f9413892f71..ed59b522ee83 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/DynamicNewInstanceNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/DynamicNewInstanceNode.java @@ -35,11 +35,9 @@ import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.spi.Canonicalizable; import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodes.spi.CoreProviders; -import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; @@ -49,17 +47,7 @@ public final class DynamicNewInstanceNode extends AbstractNewObjectNode implemen @Input ValueNode clazz; - public static void createAndPush(GraphBuilderContext b, ValueNode clazz, boolean validateClass) { - ResolvedJavaType constantType = tryConvertToNonDynamic(clazz, b); - if (constantType != null) { - b.addPush(JavaKind.Object, new NewInstanceNode(constantType, true)); - } else { - ValueNode clazzLegal = validateClass ? b.add(new ValidateNewInstanceClassNode(clazz)) : clazz; - b.addPush(JavaKind.Object, new DynamicNewInstanceNode(clazzLegal, true)); - } - } - - protected DynamicNewInstanceNode(ValueNode clazz, boolean fillContents) { + public DynamicNewInstanceNode(ValueNode clazz, boolean fillContents) { super(TYPE, StampFactory.objectNonNull(), fillContents, null); this.clazz = clazz; assert ((ObjectStamp) clazz.stamp(NodeView.DEFAULT)).nonNull(); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/DynamicNewInstanceWithExceptionNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/DynamicNewInstanceWithExceptionNode.java index e08c2f291509..e375d6f64963 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/DynamicNewInstanceWithExceptionNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/DynamicNewInstanceWithExceptionNode.java @@ -26,6 +26,7 @@ import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_8; import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_8; +import static jdk.graal.compiler.nodes.java.DynamicNewInstanceNode.tryConvertToNonDynamic; import jdk.graal.compiler.core.common.type.StampFactory; import jdk.graal.compiler.graph.Node; @@ -33,31 +34,17 @@ import jdk.graal.compiler.nodeinfo.NodeInfo; import jdk.graal.compiler.nodes.FixedNode; import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.spi.Canonicalizable; import jdk.graal.compiler.nodes.spi.CanonicalizerTool; -import jdk.graal.compiler.nodes.spi.CoreProviders; -import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaType; @NodeInfo(cycles = CYCLES_8, cyclesRationale = "tlab alloc + header init", size = SIZE_8) public class DynamicNewInstanceWithExceptionNode extends AllocateWithExceptionNode implements Canonicalizable { + public static final NodeClass TYPE = NodeClass.create(DynamicNewInstanceWithExceptionNode.class); @Input ValueNode clazz; - - public static final NodeClass TYPE = NodeClass.create(DynamicNewInstanceWithExceptionNode.class); protected boolean fillContents; - public static void createAndPush(GraphBuilderContext b, ValueNode clazz, boolean validateClass) { - ResolvedJavaType constantType = tryConvertToNonDynamic(clazz, b); - if (constantType != null) { - b.addPush(JavaKind.Object, new NewInstanceWithExceptionNode(constantType, true)); - } else { - ValueNode clazzLegal = validateClass ? b.add(new ValidateNewInstanceClassNode(clazz)) : clazz; - b.addPush(JavaKind.Object, new DynamicNewInstanceWithExceptionNode(clazzLegal, true)); - } - } - public DynamicNewInstanceWithExceptionNode(ValueNode clazz, boolean fillContents) { super(TYPE, StampFactory.objectNonNull()); this.fillContents = fillContents; @@ -68,16 +55,6 @@ public ValueNode getInstanceType() { return clazz; } - static ResolvedJavaType tryConvertToNonDynamic(ValueNode clazz, CoreProviders tool) { - if (clazz.isConstant()) { - ResolvedJavaType type = tool.getConstantReflection().asJavaType(clazz.asConstant()); - if (type != null && !DynamicNewInstanceNode.throwsInstantiationException(type, tool.getMetaAccess()) && tool.getMetaAccessExtensionProvider().canConstantFoldDynamicAllocation(type)) { - return type; - } - } - return null; - } - @Override public Node canonical(CanonicalizerTool tool) { ResolvedJavaType type = tryConvertToNonDynamic(clazz, tool); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ValidateNewInstanceClassNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ValidateNewInstanceClassNode.java index 6daf0a4c505d..ca8f18b3239f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ValidateNewInstanceClassNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/java/ValidateNewInstanceClassNode.java @@ -24,6 +24,8 @@ */ package jdk.graal.compiler.nodes.java; +import org.graalvm.word.LocationIdentity; + import jdk.graal.compiler.core.common.type.AbstractPointerStamp; import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.nodeinfo.NodeCycles; @@ -36,7 +38,6 @@ import jdk.graal.compiler.nodes.spi.Lowerable; import jdk.graal.compiler.nodes.spi.Simplifiable; import jdk.graal.compiler.nodes.spi.SimplifierTool; -import org.graalvm.word.LocationIdentity; /** * This node represents the class type checks for a {@link DynamicNewInstanceNode} and throws any @@ -58,7 +59,7 @@ public final class ValidateNewInstanceClassNode extends WithExceptionNode implem public static final NodeClass TYPE = NodeClass.create(ValidateNewInstanceClassNode.class); - protected ValidateNewInstanceClassNode(ValueNode clazz) { + public ValidateNewInstanceClassNode(ValueNode clazz) { super(TYPE, AbstractPointerStamp.pointerNonNull(clazz.stamp(NodeView.DEFAULT))); this.clazz = clazz; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java index 744121972ef9..6f549169b378 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/SnippetTemplate.java @@ -970,7 +970,11 @@ protected SnippetInfo snippet(Providers providers, LocationIdentity... initialPrivateLocations) { assert methodName != null; ResolvedJavaMethod javaMethod = findMethod(providers.getMetaAccess(), declaringClass, methodName); - assert javaMethod != null : "did not find @" + Snippet.class.getSimpleName() + " method in " + declaringClass + " named " + methodName; + if (javaMethod.isStatic()) { + assert receiver == null : "static snippet " + javaMethod + " created with non-null receiver"; + } else { + assert receiver != null : "non-static snippet " + javaMethod + " created with null receiver"; + } providers.getReplacements().registerSnippet(javaMethod, original, receiver, GraalOptions.TrackNodeSourcePosition.getValue(options), options); LocationIdentity[] privateLocations = GraalOptions.SnippetCounters.getValue(options) ? SnippetCounterNode.addSnippetCounters(initialPrivateLocations) : initialPrivateLocations; if (IS_IN_NATIVE_IMAGE || GraalOptions.EagerSnippets.getValue(options)) { @@ -1838,9 +1842,10 @@ private boolean assertSnippetKills(ValueNode replacee) { EconomicSet kills = EconomicSet.create(Equivalence.DEFAULT); kills.addAll(memoryMap.getLocations()); - if (MemoryKill.isSingleMemoryKill(replacee)) { + if (MemoryKill.isMemoryKill(replacee)) { + assert !(MemoryKill.isMultiMemoryKill(replacee)) : replacee + " multi not supported (yet)"; // check if some node in snippet graph also kills the same location - LocationIdentity locationIdentity = ((SingleMemoryKill) replacee).getKilledLocationIdentity(); + LocationIdentity locationIdentity = MemoryKill.asSingleMemoryKill(replacee).getKilledLocationIdentity(); if (locationIdentity.isAny()) { // if the replacee kills ANY_LOCATION, the snippet can kill arbitrary locations return true; @@ -1848,7 +1853,6 @@ private boolean assertSnippetKills(ValueNode replacee) { assert kills.contains(locationIdentity) : replacee + " kills " + locationIdentity + ", but snippet doesn't contain a kill to this location"; kills.remove(locationIdentity); } - assert !(MemoryKill.isMultiMemoryKill(replacee)) : replacee + " multi not supported (yet)"; // remove ANY_LOCATION if it's just a kill by the start node if (memoryMap.getLastLocationAccess(any()) instanceof MemoryAnchorNode) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index 0f5d0f3ec9f4..28b134e0bdab 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -137,6 +137,7 @@ import jdk.graal.compiler.nodes.java.InstanceOfDynamicNode; import jdk.graal.compiler.nodes.java.NewArrayNode; import jdk.graal.compiler.nodes.java.StoreIndexedNode; +import jdk.graal.compiler.nodes.java.ValidateNewInstanceClassNode; import jdk.graal.compiler.nodes.spi.ArrayLengthProvider; import jdk.graal.compiler.nodes.spi.Replacements; import jdk.graal.compiler.nodes.type.NarrowOopStamp; @@ -811,10 +812,11 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec EnsureClassInitializedNode ensureInitialized = b.append(new EnsureClassInitializedNode(clazzNonNull)); ensureInitialized.setStateAfter(b.getInvocationPluginBeforeState()); + ValidateNewInstanceClassNode clazzLegal = b.add(new ValidateNewInstanceClassNode(clazzNonNull)); if (b.currentBlockCatchesOOM()) { - DynamicNewInstanceWithExceptionNode.createAndPush(b, clazzNonNull, true); + b.addPush(JavaKind.Object, new DynamicNewInstanceWithExceptionNode(clazzLegal, true)); } else { - DynamicNewInstanceNode.createAndPush(b, clazzNonNull, true); + b.addPush(JavaKind.Object, new DynamicNewInstanceNode(clazzLegal, true)); } return true; } @@ -970,9 +972,9 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode clazz) { ValueNode clazzNonNull = b.nullCheckedValue(clazz, DeoptimizationAction.None); if (b.currentBlockCatchesOOM()) { - DynamicNewInstanceWithExceptionNode.createAndPush(b, clazzNonNull, false); + b.addPush(JavaKind.Object, new DynamicNewInstanceWithExceptionNode(clazzNonNull, true)); } else { - DynamicNewInstanceNode.createAndPush(b, clazzNonNull, false); + b.addPush(JavaKind.Object, new DynamicNewInstanceNode(clazzNonNull, true)); } return true; }