-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[dart:ffi] Inline arrays in Structs #35763
Comments
also support for fixed size arrays. its quite common to have a struct with fixed sized arrays to pass around in C |
We have For structs with inline arrays: struct MyStruct {
uint8_t arr[10];
int64_t arr2[3];
}; We need a dart syntax of representing an inline array. We could opt for exposing this as a pointer, which provides class MyStruct extends Struct {
@InlineArray(10)
Pointer<Uint8> arr;
@InlineArray(3)
Pointer<Int64> arr2;
} Using a cc @mkustermann edit: We do not want to expose it as a pointer, rather as a class MS extends Struct {}
MS foo(MS ms); // C signature for passing struct by value.
@size(4)CArray<MS> foo(@size(4)CArray<MS> mss); // C signature for passing inline array of structs.
Pointer<MS> foo(Pointer<MS> ms); // C signature for passing pointer.
class MS2 extends Struct {
MS ms; // Nested struct.
}
class MS3 extends Struct {
@size(4)
CArray<MS> mss; // Nested array of structs.
}
class MS4 extends Struct {
Pointer<MS> mss; // Pointer to struct.
}
If we expose the nested structs and the inline array as getter/setter pair, the setters would do a memcopy of the whole underlying structure. (As sidenote, we should also introduce memcopy on structs: Pointer<MS> p1, p2;
p1.value = p2.ref; // Copies over all memory. ) |
I got this error when trying your solution to getting static arrays on Dart side Codeclass StaticArray extends Struct {
@InlineArray(10)
Pointer<Int32> array;
@Int32()
int len;
} Result$ dart structs.dart
structs.dart:48:4: Error: Method not found: 'InlineArray'.
@InlineArray(10)
^^^^^^^^^^^
structs.dart:129:15: Error: A function expression can't have a name.
staticArray.forEach(idx, elem) => print("array[$idx]: $elem");
^^^^^^^
structs.dart:129:15: Error: Expected an identifier, but got 'forEach'.
staticArray.forEach(idx, elem) => print("array[$idx]: $elem");
^^^^^^^ Does it mean that this is just a proposal? Thanks in advance! |
Yes, for now it's just a proposal. See the workaround made by @timsneath here for now. I'll get around to implementing this in the future, I'm working on other |
@dcharkes Thanks! FFI has been great so far. This would affect how I use the array from a returned pointer. |
You need to use free() to release the memory. |
@timsneath Thanks. I looked at the static array workaround but it seems difficult to scale when my array is say 500-1000 elements big. Is it that the realistic workaround is to always use malloc'ated arrays? |
@dcharkes As I alluded to in the conversation in #36140, the lack of support for inline arrays in structs is a blocker for me in creating OpenXR bindings for Dart and Flutter. The proposed workaround is infeasible for the structs I need to map, which include the following: struct XrActionCreateInfo {
XrStructureType type;
const void* next;
char actionName[64];
XrActionType actionType;
uint32_t countSubactionPaths;
const XrPath* subactionPaths;
char localizedActionName[128];
};
struct XrApplicationInfo {
char applicationName[128];
uint32_t applicationVersion;
char engineName[128];
uint32_t engineVersion;
XrVersion apiVersion;
};
struct XrEventDataBuffer {
XrStructureType type;
const void* next;
uint8_t varying[4000];
}; |
As a workaround, would not creating a pointer to uint8 or utf8 with size matching the required, good enough? For example:
} Sorry for missing the auto formatting, I’m on the phone. |
What about multi dimensional inline arrays, what should the API be for multidimensional arrays? |
@artob extending a little from the idea @bitsydarel approached, you might check out https://github.com/timsneath/win32/blob/bluetooth/lib/src/structs.dart#L1941 for an example of wrapping a similar Win32 struct that seems like a viable workaround for you. (In this scenario, I have a 250 character Utf-16 string that I need to wrap). |
@timsneath It's a good workaround for the So, the suggested approach seems like it could be a workaround for
@bitsydarel After @timsneath's code example I understand better what you were proposing for |
It's not the prettiest code I've ever written, but wouldn't something like this work? Here we use the same technique as for the You could extend this still further by providing setters where appropriate, and adding clean String properties to convert from a C-style string into a Dart string, with guards to ensure a 128-byte maxlength. Curious to know if this works for you? |
For inline arrays of primitive values https://pub.dev/packages/ffigen has an option to generate 'n' fields and provide indexed access (with |
This CL does not add inline arrays to `dart:ffi` yet, only to the mock SDK in the analyzer for testing the analyzer. This means we can review and land it separately. Closes: #44747 Bug: #35763 Change-Id: I7df6a61ea4cfa522afd12194dd2f3573eb79b3ef Cq-Include-Trybots: luci.dart.try:analyzer-analysis-server-linux-try,analyzer-linux-release-try,analyzer-nnbd-linux-release-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/183684 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
So that it can be invoked from `CArray` which has a backing store that is either TypedData or Pointer. Bug: #35763 TEST=tests/ffi(_2)/* Change-Id: I30bb0c1e848f2ac4f47919009106d5428ed66453 Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-debug-x64-try,vm-kernel-precomp-nnbd-linux-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/183683 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Aske Simon Christensen <askesc@google.com>
The various ABIs lay out structs with inline arrays the same way as they do with only nested structs and primitive values. Most notably, homogenous structs (arm and arm64) and structs spread over a CPU and FPU register in x64 Linux/MacOS will even be laid out this way if irregular size nested arrays are involved. These cases are covered in the unit tests. This CL introduces the ByteRange to ease the ContainsOnlyFloats calculation for x64. Bug: #35763 tools/build.py run_ffi_unit_tests && tools/test.py ffi_unit TEST=runtime/vm/compiler/ffi/native_calling_convention_test.cc TEST=runtime/vm/compiler/ffi/native_type_test.cc tools/test.py ffi ffi_2 TEST=tests/ffi(_2)/(.*)by_value_(*.)_test.dart Change-Id: I4bbcbffd47eb8901a87db64e62aa5cbe67d03e18 Cq-Include-Trybots: luci.dart.try:vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-win-debug-ia32-try,vm-kernel-win-debug-x64-try,vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-mac-debug-x64-try,vm-ffi-android-debug-arm64-try,vm-ffi-android-debug-arm-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/183682 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Clement Skau <cskau@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This CL changes `@pragma('vm:ffi:struct-fields', [...])` to `@pragma('vm:ffi:struct-fields', _FfiStructLayout([...]))` which makes it easier to add more data in subsequent CLs. Extends `FindPragma` to allow returning multiple matched pragma's, so that we can filter them. (In this case to avoid matching user-defined pragma's that do not have an instance of the private class.) Separated out from https://dart-review.googlesource.com/c/sdk/+/183640 because of the extra constant in existing expectation files. Bug: #35763 Bug: #38158 TEST=tests/ffi(_2)/*_by_value_*_test.dart Change-Id: Idef9f82e9b53c2a32dffabcec19669eae550fe2f Cq-Include-Trybots: luci.dart.try:front-end-nnbd-mac-release-x64-try,front-end-linux-release-x64-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-nnbd-linux-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/184181 Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Clement Skau <cskau@google.com>
Introduces the `NativeTypeCfe` type hierarchy for cleaner calculation of sizes and offsets of native types and cleaner code generation. The transformation ensures we're only visiting the structs in topological order, which means the struct type can always look up its (indirectly) nested structs in the `structCache`. This simplifies adding inline arrays (https://dart-review.googlesource.com/c/sdk/+/183640), packed structs, and unions to this transformation. `typedDataBaseOffset` is moved to the `FfiTransformer` because the dependent CL uses it in the `FfiUseSiteTransformer`. Bug: #35763 Bug: #38158 Bug: #38491 TEST=tests/ffi(_2)/(.*)by_value(.*)_test.dart Change-Id: I345e02c48844ca795f9137a5addd5ba89992e1c9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/184421 Reviewed-by: Dmitry Stefantsov <dmitryas@google.com> Reviewed-by: Clement Skau <cskau@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
Update^2 design: class MyStruct extends Struct {
@Array(8)
external Array<Uint8> inlineArray;
@Array(2, 2, 2)
external Array<Uint8> threeDimensionalInlineArray;
@Array.multi([2, 2, 2, 2, 2, 2, 2, 2])
external Array<Uint8> eightDimensionalInlineArray;
} source #45023 (comment) |
This will be available on the first dev-release after Version 2.13.0-73.0.dev. |
Is it possible to have the address of the |
We're tracking this in #45508. |
Helpers for converting between
ffi.Pointer
s and arrays.Maybe use external typed data for efficient conversions.
The text was updated successfully, but these errors were encountered: