Skip to content

Commit d67a6b8

Browse files
committed
[GR-47637] Implement Thread.onSpinWait intrinsic on AArch64.
PullRequest: graal/15136
2 parents 4f67601 + 6eea384 commit d67a6b8

File tree

9 files changed

+160
-20
lines changed

9 files changed

+160
-20
lines changed

compiler/src/jdk.internal.vm.compiler/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,11 @@ public void emitPause() {
10121012
append(new AMD64PauseOp());
10131013
}
10141014

1015+
@Override
1016+
public void emitSpinWait() {
1017+
append(new AMD64PauseOp());
1018+
}
1019+
10151020
@Override
10161021
public void emitHalt() {
10171022
append(new AMD64HaltOp());

compiler/src/jdk.internal.vm.compiler/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ private HotSpotGraalRuntime.HotSpotGC getSelectedGC() throws GraalError {
137137
public final boolean useFMAIntrinsics = getFlag("UseFMA", Boolean.class);
138138
public final int useAVX3Threshold = getFlag("AVX3Threshold", Integer.class, 4096, osArch.equals("amd64"));
139139

140+
public final String onSpinWaitInst = getFlag("OnSpinWaitInst", String.class, "none", osArch.equals("aarch64"));
141+
public final int onSpinWaitInstCount = getFlag("OnSpinWaitInstCount", Integer.class, 0, osArch.equals("aarch64"));
142+
140143
public final boolean preserveFramePointer = getFlag("PreserveFramePointer", Boolean.class);
141144

142145
public final int diagnoseSyncOnValueBasedClasses = getFlag("DiagnoseSyncOnValueBasedClasses", Integer.class);

compiler/src/jdk.internal.vm.compiler/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@
3434

3535
import java.util.Arrays;
3636
import java.util.EnumSet;
37+
import java.util.function.Consumer;
3738
import java.util.function.Function;
3839

3940
import org.graalvm.compiler.asm.Label;
4041
import org.graalvm.compiler.asm.aarch64.AArch64Address;
4142
import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
4243
import org.graalvm.compiler.asm.aarch64.AArch64Assembler.PrefetchMode;
44+
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
4345
import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator;
4446
import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator;
4547
import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool;
@@ -76,6 +78,7 @@
7678
import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp;
7779
import org.graalvm.compiler.lir.aarch64.AArch64RestoreRegistersOp;
7880
import org.graalvm.compiler.lir.aarch64.AArch64SaveRegistersOp;
81+
import org.graalvm.compiler.lir.aarch64.AArch64SpinWaitOp;
7982
import org.graalvm.compiler.lir.gen.BarrierSetLIRGenerator;
8083
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
8184
import org.graalvm.compiler.lir.gen.MoveFactory;
@@ -468,6 +471,25 @@ public void emitZeroMemory(Value address, Value length, boolean isAligned) {
468471
emitZeroMemory(address, length, isAligned, useDcZva, zvaLength);
469472
}
470473

474+
private Consumer<AArch64MacroAssembler> onSpinWaitInst() {
475+
return switch (config.onSpinWaitInst) {
476+
case "nop" -> AArch64MacroAssembler::nop;
477+
case "isb" -> AArch64MacroAssembler::isb;
478+
case "yield" -> AArch64MacroAssembler::pause;
479+
default -> throw GraalError.shouldNotReachHere("Unknown OnSpinWaitInst " + config.onSpinWaitInst);
480+
};
481+
}
482+
483+
@Override
484+
public void emitSpinWait() {
485+
if ("none".equals(config.onSpinWaitInst)) {
486+
// do nothing
487+
} else {
488+
GraalError.guarantee(config.onSpinWaitInstCount > 0, "illegal onSpinWaitInstCount");
489+
append(new AArch64SpinWaitOp(onSpinWaitInst(), config.onSpinWaitInstCount));
490+
}
491+
}
492+
471493
@Override
472494
public int getArrayLengthOffset() {
473495
return config.arrayOopDescLengthOffset();

compiler/src/jdk.internal.vm.compiler/src/org/graalvm/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -401,11 +401,6 @@ public UnimplementedGraalIntrinsics(GraalHotSpotVMConfig config, Architecture ar
401401
);
402402
}
403403

404-
if (arch instanceof AArch64) {
405-
add(toBeInvestigated,
406-
"java/lang/Thread.onSpinWait()V");
407-
}
408-
409404
if (JAVA_SPEC >= 20) {
410405
// This reuses the intrinsic for java/lang/StringCoding.hasNegatives with minor changes
411406
add(toBeInvestigated,
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package org.graalvm.compiler.lir.aarch64;
26+
27+
import java.util.function.Consumer;
28+
29+
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
30+
import org.graalvm.compiler.debug.GraalError;
31+
import org.graalvm.compiler.lir.LIRInstructionClass;
32+
import org.graalvm.compiler.lir.Opcode;
33+
import org.graalvm.compiler.lir.SyncPort;
34+
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
35+
36+
/**
37+
* Emits spin wait instruction(s).
38+
*/
39+
// @formatter:off
40+
@SyncPort(from = "https://github.com/openjdk/jdk/blob/d7b941640638b35f9ac1ef11cd6bf6ccb795c29a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp#L52-L68",
41+
sha1 = "92f81ed500658553a2ef2e7c48633094d95ba974")
42+
// @formatter:on
43+
@Opcode("SPIN_WAIT")
44+
public final class AArch64SpinWaitOp extends AArch64LIRInstruction {
45+
public static final LIRInstructionClass<AArch64SpinWaitOp> TYPE = LIRInstructionClass.create(AArch64SpinWaitOp.class);
46+
47+
private final Consumer<AArch64MacroAssembler> instruction;
48+
private final int count;
49+
50+
public AArch64SpinWaitOp(Consumer<AArch64MacroAssembler> instruction, int count) {
51+
super(TYPE);
52+
53+
this.instruction = instruction;
54+
this.count = count;
55+
GraalError.guarantee(count > 0, "count should be positive");
56+
}
57+
58+
@Override
59+
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
60+
for (int i = 0; i < count; i++) {
61+
instruction.accept(masm);
62+
}
63+
}
64+
}

compiler/src/jdk.internal.vm.compiler/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,12 @@ default void emitSha256ImplCompress(Value buf, Value state) {
528528

529529
void emitPause();
530530

531+
/**
532+
* Perform no operation by default. See also {@link Thread#onSpinWait()}.
533+
*/
534+
default void emitSpinWait() {
535+
}
536+
531537
void emitPrefetchAllocate(Value address);
532538

533539
Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull);
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package org.graalvm.compiler.nodes;
26+
27+
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
28+
29+
import org.graalvm.compiler.core.common.type.StampFactory;
30+
import org.graalvm.compiler.graph.NodeClass;
31+
import org.graalvm.compiler.nodeinfo.NodeInfo;
32+
import org.graalvm.compiler.nodeinfo.NodeSize;
33+
import org.graalvm.compiler.nodes.spi.LIRLowerable;
34+
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
35+
36+
/**
37+
* A node that results in a platform dependent spin_wait instruction being emitted.
38+
*/
39+
@NodeInfo(cycles = CYCLES_IGNORED, size = NodeSize.SIZE_1)
40+
public final class SpinWaitNode extends FixedWithNextNode implements LIRLowerable {
41+
42+
public static final NodeClass<SpinWaitNode> TYPE = NodeClass.create(SpinWaitNode.class);
43+
44+
public SpinWaitNode() {
45+
super(TYPE, StampFactory.forVoid());
46+
}
47+
48+
@Override
49+
public void generate(NodeLIRBuilderTool gen) {
50+
gen.getLIRGeneratorTool().emitSpinWait();
51+
}
52+
}

compiler/src/jdk.internal.vm.compiler/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import org.graalvm.compiler.nodes.NodeView;
8383
import org.graalvm.compiler.nodes.PiNode;
8484
import org.graalvm.compiler.nodes.ProfileData.BranchProbabilityData;
85+
import org.graalvm.compiler.nodes.SpinWaitNode;
8586
import org.graalvm.compiler.nodes.StateSplit;
8687
import org.graalvm.compiler.nodes.StructuredGraph;
8788
import org.graalvm.compiler.nodes.ValueNode;
@@ -2351,6 +2352,13 @@ private static boolean hasEnsureMaterializedForStackWalk() {
23512352

23522353
private static void registerThreadPlugins(InvocationPlugins plugins, Replacements replacements) {
23532354
Registration r = new Registration(plugins, Thread.class, replacements);
2355+
r.register(new InvocationPlugin("onSpinWait") {
2356+
@Override
2357+
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
2358+
b.append(new SpinWaitNode());
2359+
return true;
2360+
}
2361+
});
23542362
if (hasEnsureMaterializedForStackWalk()) {
23552363
r.register(new InvocationPlugin("ensureMaterializedForStackWalk", Object.class) {
23562364
@Override

compiler/src/jdk.internal.vm.compiler/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import org.graalvm.compiler.nodes.ConstantNode;
4848
import org.graalvm.compiler.nodes.NamedLocationIdentity;
4949
import org.graalvm.compiler.nodes.NodeView;
50-
import org.graalvm.compiler.nodes.PauseNode;
5150
import org.graalvm.compiler.nodes.ValueNode;
5251
import org.graalvm.compiler.nodes.calc.AddNode;
5352
import org.graalvm.compiler.nodes.calc.CompressBitsNode;
@@ -115,7 +114,6 @@ public static void register(Plugins plugins, Replacements replacements, AMD64 ar
115114
invocationPlugins.defer(new Runnable() {
116115
@Override
117116
public void run() {
118-
registerThreadPlugins(invocationPlugins, arch);
119117
registerIntegerLongPlugins(invocationPlugins, JavaKind.Int, arch, replacements);
120118
registerIntegerLongPlugins(invocationPlugins, JavaKind.Long, arch, replacements);
121119
registerFloatDoublePlugins(invocationPlugins, JavaKind.Float, arch, replacements);
@@ -135,19 +133,6 @@ public void run() {
135133
});
136134
}
137135

138-
private static void registerThreadPlugins(InvocationPlugins plugins, AMD64 arch) {
139-
// Pause instruction introduced with SSE2
140-
assert (arch.getFeatures().contains(AMD64.CPUFeature.SSE2));
141-
Registration r = new Registration(plugins, Thread.class);
142-
r.register(new InvocationPlugin("onSpinWait") {
143-
@Override
144-
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
145-
b.append(new PauseNode());
146-
return true;
147-
}
148-
});
149-
}
150-
151136
private static void registerIntegerLongPlugins(InvocationPlugins plugins, JavaKind kind, AMD64 arch, Replacements replacements) {
152137
Class<?> declaringClass = kind.toBoxedJavaClass();
153138
Class<?> type = kind.toJavaClass();

0 commit comments

Comments
 (0)