Skip to content
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

[ffi] Add support for abi-specific structs #42816

Open
dcharkes opened this issue Jul 23, 2020 · 3 comments
Open

[ffi] Add support for abi-specific structs #42816

dcharkes opened this issue Jul 23, 2020 · 3 comments
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. library-ffi

Comments

@dcharkes
Copy link
Contributor

dcharkes commented Jul 23, 2020

Sometimes structs are defined differently on different platforms. (Some fields might be commented out on some platforms.)

A workaround is to have a different struct for the different platforms, but that cascades into everything that is using that struct (function signatures, struct fields, and pointers).

We could introduce an AbiSpecificStruct that exposes all the different fields on all platforms in one api.

@AbiSpecificStructMapping({
  Abi.linuxX64: MyStructLinux(),
  Abi.windowsX64: MyStructWindows(),
  // ...
})
class MyStruct extends AbiSpecificStruct {
  external int a;
  external int b;
}

This would be the struct/union counterpart of #42563.

edit: We would probably make an API similar to https://api.dart.dev/stable/2.17.0/dart-ffi/AbiSpecificInteger-class.html with annotations instead of types.

@artob
Copy link

artob commented Jul 23, 2020

@dcharkes That's pretty neat. What happens if accessing field external int b on Windows, in this example? A compiler error, I trust?

@vsmenon vsmenon added area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. library-ffi labels Jul 24, 2020
copybara-service bot pushed a commit that referenced this issue Nov 3, 2021
This CL expands the ABIs in the FFI transform and VM from 3 groups to
18 individual ABIs in preparation of adding ABI-specific integer sizes
and structs.

This increases const lists with offsets in the kernel representation
from 3 to 18 elements. We do not expect significant size increases or
performance regressions from this. The constants are deduplicated in
Dart and the optimizer should optimize indexed lookups in const lists
away. However, landing this separately will enable us to verify that
assumption.

This also moves `Abi` to its own file and makes it an opaque class with
a predefined set of instances so that we do not depend on its internals.
That will enable us to keep `pkg/vm/lib/transformations/ffi/abi.dart`
consistent with the `Abi` abstraction to be introduced in `dart:ffi`
later for specifying ABI-specific integer sizes.

Bug: #42563
Bug: #42816

