From de26411058e1d86e35d450175fb044471bee65c0 Mon Sep 17 00:00:00 2001 From: Cheng Jin Date: Mon, 19 Jul 2021 11:51:28 -0400 Subject: [PATCH] Implement the CLinker downcall handle of JEP389 on PPC64/S390x The changes aim to enable the CLinker downcall handle to support primitives and struct on AIX/ppc64, Linux/ppc64le and Linux/s390x by invoking the code in ProgrammableInvoker implemented in OpenJ9. Signed-off-by: Cheng Jin --- closed/OpenJ9.gmk | 1 + .../jdk/incubator/foreign/CLinker.java | 25 +- .../classes/jdk/internal/foreign/CABI.java | 22 +- .../jdk/internal/foreign/PlatformLayouts.java | 191 ++++++- .../jdk/internal/foreign/abi/SharedUtils.java | 22 + .../foreign/abi/aarch64/CallArranger.java | 26 +- .../foreign/abi/ppc64/aix/AixVaList.java | 500 +++++++++++++++++ .../foreign/abi/ppc64/aix/Aixppc64Linker.java | 117 ++++ .../abi/ppc64/aix/ArgumentClassImpl.java | 87 +++ .../foreign/abi/ppc64/aix/CallArranger.java | 71 +++ .../foreign/abi/ppc64/aix/TypeClass.java | 234 ++++++++ .../foreign/abi/ppc64/sysv/CallArranger.java | 71 +++ .../foreign/abi/ppc64/sysv/SysVVaList.java | 288 ++++++++++ .../abi/ppc64/sysv/SysVppc64leLinker.java | 117 ++++ .../foreign/abi/ppc64/sysv/TypeClass.java | 92 ++++ .../abi/s390x/sysv/ArgumentClassImpl.java | 87 +++ .../foreign/abi/s390x/sysv/CallArranger.java | 70 +++ .../foreign/abi/s390x/sysv/SysVVaList.java | 510 ++++++++++++++++++ .../abi/s390x/sysv/SysVs390xLinker.java | 117 ++++ .../foreign/abi/s390x/sysv/TypeClass.java | 234 ++++++++ .../foreign/abi/x64/sysv/CallArranger.java | 27 +- .../foreign/abi/x64/windows/CallArranger.java | 26 +- 22 files changed, 2877 insertions(+), 58 deletions(-) create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/AixVaList.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/Aixppc64Linker.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/ArgumentClassImpl.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/CallArranger.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/TypeClass.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/CallArranger.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/SysVVaList.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/SysVppc64leLinker.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/TypeClass.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/ArgumentClassImpl.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/CallArranger.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/SysVVaList.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/SysVs390xLinker.java create mode 100644 src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/TypeClass.java diff --git a/closed/OpenJ9.gmk b/closed/OpenJ9.gmk index 66dc45e1ee2..e3549b7a468 100644 --- a/closed/OpenJ9.gmk +++ b/closed/OpenJ9.gmk @@ -182,6 +182,7 @@ $(foreach file, \ testlibA \ testlibB \ vmruntimestateagent29 \ + clinkerffitests \ ) \ $(patsubst %, $(OPENJ9_VM_BUILD_DIR)/lib%.jnilib, \ loadLibraryTest \ diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/CLinker.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/CLinker.java index 786c2d8d9c7..489b0fc36b6 100644 --- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/CLinker.java +++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/CLinker.java @@ -23,6 +23,13 @@ * questions. * */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + package jdk.incubator.foreign; import jdk.internal.foreign.NativeMemorySegmentImpl; @@ -157,39 +164,39 @@ static CLinker getInstance() { /** * The layout for the {@code char} C type */ - ValueLayout C_CHAR = pick(SysV.C_CHAR, Win64.C_CHAR, AArch64.C_CHAR); + ValueLayout C_CHAR = pick(SysV.C_CHAR, Win64.C_CHAR, AArch64.C_CHAR, SysVppc64le.C_CHAR, SysVs390x.C_CHAR, AIX.C_CHAR); /** * The layout for the {@code short} C type */ - ValueLayout C_SHORT = pick(SysV.C_SHORT, Win64.C_SHORT, AArch64.C_SHORT); + ValueLayout C_SHORT = pick(SysV.C_SHORT, Win64.C_SHORT, AArch64.C_SHORT, SysVppc64le.C_SHORT, SysVs390x.C_SHORT, AIX.C_SHORT); /** * The layout for the {@code int} C type */ - ValueLayout C_INT = pick(SysV.C_INT, Win64.C_INT, AArch64.C_INT); + ValueLayout C_INT = pick(SysV.C_INT, Win64.C_INT, AArch64.C_INT, SysVppc64le.C_INT, SysVs390x.C_INT, AIX.C_INT); /** * The layout for the {@code long} C type */ - ValueLayout C_LONG = pick(SysV.C_LONG, Win64.C_LONG, AArch64.C_LONG); + ValueLayout C_LONG = pick(SysV.C_LONG, Win64.C_LONG, AArch64.C_LONG, SysVppc64le.C_LONG, SysVs390x.C_LONG, AIX.C_LONG); /** * The layout for the {@code long long} C type. */ - ValueLayout C_LONG_LONG = pick(SysV.C_LONG_LONG, Win64.C_LONG_LONG, AArch64.C_LONG_LONG); + ValueLayout C_LONG_LONG = pick(SysV.C_LONG_LONG, Win64.C_LONG_LONG, AArch64.C_LONG_LONG, SysVppc64le.C_LONG_LONG, SysVs390x.C_LONG_LONG, AIX.C_LONG_LONG); /** * The layout for the {@code float} C type */ - ValueLayout C_FLOAT = pick(SysV.C_FLOAT, Win64.C_FLOAT, AArch64.C_FLOAT); + ValueLayout C_FLOAT = pick(SysV.C_FLOAT, Win64.C_FLOAT, AArch64.C_FLOAT, SysVppc64le.C_FLOAT, SysVs390x.C_FLOAT, AIX.C_FLOAT); /** * The layout for the {@code double} C type */ - ValueLayout C_DOUBLE = pick(SysV.C_DOUBLE, Win64.C_DOUBLE, AArch64.C_DOUBLE); + ValueLayout C_DOUBLE = pick(SysV.C_DOUBLE, Win64.C_DOUBLE, AArch64.C_DOUBLE, SysVppc64le.C_DOUBLE, SysVs390x.C_DOUBLE, AIX.C_DOUBLE); /** * The {@code T*} native type. */ - ValueLayout C_POINTER = pick(SysV.C_POINTER, Win64.C_POINTER, AArch64.C_POINTER); + ValueLayout C_POINTER = pick(SysV.C_POINTER, Win64.C_POINTER, AArch64.C_POINTER, SysVppc64le.C_POINTER, SysVs390x.C_POINTER, AIX.C_POINTER); /** * The layout for the {@code va_list} C type */ - MemoryLayout C_VA_LIST = pick(SysV.C_VA_LIST, Win64.C_VA_LIST, AArch64.C_VA_LIST); + MemoryLayout C_VA_LIST = pick(SysV.C_VA_LIST, Win64.C_VA_LIST, AArch64.C_VA_LIST, SysVppc64le.C_VA_LIST, SysVs390x.C_VA_LIST, AIX.C_VA_LIST); /** * Returns a memory layout that is suitable to use as the layout for variadic arguments in a specialized diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/CABI.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/CABI.java index d051eb99348..760c88ee842 100644 --- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/CABI.java +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/CABI.java @@ -23,6 +23,13 @@ * questions. * */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + package jdk.internal.foreign; import jdk.internal.foreign.abi.SharedUtils; @@ -32,9 +39,12 @@ public enum CABI { SysV, Win64, - AArch64; + AArch64, + SysVppc64le, + SysVs390x, + AIX; - private static final CABI current; + private static CABI current; static { String arch = System.getProperty("os.arch"); @@ -50,6 +60,14 @@ public enum CABI { } } else if (arch.equals("aarch64")) { current = AArch64; + } else if (arch.startsWith("ppc64")) { + if (os.startsWith("Linux")) { + current = SysVppc64le; + } else { + current = AIX; + } + } else if (arch.equals("s390x") && os.startsWith("Linux")) { + current = SysVs390x; } else { throw new ExceptionInInitializerError( "Unsupported os, arch, or address size: " + os + ", " + arch + ", " + addressSize); diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/PlatformLayouts.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/PlatformLayouts.java index 16e268acc68..68ceff5c24e 100644 --- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/PlatformLayouts.java +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/PlatformLayouts.java @@ -23,6 +23,13 @@ * questions. * */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + package jdk.internal.foreign; import jdk.incubator.foreign.CLinker; @@ -32,14 +39,18 @@ import java.nio.ByteOrder; import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static java.nio.ByteOrder.BIG_ENDIAN; import static jdk.incubator.foreign.MemoryLayouts.ADDRESS; public class PlatformLayouts { - public static Z pick(Z sysv, Z win64, Z aarch64) { + public static Z pick(Z sysv, Z win64, Z aarch64, Z sysvppc64le, Z sysvs390x, Z aix) { return switch (CABI.current()) { case SysV -> sysv; case Win64 -> win64; case AArch64 -> aarch64; + case SysVppc64le -> sysvppc64le; + case SysVs390x -> sysvs390x; + case AIX -> aix; }; } @@ -273,4 +284,182 @@ private AArch64() { */ public static final MemoryLayout C_VA_LIST = AArch64.C_POINTER; } + + /** + * This class defines layout constants modelling standard primitive types supported by the PPC64LE SystemV ABI. + */ + public static final class SysVppc64le { + private SysVppc64le() { + //just the one + } + + /** + * The name of the layout attribute (see {@link MemoryLayout#attributes()} used to mark variadic parameters. The + * attribute value must be a boolean. + */ + public final static String VARARGS_ATTRIBUTE_NAME = "abi/SysV/varargs"; + + /** + * The {@code char} native type. + */ + public static final ValueLayout C_CHAR = ofChar(LITTLE_ENDIAN, 8); + + /** + * The {@code short} native type. + */ + public static final ValueLayout C_SHORT = ofShort(LITTLE_ENDIAN, 16); + + /** + * The {@code int} native type. + */ + public static final ValueLayout C_INT = ofInt(LITTLE_ENDIAN, 32); + + /** + * The {@code long} native type. + */ + public static final ValueLayout C_LONG = ofLong(LITTLE_ENDIAN, 64); + + /** + * The {@code long long} native type. + */ + public static final ValueLayout C_LONG_LONG = ofLongLong(LITTLE_ENDIAN, 64); + + /** + * The {@code float} native type. + */ + public static final ValueLayout C_FLOAT = ofFloat(LITTLE_ENDIAN, 32); + + /** + * The {@code double} native type. + */ + public static final ValueLayout C_DOUBLE = ofDouble(LITTLE_ENDIAN, 64); + + /** + * The {@code T*} native type. + */ + public static final ValueLayout C_POINTER = ofPointer(LITTLE_ENDIAN, 64); + + /** + * The {@code va_list} native type, as it is passed to a function. + */ + public static final MemoryLayout C_VA_LIST = SysVppc64le.C_POINTER; + + /** + * Return a new memory layout which describes a variadic parameter to be passed to a function. + * @param layout the original parameter layout. + * @return a layout which is the same as {@code layout}, except for the extra attribute {@link #VARARGS_ATTRIBUTE_NAME}, + * which is set to {@code true}. + */ + public static MemoryLayout asVarArg(MemoryLayout layout) { + return layout.withAttribute(VARARGS_ATTRIBUTE_NAME, true); + } + } + + /** + * This class defines layout constants modelling standard primitive types supported by the s390x SystemV ABI. + */ + public static final class SysVs390x { + private SysVs390x() { + //just the one + } + + /** + * The {@code char} native type. + */ + public static final ValueLayout C_CHAR = ofChar(BIG_ENDIAN, 8); + + /** + * The {@code short} native type. + */ + public static final ValueLayout C_SHORT = ofShort(BIG_ENDIAN, 16); + + /** + * The {@code int} native type. + */ + public static final ValueLayout C_INT = ofInt(BIG_ENDIAN, 32); + + /** + * The {@code long} native type. + */ + public static final ValueLayout C_LONG = ofLong(BIG_ENDIAN, 64); + + /** + * The {@code long long} native type. + */ + public static final ValueLayout C_LONG_LONG = ofLongLong(BIG_ENDIAN, 64); + + /** + * The {@code float} native type. + */ + public static final ValueLayout C_FLOAT = ofFloat(BIG_ENDIAN, 32); + + /** + * The {@code double} native type. + */ + public static final ValueLayout C_DOUBLE = ofDouble(BIG_ENDIAN, 64); + + /** + * The {@code T*} native type. + */ + public static final ValueLayout C_POINTER = ofPointer(BIG_ENDIAN, 64); + + /** + * The {@code va_list} native type, as it is passed to a function. + */ + public static final MemoryLayout C_VA_LIST = SysVs390x.C_POINTER; + } + + /** + * This class defines layout constants modelling standard primitive types supported by the s390x SystemV ABI. + */ + public static final class AIX { + private AIX() { + //just the one + } + + /** + * The {@code char} native type. + */ + public static final ValueLayout C_CHAR = ofChar(BIG_ENDIAN, 8); + + /** + * The {@code short} native type. + */ + public static final ValueLayout C_SHORT = ofShort(BIG_ENDIAN, 16); + + /** + * The {@code int} native type. + */ + public static final ValueLayout C_INT = ofInt(BIG_ENDIAN, 32); + + /** + * The {@code long} native type. + */ + public static final ValueLayout C_LONG = ofLong(BIG_ENDIAN, 64); + + /** + * The {@code long long} native type. + */ + public static final ValueLayout C_LONG_LONG = ofLongLong(BIG_ENDIAN, 64); + + /** + * The {@code float} native type. + */ + public static final ValueLayout C_FLOAT = ofFloat(BIG_ENDIAN, 32); + + /** + * The {@code double} native type. + */ + public static final ValueLayout C_DOUBLE = ofDouble(BIG_ENDIAN, 64); + + /** + * The {@code T*} native type. + */ + public static final ValueLayout C_POINTER = ofPointer(BIG_ENDIAN, 64); + + /** + * The {@code va_list} native type, as it is passed to a function. + */ + public static final MemoryLayout C_VA_LIST = AIX.C_POINTER; + } } diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/SharedUtils.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/SharedUtils.java index 32530d57341..b21ac69e673 100644 --- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/SharedUtils.java +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/SharedUtils.java @@ -22,6 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + package jdk.internal.foreign.abi; import jdk.incubator.foreign.FunctionDescriptor; @@ -40,6 +47,9 @@ import jdk.internal.foreign.MemoryAddressImpl; import jdk.internal.foreign.Utils; import jdk.internal.foreign.abi.aarch64.AArch64Linker; +import jdk.internal.foreign.abi.ppc64.aix.Aixppc64Linker; +import jdk.internal.foreign.abi.ppc64.sysv.SysVppc64leLinker; +import jdk.internal.foreign.abi.s390x.sysv.SysVs390xLinker; import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker; import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker; @@ -242,6 +252,9 @@ public static CLinker getSystemLinker() { case Win64 -> Windowsx64Linker.getInstance(); case SysV -> SysVx64Linker.getInstance(); case AArch64 -> AArch64Linker.getInstance(); + case SysVppc64le -> SysVppc64leLinker.getInstance(); + case SysVs390x -> SysVs390xLinker.getInstance(); + case AIX -> Aixppc64Linker.getInstance(); }; } @@ -299,6 +312,9 @@ public static VaList newVaList(Consumer actions, Allocator alloc case Win64 -> Windowsx64Linker.newVaList(actions, allocator); case SysV -> SysVx64Linker.newVaList(actions, allocator); case AArch64 -> AArch64Linker.newVaList(actions, allocator); + case SysVppc64le -> SysVppc64leLinker.newVaList(actions, allocator); + case SysVs390x -> SysVs390xLinker.newVaList(actions, allocator); + case AIX -> Aixppc64Linker.newVaList(actions, allocator); }; } @@ -313,6 +329,9 @@ public static VaList newVaListOfAddress(MemoryAddress ma) { case Win64 -> Windowsx64Linker.newVaListOfAddress(ma); case SysV -> SysVx64Linker.newVaListOfAddress(ma); case AArch64 -> AArch64Linker.newVaListOfAddress(ma); + case SysVppc64le -> SysVppc64leLinker.newVaListOfAddress(ma); + case SysVs390x -> SysVs390xLinker.newVaListOfAddress(ma); + case AIX -> Aixppc64Linker.newVaListOfAddress(ma); }; } @@ -321,6 +340,9 @@ public static VaList emptyVaList() { case Win64 -> Windowsx64Linker.emptyVaList(); case SysV -> SysVx64Linker.emptyVaList(); case AArch64 -> AArch64Linker.emptyVaList(); + case SysVppc64le -> SysVppc64leLinker.emptyVaList(); + case SysVs390x -> SysVs390xLinker.emptyVaList(); + case AIX -> Aixppc64Linker.emptyVaList(); }; } diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java index 4b19004ec50..759259fd50f 100644 --- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java @@ -23,6 +23,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + package jdk.internal.foreign.abi.aarch64; import jdk.incubator.foreign.Addressable; @@ -126,26 +133,15 @@ public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, bool return new Bindings(csb.build(), returnInMemory); } + /* Replace ProgrammableInvoker in OpenJDK with the implementation of ProgrammableInvoker specific to OpenJ9 */ public static MethodHandle arrangeDowncall(Addressable addr, MethodType mt, FunctionDescriptor cDesc) { - Bindings bindings = getBindings(mt, cDesc, false); - - MethodHandle handle = new ProgrammableInvoker(C, addr, bindings.callingSequence).getBoundMethodHandle(); - - if (bindings.isInMemoryReturn) { - handle = SharedUtils.adaptDowncallForIMR(handle, cDesc); - } - + MethodHandle handle = ProgrammableInvoker.getBoundMethodHandle(addr, mt, cDesc); return handle; } + /* Replace ProgrammableUpcallHandler in OpenJDK with the implementation of ProgrammableUpcallHandler specific to OpenJ9 */ public static UpcallHandler arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc) { - Bindings bindings = getBindings(mt, cDesc, true); - - if (bindings.isInMemoryReturn) { - target = SharedUtils.adaptUpcallForIMR(target); - } - - return new ProgrammableUpcallHandler(C, target, bindings.callingSequence); + throw new InternalError("arrangeUpcall is not yet implemented"); //$NON-NLS-1$ } private static boolean isInMemoryReturn(Optional returnLayout) { diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/AixVaList.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/AixVaList.java new file mode 100644 index 00000000000..3f9f8f354ea --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/AixVaList.java @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.ppc64.aix; + +import jdk.incubator.foreign.*; +import jdk.internal.foreign.NativeMemorySegmentImpl; +import jdk.internal.foreign.Utils; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.misc.Unsafe; + +import java.lang.invoke.VarHandle; +import java.lang.ref.Cleaner; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static jdk.internal.foreign.PlatformLayouts.AIX; +import static jdk.incubator.foreign.CLinker.VaList; +import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement; +import static jdk.internal.foreign.abi.SharedUtils.SimpleVaArg; +import static jdk.internal.foreign.abi.SharedUtils.checkCompatibleType; +import static jdk.internal.foreign.abi.SharedUtils.vhPrimitiveOrAddress; + +/** + * This file is copied from x86/sysv as a placeholder for compilation as VaList on AIX/ppc64le + * at Java level is not yet implemented for the moment. The definition of VaList corresponds to + * the underlying struct of va_list defined on AIX/ppc64le which appears to be a 4-byte pointer + * to the actual argument value in debugging (totaly distinct from the existing struct defined in + * Windows or Linux on x86_64). Thus, futher analysis on the struct is required to understand how + * the struct is laid out in memory according to the description in the publisized ABI document + * at https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.pdf. + */ +public class AixVaList implements VaList { + private static final Unsafe U = Unsafe.getUnsafe(); + + static final Class CARRIER = MemoryAddress.class; + + static final GroupLayout LAYOUT = MemoryLayout.ofStruct( + AIX.C_INT.withName("gp_offset"), + AIX.C_INT.withName("fp_offset"), + AIX.C_POINTER.withName("overflow_arg_area"), + AIX.C_POINTER.withName("reg_save_area") + ).withName("__va_list_tag"); + + private static final MemoryLayout GP_REG = MemoryLayout.ofValueBits(64, ByteOrder.nativeOrder()); + private static final MemoryLayout FP_REG = MemoryLayout.ofValueBits(128, ByteOrder.nativeOrder()); + + private static final GroupLayout LAYOUT_REG_SAVE_AREA = MemoryLayout.ofStruct( + GP_REG.withName("%rdi"), + GP_REG.withName("%rsi"), + GP_REG.withName("%rdx"), + GP_REG.withName("%rcx"), + GP_REG.withName("%r8"), + GP_REG.withName("%r9"), + FP_REG.withName("%xmm0"), + FP_REG.withName("%xmm1"), + FP_REG.withName("%xmm2"), + FP_REG.withName("%xmm3"), + FP_REG.withName("%xmm4"), + FP_REG.withName("%xmm5"), + FP_REG.withName("%xmm6"), + FP_REG.withName("%xmm7") + ); + + private static final long FP_OFFSET = LAYOUT_REG_SAVE_AREA.byteOffset(groupElement("%xmm0")); + + private static final int GP_SLOT_SIZE = (int) GP_REG.byteSize(); + private static final int FP_SLOT_SIZE = (int) FP_REG.byteSize(); + + private static final int MAX_GP_OFFSET = (int) FP_OFFSET; // 6 regs used + private static final int MAX_FP_OFFSET = (int) LAYOUT_REG_SAVE_AREA.byteSize(); // 8 16 byte regs + + private static final VarHandle VH_fp_offset = LAYOUT.varHandle(int.class, groupElement("fp_offset")); + private static final VarHandle VH_gp_offset = LAYOUT.varHandle(int.class, groupElement("gp_offset")); + private static final VarHandle VH_overflow_arg_area + = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("overflow_arg_area"))); + private static final VarHandle VH_reg_save_area + = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("reg_save_area"))); + + private static final Cleaner cleaner = Cleaner.create(); + private static final VaList EMPTY = new SharedUtils.EmptyVaList(emptyListAddress()); + + private final MemorySegment segment; + private final MemorySegment regSaveArea; + private final List attachedSegments; + + private AixVaList(MemorySegment segment, MemorySegment regSaveArea, List attachedSegments) { + this.segment = segment; + this.regSaveArea = regSaveArea; + this.attachedSegments = attachedSegments; + } + + private static AixVaList readFromSegment(MemorySegment segment) { + MemorySegment regSaveArea = getRegSaveArea(segment); + return new AixVaList(segment, regSaveArea, List.of(regSaveArea)); + } + + private static MemoryAddress emptyListAddress() { + long ptr = U.allocateMemory(LAYOUT.byteSize()); + MemorySegment base = MemoryAddress.ofLong(ptr) + .asSegmentRestricted(LAYOUT.byteSize(), () -> U.freeMemory(ptr), null) + .share(); + cleaner.register(AixVaList.class, base::close); + VH_gp_offset.set(base, MAX_GP_OFFSET); + VH_fp_offset.set(base, MAX_FP_OFFSET); + VH_overflow_arg_area.set(base, MemoryAddress.NULL); + VH_reg_save_area.set(base, MemoryAddress.NULL); + return base.withAccessModes(0).address(); + } + + public static VaList empty() { + return EMPTY; + } + + private int currentGPOffset() { + return (int) VH_gp_offset.get(segment); + } + + private void currentGPOffset(int i) { + VH_gp_offset.set(segment, i); + } + + private int currentFPOffset() { + return (int) VH_fp_offset.get(segment); + } + + private void currentFPOffset(int i) { + VH_fp_offset.set(segment, i); + } + + private MemoryAddress stackPtr() { + return (MemoryAddress) VH_overflow_arg_area.get(segment); + } + + private void stackPtr(MemoryAddress ptr) { + VH_overflow_arg_area.set(segment, ptr); + } + + private MemorySegment regSaveArea() { + return getRegSaveArea(segment); + } + + private static MemorySegment getRegSaveArea(MemorySegment segment) { + return handoffIfNeeded(((MemoryAddress)VH_reg_save_area.get(segment)) + .asSegmentRestricted(LAYOUT_REG_SAVE_AREA.byteSize()), segment.ownerThread()); + } + + private void preAlignStack(MemoryLayout layout) { + if (layout.byteAlignment() > 8) { + stackPtr(Utils.alignUp(stackPtr(), 16)); + } + } + + private void postAlignStack(MemoryLayout layout) { + stackPtr(Utils.alignUp(stackPtr().addOffset(layout.byteSize()), 8)); + } + + @Override + public int vargAsInt(MemoryLayout layout) { + //return (int) read(int.class, layout); + throw new InternalError("vargAsInt is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public long vargAsLong(MemoryLayout layout) { + //return (long) read(long.class, layout); + throw new InternalError("vargAsLong is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public double vargAsDouble(MemoryLayout layout) { + //return (double) read(double.class, layout); + throw new InternalError("vargAsDouble is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public MemoryAddress vargAsAddress(MemoryLayout layout) { + //return (MemoryAddress) read(MemoryAddress.class, layout); + throw new InternalError("vargAsAddress is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public MemorySegment vargAsSegment(MemoryLayout layout) { + //return (MemorySegment) read(MemorySegment.class, layout); + throw new InternalError("vargAsSegment is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public MemorySegment vargAsSegment(MemoryLayout layout, NativeScope scope) { + //Objects.requireNonNull(scope); + //return (MemorySegment) read(MemorySegment.class, layout, SharedUtils.Allocator.ofScope(scope)); + throw new InternalError("vargAsSegment is not yet implemented"); //$NON-NLS-1$ + } + + private Object read(Class carrier, MemoryLayout layout) { + return read(carrier, layout, MemorySegment::allocateNative); + } + + private Object read(Class carrier, MemoryLayout layout, SharedUtils.Allocator allocator) { + Objects.requireNonNull(layout); + checkCompatibleType(carrier, layout, Aixppc64Linker.ADDRESS_SIZE); + TypeClass typeClass = TypeClass.classifyLayout(layout); + if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass) + || typeClass.inMemory()) { + preAlignStack(layout); + return switch (typeClass.kind()) { + case STRUCT -> { + try (MemorySegment slice = handoffIfNeeded(stackPtr() + .asSegmentRestricted(layout.byteSize()), segment.ownerThread())) { + MemorySegment seg = allocator.allocate(layout); + seg.copyFrom(slice); + postAlignStack(layout); + yield seg; + } + } + case POINTER, INTEGER, FLOAT -> { + VarHandle reader = vhPrimitiveOrAddress(carrier, layout); + try (MemorySegment slice = handoffIfNeeded(stackPtr() + .asSegmentRestricted(layout.byteSize()), segment.ownerThread())) { + Object res = reader.get(slice); + postAlignStack(layout); + yield res; + } + } + }; + } else { + return switch (typeClass.kind()) { + case STRUCT -> { + MemorySegment value = allocator.allocate(layout); + int classIdx = 0; + long offset = 0; + while (offset < layout.byteSize()) { + final long copy = Math.min(layout.byteSize() - offset, 8); + boolean isSSE = typeClass.classes.get(classIdx++) == ArgumentClassImpl.SSE; + MemorySegment slice = value.asSlice(offset, copy); + if (isSSE) { + slice.copyFrom(regSaveArea.asSlice(currentFPOffset(), copy)); + currentFPOffset(currentFPOffset() + FP_SLOT_SIZE); + } else { + slice.copyFrom(regSaveArea.asSlice(currentGPOffset(), copy)); + currentGPOffset(currentGPOffset() + GP_SLOT_SIZE); + } + offset += copy; + } + yield value; + } + case POINTER, INTEGER -> { + VarHandle reader = SharedUtils.vhPrimitiveOrAddress(carrier, layout); + Object res = reader.get(regSaveArea.asSlice(currentGPOffset())); + currentGPOffset(currentGPOffset() + GP_SLOT_SIZE); + yield res; + } + case FLOAT -> { + VarHandle reader = layout.varHandle(carrier); + Object res = reader.get(regSaveArea.asSlice(currentFPOffset())); + currentFPOffset(currentFPOffset() + FP_SLOT_SIZE); + yield res; + } + }; + } + } + + @Override + public void skip(MemoryLayout... layouts) { + /* + Objects.requireNonNull(layouts); + for (MemoryLayout layout : layouts) { + Objects.requireNonNull(layout); + TypeClass typeClass = TypeClass.classifyLayout(layout); + if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass)) { + preAlignStack(layout); + postAlignStack(layout); + } else { + currentGPOffset(currentGPOffset() + (((int) typeClass.nIntegerRegs()) * GP_SLOT_SIZE)); + currentFPOffset(currentFPOffset() + (((int) typeClass.nVectorRegs()) * FP_SLOT_SIZE)); + } + } + */ + throw new InternalError("skip is not yet implemented"); //$NON-NLS-1$ + } + + static AixVaList.Builder builder(SharedUtils.Allocator allocator) { + return new AixVaList.Builder(allocator); + } + + public static VaList ofAddress(MemoryAddress ma) { + //return readFromSegment(ma.asSegmentRestricted(LAYOUT.byteSize())); + throw new InternalError("ofAddress is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public boolean isAlive() { + return segment.isAlive(); + } + + @Override + public void close() { + segment.close(); + attachedSegments.forEach(MemorySegment::close); + } + + @Override + public VaList copy() { + return copy(MemorySegment::allocateNative); + } + + @Override + public VaList copy(NativeScope scope) { + Objects.requireNonNull(scope); + return copy(SharedUtils.Allocator.ofScope(scope)); + } + + private VaList copy(SharedUtils.Allocator allocator) { + MemorySegment copy = allocator.allocate(LAYOUT); + copy.copyFrom(segment); + return new AixVaList(copy, regSaveArea, List.of()); + } + + @Override + public MemoryAddress address() { + return segment.address(); + } + + private static boolean isRegOverflow(long currentGPOffset, long currentFPOffset, TypeClass typeClass) { + return currentGPOffset > MAX_GP_OFFSET - typeClass.nIntegerRegs() * GP_SLOT_SIZE + || currentFPOffset > MAX_FP_OFFSET - typeClass.nVectorRegs() * FP_SLOT_SIZE; + } + + @Override + public String toString() { + return "AixVaList{" + + "gp_offset=" + currentGPOffset() + + ", fp_offset=" + currentFPOffset() + + ", overflow_arg_area=" + stackPtr() + + ", reg_save_area=" + regSaveArea() + + '}'; + } + + static class Builder implements VaList.Builder { + private final SharedUtils.Allocator allocator; + private final MemorySegment reg_save_area; + private long currentGPOffset = 0; + private long currentFPOffset = FP_OFFSET; + private final List stackArgs = new ArrayList<>(); + + public Builder(SharedUtils.Allocator allocator) { + this.allocator = allocator; + this.reg_save_area = allocator.allocate(LAYOUT_REG_SAVE_AREA); + } + + @Override + public Builder vargFromInt(ValueLayout layout, int value) { + //return arg(int.class, layout, value); + throw new InternalError("vargFromInt is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromLong(ValueLayout layout, long value) { + //return arg(long.class, layout, value); + throw new InternalError("vargFromLong is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromDouble(ValueLayout layout, double value) { + //return arg(double.class, layout, value); + throw new InternalError("vargFromDouble is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromAddress(ValueLayout layout, Addressable value) { + //return arg(MemoryAddress.class, layout, value.address()); + throw new InternalError("vargFromAddress is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromSegment(GroupLayout layout, MemorySegment value) { + //return arg(MemorySegment.class, layout, value); + throw new InternalError("vargFromSegment is not yet implemented"); //$NON-NLS-1$ + } + + private Builder arg(Class carrier, MemoryLayout layout, Object value) { + Objects.requireNonNull(layout); + Objects.requireNonNull(value); + checkCompatibleType(carrier, layout, Aixppc64Linker.ADDRESS_SIZE); + TypeClass typeClass = TypeClass.classifyLayout(layout); + if (isRegOverflow(currentGPOffset, currentFPOffset, typeClass) + || typeClass.inMemory()) { + // stack it! + stackArgs.add(new SimpleVaArg(carrier, layout, value)); + } else { + switch (typeClass.kind()) { + case STRUCT -> { + MemorySegment valueSegment = (MemorySegment) value; + int classIdx = 0; + long offset = 0; + while (offset < layout.byteSize()) { + final long copy = Math.min(layout.byteSize() - offset, 8); + boolean isSSE = typeClass.classes.get(classIdx++) == ArgumentClassImpl.SSE; + MemorySegment slice = valueSegment.asSlice(offset, copy); + if (isSSE) { + reg_save_area.asSlice(currentFPOffset, copy).copyFrom(slice); + currentFPOffset += FP_SLOT_SIZE; + } else { + reg_save_area.asSlice(currentGPOffset, copy).copyFrom(slice); + currentGPOffset += GP_SLOT_SIZE; + } + offset += copy; + } + } + case POINTER, INTEGER -> { + VarHandle writer = SharedUtils.vhPrimitiveOrAddress(carrier, layout); + writer.set(reg_save_area.asSlice(currentGPOffset), value); + currentGPOffset += GP_SLOT_SIZE; + } + case FLOAT -> { + VarHandle writer = layout.varHandle(carrier); + writer.set(reg_save_area.asSlice(currentFPOffset), value); + currentFPOffset += FP_SLOT_SIZE; + } + } + } + return this; + } + + private boolean isEmpty() { + return currentGPOffset == 0 && currentFPOffset == FP_OFFSET && stackArgs.isEmpty(); + } + + public VaList build() { + if (isEmpty()) { + return EMPTY; + } + + MemorySegment vaListSegment = allocator.allocate(LAYOUT); + List attachedSegments = new ArrayList<>(); + MemoryAddress stackArgsPtr = MemoryAddress.NULL; + if (!stackArgs.isEmpty()) { + long stackArgsSize = stackArgs.stream().reduce(0L, (acc, e) -> acc + e.layout.byteSize(), Long::sum); + MemorySegment stackArgsSegment = allocator.allocate(stackArgsSize, 16); + MemorySegment maOverflowArgArea = stackArgsSegment; + for (SimpleVaArg arg : stackArgs) { + if (arg.layout.byteSize() > 8) { + maOverflowArgArea = Utils.alignUp(maOverflowArgArea, Math.min(16, arg.layout.byteSize())); + } + if (arg.value instanceof MemorySegment) { + maOverflowArgArea.copyFrom((MemorySegment) arg.value); + } else { + VarHandle writer = arg.varHandle(); + writer.set(maOverflowArgArea, arg.value); + } + maOverflowArgArea = maOverflowArgArea.asSlice(arg.layout.byteSize()); + } + stackArgsPtr = stackArgsSegment.address(); + attachedSegments.add(stackArgsSegment); + } + + VH_fp_offset.set(vaListSegment, (int) FP_OFFSET); + VH_overflow_arg_area.set(vaListSegment, stackArgsPtr); + VH_reg_save_area.set(vaListSegment, reg_save_area.address()); + attachedSegments.add(reg_save_area); + assert reg_save_area.ownerThread() == vaListSegment.ownerThread(); + return new AixVaList(vaListSegment, reg_save_area, attachedSegments); + } + } + + private static MemorySegment handoffIfNeeded(MemorySegment segment, Thread thread) { + return segment.ownerThread() == thread ? + segment : segment.handoff(thread); + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/Aixppc64Linker.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/Aixppc64Linker.java new file mode 100644 index 00000000000..c38271aa8aa --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/Aixppc64Linker.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.ppc64.aix; + +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.CLinker; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.UpcallStubs; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; + +import static jdk.internal.foreign.PlatformLayouts.*; + +/** + * ABI implementation based on 64-bit PowerPC ELF ABI + * + * Note: This file is copied from x86/sysv with modification to accommodate the specifics + * on AIX/ppc64le and might be updated accordingly in terms of VaList in the future. + */ +public class Aixppc64Linker implements CLinker { + private static Aixppc64Linker instance; + + static final long ADDRESS_SIZE = 64; // bits + + private static final MethodHandle MH_unboxVaList; + private static final MethodHandle MH_boxVaList; + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MH_unboxVaList = lookup.findVirtual(VaList.class, "address", + MethodType.methodType(MemoryAddress.class)); + MH_boxVaList = lookup.findStatic(Aixppc64Linker.class, "newVaListOfAddress", + MethodType.methodType(VaList.class, MemoryAddress.class)); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + + public static Aixppc64Linker getInstance() { + if (instance == null) { + instance = new Aixppc64Linker(); + } + return instance; + } + + public static VaList newVaList(Consumer actions, SharedUtils.Allocator allocator) { + AixVaList.Builder builder = AixVaList.builder(allocator); + actions.accept(builder); + return builder.build(); + } + + @Override + public MethodHandle downcallHandle(Addressable symbol, MethodType type, FunctionDescriptor function) { + Objects.requireNonNull(symbol); + Objects.requireNonNull(type); + Objects.requireNonNull(function); + MethodType llMt = SharedUtils.convertVaListCarriers(type, AixVaList.CARRIER); + MethodHandle handle = CallArranger.arrangeDowncall(symbol, llMt, function); + handle = SharedUtils.unboxVaLists(type, handle, MH_unboxVaList); + return handle; + } + + @Override + public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function) { + Objects.requireNonNull(target); + Objects.requireNonNull(function); + target = SharedUtils.boxVaLists(target, MH_boxVaList); + return UpcallStubs.upcallAddress(CallArranger.arrangeUpcall(target, target.type(), function)); + } + + public static VaList newVaListOfAddress(MemoryAddress ma) { + return AixVaList.ofAddress(ma); + } + + public static VaList emptyVaList() { + return AixVaList.empty(); + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/ArgumentClassImpl.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/ArgumentClassImpl.java new file mode 100644 index 00000000000..44cb6fd44de --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/ArgumentClassImpl.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.ppc64.aix; + +/** + * This file is copied from x86/sysv as a placeholder for compilation as VaList on Linux/ppc64le + * at Java level is not yet implemented for the moment and will be removed in the future + * if not required in Linux/ppc64le. + */ +public enum ArgumentClassImpl { + POINTER, INTEGER, SSE, SSEUP, X87, X87UP, COMPLEX_X87, NO_CLASS, MEMORY; + + public ArgumentClassImpl merge(ArgumentClassImpl other) { + if (this == other) { + return this; + } + + if (other == NO_CLASS) { + return this; + } + if (this == NO_CLASS) { + return other; + } + + if (this == MEMORY || other == MEMORY) { + return MEMORY; + } + + if (this == POINTER || other == POINTER) { + return POINTER; + } + + if (this == INTEGER || other == INTEGER) { + return INTEGER; + } + + if (this == X87 || this == X87UP || this == COMPLEX_X87) { + return MEMORY; + } + if (other == X87 || other == X87UP || other == COMPLEX_X87) { + return MEMORY; + } + + return SSE; + } + + public boolean isIntegral() { + return this == INTEGER || this == POINTER; + } + + public boolean isPointer() { + return this == POINTER; + } + + public boolean isIndirect() { + return this == MEMORY; + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/CallArranger.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/CallArranger.java new file mode 100644 index 00000000000..dc044f86052 --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/CallArranger.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.ppc64.aix; + +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.GroupLayout; +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemorySegment; +import jdk.internal.foreign.PlatformLayouts; +import jdk.internal.foreign.abi.UpcallHandler; +import jdk.internal.foreign.abi.ABIDescriptor; +import jdk.internal.foreign.abi.ProgrammableInvoker; +import jdk.internal.foreign.abi.ProgrammableUpcallHandler; +import jdk.internal.foreign.abi.SharedUtils; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.Optional; + +import static jdk.internal.foreign.PlatformLayouts.*; + +/** + * For the AIX PPC64 C ABI specifically, this class uses the ProgrammableInvoker API + * which is turned into a MethodHandle to invoke the native code. + */ +public class CallArranger { + + /* Replace ProgrammableInvoker in OpenJDK with the implementation of ProgrammableInvoker specific to OpenJ9 */ + public static MethodHandle arrangeDowncall(Addressable addr, MethodType mt, FunctionDescriptor cDesc) { + MethodHandle handle = ProgrammableInvoker.getBoundMethodHandle(addr, mt, cDesc); + return handle; + } + + /* Replace ProgrammableUpcallHandler in OpenJDK with the implementation of ProgrammableUpcallHandler specific to OpenJ9 */ + public static UpcallHandler arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc) { + throw new InternalError("arrangeUpcall is not yet implemented"); //$NON-NLS-1$ + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/TypeClass.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/TypeClass.java new file mode 100644 index 00000000000..6e89ed0ef0b --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/aix/TypeClass.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.ppc64.aix; + +import jdk.incubator.foreign.GroupLayout; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.SequenceLayout; +import jdk.incubator.foreign.ValueLayout; +import jdk.internal.foreign.PlatformLayouts; +import jdk.internal.foreign.Utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * This file is copied from x86/sysv as a placeholder for compilation as VaList on AIX/ppc64le + * at Java level is not yet implemented for the moment and might be updated or removed accordingly + * in the future. + */ +class TypeClass { + enum Kind { + STRUCT, + POINTER, + INTEGER, + FLOAT + } + + private final Kind kind; + final List classes; + + private TypeClass(Kind kind, List classes) { + this.kind = kind; + this.classes = classes; + } + + public static TypeClass ofValue(ValueLayout layout) { + final Kind kind; + ArgumentClassImpl argClass = argumentClassFor(layout); + kind = switch (argClass) { + case POINTER -> Kind.POINTER; + case INTEGER -> Kind.INTEGER; + case SSE -> Kind.FLOAT; + default -> throw new IllegalStateException("Unexpected argument class: " + argClass); + }; + return new TypeClass(kind, List.of(argClass)); + } + + public static TypeClass ofStruct(GroupLayout layout) { + return new TypeClass(Kind.STRUCT, classifyStructType(layout)); + } + + boolean inMemory() { + return classes.stream().anyMatch(c -> c == ArgumentClassImpl.MEMORY); + } + + private long numClasses(ArgumentClassImpl clazz) { + return classes.stream().filter(c -> c == clazz).count(); + } + + public long nIntegerRegs() { + return numClasses(ArgumentClassImpl.INTEGER) + numClasses(ArgumentClassImpl.POINTER); + } + + public long nVectorRegs() { + return numClasses(ArgumentClassImpl.SSE); + } + + public Kind kind() { + return kind; + } + + // layout classification + + private static final int MAX_AGGREGATE_REGS_SIZE = 8; + + private static List createMemoryClassArray(long size) { + return IntStream.range(0, (int)size) + .mapToObj(i -> ArgumentClassImpl.MEMORY) + .collect(Collectors.toCollection(ArrayList::new)); + } + + private static ArgumentClassImpl argumentClassFor(MemoryLayout layout) { + return switch (PlatformLayouts.getKind(layout)) { + case CHAR, SHORT, INT, LONG, LONG_LONG -> ArgumentClassImpl.INTEGER; + case FLOAT, DOUBLE -> ArgumentClassImpl.SSE; + case POINTER -> ArgumentClassImpl.POINTER; + }; + } + + // TODO: handle zero length arrays + private static List classifyStructType(GroupLayout type) { + List[] eightbytes = groupByEightBytes(type); + long nWords = eightbytes.length; + if (nWords > MAX_AGGREGATE_REGS_SIZE) { + return createMemoryClassArray(nWords); + } + + ArrayList classes = new ArrayList<>(); + + for (int idx = 0; idx < nWords; idx++) { + List subclasses = eightbytes[idx]; + ArgumentClassImpl result = subclasses.stream() + .reduce(ArgumentClassImpl.NO_CLASS, ArgumentClassImpl::merge); + classes.add(result); + } + + for (int i = 0; i < classes.size(); i++) { + ArgumentClassImpl c = classes.get(i); + + if (c == ArgumentClassImpl.MEMORY) { + // if any of the eightbytes was passed in memory, pass the whole thing in memory + return createMemoryClassArray(classes.size()); + } + + if (c == ArgumentClassImpl.X87UP) { + if (i == 0) { + throw new IllegalArgumentException("Unexpected leading X87UP class"); + } + + if (classes.get(i - 1) != ArgumentClassImpl.X87) { + return createMemoryClassArray(classes.size()); + } + } + } + + if (classes.size() > 2) { + if (classes.get(0) != ArgumentClassImpl.SSE) { + return createMemoryClassArray(classes.size()); + } + + for (int i = 1; i < classes.size(); i++) { + if (classes.get(i) != ArgumentClassImpl.SSEUP) { + return createMemoryClassArray(classes.size()); + } + } + } + + return classes; + } + + static TypeClass classifyLayout(MemoryLayout type) { + try { + if (type instanceof ValueLayout) { + return ofValue((ValueLayout)type); + } else if (type instanceof GroupLayout) { + return ofStruct((GroupLayout)type); + } else { + throw new IllegalArgumentException("Unhandled type " + type); + } + } catch (UnsupportedOperationException e) { + System.err.println("Failed to classify layout: " + type); + throw e; + } + } + + private static List[] groupByEightBytes(GroupLayout group) { + long offset = 0L; + int nEightbytes = (int) Utils.alignUp(group.byteSize(), 8) / 8; + @SuppressWarnings({"unchecked", "rawtypes"}) + List[] groups = new List[nEightbytes]; + for (MemoryLayout l : group.memberLayouts()) { + groupByEightBytes(l, offset, groups); + if (group.isStruct()) { + offset += l.byteSize(); + } + } + return groups; + } + + private static void groupByEightBytes(MemoryLayout l, long offset, List[] groups) { + if (l instanceof GroupLayout) { + GroupLayout group = (GroupLayout)l; + for (MemoryLayout m : group.memberLayouts()) { + groupByEightBytes(m, offset, groups); + if (group.isStruct()) { + offset += m.byteSize(); + } + } + } else if (l.isPadding()) { + return; + } else if (l instanceof SequenceLayout) { + SequenceLayout seq = (SequenceLayout)l; + MemoryLayout elem = seq.elementLayout(); + for (long i = 0 ; i < seq.elementCount().getAsLong() ; i++) { + groupByEightBytes(elem, offset, groups); + offset += elem.byteSize(); + } + } else if (l instanceof ValueLayout) { + List layouts = groups[(int)offset / 8]; + if (layouts == null) { + layouts = new ArrayList<>(); + groups[(int)offset / 8] = layouts; + } + // if the aggregate contains unaligned fields, it has class MEMORY + ArgumentClassImpl argumentClass = (offset % l.byteAlignment()) == 0 ? + argumentClassFor(l) : + ArgumentClassImpl.MEMORY; + layouts.add(argumentClass); + } else { + throw new IllegalStateException("Unexpected layout: " + l); + } + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/CallArranger.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/CallArranger.java new file mode 100644 index 00000000000..637096304bf --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/CallArranger.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.ppc64.sysv; + +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.GroupLayout; +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemorySegment; +import jdk.internal.foreign.PlatformLayouts; +import jdk.internal.foreign.abi.UpcallHandler; +import jdk.internal.foreign.abi.ABIDescriptor; +import jdk.internal.foreign.abi.ProgrammableInvoker; +import jdk.internal.foreign.abi.ProgrammableUpcallHandler; +import jdk.internal.foreign.abi.SharedUtils; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.Optional; + +import static jdk.internal.foreign.PlatformLayouts.*; + +/** + * For the SysV ppc64le C ABI specifically, this class uses the ProgrammableInvoker API + * which is turned into a MethodHandle to invoke the native code. + */ +public class CallArranger { + + /* Replace ProgrammableInvoker in OpenJDK with the implementation of ProgrammableInvoker specific to OpenJ9 */ + public static MethodHandle arrangeDowncall(Addressable addr, MethodType mt, FunctionDescriptor cDesc) { + MethodHandle handle = ProgrammableInvoker.getBoundMethodHandle(addr, mt, cDesc); + return handle; + } + + /* Replace ProgrammableUpcallHandler in OpenJDK with the implementation of ProgrammableUpcallHandler specific to OpenJ9 */ + public static UpcallHandler arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc) { + throw new InternalError("arrangeUpcall is not yet implemented"); //$NON-NLS-1$ + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/SysVVaList.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/SysVVaList.java new file mode 100644 index 00000000000..a0942428b25 --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/SysVVaList.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.ppc64.sysv; + +import jdk.incubator.foreign.*; +import jdk.incubator.foreign.CLinker.VaList; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.SharedUtils.SimpleVaArg; + +import java.lang.invoke.VarHandle; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +import static jdk.internal.foreign.PlatformLayouts.SysVppc64le.C_POINTER; + +/** + * This file is copied from x86/windows (Windows/x86_64) as a placeholder for compilation + * as VaList on Linux/ppc64le at Java level is not yet implemented for the moment. + * The defintion VaList must map to the underlying struct of va_list defined on Linux/ppc64le + * which might be similar to Windows/x86_64. Thus, futher analysis on the struct is required + * to understand how the struct is laid out in memory (e.g. the type & size of each field in + * va_list) and how the registers are allocated for va_list. + */ +public class SysVVaList implements VaList { + static final Class CARRIER = MemoryAddress.class; + private static final long VA_SLOT_SIZE_BYTES = 8; + private static final VarHandle VH_address = MemoryHandles.asAddressVarHandle(C_POINTER.varHandle(long.class)); + private static final VaList EMPTY = new SharedUtils.EmptyVaList(MemoryAddress.NULL); + + private MemorySegment segment; + private final List attachedSegments; + private final MemorySegment livenessCheck; + + private SysVVaList(MemorySegment segment, List attachedSegments, MemorySegment livenessCheck) { + this.segment = segment; + this.attachedSegments = attachedSegments; + this.livenessCheck = livenessCheck; + } + + public static final VaList empty() { + return EMPTY; + } + + @Override + public int vargAsInt(MemoryLayout layout) { + //return (int) read(int.class, layout); + throw new InternalError("vargAsInt is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public long vargAsLong(MemoryLayout layout) { + //return (long) read(long.class, layout); + throw new InternalError("vargAsLong is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public double vargAsDouble(MemoryLayout layout) { + //return (double) read(double.class, layout); + throw new InternalError("vargAsDouble is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public MemoryAddress vargAsAddress(MemoryLayout layout) { + //return (MemoryAddress) read(MemoryAddress.class, layout); + throw new InternalError("vargAsAddress is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public MemorySegment vargAsSegment(MemoryLayout layout) { + //return (MemorySegment) read(MemorySegment.class, layout); + throw new InternalError("vargAsSegment is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public MemorySegment vargAsSegment(MemoryLayout layout, NativeScope scope) { + //Objects.requireNonNull(scope); + //return (MemorySegment) read(MemorySegment.class, layout, SharedUtils.Allocator.ofScope(scope)); + throw new InternalError("vargAsSegment is not yet implemented"); //$NON-NLS-1$ + } + + private Object read(Class carrier, MemoryLayout layout) { + return read(carrier, layout, MemorySegment::allocateNative); + } + + private Object read(Class carrier, MemoryLayout layout, SharedUtils.Allocator allocator) { + Objects.requireNonNull(layout); + SharedUtils.checkCompatibleType(carrier, layout, SysVppc64leLinker.ADDRESS_SIZE); + Object res; + if (carrier == MemorySegment.class) { + TypeClass typeClass = TypeClass.typeClassFor(layout); + res = switch (typeClass) { + case STRUCT_REFERENCE -> { + MemoryAddress structAddr = (MemoryAddress) VH_address.get(segment); + try (MemorySegment struct = handoffIfNeeded(structAddr.asSegmentRestricted(layout.byteSize()), + segment.ownerThread())) { + MemorySegment seg = allocator.allocate(layout.byteSize()); + seg.copyFrom(struct); + yield seg; + } + } + case STRUCT_REGISTER -> { + MemorySegment struct = allocator.allocate(layout); + struct.copyFrom(segment.asSlice(0L, layout.byteSize())); + yield struct; + } + default -> throw new IllegalStateException("Unexpected TypeClass: " + typeClass); + }; + } else { + VarHandle reader = SharedUtils.vhPrimitiveOrAddress(carrier, layout); + res = reader.get(segment); + } + segment = segment.asSlice(VA_SLOT_SIZE_BYTES); + return res; + } + + @Override + public void skip(MemoryLayout... layouts) { + //Objects.requireNonNull(layouts); + //Stream.of(layouts).forEach(Objects::requireNonNull); + //segment = segment.asSlice(layouts.length * VA_SLOT_SIZE_BYTES); + throw new InternalError("skip is not yet implemented"); //$NON-NLS-1$ + } + + static SysVVaList ofAddress(MemoryAddress addr) { + //MemorySegment segment = addr.asSegmentRestricted(Long.MAX_VALUE); + //return new SysVVaList(segment, List.of(segment), null); + throw new InternalError("ofAddress is not yet implemented"); //$NON-NLS-1$ + } + + static Builder builder(SharedUtils.Allocator allocator) { + return new Builder(allocator); + } + + @Override + public void close() { + if (livenessCheck != null) + livenessCheck.close(); + attachedSegments.forEach(MemorySegment::close); + } + + @Override + public VaList copy() { + MemorySegment liveness = handoffIfNeeded(MemoryAddress.NULL.asSegmentRestricted(1), + segment.ownerThread()); + return new SysVVaList(segment, List.of(), liveness); + } + + @Override + public VaList copy(NativeScope scope) { + Objects.requireNonNull(scope); + MemorySegment liveness = handoffIfNeeded(MemoryAddress.NULL.asSegmentRestricted(1), + segment.ownerThread()); + liveness = liveness.handoff(scope); + return new SysVVaList(segment, List.of(), liveness); + } + + @Override + public MemoryAddress address() { + return segment.address(); + } + + @Override + public boolean isAlive() { + if (livenessCheck != null) + return livenessCheck.isAlive(); + return segment.isAlive(); + } + + static class Builder implements VaList.Builder { + + private final SharedUtils.Allocator allocator; + private final List args = new ArrayList<>(); + + public Builder(SharedUtils.Allocator allocator) { + this.allocator = allocator; + } + + private Builder arg(Class carrier, MemoryLayout layout, Object value) { + Objects.requireNonNull(layout); + Objects.requireNonNull(value); + SharedUtils.checkCompatibleType(carrier, layout, SysVppc64leLinker.ADDRESS_SIZE); + args.add(new SimpleVaArg(carrier, layout, value)); + return this; + } + + @Override + public Builder vargFromInt(ValueLayout layout, int value) { + //return arg(int.class, layout, value); + throw new InternalError("vargFromInt is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromLong(ValueLayout layout, long value) { + //return arg(long.class, layout, value); + throw new InternalError("vargFromLong is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromDouble(ValueLayout layout, double value) { + //return arg(double.class, layout, value); + throw new InternalError("vargFromDouble is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromAddress(ValueLayout layout, Addressable value) { + //return arg(MemoryAddress.class, layout, value.address()); + throw new InternalError("vargFromAddress is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromSegment(GroupLayout layout, MemorySegment value) { + //return arg(MemorySegment.class, layout, value); + throw new InternalError("vargFromSegment is not yet implemented"); //$NON-NLS-1$ + } + + public VaList build() { + if (args.isEmpty()) { + return EMPTY; + } + MemorySegment segment = allocator.allocate(VA_SLOT_SIZE_BYTES * args.size()); + List attachedSegments = new ArrayList<>(); + attachedSegments.add(segment); + MemorySegment cursor = segment; + + for (SimpleVaArg arg : args) { + if (arg.carrier == MemorySegment.class) { + MemorySegment msArg = ((MemorySegment) arg.value); + TypeClass typeClass = TypeClass.typeClassFor(arg.layout); + switch (typeClass) { + case STRUCT_REFERENCE -> { + MemorySegment copy = allocator.allocate(arg.layout); + copy.copyFrom(msArg); // by-value + attachedSegments.add(copy); + VH_address.set(cursor, copy.address()); + } + case STRUCT_REGISTER -> { + MemorySegment slice = cursor.asSlice(0, VA_SLOT_SIZE_BYTES); + slice.copyFrom(msArg); + } + default -> throw new IllegalStateException("Unexpected TypeClass: " + typeClass); + } + } else { + VarHandle writer = arg.varHandle(); + writer.set(cursor, arg.value); + } + cursor = cursor.asSlice(VA_SLOT_SIZE_BYTES); + } + + return new SysVVaList(segment, attachedSegments, null); + } + } + + private static MemorySegment handoffIfNeeded(MemorySegment segment, Thread thread) { + return segment.ownerThread() == thread ? + segment : segment.handoff(thread); + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/SysVppc64leLinker.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/SysVppc64leLinker.java new file mode 100644 index 00000000000..f451e689536 --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/SysVppc64leLinker.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.ppc64.sysv; + +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.CLinker; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.UpcallStubs; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; + +import static jdk.internal.foreign.PlatformLayouts.*; + +/** + * ABI implementation based on System V ABI PPC64LE + * + * Note: This file is copied from x86/windows with modification to accommodate the specifics + * on Linux/ppc64le and might be updated accordingly in terms of VaList in the future. + */ +public class SysVppc64leLinker implements CLinker { + private static SysVppc64leLinker instance; + + static final long ADDRESS_SIZE = 64; // bits + + private static final MethodHandle MH_unboxVaList; + private static final MethodHandle MH_boxVaList; + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MH_unboxVaList = lookup.findVirtual(VaList.class, "address", + MethodType.methodType(MemoryAddress.class)); + MH_boxVaList = lookup.findStatic(SysVppc64leLinker.class, "newVaListOfAddress", + MethodType.methodType(VaList.class, MemoryAddress.class)); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + + public static SysVppc64leLinker getInstance() { + if (instance == null) { + instance = new SysVppc64leLinker(); + } + return instance; + } + + public static VaList newVaList(Consumer actions, SharedUtils.Allocator allocator) { + SysVVaList.Builder builder = SysVVaList.builder(allocator); + actions.accept(builder); + return builder.build(); + } + + @Override + public MethodHandle downcallHandle(Addressable symbol, MethodType type, FunctionDescriptor function) { + Objects.requireNonNull(symbol); + Objects.requireNonNull(type); + Objects.requireNonNull(function); + MethodType llMt = SharedUtils.convertVaListCarriers(type, SysVVaList.CARRIER); + MethodHandle handle = CallArranger.arrangeDowncall(symbol, llMt, function); + handle = SharedUtils.unboxVaLists(type, handle, MH_unboxVaList); + return handle; + } + + @Override + public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function) { + Objects.requireNonNull(target); + Objects.requireNonNull(function); + target = SharedUtils.boxVaLists(target, MH_boxVaList); + return UpcallStubs.upcallAddress(CallArranger.arrangeUpcall(target, target.type(), function)); + } + + public static VaList newVaListOfAddress(MemoryAddress ma) { + return SysVVaList.ofAddress(ma); + } + + public static VaList emptyVaList() { + return SysVVaList.empty(); + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/TypeClass.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/TypeClass.java new file mode 100644 index 00000000000..d0ccf44a59e --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ppc64/sysv/TypeClass.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.ppc64.sysv; + +import jdk.incubator.foreign.GroupLayout; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.ValueLayout; +import jdk.internal.foreign.PlatformLayouts; + +import static jdk.internal.foreign.PlatformLayouts.SysVppc64le.VARARGS_ATTRIBUTE_NAME; + +/** + * This file is copied from x86/windows as a placeholder for compilation as VaList on Linux/ppc64le + * at Java level is not yet implemented for the moment and might be updated or removed accordingly + * in the future. + */ +enum TypeClass { + STRUCT_REGISTER, + STRUCT_REFERENCE, + POINTER, + INTEGER, + FLOAT, + VARARG_FLOAT; + + private static TypeClass classifyValueType(ValueLayout type) { + return switch (PlatformLayouts.getKind(type)) { + case CHAR, SHORT, INT, LONG, LONG_LONG -> INTEGER; + case POINTER -> POINTER; + case FLOAT, DOUBLE -> { + if (type.attribute(VARARGS_ATTRIBUTE_NAME) + .map(Boolean.class::cast).orElse(false)) { + yield VARARG_FLOAT; + } + yield FLOAT; + } + }; + } + + static boolean isRegisterAggregate(MemoryLayout type) { + long size = type.byteSize(); + return size == 1 + || size == 2 + || size == 4 + || size == 8; + } + + private static TypeClass classifyStructType(MemoryLayout layout) { + if (isRegisterAggregate(layout)) { + return STRUCT_REGISTER; + } + return STRUCT_REFERENCE; + } + + static TypeClass typeClassFor(MemoryLayout type) { + if (type instanceof ValueLayout) { + return classifyValueType((ValueLayout) type); + } else if (type instanceof GroupLayout) { + return classifyStructType(type); + } else { + throw new IllegalArgumentException("Unhandled type " + type); + } + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/ArgumentClassImpl.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/ArgumentClassImpl.java new file mode 100644 index 00000000000..ed0a587702f --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/ArgumentClassImpl.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.s390x.sysv; + +/** + * This file is copied from x86/sysv as a placeholder for compilation as VaList on Linux/s390x + * at Java level is not yet implemented for the moment and will be removed in the future + * if not required in Linux/s390x. + */ +public enum ArgumentClassImpl { + POINTER, INTEGER, SSE, SSEUP, X87, X87UP, COMPLEX_X87, NO_CLASS, MEMORY; + + public ArgumentClassImpl merge(ArgumentClassImpl other) { + if (this == other) { + return this; + } + + if (other == NO_CLASS) { + return this; + } + if (this == NO_CLASS) { + return other; + } + + if (this == MEMORY || other == MEMORY) { + return MEMORY; + } + + if (this == POINTER || other == POINTER) { + return POINTER; + } + + if (this == INTEGER || other == INTEGER) { + return INTEGER; + } + + if (this == X87 || this == X87UP || this == COMPLEX_X87) { + return MEMORY; + } + if (other == X87 || other == X87UP || other == COMPLEX_X87) { + return MEMORY; + } + + return SSE; + } + + public boolean isIntegral() { + return this == INTEGER || this == POINTER; + } + + public boolean isPointer() { + return this == POINTER; + } + + public boolean isIndirect() { + return this == MEMORY; + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/CallArranger.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/CallArranger.java new file mode 100644 index 00000000000..4a2612c6a62 --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/CallArranger.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.s390x.sysv; + +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.GroupLayout; +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemorySegment; +import jdk.internal.foreign.PlatformLayouts; +import jdk.internal.foreign.abi.UpcallHandler; +import jdk.internal.foreign.abi.ABIDescriptor; +import jdk.internal.foreign.abi.ProgrammableInvoker; +import jdk.internal.foreign.abi.ProgrammableUpcallHandler; +import jdk.internal.foreign.abi.SharedUtils; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.Optional; + +import static jdk.internal.foreign.PlatformLayouts.*; + +/** + * For the SysV s390 C ABI specifically, this class uses the ProgrammableInvoker API + * which is turned into a MethodHandle to invoke the native code. + */ +public class CallArranger { + /* Replace ProgrammableInvoker in OpenJDK with the implementation of ProgrammableInvoker specific to OpenJ9 */ + public static MethodHandle arrangeDowncall(Addressable addr, MethodType mt, FunctionDescriptor cDesc) { + MethodHandle handle = ProgrammableInvoker.getBoundMethodHandle(addr, mt, cDesc); + return handle; + } + + /* Replace ProgrammableUpcallHandler in OpenJDK with the implementation of ProgrammableUpcallHandler specific to OpenJ9 */ + public static UpcallHandler arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc) { + throw new InternalError("arrangeUpcall is not yet implemented"); //$NON-NLS-1$ + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/SysVVaList.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/SysVVaList.java new file mode 100644 index 00000000000..4ca8a476235 --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/SysVVaList.java @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.s390x.sysv; + +import jdk.incubator.foreign.*; +import jdk.internal.foreign.NativeMemorySegmentImpl; +import jdk.internal.foreign.Utils; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.misc.Unsafe; + +import java.lang.invoke.VarHandle; +import java.lang.ref.Cleaner; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static jdk.internal.foreign.PlatformLayouts.SysVs390x; +import static jdk.incubator.foreign.CLinker.VaList; +import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement; +import static jdk.internal.foreign.abi.SharedUtils.SimpleVaArg; +import static jdk.internal.foreign.abi.SharedUtils.checkCompatibleType; +import static jdk.internal.foreign.abi.SharedUtils.vhPrimitiveOrAddress; + +/** + * This file is copied from x86/sysv (Linux/x86_64) as a placeholder for compilation + * as VaList on Linux/s390x at Java level is not yet implemented for the moment. + * The defintion VaList must map to the underlying struct of va_list defined on + * Linux/s390x which might be similar to Linux/x86_64. Thus, futher analysis on + * the struct is required to understand how the struct is laid out in memory (e.g. + * the type & size of each field in va_list) and how the registers are allocated + * for va_list according to the description in the publisized ABI document + * at https://refspecs.linuxfoundation.org/ELF/zSeries/lzsabi0_zSeries.pdf. + */ +public class SysVVaList implements VaList { + private static final Unsafe U = Unsafe.getUnsafe(); + + static final Class CARRIER = MemoryAddress.class; + +// struct typedef __va_list_tag __va_list_tag { +// unsigned int gp_offset; /* 0 4 */ +// unsigned int fp_offset; /* 4 4 */ +// void * overflow_arg_area; /* 8 8 */ +// void * reg_save_area; /* 16 8 */ +// +// /* size: 24, cachelines: 1, members: 4 */ +// /* last cacheline: 24 bytes */ +// }; + static final GroupLayout LAYOUT = MemoryLayout.ofStruct( + SysVs390x.C_INT.withName("gp_offset"), + SysVs390x.C_INT.withName("fp_offset"), + SysVs390x.C_POINTER.withName("overflow_arg_area"), + SysVs390x.C_POINTER.withName("reg_save_area") + ).withName("__va_list_tag"); + + private static final MemoryLayout GP_REG = MemoryLayout.ofValueBits(64, ByteOrder.nativeOrder()); + private static final MemoryLayout FP_REG = MemoryLayout.ofValueBits(128, ByteOrder.nativeOrder()); + + private static final GroupLayout LAYOUT_REG_SAVE_AREA = MemoryLayout.ofStruct( + GP_REG.withName("%rdi"), + GP_REG.withName("%rsi"), + GP_REG.withName("%rdx"), + GP_REG.withName("%rcx"), + GP_REG.withName("%r8"), + GP_REG.withName("%r9"), + FP_REG.withName("%xmm0"), + FP_REG.withName("%xmm1"), + FP_REG.withName("%xmm2"), + FP_REG.withName("%xmm3"), + FP_REG.withName("%xmm4"), + FP_REG.withName("%xmm5"), + FP_REG.withName("%xmm6"), + FP_REG.withName("%xmm7") + ); + + private static final long FP_OFFSET = LAYOUT_REG_SAVE_AREA.byteOffset(groupElement("%xmm0")); + + private static final int GP_SLOT_SIZE = (int) GP_REG.byteSize(); + private static final int FP_SLOT_SIZE = (int) FP_REG.byteSize(); + + private static final int MAX_GP_OFFSET = (int) FP_OFFSET; // 6 regs used + private static final int MAX_FP_OFFSET = (int) LAYOUT_REG_SAVE_AREA.byteSize(); // 8 16 byte regs + + private static final VarHandle VH_fp_offset = LAYOUT.varHandle(int.class, groupElement("fp_offset")); + private static final VarHandle VH_gp_offset = LAYOUT.varHandle(int.class, groupElement("gp_offset")); + private static final VarHandle VH_overflow_arg_area + = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("overflow_arg_area"))); + private static final VarHandle VH_reg_save_area + = MemoryHandles.asAddressVarHandle(LAYOUT.varHandle(long.class, groupElement("reg_save_area"))); + + private static final Cleaner cleaner = Cleaner.create(); + private static final VaList EMPTY = new SharedUtils.EmptyVaList(emptyListAddress()); + + private final MemorySegment segment; + private final MemorySegment regSaveArea; + private final List attachedSegments; + + private SysVVaList(MemorySegment segment, MemorySegment regSaveArea, List attachedSegments) { + this.segment = segment; + this.regSaveArea = regSaveArea; + this.attachedSegments = attachedSegments; + } + + private static SysVVaList readFromSegment(MemorySegment segment) { + MemorySegment regSaveArea = getRegSaveArea(segment); + return new SysVVaList(segment, regSaveArea, List.of(regSaveArea)); + } + + private static MemoryAddress emptyListAddress() { + long ptr = U.allocateMemory(LAYOUT.byteSize()); + MemorySegment base = MemoryAddress.ofLong(ptr) + .asSegmentRestricted(LAYOUT.byteSize(), () -> U.freeMemory(ptr), null) + .share(); + cleaner.register(SysVVaList.class, base::close); + VH_gp_offset.set(base, MAX_GP_OFFSET); + VH_fp_offset.set(base, MAX_FP_OFFSET); + VH_overflow_arg_area.set(base, MemoryAddress.NULL); + VH_reg_save_area.set(base, MemoryAddress.NULL); + return base.withAccessModes(0).address(); + } + + public static VaList empty() { + return EMPTY; + } + + private int currentGPOffset() { + return (int) VH_gp_offset.get(segment); + } + + private void currentGPOffset(int i) { + VH_gp_offset.set(segment, i); + } + + private int currentFPOffset() { + return (int) VH_fp_offset.get(segment); + } + + private void currentFPOffset(int i) { + VH_fp_offset.set(segment, i); + } + + private MemoryAddress stackPtr() { + return (MemoryAddress) VH_overflow_arg_area.get(segment); + } + + private void stackPtr(MemoryAddress ptr) { + VH_overflow_arg_area.set(segment, ptr); + } + + private MemorySegment regSaveArea() { + return getRegSaveArea(segment); + } + + private static MemorySegment getRegSaveArea(MemorySegment segment) { + return handoffIfNeeded(((MemoryAddress)VH_reg_save_area.get(segment)) + .asSegmentRestricted(LAYOUT_REG_SAVE_AREA.byteSize()), segment.ownerThread()); + } + + private void preAlignStack(MemoryLayout layout) { + if (layout.byteAlignment() > 8) { + stackPtr(Utils.alignUp(stackPtr(), 16)); + } + } + + private void postAlignStack(MemoryLayout layout) { + stackPtr(Utils.alignUp(stackPtr().addOffset(layout.byteSize()), 8)); + } + + @Override + public int vargAsInt(MemoryLayout layout) { + //return (int) read(int.class, layout); + throw new InternalError("vargAsInt is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public long vargAsLong(MemoryLayout layout) { + //return (long) read(long.class, layout); + throw new InternalError("vargAsLong is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public double vargAsDouble(MemoryLayout layout) { + //return (double) read(double.class, layout); + throw new InternalError("vargAsDouble is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public MemoryAddress vargAsAddress(MemoryLayout layout) { + //return (MemoryAddress) read(MemoryAddress.class, layout); + throw new InternalError("vargAsAddress is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public MemorySegment vargAsSegment(MemoryLayout layout) { + //return (MemorySegment) read(MemorySegment.class, layout); + throw new InternalError("vargAsSegment is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public MemorySegment vargAsSegment(MemoryLayout layout, NativeScope scope) { + //Objects.requireNonNull(scope); + //return (MemorySegment) read(MemorySegment.class, layout, SharedUtils.Allocator.ofScope(scope)); + throw new InternalError("vargAsSegment is not yet implemented"); //$NON-NLS-1$ + } + + private Object read(Class carrier, MemoryLayout layout) { + return read(carrier, layout, MemorySegment::allocateNative); + } + + private Object read(Class carrier, MemoryLayout layout, SharedUtils.Allocator allocator) { + Objects.requireNonNull(layout); + checkCompatibleType(carrier, layout, SysVs390xLinker.ADDRESS_SIZE); + TypeClass typeClass = TypeClass.classifyLayout(layout); + if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass) + || typeClass.inMemory()) { + preAlignStack(layout); + return switch (typeClass.kind()) { + case STRUCT -> { + try (MemorySegment slice = handoffIfNeeded(stackPtr() + .asSegmentRestricted(layout.byteSize()), segment.ownerThread())) { + MemorySegment seg = allocator.allocate(layout); + seg.copyFrom(slice); + postAlignStack(layout); + yield seg; + } + } + case POINTER, INTEGER, FLOAT -> { + VarHandle reader = vhPrimitiveOrAddress(carrier, layout); + try (MemorySegment slice = handoffIfNeeded(stackPtr() + .asSegmentRestricted(layout.byteSize()), segment.ownerThread())) { + Object res = reader.get(slice); + postAlignStack(layout); + yield res; + } + } + }; + } else { + return switch (typeClass.kind()) { + case STRUCT -> { + MemorySegment value = allocator.allocate(layout); + int classIdx = 0; + long offset = 0; + while (offset < layout.byteSize()) { + final long copy = Math.min(layout.byteSize() - offset, 8); + boolean isSSE = typeClass.classes.get(classIdx++) == ArgumentClassImpl.SSE; + MemorySegment slice = value.asSlice(offset, copy); + if (isSSE) { + slice.copyFrom(regSaveArea.asSlice(currentFPOffset(), copy)); + currentFPOffset(currentFPOffset() + FP_SLOT_SIZE); + } else { + slice.copyFrom(regSaveArea.asSlice(currentGPOffset(), copy)); + currentGPOffset(currentGPOffset() + GP_SLOT_SIZE); + } + offset += copy; + } + yield value; + } + case POINTER, INTEGER -> { + VarHandle reader = SharedUtils.vhPrimitiveOrAddress(carrier, layout); + Object res = reader.get(regSaveArea.asSlice(currentGPOffset())); + currentGPOffset(currentGPOffset() + GP_SLOT_SIZE); + yield res; + } + case FLOAT -> { + VarHandle reader = layout.varHandle(carrier); + Object res = reader.get(regSaveArea.asSlice(currentFPOffset())); + currentFPOffset(currentFPOffset() + FP_SLOT_SIZE); + yield res; + } + }; + } + } + + @Override + public void skip(MemoryLayout... layouts) { + /* + Objects.requireNonNull(layouts); + for (MemoryLayout layout : layouts) { + Objects.requireNonNull(layout); + TypeClass typeClass = TypeClass.classifyLayout(layout); + if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass)) { + preAlignStack(layout); + postAlignStack(layout); + } else { + currentGPOffset(currentGPOffset() + (((int) typeClass.nIntegerRegs()) * GP_SLOT_SIZE)); + currentFPOffset(currentFPOffset() + (((int) typeClass.nVectorRegs()) * FP_SLOT_SIZE)); + } + } + */ + throw new InternalError("skip is not yet implemented"); //$NON-NLS-1$ + } + + static SysVVaList.Builder builder(SharedUtils.Allocator allocator) { + return new SysVVaList.Builder(allocator); + } + + public static VaList ofAddress(MemoryAddress ma) { + //return readFromSegment(ma.asSegmentRestricted(LAYOUT.byteSize())); + throw new InternalError("ofAddress is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public boolean isAlive() { + return segment.isAlive(); + } + + @Override + public void close() { + segment.close(); + attachedSegments.forEach(MemorySegment::close); + } + + @Override + public VaList copy() { + return copy(MemorySegment::allocateNative); + } + + @Override + public VaList copy(NativeScope scope) { + Objects.requireNonNull(scope); + return copy(SharedUtils.Allocator.ofScope(scope)); + } + + private VaList copy(SharedUtils.Allocator allocator) { + MemorySegment copy = allocator.allocate(LAYOUT); + copy.copyFrom(segment); + return new SysVVaList(copy, regSaveArea, List.of()); + } + + @Override + public MemoryAddress address() { + return segment.address(); + } + + private static boolean isRegOverflow(long currentGPOffset, long currentFPOffset, TypeClass typeClass) { + return currentGPOffset > MAX_GP_OFFSET - typeClass.nIntegerRegs() * GP_SLOT_SIZE + || currentFPOffset > MAX_FP_OFFSET - typeClass.nVectorRegs() * FP_SLOT_SIZE; + } + + @Override + public String toString() { + return "SysVVaList{" + + "gp_offset=" + currentGPOffset() + + ", fp_offset=" + currentFPOffset() + + ", overflow_arg_area=" + stackPtr() + + ", reg_save_area=" + regSaveArea() + + '}'; + } + + static class Builder implements VaList.Builder { + private final SharedUtils.Allocator allocator; + private final MemorySegment reg_save_area; + private long currentGPOffset = 0; + private long currentFPOffset = FP_OFFSET; + private final List stackArgs = new ArrayList<>(); + + public Builder(SharedUtils.Allocator allocator) { + this.allocator = allocator; + this.reg_save_area = allocator.allocate(LAYOUT_REG_SAVE_AREA); + } + + @Override + public Builder vargFromInt(ValueLayout layout, int value) { + //return arg(int.class, layout, value); + throw new InternalError("vargFromInt is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromLong(ValueLayout layout, long value) { + //return arg(long.class, layout, value); + throw new InternalError("vargFromLong is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromDouble(ValueLayout layout, double value) { + //return arg(double.class, layout, value); + throw new InternalError("vargFromDouble is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromAddress(ValueLayout layout, Addressable value) { + //return arg(MemoryAddress.class, layout, value.address()); + throw new InternalError("vargFromAddress is not yet implemented"); //$NON-NLS-1$ + } + + @Override + public Builder vargFromSegment(GroupLayout layout, MemorySegment value) { + //return arg(MemorySegment.class, layout, value); + throw new InternalError("vargFromSegment is not yet implemented"); //$NON-NLS-1$ + } + + private Builder arg(Class carrier, MemoryLayout layout, Object value) { + Objects.requireNonNull(layout); + Objects.requireNonNull(value); + checkCompatibleType(carrier, layout, SysVs390xLinker.ADDRESS_SIZE); + TypeClass typeClass = TypeClass.classifyLayout(layout); + if (isRegOverflow(currentGPOffset, currentFPOffset, typeClass) + || typeClass.inMemory()) { + // stack it! + stackArgs.add(new SimpleVaArg(carrier, layout, value)); + } else { + switch (typeClass.kind()) { + case STRUCT -> { + MemorySegment valueSegment = (MemorySegment) value; + int classIdx = 0; + long offset = 0; + while (offset < layout.byteSize()) { + final long copy = Math.min(layout.byteSize() - offset, 8); + boolean isSSE = typeClass.classes.get(classIdx++) == ArgumentClassImpl.SSE; + MemorySegment slice = valueSegment.asSlice(offset, copy); + if (isSSE) { + reg_save_area.asSlice(currentFPOffset, copy).copyFrom(slice); + currentFPOffset += FP_SLOT_SIZE; + } else { + reg_save_area.asSlice(currentGPOffset, copy).copyFrom(slice); + currentGPOffset += GP_SLOT_SIZE; + } + offset += copy; + } + } + case POINTER, INTEGER -> { + VarHandle writer = SharedUtils.vhPrimitiveOrAddress(carrier, layout); + writer.set(reg_save_area.asSlice(currentGPOffset), value); + currentGPOffset += GP_SLOT_SIZE; + } + case FLOAT -> { + VarHandle writer = layout.varHandle(carrier); + writer.set(reg_save_area.asSlice(currentFPOffset), value); + currentFPOffset += FP_SLOT_SIZE; + } + } + } + return this; + } + + private boolean isEmpty() { + return currentGPOffset == 0 && currentFPOffset == FP_OFFSET && stackArgs.isEmpty(); + } + + public VaList build() { + if (isEmpty()) { + return EMPTY; + } + + MemorySegment vaListSegment = allocator.allocate(LAYOUT); + List attachedSegments = new ArrayList<>(); + MemoryAddress stackArgsPtr = MemoryAddress.NULL; + if (!stackArgs.isEmpty()) { + long stackArgsSize = stackArgs.stream().reduce(0L, (acc, e) -> acc + e.layout.byteSize(), Long::sum); + MemorySegment stackArgsSegment = allocator.allocate(stackArgsSize, 16); + MemorySegment maOverflowArgArea = stackArgsSegment; + for (SimpleVaArg arg : stackArgs) { + if (arg.layout.byteSize() > 8) { + maOverflowArgArea = Utils.alignUp(maOverflowArgArea, Math.min(16, arg.layout.byteSize())); + } + if (arg.value instanceof MemorySegment) { + maOverflowArgArea.copyFrom((MemorySegment) arg.value); + } else { + VarHandle writer = arg.varHandle(); + writer.set(maOverflowArgArea, arg.value); + } + maOverflowArgArea = maOverflowArgArea.asSlice(arg.layout.byteSize()); + } + stackArgsPtr = stackArgsSegment.address(); + attachedSegments.add(stackArgsSegment); + } + + VH_fp_offset.set(vaListSegment, (int) FP_OFFSET); + VH_overflow_arg_area.set(vaListSegment, stackArgsPtr); + VH_reg_save_area.set(vaListSegment, reg_save_area.address()); + attachedSegments.add(reg_save_area); + assert reg_save_area.ownerThread() == vaListSegment.ownerThread(); + return new SysVVaList(vaListSegment, reg_save_area, attachedSegments); + } + } + + private static MemorySegment handoffIfNeeded(MemorySegment segment, Thread thread) { + return segment.ownerThread() == thread ? + segment : segment.handoff(thread); + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/SysVs390xLinker.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/SysVs390xLinker.java new file mode 100644 index 00000000000..09ed3da5865 --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/SysVs390xLinker.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.s390x.sysv; + +import jdk.incubator.foreign.Addressable; +import jdk.incubator.foreign.FunctionDescriptor; +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.CLinker; +import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.foreign.abi.UpcallStubs; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; + +import static jdk.internal.foreign.PlatformLayouts.*; + +/** + * ABI implementation based on System V ABI s390x + * + * Note: This file is copied from x86/sysv with modification to accommodate the specifics + * on Linux/s390x and might be updated accordingly in terms of VaList in the future. + */ +public class SysVs390xLinker implements CLinker { + private static SysVs390xLinker instance; + + static final long ADDRESS_SIZE = 64; // bits + + private static final MethodHandle MH_unboxVaList; + private static final MethodHandle MH_boxVaList; + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MH_unboxVaList = lookup.findVirtual(VaList.class, "address", + MethodType.methodType(MemoryAddress.class)); + MH_boxVaList = lookup.findStatic(SysVs390xLinker.class, "newVaListOfAddress", + MethodType.methodType(VaList.class, MemoryAddress.class)); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + + public static SysVs390xLinker getInstance() { + if (instance == null) { + instance = new SysVs390xLinker(); + } + return instance; + } + + public static VaList newVaList(Consumer actions, SharedUtils.Allocator allocator) { + SysVVaList.Builder builder = SysVVaList.builder(allocator); + actions.accept(builder); + return builder.build(); + } + + @Override + public MethodHandle downcallHandle(Addressable symbol, MethodType type, FunctionDescriptor function) { + Objects.requireNonNull(symbol); + Objects.requireNonNull(type); + Objects.requireNonNull(function); + MethodType llMt = SharedUtils.convertVaListCarriers(type, SysVVaList.CARRIER); + MethodHandle handle = CallArranger.arrangeDowncall(symbol, llMt, function); + handle = SharedUtils.unboxVaLists(type, handle, MH_unboxVaList); + return handle; + } + + @Override + public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function) { + Objects.requireNonNull(target); + Objects.requireNonNull(function); + target = SharedUtils.boxVaLists(target, MH_boxVaList); + return UpcallStubs.upcallAddress(CallArranger.arrangeUpcall(target, target.type(), function)); + } + + public static VaList newVaListOfAddress(MemoryAddress ma) { + return SysVVaList.ofAddress(ma); + } + + public static VaList emptyVaList() { + return SysVVaList.empty(); + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/TypeClass.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/TypeClass.java new file mode 100644 index 00000000000..b40421b545e --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/s390x/sysv/TypeClass.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2020, 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. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + +package jdk.internal.foreign.abi.s390x.sysv; + +import jdk.incubator.foreign.GroupLayout; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.SequenceLayout; +import jdk.incubator.foreign.ValueLayout; +import jdk.internal.foreign.PlatformLayouts; +import jdk.internal.foreign.Utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * This file is copied from x86/sysv as a placeholder for compilation as VaList on Linux/s390x + * at Java level is not yet implemented for the moment and might be updated or removed accordingly + * in the future. + */ +class TypeClass { + enum Kind { + STRUCT, + POINTER, + INTEGER, + FLOAT + } + + private final Kind kind; + final List classes; + + private TypeClass(Kind kind, List classes) { + this.kind = kind; + this.classes = classes; + } + + public static TypeClass ofValue(ValueLayout layout) { + final Kind kind; + ArgumentClassImpl argClass = argumentClassFor(layout); + kind = switch (argClass) { + case POINTER -> Kind.POINTER; + case INTEGER -> Kind.INTEGER; + case SSE -> Kind.FLOAT; + default -> throw new IllegalStateException("Unexpected argument class: " + argClass); + }; + return new TypeClass(kind, List.of(argClass)); + } + + public static TypeClass ofStruct(GroupLayout layout) { + return new TypeClass(Kind.STRUCT, classifyStructType(layout)); + } + + boolean inMemory() { + return classes.stream().anyMatch(c -> c == ArgumentClassImpl.MEMORY); + } + + private long numClasses(ArgumentClassImpl clazz) { + return classes.stream().filter(c -> c == clazz).count(); + } + + public long nIntegerRegs() { + return numClasses(ArgumentClassImpl.INTEGER) + numClasses(ArgumentClassImpl.POINTER); + } + + public long nVectorRegs() { + return numClasses(ArgumentClassImpl.SSE); + } + + public Kind kind() { + return kind; + } + + // layout classification + + private static final int MAX_AGGREGATE_REGS_SIZE = 8; + + private static List createMemoryClassArray(long size) { + return IntStream.range(0, (int)size) + .mapToObj(i -> ArgumentClassImpl.MEMORY) + .collect(Collectors.toCollection(ArrayList::new)); + } + + private static ArgumentClassImpl argumentClassFor(MemoryLayout layout) { + return switch (PlatformLayouts.getKind(layout)) { + case CHAR, SHORT, INT, LONG, LONG_LONG -> ArgumentClassImpl.INTEGER; + case FLOAT, DOUBLE -> ArgumentClassImpl.SSE; + case POINTER -> ArgumentClassImpl.POINTER; + }; + } + + // TODO: handle zero length arrays + private static List classifyStructType(GroupLayout type) { + List[] eightbytes = groupByEightBytes(type); + long nWords = eightbytes.length; + if (nWords > MAX_AGGREGATE_REGS_SIZE) { + return createMemoryClassArray(nWords); + } + + ArrayList classes = new ArrayList<>(); + + for (int idx = 0; idx < nWords; idx++) { + List subclasses = eightbytes[idx]; + ArgumentClassImpl result = subclasses.stream() + .reduce(ArgumentClassImpl.NO_CLASS, ArgumentClassImpl::merge); + classes.add(result); + } + + for (int i = 0; i < classes.size(); i++) { + ArgumentClassImpl c = classes.get(i); + + if (c == ArgumentClassImpl.MEMORY) { + // if any of the eightbytes was passed in memory, pass the whole thing in memory + return createMemoryClassArray(classes.size()); + } + + if (c == ArgumentClassImpl.X87UP) { + if (i == 0) { + throw new IllegalArgumentException("Unexpected leading X87UP class"); + } + + if (classes.get(i - 1) != ArgumentClassImpl.X87) { + return createMemoryClassArray(classes.size()); + } + } + } + + if (classes.size() > 2) { + if (classes.get(0) != ArgumentClassImpl.SSE) { + return createMemoryClassArray(classes.size()); + } + + for (int i = 1; i < classes.size(); i++) { + if (classes.get(i) != ArgumentClassImpl.SSEUP) { + return createMemoryClassArray(classes.size()); + } + } + } + + return classes; + } + + static TypeClass classifyLayout(MemoryLayout type) { + try { + if (type instanceof ValueLayout) { + return ofValue((ValueLayout)type); + } else if (type instanceof GroupLayout) { + return ofStruct((GroupLayout)type); + } else { + throw new IllegalArgumentException("Unhandled type " + type); + } + } catch (UnsupportedOperationException e) { + System.err.println("Failed to classify layout: " + type); + throw e; + } + } + + private static List[] groupByEightBytes(GroupLayout group) { + long offset = 0L; + int nEightbytes = (int) Utils.alignUp(group.byteSize(), 8) / 8; + @SuppressWarnings({"unchecked", "rawtypes"}) + List[] groups = new List[nEightbytes]; + for (MemoryLayout l : group.memberLayouts()) { + groupByEightBytes(l, offset, groups); + if (group.isStruct()) { + offset += l.byteSize(); + } + } + return groups; + } + + private static void groupByEightBytes(MemoryLayout l, long offset, List[] groups) { + if (l instanceof GroupLayout) { + GroupLayout group = (GroupLayout)l; + for (MemoryLayout m : group.memberLayouts()) { + groupByEightBytes(m, offset, groups); + if (group.isStruct()) { + offset += m.byteSize(); + } + } + } else if (l.isPadding()) { + return; + } else if (l instanceof SequenceLayout) { + SequenceLayout seq = (SequenceLayout)l; + MemoryLayout elem = seq.elementLayout(); + for (long i = 0 ; i < seq.elementCount().getAsLong() ; i++) { + groupByEightBytes(elem, offset, groups); + offset += elem.byteSize(); + } + } else if (l instanceof ValueLayout) { + List layouts = groups[(int)offset / 8]; + if (layouts == null) { + layouts = new ArrayList<>(); + groups[(int)offset / 8] = layouts; + } + // if the aggregate contains unaligned fields, it has class MEMORY + ArgumentClassImpl argumentClass = (offset % l.byteAlignment()) == 0 ? + argumentClassFor(l) : + ArgumentClassImpl.MEMORY; + layouts.add(argumentClass); + } else { + throw new IllegalStateException("Unexpected layout: " + l); + } + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java index d748f3e4145..529d7dce788 100644 --- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java @@ -23,6 +23,13 @@ * questions. * */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + package jdk.internal.foreign.abi.x64.sysv; import jdk.incubator.foreign.Addressable; @@ -123,27 +130,15 @@ public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, bool return new Bindings(csb.build(), returnInMemory, argCalc.storageCalculator.nVectorReg); } + /* Replace ProgrammableInvoker in OpenJDK with the implementation of ProgrammableInvoker specific to OpenJ9 */ public static MethodHandle arrangeDowncall(Addressable addr, MethodType mt, FunctionDescriptor cDesc) { - Bindings bindings = getBindings(mt, cDesc, false); - - MethodHandle handle = new ProgrammableInvoker(CSysV, addr, bindings.callingSequence).getBoundMethodHandle(); - handle = MethodHandles.insertArguments(handle, handle.type().parameterCount() - 1, bindings.nVectorArgs); - - if (bindings.isInMemoryReturn) { - handle = SharedUtils.adaptDowncallForIMR(handle, cDesc); - } - + MethodHandle handle = ProgrammableInvoker.getBoundMethodHandle(addr, mt, cDesc); return handle; } + /* Replace ProgrammableUpcallHandler in OpenJDK with the implementation of ProgrammableUpcallHandler specific to OpenJ9 */ public static UpcallHandler arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc) { - Bindings bindings = getBindings(mt, cDesc, true); - - if (bindings.isInMemoryReturn) { - target = SharedUtils.adaptUpcallForIMR(target); - } - - return new ProgrammableUpcallHandler(CSysV, target, bindings.callingSequence); + throw new InternalError("arrangeUpcall is not yet implemented"); //$NON-NLS-1$ } private static boolean isInMemoryReturn(Optional returnLayout) { diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java index 8e8be4bc572..db87c6221fd 100644 --- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java @@ -22,6 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2021, 2021 All Rights Reserved + * =========================================================================== + */ + package jdk.internal.foreign.abi.x64.windows; import jdk.incubator.foreign.Addressable; @@ -124,26 +131,15 @@ void setReturnBindings(Class carrier, MemoryLayout layout) { return new Bindings(csb.csb.build(), returnInMemory); } + /* Replace ProgrammableInvoker in OpenJDK with the implementation of ProgrammableInvoker specific to OpenJ9 */ public static MethodHandle arrangeDowncall(Addressable addr, MethodType mt, FunctionDescriptor cDesc) { - Bindings bindings = getBindings(mt, cDesc, false); - - MethodHandle handle = new ProgrammableInvoker(CWindows, addr, bindings.callingSequence).getBoundMethodHandle(); - - if (bindings.isInMemoryReturn) { - handle = SharedUtils.adaptDowncallForIMR(handle, cDesc); - } - + MethodHandle handle = ProgrammableInvoker.getBoundMethodHandle(addr, mt, cDesc); return handle; } + /* Replace ProgrammableUpcallHandler in OpenJDK with the implementation of ProgrammableUpcallHandler specific to OpenJ9 */ public static UpcallHandler arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc) { - Bindings bindings = getBindings(mt, cDesc, true); - - if (bindings.isInMemoryReturn) { - target = SharedUtils.adaptUpcallForIMR(target); - } - - return new ProgrammableUpcallHandler(CWindows, target, bindings.callingSequence); + throw new InternalError("arrangeUpcall is not yet implemented"); //$NON-NLS-1$ } private static boolean isInMemoryReturn(Optional returnLayout) {