mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:58:32 +00:00
4b66657b98
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>
595 lines
15 KiB
Dart
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);
|
|
}
|