8277924: Small tweaks to foreign function and memory API

Reviewed-by: jvernee, psandoz
This commit is contained in:
Maurizio Cimadamore 2021-12-02 11:22:31 +00:00
parent e002bfec8c
commit ea905bd3da
7 changed files with 79 additions and 38 deletions

View File

@ -97,7 +97,7 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
* Obtain a specialized variadic function descriptor, by appending given variadic layouts to this
* function descriptor argument layouts. The resulting function descriptor can report the position
* of the {@linkplain #firstVariadicArgumentIndex() first variadic argument}, and cannot be altered
* in any way: for instance, calling {@link #withReturnLayout(MemoryLayout)} on the resulting descriptor
* in any way: for instance, calling {@link #changeReturnLayout(MemoryLayout)} on the resulting descriptor
* will throw an {@link UnsupportedOperationException}.
* @param variadicLayouts the variadic argument layouts to be appended to this descriptor argument layouts.
* @return a new variadic function descriptor, or this descriptor if {@code variadicLayouts.length == 0}.
@ -123,10 +123,26 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
* @param addedLayouts the argument layouts to append.
* @return the new function descriptor.
*/
public FunctionDescriptor withAppendedArgumentLayouts(MemoryLayout... addedLayouts) {
Objects.requireNonNull(addedLayouts);
Arrays.stream(addedLayouts).forEach(Objects::requireNonNull);
List<MemoryLayout> newLayouts = Stream.concat(argLayouts.stream(), Stream.of(addedLayouts)).toList();
public FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts) {
return insertArgumentLayouts(argLayouts.size(), addedLayouts);
}
/**
* Create a new function descriptor with the given argument layouts inserted at the given index, into the argument
* layout array of this function descriptor.
* @param index the index at which to insert the arguments
* @param addedLayouts the argument layouts to insert at given index.
* @return the new function descriptor.
* @throws IllegalArgumentException if {@code index < 0 || index > argumentLayouts().size()}.
*/
public FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts) {
if (index < 0 || index > argLayouts.size())
throw new IllegalArgumentException("Index out of bounds: " + index);
List<MemoryLayout> added = List.of(addedLayouts); // null check on array and its elements
List<MemoryLayout> newLayouts = new ArrayList<>(argLayouts.size() + addedLayouts.length);
newLayouts.addAll(argLayouts.subList(0, index));
newLayouts.addAll(added);
newLayouts.addAll(argLayouts.subList(index, argLayouts.size()));
return new FunctionDescriptor(resLayout, newLayouts);
}
@ -135,16 +151,17 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
* @param newReturn the new return layout.
* @return the new function descriptor.
*/
public FunctionDescriptor withReturnLayout(MemoryLayout newReturn) {
public FunctionDescriptor changeReturnLayout(MemoryLayout newReturn) {
Objects.requireNonNull(newReturn);
return new FunctionDescriptor(newReturn, argLayouts);
}
/**
* Create a new function descriptor with the return layout dropped.
* Create a new function descriptor with the return layout dropped. This is useful to model functions
* which return no values.
* @return the new function descriptor.
*/
public FunctionDescriptor withVoidReturnLayout() {
public FunctionDescriptor dropReturnLayout() {
return new FunctionDescriptor(null, argLayouts);
}
@ -231,17 +248,22 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
}
@Override
public FunctionDescriptor withAppendedArgumentLayouts(MemoryLayout... addedLayouts) {
public FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts) {
throw new UnsupportedOperationException();
}
@Override
public FunctionDescriptor withReturnLayout(MemoryLayout newReturn) {
public FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts) {
throw new UnsupportedOperationException();
}
@Override
public FunctionDescriptor withVoidReturnLayout() {
public FunctionDescriptor changeReturnLayout(MemoryLayout newReturn) {
throw new UnsupportedOperationException();
}
@Override
public FunctionDescriptor dropReturnLayout() {
throw new UnsupportedOperationException();
}

View File

@ -59,7 +59,7 @@ public class CallingSequenceBuilder {
verifyBindings(true, carrier, bindings);
inputBindings.add(bindings);
mt = mt.appendParameterTypes(carrier);
desc = desc.withAppendedArgumentLayouts(layout);
desc = desc.appendArgumentLayouts(layout);
return this;
}
@ -68,7 +68,7 @@ public class CallingSequenceBuilder {
verifyBindings(false, carrier, bindings);
this.outputBindings = bindings;
mt = mt.changeReturnType(carrier);
desc = desc.withReturnLayout(layout);
desc = desc.changeReturnLayout(layout);
return this;
}

View File

@ -32,10 +32,8 @@ import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.MemoryLayout;
import org.testng.annotations.Test;
import java.lang.constant.Constable;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
@ -67,7 +65,7 @@ public class TestFunctionDescriptor extends NativeTestHelper {
@Test
public void testAppendArgumentLayouts() {
FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG);
fd = fd.withAppendedArgumentLayouts(C_POINTER);
fd = fd.appendArgumentLayouts(C_POINTER);
assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG, C_POINTER));
Optional<MemoryLayout> returnLayoutOp = fd.returnLayout();
@ -78,7 +76,7 @@ public class TestFunctionDescriptor extends NativeTestHelper {
@Test
public void testChangeReturnLayout() {
FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG);
fd = fd.withReturnLayout(C_INT);
fd = fd.changeReturnLayout(C_INT);
assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG));
Optional<MemoryLayout> returnLayoutOp = fd.returnLayout();
@ -89,7 +87,7 @@ public class TestFunctionDescriptor extends NativeTestHelper {
@Test
public void testDropReturnLayout() {
FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_DOUBLE, C_LONG_LONG);
fd = fd.withVoidReturnLayout();
fd = fd.dropReturnLayout();
assertEquals(fd.argumentLayouts(), List.of(C_DOUBLE, C_LONG_LONG));
Optional<MemoryLayout> returnLayoutOp = fd.returnLayout();

View File

@ -40,7 +40,6 @@ import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.SymbolLookup;
@ -127,7 +126,7 @@ public class TestIntrinsics extends NativeTestHelper {
for (int i = 0; i < args.length; i++) {
NativeSymbol ma = LOOKUP.lookup("invoke_high_arity" + i).get();
MethodType mt = baseMT.changeReturnType(baseMT.parameterType(i));
FunctionDescriptor fd = baseFD.withReturnLayout(baseFD.argumentLayouts().get(i));
FunctionDescriptor fd = baseFD.changeReturnLayout(baseFD.argumentLayouts().get(i));
Object expected = args[i];
tests.add(abi.downcallHandle(ma, fd), expected, args);
}

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
@ -22,6 +22,30 @@
*
*/
/*
* @test id=scope
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
* @modules jdk.incubator.foreign/jdk.internal.foreign
* @build NativeTestHelper CallGeneratorHelper TestUpcall
*
* @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
* --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17
* -DUPCALL_TEST_TYPE=SCOPE
* TestUpcall
*/
/*
* @test id=no_scope
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
* @modules jdk.incubator.foreign/jdk.internal.foreign
* @build NativeTestHelper CallGeneratorHelper TestUpcall
*
* @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
* --enable-native-access=ALL-UNNAMED -Dgenerator.sample.factor=17
* -DUPCALL_TEST_TYPE=NO_SCOPE
* TestUpcall
*/
/*
* @test id=async
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
@ -34,13 +58,11 @@
* TestUpcall
*/
import jdk.incubator.foreign.Addressable;
import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.SegmentAllocator;
import jdk.incubator.foreign.SymbolLookup;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemorySegment;
@ -104,7 +126,7 @@ public class TestUpcall extends CallGeneratorHelper {
private static void checkSelected(TestType type) {
if (UPCALL_TEST_TYPE != type)
return;//throw new SkipException("Skipping tests that were not selected");
throw new SkipException("Skipping tests that were not selected");
}
@Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)

View File

@ -62,7 +62,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ vmStore(rax, long.class) }
@ -89,7 +89,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ dup(), bufferLoad(0, long.class), vmStore(rdi, long.class),
@ -119,7 +119,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ dup(), bufferLoad(0, long.class), vmStore(rdi, long.class),
@ -148,7 +148,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ dup(), bufferLoad(0, long.class), vmStore(stackStorage(0), long.class),
@ -177,7 +177,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ dup(), bufferLoad(0, long.class), vmStore(stackStorage(0), long.class),
@ -201,7 +201,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ vmStore(rdi, int.class) },
@ -231,7 +231,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ vmStore(xmm0, double.class) },
@ -265,7 +265,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ vmStore(rdi, long.class) },
@ -321,7 +321,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ vmStore(rdi, int.class) },
@ -363,7 +363,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ unboxAddress(), vmStore(rdi, long.class) },
@ -384,7 +384,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
expectedBindings,
@ -442,7 +442,7 @@ public class TestSysVCallArranger extends CallArrangerTestBase {
assertFalse(bindings.isInMemoryReturn);
CallingSequence callingSequence = bindings.callingSequence;
assertEquals(callingSequence.methodType(), mt.appendParameterTypes(long.class));
assertEquals(callingSequence.functionDesc(), fd.withAppendedArgumentLayouts(C_LONG));
assertEquals(callingSequence.functionDesc(), fd.appendArgumentLayouts(C_LONG));
checkArgumentBindings(callingSequence, new Binding[][]{
{ vmStore(rax, long.class) }

View File

@ -124,7 +124,7 @@ public class Upcalls extends CLayouts {
static MethodHandle linkFunc(String name, FunctionDescriptor baseDesc) {
return abi.downcallHandle(
SymbolLookup.loaderLookup().lookup(name).orElseThrow(),
baseDesc.withAppendedArgumentLayouts(C_POINTER)
baseDesc.appendArgumentLayouts(C_POINTER)
);
}