8317545: AIX PPC64: Implementation of Foreign Function & Memory API

Reviewed-by: jvernee
This commit is contained in:
Martin Doerr 2023-11-02 13:13:46 +00:00
parent e9d19d0fff
commit 99efcded6c
12 changed files with 209 additions and 30 deletions

View File

@ -47,11 +47,7 @@ bool ABIDescriptor::is_volatile_reg(FloatRegister reg) const {
}
bool ForeignGlobals::is_foreign_linker_supported() {
#ifdef LINUX
return true;
#else
return false;
#endif
}
// Stubbed out, implement later

View File

@ -39,6 +39,7 @@ public enum CABI {
LINUX_AARCH_64,
MAC_OS_AARCH_64,
WIN_AARCH_64,
AIX_PPC_64,
LINUX_PPC_64,
LINUX_PPC_64_LE,
LINUX_RISCV_64,
@ -78,6 +79,8 @@ public enum CABI {
} else if (arch.equals("ppc64")) {
if (OperatingSystem.isLinux()) {
return LINUX_PPC_64;
} else if (OperatingSystem.isAix()) {
return AIX_PPC_64;
}
} else if (arch.equals("ppc64le")) {
if (OperatingSystem.isLinux()) {

View File

@ -30,6 +30,7 @@ import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker;
import jdk.internal.foreign.abi.fallback.FallbackLinker;
import jdk.internal.foreign.abi.ppc64.aix.AixPPC64Linker;
import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64Linker;
import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker;
import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker;
@ -62,7 +63,7 @@ import java.util.Set;
public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker,
SysVx64Linker, WindowsAArch64Linker,
Windowsx64Linker,
Windowsx64Linker, AixPPC64Linker,
LinuxPPC64Linker, LinuxPPC64leLinker,
LinuxRISCV64Linker, LinuxS390Linker,
FallbackLinker {
@ -179,6 +180,11 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
}
}
// some ABIs have special handling for struct members
protected void checkStructMember(MemoryLayout member, long offset) {
checkLayoutRecursive(member);
}
private void checkLayoutRecursive(MemoryLayout layout) {
if (layout instanceof ValueLayout vl) {
checkSupported(vl);
@ -190,7 +196,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
// check element offset before recursing so that an error points at the
// outermost layout first
checkMemberOffset(sl, member, lastUnpaddedOffset, offset);
checkLayoutRecursive(member);
checkStructMember(member, offset);
offset += member.byteSize();
if (!(member instanceof PaddingLayout)) {

View File

@ -33,6 +33,7 @@ import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker;
import jdk.internal.foreign.abi.fallback.FallbackLinker;
import jdk.internal.foreign.abi.ppc64.aix.AixPPC64Linker;
import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64Linker;
import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker;
import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker;
@ -244,6 +245,7 @@ public final class SharedUtils {
case LINUX_AARCH_64 -> LinuxAArch64Linker.getInstance();
case MAC_OS_AARCH_64 -> MacOsAArch64Linker.getInstance();
case WIN_AARCH_64 -> WindowsAArch64Linker.getInstance();
case AIX_PPC_64 -> AixPPC64Linker.getInstance();
case LINUX_PPC_64 -> LinuxPPC64Linker.getInstance();
case LINUX_PPC_64_LE -> LinuxPPC64leLinker.getInstance();
case LINUX_RISCV_64 -> LinuxRISCV64Linker.getInstance();

View File

@ -35,6 +35,9 @@ import jdk.internal.foreign.abi.DowncallLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.ppc64.aix.AixCallArranger;
import jdk.internal.foreign.abi.ppc64.linux.ABIv1CallArranger;
import jdk.internal.foreign.abi.ppc64.linux.ABIv2CallArranger;
import java.lang.foreign.AddressLayout;
import java.lang.foreign.FunctionDescriptor;
@ -62,6 +65,7 @@ import static jdk.internal.foreign.abi.ppc64.PPC64Architecture.Regs.*;
*/
public abstract class CallArranger {
final boolean useABIv2 = useABIv2();
final boolean isAIX = isAIX();
private static final int STACK_SLOT_SIZE = 8;
private static final int MAX_COPY_SIZE = 8;
@ -91,11 +95,13 @@ public abstract class CallArranger {
public static final CallArranger ABIv1 = new ABIv1CallArranger();
public static final CallArranger ABIv2 = new ABIv2CallArranger();
public static final CallArranger AIX = new AixCallArranger();
/**
* Select ABI version
*/
protected abstract boolean useABIv2();
protected abstract boolean isAIX();
public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {
return getBindings(mt, cDesc, forUpcall, LinkerOptions.empty());
@ -206,7 +212,7 @@ public abstract class CallArranger {
// offset for the next argument which will really use the stack.
// The reserved space for the Parameter Save Area is determined by the DowncallStubGenerator.
VMStorage stack;
if (!useABIv2 && is32Bit) {
if (!useABIv2 && !isAIX && is32Bit) {
stackAlloc(4, STACK_SLOT_SIZE); // Skip first half of stack slot.
stack = stackAlloc(4, 4);
} else {
@ -343,13 +349,14 @@ public abstract class CallArranger {
@Override
List<Binding> getBindings(Class<?> carrier, MemoryLayout layout) {
TypeClass argumentClass = TypeClass.classifyLayout(layout, useABIv2);
TypeClass argumentClass = TypeClass.classifyLayout(layout, useABIv2, isAIX);
Binding.Builder bindings = Binding.builder();
switch (argumentClass) {
case STRUCT_REGISTER -> {
assert carrier == MemorySegment.class;
VMStorage[] regs = storageCalculator.structAlloc(layout);
final boolean isLargeABIv1Struct = !useABIv2 && layout.byteSize() > MAX_COPY_SIZE;
final boolean isLargeABIv1Struct = !useABIv2 &&
(isAIX || layout.byteSize() > MAX_COPY_SIZE);
long offset = 0;
for (VMStorage storage : regs) {
// Last slot may be partly used.
@ -430,14 +437,15 @@ public abstract class CallArranger {
@Override
List<Binding> getBindings(Class<?> carrier, MemoryLayout layout) {
TypeClass argumentClass = TypeClass.classifyLayout(layout, useABIv2);
TypeClass argumentClass = TypeClass.classifyLayout(layout, useABIv2, isAIX);
Binding.Builder bindings = Binding.builder();
switch (argumentClass) {
case STRUCT_REGISTER -> {
assert carrier == MemorySegment.class;
bindings.allocate(layout);
VMStorage[] regs = storageCalculator.structAlloc(layout);
final boolean isLargeABIv1Struct = !useABIv2 && layout.byteSize() > MAX_COPY_SIZE;
final boolean isLargeABIv1Struct = !useABIv2 &&
(isAIX || layout.byteSize() > MAX_COPY_SIZE);
long offset = 0;
for (VMStorage storage : regs) {
// Last slot may be partly used.

View File

@ -112,8 +112,8 @@ public enum TypeClass {
return true;
}
private static TypeClass classifyStructType(MemoryLayout layout, boolean useABIv2) {
if (isHomogeneousFloatAggregate(layout, useABIv2)) {
private static TypeClass classifyStructType(MemoryLayout layout, boolean useABIv2, boolean isAIX) {
if (!isAIX && isHomogeneousFloatAggregate(layout, useABIv2)) {
return TypeClass.STRUCT_HFA;
}
return TypeClass.STRUCT_REGISTER;
@ -124,11 +124,11 @@ public enum TypeClass {
return isHomogeneousFloatAggregate(layout, true) || isReturnRegisterAggregate(layout);
}
public static TypeClass classifyLayout(MemoryLayout type, boolean useABIv2) {
public static TypeClass classifyLayout(MemoryLayout type, boolean useABIv2, boolean isAIX) {
if (type instanceof ValueLayout) {
return classifyValueType((ValueLayout) type);
} else if (type instanceof GroupLayout) {
return classifyStructType(type, useABIv2);
return classifyStructType(type, useABIv2, isAIX);
} else {
throw new IllegalArgumentException("Unhandled type " + type);
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023 SAP SE. 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.internal.foreign.abi.ppc64.aix;
import jdk.internal.foreign.abi.ppc64.CallArranger;
/**
* PPC64 CallArranger specialized for AIX.
*/
public class AixCallArranger extends CallArranger {
@Override
protected boolean useABIv2() {
return false;
}
@Override
protected boolean isAIX() {
return true;
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023 SAP SE. 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.internal.foreign.abi.ppc64.aix;
import jdk.internal.foreign.abi.AbstractLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.ppc64.CallArranger;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.Map;
public final class AixPPC64Linker extends AbstractLinker {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT);
public static AixPPC64Linker getInstance() {
final class Holder {
private static final AixPPC64Linker INSTANCE = new AixPPC64Linker();
}
return Holder.INSTANCE;
}
private AixPPC64Linker() {
// Ensure there is only one instance
}
@Override
protected void checkStructMember(MemoryLayout member, long offset) {
// special case double members that are not the first member
// see: https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes
// Note: It is possible to enforce 8-byte alignment by #pragma align (natural)
// Therefore, we use normal checks if we are already 8-byte aligned.
if ((offset % 8 != 0) && (member instanceof ValueLayout vl && vl.carrier() == double.class)) {
if (vl.byteAlignment() != 4) {
throw new IllegalArgumentException("double struct member " + vl + " at offset " + offset + " should be 4-byte aligned");
}
if (vl.order() != linkerByteOrder()) {
throw new IllegalArgumentException("double struct member " + vl + " at offset " + offset + " has an unexpected byte order");
}
} else {
super.checkStructMember(member, offset);
}
}
@Override
protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) {
return CallArranger.AIX.arrangeDowncall(inferredMethodType, function, options);
}
@Override
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return CallArranger.AIX.arrangeUpcall(targetType, function, options);
}
@Override
protected ByteOrder linkerByteOrder() {
return ByteOrder.BIG_ENDIAN;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
return CANONICAL_LAYOUTS;
}
}

View File

@ -23,7 +23,9 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.foreign.abi.ppc64;
package jdk.internal.foreign.abi.ppc64.linux;
import jdk.internal.foreign.abi.ppc64.CallArranger;
/**
* PPC64 CallArranger specialized for ABI v1.
@ -34,4 +36,9 @@ public class ABIv1CallArranger extends CallArranger {
protected boolean useABIv2() {
return false;
}
@Override
protected boolean isAIX() {
return false;
}
}

View File

@ -23,7 +23,9 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.foreign.abi.ppc64;
package jdk.internal.foreign.abi.ppc64.linux;
import jdk.internal.foreign.abi.ppc64.CallArranger;
/**
* PPC64 CallArranger specialized for ABI v2.
@ -34,4 +36,9 @@ public class ABIv2CallArranger extends CallArranger {
protected boolean useABIv2() {
return true;
}
@Override
protected boolean isAIX() {
return false;
}
}

View File

@ -33,46 +33,45 @@ import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
public class CLayouts {
private static Linker LINKER = Linker.nativeLinker();
// the constants below are useful aliases for C types. The type/carrier association is only valid for 64-bit platforms.
/**
* The layout for the {@code bool} C type
*/
public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN;
public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) LINKER.canonicalLayouts().get("bool");
/**
* The layout for the {@code char} C type
*/
public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE;
public static final ValueLayout.OfByte C_CHAR = (ValueLayout.OfByte) LINKER.canonicalLayouts().get("char");
/**
* The layout for the {@code short} C type
*/
public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT;
public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) LINKER.canonicalLayouts().get("short");
/**
* The layout for the {@code int} C type
*/
public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT;
public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) LINKER.canonicalLayouts().get("int");
/**
* The layout for the {@code long long} C type.
*/
public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG;
public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) LINKER.canonicalLayouts().get("long");
/**
* The layout for the {@code float} C type
*/
public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT;
public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) LINKER.canonicalLayouts().get("float");
/**
* The layout for the {@code double} C type
*/
public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE;
public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) LINKER.canonicalLayouts().get("double");
/**
* The {@code T*} native type.
*/
public static final AddressLayout C_POINTER = ValueLayout.ADDRESS
.withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, C_CHAR));
private static Linker LINKER = Linker.nativeLinker();
private static final MethodHandle FREE = LINKER.downcallHandle(
LINKER.defaultLookup().find("free").get(), FunctionDescriptor.ofVoid(C_POINTER));

View File

@ -25,11 +25,11 @@ package org.openjdk.bench.java.lang.foreign.pointers;
import java.lang.foreign.AddressLayout;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.Linker;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
public sealed abstract class NativeType<X> {
public abstract MemoryLayout layout();
public non-sealed static abstract class OfInt<X> extends NativeType<X> {
@ -39,6 +39,18 @@ public sealed abstract class NativeType<X> {
public abstract ValueLayout.OfDouble layout();
}
private static Linker LINKER = Linker.nativeLinker();
/**
* The layout for the {@code int} C type
*/
private static final ValueLayout.OfInt CANONICAL_INT = (ValueLayout.OfInt) LINKER.canonicalLayouts().get("int");
/**
* The layout for the {@code double} C type
*/
private static final ValueLayout.OfDouble CANONICAL_DOUBLE = (ValueLayout.OfDouble) LINKER.canonicalLayouts().get("double");
private static final AddressLayout UNSAFE_ADDRESS = ValueLayout.ADDRESS
.withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE));
@ -56,14 +68,14 @@ public sealed abstract class NativeType<X> {
public static final OfInt<Integer> C_INT = new OfInt<>() {
@Override
public ValueLayout.OfInt layout() {
return ValueLayout.JAVA_INT;
return CANONICAL_INT;
}
};
public static final OfDouble<Double> C_DOUBLE = new OfDouble<>() {
@Override
public ValueLayout.OfDouble layout() {
return ValueLayout.JAVA_DOUBLE;
return CANONICAL_DOUBLE;
}
};