List of ABIs decided based on what's currently used (as Dart SDK target
platform, or Flutter target platform, or G3 target) and added
windows_arm64 in anticipation of
(flutter/flutter#53120).
Excluded are macos_ia32 (#39810)
because we discontinued support; and windows_arm, fuchsia_arm,
fuchsia_ia32, ios_ia32, and macos_arm because these are
unlikely to be added.

TEST=pkg/front_end/testcases/*.expect
TEST=tests/ffi/*

Change-Id: I437707c18d8667490c063272a5f8a33d846e6061
Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-debug-x64-try,vm-ffi-android-debug-arm-try,vm-kernel-mac-debug-x64-try,vm-kernel-nnbd-linux-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-precomp-linux-debug-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-ffi-android-debug-arm64c-try,vm-kernel-mac-release-arm64-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-precomp-android-release-arm64c-try,vm-kernel-precomp-android-release-arm_x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/217184
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Clement Skau <cskau@google.com>
copybara-service bot pushed a commit that referenced this issue Dec 1, 2021
This introduces the application binary interface (ABI) concept to
`dart:ffi` as a class with opaque instances.

We will use this for providing mappings for ABI-specific types.
Bug: #42563
Bug: #42816
Closes: #45254

Later, we might open up the contents of `Abi` if need be.

Some API design discussion notes:
#42563 (comment)

TEST=tests/ffi/abi_test.dart

Change-Id: Iebf290fc12f37d6f4236432ddf27ab3e12bde06d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/221627
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
copybara-service bot pushed a commit that referenced this issue Dec 2, 2021
TEST=pkg/analyzer/test/src/diagnostics/abi_specific_integer_mapping_test.dart

Bug: #42816

Change-Id: I7ae6e05073e6f28a42b5f8f7d06c9b5b91c510a7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/221821
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
copybara-service bot pushed a commit that referenced this issue Dec 2, 2021
When ABI-specific integers are introduced, their mappings can be
partial. We need to account for this in the marshaller.

This CL refactors the marshaller API to take an char** error return
parameter and changes the return type to a pointer (nullable) rather
than a reference.

Note that with only this CL we can not generate errors yet, because all
native types are still complete.

TEST=runtime/vm/compiler/ffi/native_type_vm_test.cc
TEST=tests/ffi*

Bug: #42816

Change-Id: Id97e73795c357e129e6280e8c5b528d18072c14d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/221632
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
@LeoSandbox
Copy link

Hey guys, I'm looking to use this package https://pub.dev/packages/steamworks on both Windows and MacOS. This issue is blocking the package to work properly.

I've been making a breakthrough RPG with Flutter for the past 2 years and about to start the last stretch of production to ship a demo and then release. This package will be used to send Steam Achievement to Steam API.

Is there any way I can help on this issue? Can you point me to the right resource so I can try to work on it?

@dcharkes
Copy link
Contributor Author

dcharkes commented Jul 9, 2024

Hi @LeoSandbox nice to meet you!

We welcome contributions! ❤️

The first step is to build a Dart SDK locally:

The best starting point would be to look at the commits that introduced ABI-specific integers:

The analyzer is a different implementation than the common compiler frontend (CFE).

To run the analyzer and CFE from source to be able to run the debugger in vscode:

			{
				"name": "dart analyzer.dart",
				"type": "dart",
				"request": "launch",
				"program": "pkg/analyzer_cli/bin/analyzer.dart",
				"args": [
					"tests/ffi/static_checks/vmspecific_static_checks_array_test.dart",
				],
				"toolArgs": [],
				"enableAsserts": true,
				"cwd": "${workspaceFolder}",
			},
			{
				"name": "dart gen_kernel.dart",
				"type": "dart",
				"request": "launch",
				"program": "pkg/vm/bin/gen_kernel.dart",
				"args": [
					"--enable-experiment=records",
					"--platform=${workspaceFolder}/xcodebuild/ReleaseARM64/vm_platform_strong.dill",
					"pkg/vm/testcases/transformations/ffi/address_of_struct_element.dart",
				],
				"toolArgs": [],
				"enableAsserts": true,
				"cwd": "${workspaceFolder}",
			},

You might need to adjust the build folder to out/ instead of xcodebuild/ if you're not on MacOS.

The use of the API could look something like the following:

@AbiSpecificStructMapping({
  Abi.linuxX64: MyStructLinux(),
  Abi.windowsX64: MyStructWindows(),
  // ...
})
final class MyStruct extends AbiSpecificStruct {
  // No annotation, the native types are per ABI
  external int a;

  // The ABI-specific struct should have the superset of all fields of the struct per ABI.
  external int b;

  // The ABI-specific struct should have the superset of all fields of the struct per ABI.
  external int c;
}

final class MyStructLinux extends Struct {
  @Int8()
  external int a;

  @Int8()
  external int b;
}

final class MyStructWindows extends Struct {
  @Int64()
  external int a;

  @Int64()
  external int c;
}

I expect a PR to implement this feature to roughly have the following changes:

  • A new class AbiSpecificStruct (and AbiSpecificUnion) in sdk/lib/ffi/abi_specific.dart
    • With a long doc-comment including examples
  • An implementation for static errors
    • The ABI-specific struct must have the superset of all fields of the structs mentioned in the annotation
    • The ABI-specific struct must have a Dart type compatible with the fields of the structs mentioned in the annotation (e.g. Windows cannot have @Double() external double a; while Linux has @Int8() external int a;).
    • The annotation must only mention other structs if it's a struct.
    • The error messages are defined in pkg/analyzer/messages.yaml and pkg/front_end/messages.yaml. You'll need to run the code generators mentioned in those files to get the Dart methods to use in the analyzer and CFE to report the errors.
  • Tests for static errors (both for CFE and analyzer) in tests/ffi/static_checks/vmspecific_static_checks_abi_specific_struct_test.dart
  • An implementation in the CFE in pkg/vm/lib/transformations/ffi/*.dart. I believe AbiSpecificNativeTypeCfe can be mostly reused to deal with structs/unions besides only integers. Basically the idea is that the external Foo x is transformed to a getter and setter with the real body that has a big switch based on ABI in it.
  • Unit test cases for the CFE similar to pkg/vm/testcases/transformations/ffi/abi_specific_int.dart. They show the transformed code before it is send to the backend.
  • Integration test cases that exercise the code in tests/ffi/*_test.dart
    • The best way to do this is probably to extend the test generator in tests/ffi/function_callbacks_structs_by_value_generated_test.dart to be able to generate tests for AbiSpecificStructs. Then you don't have to write tests by hand.
  • The most tricky part will most likely be the backend implementation for passing AbiSpecificStructs by value in FFI calls and callbacks (Pointer.fromFunction and NativeCallables). The implementation there would be in runtime/vm/compiler/frontend/* See the linked PR for what was changed for AbiSpecificInteger.

You'll have to touch many parts of the Dart compiler for this feature (similar to https://dart-review.googlesource.com/c/sdk/+/221501). However, the feature should be somewhat straightforward to implement due to its similarity to the AbiSpecificIntegers. Please feel free to ping me or this issue with any questions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. library-ffi
Projects
None yet
Development

No branches or pull requests

4 participants