diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/UnsafeSubstitutionsWithoutLSETest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/UnsafeSubstitutionsWithoutLSETest.java new file mode 100644 index 000000000000..9819fa3eecd4 --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/UnsafeSubstitutionsWithoutLSETest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 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 jdk.graal.compiler.hotspot.test; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import jdk.graal.compiler.core.test.GraalCompilerTest; +import jdk.graal.compiler.core.test.SubprocessTest; +import jdk.graal.compiler.replacements.test.UnsafeSubstitutionsTest; +import jdk.graal.compiler.test.SubprocessUtil; +import jdk.vm.ci.aarch64.AArch64; + +public class UnsafeSubstitutionsWithoutLSETest extends SubprocessTest { + @Before + public void before() { + Assume.assumeTrue("AArch64-specific test", getArchitecture() instanceof AArch64); + } + + public void testWithoutLSE(Class testClass) { + Runnable nopRunnable = () -> { + /* + * The runnable is only relevant when running a test in the same class as the parent + * process. + */ + }; + SubprocessUtil.Subprocess subprocess = null; + try { + subprocess = launchSubprocess(testClass, ALL_TESTS, nopRunnable, "-XX:-UseLSE"); + } catch (IOException | InterruptedException e) { + Assert.fail("subprocess exception: " + e); + } + Assert.assertEquals("subprocess exit code", 0, subprocess.exitCode); + } + + @Test + public void unsafeSubstitutions() { + testWithoutLSE(UnsafeSubstitutionsTest.class); + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/z/AArch64HotSpotZBarrierSetLIRGenerator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/z/AArch64HotSpotZBarrierSetLIRGenerator.java index 73fe5e65d38d..740f385b8f89 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/z/AArch64HotSpotZBarrierSetLIRGenerator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/z/AArch64HotSpotZBarrierSetLIRGenerator.java @@ -120,7 +120,7 @@ static void emitStoreBarrier(CompilationResultBuilder crb, LIRInstruction op, GraalHotSpotVMConfig config, AArch64Address address, - Register result, + Register tmp, StoreKind storeKind, ForeignCallLinkage callTarget, LIRFrameState state) { @@ -130,9 +130,9 @@ static void emitStoreBarrier(CompilationResultBuilder crb, Register rscratch1 = sc1.getRegister(); Register rscratch2 = sc2.getRegister(); - Assembler.guaranteeDifferentRegisters(address.getBase(), result, rscratch1); - Assembler.guaranteeDifferentRegisters(address.getOffset(), result, rscratch1); - Assembler.guaranteeDifferentRegisters(result, rscratch1); + Assembler.guaranteeDifferentRegisters(address.getBase(), tmp, rscratch1); + Assembler.guaranteeDifferentRegisters(address.getOffset(), tmp, rscratch1); + Assembler.guaranteeDifferentRegisters(tmp, rscratch1); if (storeKind == StoreKind.Atomic) { if (state != null) { @@ -182,7 +182,7 @@ static void emitStoreBarrier(CompilationResultBuilder crb, storeBarrierMedium(crb, masm, config, address, rscratch2, - result, + tmp, rscratch1, storeKind, continuation, @@ -423,10 +423,11 @@ public void emitCompareAndSwapOp(LIRGeneratorTool tool, AllocatableValue allocatableNewValue, BarrierType barrierType) { ForeignCallLinkage callTarget = getWriteBarrierStub(barrierType, StoreKind.Atomic); - AllocatableValue temp = tool.newVariable(tool.toRegisterKind(LIRKind.value(memKind))); + AllocatableValue tmp = tool.newVariable(tool.toRegisterKind(LIRKind.value(memKind))); + AllocatableValue tmp2 = tool.newVariable(tool.toRegisterKind(LIRKind.value(memKind))); tool.getResult().getFrameMapBuilder().callsMethod(callTarget.getOutgoingCallingConvention()); tool.append(new AArch64HotSpotZCompareAndSwapOp(isLogicVariant, memKind, memoryOrder, isLogicVariant, result, - allocatableExpectedValue, allocatableNewValue, tool.asAllocatable(address), config, callTarget, temp)); + allocatableExpectedValue, allocatableNewValue, tool.asAllocatable(address), config, callTarget, tmp, tmp2)); } @Override diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/z/AArch64HotSpotZCompareAndSwapOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/z/AArch64HotSpotZCompareAndSwapOp.java index 966a0ae9ecb0..5845d5400dde 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/z/AArch64HotSpotZCompareAndSwapOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/z/AArch64HotSpotZCompareAndSwapOp.java @@ -51,37 +51,46 @@ public final class AArch64HotSpotZCompareAndSwapOp extends AArch64AtomicMove.Com private final boolean isLogic; private final GraalHotSpotVMConfig config; private final ForeignCallLinkage callTarget; - @Temp protected AllocatableValue tmp; + @Temp private AllocatableValue tmp; + @Temp private AllocatableValue tmp2; - public AArch64HotSpotZCompareAndSwapOp(boolean isLogic, AArch64Kind accessKind, MemoryOrderMode memoryOrder, boolean setConditionFlags, AllocatableValue result, Value expectedValue, + public AArch64HotSpotZCompareAndSwapOp(boolean isLogic, + AArch64Kind accessKind, + MemoryOrderMode memoryOrder, + boolean setConditionFlags, + AllocatableValue result, + Value expectedValue, AllocatableValue newValue, - AllocatableValue addressValue, GraalHotSpotVMConfig config, ForeignCallLinkage callTarget, AllocatableValue tmp) { + AllocatableValue addressValue, + GraalHotSpotVMConfig config, + ForeignCallLinkage callTarget, + AllocatableValue tmp, AllocatableValue tmp2) { super(TYPE, accessKind, memoryOrder, setConditionFlags, result, expectedValue, newValue, addressValue); this.isLogic = isLogic; this.config = config; this.callTarget = callTarget; this.tmp = tmp; + this.tmp2 = tmp2; } @Override public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { // Use ANY_SIZE here because the store barrier performs 16 and 64 access for atomics. AArch64Address location = AArch64Address.createBaseRegisterOnlyAddress(AArch64Address.ANY_SIZE, asRegister(addressValue)); - AArch64HotSpotZBarrierSetLIRGenerator.emitStoreBarrier(crb, masm, this, config, location, asRegister(tmp), ZWriteBarrierSetLIRGeneratorTool.StoreKind.Atomic, + Register tmpRegister = asRegister(tmp); + AArch64HotSpotZBarrierSetLIRGenerator.emitStoreBarrier(crb, masm, this, config, location, tmpRegister, ZWriteBarrierSetLIRGeneratorTool.StoreKind.Atomic, callTarget, null); - try (AArch64MacroAssembler.ScratchRegister sc1 = masm.getScratchRegister()) { - Register rscratch1 = sc1.getRegister(); - // Color newValue and expectedValue into a temporary registers - AArch64HotSpotZBarrierSetLIRGenerator.zColor(crb, masm, config, asRegister(tmp), asRegister(newValue)); - AArch64HotSpotZBarrierSetLIRGenerator.zColor(crb, masm, config, rscratch1, asRegister(expectedValue)); - Register address = asRegister(addressValue); - // Produce the colored result into a temporary register - Register result = asRegister(resultValue); - Register expected = rscratch1; - emitCompareAndSwap(masm, accessKind, address, result, expected, asRegister(tmp), memoryOrder, setConditionFlags); - if (!isLogic) { - AArch64HotSpotZBarrierSetLIRGenerator.zUncolor(masm, config, asRegister(resultValue)); - } + Register tmp2Register = asRegister(tmp2); + // Color newValue and expectedValue into a temporary registers + AArch64HotSpotZBarrierSetLIRGenerator.zColor(crb, masm, config, tmpRegister, asRegister(newValue)); + AArch64HotSpotZBarrierSetLIRGenerator.zColor(crb, masm, config, tmp2Register, asRegister(expectedValue)); + Register address = asRegister(addressValue); + // Produce the colored result into a temporary register + Register result = asRegister(resultValue); + Register expected = tmp2Register; + emitCompareAndSwap(masm, accessKind, address, result, expected, tmpRegister, memoryOrder, setConditionFlags); + if (!isLogic) { + AArch64HotSpotZBarrierSetLIRGenerator.zUncolor(masm, config, asRegister(resultValue)); } } }