Skip to content

Commit 98a4742

Browse files
committed
Move generation of FFI upcall stubs later, and use the correct assembler from the backend.
1 parent e105152 commit 98a4742

File tree

3 files changed

+74
-17
lines changed

3 files changed

+74
-17
lines changed

substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/AbiUtils.java

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,17 @@
5252
import org.graalvm.nativeimage.Platforms;
5353
import org.graalvm.word.Pointer;
5454

55+
import com.oracle.svm.core.BuildPhaseProvider.AfterAnalysis;
56+
import com.oracle.svm.core.SubstrateControlFlowIntegrity;
5557
import com.oracle.svm.core.SubstrateTargetDescription;
5658
import com.oracle.svm.core.aarch64.SubstrateAArch64MacroAssembler;
5759
import com.oracle.svm.core.config.ConfigurationValues;
5860
import com.oracle.svm.core.foreign.AbiUtils.Adapter.Adaptation;
5961
import com.oracle.svm.core.graal.code.AssignedLocation;
62+
import com.oracle.svm.core.graal.code.SubstrateBackendWithAssembler;
6063
import com.oracle.svm.core.headers.LibC;
6164
import com.oracle.svm.core.headers.WindowsAPIs;
65+
import com.oracle.svm.core.heap.UnknownPrimitiveField;
6266
import com.oracle.svm.core.util.BasedOnJDKClass;
6367
import com.oracle.svm.core.util.BasedOnJDKFile;
6468
import com.oracle.svm.core.util.VMError;
@@ -69,8 +73,8 @@
6973
import jdk.graal.compiler.asm.aarch64.AArch64Address;
7074
import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler;
7175
import jdk.graal.compiler.asm.amd64.AMD64Address;
72-
import jdk.graal.compiler.asm.amd64.AMD64Assembler;
7376
import jdk.graal.compiler.asm.amd64.AMD64BaseAssembler;
77+
import jdk.graal.compiler.asm.amd64.AMD64MacroAssembler;
7478
import jdk.graal.compiler.graph.Node;
7579
import jdk.graal.compiler.nodes.ValueNode;
7680
import jdk.graal.compiler.nodes.calc.AddNode;
@@ -671,11 +675,40 @@ public record Registers(Register methodHandle, Register isolate) {
671675

672676
public abstract int trampolineSize();
673677

674-
record TrampolineTemplate(byte[] assemblyTemplate, int isolateOffset, int methodHandleOffset, int stubOffset) {
678+
public static class TrampolineTemplate {
679+
680+
private final byte[] assemblyTemplate;
681+
682+
/*
683+
* These fields will only be filled after the analysis, when an assembler is available.
684+
* Prevent optimizations that constant-fold these fields already during analysis.
685+
*/
686+
687+
@UnknownPrimitiveField(availability = AfterAnalysis.class) //
688+
private int isolateOffset;
689+
@UnknownPrimitiveField(availability = AfterAnalysis.class) //
690+
private int methodHandleOffset;
691+
@UnknownPrimitiveField(availability = AfterAnalysis.class) //
692+
private int stubOffset;
693+
694+
public TrampolineTemplate(byte[] assemblyTemplate) {
695+
this.assemblyTemplate = assemblyTemplate;
696+
}
697+
698+
@Platforms(Platform.HOSTED_ONLY.class)
699+
public void setTemplate(byte[] code, int isolateOff, int methodHandleOff, int stubOff) {
700+
assert code.length == this.assemblyTemplate.length;
701+
System.arraycopy(code, 0, this.assemblyTemplate, 0, this.assemblyTemplate.length);
702+
this.isolateOffset = isolateOff;
703+
this.methodHandleOffset = methodHandleOff;
704+
this.stubOffset = stubOff;
705+
}
706+
675707
public Pointer write(Pointer at, Isolate isolate, Word methodHandle, Word stubPointer) {
676708
for (int i = 0; i < assemblyTemplate.length; ++i) {
677709
at.writeByte(i, assemblyTemplate[i]);
678710
}
711+
679712
at.writeWord(isolateOffset, isolate);
680713
at.writeWord(methodHandleOffset, methodHandle);
681714
at.writeWord(stubOffset, stubPointer);
@@ -685,7 +718,7 @@ public Pointer write(Pointer at, Isolate isolate, Word methodHandle, Word stubPo
685718
}
686719

687720
@Platforms(Platform.HOSTED_ONLY.class)
688-
abstract TrampolineTemplate generateTrampolineTemplate();
721+
abstract void generateTrampolineTemplate(SubstrateBackendWithAssembler<?> backend, TrampolineTemplate template);
689722
}
690723

691724
class ABIs {
@@ -740,8 +773,8 @@ public int trampolineSize() {
740773
}
741774

742775
@Override
743-
public TrampolineTemplate generateTrampolineTemplate() {
744-
return null;
776+
public void generateTrampolineTemplate(SubstrateBackendWithAssembler<?> backend, TrampolineTemplate template) {
777+
fail();
745778
}
746779

747780
@Override
@@ -812,8 +845,8 @@ public int trampolineSize() {
812845

813846
@Platforms(Platform.HOSTED_ONLY.class)
814847
@Override
815-
public TrampolineTemplate generateTrampolineTemplate() {
816-
AArch64MacroAssembler masm = new SubstrateAArch64MacroAssembler(ConfigurationValues.getTarget());
848+
public void generateTrampolineTemplate(SubstrateBackendWithAssembler<?> backend, TrampolineTemplate template) {
849+
AArch64MacroAssembler masm = (AArch64MacroAssembler) backend.createAssemblerNoOptions();
817850

818851
Register mhRegister = upcallSpecialArgumentsRegisters().methodHandle();
819852
Register isolateRegister = upcallSpecialArgumentsRegisters().isolate();
@@ -849,12 +882,11 @@ public TrampolineTemplate generateTrampolineTemplate() {
849882
masm.jmp(scratch);
850883

851884
assert trampolineSize() >= masm.position();
852-
masm.align(trampolineSize());
853885

854-
byte[] assembly = masm.close(true);
886+
byte[] assembly = masm.closeAligned(true, trampolineSize());
855887
assert assembly.length == trampolineSize();
856888

857-
return new TrampolineTemplate(assembly, posIsolate, posMHArray, posCallTarget);
889+
template.setTemplate(assembly, posIsolate, posMHArray, posCallTarget);
858890
}
859891

860892
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java#L195")
@@ -974,9 +1006,9 @@ public int trampolineSize() {
9741006

9751007
@Platforms(Platform.HOSTED_ONLY.class)
9761008
@Override
977-
public TrampolineTemplate generateTrampolineTemplate() {
1009+
public void generateTrampolineTemplate(SubstrateBackendWithAssembler<?> backend, TrampolineTemplate template) {
9781010
// Generate the trampoline
979-
AMD64Assembler asm = new AMD64Assembler(ConfigurationValues.getTarget());
1011+
AMD64MacroAssembler asm = (AMD64MacroAssembler) backend.createAssemblerNoOptions();
9801012
var odas = new ArrayList<AMD64BaseAssembler.OperandDataAnnotation>(3);
9811013
// Collect the positions of the address in the movq instructions.
9821014
asm.setCodePatchingAnnotationConsumer(ca -> {
@@ -988,6 +1020,7 @@ public TrampolineTemplate generateTrampolineTemplate() {
9881020
Register mhRegister = upcallSpecialArgumentsRegisters().methodHandle();
9891021
Register isolateRegister = upcallSpecialArgumentsRegisters().isolate();
9901022

1023+
asm.maybeEmitIndirectTargetMarker();
9911024
/* Store isolate in the assigned register */
9921025
asm.movq(isolateRegister, 0L, true);
9931026
/* r10 points in the mh array */
@@ -997,17 +1030,21 @@ public TrampolineTemplate generateTrampolineTemplate() {
9971030
/* rax contains the stub address */
9981031
asm.movq(rax, 0L, true);
9991032
/* executes the stub */
1000-
asm.jmp(new AMD64Address(rax, 0));
1033+
if (SubstrateControlFlowIntegrity.useSoftwareCFI()) {
1034+
asm.movq(rax, new AMD64Address(rax, 0));
1035+
asm.jmp(rax);
1036+
} else {
1037+
asm.jmp(new AMD64Address(rax, 0));
1038+
}
10011039

10021040
assert trampolineSize() - asm.position() >= 0;
1003-
asm.nop(trampolineSize() - asm.position());
10041041

1005-
byte[] assembly = asm.close(true);
1042+
byte[] assembly = asm.closeAligned(true, trampolineSize());
10061043
assert assembly.length == trampolineSize();
10071044
assert odas.size() == 3;
10081045
assert odas.stream().allMatch(oda -> oda.operandSize == 8);
10091046

1010-
return new TrampolineTemplate(assembly, odas.get(0).operandPosition, odas.get(1).operandPosition, odas.get(2).operandPosition);
1047+
template.setTemplate(assembly, odas.get(0).operandPosition, odas.get(1).operandPosition, odas.get(2).operandPosition);
10111048
}
10121049
}
10131050

substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsRuntime.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858
import com.oracle.svm.core.SubstrateUtil;
5959
import com.oracle.svm.core.Uninterruptible;
6060
import com.oracle.svm.core.c.InvokeJavaFunctionPointer;
61+
import com.oracle.svm.core.foreign.AbiUtils.TrampolineTemplate;
6162
import com.oracle.svm.core.foreign.phases.SubstrateOptimizeSharedArenaAccessPhase.OptimizeSharedArenaConfig;
63+
import com.oracle.svm.core.graal.code.SubstrateBackendWithAssembler;
6264
import com.oracle.svm.core.headers.LibC;
6365
import com.oracle.svm.core.headers.WindowsAPIs;
6466
import com.oracle.svm.core.image.DisallowedImageHeapObjects.DisallowedObjectReporter;
@@ -99,7 +101,12 @@ public static ForeignFunctionsRuntime singleton() {
99101

100102
@Platforms(Platform.HOSTED_ONLY.class)
101103
public ForeignFunctionsRuntime(AbiUtils abiUtils) {
102-
this.trampolineTemplate = abiUtils.generateTrampolineTemplate();
104+
this.trampolineTemplate = new TrampolineTemplate(new byte[abiUtils.trampolineSize()]);
105+
}
106+
107+
@Platforms(Platform.HOSTED_ONLY.class)
108+
public void generateTrampolineTemplate(SubstrateBackendWithAssembler<?> backend) {
109+
AbiUtils.singleton().generateTrampolineTemplate(backend, this.trampolineTemplate);
103110
}
104111

105112
public static boolean areFunctionCallsSupported() {

substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@
8989
import com.oracle.svm.core.foreign.Target_java_nio_MappedMemoryUtils;
9090
import com.oracle.svm.core.foreign.phases.SubstrateOptimizeSharedArenaAccessPhase;
9191
import com.oracle.svm.core.graal.RuntimeCompilation;
92+
import com.oracle.svm.core.graal.code.SubstrateBackend;
93+
import com.oracle.svm.core.graal.code.SubstrateBackendWithAssembler;
9294
import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider;
9395
import com.oracle.svm.core.jdk.VectorAPIEnabled;
9496
import com.oracle.svm.core.meta.MethodPointer;
@@ -405,6 +407,17 @@ public void duringSetup(DuringSetupAccess a) {
405407
ConfigurationParserUtils.parseAndRegisterConfigurationsFromCombinedFile(getConfigurationParser(imageClassLoader), imageClassLoader, "panama foreign");
406408
}
407409

410+
@Override
411+
public void beforeCompilation(BeforeCompilationAccess access) {
412+
FeatureImpl.BeforeCompilationAccessImpl a = (FeatureImpl.BeforeCompilationAccessImpl) access;
413+
SubstrateBackend b = a.getRuntimeConfiguration().getBackendForNormalMethod();
414+
if (b instanceof SubstrateBackendWithAssembler<?> bAsm) {
415+
foreignFunctionsRuntime.generateTrampolineTemplate(bAsm);
416+
} else {
417+
throw VMError.shouldNotReachHere("Support for the Foreign Function and Memory API needs a backend with an assembler, it is not available with backend %s", b.getClass());
418+
}
419+
}
420+
408421
private ConfigurationParser getConfigurationParser(ImageClassLoader imageClassLoader) {
409422
/*
410423
* If foreign function calls are not supported on this platform, we still want to parse the

0 commit comments

Comments
 (0)