8263512: [macos_aarch64] issues with calling va_args functions from invoke_native

Reviewed-by: jvernee
This commit is contained in:
Nick Gasson 2021-06-04 23:55:12 +00:00
parent 4e6748c543
commit 76b54a1995
14 changed files with 563 additions and 107 deletions

View File

@ -30,7 +30,8 @@ import jdk.internal.foreign.NativeMemorySegmentImpl;
import jdk.internal.foreign.PlatformLayouts;
import jdk.internal.foreign.SystemLookup;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.AArch64VaList;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64VaList;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64VaList;
import jdk.internal.foreign.abi.x64.sysv.SysVVaList;
import jdk.internal.foreign.abi.x64.windows.WinVaList;
import jdk.internal.reflect.CallerSensitive;
@ -523,7 +524,7 @@ public sealed interface CLinker permits AbstractCLinker {
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
*/
sealed interface VaList extends Addressable permits WinVaList, SysVVaList, AArch64VaList, SharedUtils.EmptyVaList {
sealed interface VaList extends Addressable permits WinVaList, SysVVaList, LinuxAArch64VaList, MacOsAArch64VaList, SharedUtils.EmptyVaList {
/**
* Reads the next value as an {@code int} and advances this va list's position.
@ -729,7 +730,7 @@ public sealed interface CLinker permits AbstractCLinker {
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
*/
sealed interface Builder permits WinVaList.Builder, SysVVaList.Builder, AArch64VaList.Builder {
sealed interface Builder permits WinVaList.Builder, SysVVaList.Builder, LinuxAArch64VaList.Builder, MacOsAArch64VaList.Builder {
/**
* Adds a native value represented as an {@code int} to the C {@code va_list} being constructed.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, 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
@ -32,7 +32,8 @@ import static jdk.incubator.foreign.MemoryLayouts.ADDRESS;
public enum CABI {
SysV,
Win64,
AArch64;
LinuxAArch64,
MacOsAArch64;
private static final CABI current;
@ -49,7 +50,12 @@ public enum CABI {
current = SysV;
}
} else if (arch.equals("aarch64")) {
current = AArch64;
if (os.startsWith("Mac")) {
current = MacOsAArch64;
} else {
// The Linux ABI follows the standard AAPCS ABI
current = LinuxAArch64;
}
} else {
throw new ExceptionInInitializerError(
"Unsupported os, arch, or address size: " + os + ", " + arch + ", " + addressSize);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, 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
@ -38,15 +38,16 @@ public class PlatformLayouts {
return switch (CABI.current()) {
case SysV -> sysv;
case Win64 -> win64;
case AArch64 -> aarch64;
case LinuxAArch64, MacOsAArch64 -> aarch64;
};
}
public static MemoryLayout asVarArg(MemoryLayout ml) {
if (CABI.current() == CABI.Win64) {
return Win64.asVarArg(ml);
}
return ml;
return switch (CABI.current()) {
case Win64 -> Win64.asVarArg(ml);
case MacOsAArch64 -> AArch64.asVarArg(ml);
default -> ml;
};
}
private static ValueLayout ofChar(ByteOrder order, long bitSize) {
@ -158,7 +159,7 @@ public class PlatformLayouts {
}
/**
* The name of the layout attribute (see {@link MemoryLayout#attributes()} used to mark variadic parameters. The
* The name of the layout attribute (see {@link MemoryLayout#attributes()}) used to mark variadic parameters. The
* attribute value must be a boolean.
*/
public static final String VARARGS_ATTRIBUTE_NAME = "abi/windows/varargs";
@ -271,5 +272,25 @@ public class PlatformLayouts {
* The {@code va_list} native type, as it is passed to a function.
*/
public static final MemoryLayout C_VA_LIST = AArch64.C_POINTER;
/**
* The name of the layout attribute (see {@link MemoryLayout#attributes()})
* used to mark variadic parameters on systems such as macOS which pass these
* entirely on the stack. The attribute value must be a boolean.
*/
public final static String STACK_VARARGS_ATTRIBUTE_NAME = "abi/aarch64/stack_varargs";
/**
* Return a new memory layout which describes a variadic parameter to be
* passed to a function. This is only required on platforms such as macOS
* which pass variadic parameters entirely on the stack.
* @param layout the original parameter layout.
* @return a layout which is the same as {@code layout}, except for
* the extra attribute {@link #STACK_VARARGS_ATTRIBUTE_NAME}, which is set
* to {@code true}.
*/
public static MemoryLayout asVarArg(MemoryLayout layout) {
return layout.withAttribute(STACK_VARARGS_ATTRIBUTE_NAME, true);
}
}
}

View File

@ -46,7 +46,7 @@ public class SystemLookup implements SymbolLookup {
* on Windows. For this reason, on Windows we do not generate any side-library, and load msvcrt.dll directly instead.
*/
final NativeLibrary syslookup = switch (CABI.current()) {
case SysV, AArch64 -> NativeLibraries.rawNativeLibraries(SystemLookup.class, false).loadLibrary("syslookup");
case SysV, LinuxAArch64, MacOsAArch64 -> NativeLibraries.rawNativeLibraries(SystemLookup.class, false).loadLibrary("syslookup");
case Win64 -> {
Path system32 = Path.of(System.getenv("SystemRoot"), "System32");
Path ucrtbase = system32.resolve("ucrtbase.dll");

View File

@ -40,7 +40,8 @@ import jdk.incubator.foreign.ValueLayout;
import jdk.internal.foreign.CABI;
import jdk.internal.foreign.MemoryAddressImpl;
import jdk.internal.foreign.Utils;
import jdk.internal.foreign.abi.aarch64.AArch64Linker;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
@ -269,7 +270,8 @@ public class SharedUtils {
return switch (CABI.current()) {
case Win64 -> Windowsx64Linker.getInstance();
case SysV -> SysVx64Linker.getInstance();
case AArch64 -> AArch64Linker.getInstance();
case LinuxAArch64 -> LinuxAArch64Linker.getInstance();
case MacOsAArch64 -> MacOsAArch64Linker.getInstance();
};
}
@ -454,7 +456,8 @@ public class SharedUtils {
return switch (CABI.current()) {
case Win64 -> Windowsx64Linker.newVaList(actions, scope);
case SysV -> SysVx64Linker.newVaList(actions, scope);
case AArch64 -> AArch64Linker.newVaList(actions, scope);
case LinuxAArch64 -> LinuxAArch64Linker.newVaList(actions, scope);
case MacOsAArch64 -> MacOsAArch64Linker.newVaList(actions, scope);
};
}
@ -468,7 +471,8 @@ public class SharedUtils {
return switch (CABI.current()) {
case Win64 -> Windowsx64Linker.newVaListOfAddress(ma, scope);
case SysV -> SysVx64Linker.newVaListOfAddress(ma, scope);
case AArch64 -> AArch64Linker.newVaListOfAddress(ma, scope);
case LinuxAArch64 -> LinuxAArch64Linker.newVaListOfAddress(ma, scope);
case MacOsAArch64 -> MacOsAArch64Linker.newVaListOfAddress(ma, scope);
};
}
@ -476,7 +480,8 @@ public class SharedUtils {
return switch (CABI.current()) {
case Win64 -> Windowsx64Linker.emptyVaList();
case SysV -> SysVx64Linker.emptyVaList();
case AArch64 -> AArch64Linker.emptyVaList();
case LinuxAArch64 -> LinuxAArch64Linker.emptyVaList();
case MacOsAArch64 -> MacOsAArch64Linker.emptyVaList();
};
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Arm Limited. All rights reserved.
* Copyright (c) 2019, 2021, Arm Limited. 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
@ -96,7 +96,7 @@ public class CallArranger {
}
public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {
SharedUtils.checkFunctionTypes(mt, cDesc, AArch64Linker.ADDRESS_SIZE);
SharedUtils.checkFunctionTypes(mt, cDesc, AArch64.C_POINTER.bitSize());
CallingSequenceBuilder csb = new CallingSequenceBuilder(forUpcall);
@ -207,6 +207,16 @@ public class CallArranger {
return storage[0];
}
void adjustForVarArgs(MemoryLayout layout) {
if (layout.attribute(AArch64.STACK_VARARGS_ATTRIBUTE_NAME)
.map(Boolean.class::cast).orElse(false)) {
// This system passes all variadic parameters on the stack. Ensure
// no further arguments are allocated to registers.
nRegs[StorageClasses.INTEGER] = MAX_REGISTER_ARGUMENTS;
nRegs[StorageClasses.VECTOR] = MAX_REGISTER_ARGUMENTS;
}
}
}
static abstract class BindingCalculator {
@ -278,6 +288,7 @@ public class CallArranger {
List<Binding> getBindings(Class<?> carrier, MemoryLayout layout) {
TypeClass argumentClass = TypeClass.classifyLayout(layout);
Binding.Builder bindings = Binding.builder();
storageCalculator.adjustForVarArgs(layout);
switch (argumentClass) {
case STRUCT_REGISTER: {
assert carrier == MemorySegment.class;
@ -380,6 +391,7 @@ public class CallArranger {
List<Binding> getBindings(Class<?> carrier, MemoryLayout layout) {
TypeClass argumentClass = TypeClass.classifyLayout(layout);
Binding.Builder bindings = Binding.builder();
assert !layout.attribute(AArch64.STACK_VARARGS_ATTRIBUTE_NAME).isPresent() : "no variadic upcalls";
switch (argumentClass) {
case STRUCT_REGISTER: {
assert carrier == MemorySegment.class;

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Arm Limited. All rights reserved.
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, Arm Limited. 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
@ -31,7 +31,7 @@ import jdk.incubator.foreign.SequenceLayout;
import jdk.incubator.foreign.ValueLayout;
import jdk.internal.foreign.PlatformLayouts;
enum TypeClass {
public enum TypeClass {
STRUCT_REGISTER,
STRUCT_REFERENCE,
STRUCT_HFA,

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Arm Limited. All rights reserved.
* Copyright (c) 2019, 2021, Arm Limited. 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
@ -23,7 +23,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.foreign.abi.aarch64;
package jdk.internal.foreign.abi.aarch64.linux;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.MemoryAddress;
@ -33,6 +33,7 @@ import jdk.internal.foreign.AbstractCLinker;
import jdk.internal.foreign.ResourceScopeImpl;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.UpcallStubs;
import jdk.internal.foreign.abi.aarch64.CallArranger;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@ -44,8 +45,8 @@ import java.util.function.Consumer;
* ABI implementation based on ARM document "Procedure Call Standard for
* the ARM 64-bit Architecture".
*/
public final class AArch64Linker extends AbstractCLinker {
private static AArch64Linker instance;
public final class LinuxAArch64Linker extends AbstractCLinker {
private static LinuxAArch64Linker instance;
static final long ADDRESS_SIZE = 64; // bits
@ -57,16 +58,16 @@ public final class AArch64Linker extends AbstractCLinker {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MH_unboxVaList = lookup.findVirtual(VaList.class, "address",
MethodType.methodType(MemoryAddress.class));
MH_boxVaList = MethodHandles.insertArguments(lookup.findStatic(AArch64Linker.class, "newVaListOfAddress",
MH_boxVaList = MethodHandles.insertArguments(lookup.findStatic(LinuxAArch64Linker.class, "newVaListOfAddress",
MethodType.methodType(VaList.class, MemoryAddress.class, ResourceScope.class)), 1, ResourceScope.globalScope());
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
public static AArch64Linker getInstance() {
public static LinuxAArch64Linker getInstance() {
if (instance == null) {
instance = new AArch64Linker();
instance = new LinuxAArch64Linker();
}
return instance;
}
@ -75,7 +76,7 @@ public final class AArch64Linker extends AbstractCLinker {
public final MethodHandle downcallHandle(MethodType type, FunctionDescriptor function) {
Objects.requireNonNull(type);
Objects.requireNonNull(function);
MethodType llMt = SharedUtils.convertVaListCarriers(type, AArch64VaList.CARRIER);
MethodType llMt = SharedUtils.convertVaListCarriers(type, LinuxAArch64VaList.CARRIER);
MethodHandle handle = CallArranger.arrangeDowncall(llMt, function);
if (!type.returnType().equals(MemorySegment.class)) {
// not returning segment, just insert a throwing allocator
@ -95,17 +96,17 @@ public final class AArch64Linker extends AbstractCLinker {
}
public static VaList newVaList(Consumer<VaList.Builder> actions, ResourceScope scope) {
AArch64VaList.Builder builder = AArch64VaList.builder(scope);
LinuxAArch64VaList.Builder builder = LinuxAArch64VaList.builder(scope);
actions.accept(builder);
return builder.build();
}
public static VaList newVaListOfAddress(MemoryAddress ma, ResourceScope scope) {
return AArch64VaList.ofAddress(ma, scope);
return LinuxAArch64VaList.ofAddress(ma, scope);
}
public static VaList emptyVaList() {
return AArch64VaList.empty();
return LinuxAArch64VaList.empty();
}
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Arm Limited. All rights reserved.
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, Arm Limited. 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
@ -23,11 +23,12 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.foreign.abi.aarch64;
package jdk.internal.foreign.abi.aarch64.linux;
import jdk.incubator.foreign.*;
import jdk.internal.foreign.Utils;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.*;
import jdk.internal.misc.Unsafe;
import java.lang.invoke.VarHandle;
@ -46,7 +47,11 @@ import static jdk.internal.foreign.abi.SharedUtils.checkCompatibleType;
import static jdk.internal.foreign.abi.SharedUtils.vhPrimitiveOrAddress;
import static jdk.internal.foreign.abi.aarch64.CallArranger.MAX_REGISTER_ARGUMENTS;
public non-sealed class AArch64VaList implements VaList {
/**
* Standard va_list implementation as defined by AAPCS document and used on
* Linux. Variadic parameters may be passed in registers or on the stack.
*/
public non-sealed class LinuxAArch64VaList implements VaList {
private static final Unsafe U = Unsafe.getUnsafe();
static final Class<?> CARRIER = MemoryAddress.class;
@ -105,26 +110,26 @@ public non-sealed class AArch64VaList implements VaList {
private final MemorySegment gpRegsArea;
private final MemorySegment fpRegsArea;
private AArch64VaList(MemorySegment segment, MemorySegment gpRegsArea, MemorySegment fpRegsArea) {
private LinuxAArch64VaList(MemorySegment segment, MemorySegment gpRegsArea, MemorySegment fpRegsArea) {
this.segment = segment;
this.gpRegsArea = gpRegsArea;
this.fpRegsArea = fpRegsArea;
}
private static AArch64VaList readFromSegment(MemorySegment segment) {
private static LinuxAArch64VaList readFromSegment(MemorySegment segment) {
MemorySegment gpRegsArea = grTop(segment).addOffset(-MAX_GP_OFFSET).asSegment(
MAX_GP_OFFSET, segment.scope());
MemorySegment fpRegsArea = vrTop(segment).addOffset(-MAX_FP_OFFSET).asSegment(
MAX_FP_OFFSET, segment.scope());
return new AArch64VaList(segment, gpRegsArea, fpRegsArea);
return new LinuxAArch64VaList(segment, gpRegsArea, fpRegsArea);
}
private static MemoryAddress emptyListAddress() {
long ptr = U.allocateMemory(LAYOUT.byteSize());
MemorySegment ms = MemoryAddress.ofLong(ptr).asSegment(
LAYOUT.byteSize(), () -> U.freeMemory(ptr), ResourceScope.newSharedScope());
cleaner.register(AArch64VaList.class, () -> ms.scope().close());
cleaner.register(LinuxAArch64VaList.class, () -> ms.scope().close());
VH_stack.set(ms, MemoryAddress.NULL);
VH_gr_top.set(ms, MemoryAddress.NULL);
VH_vr_top.set(ms, MemoryAddress.NULL);
@ -246,7 +251,7 @@ public non-sealed class AArch64VaList implements VaList {
private Object read(Class<?> carrier, MemoryLayout layout, SegmentAllocator allocator) {
Objects.requireNonNull(layout);
checkCompatibleType(carrier, layout, AArch64Linker.ADDRESS_SIZE);
checkCompatibleType(carrier, layout, LinuxAArch64Linker.ADDRESS_SIZE);
TypeClass typeClass = TypeClass.classifyLayout(layout);
if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass, layout)) {
@ -346,8 +351,8 @@ public non-sealed class AArch64VaList implements VaList {
}
}
static AArch64VaList.Builder builder(ResourceScope scope) {
return new AArch64VaList.Builder(scope);
static LinuxAArch64VaList.Builder builder(ResourceScope scope) {
return new LinuxAArch64VaList.Builder(scope);
}
public static VaList ofAddress(MemoryAddress ma, ResourceScope scope) {
@ -363,7 +368,7 @@ public non-sealed class AArch64VaList implements VaList {
public VaList copy() {
MemorySegment copy = MemorySegment.allocateNative(LAYOUT, segment.scope());
copy.copyFrom(segment);
return new AArch64VaList(copy, gpRegsArea, fpRegsArea);
return new LinuxAArch64VaList(copy, gpRegsArea, fpRegsArea);
}
@Override
@ -388,7 +393,7 @@ public non-sealed class AArch64VaList implements VaList {
@Override
public String toString() {
return "AArch64VaList{"
return "LinuxAArch64VaList{"
+ "__stack=" + stackPtr()
+ ", __gr_top=" + grTop()
+ ", __vr_top=" + vrTop()
@ -440,7 +445,7 @@ public non-sealed class AArch64VaList implements VaList {
private Builder arg(Class<?> carrier, MemoryLayout layout, Object value) {
Objects.requireNonNull(layout);
Objects.requireNonNull(value);
checkCompatibleType(carrier, layout, AArch64Linker.ADDRESS_SIZE);
checkCompatibleType(carrier, layout, LinuxAArch64Linker.ADDRESS_SIZE);
TypeClass typeClass = TypeClass.classifyLayout(layout);
if (isRegOverflow(currentGPOffset, currentFPOffset, typeClass, layout)) {
@ -533,7 +538,7 @@ public non-sealed class AArch64VaList implements VaList {
assert gpRegs.scope().ownerThread() == vaListSegment.scope().ownerThread();
assert fpRegs.scope().ownerThread() == vaListSegment.scope().ownerThread();
return new AArch64VaList(vaListSegment, gpRegs, fpRegs);
return new LinuxAArch64VaList(vaListSegment, gpRegs, fpRegs);
}
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, Arm Limited. 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.aarch64.macos;
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.ResourceScope;
import jdk.internal.foreign.AbstractCLinker;
import jdk.internal.foreign.ResourceScopeImpl;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.UpcallStubs;
import jdk.internal.foreign.abi.aarch64.CallArranger;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Objects;
import java.util.function.Consumer;
import static jdk.internal.foreign.PlatformLayouts.*;
/**
* ABI implementation for macOS on Apple silicon. Based on AAPCS with
* changes to va_list and passing arguments on the stack.
*/
public final class MacOsAArch64Linker extends AbstractCLinker {
private static MacOsAArch64Linker 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 = MethodHandles.insertArguments(lookup.findStatic(MacOsAArch64Linker.class, "newVaListOfAddress",
MethodType.methodType(VaList.class, MemoryAddress.class, ResourceScope.class)), 1, ResourceScope.globalScope());
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
public static MacOsAArch64Linker getInstance() {
if (instance == null) {
instance = new MacOsAArch64Linker();
}
return instance;
}
@Override
public final MethodHandle downcallHandle(MethodType type, FunctionDescriptor function) {
Objects.requireNonNull(type);
Objects.requireNonNull(function);
MethodType llMt = SharedUtils.convertVaListCarriers(type, MacOsAArch64VaList.CARRIER);
MethodHandle handle = CallArranger.arrangeDowncall(llMt, function);
if (!type.returnType().equals(MemorySegment.class)) {
// not returning segment, just insert a throwing allocator
handle = MethodHandles.insertArguments(handle, 1, SharedUtils.THROWING_ALLOCATOR);
}
handle = SharedUtils.unboxVaLists(type, handle, MH_unboxVaList);
return handle;
}
@Override
public final MemoryAddress upcallStub(MethodHandle target, FunctionDescriptor function, ResourceScope scope) {
Objects.requireNonNull(scope);
Objects.requireNonNull(target);
Objects.requireNonNull(function);
target = SharedUtils.boxVaLists(target, MH_boxVaList);
return UpcallStubs.upcallAddress(CallArranger.arrangeUpcall(target, target.type(), function), (ResourceScopeImpl) scope);
}
public static VaList newVaList(Consumer<VaList.Builder> actions, ResourceScope scope) {
MacOsAArch64VaList.Builder builder = MacOsAArch64VaList.builder(scope);
actions.accept(builder);
return builder.build();
}
public static VaList newVaListOfAddress(MemoryAddress ma, ResourceScope scope) {
return MacOsAArch64VaList.ofAddress(ma, scope);
}
public static VaList emptyVaList() {
return MacOsAArch64VaList.empty();
}
}

View File

@ -0,0 +1,256 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, Arm Limited. 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.aarch64.macos;
import jdk.incubator.foreign.*;
import jdk.incubator.foreign.CLinker.VaList;
import jdk.internal.foreign.ResourceScopeImpl;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.SharedUtils.SimpleVaArg;
import jdk.internal.foreign.abi.aarch64.*;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static jdk.internal.foreign.PlatformLayouts.AArch64.C_POINTER;
import static jdk.internal.foreign.abi.SharedUtils.alignUp;
/**
* Simplified va_list implementation used on macOS where all variadic
* parameters are passed on the stack and the type of va_list decays to
* char* instead of the structure defined in the AAPCS.
*/
public non-sealed class MacOsAArch64VaList implements VaList {
public 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 ResourceScope scope;
private MacOsAArch64VaList(MemorySegment segment, ResourceScope scope) {
this.segment = segment;
this.scope = scope;
}
public static final VaList empty() {
return EMPTY;
}
@Override
public int vargAsInt(MemoryLayout layout) {
return (int) read(int.class, layout);
}
@Override
public long vargAsLong(MemoryLayout layout) {
return (long) read(long.class, layout);
}
@Override
public double vargAsDouble(MemoryLayout layout) {
return (double) read(double.class, layout);
}
@Override
public MemoryAddress vargAsAddress(MemoryLayout layout) {
return (MemoryAddress) read(MemoryAddress.class, layout);
}
@Override
public MemorySegment vargAsSegment(MemoryLayout layout, SegmentAllocator allocator) {
Objects.requireNonNull(allocator);
return (MemorySegment) read(MemorySegment.class, layout, allocator);
}
@Override
public MemorySegment vargAsSegment(MemoryLayout layout, ResourceScope scope) {
return vargAsSegment(layout, SegmentAllocator.ofScope(scope));
}
private Object read(Class<?> carrier, MemoryLayout layout) {
return read(carrier, layout, SharedUtils.THROWING_ALLOCATOR);
}
private Object read(Class<?> carrier, MemoryLayout layout, SegmentAllocator allocator) {
Objects.requireNonNull(layout);
SharedUtils.checkCompatibleType(carrier, layout, MacOsAArch64Linker.ADDRESS_SIZE);
Object res;
if (carrier == MemorySegment.class) {
TypeClass typeClass = TypeClass.classifyLayout(layout);
res = switch (typeClass) {
case STRUCT_REFERENCE -> {
MemoryAddress structAddr = (MemoryAddress) VH_address.get(segment);
MemorySegment struct = structAddr.asSegment(layout.byteSize(), scope());
MemorySegment seg = allocator.allocate(layout);
seg.copyFrom(struct);
segment = segment.asSlice(VA_SLOT_SIZE_BYTES);
yield seg;
}
case STRUCT_REGISTER, STRUCT_HFA -> {
MemorySegment struct = allocator.allocate(layout);
struct.copyFrom(segment.asSlice(0L, layout.byteSize()));
segment = segment.asSlice(alignUp(layout.byteSize(), VA_SLOT_SIZE_BYTES));
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);
for (MemoryLayout layout : layouts) {
Objects.requireNonNull(layout);
segment = segment.asSlice(switch (TypeClass.classifyLayout(layout)) {
case STRUCT_REGISTER, STRUCT_HFA -> alignUp(layout.byteSize(), VA_SLOT_SIZE_BYTES);
default -> VA_SLOT_SIZE_BYTES;
});
}
}
static MacOsAArch64VaList ofAddress(MemoryAddress addr, ResourceScope scope) {
MemorySegment segment = addr.asSegment(Long.MAX_VALUE, scope);
return new MacOsAArch64VaList(segment, scope);
}
static Builder builder(ResourceScope scope) {
return new Builder(scope);
}
@Override
public ResourceScope scope() {
return scope;
}
@Override
public VaList copy() {
((ResourceScopeImpl)scope).checkValidStateSlow();
return new MacOsAArch64VaList(segment, scope);
}
@Override
public MemoryAddress address() {
return segment.address();
}
public static non-sealed class Builder implements VaList.Builder {
private final ResourceScope scope;
private final List<SimpleVaArg> args = new ArrayList<>();
public Builder(ResourceScope scope) {
((ResourceScopeImpl)scope).checkValidStateSlow();
this.scope = scope;
}
private Builder arg(Class<?> carrier, MemoryLayout layout, Object value) {
Objects.requireNonNull(layout);
Objects.requireNonNull(value);
SharedUtils.checkCompatibleType(carrier, layout, MacOsAArch64Linker.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);
}
@Override
public Builder vargFromLong(ValueLayout layout, long value) {
return arg(long.class, layout, value);
}
@Override
public Builder vargFromDouble(ValueLayout layout, double value) {
return arg(double.class, layout, value);
}
@Override
public Builder vargFromAddress(ValueLayout layout, Addressable value) {
return arg(MemoryAddress.class, layout, value.address());
}
@Override
public Builder vargFromSegment(GroupLayout layout, MemorySegment value) {
return arg(MemorySegment.class, layout, value);
}
public VaList build() {
if (args.isEmpty()) {
return EMPTY;
}
SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
// Each argument may occupy up to four slots
MemorySegment segment = allocator.allocate(VA_SLOT_SIZE_BYTES * args.size() * 4);
List<MemorySegment> 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.classifyLayout(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());
cursor = cursor.asSlice(VA_SLOT_SIZE_BYTES);
}
case STRUCT_REGISTER, STRUCT_HFA -> {
cursor.copyFrom(msArg.asSlice(0, arg.layout.byteSize()));
cursor = cursor.asSlice(alignUp(arg.layout.byteSize(), VA_SLOT_SIZE_BYTES));
}
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 MacOsAArch64VaList(segment, scope);
}
}
}

View File

@ -542,10 +542,6 @@ java/beans/XMLEncoder/Test6570354.java 8015593 macosx-all
java/foreign/TestMismatch.java 8249684 macosx-all
java/foreign/StdLibTest.java 8263512 macosx-aarch64
java/foreign/TestVarArgs.java 8263512 macosx-aarch64
java/foreign/valist/VaListTest.java 8263512 macosx-aarch64
############################################################################
# jdk_lang

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, 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
@ -28,7 +28,8 @@
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
* @modules jdk.incubator.foreign/jdk.internal.foreign
* jdk.incubator.foreign/jdk.internal.foreign.abi
* jdk.incubator.foreign/jdk.internal.foreign.abi.aarch64
* jdk.incubator.foreign/jdk.internal.foreign.abi.aarch64.linux
* jdk.incubator.foreign/jdk.internal.foreign.abi.aarch64.macos
* jdk.incubator.foreign/jdk.internal.foreign.abi.x64.windows
* jdk.incubator.foreign/jdk.internal.foreign.abi.x64.sysv
* @run testng/othervm --enable-native-access=ALL-UNNAMED VaListTest
@ -36,7 +37,8 @@
import jdk.incubator.foreign.*;
import jdk.incubator.foreign.CLinker.VaList;
import jdk.internal.foreign.abi.aarch64.AArch64Linker;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
import org.testng.annotations.DataProvider;
@ -56,6 +58,7 @@ import java.util.stream.IntStream;
import static jdk.incubator.foreign.CLinker.C_DOUBLE;
import static jdk.incubator.foreign.CLinker.C_FLOAT;
import static jdk.incubator.foreign.CLinker.C_INT;
import static jdk.incubator.foreign.CLinker.C_LONG;
import static jdk.incubator.foreign.CLinker.C_LONG_LONG;
import static jdk.incubator.foreign.CLinker.C_POINTER;
import static jdk.incubator.foreign.CLinker.C_VA_LIST;
@ -113,8 +116,10 @@ public class VaListTest extends NativeTestHelper {
= actions -> Windowsx64Linker.newVaList(actions, ResourceScope.newConfinedScope());
private static final Function<Consumer<VaList.Builder>, VaList> sysvVaListFactory
= actions -> SysVx64Linker.newVaList(actions, ResourceScope.newConfinedScope());
private static final Function<Consumer<VaList.Builder>, VaList> aarch64VaListFactory
= actions -> AArch64Linker.newVaList(actions, ResourceScope.newConfinedScope());
private static final Function<Consumer<VaList.Builder>, VaList> linuxAArch64VaListFactory
= actions -> LinuxAArch64Linker.newVaList(actions, ResourceScope.newConfinedScope());
private static final Function<Consumer<VaList.Builder>, VaList> macAArch64VaListFactory
= actions -> MacOsAArch64Linker.newVaList(actions, ResourceScope.newConfinedScope());
private static final Function<Consumer<VaList.Builder>, VaList> platformVaListFactory
= (builder) -> VaList.make(builder, ResourceScope.newConfinedScope());
@ -122,8 +127,10 @@ public class VaListTest extends NativeTestHelper {
= (builder, scope) -> Windowsx64Linker.newVaList(builder, scope.scope());
private static final BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> sysvVaListScopedFactory
= (builder, scope) -> SysVx64Linker.newVaList(builder, scope.scope());
private static final BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> aarch64VaListScopedFactory
= (builder, scope) -> AArch64Linker.newVaList(builder, scope.scope());
private static final BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> linuxAArch64VaListScopedFactory
= (builder, scope) -> LinuxAArch64Linker.newVaList(builder, scope.scope());
private static final BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> macAArch64VaListScopedFactory
= (builder, scope) -> MacOsAArch64Linker.newVaList(builder, scope.scope());
private static final BiFunction<Consumer<VaList.Builder>, NativeScope, VaList> platformVaListScopedFactory
= (builder, scope) -> VaList.make(builder, scope.scope());
@ -135,10 +142,11 @@ public class VaListTest extends NativeTestHelper {
BiFunction<Integer, VaList, Integer> sumIntsNative
= MethodHandleProxies.asInterfaceInstance(BiFunction.class, MH_sumInts);
return new Object[][]{
{ winVaListFactory, sumIntsJavaFact.apply(Win64.C_INT), Win64.C_INT },
{ sysvVaListFactory, sumIntsJavaFact.apply(SysV.C_INT), SysV.C_INT },
{ aarch64VaListFactory, sumIntsJavaFact.apply(AArch64.C_INT), AArch64.C_INT },
{ platformVaListFactory, sumIntsNative, C_INT },
{ winVaListFactory, sumIntsJavaFact.apply(Win64.C_INT), Win64.C_INT },
{ sysvVaListFactory, sumIntsJavaFact.apply(SysV.C_INT), SysV.C_INT },
{ linuxAArch64VaListFactory, sumIntsJavaFact.apply(AArch64.C_INT), AArch64.C_INT },
{ macAArch64VaListFactory, sumIntsJavaFact.apply(AArch64.C_INT), AArch64.C_INT },
{ platformVaListFactory, sumIntsNative, C_INT },
};
}
@ -163,10 +171,11 @@ public class VaListTest extends NativeTestHelper {
BiFunction<Integer, VaList, Double> sumDoublesNative
= MethodHandleProxies.asInterfaceInstance(BiFunction.class, MH_sumDoubles);
return new Object[][]{
{ winVaListFactory, sumDoublesJavaFact.apply(Win64.C_DOUBLE), Win64.C_DOUBLE },
{ sysvVaListFactory, sumDoublesJavaFact.apply(SysV.C_DOUBLE), SysV.C_DOUBLE },
{ aarch64VaListFactory, sumDoublesJavaFact.apply(AArch64.C_DOUBLE), AArch64.C_DOUBLE },
{ platformVaListFactory, sumDoublesNative, C_DOUBLE },
{ winVaListFactory, sumDoublesJavaFact.apply(Win64.C_DOUBLE), Win64.C_DOUBLE },
{ sysvVaListFactory, sumDoublesJavaFact.apply(SysV.C_DOUBLE), SysV.C_DOUBLE },
{ linuxAArch64VaListFactory, sumDoublesJavaFact.apply(AArch64.C_DOUBLE), AArch64.C_DOUBLE },
{ macAArch64VaListFactory, sumDoublesJavaFact.apply(AArch64.C_DOUBLE), AArch64.C_DOUBLE },
{ platformVaListFactory, sumDoublesNative, C_DOUBLE },
};
}
@ -193,10 +202,11 @@ public class VaListTest extends NativeTestHelper {
};
Function<VaList, Integer> getIntNative = MethodHandleProxies.asInterfaceInstance(Function.class, MH_getInt);
return new Object[][]{
{ winVaListFactory, getIntJavaFact.apply(Win64.C_POINTER), Win64.C_POINTER },
{ sysvVaListFactory, getIntJavaFact.apply(SysV.C_POINTER), SysV.C_POINTER },
{ aarch64VaListFactory, getIntJavaFact.apply(AArch64.C_POINTER), AArch64.C_POINTER },
{ platformVaListFactory, getIntNative, C_POINTER },
{ winVaListFactory, getIntJavaFact.apply(Win64.C_POINTER), Win64.C_POINTER },
{ sysvVaListFactory, getIntJavaFact.apply(SysV.C_POINTER), SysV.C_POINTER },
{ linuxAArch64VaListFactory, getIntJavaFact.apply(AArch64.C_POINTER), AArch64.C_POINTER },
{ macAArch64VaListFactory, getIntJavaFact.apply(AArch64.C_POINTER), AArch64.C_POINTER },
{ platformVaListFactory, getIntNative, C_POINTER },
};
}
@ -247,10 +257,11 @@ public class VaListTest extends NativeTestHelper {
pointLayout, VH_Point_x, VH_Point_y };
};
return new Object[][]{
argsFact.apply(winVaListFactory, Win64.C_INT, sumStructJavaFact),
argsFact.apply(sysvVaListFactory, SysV.C_INT, sumStructJavaFact),
argsFact.apply(aarch64VaListFactory, AArch64.C_INT, sumStructJavaFact),
argsFact.apply(platformVaListFactory, C_INT, sumStructNativeFact),
argsFact.apply(winVaListFactory, Win64.C_INT, sumStructJavaFact),
argsFact.apply(sysvVaListFactory, SysV.C_INT, sumStructJavaFact),
argsFact.apply(linuxAArch64VaListFactory, AArch64.C_INT, sumStructJavaFact),
argsFact.apply(macAArch64VaListFactory, AArch64.C_INT, sumStructJavaFact),
argsFact.apply(platformVaListFactory, C_INT, sumStructNativeFact),
};
}
@ -299,10 +310,11 @@ public class VaListTest extends NativeTestHelper {
BigPoint_LAYOUT, VH_BigPoint_x, VH_BigPoint_y };
};
return new Object[][]{
argsFact.apply(winVaListFactory, Win64.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(sysvVaListFactory, SysV.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(aarch64VaListFactory, AArch64.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(platformVaListFactory, C_LONG_LONG, sumStructNativeFact),
argsFact.apply(winVaListFactory, Win64.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(sysvVaListFactory, SysV.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(linuxAArch64VaListFactory, AArch64.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(macAArch64VaListFactory, AArch64.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(platformVaListFactory, C_LONG_LONG, sumStructNativeFact),
};
}
@ -351,10 +363,11 @@ public class VaListTest extends NativeTestHelper {
FloatPoint_LAYOUT, VH_FloatPoint_x, VH_FloatPoint_y };
};
return new Object[][]{
argsFact.apply(winVaListFactory, Win64.C_FLOAT, sumStructJavaFact),
argsFact.apply(sysvVaListFactory, SysV.C_FLOAT, sumStructJavaFact),
argsFact.apply(aarch64VaListFactory, AArch64.C_FLOAT, sumStructJavaFact),
argsFact.apply(platformVaListFactory, C_FLOAT, sumStructNativeFact),
argsFact.apply(winVaListFactory, Win64.C_FLOAT, sumStructJavaFact),
argsFact.apply(sysvVaListFactory, SysV.C_FLOAT, sumStructJavaFact),
argsFact.apply(linuxAArch64VaListFactory, AArch64.C_FLOAT, sumStructJavaFact),
argsFact.apply(macAArch64VaListFactory, AArch64.C_FLOAT, sumStructJavaFact),
argsFact.apply(platformVaListFactory, C_FLOAT, sumStructNativeFact),
};
}
@ -412,10 +425,11 @@ public class VaListTest extends NativeTestHelper {
HugePoint_LAYOUT, VH_HugePoint_x, VH_HugePoint_y, VH_HugePoint_z };
};
return new Object[][]{
argsFact.apply(winVaListFactory, Win64.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(sysvVaListFactory, SysV.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(aarch64VaListFactory, AArch64.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(platformVaListFactory, C_LONG_LONG, sumStructNativeFact),
argsFact.apply(winVaListFactory, Win64.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(sysvVaListFactory, SysV.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(linuxAArch64VaListFactory, AArch64.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(macAArch64VaListFactory, AArch64.C_LONG_LONG, sumStructJavaFact),
argsFact.apply(platformVaListFactory, C_LONG_LONG, sumStructNativeFact),
};
}
@ -466,10 +480,11 @@ public class VaListTest extends NativeTestHelper {
}
};
return new Object[][]{
{ winVaListFactory, sumStackJavaFact.apply(Win64.C_LONG_LONG, Win64.C_DOUBLE), Win64.C_LONG_LONG, Win64.C_DOUBLE },
{ sysvVaListFactory, sumStackJavaFact.apply(SysV.C_LONG_LONG, SysV.C_DOUBLE), SysV.C_LONG_LONG, SysV.C_DOUBLE },
{ aarch64VaListFactory, sumStackJavaFact.apply(AArch64.C_LONG_LONG, AArch64.C_DOUBLE), AArch64.C_LONG_LONG, AArch64.C_DOUBLE },
{ platformVaListFactory, sumStackNative, C_LONG_LONG, C_DOUBLE },
{ winVaListFactory, sumStackJavaFact.apply(Win64.C_LONG_LONG, Win64.C_DOUBLE), Win64.C_LONG_LONG, Win64.C_DOUBLE },
{ sysvVaListFactory, sumStackJavaFact.apply(SysV.C_LONG_LONG, SysV.C_DOUBLE), SysV.C_LONG_LONG, SysV.C_DOUBLE },
{ linuxAArch64VaListFactory, sumStackJavaFact.apply(AArch64.C_LONG_LONG, AArch64.C_DOUBLE), AArch64.C_LONG_LONG, AArch64.C_DOUBLE },
{ macAArch64VaListFactory, sumStackJavaFact.apply(AArch64.C_LONG_LONG, AArch64.C_DOUBLE), AArch64.C_LONG_LONG, AArch64.C_DOUBLE },
{ platformVaListFactory, sumStackNative, C_LONG_LONG, C_DOUBLE },
};
}
@ -519,12 +534,14 @@ public class VaListTest extends NativeTestHelper {
@DataProvider
public Object[][] emptyVaLists() {
return new Object[][] {
{ Windowsx64Linker.emptyVaList() },
{ winVaListFactory.apply(b -> {}) },
{ SysVx64Linker.emptyVaList() },
{ sysvVaListFactory.apply(b -> {}) },
{ AArch64Linker.emptyVaList() },
{ aarch64VaListFactory.apply(b -> {}) },
{ Windowsx64Linker.emptyVaList() },
{ winVaListFactory.apply(b -> {}) },
{ SysVx64Linker.emptyVaList() },
{ sysvVaListFactory.apply(b -> {}) },
{ LinuxAArch64Linker.emptyVaList() },
{ linuxAArch64VaListFactory.apply(b -> {}) },
{ MacOsAArch64Linker.emptyVaList() },
{ macAArch64VaListFactory.apply(b -> {}) },
};
}
@ -543,10 +560,11 @@ public class VaListTest extends NativeTestHelper {
BiFunction<Integer, VaList, Integer> sumIntsNative
= MethodHandleProxies.asInterfaceInstance(BiFunction.class, MH_sumInts);
return new Object[][]{
{ winVaListScopedFactory, sumIntsJavaFact.apply(Win64.C_INT), Win64.C_INT },
{ sysvVaListScopedFactory, sumIntsJavaFact.apply(SysV.C_INT), SysV.C_INT },
{ aarch64VaListScopedFactory, sumIntsJavaFact.apply(AArch64.C_INT), AArch64.C_INT },
{ platformVaListScopedFactory, sumIntsNative, C_INT },
{ winVaListScopedFactory, sumIntsJavaFact.apply(Win64.C_INT), Win64.C_INT },
{ sysvVaListScopedFactory, sumIntsJavaFact.apply(SysV.C_INT), SysV.C_INT },
{ linuxAArch64VaListScopedFactory, sumIntsJavaFact.apply(AArch64.C_INT), AArch64.C_INT },
{ macAArch64VaListScopedFactory, sumIntsJavaFact.apply(AArch64.C_INT), AArch64.C_INT },
{ platformVaListScopedFactory, sumIntsNative, C_INT },
};
}
@ -591,9 +609,10 @@ public class VaListTest extends NativeTestHelper {
@DataProvider
public Object[][] copy() {
return new Object[][] {
{ winVaListFactory, Win64.C_INT },
{ sysvVaListFactory, SysV.C_INT },
{ aarch64VaListFactory, AArch64.C_INT },
{ winVaListFactory, Win64.C_INT },
{ sysvVaListFactory, SysV.C_INT },
{ linuxAArch64VaListFactory, AArch64.C_INT },
{ macAArch64VaListFactory, AArch64.C_INT },
};
}
@ -678,6 +697,17 @@ public class VaListTest extends NativeTestHelper {
assertEquals((long) VH_BigPoint_x.get(struct), 8);
assertEquals((long) VH_BigPoint_y.get(struct), 16);
})},
{ linkVaListCB("upcallBigStructPlusScalar"), VaListConsumer.mh(vaList -> {
MemorySegment struct = vaList.vargAsSegment(BigPoint_LAYOUT, ResourceScope.newImplicitScope());
assertEquals((long) VH_BigPoint_x.get(struct), 8);
assertEquals((long) VH_BigPoint_y.get(struct), 16);
assertEquals(vaList.vargAsLong(C_LONG_LONG), 42);
})},
{ linkVaListCB("upcallBigStructPlusScalar"), VaListConsumer.mh(vaList -> {
vaList.skip(BigPoint_LAYOUT);
assertEquals(vaList.vargAsLong(C_LONG_LONG), 42);
})},
{ linkVaListCB("upcallStruct"), VaListConsumer.mh(vaList -> {
MemorySegment struct = vaList.vargAsSegment(Point_LAYOUT, ResourceScope.newImplicitScope());
assertEquals((int) VH_Point_x.get(struct), 5);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, 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
@ -172,6 +172,13 @@ EXPORT void upcallBigStruct(CB cb) {
passToUpcall(cb, 1, point);
}
EXPORT void upcallBigStructPlusScalar(CB cb) {
BigPoint point;
point.x = 8;
point.y = 16;
passToUpcall(cb, 2, point, 42);
}
EXPORT void upcallHugeStruct(CB cb) {
HugePoint point;
point.x = 1;