From f6c203e61620dc130b8c366f824e6923fca52e82 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 6 Sep 2023 08:26:48 +0000 Subject: [PATCH] 8314949: linux PPC64 Big Endian: Implementation of Foreign Function & Memory API Reviewed-by: mcimadamore, jvernee --- src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp | 2 +- .../classes/jdk/internal/foreign/CABI.java | 5 + .../internal/foreign/abi/AbstractLinker.java | 4 +- .../jdk/internal/foreign/abi/Binding.java | 109 +++++++++++++++++- .../foreign/abi/BindingSpecializer.java | 23 ++++ .../foreign/abi/CallingSequenceBuilder.java | 6 + .../jdk/internal/foreign/abi/SharedUtils.java | 2 + .../foreign/abi/ppc64/ABIv1CallArranger.java | 37 ++++++ .../foreign/abi/ppc64/ABIv2CallArranger.java | 8 +- .../foreign/abi/ppc64/CallArranger.java | 58 ++++++++-- .../abi/ppc64/linux/LinuxPPC64Linker.java | 65 +++++++++++ 11 files changed, 303 insertions(+), 16 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv1CallArranger.java create mode 100644 src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker.java diff --git a/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp b/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp index 6e10aacaad1..9e689bccab1 100644 --- a/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp +++ b/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp @@ -47,7 +47,7 @@ bool ABIDescriptor::is_volatile_reg(FloatRegister reg) const { } bool ForeignGlobals::is_foreign_linker_supported() { -#ifdef ABI_ELFv2 +#ifdef LINUX return true; #else return false; diff --git a/src/java.base/share/classes/jdk/internal/foreign/CABI.java b/src/java.base/share/classes/jdk/internal/foreign/CABI.java index d376a196333..5f8a30017c2 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/CABI.java +++ b/src/java.base/share/classes/jdk/internal/foreign/CABI.java @@ -39,6 +39,7 @@ public enum CABI { LINUX_AARCH_64, MAC_OS_AARCH_64, WIN_AARCH_64, + LINUX_PPC_64, LINUX_PPC_64_LE, LINUX_RISCV_64, LINUX_S390, @@ -74,6 +75,10 @@ public enum CABI { // The Linux ABI follows the standard AAPCS ABI return LINUX_AARCH_64; } + } else if (arch.equals("ppc64")) { + if (OperatingSystem.isLinux()) { + return LINUX_PPC_64; + } } else if (arch.equals("ppc64le")) { if (OperatingSystem.isLinux()) { return LINUX_PPC_64_LE; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java index 8a322cdcf7a..e0c5c5575fc 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java @@ -30,6 +30,7 @@ import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker; import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker; import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker; import jdk.internal.foreign.abi.fallback.FallbackLinker; +import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64Linker; import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker; import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker; import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker; @@ -60,7 +61,8 @@ import java.util.Set; public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker, SysVx64Linker, WindowsAArch64Linker, - Windowsx64Linker, LinuxPPC64leLinker, + Windowsx64Linker, + LinuxPPC64Linker, LinuxPPC64leLinker, LinuxRISCV64Linker, LinuxS390Linker, FallbackLinker { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java b/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java index 008c6683528..da288d51406 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java @@ -276,6 +276,18 @@ public sealed interface Binding { return Dup.INSTANCE; } + static ShiftLeft shiftLeft(int shiftAmount) { + if (shiftAmount <= 0) + throw new IllegalArgumentException("shiftAmount must be positive"); + return new ShiftLeft(shiftAmount); + } + + static ShiftRight shiftRight(int shiftAmount) { + if (shiftAmount <= 0) + throw new IllegalArgumentException("shiftAmount must be positive"); + return new ShiftRight(shiftAmount); + } + static Binding cast(Class fromType, Class toType) { if (fromType == int.class) { if (toType == boolean.class) { @@ -286,6 +298,8 @@ public sealed interface Binding { return Cast.INT_TO_SHORT; } else if (toType == char.class) { return Cast.INT_TO_CHAR; + } else if (toType == long.class) { + return Cast.INT_TO_LONG; } } else if (toType == int.class) { if (fromType == boolean.class) { @@ -296,6 +310,24 @@ public sealed interface Binding { return Cast.SHORT_TO_INT; } else if (fromType == char.class) { return Cast.CHAR_TO_INT; + } else if (fromType == long.class) { + return Cast.LONG_TO_INT; + } + } else if (fromType == long.class) { + if (toType == byte.class) { + return Cast.LONG_TO_BYTE; + } else if (toType == short.class) { + return Cast.LONG_TO_SHORT; + } else if (toType == char.class) { + return Cast.LONG_TO_CHAR; + } + } else if (toType == long.class) { + if (fromType == byte.class) { + return Cast.BYTE_TO_LONG; + } else if (fromType == short.class) { + return Cast.SHORT_TO_LONG; + } else if (fromType == char.class) { + return Cast.CHAR_TO_LONG; } } throw new IllegalArgumentException("Unknown conversion: " + fromType + " -> " + toType); @@ -387,6 +419,24 @@ public sealed interface Binding { return this; } + // Converts to long if needed then shifts left by the given number of Bytes. + public Binding.Builder shiftLeft(int shiftAmount, Class type) { + if (type != long.class) { + bindings.add(Binding.cast(type, long.class)); + } + bindings.add(Binding.shiftLeft(shiftAmount)); + return this; + } + + // Shifts right by the given number of Bytes then converts from long if needed. + public Binding.Builder shiftRight(int shiftAmount, Class type) { + bindings.add(Binding.shiftRight(shiftAmount)); + if (type != long.class) { + bindings.add(Binding.cast(long.class, type)); + } + return this; + } + public List build() { return List.copyOf(bindings); } @@ -670,6 +720,52 @@ public sealed interface Binding { } } + /** + * ShiftLeft([shiftAmount]) + * Shifts the Bytes on the top of the operand stack (64 bit unsigned). + * Shifts left by the given number of Bytes. + */ + record ShiftLeft(int shiftAmount) implements Binding { + + @Override + public void verify(Deque> stack) { + Class last = stack.pop(); + SharedUtils.checkType(last, long.class); + stack.push(long.class); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + long l = (long) stack.pop(); + l <<= (shiftAmount * Byte.SIZE); + stack.push(l); + } + } + + /** + * ShiftRight([shiftAmount]) + * Shifts the Bytes on the top of the operand stack (64 bit unsigned). + * Shifts right by the given number of Bytes. + */ + record ShiftRight(int shiftAmount) implements Binding { + + @Override + public void verify(Deque> stack) { + Class last = stack.pop(); + SharedUtils.checkType(last, long.class); + stack.push(long.class); + } + + @Override + public void interpret(Deque stack, StoreFunc storeFunc, + LoadFunc loadFunc, SegmentAllocator allocator) { + long l = (long) stack.pop(); + l >>>= (shiftAmount * Byte.SIZE); + stack.push(l); + } + } + /** * CAST([fromType], [toType]) * Pop a [fromType] from the stack, convert it to [toType], and push the resulting @@ -690,10 +786,21 @@ public sealed interface Binding { INT_TO_BYTE(int.class, byte.class), INT_TO_CHAR(int.class, char.class), INT_TO_SHORT(int.class, short.class), + INT_TO_LONG(int.class, long.class), + BOOLEAN_TO_INT(boolean.class, int.class), BYTE_TO_INT(byte.class, int.class), CHAR_TO_INT(char.class, int.class), - SHORT_TO_INT(short.class, int.class); + SHORT_TO_INT(short.class, int.class), + LONG_TO_INT(long.class, int.class), + + LONG_TO_BYTE(long.class, byte.class), + LONG_TO_SHORT(long.class, short.class), + LONG_TO_CHAR(long.class, char.class), + + BYTE_TO_LONG(byte.class, long.class), + SHORT_TO_LONG(short.class, long.class), + CHAR_TO_LONG(char.class, long.class); private final Class fromType; private final Class toType; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java index b447bd31b48..3855a49c389 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java @@ -39,6 +39,8 @@ import jdk.internal.foreign.abi.Binding.BufferStore; import jdk.internal.foreign.abi.Binding.Cast; import jdk.internal.foreign.abi.Binding.Copy; import jdk.internal.foreign.abi.Binding.Dup; +import jdk.internal.foreign.abi.Binding.ShiftLeft; +import jdk.internal.foreign.abi.Binding.ShiftRight; import jdk.internal.foreign.abi.Binding.UnboxAddress; import jdk.internal.foreign.abi.Binding.VMLoad; import jdk.internal.foreign.abi.Binding.VMStore; @@ -463,6 +465,8 @@ public class BindingSpecializer { case BoxAddress boxAddress -> emitBoxAddress(boxAddress); case UnboxAddress unused -> emitUnboxAddress(); case Dup unused -> emitDupBinding(); + case ShiftLeft shiftLeft -> emitShiftLeft(shiftLeft); + case ShiftRight shiftRight -> emitShiftRight(shiftRight); case Cast cast -> emitCast(cast); } } @@ -725,6 +729,20 @@ public class BindingSpecializer { pushType(dupType); } + private void emitShiftLeft(ShiftLeft shiftLeft) { + popType(long.class); + cb.constantInstruction(shiftLeft.shiftAmount() * Byte.SIZE); + cb.lshl(); + pushType(long.class); + } + + private void emitShiftRight(ShiftRight shiftRight) { + popType(long.class); + cb.constantInstruction(shiftRight.shiftAmount() * Byte.SIZE); + cb.lushr(); + pushType(long.class); + } + private void emitCast(Cast cast) { Class fromType = cast.fromType(); Class toType = cast.toType(); @@ -744,6 +762,11 @@ public class BindingSpecializer { case INT_TO_BYTE -> cb.i2b(); case INT_TO_CHAR -> cb.i2c(); case INT_TO_SHORT -> cb.i2s(); + case BYTE_TO_LONG, CHAR_TO_LONG, SHORT_TO_LONG, INT_TO_LONG -> cb.i2l(); + case LONG_TO_BYTE -> { cb.l2i(); cb.i2b(); } + case LONG_TO_SHORT -> { cb.l2i(); cb.i2s(); } + case LONG_TO_CHAR -> { cb.l2i(); cb.i2c(); } + case LONG_TO_INT -> cb.l2i(); case BOOLEAN_TO_INT, BYTE_TO_INT, CHAR_TO_INT, SHORT_TO_INT -> { // no-op in bytecode } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java index 65f08b75a39..2683dc4542f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java @@ -32,6 +32,8 @@ import jdk.internal.foreign.abi.Binding.BufferStore; import jdk.internal.foreign.abi.Binding.Cast; import jdk.internal.foreign.abi.Binding.Copy; import jdk.internal.foreign.abi.Binding.Dup; +import jdk.internal.foreign.abi.Binding.ShiftLeft; +import jdk.internal.foreign.abi.Binding.ShiftRight; import jdk.internal.foreign.abi.Binding.UnboxAddress; import jdk.internal.foreign.abi.Binding.VMLoad; import jdk.internal.foreign.abi.Binding.VMStore; @@ -220,6 +222,8 @@ public class CallingSequenceBuilder { case Copy unused -> true; case UnboxAddress unused -> true; case Dup unused -> true; + case ShiftLeft unused -> true; + case ShiftRight unused -> true; case Cast unused -> true; case VMLoad unused -> false; @@ -254,6 +258,8 @@ public class CallingSequenceBuilder { case Allocate unused -> true; case BoxAddress unused -> true; case Dup unused -> true; + case ShiftLeft unused -> true; + case ShiftRight unused -> true; case Cast unused -> true; case VMStore unused -> false; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java index 92d10a1dbdf..24892a50b0f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java @@ -33,6 +33,7 @@ import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker; import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker; import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker; import jdk.internal.foreign.abi.fallback.FallbackLinker; +import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64Linker; import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker; import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker; import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker; @@ -241,6 +242,7 @@ public final class SharedUtils { case LINUX_AARCH_64 -> LinuxAArch64Linker.getInstance(); case MAC_OS_AARCH_64 -> MacOsAArch64Linker.getInstance(); case WIN_AARCH_64 -> WindowsAArch64Linker.getInstance(); + case LINUX_PPC_64 -> LinuxPPC64Linker.getInstance(); case LINUX_PPC_64_LE -> LinuxPPC64leLinker.getInstance(); case LINUX_RISCV_64 -> LinuxRISCV64Linker.getInstance(); case LINUX_S390 -> LinuxS390Linker.getInstance(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv1CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv1CallArranger.java new file mode 100644 index 00000000000..a32d4796337 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv1CallArranger.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.ppc64; + +/** + * PPC64 CallArranger specialized for ABI v1. + */ +public class ABIv1CallArranger extends CallArranger { + + @Override + protected boolean useABIv2() { + return false; + } +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv2CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv2CallArranger.java index c31204e8671..2a13daed0bd 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv2CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv2CallArranger.java @@ -25,11 +25,13 @@ */ package jdk.internal.foreign.abi.ppc64; -import jdk.internal.foreign.abi.ppc64.CallArranger; - /** * PPC64 CallArranger specialized for ABI v2. */ public class ABIv2CallArranger extends CallArranger { - // Currently no specific content, but CallArranger detects usage of ABIv2 for this class. + + @Override + protected boolean useABIv2() { + return true; + } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java index 6c26d67ae99..53adf5c9028 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java @@ -35,7 +35,6 @@ import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.LinkerOptions; import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.VMStorage; -import jdk.internal.foreign.abi.ppc64.ABIv2CallArranger; import java.lang.foreign.AddressLayout; import java.lang.foreign.FunctionDescriptor; @@ -62,7 +61,7 @@ import static jdk.internal.foreign.abi.ppc64.PPC64Architecture.Regs.*; * public constants CallArranger.ABIv1/2. */ public abstract class CallArranger { - final boolean useABIv2 = (this instanceof ABIv2CallArranger); + final boolean useABIv2 = useABIv2(); private static final int STACK_SLOT_SIZE = 8; private static final int MAX_COPY_SIZE = 8; @@ -90,8 +89,14 @@ public abstract class CallArranger { protected CallArranger() {} + public static final CallArranger ABIv1 = new ABIv1CallArranger(); public static final CallArranger ABIv2 = new ABIv2CallArranger(); + /** + * Select ABI version + */ + protected abstract boolean useABIv2(); + public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) { return getBindings(mt, cDesc, forUpcall, LinkerOptions.empty()); } @@ -214,11 +219,23 @@ public abstract class CallArranger { return reg; } + /* The struct is split into 8-byte chunks, and those chunks are passed in registers or on the stack. + ABIv1 requires shifting if the struct occupies more than one 8-byte chunk and the last one is not full. + Here's an example for passing an 11 byte struct with ABIv1: + offset : 0 .... 32 ..... 64 ..... 96 .... 128 + values : xxxxxxxx|yyyyyyyy|zzzzzz??|???????? (can't touch bits 96..128) + Load into int : V +--------+ + | | + +--------+ | + V V + In register : ????????|??zzzzzz (LSBs are zz...z) + Shift left : zzzzzz00|00000000 (LSBs are 00...0) + Write long : V V + Result : xxxxxxxx|yyyyyyyy|zzzzzz00|00000000 + */ + // Regular struct, no HFA. VMStorage[] structAlloc(MemoryLayout layout) { - // TODO: Big Endian can't pass partially used slots correctly in some cases with: - // !useABIv2 && layout.byteSize() > 8 && layout.byteSize() % 8 != 0 - // Allocate enough gp slots (regs and stack) such that the struct fits in them. int numChunks = (int) Utils.alignUp(layout.byteSize(), MAX_COPY_SIZE) / MAX_COPY_SIZE; VMStorage[] result = new VMStorage[numChunks]; @@ -332,16 +349,26 @@ public abstract class CallArranger { case STRUCT_REGISTER -> { assert carrier == MemorySegment.class; VMStorage[] regs = storageCalculator.structAlloc(layout); + final boolean isLargeABIv1Struct = !useABIv2 && layout.byteSize() > MAX_COPY_SIZE; long offset = 0; for (VMStorage storage : regs) { // Last slot may be partly used. final long size = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE); + int shiftAmount = 0; Class type = SharedUtils.primitiveCarrierForSize(size, false); if (offset + size < layout.byteSize()) { bindings.dup(); + } else if (isLargeABIv1Struct) { + // Last slot requires shift. + shiftAmount = MAX_COPY_SIZE - (int) size; + } + bindings.bufferLoad(offset, type, (int) size); + if (shiftAmount != 0) { + bindings.shiftLeft(shiftAmount, type) + .vmStore(storage, long.class); + } else { + bindings.vmStore(storage, type); } - bindings.bufferLoad(offset, type, (int) size) - .vmStore(storage, type); offset += size; } } @@ -410,14 +437,25 @@ public abstract class CallArranger { assert carrier == MemorySegment.class; bindings.allocate(layout); VMStorage[] regs = storageCalculator.structAlloc(layout); + final boolean isLargeABIv1Struct = !useABIv2 && layout.byteSize() > MAX_COPY_SIZE; long offset = 0; for (VMStorage storage : regs) { // Last slot may be partly used. final long size = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE); + int shiftAmount = 0; Class type = SharedUtils.primitiveCarrierForSize(size, false); - bindings.dup() - .vmLoad(storage, type) - .bufferStore(offset, type, (int) size); + if (isLargeABIv1Struct && offset + size >= layout.byteSize()) { + // Last slot requires shift. + shiftAmount = MAX_COPY_SIZE - (int) size; + } + bindings.dup(); + if (shiftAmount != 0) { + bindings.vmLoad(storage, long.class) + .shiftRight(shiftAmount, type); + } else { + bindings.vmLoad(storage, type); + } + bindings.bufferStore(offset, type, (int) size); offset += size; } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker.java new file mode 100644 index 00000000000..150687d4078 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.foreign.abi.ppc64.linux; + +import jdk.internal.foreign.abi.AbstractLinker; +import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.ppc64.CallArranger; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.nio.ByteOrder; + +public final class LinuxPPC64Linker extends AbstractLinker { + + public static LinuxPPC64Linker getInstance() { + final class Holder { + private static final LinuxPPC64Linker INSTANCE = new LinuxPPC64Linker(); + } + + return Holder.INSTANCE; + } + + private LinuxPPC64Linker() { + // Ensure there is only one instance + } + + @Override + protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.ABIv1.arrangeDowncall(inferredMethodType, function, options); + } + + @Override + protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) { + return CallArranger.ABIv1.arrangeUpcall(targetType, function, options); + } + + @Override + protected ByteOrder linkerByteOrder() { + return ByteOrder.BIG_ENDIAN; + } +}