8287158: Explicitly reject unsupported call shapes on macos-aarch64 in mainline
Reviewed-by: mcimadamore, ngasson
This commit is contained in:
parent
0a82c4ebc3
commit
8f0eb5d401
src/java.base/share/classes/jdk/internal/foreign/abi/aarch64
test/jdk
@ -110,9 +110,14 @@ public abstract class CallArranger {
|
||||
* Are variadic arguments assigned to registers as in the standard calling
|
||||
* convention, or always passed on the stack?
|
||||
*
|
||||
* @returns true if variadic arguments should be spilled to the stack.
|
||||
* @return true if variadic arguments should be spilled to the stack.
|
||||
*/
|
||||
protected abstract boolean varArgsOnStack();
|
||||
|
||||
/**
|
||||
* {@return true if this ABI requires sub-slot (smaller than STACK_SLOT_SIZE) packing of arguments on the stack.}
|
||||
*/
|
||||
protected abstract boolean varArgsOnStack();
|
||||
protected abstract boolean requiresSubSlotStackPacking();
|
||||
|
||||
protected CallArranger() {}
|
||||
|
||||
@ -173,8 +178,9 @@ public abstract class CallArranger {
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
static class StorageCalculator {
|
||||
class StorageCalculator {
|
||||
private final boolean forArguments;
|
||||
private boolean forVarArgs = false;
|
||||
|
||||
private final int[] nRegs = new int[] { 0, 0 };
|
||||
private long stackOffset = 0;
|
||||
@ -185,8 +191,21 @@ public abstract class CallArranger {
|
||||
|
||||
VMStorage stackAlloc(long size, long alignment) {
|
||||
assert forArguments : "no stack returns";
|
||||
alignment = Math.max(alignment, STACK_SLOT_SIZE);
|
||||
stackOffset = Utils.alignUp(stackOffset, alignment);
|
||||
// Implementation limit: each arg must take up at least an 8 byte stack slot (on the Java side)
|
||||
// There is currently no way to address stack offsets that are not multiples of 8 bytes
|
||||
// The VM can only address multiple-of-4-bytes offsets, which is also not good enough for some ABIs
|
||||
// see JDK-8283462 and related issues
|
||||
long stackSlotAlignment = Math.max(alignment, STACK_SLOT_SIZE);
|
||||
long alignedStackOffset = Utils.alignUp(stackOffset, stackSlotAlignment);
|
||||
// macos-aarch64 ABI potentially requires addressing stack offsets that are not multiples of 8 bytes
|
||||
// Reject such call types here, to prevent undefined behavior down the line
|
||||
// Reject if the above stack-slot-aligned offset does not match the offset the ABI really wants
|
||||
// Except for variadic arguments, which _are_ passed at 8-byte-aligned offsets
|
||||
if (requiresSubSlotStackPacking() && alignedStackOffset != Utils.alignUp(stackOffset, alignment)
|
||||
&& !forVarArgs) // varargs are given a pass on all aarch64 ABIs
|
||||
throw new UnsupportedOperationException("Call type not supported on this platform");
|
||||
|
||||
stackOffset = alignedStackOffset;
|
||||
|
||||
VMStorage storage =
|
||||
stackStorage((int)(stackOffset / STACK_SLOT_SIZE));
|
||||
@ -233,10 +252,11 @@ public abstract class CallArranger {
|
||||
// no further arguments are allocated to registers.
|
||||
nRegs[StorageClasses.INTEGER] = MAX_REGISTER_ARGUMENTS;
|
||||
nRegs[StorageClasses.VECTOR] = MAX_REGISTER_ARGUMENTS;
|
||||
forVarArgs = true;
|
||||
}
|
||||
}
|
||||
|
||||
abstract static class BindingCalculator {
|
||||
abstract class BindingCalculator {
|
||||
protected final StorageCalculator storageCalculator;
|
||||
|
||||
protected BindingCalculator(boolean forArguments) {
|
||||
@ -288,7 +308,7 @@ public abstract class CallArranger {
|
||||
abstract List<Binding> getIndirectBindings();
|
||||
}
|
||||
|
||||
static class UnboxBindingCalculator extends BindingCalculator {
|
||||
class UnboxBindingCalculator extends BindingCalculator {
|
||||
UnboxBindingCalculator(boolean forArguments) {
|
||||
super(forArguments);
|
||||
}
|
||||
@ -389,7 +409,7 @@ public abstract class CallArranger {
|
||||
}
|
||||
}
|
||||
|
||||
static class BoxBindingCalculator extends BindingCalculator{
|
||||
class BoxBindingCalculator extends BindingCalculator {
|
||||
BoxBindingCalculator(boolean forArguments) {
|
||||
super(forArguments);
|
||||
}
|
||||
|
@ -38,4 +38,9 @@ public class LinuxAArch64CallArranger extends CallArranger {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requiresSubSlotStackPacking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -38,4 +38,9 @@ public class MacOsAArch64CallArranger extends CallArranger {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requiresSubSlotStackPacking() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -486,6 +486,7 @@ java/beans/XMLEncoder/Test6570354.java 8015593 macosx-all
|
||||
# jdk_foreign
|
||||
|
||||
java/foreign/TestUpcallStack.java 8275584 macosx-aarch64
|
||||
java/foreign/TestDowncallStack.java 8275584 macosx-aarch64
|
||||
|
||||
############################################################################
|
||||
|
||||
|
@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @enablePreview
|
||||
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
|
||||
* @build NativeTestHelper CallGeneratorHelper TestDowncall
|
||||
*
|
||||
* @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
|
||||
* --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17
|
||||
* TestDowncall
|
||||
*
|
||||
* @run testng/othervm -Xint -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
|
||||
* --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=100000
|
||||
* TestDowncall
|
||||
*/
|
||||
|
||||
import java.lang.foreign.Addressable;
|
||||
import java.lang.foreign.Linker;
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
import java.lang.foreign.GroupLayout;
|
||||
import java.lang.foreign.MemoryLayout;
|
||||
|
||||
import java.lang.foreign.MemorySession;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.SegmentAllocator;
|
||||
import org.testng.annotations.*;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class TestDowncall extends CallGeneratorHelper {
|
||||
|
||||
static Linker abi = Linker.nativeLinker();
|
||||
static {
|
||||
System.loadLibrary("TestDowncall");
|
||||
System.loadLibrary("TestDowncallStack");
|
||||
}
|
||||
|
||||
@Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
|
||||
public void testDowncall(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
|
||||
List<Consumer<Object>> checks = new ArrayList<>();
|
||||
Addressable addr = findNativeOrThrow(fName);
|
||||
FunctionDescriptor descriptor = function(ret, paramTypes, fields);
|
||||
Object[] args = makeArgs(paramTypes, fields, checks);
|
||||
try (MemorySession session = MemorySession.openShared()) {
|
||||
boolean needsScope = descriptor.returnLayout().map(GroupLayout.class::isInstance).orElse(false);
|
||||
SegmentAllocator allocator = needsScope ?
|
||||
SegmentAllocator.newNativeArena(session) :
|
||||
THROWING_ALLOCATOR;
|
||||
Object res = doCall(addr, allocator, descriptor, args);
|
||||
if (ret == Ret.NON_VOID) {
|
||||
checks.forEach(c -> c.accept(res));
|
||||
if (needsScope) {
|
||||
// check that return struct has indeed been allocated in the native scope
|
||||
assertEquals(((MemorySegment)res).session(), session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
|
||||
public void testDowncallStack(int count, String fName, Ret ret, List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
|
||||
List<Consumer<Object>> checks = new ArrayList<>();
|
||||
Addressable addr = findNativeOrThrow("s" + fName);
|
||||
FunctionDescriptor descriptor = functionStack(ret, paramTypes, fields);
|
||||
Object[] args = makeArgsStack(paramTypes, fields, checks);
|
||||
try (MemorySession session = MemorySession.openShared()) {
|
||||
boolean needsScope = descriptor.returnLayout().map(GroupLayout.class::isInstance).orElse(false);
|
||||
SegmentAllocator allocator = needsScope ?
|
||||
SegmentAllocator.newNativeArena(session) :
|
||||
THROWING_ALLOCATOR;
|
||||
Object res = doCall(addr, allocator, descriptor, args);
|
||||
if (ret == Ret.NON_VOID) {
|
||||
checks.forEach(c -> c.accept(res));
|
||||
if (needsScope) {
|
||||
// check that return struct has indeed been allocated in the native scope
|
||||
assertEquals(((MemorySegment)res).session(), session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object doCall(Addressable symbol, SegmentAllocator allocator, FunctionDescriptor descriptor, Object[] args) throws Throwable {
|
||||
MethodHandle mh = downcallHandle(abi, symbol, allocator, descriptor);
|
||||
Object res = mh.invokeWithArguments(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
static FunctionDescriptor functionStack(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
|
||||
return function(ret, params, fields, STACK_PREFIX_LAYOUTS);
|
||||
}
|
||||
|
||||
static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
|
||||
return function(ret, params, fields, List.of());
|
||||
}
|
||||
|
||||
static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields, List<MemoryLayout> prefix) {
|
||||
List<MemoryLayout> pLayouts = params.stream().map(p -> p.layout(fields)).toList();
|
||||
MemoryLayout[] paramLayouts = Stream.concat(prefix.stream(), pLayouts.stream()).toArray(MemoryLayout[]::new);
|
||||
return ret == Ret.VOID ?
|
||||
FunctionDescriptor.ofVoid(paramLayouts) :
|
||||
FunctionDescriptor.of(paramLayouts[prefix.size()], paramLayouts);
|
||||
}
|
||||
|
||||
static Object[] makeArgsStack(List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks) throws ReflectiveOperationException {
|
||||
return makeArgs(params, fields, checks, STACK_PREFIX_LAYOUTS);
|
||||
}
|
||||
|
||||
static Object[] makeArgs(List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks) throws ReflectiveOperationException {
|
||||
return makeArgs(params, fields, checks, List.of());
|
||||
}
|
||||
|
||||
static Object[] makeArgs(List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<MemoryLayout> prefix) throws ReflectiveOperationException {
|
||||
Object[] args = new Object[prefix.size() + params.size()];
|
||||
int argNum = 0;
|
||||
for (MemoryLayout layout : prefix) {
|
||||
args[argNum++] = makeArg(layout, null, false);
|
||||
}
|
||||
for (int i = 0 ; i < params.size() ; i++) {
|
||||
args[argNum++] = makeArg(params.get(i).layout(fields), checks, i == 0);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
64
test/jdk/java/foreign/TestDowncallBase.java
Normal file
64
test/jdk/java/foreign/TestDowncallBase.java
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.lang.foreign.Addressable;
|
||||
import java.lang.foreign.Linker;
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
import java.lang.foreign.MemoryLayout;
|
||||
import java.lang.foreign.SegmentAllocator;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TestDowncallBase extends CallGeneratorHelper {
|
||||
|
||||
static Linker LINKER = Linker.nativeLinker();
|
||||
|
||||
Object doCall(Addressable symbol, SegmentAllocator allocator, FunctionDescriptor descriptor, Object[] args) throws Throwable {
|
||||
MethodHandle mh = downcallHandle(LINKER, symbol, allocator, descriptor);
|
||||
Object res = mh.invokeWithArguments(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields, List<MemoryLayout> prefix) {
|
||||
List<MemoryLayout> pLayouts = params.stream().map(p -> p.layout(fields)).toList();
|
||||
MemoryLayout[] paramLayouts = Stream.concat(prefix.stream(), pLayouts.stream()).toArray(MemoryLayout[]::new);
|
||||
return ret == Ret.VOID ?
|
||||
FunctionDescriptor.ofVoid(paramLayouts) :
|
||||
FunctionDescriptor.of(paramLayouts[prefix.size()], paramLayouts);
|
||||
}
|
||||
|
||||
static Object[] makeArgs(List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks, List<MemoryLayout> prefix) throws ReflectiveOperationException {
|
||||
Object[] args = new Object[prefix.size() + params.size()];
|
||||
int argNum = 0;
|
||||
for (MemoryLayout layout : prefix) {
|
||||
args[argNum++] = makeArg(layout, null, false);
|
||||
}
|
||||
for (int i = 0 ; i < params.size() ; i++) {
|
||||
args[argNum++] = makeArg(params.get(i).layout(fields), checks, i == 0);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
91
test/jdk/java/foreign/TestDowncallScope.java
Normal file
91
test/jdk/java/foreign/TestDowncallScope.java
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @enablePreview
|
||||
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
|
||||
* @build NativeTestHelper CallGeneratorHelper TestDowncallBase
|
||||
*
|
||||
* @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
|
||||
* --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17
|
||||
* TestDowncallScope
|
||||
*
|
||||
* @run testng/othervm -Xint -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
|
||||
* --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=100000
|
||||
* TestDowncallScope
|
||||
*/
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.foreign.Addressable;
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
import java.lang.foreign.GroupLayout;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.MemorySession;
|
||||
import java.lang.foreign.SegmentAllocator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
public class TestDowncallScope extends TestDowncallBase {
|
||||
|
||||
static {
|
||||
System.loadLibrary("TestDowncall");
|
||||
}
|
||||
|
||||
@Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
|
||||
public void testDowncall(int count, String fName, CallGeneratorHelper.Ret ret,
|
||||
List<CallGeneratorHelper.ParamType> paramTypes,
|
||||
List<CallGeneratorHelper.StructFieldType> fields) throws Throwable {
|
||||
List<Consumer<Object>> checks = new ArrayList<>();
|
||||
Addressable addr = findNativeOrThrow(fName);
|
||||
FunctionDescriptor descriptor = function(ret, paramTypes, fields);
|
||||
Object[] args = makeArgs(paramTypes, fields, checks);
|
||||
try (MemorySession session = MemorySession.openShared()) {
|
||||
boolean needsScope = descriptor.returnLayout().map(GroupLayout.class::isInstance).orElse(false);
|
||||
SegmentAllocator allocator = needsScope ?
|
||||
SegmentAllocator.newNativeArena(session) :
|
||||
THROWING_ALLOCATOR;
|
||||
Object res = doCall(addr, allocator, descriptor, args);
|
||||
if (ret == CallGeneratorHelper.Ret.NON_VOID) {
|
||||
checks.forEach(c -> c.accept(res));
|
||||
if (needsScope) {
|
||||
// check that return struct has indeed been allocated in the native scope
|
||||
assertEquals(((MemorySegment)res).session(), session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static FunctionDescriptor function(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
|
||||
return function(ret, params, fields, List.of());
|
||||
}
|
||||
|
||||
static Object[] makeArgs(List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks) throws ReflectiveOperationException {
|
||||
return makeArgs(params, fields, checks, List.of());
|
||||
}
|
||||
|
||||
}
|
87
test/jdk/java/foreign/TestDowncallStack.java
Normal file
87
test/jdk/java/foreign/TestDowncallStack.java
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @enablePreview
|
||||
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
|
||||
* @build NativeTestHelper CallGeneratorHelper TestDowncallBase
|
||||
*
|
||||
* @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
|
||||
* --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17
|
||||
* TestDowncallStack
|
||||
*/
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.foreign.Addressable;
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
import java.lang.foreign.GroupLayout;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.MemorySession;
|
||||
import java.lang.foreign.SegmentAllocator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
public class TestDowncallStack extends TestDowncallBase {
|
||||
|
||||
static {
|
||||
System.loadLibrary("TestDowncallStack");
|
||||
}
|
||||
|
||||
@Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
|
||||
public void testDowncallStack(int count, String fName, CallGeneratorHelper.Ret ret,
|
||||
List<CallGeneratorHelper.ParamType> paramTypes,
|
||||
List<CallGeneratorHelper.StructFieldType> fields) throws Throwable {
|
||||
List<Consumer<Object>> checks = new ArrayList<>();
|
||||
Addressable addr = findNativeOrThrow("s" + fName);
|
||||
FunctionDescriptor descriptor = functionStack(ret, paramTypes, fields);
|
||||
Object[] args = makeArgsStack(paramTypes, fields, checks);
|
||||
try (MemorySession session = MemorySession.openShared()) {
|
||||
boolean needsScope = descriptor.returnLayout().map(GroupLayout.class::isInstance).orElse(false);
|
||||
SegmentAllocator allocator = needsScope ?
|
||||
SegmentAllocator.newNativeArena(session) :
|
||||
THROWING_ALLOCATOR;
|
||||
Object res = doCall(addr, allocator, descriptor, args);
|
||||
if (ret == CallGeneratorHelper.Ret.NON_VOID) {
|
||||
checks.forEach(c -> c.accept(res));
|
||||
if (needsScope) {
|
||||
// check that return struct has indeed been allocated in the native scope
|
||||
assertEquals(((MemorySegment)res).session(), session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static FunctionDescriptor functionStack(Ret ret, List<ParamType> params, List<StructFieldType> fields) {
|
||||
return function(ret, params, fields, STACK_PREFIX_LAYOUTS);
|
||||
}
|
||||
|
||||
static Object[] makeArgsStack(List<ParamType> params, List<StructFieldType> fields, List<Consumer<Object>> checks) throws ReflectiveOperationException {
|
||||
return makeArgs(params, fields, checks, STACK_PREFIX_LAYOUTS);
|
||||
}
|
||||
|
||||
}
|
@ -26,7 +26,7 @@
|
||||
* @test
|
||||
* @enablePreview
|
||||
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
|
||||
* @run testng/othervm --enable-native-access=ALL-UNNAMED TestVarArgs
|
||||
* @run testng/othervm --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17 TestVarArgs
|
||||
*/
|
||||
|
||||
import java.lang.foreign.Addressable;
|
||||
@ -36,50 +36,52 @@ import java.lang.foreign.MemoryAddress;
|
||||
import java.lang.foreign.MemoryLayout;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.MemorySession;
|
||||
import java.lang.foreign.ValueLayout;
|
||||
import org.testng.annotations.DataProvider;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static java.lang.foreign.MemoryLayout.PathElement.*;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
public class TestVarArgs extends NativeTestHelper {
|
||||
|
||||
static final MemoryLayout ML_CallInfo = MemoryLayout.structLayout(
|
||||
C_POINTER.withName("writeback"), // writeback
|
||||
C_POINTER.withName("argIDs")); // arg ids
|
||||
|
||||
static final VarHandle VH_CallInfo_writeback = ML_CallInfo.varHandle(groupElement("writeback"));
|
||||
static final VarHandle VH_CallInfo_argIDs = ML_CallInfo.varHandle(groupElement("argIDs"));
|
||||
public class TestVarArgs extends CallGeneratorHelper {
|
||||
|
||||
static final VarHandle VH_IntArray = C_INT.arrayElementVarHandle();
|
||||
static final MethodHandle MH_CHECK;
|
||||
|
||||
static final Linker abi = Linker.nativeLinker();
|
||||
static final Linker LINKER = Linker.nativeLinker();
|
||||
static {
|
||||
System.loadLibrary("VarArgs");
|
||||
try {
|
||||
MH_CHECK = MethodHandles.lookup().findStatic(TestVarArgs.class, "check",
|
||||
MethodType.methodType(void.class, int.class, MemoryAddress.class, List.class));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
static final Addressable VARARGS_ADDR = findNativeOrThrow("varargs");
|
||||
|
||||
static final int WRITEBACK_BYTES_PER_ARG = 8;
|
||||
@Test(dataProvider = "functions")
|
||||
public void testVarArgs(int count, String fName, Ret ret, // ignore this stuff
|
||||
List<ParamType> paramTypes, List<StructFieldType> fields) throws Throwable {
|
||||
List<Arg> args = makeArgs(paramTypes, fields);
|
||||
|
||||
@Test(dataProvider = "args")
|
||||
public void testVarArgs(List<VarArg> args) throws Throwable {
|
||||
try (MemorySession session = MemorySession.openConfined()) {
|
||||
MemorySegment writeBack = MemorySegment.allocateNative(args.size() * WRITEBACK_BYTES_PER_ARG, WRITEBACK_BYTES_PER_ARG, session);
|
||||
MemorySegment callInfo = MemorySegment.allocateNative(ML_CallInfo, session);
|
||||
MethodHandle checker = MethodHandles.insertArguments(MH_CHECK, 2, args);
|
||||
MemorySegment writeBack = LINKER.upcallStub(checker, FunctionDescriptor.ofVoid(C_INT, C_POINTER), session);
|
||||
MemorySegment callInfo = MemorySegment.allocateNative(CallInfo.LAYOUT, session);
|
||||
MemorySegment argIDs = MemorySegment.allocateNative(MemoryLayout.sequenceLayout(args.size(), C_INT), session);
|
||||
|
||||
MemoryAddress callInfoPtr = callInfo.address();
|
||||
|
||||
VH_CallInfo_writeback.set(callInfo, writeBack.address());
|
||||
VH_CallInfo_argIDs.set(callInfo, argIDs.address());
|
||||
CallInfo.writeback(callInfo, writeBack);
|
||||
CallInfo.argIDs(callInfo, argIDs);
|
||||
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
VH_IntArray.set(argIDs, (long) i, args.get(i).id.ordinal());
|
||||
@ -89,17 +91,10 @@ public class TestVarArgs extends NativeTestHelper {
|
||||
argLayouts.add(C_POINTER); // call info
|
||||
argLayouts.add(C_INT); // size
|
||||
|
||||
FunctionDescriptor desc = FunctionDescriptor.ofVoid(argLayouts.stream().toArray(MemoryLayout[]::new))
|
||||
FunctionDescriptor desc = FunctionDescriptor.ofVoid(argLayouts.toArray(MemoryLayout[]::new))
|
||||
.asVariadic(args.stream().map(a -> a.layout).toArray(MemoryLayout[]::new));
|
||||
|
||||
List<Class<?>> carriers = new ArrayList<>();
|
||||
carriers.add(MemoryAddress.class); // call info
|
||||
carriers.add(int.class); // size
|
||||
args.forEach(a -> carriers.add(a.carrier));
|
||||
|
||||
MethodType mt = MethodType.methodType(void.class, carriers);
|
||||
|
||||
MethodHandle downcallHandle = abi.downcallHandle(VARARGS_ADDR, desc);
|
||||
MethodHandle downcallHandle = LINKER.downcallHandle(VARARGS_ADDR, desc);
|
||||
|
||||
List<Object> argValues = new ArrayList<>();
|
||||
argValues.add(callInfoPtr); // call info
|
||||
@ -108,50 +103,177 @@ public class TestVarArgs extends NativeTestHelper {
|
||||
|
||||
downcallHandle.invokeWithArguments(argValues);
|
||||
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
VarArg a = args.get(i);
|
||||
MemorySegment writtenPtr = writeBack.asSlice(i * WRITEBACK_BYTES_PER_ARG);
|
||||
Object written = a.vh.get(writtenPtr);
|
||||
assertEquals(written, a.value);
|
||||
}
|
||||
// args checked by upcall
|
||||
}
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public static Object[][] args() {
|
||||
return new Object[][] {
|
||||
new Object[] { List.of(VarArg.intArg(5), VarArg.intArg(10), VarArg.intArg(15)) },
|
||||
new Object[] { List.of(VarArg.doubleArg(5), VarArg.doubleArg(10), VarArg.doubleArg(15)) },
|
||||
new Object[] { List.of(VarArg.intArg(5), VarArg.doubleArg(10), VarArg.intArg(15)) },
|
||||
};
|
||||
private static List<Arg> makeArgs(List<ParamType> paramTypes, List<StructFieldType> fields) throws ReflectiveOperationException {
|
||||
List<Arg> args = new ArrayList<>();
|
||||
for (ParamType pType : paramTypes) {
|
||||
MemoryLayout layout = pType.layout(fields);
|
||||
List<Consumer<Object>> checks = new ArrayList<>();
|
||||
Object arg = makeArg(layout, checks, true);
|
||||
Arg.NativeType type = Arg.NativeType.of(pType.type(fields));
|
||||
args.add(pType == ParamType.STRUCT
|
||||
? Arg.structArg(type, layout, arg, checks)
|
||||
: Arg.primitiveArg(type, layout, arg, checks));
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
private static final class VarArg {
|
||||
private static void check(int index, MemoryAddress ptr, List<Arg> args) {
|
||||
Arg varArg = args.get(index);
|
||||
MemoryLayout layout = varArg.layout;
|
||||
MethodHandle getter = varArg.getter;
|
||||
List<Consumer<Object>> checks = varArg.checks;
|
||||
try (MemorySession session = MemorySession.openConfined()) {
|
||||
MemorySegment seg = MemorySegment.ofAddress(ptr, layout.byteSize(), session);
|
||||
Object obj = getter.invoke(seg);
|
||||
checks.forEach(check -> check.accept(obj));
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CallInfo {
|
||||
static final MemoryLayout LAYOUT = MemoryLayout.structLayout(
|
||||
C_POINTER.withName("writeback"), // writeback
|
||||
C_POINTER.withName("argIDs")); // arg ids
|
||||
|
||||
static final VarHandle VH_writeback = LAYOUT.varHandle(groupElement("writeback"));
|
||||
static final VarHandle VH_argIDs = LAYOUT.varHandle(groupElement("argIDs"));
|
||||
|
||||
static void writeback(MemorySegment seg, Addressable addr) {
|
||||
VH_writeback.set(seg, addr.address());
|
||||
}
|
||||
static void argIDs(MemorySegment seg, Addressable addr) {
|
||||
VH_argIDs.set(seg, addr.address());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Arg {
|
||||
final NativeType id;
|
||||
final MemoryLayout layout;
|
||||
final Object value;
|
||||
final ValueLayout layout;
|
||||
final Class<?> carrier;
|
||||
final VarHandle vh;
|
||||
final MethodHandle getter;
|
||||
final List<Consumer<Object>> checks;
|
||||
|
||||
private VarArg(NativeType id, ValueLayout layout, Class<?> carrier, Object value) {
|
||||
private Arg(NativeType id, MemoryLayout layout, Object value, MethodHandle getter, List<Consumer<Object>> checks) {
|
||||
this.id = id;
|
||||
this.value = value;
|
||||
this.layout = layout;
|
||||
this.carrier = carrier;
|
||||
this.vh = layout.varHandle();
|
||||
this.value = value;
|
||||
this.getter = getter;
|
||||
this.checks = checks;
|
||||
}
|
||||
|
||||
static VarArg intArg(int value) {
|
||||
return new VarArg(VarArg.NativeType.INT, C_INT, int.class, value);
|
||||
private static Arg primitiveArg(NativeType id, MemoryLayout layout, Object value, List<Consumer<Object>> checks) {
|
||||
return new Arg(id, layout, value, layout.varHandle().toMethodHandle(VarHandle.AccessMode.GET), checks);
|
||||
}
|
||||
|
||||
static VarArg doubleArg(double value) {
|
||||
return new VarArg(VarArg.NativeType.DOUBLE, C_DOUBLE, double.class, value);
|
||||
private static Arg structArg(NativeType id, MemoryLayout layout, Object value, List<Consumer<Object>> checks) {
|
||||
return new Arg(id, layout, value, MethodHandles.identity(MemorySegment.class), checks);
|
||||
}
|
||||
|
||||
enum NativeType {
|
||||
INT,
|
||||
DOUBLE
|
||||
FLOAT,
|
||||
DOUBLE,
|
||||
POINTER,
|
||||
S_I,
|
||||
S_F,
|
||||
S_D,
|
||||
S_P,
|
||||
S_II,
|
||||
S_IF,
|
||||
S_ID,
|
||||
S_IP,
|
||||
S_FI,
|
||||
S_FF,
|
||||
S_FD,
|
||||
S_FP,
|
||||
S_DI,
|
||||
S_DF,
|
||||
S_DD,
|
||||
S_DP,
|
||||
S_PI,
|
||||
S_PF,
|
||||
S_PD,
|
||||
S_PP,
|
||||
S_III,
|
||||
S_IIF,
|
||||
S_IID,
|
||||
S_IIP,
|
||||
S_IFI,
|
||||
S_IFF,
|
||||
S_IFD,
|
||||
S_IFP,
|
||||
S_IDI,
|
||||
S_IDF,
|
||||
S_IDD,
|
||||
S_IDP,
|
||||
S_IPI,
|
||||
S_IPF,
|
||||
S_IPD,
|
||||
S_IPP,
|
||||
S_FII,
|
||||
S_FIF,
|
||||
S_FID,
|
||||
S_FIP,
|
||||
S_FFI,
|
||||
S_FFF,
|
||||
S_FFD,
|
||||
S_FFP,
|
||||
S_FDI,
|
||||
S_FDF,
|
||||
S_FDD,
|
||||
S_FDP,
|
||||
S_FPI,
|
||||
S_FPF,
|
||||
S_FPD,
|
||||
S_FPP,
|
||||
S_DII,
|
||||
S_DIF,
|
||||
S_DID,
|
||||
S_DIP,
|
||||
S_DFI,
|
||||
S_DFF,
|
||||
S_DFD,
|
||||
S_DFP,
|
||||
S_DDI,
|
||||
S_DDF,
|
||||
S_DDD,
|
||||
S_DDP,
|
||||
S_DPI,
|
||||
S_DPF,
|
||||
S_DPD,
|
||||
S_DPP,
|
||||
S_PII,
|
||||
S_PIF,
|
||||
S_PID,
|
||||
S_PIP,
|
||||
S_PFI,
|
||||
S_PFF,
|
||||
S_PFD,
|
||||
S_PFP,
|
||||
S_PDI,
|
||||
S_PDF,
|
||||
S_PDD,
|
||||
S_PDP,
|
||||
S_PPI,
|
||||
S_PPF,
|
||||
S_PPD,
|
||||
S_PPP,
|
||||
;
|
||||
|
||||
public static NativeType of(String type) {
|
||||
return NativeType.valueOf(switch (type) {
|
||||
case "int" -> "INT";
|
||||
case "float" -> "FLOAT";
|
||||
case "double" -> "DOUBLE";
|
||||
case "void*" -> "POINTER";
|
||||
default -> type.substring("struct ".length());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,14 +23,7 @@
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "libTestUpcall.h"
|
||||
#ifdef __clang__
|
||||
#pragma clang optimize off
|
||||
#elif defined __GNUC__
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined _MSC_BUILD
|
||||
#pragma optimize( "", off )
|
||||
#endif
|
||||
#include "shared.h"
|
||||
|
||||
template<typename CB>
|
||||
void launch_v(CB cb) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, 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
|
||||
@ -21,14 +21,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "libTestDowncall.h"
|
||||
#ifdef __clang__
|
||||
#pragma clang optimize off
|
||||
#elif defined __GNUC__
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined _MSC_BUILD
|
||||
#pragma optimize( "", off )
|
||||
#endif
|
||||
#include "shared.h"
|
||||
|
||||
EXPORT void f0_V__(void) { }
|
||||
EXPORT void f0_V_I_(int p0) { }
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@ -20,14 +20,7 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
#include "libTestDowncall.h"
|
||||
#ifdef __clang__
|
||||
#pragma clang optimize off
|
||||
#elif defined __GNUC__
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined _MSC_BUILD
|
||||
#pragma optimize("", off )
|
||||
#endif
|
||||
#include "shared.h"
|
||||
|
||||
EXPORT void sf0_V__(long long pf0, long long pf1, long long pf2, long long pf3, long long pf4, long long pf5, long long pf6, long long pf7, double pf8, double pf9, double pf10, double pf11, double pf12, double pf13, double pf14, double pf15) { }
|
||||
EXPORT void sf0_V_I_(long long pf0, long long pf1, long long pf2, long long pf3, long long pf4, long long pf5, long long pf6, long long pf7, double pf8, double pf9, double pf10, double pf11, double pf12, double pf13, double pf14, double pf15,int p0) { }
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, 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
|
||||
@ -21,14 +21,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "libTestUpcall.h"
|
||||
#ifdef __clang__
|
||||
#pragma clang optimize off
|
||||
#elif defined __GNUC__
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined _MSC_BUILD
|
||||
#pragma optimize( "", off )
|
||||
#endif
|
||||
#include "shared.h"
|
||||
|
||||
EXPORT void f0_V__( void (*cb)(void)) { cb(); }
|
||||
EXPORT void f0_V_I_(int p0, void (*cb)(int)) { cb(p0); }
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@ -21,14 +21,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "libTestUpcall.h"
|
||||
#ifdef __clang__
|
||||
#pragma clang optimize off
|
||||
#elif defined __GNUC__
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined _MSC_BUILD
|
||||
#pragma optimize( "", off )
|
||||
#endif
|
||||
#include "shared.h"
|
||||
|
||||
EXPORT void sf0_V__(long long pf0, long long pf1, long long pf2, long long pf3, long long pf4, long long pf5, long long pf6, long long pf7, double pf8, double pf9, double pf10, double pf11, double pf12, double pf13, double pf14, double pf15, void (*cb)(long long, long long, long long, long long, long long, long long, long long, long long, double, double, double, double, double, double, double, double)) { cb(pf0, pf1, pf2, pf3, pf4, pf5, pf6, pf7, pf8, pf9, pf10, pf11, pf12, pf13, pf14, pf15); }
|
||||
EXPORT void sf0_V_I_(long long pf0, long long pf1, long long pf2, long long pf3, long long pf4, long long pf5, long long pf6, long long pf7, double pf8, double pf9, double pf10, double pf11, double pf12, double pf13, double pf14, double pf15, int p0, void (*cb)(long long, long long, long long, long long, long long, long long, long long, long long, double, double, double, double, double, double, double, double, int)) { cb(pf0, pf1, pf2, pf3, pf4, pf5, pf6, pf7, pf8, pf9, pf10, pf11, pf12, pf13, pf14, pf15, p0); }
|
||||
|
@ -23,35 +23,211 @@
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN64
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
#include "shared.h"
|
||||
|
||||
typedef void (*writeback_t)(int,void*);
|
||||
|
||||
typedef struct {
|
||||
unsigned char* writeback;
|
||||
writeback_t writeback;
|
||||
int* argids;
|
||||
} call_info;
|
||||
|
||||
#define WRITEBACK_BYTES_PER_ARG 8
|
||||
#define write_back_ptr(type) ((type*)(info->writeback + (i * WRITEBACK_BYTES_PER_ARG)))
|
||||
#define CASE(num, type) case num: { \
|
||||
type x = va_arg(a_list, type); \
|
||||
writeback(i, &x); \
|
||||
} break;
|
||||
|
||||
enum NativeType {
|
||||
T_INT,
|
||||
T_FLOAT,
|
||||
T_DOUBLE,
|
||||
T_POINTER,
|
||||
T_S_I,
|
||||
T_S_F,
|
||||
T_S_D,
|
||||
T_S_P,
|
||||
T_S_II,
|
||||
T_S_IF,
|
||||
T_S_ID,
|
||||
T_S_IP,
|
||||
T_S_FI,
|
||||
T_S_FF,
|
||||
T_S_FD,
|
||||
T_S_FP,
|
||||
T_S_DI,
|
||||
T_S_DF,
|
||||
T_S_DD,
|
||||
T_S_DP,
|
||||
T_S_PI,
|
||||
T_S_PF,
|
||||
T_S_PD,
|
||||
T_S_PP,
|
||||
T_S_III,
|
||||
T_S_IIF,
|
||||
T_S_IID,
|
||||
T_S_IIP,
|
||||
T_S_IFI,
|
||||
T_S_IFF,
|
||||
T_S_IFD,
|
||||
T_S_IFP,
|
||||
T_S_IDI,
|
||||
T_S_IDF,
|
||||
T_S_IDD,
|
||||
T_S_IDP,
|
||||
T_S_IPI,
|
||||
T_S_IPF,
|
||||
T_S_IPD,
|
||||
T_S_IPP,
|
||||
T_S_FII,
|
||||
T_S_FIF,
|
||||
T_S_FID,
|
||||
T_S_FIP,
|
||||
T_S_FFI,
|
||||
T_S_FFF,
|
||||
T_S_FFD,
|
||||
T_S_FFP,
|
||||
T_S_FDI,
|
||||
T_S_FDF,
|
||||
T_S_FDD,
|
||||
T_S_FDP,
|
||||
T_S_FPI,
|
||||
T_S_FPF,
|
||||
T_S_FPD,
|
||||
T_S_FPP,
|
||||
T_S_DII,
|
||||
T_S_DIF,
|
||||
T_S_DID,
|
||||
T_S_DIP,
|
||||
T_S_DFI,
|
||||
T_S_DFF,
|
||||
T_S_DFD,
|
||||
T_S_DFP,
|
||||
T_S_DDI,
|
||||
T_S_DDF,
|
||||
T_S_DDD,
|
||||
T_S_DDP,
|
||||
T_S_DPI,
|
||||
T_S_DPF,
|
||||
T_S_DPD,
|
||||
T_S_DPP,
|
||||
T_S_PII,
|
||||
T_S_PIF,
|
||||
T_S_PID,
|
||||
T_S_PIP,
|
||||
T_S_PFI,
|
||||
T_S_PFF,
|
||||
T_S_PFD,
|
||||
T_S_PFP,
|
||||
T_S_PDI,
|
||||
T_S_PDF,
|
||||
T_S_PDD,
|
||||
T_S_PDP,
|
||||
T_S_PPI,
|
||||
T_S_PPF,
|
||||
T_S_PPD,
|
||||
T_S_PPP,
|
||||
};
|
||||
|
||||
// need to pass `num` separately as last argument preceding varargs according to spec (and for MSVC)
|
||||
EXPORT void varargs(call_info* info, int num, ...) {
|
||||
va_list a_list;
|
||||
va_start(a_list, num);
|
||||
writeback_t writeback = info->writeback;
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
int id = info->argids[i];
|
||||
switch (id) {
|
||||
case 0: // int
|
||||
*write_back_ptr(int) = va_arg(a_list, int);
|
||||
break;
|
||||
case 1: // double
|
||||
*write_back_ptr(double) = va_arg(a_list, double);
|
||||
break;
|
||||
CASE(T_INT, int)
|
||||
CASE(T_FLOAT, double) // vararg float is promoted to double per C spec
|
||||
CASE(T_DOUBLE, double)
|
||||
CASE(T_POINTER, void*)
|
||||
CASE(T_S_I, struct S_I)
|
||||
CASE(T_S_F, struct S_F)
|
||||
CASE(T_S_D, struct S_D)
|
||||
CASE(T_S_P, struct S_P)
|
||||
CASE(T_S_II, struct S_II)
|
||||
CASE(T_S_IF, struct S_IF)
|
||||
CASE(T_S_ID, struct S_ID)
|
||||
CASE(T_S_IP, struct S_IP)
|
||||
CASE(T_S_FI, struct S_FI)
|
||||
CASE(T_S_FF, struct S_FF)
|
||||
CASE(T_S_FD, struct S_FD)
|
||||
CASE(T_S_FP, struct S_FP)
|
||||
CASE(T_S_DI, struct S_DI)
|
||||
CASE(T_S_DF, struct S_DF)
|
||||
CASE(T_S_DD, struct S_DD)
|
||||
CASE(T_S_DP, struct S_DP)
|
||||
CASE(T_S_PI, struct S_PI)
|
||||
CASE(T_S_PF, struct S_PF)
|
||||
CASE(T_S_PD, struct S_PD)
|
||||
CASE(T_S_PP, struct S_PP)
|
||||
CASE(T_S_III, struct S_III)
|
||||
CASE(T_S_IIF, struct S_IIF)
|
||||
CASE(T_S_IID, struct S_IID)
|
||||
CASE(T_S_IIP, struct S_IIP)
|
||||
CASE(T_S_IFI, struct S_IFI)
|
||||
CASE(T_S_IFF, struct S_IFF)
|
||||
CASE(T_S_IFD, struct S_IFD)
|
||||
CASE(T_S_IFP, struct S_IFP)
|
||||
CASE(T_S_IDI, struct S_IDI)
|
||||
CASE(T_S_IDF, struct S_IDF)
|
||||
CASE(T_S_IDD, struct S_IDD)
|
||||
CASE(T_S_IDP, struct S_IDP)
|
||||
CASE(T_S_IPI, struct S_IPI)
|
||||
CASE(T_S_IPF, struct S_IPF)
|
||||
CASE(T_S_IPD, struct S_IPD)
|
||||
CASE(T_S_IPP, struct S_IPP)
|
||||
CASE(T_S_FII, struct S_FII)
|
||||
CASE(T_S_FIF, struct S_FIF)
|
||||
CASE(T_S_FID, struct S_FID)
|
||||
CASE(T_S_FIP, struct S_FIP)
|
||||
CASE(T_S_FFI, struct S_FFI)
|
||||
CASE(T_S_FFF, struct S_FFF)
|
||||
CASE(T_S_FFD, struct S_FFD)
|
||||
CASE(T_S_FFP, struct S_FFP)
|
||||
CASE(T_S_FDI, struct S_FDI)
|
||||
CASE(T_S_FDF, struct S_FDF)
|
||||
CASE(T_S_FDD, struct S_FDD)
|
||||
CASE(T_S_FDP, struct S_FDP)
|
||||
CASE(T_S_FPI, struct S_FPI)
|
||||
CASE(T_S_FPF, struct S_FPF)
|
||||
CASE(T_S_FPD, struct S_FPD)
|
||||
CASE(T_S_FPP, struct S_FPP)
|
||||
CASE(T_S_DII, struct S_DII)
|
||||
CASE(T_S_DIF, struct S_DIF)
|
||||
CASE(T_S_DID, struct S_DID)
|
||||
CASE(T_S_DIP, struct S_DIP)
|
||||
CASE(T_S_DFI, struct S_DFI)
|
||||
CASE(T_S_DFF, struct S_DFF)
|
||||
CASE(T_S_DFD, struct S_DFD)
|
||||
CASE(T_S_DFP, struct S_DFP)
|
||||
CASE(T_S_DDI, struct S_DDI)
|
||||
CASE(T_S_DDF, struct S_DDF)
|
||||
CASE(T_S_DDD, struct S_DDD)
|
||||
CASE(T_S_DDP, struct S_DDP)
|
||||
CASE(T_S_DPI, struct S_DPI)
|
||||
CASE(T_S_DPF, struct S_DPF)
|
||||
CASE(T_S_DPD, struct S_DPD)
|
||||
CASE(T_S_DPP, struct S_DPP)
|
||||
CASE(T_S_PII, struct S_PII)
|
||||
CASE(T_S_PIF, struct S_PIF)
|
||||
CASE(T_S_PID, struct S_PID)
|
||||
CASE(T_S_PIP, struct S_PIP)
|
||||
CASE(T_S_PFI, struct S_PFI)
|
||||
CASE(T_S_PFF, struct S_PFF)
|
||||
CASE(T_S_PFD, struct S_PFD)
|
||||
CASE(T_S_PFP, struct S_PFP)
|
||||
CASE(T_S_PDI, struct S_PDI)
|
||||
CASE(T_S_PDF, struct S_PDF)
|
||||
CASE(T_S_PDD, struct S_PDD)
|
||||
CASE(T_S_PDP, struct S_PDP)
|
||||
CASE(T_S_PPI, struct S_PPI)
|
||||
CASE(T_S_PPF, struct S_PPF)
|
||||
CASE(T_S_PPD, struct S_PPD)
|
||||
CASE(T_S_PPP, struct S_PPP)
|
||||
default: exit(-1); // invalid id
|
||||
}
|
||||
}
|
||||
|
||||
|
121
test/jdk/java/foreign/shared.h
Normal file
121
test/jdk/java/foreign/shared.h
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang optimize off
|
||||
#elif defined __GNUC__
|
||||
#pragma GCC optimize ("O0")
|
||||
#elif defined _MSC_BUILD
|
||||
#pragma optimize( "", off )
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
struct S_I { int p0; };
|
||||
struct S_F { float p0; };
|
||||
struct S_D { double p0; };
|
||||
struct S_P { void* p0; };
|
||||
struct S_II { int p0; int p1; };
|
||||
struct S_IF { int p0; float p1; };
|
||||
struct S_ID { int p0; double p1; };
|
||||
struct S_IP { int p0; void* p1; };
|
||||
struct S_FI { float p0; int p1; };
|
||||
struct S_FF { float p0; float p1; };
|
||||
struct S_FD { float p0; double p1; };
|
||||
struct S_FP { float p0; void* p1; };
|
||||
struct S_DI { double p0; int p1; };
|
||||
struct S_DF { double p0; float p1; };
|
||||
struct S_DD { double p0; double p1; };
|
||||
struct S_DP { double p0; void* p1; };
|
||||
struct S_PI { void* p0; int p1; };
|
||||
struct S_PF { void* p0; float p1; };
|
||||
struct S_PD { void* p0; double p1; };
|
||||
struct S_PP { void* p0; void* p1; };
|
||||
struct S_III { int p0; int p1; int p2; };
|
||||
struct S_IIF { int p0; int p1; float p2; };
|
||||
struct S_IID { int p0; int p1; double p2; };
|
||||
struct S_IIP { int p0; int p1; void* p2; };
|
||||
struct S_IFI { int p0; float p1; int p2; };
|
||||
struct S_IFF { int p0; float p1; float p2; };
|
||||
struct S_IFD { int p0; float p1; double p2; };
|
||||
struct S_IFP { int p0; float p1; void* p2; };
|
||||
struct S_IDI { int p0; double p1; int p2; };
|
||||
struct S_IDF { int p0; double p1; float p2; };
|
||||
struct S_IDD { int p0; double p1; double p2; };
|
||||
struct S_IDP { int p0; double p1; void* p2; };
|
||||
struct S_IPI { int p0; void* p1; int p2; };
|
||||
struct S_IPF { int p0; void* p1; float p2; };
|
||||
struct S_IPD { int p0; void* p1; double p2; };
|
||||
struct S_IPP { int p0; void* p1; void* p2; };
|
||||
struct S_FII { float p0; int p1; int p2; };
|
||||
struct S_FIF { float p0; int p1; float p2; };
|
||||
struct S_FID { float p0; int p1; double p2; };
|
||||
struct S_FIP { float p0; int p1; void* p2; };
|
||||
struct S_FFI { float p0; float p1; int p2; };
|
||||
struct S_FFF { float p0; float p1; float p2; };
|
||||
struct S_FFD { float p0; float p1; double p2; };
|
||||
struct S_FFP { float p0; float p1; void* p2; };
|
||||
struct S_FDI { float p0; double p1; int p2; };
|
||||
struct S_FDF { float p0; double p1; float p2; };
|
||||
struct S_FDD { float p0; double p1; double p2; };
|
||||
struct S_FDP { float p0; double p1; void* p2; };
|
||||
struct S_FPI { float p0; void* p1; int p2; };
|
||||
struct S_FPF { float p0; void* p1; float p2; };
|
||||
struct S_FPD { float p0; void* p1; double p2; };
|
||||
struct S_FPP { float p0; void* p1; void* p2; };
|
||||
struct S_DII { double p0; int p1; int p2; };
|
||||
struct S_DIF { double p0; int p1; float p2; };
|
||||
struct S_DID { double p0; int p1; double p2; };
|
||||
struct S_DIP { double p0; int p1; void* p2; };
|
||||
struct S_DFI { double p0; float p1; int p2; };
|
||||
struct S_DFF { double p0; float p1; float p2; };
|
||||
struct S_DFD { double p0; float p1; double p2; };
|
||||
struct S_DFP { double p0; float p1; void* p2; };
|
||||
struct S_DDI { double p0; double p1; int p2; };
|
||||
struct S_DDF { double p0; double p1; float p2; };
|
||||
struct S_DDD { double p0; double p1; double p2; };
|
||||
struct S_DDP { double p0; double p1; void* p2; };
|
||||
struct S_DPI { double p0; void* p1; int p2; };
|
||||
struct S_DPF { double p0; void* p1; float p2; };
|
||||
struct S_DPD { double p0; void* p1; double p2; };
|
||||
struct S_DPP { double p0; void* p1; void* p2; };
|
||||
struct S_PII { void* p0; int p1; int p2; };
|
||||
struct S_PIF { void* p0; int p1; float p2; };
|
||||
struct S_PID { void* p0; int p1; double p2; };
|
||||
struct S_PIP { void* p0; int p1; void* p2; };
|
||||
struct S_PFI { void* p0; float p1; int p2; };
|
||||
struct S_PFF { void* p0; float p1; float p2; };
|
||||
struct S_PFD { void* p0; float p1; double p2; };
|
||||
struct S_PFP { void* p0; float p1; void* p2; };
|
||||
struct S_PDI { void* p0; double p1; int p2; };
|
||||
struct S_PDF { void* p0; double p1; float p2; };
|
||||
struct S_PDD { void* p0; double p1; double p2; };
|
||||
struct S_PDP { void* p0; double p1; void* p2; };
|
||||
struct S_PPI { void* p0; void* p1; int p2; };
|
||||
struct S_PPF { void* p0; void* p1; float p2; };
|
||||
struct S_PPD { void* p0; void* p1; double p2; };
|
||||
struct S_PPP { void* p0; void* p1; void* p2; };
|
Loading…
x
Reference in New Issue
Block a user