dart-sdk/tests/ffi_2/function_callbacks_structs_by_value_test.dart

139 lines
4.2 KiB
Dart
Raw Normal View History

// Copyright (c) 2020, 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.
//
// SharedObjects=ffi_test_functions
//
// VMOptions=--deterministic --optimization-counter-threshold=5 --use-slow-path --stacktrace-every=100
// @dart = 2.9
import 'dart:ffi';
import "package:expect/expect.dart";
import "package:ffi/ffi.dart";
// Reuse the struct classes.
import 'function_structs_by_value_generated_test.dart';
void main() {
for (int i = 0; i < 10; i++) {
recursiveTest(10);
recursiveTest(11);
[vm/ffi] Support nested structs This CL adds support for nested structs in FFI calls, callbacks, and memory loads and stores through the Struct classes itself. Nesting empty structs and nesting a structs in themselves (directly or indirectly) is reported as error. This feature is almost fully implemented in the CFE transformation. Because structs depend on the sizes of their nested structs, the structs now need to be processed in topological order. Field access to nested structs branches at runtime on making a derived Pointer if the backing memory of the outer struct was a Pointer or making a TypedDataView if the backing memory of the outer struct was a TypedData. Assigning to a nested struct is a byte for byte copy from the source. The only changes in the VM are contained in the native calling convention calculation which now recursively needs to reason about fundamental types instead of just 1 struct deep. Because of the amount of corner cases in the calling conventions that need to be covered, the tests are generated, rather than hand-written. ABIs tested on CQ: x64 (Linux, MacOS, Windows), ia32 (Linux, Windows), arm (Android softFP, Linux hardFP), arm64 Android. ABIs tested locally through Flutter: arm64 iOS. ABIs not tested: ia32 Android (emulator), x64 iOS (simulator), arm iOS. TEST=runtime/bin/ffi_test/ffi_test_functions_generated.cc TEST=runtime/bin/ffi_test/ffi_test_functions.cc TEST=tests/{ffi,ffi_2}/function_structs_by_value_generated_test.dart TEST=tests/{ffi,ffi_2}/function_callbacks_structs_by_value_generated_tes TEST=tests/{ffi,ffi_2}/function_callbacks_structs_by_value_test.dart TEST=tests/{ffi,ffi_2}/vmspecific_static_checks_test.dart Closes https://github.com/dart-lang/sdk/issues/37271. Contains a temporary workaround for https://github.com/dart-lang/sdk/issues/44454. Change-Id: I5e5d10e09e5c3fc209f5f7e997efe17bd362214d Cq-Include-Trybots: luci.dart.try:dart-sdk-linux-try,dart-sdk-mac-try,dart-sdk-win-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-mac-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-ia32-try,vm-kernel-nnbd-mac-release-x64-try,vm-kernel-nnbd-win-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-msan-linux-release-x64-try,vm-kernel-precomp-msan-linux-release-x64-try,vm-kernel-precomp-android-release-arm_x64-try,analyzer-analysis-server-linux-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/169221 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
2020-12-18 09:34:35 +00:00
testCopyLogic();
}
}
void recursiveTest(int recursionCounter) {
final pointer = calloc<Struct20BytesHomogeneousInt32>();
final struct = pointer.ref;
struct.a0 = 1;
struct.a1 = 2;
struct.a2 = 3;
struct.a3 = 4;
struct.a4 = 5;
final result = dartPassStructRecursive(recursionCounter, struct);
Expect.equals(struct.a0 + recursionCounter * 2, result.a0);
Expect.equals(struct.a1, result.a1);
Expect.equals(struct.a2, result.a2);
Expect.equals(struct.a3, result.a3);
Expect.equals(struct.a4, result.a4);
calloc.free(pointer);
}
Struct20BytesHomogeneousInt32 dartPassStructRecursive(
int recursionCounter, Struct20BytesHomogeneousInt32 struct) {
print("callbackPassStructRecurisive($recursionCounter, $struct)");
struct.a0++;
final structA0Saved = struct.a0;
if (recursionCounter <= 0) {
print("returning");
return struct;
}
final result =
cPassStructRecursive(recursionCounter - 1, struct, functionPointer);
result.a0++;
// Check struct.a0 is not modified by Dart->C call.
Expect.equals(structA0Saved, struct.a0);
// Check struct.a0 is not modified by C->Dart callback, if so struct.a4 == 0.
Expect.notEquals(0, struct.a4);
return result;
}
final functionPointer = Pointer.fromFunction<
Struct20BytesHomogeneousInt32 Function(
Int64, Struct20BytesHomogeneousInt32)>(dartPassStructRecursive);
final cPassStructRecursive = ffiTestFunctions.lookupFunction<
Struct20BytesHomogeneousInt32 Function(Int64 recursionCounter,
Struct20BytesHomogeneousInt32 struct, Pointer callbackAddress),
Struct20BytesHomogeneousInt32 Function(int recursionCounter,
Struct20BytesHomogeneousInt32, Pointer)>("PassStructRecursive");
[vm/ffi] Support nested structs This CL adds support for nested structs in FFI calls, callbacks, and memory loads and stores through the Struct classes itself. Nesting empty structs and nesting a structs in themselves (directly or indirectly) is reported as error. This feature is almost fully implemented in the CFE transformation. Because structs depend on the sizes of their nested structs, the structs now need to be processed in topological order. Field access to nested structs branches at runtime on making a derived Pointer if the backing memory of the outer struct was a Pointer or making a TypedDataView if the backing memory of the outer struct was a TypedData. Assigning to a nested struct is a byte for byte copy from the source. The only changes in the VM are contained in the native calling convention calculation which now recursively needs to reason about fundamental types instead of just 1 struct deep. Because of the amount of corner cases in the calling conventions that need to be covered, the tests are generated, rather than hand-written. ABIs tested on CQ: x64 (Linux, MacOS, Windows), ia32 (Linux, Windows), arm (Android softFP, Linux hardFP), arm64 Android. ABIs tested locally through Flutter: arm64 iOS. ABIs not tested: ia32 Android (emulator), x64 iOS (simulator), arm iOS. TEST=runtime/bin/ffi_test/ffi_test_functions_generated.cc TEST=runtime/bin/ffi_test/ffi_test_functions.cc TEST=tests/{ffi,ffi_2}/function_structs_by_value_generated_test.dart TEST=tests/{ffi,ffi_2}/function_callbacks_structs_by_value_generated_tes TEST=tests/{ffi,ffi_2}/function_callbacks_structs_by_value_test.dart TEST=tests/{ffi,ffi_2}/vmspecific_static_checks_test.dart Closes https://github.com/dart-lang/sdk/issues/37271. Contains a temporary workaround for https://github.com/dart-lang/sdk/issues/44454. Change-Id: I5e5d10e09e5c3fc209f5f7e997efe17bd362214d Cq-Include-Trybots: luci.dart.try:dart-sdk-linux-try,dart-sdk-mac-try,dart-sdk-win-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-mac-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-ia32-try,vm-kernel-nnbd-mac-release-x64-try,vm-kernel-nnbd-win-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-msan-linux-release-x64-try,vm-kernel-precomp-msan-linux-release-x64-try,vm-kernel-precomp-android-release-arm_x64-try,analyzer-analysis-server-linux-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/169221 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
2020-12-18 09:34:35 +00:00
Struct8BytesNestedInt typedDataBackedStruct = Struct8BytesNestedInt();
bool typedDataBackedStructSet = false;
void _receiveStructByValue(Struct8BytesNestedInt struct) {
typedDataBackedStruct = struct;
typedDataBackedStructSet = true;
}
final _receiveStructByValuePointer =
Pointer.fromFunction<Void Function(Struct8BytesNestedInt)>(
_receiveStructByValue);
final _invokeReceiveStructByValue = ffiTestFunctions.lookupFunction<
Void Function(
Pointer<NativeFunction<Void Function(Struct8BytesNestedInt)>>),
void Function(
Pointer<NativeFunction<Void Function(Struct8BytesNestedInt)>>)>(
"CallbackWithStruct");
void testCopyLogic() {
_invokeReceiveStructByValue(_receiveStructByValuePointer);
Expect.isTrue(typedDataBackedStructSet);
final pointer = calloc<Struct8BytesNestedInt>();
final pointerBackedStruct = pointer.ref;
[vm/ffi] Support nested structs This CL adds support for nested structs in FFI calls, callbacks, and memory loads and stores through the Struct classes itself. Nesting empty structs and nesting a structs in themselves (directly or indirectly) is reported as error. This feature is almost fully implemented in the CFE transformation. Because structs depend on the sizes of their nested structs, the structs now need to be processed in topological order. Field access to nested structs branches at runtime on making a derived Pointer if the backing memory of the outer struct was a Pointer or making a TypedDataView if the backing memory of the outer struct was a TypedData. Assigning to a nested struct is a byte for byte copy from the source. The only changes in the VM are contained in the native calling convention calculation which now recursively needs to reason about fundamental types instead of just 1 struct deep. Because of the amount of corner cases in the calling conventions that need to be covered, the tests are generated, rather than hand-written. ABIs tested on CQ: x64 (Linux, MacOS, Windows), ia32 (Linux, Windows), arm (Android softFP, Linux hardFP), arm64 Android. ABIs tested locally through Flutter: arm64 iOS. ABIs not tested: ia32 Android (emulator), x64 iOS (simulator), arm iOS. TEST=runtime/bin/ffi_test/ffi_test_functions_generated.cc TEST=runtime/bin/ffi_test/ffi_test_functions.cc TEST=tests/{ffi,ffi_2}/function_structs_by_value_generated_test.dart TEST=tests/{ffi,ffi_2}/function_callbacks_structs_by_value_generated_tes TEST=tests/{ffi,ffi_2}/function_callbacks_structs_by_value_test.dart TEST=tests/{ffi,ffi_2}/vmspecific_static_checks_test.dart Closes https://github.com/dart-lang/sdk/issues/37271. Contains a temporary workaround for https://github.com/dart-lang/sdk/issues/44454. Change-Id: I5e5d10e09e5c3fc209f5f7e997efe17bd362214d Cq-Include-Trybots: luci.dart.try:dart-sdk-linux-try,dart-sdk-mac-try,dart-sdk-win-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-mac-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-ia32-try,vm-kernel-nnbd-mac-release-x64-try,vm-kernel-nnbd-win-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-msan-linux-release-x64-try,vm-kernel-precomp-msan-linux-release-x64-try,vm-kernel-precomp-android-release-arm_x64-try,analyzer-analysis-server-linux-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/169221 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
2020-12-18 09:34:35 +00:00
void reset() {
pointerBackedStruct.a0.a0 = 1;
pointerBackedStruct.a0.a1 = 2;
pointerBackedStruct.a1.a0 = 3;
pointerBackedStruct.a1.a1 = 4;
typedDataBackedStruct.a0.a0 = 5;
typedDataBackedStruct.a0.a1 = 6;
typedDataBackedStruct.a1.a0 = 7;
typedDataBackedStruct.a1.a1 = 8;
}
// Pointer -> Pointer.
reset();
pointerBackedStruct.a1 = pointerBackedStruct.a0;
Expect.equals(1, pointerBackedStruct.a1.a0);
Expect.equals(2, pointerBackedStruct.a1.a1);
// Pointer -> TypedData.
reset();
typedDataBackedStruct.a1 = pointerBackedStruct.a0;
Expect.equals(1, typedDataBackedStruct.a1.a0);
Expect.equals(2, typedDataBackedStruct.a1.a1);
// TypedData -> Pointer.
reset();
pointerBackedStruct.a1 = typedDataBackedStruct.a0;
Expect.equals(5, pointerBackedStruct.a1.a0);
Expect.equals(6, pointerBackedStruct.a1.a1);
// TypedData -> TypedData.
reset();
typedDataBackedStruct.a1 = typedDataBackedStruct.a0;
Expect.equals(5, typedDataBackedStruct.a1.a0);
Expect.equals(6, typedDataBackedStruct.a1.a1);
calloc.free(pointer);
[vm/ffi] Support nested structs This CL adds support for nested structs in FFI calls, callbacks, and memory loads and stores through the Struct classes itself. Nesting empty structs and nesting a structs in themselves (directly or indirectly) is reported as error. This feature is almost fully implemented in the CFE transformation. Because structs depend on the sizes of their nested structs, the structs now need to be processed in topological order. Field access to nested structs branches at runtime on making a derived Pointer if the backing memory of the outer struct was a Pointer or making a TypedDataView if the backing memory of the outer struct was a TypedData. Assigning to a nested struct is a byte for byte copy from the source. The only changes in the VM are contained in the native calling convention calculation which now recursively needs to reason about fundamental types instead of just 1 struct deep. Because of the amount of corner cases in the calling conventions that need to be covered, the tests are generated, rather than hand-written. ABIs tested on CQ: x64 (Linux, MacOS, Windows), ia32 (Linux, Windows), arm (Android softFP, Linux hardFP), arm64 Android. ABIs tested locally through Flutter: arm64 iOS. ABIs not tested: ia32 Android (emulator), x64 iOS (simulator), arm iOS. TEST=runtime/bin/ffi_test/ffi_test_functions_generated.cc TEST=runtime/bin/ffi_test/ffi_test_functions.cc TEST=tests/{ffi,ffi_2}/function_structs_by_value_generated_test.dart TEST=tests/{ffi,ffi_2}/function_callbacks_structs_by_value_generated_tes TEST=tests/{ffi,ffi_2}/function_callbacks_structs_by_value_test.dart TEST=tests/{ffi,ffi_2}/vmspecific_static_checks_test.dart Closes https://github.com/dart-lang/sdk/issues/37271. Contains a temporary workaround for https://github.com/dart-lang/sdk/issues/44454. Change-Id: I5e5d10e09e5c3fc209f5f7e997efe17bd362214d Cq-Include-Trybots: luci.dart.try:dart-sdk-linux-try,dart-sdk-mac-try,dart-sdk-win-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-mac-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-ia32-try,vm-kernel-nnbd-mac-release-x64-try,vm-kernel-nnbd-win-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-msan-linux-release-x64-try,vm-kernel-precomp-msan-linux-release-x64-try,vm-kernel-precomp-android-release-arm_x64-try,analyzer-analysis-server-linux-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/169221 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
2020-12-18 09:34:35 +00:00
}