Skip to content

Commit eae9cac

Browse files
committed
[GR-61783] Add exception edges to failing arraycopy calls.
PullRequest: graal/19957
2 parents baeab6a + 19f52a5 commit eae9cac

File tree

5 files changed

+241
-80
lines changed

5 files changed

+241
-80
lines changed

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyGuardsStageUsages.java

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ protected void verify(StructuredGraph graph, CoreProviders context) {
6363
case "jdk.graal.compiler.replacements.arraycopy.ArrayCopySnippets.delayedCheckcastArraycopySnippet":
6464
case "jdk.graal.compiler.replacements.arraycopy.ArrayCopySnippets.delayedExactArraycopyWithExpandedLoopSnippet":
6565
case "jdk.graal.compiler.replacements.arraycopy.ArrayCopySnippets.delayedGenericArraycopySnippet":
66+
case "jdk.graal.compiler.replacements.arraycopy.ArrayCopySnippets.checkTypesAndLimits":
6667
// Exempted cases
6768
return;
6869
default:

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/ArrayCopyExceptionSeenTest.java

+37-3
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,26 @@
2626

2727
import static jdk.graal.compiler.core.common.GraalOptions.StressInvokeWithExceptionNode;
2828

29+
import org.junit.Assert;
30+
import org.junit.Test;
31+
2932
import jdk.graal.compiler.api.directives.GraalDirectives;
3033
import jdk.graal.compiler.core.test.GraalCompilerTest;
3134
import jdk.graal.compiler.nodes.spi.ProfileProvider;
3235
import jdk.graal.compiler.options.OptionValues;
33-
import org.junit.Test;
34-
36+
import jdk.vm.ci.code.InvalidInstalledCodeException;
37+
import jdk.vm.ci.meta.DeoptimizationReason;
3538
import jdk.vm.ci.meta.ResolvedJavaMethod;
3639

3740
public class ArrayCopyExceptionSeenTest extends GraalCompilerTest {
3841

3942
@Override
4043
protected ProfileProvider getProfileProvider(ResolvedJavaMethod method) {
41-
return NO_PROFILE_PROVIDER;
44+
if (method == getResolvedJavaMethod("copyWithHandler")) {
45+
return super.getProfileProvider(method);
46+
} else {
47+
return NO_PROFILE_PROVIDER;
48+
}
4249
}
4350

4451
static class A {
@@ -59,9 +66,36 @@ public void copy(Object src, Object dst) {
5966
}
6067
}
6168

69+
public static boolean copyWithHandler(Object src, int srcPos, Object dst, int destPos, int length) {
70+
try {
71+
System.arraycopy(src, srcPos, dst, destPos, length);
72+
return true;
73+
} catch (Throwable t) {
74+
return false;
75+
}
76+
}
77+
6278
@Test
6379
public void testCopy() {
6480
getFinalGraph(getResolvedJavaMethod("copy"), new OptionValues(getInitialOptions(), StressInvokeWithExceptionNode, true));
6581
}
6682

83+
/**
84+
* Tests that calls to {@link System#arraycopy} which result in an exception will be compiled
85+
* with explicit exception handlers when recompiled.
86+
*/
87+
@Test
88+
public void testFailingCopy() throws InvalidInstalledCodeException {
89+
var method = getResolvedJavaMethod("copyWithHandler");
90+
Assert.assertEquals("No recorded deopt expected before first invocation.", 0, method.getProfilingInfo().getDeoptimizationCount(DeoptimizationReason.BoundsCheckException));
91+
test(method, null, new Object[3], -1, new Object[3], 0, 1);
92+
Assert.assertEquals("Single deopt expected after first invocation.", 1, method.getProfilingInfo().getDeoptimizationCount(DeoptimizationReason.BoundsCheckException));
93+
/*
94+
* Force a recompile which should create an explicit exception edge for the System.arraycopy
95+
* call because an exception has been recorded at that position.
96+
*/
97+
var code = getCode(method, null, true, true, getInitialOptions());
98+
code.executeVarargs(new Object[3], -1, new Object[3], 0, 1);
99+
Assert.assertEquals("No more deopts expected after recompile with explicit exception edge.", 1, method.getProfilingInfo().getDeoptimizationCount(DeoptimizationReason.BoundsCheckException));
100+
}
67101
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/arraycopy/HotSpotArraycopySnippets.java

+64-4
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,37 @@
2626
package jdk.graal.compiler.hotspot.replacements.arraycopy;
2727

2828
import static jdk.graal.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
29+
import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
30+
import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
2931
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
3032
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
3133
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
3234
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.probability;
35+
import static jdk.graal.compiler.replacements.SnippetTemplate.AbstractTemplates.findMethod;
3336

37+
import org.graalvm.word.LocationIdentity;
38+
39+
import jdk.graal.compiler.core.common.type.StampFactory;
40+
import jdk.graal.compiler.core.common.type.StampPair;
41+
import jdk.graal.compiler.graph.NodeClass;
42+
import jdk.graal.compiler.hotspot.nodes.HotSpotDirectCallTargetNode;
3443
import jdk.graal.compiler.hotspot.replacements.HotSpotReplacementsUtil;
3544
import jdk.graal.compiler.hotspot.word.KlassPointer;
45+
import jdk.graal.compiler.nodeinfo.InputType;
46+
import jdk.graal.compiler.nodeinfo.NodeInfo;
47+
import jdk.graal.compiler.nodes.CallTargetNode;
48+
import jdk.graal.compiler.nodes.InvokeWithExceptionNode;
3649
import jdk.graal.compiler.nodes.PiNode;
3750
import jdk.graal.compiler.nodes.SnippetAnchorNode;
51+
import jdk.graal.compiler.nodes.StructuredGraph;
52+
import jdk.graal.compiler.nodes.ValueNode;
53+
import jdk.graal.compiler.nodes.spi.Lowerable;
54+
import jdk.graal.compiler.nodes.spi.LoweringTool;
3855
import jdk.graal.compiler.replacements.arraycopy.ArrayCopyCallNode;
3956
import jdk.graal.compiler.replacements.arraycopy.ArrayCopySnippets;
57+
import jdk.graal.compiler.replacements.nodes.BasicArrayCopyNode;
4058
import jdk.graal.compiler.word.Word;
41-
import org.graalvm.word.LocationIdentity;
42-
59+
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
4360
import jdk.vm.ci.meta.JavaKind;
4461

4562
public class HotSpotArraycopySnippets extends ArrayCopySnippets {
@@ -106,7 +123,8 @@ protected void doCheckcastArraycopySnippet(Object src, int srcPos, Object dest,
106123
}
107124

108125
@Override
109-
protected void doGenericArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters) {
126+
protected void doGenericArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, LocationIdentity arrayLocation, Counters counters,
127+
boolean exceptionSeen) {
110128
counters.genericArraycopyDifferentTypeCounter.inc();
111129
counters.genericArraycopyDifferentTypeCopiedCounter.add(length);
112130
int copiedElements = GenericArrayCopyCallNode.genericArraycopy(src, srcPos, dest, destPos, length);
@@ -116,7 +134,49 @@ protected void doGenericArraycopySnippet(Object src, int srcPos, Object dest, in
116134
* elements (xor'd with -1).
117135
*/
118136
copiedElements ^= -1;
119-
System.arraycopy(src, srcPos + copiedElements, dest, destPos + copiedElements, length - copiedElements);
137+
if (exceptionSeen) {
138+
HotSpotArrayCopyCallWithExceptionNode.arraycopyWithException(src, srcPos + copiedElements, dest, destPos + copiedElements, length - copiedElements, elementKind);
139+
} else {
140+
System.arraycopy(src, srcPos + copiedElements, dest, destPos + copiedElements, length - copiedElements);
141+
}
142+
}
143+
}
144+
145+
@Override
146+
protected void doFailingArraycopySnippet(Object src, int srcPos, Object dest, int destPos, int length, JavaKind elementKind, Counters counters) {
147+
// Call System.arraycopy but have an exception edge for the call.
148+
HotSpotArrayCopyCallWithExceptionNode.arraycopyWithException(src, srcPos, dest, destPos, length, elementKind);
149+
}
150+
151+
@NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Value}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
152+
public static final class HotSpotArrayCopyCallWithExceptionNode extends BasicArrayCopyNode implements Lowerable {
153+
public static final NodeClass<HotSpotArrayCopyCallWithExceptionNode> TYPE = NodeClass.create(HotSpotArrayCopyCallWithExceptionNode.class);
154+
155+
public HotSpotArrayCopyCallWithExceptionNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind) {
156+
super(TYPE, src, srcPos, dest, destPos, length, elementKind);
120157
}
158+
159+
@Override
160+
public void lower(LoweringTool tool) {
161+
// Based on SubstrateGenericArrayCopyCallNode.
162+
if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
163+
StructuredGraph graph = graph();
164+
ValueNode[] args = new ValueNode[]{getSource(), getSourcePosition(), getDestination(), getDestinationPosition(), getLength()};
165+
var returnStamp = StampPair.create(StampFactory.forVoid(), StampFactory.forVoid());
166+
var target = findMethod(tool.getMetaAccess(), System.class, "arraycopy");
167+
var signature = target.getSignature().toParameterTypes(null);
168+
var callType = HotSpotCallingConventionType.JavaCall;
169+
var invokeKind = CallTargetNode.InvokeKind.Static;
170+
CallTargetNode ct = graph.add(new HotSpotDirectCallTargetNode(args, returnStamp, signature, target, callType, invokeKind));
171+
172+
InvokeWithExceptionNode call = graph.add(new InvokeWithExceptionNode(ct, null, bci()));
173+
call.setStateAfter(stateAfter());
174+
call.setStateDuring(stateDuring());
175+
graph.replaceWithExceptionSplit(this, call);
176+
}
177+
}
178+
179+
@NodeIntrinsic
180+
public static native int arraycopyWithException(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind);
121181
}
122182
}

0 commit comments

Comments
 (0)