8314949: linux PPC64 Big Endian: Implementation of Foreign Function & Memory API

Reviewed-by: mcimadamore, jvernee
This commit is contained in:
Martin Doerr 2023-09-06 08:26:48 +00:00
parent a01b3fb8e9
commit f6c203e616
11 changed files with 303 additions and 16 deletions

View File

@ -47,7 +47,7 @@ bool ABIDescriptor::is_volatile_reg(FloatRegister reg) const {
} }
bool ForeignGlobals::is_foreign_linker_supported() { bool ForeignGlobals::is_foreign_linker_supported() {
#ifdef ABI_ELFv2 #ifdef LINUX
return true; return true;
#else #else
return false; return false;

View File

@ -39,6 +39,7 @@ public enum CABI {
LINUX_AARCH_64, LINUX_AARCH_64,
MAC_OS_AARCH_64, MAC_OS_AARCH_64,
WIN_AARCH_64, WIN_AARCH_64,
LINUX_PPC_64,
LINUX_PPC_64_LE, LINUX_PPC_64_LE,
LINUX_RISCV_64, LINUX_RISCV_64,
LINUX_S390, LINUX_S390,
@ -74,6 +75,10 @@ public enum CABI {
// The Linux ABI follows the standard AAPCS ABI // The Linux ABI follows the standard AAPCS ABI
return LINUX_AARCH_64; return LINUX_AARCH_64;
} }
} else if (arch.equals("ppc64")) {
if (OperatingSystem.isLinux()) {
return LINUX_PPC_64;
}
} else if (arch.equals("ppc64le")) { } else if (arch.equals("ppc64le")) {
if (OperatingSystem.isLinux()) { if (OperatingSystem.isLinux()) {
return LINUX_PPC_64_LE; return LINUX_PPC_64_LE;

View File

@ -30,6 +30,7 @@ import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker; import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker; import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker;
import jdk.internal.foreign.abi.fallback.FallbackLinker; 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.ppc64.linux.LinuxPPC64leLinker;
import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker; import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker;
import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker; 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, public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker,
SysVx64Linker, WindowsAArch64Linker, SysVx64Linker, WindowsAArch64Linker,
Windowsx64Linker, LinuxPPC64leLinker, Windowsx64Linker,
LinuxPPC64Linker, LinuxPPC64leLinker,
LinuxRISCV64Linker, LinuxS390Linker, LinuxRISCV64Linker, LinuxS390Linker,
FallbackLinker { FallbackLinker {

View File

@ -276,6 +276,18 @@ public sealed interface Binding {
return Dup.INSTANCE; 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) { static Binding cast(Class<?> fromType, Class<?> toType) {
if (fromType == int.class) { if (fromType == int.class) {
if (toType == boolean.class) { if (toType == boolean.class) {
@ -286,6 +298,8 @@ public sealed interface Binding {
return Cast.INT_TO_SHORT; return Cast.INT_TO_SHORT;
} else if (toType == char.class) { } else if (toType == char.class) {
return Cast.INT_TO_CHAR; return Cast.INT_TO_CHAR;
} else if (toType == long.class) {
return Cast.INT_TO_LONG;
} }
} else if (toType == int.class) { } else if (toType == int.class) {
if (fromType == boolean.class) { if (fromType == boolean.class) {
@ -296,6 +310,24 @@ public sealed interface Binding {
return Cast.SHORT_TO_INT; return Cast.SHORT_TO_INT;
} else if (fromType == char.class) { } else if (fromType == char.class) {
return Cast.CHAR_TO_INT; 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); throw new IllegalArgumentException("Unknown conversion: " + fromType + " -> " + toType);
@ -387,6 +419,24 @@ public sealed interface Binding {
return this; 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<Binding> build() { public List<Binding> build() {
return List.copyOf(bindings); 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<Class<?>> stack) {
Class<?> last = stack.pop();
SharedUtils.checkType(last, long.class);
stack.push(long.class);
}
@Override
public void interpret(Deque<Object> 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<Class<?>> stack) {
Class<?> last = stack.pop();
SharedUtils.checkType(last, long.class);
stack.push(long.class);
}
@Override
public void interpret(Deque<Object> stack, StoreFunc storeFunc,
LoadFunc loadFunc, SegmentAllocator allocator) {
long l = (long) stack.pop();
l >>>= (shiftAmount * Byte.SIZE);
stack.push(l);
}
}
/** /**
* CAST([fromType], [toType]) * CAST([fromType], [toType])
* Pop a [fromType] from the stack, convert it to [toType], and push the resulting * 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_BYTE(int.class, byte.class),
INT_TO_CHAR(int.class, char.class), INT_TO_CHAR(int.class, char.class),
INT_TO_SHORT(int.class, short.class), INT_TO_SHORT(int.class, short.class),
INT_TO_LONG(int.class, long.class),
BOOLEAN_TO_INT(boolean.class, int.class), BOOLEAN_TO_INT(boolean.class, int.class),
BYTE_TO_INT(byte.class, int.class), BYTE_TO_INT(byte.class, int.class),
CHAR_TO_INT(char.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<?> fromType;
private final Class<?> toType; private final Class<?> toType;

View File

@ -39,6 +39,8 @@ import jdk.internal.foreign.abi.Binding.BufferStore;
import jdk.internal.foreign.abi.Binding.Cast; import jdk.internal.foreign.abi.Binding.Cast;
import jdk.internal.foreign.abi.Binding.Copy; import jdk.internal.foreign.abi.Binding.Copy;
import jdk.internal.foreign.abi.Binding.Dup; 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.UnboxAddress;
import jdk.internal.foreign.abi.Binding.VMLoad; import jdk.internal.foreign.abi.Binding.VMLoad;
import jdk.internal.foreign.abi.Binding.VMStore; import jdk.internal.foreign.abi.Binding.VMStore;
@ -463,6 +465,8 @@ public class BindingSpecializer {
case BoxAddress boxAddress -> emitBoxAddress(boxAddress); case BoxAddress boxAddress -> emitBoxAddress(boxAddress);
case UnboxAddress unused -> emitUnboxAddress(); case UnboxAddress unused -> emitUnboxAddress();
case Dup unused -> emitDupBinding(); case Dup unused -> emitDupBinding();
case ShiftLeft shiftLeft -> emitShiftLeft(shiftLeft);
case ShiftRight shiftRight -> emitShiftRight(shiftRight);
case Cast cast -> emitCast(cast); case Cast cast -> emitCast(cast);
} }
} }
@ -725,6 +729,20 @@ public class BindingSpecializer {
pushType(dupType); 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) { private void emitCast(Cast cast) {
Class<?> fromType = cast.fromType(); Class<?> fromType = cast.fromType();
Class<?> toType = cast.toType(); Class<?> toType = cast.toType();
@ -744,6 +762,11 @@ public class BindingSpecializer {
case INT_TO_BYTE -> cb.i2b(); case INT_TO_BYTE -> cb.i2b();
case INT_TO_CHAR -> cb.i2c(); case INT_TO_CHAR -> cb.i2c();
case INT_TO_SHORT -> cb.i2s(); 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 -> { case BOOLEAN_TO_INT, BYTE_TO_INT, CHAR_TO_INT, SHORT_TO_INT -> {
// no-op in bytecode // no-op in bytecode
} }

View File

@ -32,6 +32,8 @@ import jdk.internal.foreign.abi.Binding.BufferStore;
import jdk.internal.foreign.abi.Binding.Cast; import jdk.internal.foreign.abi.Binding.Cast;
import jdk.internal.foreign.abi.Binding.Copy; import jdk.internal.foreign.abi.Binding.Copy;
import jdk.internal.foreign.abi.Binding.Dup; 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.UnboxAddress;
import jdk.internal.foreign.abi.Binding.VMLoad; import jdk.internal.foreign.abi.Binding.VMLoad;
import jdk.internal.foreign.abi.Binding.VMStore; import jdk.internal.foreign.abi.Binding.VMStore;
@ -220,6 +222,8 @@ public class CallingSequenceBuilder {
case Copy unused -> true; case Copy unused -> true;
case UnboxAddress unused -> true; case UnboxAddress unused -> true;
case Dup unused -> true; case Dup unused -> true;
case ShiftLeft unused -> true;
case ShiftRight unused -> true;
case Cast unused -> true; case Cast unused -> true;
case VMLoad unused -> false; case VMLoad unused -> false;
@ -254,6 +258,8 @@ public class CallingSequenceBuilder {
case Allocate unused -> true; case Allocate unused -> true;
case BoxAddress unused -> true; case BoxAddress unused -> true;
case Dup unused -> true; case Dup unused -> true;
case ShiftLeft unused -> true;
case ShiftRight unused -> true;
case Cast unused -> true; case Cast unused -> true;
case VMStore unused -> false; case VMStore unused -> false;

View File

@ -33,6 +33,7 @@ import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker; import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker; import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker;
import jdk.internal.foreign.abi.fallback.FallbackLinker; 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.ppc64.linux.LinuxPPC64leLinker;
import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker; import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker;
import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker; import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker;
@ -241,6 +242,7 @@ public final class SharedUtils {
case LINUX_AARCH_64 -> LinuxAArch64Linker.getInstance(); case LINUX_AARCH_64 -> LinuxAArch64Linker.getInstance();
case MAC_OS_AARCH_64 -> MacOsAArch64Linker.getInstance(); case MAC_OS_AARCH_64 -> MacOsAArch64Linker.getInstance();
case WIN_AARCH_64 -> WindowsAArch64Linker.getInstance(); case WIN_AARCH_64 -> WindowsAArch64Linker.getInstance();
case LINUX_PPC_64 -> LinuxPPC64Linker.getInstance();
case LINUX_PPC_64_LE -> LinuxPPC64leLinker.getInstance(); case LINUX_PPC_64_LE -> LinuxPPC64leLinker.getInstance();
case LINUX_RISCV_64 -> LinuxRISCV64Linker.getInstance(); case LINUX_RISCV_64 -> LinuxRISCV64Linker.getInstance();
case LINUX_S390 -> LinuxS390Linker.getInstance(); case LINUX_S390 -> LinuxS390Linker.getInstance();

View File

@ -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;
}
}

View File

@ -25,11 +25,13 @@
*/ */
package jdk.internal.foreign.abi.ppc64; package jdk.internal.foreign.abi.ppc64;
import jdk.internal.foreign.abi.ppc64.CallArranger;
/** /**
* PPC64 CallArranger specialized for ABI v2. * PPC64 CallArranger specialized for ABI v2.
*/ */
public class ABIv2CallArranger extends CallArranger { public class ABIv2CallArranger extends CallArranger {
// Currently no specific content, but CallArranger detects usage of ABIv2 for this class.
@Override
protected boolean useABIv2() {
return true;
}
} }

View File

@ -35,7 +35,6 @@ import jdk.internal.foreign.abi.DowncallLinker;
import jdk.internal.foreign.abi.LinkerOptions; import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.ppc64.ABIv2CallArranger;
import java.lang.foreign.AddressLayout; import java.lang.foreign.AddressLayout;
import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.FunctionDescriptor;
@ -62,7 +61,7 @@ import static jdk.internal.foreign.abi.ppc64.PPC64Architecture.Regs.*;
* public constants CallArranger.ABIv1/2. * public constants CallArranger.ABIv1/2.
*/ */
public abstract class CallArranger { 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 STACK_SLOT_SIZE = 8;
private static final int MAX_COPY_SIZE = 8; private static final int MAX_COPY_SIZE = 8;
@ -90,8 +89,14 @@ public abstract class CallArranger {
protected CallArranger() {} protected CallArranger() {}
public static final CallArranger ABIv1 = new ABIv1CallArranger();
public static final CallArranger ABIv2 = new ABIv2CallArranger(); public static final CallArranger ABIv2 = new ABIv2CallArranger();
/**
* Select ABI version
*/
protected abstract boolean useABIv2();
public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) { public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {
return getBindings(mt, cDesc, forUpcall, LinkerOptions.empty()); return getBindings(mt, cDesc, forUpcall, LinkerOptions.empty());
} }
@ -214,11 +219,23 @@ public abstract class CallArranger {
return reg; 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. // Regular struct, no HFA.
VMStorage[] structAlloc(MemoryLayout layout) { 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. // 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; int numChunks = (int) Utils.alignUp(layout.byteSize(), MAX_COPY_SIZE) / MAX_COPY_SIZE;
VMStorage[] result = new VMStorage[numChunks]; VMStorage[] result = new VMStorage[numChunks];
@ -332,16 +349,26 @@ public abstract class CallArranger {
case STRUCT_REGISTER -> { case STRUCT_REGISTER -> {
assert carrier == MemorySegment.class; assert carrier == MemorySegment.class;
VMStorage[] regs = storageCalculator.structAlloc(layout); VMStorage[] regs = storageCalculator.structAlloc(layout);
final boolean isLargeABIv1Struct = !useABIv2 && layout.byteSize() > MAX_COPY_SIZE;
long offset = 0; long offset = 0;
for (VMStorage storage : regs) { for (VMStorage storage : regs) {
// Last slot may be partly used. // Last slot may be partly used.
final long size = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE); final long size = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE);
int shiftAmount = 0;
Class<?> type = SharedUtils.primitiveCarrierForSize(size, false); Class<?> type = SharedUtils.primitiveCarrierForSize(size, false);
if (offset + size < layout.byteSize()) { if (offset + size < layout.byteSize()) {
bindings.dup(); 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; offset += size;
} }
} }
@ -410,14 +437,25 @@ public abstract class CallArranger {
assert carrier == MemorySegment.class; assert carrier == MemorySegment.class;
bindings.allocate(layout); bindings.allocate(layout);
VMStorage[] regs = storageCalculator.structAlloc(layout); VMStorage[] regs = storageCalculator.structAlloc(layout);
final boolean isLargeABIv1Struct = !useABIv2 && layout.byteSize() > MAX_COPY_SIZE;
long offset = 0; long offset = 0;
for (VMStorage storage : regs) { for (VMStorage storage : regs) {
// Last slot may be partly used. // Last slot may be partly used.
final long size = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE); final long size = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE);
int shiftAmount = 0;
Class<?> type = SharedUtils.primitiveCarrierForSize(size, false); Class<?> type = SharedUtils.primitiveCarrierForSize(size, false);
bindings.dup() if (isLargeABIv1Struct && offset + size >= layout.byteSize()) {
.vmLoad(storage, type) // Last slot requires shift.
.bufferStore(offset, type, (int) size); 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; offset += size;
} }
} }

View File

@ -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;
}
}