Skip to content

Commit d1d85ea

Browse files
committed
[GR-71022] Make near/far foreign calls deterministic during replay.
PullRequest: graal/22468
2 parents 089bae3 + 3a0ddd5 commit d1d85ea

15 files changed

+53
-37
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64LIRGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ public void emitMembar(int barriers) {
713713

714714
@Override
715715
protected void emitForeignCallOp(ForeignCallLinkage linkage, Value targetAddress, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
716-
long maxOffset = linkage.getMaxCallTargetOffset();
716+
long maxOffset = linkage.getMaxCallTargetOffset(getCodeCache());
717717
if (maxOffset != (int) maxOffset) {
718718
append(new AMD64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
719719
} else {

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/spi/ForeignCallLinkage.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
package jdk.graal.compiler.core.common.spi;
2626

2727
import jdk.vm.ci.code.CallingConvention;
28+
import jdk.vm.ci.code.CodeCacheProvider;
2829
import jdk.vm.ci.meta.InvokeTarget;
2930
import jdk.vm.ci.meta.Value;
3031

@@ -50,7 +51,7 @@ public interface ForeignCallLinkage extends InvokeTarget {
5051
* the code cache or -1 when not applicable. Intended for determining the required size of
5152
* address/offset fields.
5253
*/
53-
long getMaxCallTargetOffset();
54+
long getMaxCallTargetOffset(CodeCacheProvider codeCache);
5455

5556
ForeignCallDescriptor getDescriptor();
5657

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotForeignCallLinkageImpl.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
*/
2525
package jdk.graal.compiler.hotspot;
2626

27-
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
28-
2927
import java.util.Arrays;
3028

3129
import org.graalvm.collections.EconomicSet;
@@ -263,8 +261,8 @@ public Value[] getTemporaries() {
263261
}
264262

265263
@Override
266-
public long getMaxCallTargetOffset() {
267-
return runtime().getHostJVMCIBackend().getCodeCache().getMaxCallTargetOffset(address);
264+
public long getMaxCallTargetOffset(CodeCacheProvider codeCache) {
265+
return codeCache.getMaxCallTargetOffset(address);
268266
}
269267

270268
@Override

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotBackend.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ private void emitNmethodEntryBarrier(CompilationResultBuilder crb, AArch64MacroA
351351
crb.getLIR().addSlowPath(null, () -> {
352352
masm.bind(entryPoint);
353353
int beforeCall = masm.position();
354-
if (AArch64Call.isNearCall(callTarget)) {
354+
if (AArch64Call.isNearCall(callTarget, getCodeCache())) {
355355
// Address is fixed up by the runtime.
356356
masm.bl();
357357
} else {
@@ -471,7 +471,7 @@ private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod ins
471471
ForeignCallLinkage icMissHandler = getForeignCalls().lookupForeignCall(IC_MISS_HANDLER);
472472

473473
// Size of IC check sequence checked with a guarantee below.
474-
int inlineCacheCheckSize = AArch64Call.isNearCall(icMissHandler) ? 20 : 32;
474+
int inlineCacheCheckSize = AArch64Call.isNearCall(icMissHandler, getCodeCache()) ? 20 : 32;
475475
if (config.useCompactObjectHeaders) {
476476
// Extra instruction for shifting
477477
inlineCacheCheckSize += 4;
@@ -560,7 +560,7 @@ private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler
560560
}
561561

562562
ForeignCallLinkage uncommonTrapBlob = foreignCalls.lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP);
563-
Register helper = AArch64Call.isNearCall(uncommonTrapBlob) ? null : scratch;
563+
Register helper = AArch64Call.isNearCall(uncommonTrapBlob, getCodeCache()) ? null : scratch;
564564
AArch64Call.directCall(crb, masm, uncommonTrapBlob, helper, pendingImplicitException.state());
565565
crb.recordImplicitException(pendingImplicitException.codeOffset(), pos, pendingImplicitException.state());
566566
}
@@ -570,7 +570,7 @@ private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler
570570
Register scratch = sc.getRegister();
571571
crb.recordMark(HotSpotMarkId.EXCEPTION_HANDLER_ENTRY);
572572
ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER);
573-
Register helper = AArch64Call.isNearCall(linkage) ? null : scratch;
573+
Register helper = AArch64Call.isNearCall(linkage, getCodeCache()) ? null : scratch;
574574
AArch64Call.directCall(crb, masm, linkage, helper, null);
575575
// Ensure the return location is a unique pc and that control flow doesn't return
576576
// here

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ protected Value getCompareValueForConstantPointer(Value v) {
171171
@Override
172172
protected void emitForeignCallOp(ForeignCallLinkage linkage, Value targetAddress, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
173173
currentRuntimeCallInfo = info;
174-
if (AArch64Call.isNearCall(linkage)) {
174+
if (AArch64Call.isNearCall(linkage, getCodeCache())) {
175175
append(new AArch64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info, label));
176176
} else {
177177
append(new AArch64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info, label));

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/shenandoah/AArch64HotSpotShenandoahLoadRefBarrierOp.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public static void emitCode(GraalHotSpotVMConfig config, CompilationResultBuilde
199199
masm.str(64, addressReg, cArg1);
200200

201201
// Make the call
202-
AArch64Call.directCall(crb, masm, callTarget, AArch64Call.isNearCall(callTarget) ? null : rtmp2, null);
202+
AArch64Call.directCall(crb, masm, callTarget, AArch64Call.isNearCall(callTarget, crb.getCodeCache()) ? null : rtmp2, null);
203203

204204
// Retrieve result and move to the result register.
205205
AArch64Address cRet = (AArch64Address) crb.asAddress(cc.getReturn());

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/shenandoah/AArch64HotSpotShenandoahSATBBarrierOp.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm
199199
CallingConvention cc = callTarget.getOutgoingCallingConvention();
200200
AArch64Address cArg0 = (AArch64Address) crb.asAddress(cc.getArgument(0));
201201
masm.str(64, previousValue, cArg0);
202-
AArch64Call.directCall(crb, masm, callTarget, AArch64Call.isNearCall(callTarget) ? null : scratch1, null);
202+
AArch64Call.directCall(crb, masm, callTarget, AArch64Call.isNearCall(callTarget, crb.getCodeCache()) ? null : scratch1, null);
203203
masm.jmp(done);
204204
}
205205
});

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/aarch64/z/AArch64HotSpotZBarrierSetLIRGenerator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ static void emitStoreBarrier(CompilationResultBuilder crb,
198198
masm.loadAddress(rscratch1, address);
199199
masm.str(64, rscratch1, cArg0);
200200

201-
AArch64Call.directCall(crb, masm, callTarget, AArch64Call.isNearCall(callTarget) ? null : rscratch1, null);
201+
AArch64Call.directCall(crb, masm, callTarget, AArch64Call.isNearCall(callTarget, crb.getCodeCache()) ? null : rscratch1, null);
202202
assert cc.getReturn().equals(Value.ILLEGAL) : cc + " " + callTarget;
203203

204204
masm.jmp(slowContinuation);
@@ -383,7 +383,7 @@ public static void emitLoadBarrier(CompilationResultBuilder crb,
383383
masm.loadAddress(ref, address);
384384
}
385385
masm.str(64, addressReg, cArg1);
386-
AArch64Call.directCall(crb, masm, callTarget, AArch64Call.isNearCall(callTarget) ? null : scratch1, null);
386+
AArch64Call.directCall(crb, masm, callTarget, AArch64Call.isNearCall(callTarget, crb.getCodeCache()) ? null : scratch1, null);
387387
masm.ldr(64, ref, cArg0);
388388

389389
masm.jmp(continuation);

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replaycomp/CompilerInterfaceDeclarations.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ public record MethodCallToRecord(Object receiver, CompilationProxy.SymbolicMetho
312312
* @param clazz the class
313313
* @param singleton {@code true} iff the class should be treated as a singleton (e.g., a
314314
* provider)
315+
* @param useLocalMirrorFallback {@code true} iff the methods of this class can be invoked with
316+
* local mirrors on the replaying VM as a fallback
315317
* @param mirrorLocator a method that can find the local mirror of a proxy during replay or
316318
* {@code null}
317319
* @param methods the recording/replay behavior the methods - only needed for non-default
@@ -320,7 +322,7 @@ public record MethodCallToRecord(Object receiver, CompilationProxy.SymbolicMetho
320322
* @param methodCallsToRecordProvider provides the methods calls that should be recorded in the
321323
* serialized compilation unit
322324
*/
323-
public record Registration(Class<?> clazz, boolean singleton, LocalMirrorLocator mirrorLocator,
325+
public record Registration(Class<?> clazz, boolean singleton, boolean useLocalMirrorFallback, LocalMirrorLocator mirrorLocator,
324326
UnmodifiableEconomicMap<CompilationProxy.SymbolicMethod, MethodRegistration> methods, Class<?>[] extraInterfaces,
325327
MethodCallsToRecordProvider methodCallsToRecordProvider) {
326328
/**
@@ -451,6 +453,8 @@ private static class RegistrationBuilder<T> {
451453

452454
private boolean singleton;
453455

456+
private boolean localMirrorFallback;
457+
454458
private LocalMirrorLocator mirrorLocator;
455459

456460
private final EconomicMap<CompilationProxy.SymbolicMethod, MethodRegistrationBuilder> methods;
@@ -461,6 +465,7 @@ private static class RegistrationBuilder<T> {
461465

462466
RegistrationBuilder(Class<T> clazz, Class<?>... extraInterfaces) {
463467
this.clazz = clazz;
468+
this.localMirrorFallback = true;
464469
this.methods = EconomicMap.create();
465470
this.extraInterfaces = extraInterfaces;
466471
this.methods.put(CompilationProxyBase.toStringMethod, MethodRegistrationBuilder.createDefault(CompilationProxyBase.toStringMethod));
@@ -476,6 +481,11 @@ public RegistrationBuilder<T> setSingleton(boolean newSingleton) {
476481
return this;
477482
}
478483

484+
public RegistrationBuilder<T> useLocalMirrorFallback(boolean enabled) {
485+
localMirrorFallback = enabled;
486+
return this;
487+
}
488+
479489
private MethodRegistrationBuilder findRegistrationBuilder(CompilationProxy.SymbolicMethod symbolicMethod) {
480490
MethodRegistrationBuilder builder = methods.get(symbolicMethod);
481491
if (builder == null) {
@@ -532,7 +542,7 @@ private void register(CompilerInterfaceDeclarations declarations) {
532542
while (cursor.advance()) {
533543
registrations.put(cursor.getKey(), cursor.getValue().build());
534544
}
535-
declarations.addRegistration(new Registration(clazz, singleton, mirrorLocator, registrations, extraInterfaces, methodCallsToRecordProvider));
545+
declarations.addRegistration(new Registration(clazz, singleton, localMirrorFallback, mirrorLocator, registrations, extraInterfaces, methodCallsToRecordProvider));
536546
}
537547
}
538548

@@ -663,6 +673,9 @@ public static CompilerInterfaceDeclarations build() {
663673
constantReflection.getMemoryAccessProvider())
664674
.register(declarations);
665675
new RegistrationBuilder<>(HotSpotCodeCacheProvider.class).setSingleton(true)
676+
// Avoid using the code cache of the replaying VM due to non-determinism (e.g., max call target offset).
677+
.useLocalMirrorFallback(false)
678+
.setDefaultValue(HotSpotCodeCacheProviderProxy.getMaxCallTargetOffsetMethod, -1L)
666679
.setDefaultValueStrategy(HotSpotCodeCacheProviderProxy.installCodeMethod, null)
667680
.setDefaultValueSupplier(HotSpotCodeCacheProviderProxy.installCodeMethod, CompilerInterfaceDeclarations::installCodeReplacement)
668681
// Interpreter frame size is not tracked since the arguments are not serializable.

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replaycomp/ReplayCompilationProxies.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -503,20 +503,22 @@ public CompilationProxy createProxy(CompilerInterfaceDeclarations.Registration r
503503
return proxyMapper.proxifyRecursive(result);
504504
}
505505
}
506-
try {
507-
Object[] unproxifiedArgs = (Object[]) proxyMapper.unproxifyRecursive(args);
508-
if (registration.singleton()) {
509-
return proxyMapper.proxifyRecursive(callback.invoke(input, unproxifiedArgs));
510-
}
511-
Object localMirror = proxyInfo.localMirror;
512-
if (localMirror != null) {
513-
return proxyMapper.proxifyRecursive(callback.invoke(localMirror, unproxifiedArgs));
506+
if (registration.useLocalMirrorFallback()) {
507+
try {
508+
Object[] unproxifiedArgs = (Object[]) proxyMapper.unproxifyRecursive(args);
509+
if (registration.singleton()) {
510+
return proxyMapper.proxifyRecursive(callback.invoke(input, unproxifiedArgs));
511+
}
512+
Object localMirror = proxyInfo.localMirror;
513+
if (localMirror != null) {
514+
return proxyMapper.proxifyRecursive(callback.invoke(localMirror, unproxifiedArgs));
515+
}
516+
} catch (NotUnproxifiableException ignored2) {
517+
// Cannot unproxify the arguments: continue.
518+
} catch (InvocationTargetException exception) {
519+
// The result of the invocation is a thrown exception.
520+
throw exception.getTargetException();
514521
}
515-
} catch (NotUnproxifiableException ignored2) {
516-
// Cannot unproxify the arguments: continue.
517-
} catch (InvocationTargetException exception) {
518-
// The result of the invocation is a thrown exception.
519-
throw exception.getTargetException();
520522
}
521523
CompilerInterfaceDeclarations.OperationResultSupplier handler = registration.findFallbackHandler(method);
522524
if (handler != null) {

0 commit comments

Comments
 (0)