Skip to content

Commit

Permalink
[vm/ffi] Introduce Abi
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
dcharkes authored and Commit Bot committed Dec 1, 2021
1 parent 66d2bba commit 6633572
Show file tree
Hide file tree
Showing 21 changed files with 445 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ additionalExports = (ffi::nullptr,
ffi::unsized,
ffi::sizeOf,
ffi::Dart_NativeMessageHandler,
ffi::Abi,
ffi::Allocator,
ffi::AllocatorAlloc,
ffi::Array,
Expand Down Expand Up @@ -112,6 +113,7 @@ additionalExports = (ffi::nullptr,
ffi::unsized,
ffi::sizeOf,
ffi::Dart_NativeMessageHandler,
ffi::Abi,
ffi::Allocator,
ffi::AllocatorAlloc,
ffi::Array,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ additionalExports = (ffi::nullptr,
ffi::unsized,
ffi::sizeOf,
ffi::Dart_NativeMessageHandler,
ffi::Abi,
ffi::Allocator,
ffi::AllocatorAlloc,
ffi::Array,
Expand Down Expand Up @@ -112,6 +113,7 @@ additionalExports = (ffi::nullptr,
ffi::unsized,
ffi::sizeOf,
ffi::Dart_NativeMessageHandler,
ffi::Abi,
ffi::Allocator,
ffi::AllocatorAlloc,
ffi::Array,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ constants {

Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:137:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ constants {

Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:137:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ constants {

Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:137:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ constants {

Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:137:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ constants {

Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:137:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,5 @@ Extra constant evaluation: evaluated: 110, effectively constant: 2

Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:137:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ constants {

Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:137:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,5 @@ Extra constant evaluation: evaluated: 110, effectively constant: 2

Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:136:9)
- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:137:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
265 changes: 184 additions & 81 deletions pkg/vm/lib/transformations/ffi/abi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import 'common.dart';

// TODO(http://dartbug.com/47823): Remove this copy of `Abi`.

/// The hardware architectures the Dart VM runs on.
enum _Architecture {
arm,
Expand Down Expand Up @@ -36,108 +38,209 @@ enum _OS {
windows,
}

/// Application binary interface.
/// An application binary interface (ABI).
///
/// An ABI defines the memory layout of data
/// and the function call protocol for native code.
/// It is usually defined by the an operating system for each
/// architecture that operating system runs on.
///
/// The Dart VM can run on a variety of [Abi]s, see [supportedAbis].
/// The Dart VM can run on a variety of operating systems and architectures.
/// Supported ABIs are represented by `Abi` objects.
/// See [values] for all the supported ABIs.
class Abi {
/// The application binary interface for Android on the Arm architecture.
static const androidArm = _androidArm;

/// The application binary interface for Android on the Arm64 architecture.
static const androidArm64 = _androidArm64;

/// The application binary interface for Android on the IA32 architecture.
static const androidIA32 = _androidIA32;

/// The application binary interface for android on the X64 architecture.
static const androidX64 = _androidX64;

/// The application binary interface for Fuchsia on the Arm64 architecture.
static const fuchsiaArm64 = _fuchsiaArm64;

/// The application binary interface for Fuchsia on the X64 architecture.
static const fuchsiaX64 = _fuchsiaX64;

/// The application binary interface for iOS on the Arm architecture.
static const iosArm = _iosArm;

/// The application binary interface for iOS on the Arm64 architecture.
static const iosArm64 = _iosArm64;

/// The application binary interface for iOS on the X64 architecture.
static const iosX64 = _iosX64;

/// The application binary interface for Linux on the Arm architecture.
///
/// Does not distinguish between hard and soft fp. Currently, no uses of Abi
/// require this distinction.
static const linuxArm = _linuxArm;

/// The application binary interface for linux on the Arm64 architecture.
static const linuxArm64 = _linuxArm64;

/// The application binary interface for linux on the IA32 architecture.
static const linuxIA32 = _linuxIA32;

/// The application binary interface for linux on the X64 architecture.
static const linuxX64 = _linuxX64;

/// The application binary interface for MacOS on the Arm64 architecture.
static const macosArm64 = _macosArm64;

/// The application binary interface for MacOS on the X64 architecture.
static const macosX64 = _macosX64;

/// The application binary interface for Windows on the Arm64 architecture.
static const windowsArm64 = _windowsArm64;

/// The application binary interface for Windows on the IA32 architecture.
static const windowsIA32 = _windowsIA32;

/// The application binary interface for Windows on the X64 architecture.
static const windowsX64 = _windowsX64;

/// The ABIs that the DartVM can run on, sorted alphabetically.
///
/// Does not contain macosIA32, we stopped supporting it.
/// https://github.com/dart-lang/sdk/issues/39810
///
/// Includes [windowsArm64], even though it is currently not supported.
/// Support has been requested for Flutter.
/// https://github.com/flutter/flutter/issues/53120
static const values = [
androidArm,
androidArm64,
androidIA32,
androidX64,
fuchsiaArm64,
fuchsiaX64,
iosArm,
iosArm64,
iosX64,
linuxArm,
linuxArm64,
linuxIA32,
linuxX64,
macosArm64,
macosX64,
windowsArm64,
windowsIA32,
windowsX64,
];

/// The ABI the Dart VM is currently running on.
external factory Abi.current();

/// A string representation of this ABI.
///
/// The string is equal to the 'on' part from `Platform.version` and
/// `dart --version`.
@override
String toString() => '${_os.name}_${_architecture.name}';

/// The size of both integer registers and memory addresses in bytes.
int get wordSize => _architecture.wordSize;

/// The operating system of this [Abi].
// ignore: unused_field
final _OS _os;

/// The architecture of this [Abi].
final _Architecture _architecture;

/// The size of integer registers and memory addresses in bytes.
int get wordSize => _architecture.wordSize;

/// The constructor is private so that we can use [Abi.values] as opaque
/// tokens.
const Abi._(this._architecture, this._os);

static const _androidArm = Abi._(_Architecture.arm, _OS.android);
static const _androidArm64 = Abi._(_Architecture.arm64, _OS.android);
static const _androidIA32 = Abi._(_Architecture.ia32, _OS.android);
static const _androidX64 = Abi._(_Architecture.x64, _OS.android);
static const _fuchsiaArm64 = Abi._(_Architecture.arm64, _OS.fuchsia);
static const _fuchsiaX64 = Abi._(_Architecture.x64, _OS.fuchsia);
static const _iosArm = Abi._(_Architecture.arm, _OS.ios);
static const _iosArm64 = Abi._(_Architecture.arm64, _OS.ios);
static const _iosX64 = Abi._(_Architecture.x64, _OS.ios);
static const _linuxArm = Abi._(_Architecture.arm, _OS.linux);
static const _linuxArm64 = Abi._(_Architecture.arm64, _OS.linux);
static const _linuxIA32 = Abi._(_Architecture.ia32, _OS.linux);
static const _linuxX64 = Abi._(_Architecture.x64, _OS.linux);
static const _macosArm64 = Abi._(_Architecture.arm64, _OS.macos);
static const _macosX64 = Abi._(_Architecture.x64, _OS.macos);
static const _windowsArm64 = Abi._(_Architecture.arm64, _OS.windows);
static const _windowsIA32 = Abi._(_Architecture.ia32, _OS.windows);
static const _windowsX64 = Abi._(_Architecture.x64, _OS.windows);
}

const androidArm = Abi._(_Architecture.arm, _OS.android);
const androidArm64 = Abi._(_Architecture.arm64, _OS.android);
const androidIA32 = Abi._(_Architecture.ia32, _OS.android);
const androidX64 = Abi._(_Architecture.x64, _OS.android);
const fuchsiaArm64 = Abi._(_Architecture.arm64, _OS.fuchsia);
const fuchsiaX64 = Abi._(_Architecture.x64, _OS.fuchsia);
const iosArm = Abi._(_Architecture.arm, _OS.ios);
const iosArm64 = Abi._(_Architecture.arm64, _OS.ios);
const iosX64 = Abi._(_Architecture.x64, _OS.ios);
const linuxArm = Abi._(_Architecture.arm, _OS.linux);
const linuxArm64 = Abi._(_Architecture.arm64, _OS.linux);
const linuxIA32 = Abi._(_Architecture.ia32, _OS.linux);
const linuxX64 = Abi._(_Architecture.x64, _OS.linux);
const macosArm64 = Abi._(_Architecture.arm64, _OS.macos);

// No macosIA32, not intending to support.
// https://github.com/dart-lang/sdk/issues/39810

const macosX64 = Abi._(_Architecture.x64, _OS.macos);

/// Currently not supported, but feature requested for Flutter.
/// https://github.com/flutter/flutter/issues/53120
const windowsArm64 = Abi._(_Architecture.arm64, _OS.windows);
const windowsIA32 = Abi._(_Architecture.ia32, _OS.windows);
const windowsX64 = Abi._(_Architecture.x64, _OS.windows);

/// All ABIs that the DartVM can run on sorted alphabetically.
///
/// Keep consistent with runtime/vm/compiler/ffi/abi.cc.
const supportedAbisOrdered = [
androidArm,
androidArm64,
androidIA32,
androidX64,
fuchsiaArm64,
fuchsiaX64,
iosArm,
iosArm64,
iosX64,
linuxArm,
linuxArm64,
linuxIA32,
linuxX64,
macosArm64,
macosX64,
windowsArm64,
windowsIA32,
windowsX64,
];
// Keep consistent with sdk/lib/ffi/abi.dart.
const Map<Abi, String> abiNames = {
Abi.androidArm: 'androidArm',
Abi.androidArm64: 'androidArm64',
Abi.androidIA32: 'androidIA32',
Abi.androidX64: 'androidX64',
Abi.fuchsiaArm64: 'fuchsiaArm64',
Abi.fuchsiaX64: 'fuchsiaX64',
Abi.iosArm: 'iosArm',
Abi.iosArm64: 'iosArm64',
Abi.iosX64: 'iosX64',
Abi.linuxArm: 'linuxArm',
Abi.linuxArm64: 'linuxArm64',
Abi.linuxIA32: 'linuxIA32',
Abi.linuxX64: 'linuxX64',
Abi.macosArm64: 'macosArm64',
Abi.macosX64: 'macosX64',
Abi.windowsArm64: 'windowsArm64',
Abi.windowsIA32: 'windowsIA32',
Abi.windowsX64: 'windowsX64',
};

/// The size of integer registers and memory addresses in bytes per [Abi].
// Keep consistent with sdk/lib/_internal/vm/lib/ffi_patch.dart
final Map<Abi, int> wordSize = {
for (final abi in supportedAbisOrdered) abi: abi.wordSize
};
final Map<Abi, int> wordSize =
Map.unmodifiable({for (final abi in Abi.values) abi: abi.wordSize});

/// Struct and union fields that are not aligned to their size.
/// Alignment for types that are not aligned to a multiple of their size.
///
/// When a type occurs in a struct or union, it's usually aligned
/// to a multiple of its own size.
/// Some ABIs have types which are not aligned to their own size,
/// but to a smaller size.
///
/// Has an entry for all Abis. Empty entries document that every native
/// type is aligned to it's own size in this ABI.
/// This map maps each [Abi] to a mapping from types that are not
/// aligned by their size, to their actual alignment.
/// If such a map is empty, which many are,
/// it means that all types are aligned to their own size in that ABI.
///
/// See runtime/vm/compiler/ffi/abi.cc for asserts in the VM that verify these
/// alignments.
const nonSizeAlignment = <Abi, Map<NativeType, int>>{
const Map<Abi, Map<NativeType, int>> nonSizeAlignment = {
// _wordSize64
androidArm64: _wordSize64,
androidX64: _wordSize64,
fuchsiaArm64: _wordSize64,
fuchsiaX64: _wordSize64,
iosArm64: _wordSize64,
iosX64: _wordSize64,
linuxArm64: _wordSize64,
linuxX64: _wordSize64,
macosArm64: _wordSize64,
macosX64: _wordSize64,
windowsArm64: _wordSize64,
windowsX64: _wordSize64,
Abi.androidArm64: _wordSize64,
Abi.androidX64: _wordSize64,
Abi.fuchsiaArm64: _wordSize64,
Abi.fuchsiaX64: _wordSize64,
Abi.iosArm64: _wordSize64,
Abi.iosX64: _wordSize64,
Abi.linuxArm64: _wordSize64,
Abi.linuxX64: _wordSize64,
Abi.macosArm64: _wordSize64,
Abi.macosX64: _wordSize64,
Abi.windowsArm64: _wordSize64,
Abi.windowsX64: _wordSize64,
// _wordSize32Align32
androidIA32: _wordSize32Align32,
iosArm: _wordSize32Align32,
linuxIA32: _wordSize32Align32,
Abi.androidIA32: _wordSize32Align32,
Abi.iosArm: _wordSize32Align32,
Abi.linuxIA32: _wordSize32Align32,
// _wordSize32Align64
androidArm: _wordSize32Align64,
linuxArm: _wordSize32Align64,
windowsIA32: _wordSize32Align64,
Abi.androidArm: _wordSize32Align64,
Abi.linuxArm: _wordSize32Align64,
Abi.windowsIA32: _wordSize32Align64,
};

// All 64 bit ABIs align struct fields to their size.
Expand Down Expand Up @@ -170,6 +273,6 @@ const Map<NativeType, int> _wordSize32Align32 = {
// > compatible with structures in code compiled without that switch.
// https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
//
// ARM always requires 8 byte alignment for 8 byte values:
// Arm always requires 8 byte alignment for 8 byte values:
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf 4.1 Fundamental Data Types
const Map<NativeType, int> _wordSize32Align64 = {};
Loading

0 comments on commit 6633572

Please sign in to comment.