2020-10-26 12:01:16 +00:00
|
|
|
// 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
|
|
|
|
|
2021-04-26 17:58:57 +00:00
|
|
|
// @dart = 2.9
|
|
|
|
|
2020-10-26 12:01:16 +00:00
|
|
|
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();
|
2020-10-26 12:01:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void recursiveTest(int recursionCounter) {
|
2021-01-28 21:40:15 +00:00
|
|
|
final pointer = calloc<Struct20BytesHomogeneousInt32>();
|
|
|
|
final struct = pointer.ref;
|
2020-10-26 12:01:16 +00:00
|
|
|
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);
|
2021-01-28 21:40:15 +00:00
|
|
|
calloc.free(pointer);
|
2020-10-26 12:01:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2021-01-28 21:40:15 +00:00
|
|
|
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);
|
|
|
|
|
2021-01-28 21:40:15 +00:00
|
|
|
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
|
|
|
}
|