Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,24 @@ public void emitString(String s, int pos) {
* including) {@code position()} is returned
* @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
*/
public byte[] close(boolean trimmedCopy) {
public final byte[] close(boolean trimmedCopy) {
return closeAligned(trimmedCopy, 0);
}

/**
* Closes this assembler. No extra data can be written to this assembler after this call.
*
* @param trimmedCopy if {@code true}, then a copy of the underlying byte array up to (but not
* including) {@code position()} is returned
* @param alignment if {@code > 0}, then align the end of the code buffer with NOPs to the
* specified alignment
* @return the data in this buffer or a trimmed copy if {@code trimmedCopy} is {@code true}
*/
public byte[] closeAligned(boolean trimmedCopy, int alignment) {
checkAndClearLabelsWithPatches();
if (alignment > 0 && position() % alignment != 0) {
this.align(alignment);
}
finalCodeSize = position();
return codeBuffer.close(trimmedCopy);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,17 @@
import org.graalvm.nativeimage.Platforms;
import org.graalvm.word.Pointer;

import com.oracle.svm.core.BuildPhaseProvider.AfterAnalysis;
import com.oracle.svm.core.SubstrateControlFlowIntegrity;
import com.oracle.svm.core.SubstrateTargetDescription;
import com.oracle.svm.core.aarch64.SubstrateAArch64MacroAssembler;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.core.foreign.AbiUtils.Adapter.Adaptation;
import com.oracle.svm.core.graal.code.AssignedLocation;
import com.oracle.svm.core.graal.code.SubstrateBackendWithAssembler;
import com.oracle.svm.core.headers.LibC;
import com.oracle.svm.core.headers.WindowsAPIs;
import com.oracle.svm.core.heap.UnknownPrimitiveField;
import com.oracle.svm.core.util.BasedOnJDKClass;
import com.oracle.svm.core.util.BasedOnJDKFile;
import com.oracle.svm.core.util.VMError;
Expand All @@ -69,8 +73,8 @@
import jdk.graal.compiler.asm.aarch64.AArch64Address;
import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler;
import jdk.graal.compiler.asm.amd64.AMD64Address;
import jdk.graal.compiler.asm.amd64.AMD64Assembler;
import jdk.graal.compiler.asm.amd64.AMD64BaseAssembler;
import jdk.graal.compiler.asm.amd64.AMD64MacroAssembler;
import jdk.graal.compiler.graph.Node;
import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.calc.AddNode;
Expand Down Expand Up @@ -671,11 +675,40 @@ public record Registers(Register methodHandle, Register isolate) {

public abstract int trampolineSize();

record TrampolineTemplate(byte[] assemblyTemplate, int isolateOffset, int methodHandleOffset, int stubOffset) {
public static class TrampolineTemplate {

private final byte[] assemblyTemplate;

/*
* These fields will only be filled after the analysis, when an assembler is available.
* Prevent optimizations that constant-fold these fields already during analysis.
*/

@UnknownPrimitiveField(availability = AfterAnalysis.class) //
private int isolateOffset;
@UnknownPrimitiveField(availability = AfterAnalysis.class) //
private int methodHandleOffset;
@UnknownPrimitiveField(availability = AfterAnalysis.class) //
private int stubOffset;

public TrampolineTemplate(byte[] assemblyTemplate) {
this.assemblyTemplate = assemblyTemplate;
}

@Platforms(Platform.HOSTED_ONLY.class)
public void setTemplate(byte[] code, int isolateOff, int methodHandleOff, int stubOff) {
assert code.length == this.assemblyTemplate.length;
System.arraycopy(code, 0, this.assemblyTemplate, 0, this.assemblyTemplate.length);
this.isolateOffset = isolateOff;
this.methodHandleOffset = methodHandleOff;
this.stubOffset = stubOff;
}

public Pointer write(Pointer at, Isolate isolate, Word methodHandle, Word stubPointer) {
for (int i = 0; i < assemblyTemplate.length; ++i) {
at.writeByte(i, assemblyTemplate[i]);
}

at.writeWord(isolateOffset, isolate);
at.writeWord(methodHandleOffset, methodHandle);
at.writeWord(stubOffset, stubPointer);
Expand All @@ -685,7 +718,7 @@ public Pointer write(Pointer at, Isolate isolate, Word methodHandle, Word stubPo
}

@Platforms(Platform.HOSTED_ONLY.class)
abstract TrampolineTemplate generateTrampolineTemplate();
abstract void generateTrampolineTemplate(SubstrateBackendWithAssembler<?> backend, TrampolineTemplate template);
}

class ABIs {
Expand Down Expand Up @@ -740,8 +773,8 @@ public int trampolineSize() {
}

@Override
public TrampolineTemplate generateTrampolineTemplate() {
return null;
public void generateTrampolineTemplate(SubstrateBackendWithAssembler<?> backend, TrampolineTemplate template) {
fail();
}

@Override
Expand Down Expand Up @@ -812,8 +845,8 @@ public int trampolineSize() {

@Platforms(Platform.HOSTED_ONLY.class)
@Override
public TrampolineTemplate generateTrampolineTemplate() {
AArch64MacroAssembler masm = new SubstrateAArch64MacroAssembler(ConfigurationValues.getTarget());
public void generateTrampolineTemplate(SubstrateBackendWithAssembler<?> backend, TrampolineTemplate template) {
AArch64MacroAssembler masm = (AArch64MacroAssembler) backend.createAssemblerNoOptions();

Register mhRegister = upcallSpecialArgumentsRegisters().methodHandle();
Register isolateRegister = upcallSpecialArgumentsRegisters().isolate();
Expand Down Expand Up @@ -849,12 +882,11 @@ public TrampolineTemplate generateTrampolineTemplate() {
masm.jmp(scratch);

assert trampolineSize() >= masm.position();
masm.align(trampolineSize());

byte[] assembly = masm.close(true);
byte[] assembly = masm.closeAligned(true, trampolineSize());
assert assembly.length == trampolineSize();

return new TrampolineTemplate(assembly, posIsolate, posMHArray, posCallTarget);
template.setTemplate(assembly, posIsolate, posMHArray, posCallTarget);
}

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

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

asm.maybeEmitIndirectTargetMarker();
/* Store isolate in the assigned register */
asm.movq(isolateRegister, 0L, true);
/* r10 points in the mh array */
Expand All @@ -997,17 +1030,21 @@ public TrampolineTemplate generateTrampolineTemplate() {
/* rax contains the stub address */
asm.movq(rax, 0L, true);
/* executes the stub */
asm.jmp(new AMD64Address(rax, 0));
if (SubstrateControlFlowIntegrity.useSoftwareCFI()) {
asm.movq(rax, new AMD64Address(rax, 0));
asm.jmp(rax);
} else {
asm.jmp(new AMD64Address(rax, 0));
}

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

byte[] assembly = asm.close(true);
byte[] assembly = asm.closeAligned(true, trampolineSize());
assert assembly.length == trampolineSize();
assert odas.size() == 3;
assert odas.stream().allMatch(oda -> oda.operandSize == 8);

return new TrampolineTemplate(assembly, odas.get(0).operandPosition, odas.get(1).operandPosition, odas.get(2).operandPosition);
template.setTemplate(assembly, odas.get(0).operandPosition, odas.get(1).operandPosition, odas.get(2).operandPosition);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.Uninterruptible;
import com.oracle.svm.core.c.InvokeJavaFunctionPointer;
import com.oracle.svm.core.foreign.AbiUtils.TrampolineTemplate;
import com.oracle.svm.core.foreign.phases.SubstrateOptimizeSharedArenaAccessPhase.OptimizeSharedArenaConfig;
import com.oracle.svm.core.graal.code.SubstrateBackendWithAssembler;
import com.oracle.svm.core.headers.LibC;
import com.oracle.svm.core.headers.WindowsAPIs;
import com.oracle.svm.core.image.DisallowedImageHeapObjects.DisallowedObjectReporter;
Expand Down Expand Up @@ -99,7 +101,12 @@ public static ForeignFunctionsRuntime singleton() {

@Platforms(Platform.HOSTED_ONLY.class)
public ForeignFunctionsRuntime(AbiUtils abiUtils) {
this.trampolineTemplate = abiUtils.generateTrampolineTemplate();
this.trampolineTemplate = new TrampolineTemplate(new byte[abiUtils.trampolineSize()]);
}

@Platforms(Platform.HOSTED_ONLY.class)
public void generateTrampolineTemplate(SubstrateBackendWithAssembler<?> backend) {
AbiUtils.singleton().generateTrampolineTemplate(backend, this.trampolineTemplate);
}

public static boolean areFunctionCallsSupported() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ private Pointer prepareTrampolines(PinnedObject mhsArray, PinnedObject stubsArra
VMError.guarantee(it.belowOrEqual(end), "Not enough memory was allocated to hold trampolines");
}

VMError.guarantee(VirtualMemoryProvider.get().protect(page, pageSize, VirtualMemoryProvider.Access.EXECUTE) == 0,
VMError.guarantee(VirtualMemoryProvider.get().protect(page, pageSize, VirtualMemoryProvider.Access.READ | VirtualMemoryProvider.Access.EXECUTE) == 0,
"Error when making the trampoline allocation executable");

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
import com.oracle.svm.core.graal.code.AssignedLocation;
import com.oracle.svm.core.graal.code.PatchConsumerFactory;
import com.oracle.svm.core.graal.code.SharedCompilationResult;
import com.oracle.svm.core.graal.code.SubstrateBackend;
import com.oracle.svm.core.graal.code.SubstrateBackendWithAssembler;
import com.oracle.svm.core.graal.code.SubstrateCallingConvention;
import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind;
import com.oracle.svm.core.graal.code.SubstrateCallingConventionType;
Expand Down Expand Up @@ -194,7 +194,7 @@
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.Value;

public class SubstrateAArch64Backend extends SubstrateBackend implements LIRGenerationProvider {
public class SubstrateAArch64Backend extends SubstrateBackendWithAssembler<SubstrateAArch64MacroAssembler> implements LIRGenerationProvider {

protected static CompressEncoding getCompressEncoding() {
return ImageSingletons.lookup(CompressEncoding.class);
Expand Down Expand Up @@ -1564,4 +1564,9 @@ public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilat
public BasePhase<CoreProviders> newAddressLoweringPhase(CodeCacheProvider codeCache) {
return new AddressLoweringByUsePhase(new AArch64AddressLoweringByUse(createLirKindTool(), false));
}

@Override
public SubstrateAArch64MacroAssembler createAssembler(OptionValues options) {
return new SubstrateAArch64MacroAssembler(getTarget());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
import java.util.List;
import java.util.function.BiConsumer;

import org.graalvm.collections.EconomicMap;
import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.CPUFeatureAccess;
Expand All @@ -67,7 +66,7 @@
import com.oracle.svm.core.graal.code.PatchConsumerFactory;
import com.oracle.svm.core.graal.code.SharedCompilationResult;
import com.oracle.svm.core.graal.code.StubCallingConvention;
import com.oracle.svm.core.graal.code.SubstrateBackend;
import com.oracle.svm.core.graal.code.SubstrateBackendWithAssembler;
import com.oracle.svm.core.graal.code.SubstrateCallingConvention;
import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind;
import com.oracle.svm.core.graal.code.SubstrateCallingConventionType;
Expand Down Expand Up @@ -222,7 +221,7 @@
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.Value;

public class SubstrateAMD64Backend extends SubstrateBackend implements LIRGenerationProvider {
public class SubstrateAMD64Backend extends SubstrateBackendWithAssembler<AMD64MacroAssembler> implements LIRGenerationProvider {

protected static CompressEncoding getCompressEncoding() {
return ImageSingletons.lookup(CompressEncoding.class);
Expand Down Expand Up @@ -1922,6 +1921,7 @@ public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult
return crb;
}

@Override
protected AMD64MacroAssembler createAssembler(OptionValues options) {
return new AMD64MacroAssembler(getTarget(), options, true);
}
Expand Down Expand Up @@ -1961,11 +1961,6 @@ public void emitCode(CompilationResultBuilder crb, ResolvedJavaMethod installedC
}
}

public AMD64Assembler createAssemblerNoOptions() {
OptionValues o = new OptionValues(EconomicMap.create());
return createAssembler(o);
}

protected void resetForEmittingCode(CompilationResultBuilder crb) {
crb.resetForEmittingCode();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2025, 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 com.oracle.svm.core.graal.code;

import org.graalvm.collections.EconomicMap;

import jdk.graal.compiler.asm.Assembler;
import jdk.graal.compiler.options.OptionValues;
import jdk.graal.compiler.phases.util.Providers;

public abstract class SubstrateBackendWithAssembler<A extends Assembler<?>> extends SubstrateBackend {

protected SubstrateBackendWithAssembler(Providers providers) {
super(providers);
}

protected abstract A createAssembler(OptionValues options);

public final A createAssemblerNoOptions() {
OptionValues o = new OptionValues(EconomicMap.create());
return createAssembler(o);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
import com.oracle.svm.core.foreign.Target_java_nio_MappedMemoryUtils;
import com.oracle.svm.core.foreign.phases.SubstrateOptimizeSharedArenaAccessPhase;
import com.oracle.svm.core.graal.RuntimeCompilation;
import com.oracle.svm.core.graal.code.SubstrateBackend;
import com.oracle.svm.core.graal.code.SubstrateBackendWithAssembler;
import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider;
import com.oracle.svm.core.jdk.VectorAPIEnabled;
import com.oracle.svm.core.meta.MethodPointer;
Expand Down Expand Up @@ -405,6 +407,17 @@ public void duringSetup(DuringSetupAccess a) {
ConfigurationParserUtils.parseAndRegisterConfigurationsFromCombinedFile(getConfigurationParser(imageClassLoader), imageClassLoader, "panama foreign");
}

@Override
public void beforeCompilation(BeforeCompilationAccess access) {
FeatureImpl.BeforeCompilationAccessImpl a = (FeatureImpl.BeforeCompilationAccessImpl) access;
SubstrateBackend b = a.getRuntimeConfiguration().getBackendForNormalMethod();
if (b instanceof SubstrateBackendWithAssembler<?> bAsm) {
foreignFunctionsRuntime.generateTrampolineTemplate(bAsm);
} else {
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());
}
}

private ConfigurationParser getConfigurationParser(ImageClassLoader imageClassLoader) {
/*
* If foreign function calls are not supported on this platform, we still want to parse the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public byte[] generatePLT(SharedMethod[] got, SubstrateBackend substrateBackend)
RegisterConfig registerConfig = amd64Backend.getCodeCache().getRegisterConfig();
Register register = configuration.getGOTPassingRegister(registerConfig);

AMD64MacroAssembler asm = (AMD64MacroAssembler) amd64Backend.createAssemblerNoOptions();
AMD64MacroAssembler asm = amd64Backend.createAssemblerNoOptions();
PLTSectionSupport support = HostedPLTGOTConfiguration.singleton().getPLTSectionSupport();

asm.setCodePatchingAnnotationConsumer(this::recordResolverCallForPatching);
Expand Down