blob: cc2d86bafd7f45493b079aa20995825f58ad92c4 [file] [log] [blame]
// Copyright (c) 2021, 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.
import 'common.dart';
// TODO(http://dartbug.com/47823): Remove this copy of `Abi`.
/// The hardware architectures the Dart VM runs on.
enum _Architecture {
arm,
arm64,
ia32,
x64,
riscv32,
riscv64,
}
extension on _Architecture {
/// The size of integer registers and memory addresses in bytes.
int get wordSize {
switch (this) {
case _Architecture.arm:
case _Architecture.ia32:
case _Architecture.riscv32:
return 4;
case _Architecture.arm64:
case _Architecture.x64:
case _Architecture.riscv64:
return 8;
}
}
}
/// The operating systems the Dart VM runs on.
enum _OS {
android,
fuchsia,
ios,
linux,
macos,
windows,
}
/// 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 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 linux on 32-bit RISC-V.
static const linuxRiscv32 = _linuxRiscv32;
/// The application binary interface for linux on 64-bit RISC-V.
static const linuxRiscv64 = _linuxRiscv64;
/// 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,
linuxRiscv32,
linuxRiscv64,
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].
final _OS _os;
/// The architecture of this [Abi].
final _Architecture _architecture;
/// 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 _linuxRiscv32 = Abi._(_Architecture.riscv32, _OS.linux);
static const _linuxRiscv64 = Abi._(_Architecture.riscv64, _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);
}
// 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.linuxRiscv32: 'linuxRiscv32',
Abi.linuxRiscv64: 'linuxRiscv64',
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 =
Map.unmodifiable({for (final abi in Abi.values) abi: abi.wordSize});
/// 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.
///
/// 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 Map<Abi, Map<NativeType, int>> nonSizeAlignment = {
// _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.linuxRiscv64: _wordSize64,
Abi.macosArm64: _wordSize64,
Abi.macosX64: _wordSize64,
Abi.windowsArm64: _wordSize64,
Abi.windowsX64: _wordSize64,
// _wordSize32Align32
Abi.androidIA32: _wordSize32Align32,
Abi.iosArm: _wordSize32Align32,
Abi.linuxIA32: _wordSize32Align32,
// _wordSize32Align64
Abi.androidArm: _wordSize32Align64,
Abi.linuxArm: _wordSize32Align64,
Abi.linuxRiscv32: _wordSize32Align64,
Abi.windowsIA32: _wordSize32Align64,
};
// All 64 bit ABIs align struct fields to their size.
const Map<NativeType, int> _wordSize64 = {};
// x86 System V ABI:
// > uint64_t | size 8 | alignment 4
// > double | size 8 | alignment 4
// https://github.com/hjl-tools/x86-psABI/wiki/intel386-psABI-1.1.pdf page 8.
//
// ios 32 bit alignment:
// https://developer.apple.com/documentation/uikit/app_and_environment/updating_your_app_from_32-bit_to_64-bit_architecture/updating_data_structures
const Map<NativeType, int> _wordSize32Align32 = {
NativeType.kDouble: 4,
NativeType.kInt64: 4,
NativeType.kUint64: 4
};
// The default for MSVC x86:
// > The alignment-requirement for all data except structures, unions, and
// > arrays is either the size of the object or the current packing size
// > (specified with either /Zp or the pack pragma, whichever is less).
// https://docs.microsoft.com/en-us/cpp/c-language/padding-and-alignment-of-structure-members?view=vs-2019
//
// GCC _can_ compile on Linux to this alignment with -malign-double, but does
// not do so by default:
// > Warning: if you use the -malign-double switch, structures containing the
// > above types are aligned differently than the published application
// > binary interface specifications for the x86-32 and are not binary
// > 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:
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf 4.1 Fundamental Data Types
const Map<NativeType, int> _wordSize32Align64 = {};