| // 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=90 --use-slow-path --stacktrace-every=100 | |
| import 'dart:ffi'; | |
| import "package:expect/expect.dart"; | |
| import "package:ffi/ffi.dart"; | |
| import 'dylib_utils.dart'; | |
| // Reuse the struct classes. | |
| import 'function_structs_by_value_generated_compounds.dart'; | |
| final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions"); | |
| void main() { | |
| for (int i = 0; i < 100; i++) { | |
| recursiveTest(10); | |
| recursiveTest(11); | |
| 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("callbackPassStructRecursive($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"); | |
| Struct8BytesNestedInt typedDataBackedStruct = | |
| Pointer<Struct8BytesNestedInt>.fromAddress(0).ref; | |
| 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; | |
| 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); | |
| } |