dart-sdk/tests/ffi/address_of_array_generated_test.dart
Daco Harkes 4b66657b98 [vm/ffi] address of operator for FFI leaf calls
During FFI leaf calls, the Dart GC will not run. This means that we
can pass pointers into `TypedData` to FFI calls that take `Pointer`
arguments.

After this CL, we have three types of arguments that can flow into
`Pointer` argument in an FFI call:
* `Pointer`.
* `TypedData`: Any typed data including views.
* `_Compound`: A TypedData/Pointer and an offset in bytes.

The is only possible for `@Native external` functions, `asFunction`
does not support passing in `TypedData`. (See related GitHub issues
for discussion. TLDR: FFIgen should generate bindings without config.)

`.address` expressions on `TypedData` and `Array` elements do _not_
introduce bounds checks, even though `TypedData` and `Array` have
bounds information. E.g. `ffiNative(Uint8List(10)[20].address)` does
not throw.

Implementation details:

The CFE analyzes call-sites to `@Native external` functions. If the
arguments are `.address` expressions, it transforms the call site to
pass the compound or `TypedData`. If an additional offset needs to be
applied, the CFE constructs a new `_Compound` with the correct offset
in bytes.

The CFE then also creates a new `@Native external` function which have
`TypedData`s and `_Compound`s parameters. To avoid name clashes, these
functions are postfixed with `#` and `P`, `T`, or `C` for each Pointer
parameter.

TEST=pkg/vm/testcases/transformations/ffi/address_of_*

In the VM, `TypedData` arguments are passed as tagged values, and the
address is loaded inside the `FfiCallInstr`. `_Compound` arguments
turn into two IL definitions, one for the `TypedDataBase` (tagged),
and one for the offset in bytes (unboxed). The address is then loaded
inside the `FfiCallInstr` and the offset in bytes is applied.

Adding the offset in bytes required an extra temp register for ia32.
Also, it uncovered that the temp register in arm32 was conflicting
with the argument registers. However, TMP should suffice instead.

TEST=tests/ffi/address_of_array_generated_test.dart
TEST=tests/ffi/address_of_struct_generated_test.dart
TEST=tests/ffi/address_of_typeddata_generated_test.dart

Closes: https://github.com/dart-lang/sdk/issues/44589
Closes: https://github.com/dart-lang/sdk/issues/54771

CoreLibraryReviewExempt: VM only, unsupported in dart2wasm
Change-Id: I01fb428cfd6f9096a34689c2819c124a8003cb6b
Cq-Include-Trybots: dart/try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64c-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-arm64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360882
Reviewed-by: Jens Johansen <jensj@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Tess Strickland <sstrickl@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
2024-04-25 10:06:16 +00:00

595 lines
15 KiB
Dart

// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// This file has been automatically generated. Please do not edit it manually.
// Generated by tests/ffi/generator/address_of_test_generator.dart.
//
// SharedObjects=ffi_test_functions
// VMOptions=
// VMOptions=--deterministic --optimization-counter-threshold=90
// VMOptions=--use-slow-path
// VMOptions=--use-slow-path --stacktrace-every=100
// ignore_for_file: unused_import
import 'dart:ffi';
import 'dart:typed_data';
import 'package:expect/expect.dart';
import 'address_of_generated_shared.dart';
import 'address_of_shared.dart';
import 'dylib_utils.dart';
final ffiTestFunctions = dlopenPlatformSpecific('ffi_test_functions');
void main() {
// Force dlopen so @Native lookups in DynamicLibrary.process() succeed.
dlopenGlobalPlatformSpecific('ffi_test_functions');
for (int i = 0; i < 100; ++i) {
testAddressOfInt8Array();
testAddressOfInt8ArrayElementAt();
testAddressOfInt16Array();
testAddressOfInt16ArrayElementAt();
testAddressOfInt32Array();
testAddressOfInt32ArrayElementAt();
testAddressOfInt64Array();
testAddressOfInt64ArrayElementAt();
testAddressOfUint8Array();
testAddressOfUint8ArrayElementAt();
testAddressOfUint16Array();
testAddressOfUint16ArrayElementAt();
testAddressOfUint32Array();
testAddressOfUint32ArrayElementAt();
testAddressOfUint64Array();
testAddressOfUint64ArrayElementAt();
testAddressOfFloatArray();
testAddressOfFloatArrayElementAt();
testAddressOfDoubleArray();
testAddressOfDoubleArrayElementAt();
testAddressOfBoolArray();
testAddressOfBoolArrayElementAt();
}
}
final class Int8ArrayStruct extends Struct {
@Array(20)
external Array<Int8> array;
}
Array<Int8> makeInt8Array(int length) {
assert(length == 20);
final typedData = makeInt8List(length);
final struct = Struct.create<Int8ArrayStruct>(typedData);
return struct.array;
}
void testAddressOfInt8Array() {
const length = 20;
final array = makeInt8Array(length);
final expectedResult = makeExpectedResultInt8(0, length);
final result = takeInt8Pointer(array.address, length);
Expect.equals(expectedResult, result);
}
void testAddressOfInt8ArrayElementAt() {
const length = 20;
final array = makeInt8Array(length);
final expectedResult = makeExpectedResultInt8(0, length);
final result = takeInt8PointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.equals(expectedResult, result);
}
final class Int16ArrayStruct extends Struct {
@Array(20)
external Array<Int16> array;
}
Array<Int16> makeInt16Array(int length) {
assert(length == 20);
final typedData = makeInt16List(length);
final struct = Struct.create<Int16ArrayStruct>(typedData);
return struct.array;
}
void testAddressOfInt16Array() {
const length = 20;
final array = makeInt16Array(length);
final expectedResult = makeExpectedResultInt16(0, length);
final result = takeInt16Pointer(array.address, length);
Expect.equals(expectedResult, result);
}
void testAddressOfInt16ArrayElementAt() {
const length = 20;
final array = makeInt16Array(length);
final expectedResult = makeExpectedResultInt16(0, length);
final result = takeInt16PointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.equals(expectedResult, result);
}
final class Int32ArrayStruct extends Struct {
@Array(20)
external Array<Int32> array;
}
Array<Int32> makeInt32Array(int length) {
assert(length == 20);
final typedData = makeInt32List(length);
final struct = Struct.create<Int32ArrayStruct>(typedData);
return struct.array;
}
void testAddressOfInt32Array() {
const length = 20;
final array = makeInt32Array(length);
final expectedResult = makeExpectedResultInt32(0, length);
final result = takeInt32Pointer(array.address, length);
Expect.equals(expectedResult, result);
}
void testAddressOfInt32ArrayElementAt() {
const length = 20;
final array = makeInt32Array(length);
final expectedResult = makeExpectedResultInt32(0, length);
final result = takeInt32PointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.equals(expectedResult, result);
}
final class Int64ArrayStruct extends Struct {
@Array(20)
external Array<Int64> array;
}
Array<Int64> makeInt64Array(int length) {
assert(length == 20);
final typedData = makeInt64List(length);
final struct = Struct.create<Int64ArrayStruct>(typedData);
return struct.array;
}
void testAddressOfInt64Array() {
const length = 20;
final array = makeInt64Array(length);
final expectedResult = makeExpectedResultInt64(0, length);
final result = takeInt64Pointer(array.address, length);
Expect.equals(expectedResult, result);
}
void testAddressOfInt64ArrayElementAt() {
const length = 20;
final array = makeInt64Array(length);
final expectedResult = makeExpectedResultInt64(0, length);
final result = takeInt64PointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.equals(expectedResult, result);
}
final class Uint8ArrayStruct extends Struct {
@Array(20)
external Array<Uint8> array;
}
Array<Uint8> makeUint8Array(int length) {
assert(length == 20);
final typedData = makeUint8List(length);
final struct = Struct.create<Uint8ArrayStruct>(typedData);
return struct.array;
}
void testAddressOfUint8Array() {
const length = 20;
final array = makeUint8Array(length);
final expectedResult = makeExpectedResultUint8(0, length);
final result = takeUint8Pointer(array.address, length);
Expect.equals(expectedResult, result);
}
void testAddressOfUint8ArrayElementAt() {
const length = 20;
final array = makeUint8Array(length);
final expectedResult = makeExpectedResultUint8(0, length);
final result = takeUint8PointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.equals(expectedResult, result);
}
final class Uint16ArrayStruct extends Struct {
@Array(20)
external Array<Uint16> array;
}
Array<Uint16> makeUint16Array(int length) {
assert(length == 20);
final typedData = makeUint16List(length);
final struct = Struct.create<Uint16ArrayStruct>(typedData);
return struct.array;
}
void testAddressOfUint16Array() {
const length = 20;
final array = makeUint16Array(length);
final expectedResult = makeExpectedResultUint16(0, length);
final result = takeUint16Pointer(array.address, length);
Expect.equals(expectedResult, result);
}
void testAddressOfUint16ArrayElementAt() {
const length = 20;
final array = makeUint16Array(length);
final expectedResult = makeExpectedResultUint16(0, length);
final result = takeUint16PointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.equals(expectedResult, result);
}
final class Uint32ArrayStruct extends Struct {
@Array(20)
external Array<Uint32> array;
}
Array<Uint32> makeUint32Array(int length) {
assert(length == 20);
final typedData = makeUint32List(length);
final struct = Struct.create<Uint32ArrayStruct>(typedData);
return struct.array;
}
void testAddressOfUint32Array() {
const length = 20;
final array = makeUint32Array(length);
final expectedResult = makeExpectedResultUint32(0, length);
final result = takeUint32Pointer(array.address, length);
Expect.equals(expectedResult, result);
}
void testAddressOfUint32ArrayElementAt() {
const length = 20;
final array = makeUint32Array(length);
final expectedResult = makeExpectedResultUint32(0, length);
final result = takeUint32PointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.equals(expectedResult, result);
}
final class Uint64ArrayStruct extends Struct {
@Array(20)
external Array<Uint64> array;
}
Array<Uint64> makeUint64Array(int length) {
assert(length == 20);
final typedData = makeUint64List(length);
final struct = Struct.create<Uint64ArrayStruct>(typedData);
return struct.array;
}
void testAddressOfUint64Array() {
const length = 20;
final array = makeUint64Array(length);
final expectedResult = makeExpectedResultUint64(0, length);
final result = takeUint64Pointer(array.address, length);
Expect.equals(expectedResult, result);
}
void testAddressOfUint64ArrayElementAt() {
const length = 20;
final array = makeUint64Array(length);
final expectedResult = makeExpectedResultUint64(0, length);
final result = takeUint64PointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.equals(expectedResult, result);
}
final class FloatArrayStruct extends Struct {
@Array(20)
external Array<Float> array;
}
Array<Float> makeFloatArray(int length) {
assert(length == 20);
final typedData = makeFloat32List(length);
final struct = Struct.create<FloatArrayStruct>(typedData);
return struct.array;
}
void testAddressOfFloatArray() {
const length = 20;
final array = makeFloatArray(length);
final expectedResult = makeExpectedResultFloat(0, length);
final result = takeFloatPointer(array.address, length);
Expect.approxEquals(expectedResult, result);
}
void testAddressOfFloatArrayElementAt() {
const length = 20;
final array = makeFloatArray(length);
final expectedResult = makeExpectedResultFloat(0, length);
final result = takeFloatPointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.approxEquals(expectedResult, result);
}
final class DoubleArrayStruct extends Struct {
@Array(20)
external Array<Double> array;
}
Array<Double> makeDoubleArray(int length) {
assert(length == 20);
final typedData = makeFloat64List(length);
final struct = Struct.create<DoubleArrayStruct>(typedData);
return struct.array;
}
void testAddressOfDoubleArray() {
const length = 20;
final array = makeDoubleArray(length);
final expectedResult = makeExpectedResultDouble(0, length);
final result = takeDoublePointer(array.address, length);
Expect.approxEquals(expectedResult, result);
}
void testAddressOfDoubleArrayElementAt() {
const length = 20;
final array = makeDoubleArray(length);
final expectedResult = makeExpectedResultDouble(0, length);
final result = takeDoublePointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.approxEquals(expectedResult, result);
}
final class BoolArrayStruct extends Struct {
@Array(20)
external Array<Bool> array;
}
Array<Bool> makeBoolArray(int length) {
assert(length == 20);
final typedData = makeBoolList(length);
final struct = Struct.create<BoolArrayStruct>(typedData);
return struct.array;
}
void testAddressOfBoolArray() {
const length = 20;
final array = makeBoolArray(length);
final expectedResult = makeExpectedResultBool(0, length);
final result = takeBoolPointer(array.address, length);
Expect.equals(expectedResult, result);
}
void testAddressOfBoolArrayElementAt() {
const length = 20;
final array = makeBoolArray(length);
final expectedResult = makeExpectedResultBool(0, length);
final result = takeBoolPointerMany(
array[0].address,
array[1].address,
array[2].address,
array[3].address,
array[4].address,
array[5].address,
array[6].address,
array[7].address,
array[8].address,
array[9].address,
array[10].address,
array[11].address,
array[12].address,
array[13].address,
array[14].address,
array[15].address,
array[16].address,
array[17].address,
array[18].address,
array[19].address,
);
Expect.equals(expectedResult, result);
}