Version 2.16.0-69.0.dev
Merge commit '663357209c3c5f3e1a68ffb3e1320801bc192a7d' into 'dev'
diff --git a/pkg/dds/lib/src/dap/adapters/dart.dart b/pkg/dds/lib/src/dap/adapters/dart.dart
index 6f24604..a703267 100644
--- a/pkg/dds/lib/src/dap/adapters/dart.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart.dart
@@ -1897,6 +1897,24 @@
/// simplest) way, but prevents the user from being able to type into `stdin`.
final String? console;
+ /// An optional tool to run instead of "dart".
+ ///
+ /// In combination with [customToolReplacesArgs] allows invoking a custom
+ /// tool instead of "dart" to launch scripts/tests. The custom tool must be
+ /// completely compatible with the tool/command it is replacing.
+ ///
+ /// This field should be a full absolute path if the tool may not be available
+ /// in `PATH`.
+ final String? customTool;
+
+ /// The number of arguments to delete from the beginning of the argument list
+ /// when invoking [customTool].
+ ///
+ /// For example, setting [customTool] to `dart_test` and
+ /// `customToolReplacesArgs` to `2` for a test run would invoke
+ /// `dart_test foo_test.dart` instead of `dart run test:test foo_test.dart`.
+ final int? customToolReplacesArgs;
+
DartLaunchRequestArguments({
this.noDebug,
required this.program,
@@ -1905,6 +1923,8 @@
this.toolArgs,
this.console,
this.enableAsserts,
+ this.customTool,
+ this.customToolReplacesArgs,
Object? restart,
String? name,
String? cwd,
@@ -1934,6 +1954,8 @@
vmServicePort = obj['vmServicePort'] as int?,
console = obj['console'] as String?,
enableAsserts = obj['enableAsserts'] as bool?,
+ customTool = obj['customTool'] as String?,
+ customToolReplacesArgs = obj['customToolReplacesArgs'] as int?,
super.fromMap(obj);
@override
@@ -1946,6 +1968,9 @@
if (vmServicePort != null) 'vmServicePort': vmServicePort,
if (console != null) 'console': console,
if (enableAsserts != null) 'enableAsserts': enableAsserts,
+ if (customTool != null) 'customTool': customTool,
+ if (customToolReplacesArgs != null)
+ 'customToolReplacesArgs': customToolReplacesArgs,
};
static DartLaunchRequestArguments fromJson(Map<String, Object?> obj) =>
diff --git a/pkg/dds/lib/src/dap/adapters/dart_cli_adapter.dart b/pkg/dds/lib/src/dap/adapters/dart_cli_adapter.dart
index 3560867..9beae08 100644
--- a/pkg/dds/lib/src/dap/adapters/dart_cli_adapter.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart_cli_adapter.dart
@@ -5,6 +5,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
+import 'dart:math' as math;
import 'package:path/path.dart' as path;
import 'package:pedantic/pedantic.dart';
@@ -76,7 +77,6 @@
/// breakpoints, and resume.
Future<void> launchImpl() async {
final args = this.args as DartLaunchRequestArguments;
- final vmPath = Platform.resolvedExecutable;
File? vmServiceInfoFile;
final debug = !(args.noDebug ?? false);
@@ -101,6 +101,14 @@
// editor-spawned debug sessions.
if (args.enableAsserts ?? true) '--enable-asserts',
];
+
+ // Handle customTool and deletion of any arguments for it.
+ final executable = args.customTool ?? Platform.resolvedExecutable;
+ final removeArgs = args.customToolReplacesArgs;
+ if (args.customTool != null && removeArgs != null) {
+ vmArgs.removeRange(0, math.min(removeArgs, vmArgs.length));
+ }
+
final processArgs = [
...vmArgs,
...?args.toolArgs,
@@ -127,9 +135,14 @@
// TODO(dantup): Support passing env to both of these.
if (terminalKind != null) {
- await launchInEditorTerminal(debug, terminalKind, vmPath, processArgs);
+ await launchInEditorTerminal(
+ debug,
+ terminalKind,
+ executable,
+ processArgs,
+ );
} else {
- await launchAsProcess(vmPath, processArgs);
+ await launchAsProcess(executable, processArgs);
}
// Delay responding until the debugger is connected.
@@ -166,11 +179,11 @@
Future<void> launchInEditorTerminal(
bool debug,
String terminalKind,
- String vmPath,
+ String executable,
List<String> processArgs,
) async {
final args = this.args as DartLaunchRequestArguments;
- logger?.call('Spawning $vmPath with $processArgs in ${args.cwd}'
+ logger?.call('Spawning $executable with $processArgs in ${args.cwd}'
' via client ${terminalKind} terminal');
// runInTerminal is a DAP request that goes from server-to-client that
@@ -179,7 +192,7 @@
// for debugging will rely on the process writing the service-info file that
// we can detect with the normal watching code.
final requestArgs = RunInTerminalRequestArguments(
- args: [vmPath, ...processArgs],
+ args: [executable, ...processArgs],
cwd: args.cwd ?? path.dirname(args.program),
kind: terminalKind,
title: args.name ?? 'Dart',
@@ -210,10 +223,13 @@
///
/// Output to `stdout`/`stderr` will be sent to the editor using
/// [OutputEvent]s.
- Future<void> launchAsProcess(String vmPath, List<String> processArgs) async {
- logger?.call('Spawning $vmPath with $processArgs in ${args.cwd}');
+ Future<void> launchAsProcess(
+ String executable,
+ List<String> processArgs,
+ ) async {
+ logger?.call('Spawning $executable with $processArgs in ${args.cwd}');
final process = await Process.start(
- vmPath,
+ executable,
processArgs,
workingDirectory: args.cwd,
);
diff --git a/pkg/dds/lib/src/dap/adapters/dart_test_adapter.dart b/pkg/dds/lib/src/dap/adapters/dart_test_adapter.dart
index 2a63b38..5b0ebfd 100644
--- a/pkg/dds/lib/src/dap/adapters/dart_test_adapter.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart_test_adapter.dart
@@ -5,6 +5,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
+import 'dart:math' as math;
import 'package:pedantic/pedantic.dart';
import 'package:vm_service/vm_service.dart' as vm;
@@ -72,7 +73,6 @@
/// breakpoints, and resume.
Future<void> launchImpl() async {
final args = this.args as DartLaunchRequestArguments;
- final vmPath = Platform.resolvedExecutable;
File? vmServiceInfoFile;
final debug = !(args.noDebug ?? false);
@@ -110,6 +110,14 @@
'-r',
'json',
];
+
+ // Handle customTool and deletion of any arguments for it.
+ final executable = args.customTool ?? Platform.resolvedExecutable;
+ final removeArgs = args.customToolReplacesArgs;
+ if (args.customTool != null && removeArgs != null) {
+ vmArgs.removeRange(0, math.min(removeArgs, vmArgs.length));
+ }
+
final processArgs = [
...vmArgs,
...?args.toolArgs,
@@ -117,11 +125,19 @@
...?args.args,
];
- // TODO(dantup): Support passing env to both of these.
+ // TODO(dantup): Support passing env.
- logger?.call('Spawning $vmPath with $processArgs in ${args.cwd}');
+ await launchAsProcess(executable, processArgs);
+ }
+
+ /// Launches the test script as a process controlled by the debug adapter.
+ Future<void> launchAsProcess(
+ String executable,
+ List<String> processArgs,
+ ) async {
+ logger?.call('Spawning $executable with $processArgs in ${args.cwd}');
final process = await Process.start(
- vmPath,
+ executable,
processArgs,
workingDirectory: args.cwd,
);
diff --git a/pkg/dds/lib/src/dap/isolate_manager.dart b/pkg/dds/lib/src/dap/isolate_manager.dart
index 6d678dc..cbf2087 100644
--- a/pkg/dds/lib/src/dap/isolate_manager.dart
+++ b/pkg/dds/lib/src/dap/isolate_manager.dart
@@ -939,7 +939,7 @@
final fileUri = Uri.file(filePath);
// Track how many segments from the path are from the lib folder to the
- // libary that will need to be removed later.
+ // library that will need to be removed later.
final libraryPathSegments = uri.pathSegments.length - 1;
// It should never be the case that the returned value doesn't have at
diff --git a/pkg/dds/test/dap/dart_cli_test.dart b/pkg/dds/test/dap/dart_cli_test.dart
new file mode 100644
index 0000000..26e56c5
--- /dev/null
+++ b/pkg/dds/test/dap/dart_cli_test.dart
@@ -0,0 +1,79 @@
+// 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 'dart:async';
+import 'dart:io';
+
+import 'package:dds/dap.dart';
+import 'package:test/test.dart';
+
+import 'mocks.dart';
+
+main() {
+ group('dart cli adapter', () {
+ test('includes toolArgs', () async {
+ final adapter = MockDartCliDebugAdapter();
+ final responseCompleter = Completer<void>();
+ final request = MockRequest();
+ final args = DartLaunchRequestArguments(
+ program: 'foo.dart',
+ toolArgs: ['tool_arg'],
+ noDebug: true,
+ );
+
+ await adapter.configurationDoneRequest(request, null, () {});
+ await adapter.launchRequest(request, args, responseCompleter.complete);
+ await responseCompleter.future;
+
+ expect(adapter.executable, equals(Platform.resolvedExecutable));
+ expect(adapter.processArgs, contains('tool_arg'));
+ });
+
+ group('includes customTool', () {
+ test('with no args replaced', () async {
+ final adapter = MockDartCliDebugAdapter();
+ final responseCompleter = Completer<void>();
+ final request = MockRequest();
+ final args = DartLaunchRequestArguments(
+ program: 'foo.dart',
+ customTool: '/custom/dart',
+ noDebug: true,
+ enableAsserts: true, // to check args are still passed through
+ );
+
+ await adapter.configurationDoneRequest(request, null, () {});
+ await adapter.launchRequest(request, args, responseCompleter.complete);
+ await responseCompleter.future;
+
+ expect(adapter.executable, equals('/custom/dart'));
+ // args should be in-tact
+ expect(adapter.processArgs, contains('--enable-asserts'));
+ });
+
+ test('with all args replaced', () async {
+ final adapter = MockDartCliDebugAdapter();
+ final responseCompleter = Completer<void>();
+ final request = MockRequest();
+ final args = DartLaunchRequestArguments(
+ program: 'foo.dart',
+ customTool: '/custom/dart',
+ customToolReplacesArgs: 9999, // replaces all built-in args
+ noDebug: true,
+ enableAsserts: true, // should not be in args
+ toolArgs: ['tool_args'], // should still be in args
+ );
+
+ await adapter.configurationDoneRequest(request, null, () {});
+ await adapter.launchRequest(request, args, responseCompleter.complete);
+ await responseCompleter.future;
+
+ expect(adapter.executable, equals('/custom/dart'));
+ // normal built-in args are replaced by customToolReplacesArgs, but
+ // user-provided toolArgs are not.
+ expect(adapter.processArgs, isNot(contains('--enable-asserts')));
+ expect(adapter.processArgs, contains('tool_args'));
+ });
+ });
+ });
+}
diff --git a/pkg/dds/test/dap/dart_test_test.dart b/pkg/dds/test/dap/dart_test_test.dart
new file mode 100644
index 0000000..eac0a34
--- /dev/null
+++ b/pkg/dds/test/dap/dart_test_test.dart
@@ -0,0 +1,81 @@
+// 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 'dart:async';
+import 'dart:io';
+
+import 'package:dds/dap.dart';
+import 'package:test/test.dart';
+
+import 'mocks.dart';
+
+main() {
+ group('dart test adapter', () {
+ test('includes toolArgs', () async {
+ final adapter = MockDartTestDebugAdapter();
+ final responseCompleter = Completer<void>();
+ final request = MockRequest();
+ final args = DartLaunchRequestArguments(
+ program: 'foo.dart',
+ toolArgs: ['tool_arg'],
+ noDebug: true,
+ );
+
+ await adapter.configurationDoneRequest(request, null, () {});
+ await adapter.launchRequest(request, args, responseCompleter.complete);
+ await responseCompleter.future;
+
+ expect(adapter.executable, equals(Platform.resolvedExecutable));
+ expect(adapter.processArgs, containsAllInOrder(['run', 'test:test']));
+ expect(adapter.processArgs, contains('tool_arg'));
+ });
+
+ group('includes customTool', () {
+ test('with no args replaced', () async {
+ final adapter = MockDartTestDebugAdapter();
+ final responseCompleter = Completer<void>();
+ final request = MockRequest();
+ final args = DartLaunchRequestArguments(
+ program: 'foo.dart',
+ customTool: '/custom/dart',
+ noDebug: true,
+ );
+
+ await adapter.configurationDoneRequest(request, null, () {});
+ await adapter.launchRequest(request, args, responseCompleter.complete);
+ await responseCompleter.future;
+
+ expect(adapter.executable, equals('/custom/dart'));
+ // args should be in-tact
+ expect(adapter.processArgs, containsAllInOrder(['run', 'test:test']));
+ });
+
+ test('with all args replaced', () async {
+ final adapter = MockDartTestDebugAdapter();
+ final responseCompleter = Completer<void>();
+ final request = MockRequest();
+ final args = DartLaunchRequestArguments(
+ program: 'foo.dart',
+ customTool: '/custom/dart',
+ customToolReplacesArgs: 9999, // replaces all built-in args
+ noDebug: true,
+ toolArgs: ['tool_args'], // should still be in args
+ );
+
+ await adapter.configurationDoneRequest(request, null, () {});
+ await adapter.launchRequest(request, args, responseCompleter.complete);
+ await responseCompleter.future;
+
+ expect(adapter.executable, equals('/custom/dart'));
+ // normal built-in args are replaced by customToolReplacesArgs, but
+ // user-provided toolArgs are not.
+ expect(
+ adapter.processArgs,
+ isNot(containsAllInOrder(['run', 'test:test'])),
+ );
+ expect(adapter.processArgs, contains('tool_args'));
+ });
+ });
+ });
+}
diff --git a/pkg/dds/test/dap/mocks.dart b/pkg/dds/test/dap/mocks.dart
new file mode 100644
index 0000000..954f25d
--- /dev/null
+++ b/pkg/dds/test/dap/mocks.dart
@@ -0,0 +1,97 @@
+// 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 'dart:async';
+
+import 'package:dds/dap.dart';
+import 'package:dds/src/dap/adapters/dart_cli_adapter.dart';
+import 'package:dds/src/dap/adapters/dart_test_adapter.dart';
+
+/// A [DartCliDebugAdapter] that captures what process/args will be launched.
+class MockDartCliDebugAdapter extends DartCliDebugAdapter {
+ final StreamSink<List<int>> stdin;
+ final Stream<List<int>> stdout;
+
+ late bool launchedInTerminal;
+ late String executable;
+ late List<String> processArgs;
+
+ factory MockDartCliDebugAdapter() {
+ final stdinController = StreamController<List<int>>();
+ final stdoutController = StreamController<List<int>>();
+ final channel = ByteStreamServerChannel(
+ stdinController.stream, stdoutController.sink, null);
+
+ return MockDartCliDebugAdapter._(
+ stdinController.sink, stdoutController.stream, channel);
+ }
+
+ MockDartCliDebugAdapter._(
+ this.stdin, this.stdout, ByteStreamServerChannel channel)
+ : super(channel);
+
+ Future<void> launchAsProcess(
+ String executable,
+ List<String> processArgs,
+ ) async {
+ this.launchedInTerminal = false;
+ this.executable = executable;
+ this.processArgs = processArgs;
+ }
+
+ Future<void> launchInEditorTerminal(
+ bool debug,
+ String terminalKind,
+ String executable,
+ List<String> processArgs,
+ ) async {
+ this.launchedInTerminal = true;
+ this.executable = executable;
+ this.processArgs = processArgs;
+ }
+}
+
+/// A [DartTestDebugAdapter] that captures what process/args will be launched.
+class MockDartTestDebugAdapter extends DartTestDebugAdapter {
+ final StreamSink<List<int>> stdin;
+ final Stream<List<int>> stdout;
+
+ late String executable;
+ late List<String> processArgs;
+
+ factory MockDartTestDebugAdapter() {
+ final stdinController = StreamController<List<int>>();
+ final stdoutController = StreamController<List<int>>();
+ final channel = ByteStreamServerChannel(
+ stdinController.stream, stdoutController.sink, null);
+
+ return MockDartTestDebugAdapter._(
+ stdinController.sink,
+ stdoutController.stream,
+ channel,
+ );
+ }
+
+ MockDartTestDebugAdapter._(
+ this.stdin, this.stdout, ByteStreamServerChannel channel)
+ : super(channel);
+
+ Future<void> launchAsProcess(
+ String executable,
+ List<String> processArgs,
+ ) async {
+ this.executable = executable;
+ this.processArgs = processArgs;
+ }
+}
+
+class MockRequest extends Request {
+ static var _requestId = 1;
+ MockRequest()
+ : super.fromMap({
+ 'command': 'mock_command',
+ 'type': 'mock_type',
+ 'seq': _requestId++,
+ });
+}
diff --git a/pkg/dds/tool/dap/README.md b/pkg/dds/tool/dap/README.md
index ac86324..5dd4e54 100644
--- a/pkg/dds/tool/dap/README.md
+++ b/pkg/dds/tool/dap/README.md
@@ -38,6 +38,9 @@
- `List<String>? toolArgs` - arguments for the Dart VM
- `String? console` - if set to `"terminal"` or `"externalTerminal"` will be run using the `runInTerminal` reverse-request; otherwise the debug adapter spawns the Dart process
- `bool? enableAsserts` - whether to enable asserts (if not supplied, defaults to enabled)
+- `String? customTool` - an optional tool to run instead of `dart` - the custom tool must be completely compatible with the tool/command it is replacing
+- `int? customToolReplacesArgs` - the number of arguments to delete from the beginning of the argument list when invoking `customTool` - e.g. setting `customTool` to `dart_test` and
+ `customToolReplacesArgs` to `2` for a test run would invoke `dart_test foo_test.dart` instead of `dart run test:test foo_test.dart` (if larger than the number of computed arguments all arguments will be removed, if not supplied will default to `0`)
Arguments specific to `attachRequest` are:
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.1.expect
index 1c2210e..4e4f764 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.1.expect
@@ -39,6 +39,7 @@
ffi::unsized,
ffi::sizeOf,
ffi::Dart_NativeMessageHandler,
+ ffi::Abi,
ffi::Allocator,
ffi::AllocatorAlloc,
ffi::Array,
@@ -112,6 +113,7 @@
ffi::unsized,
ffi::sizeOf,
ffi::Dart_NativeMessageHandler,
+ ffi::Abi,
ffi::Allocator,
ffi::AllocatorAlloc,
ffi::Array,
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.2.expect
index ae09732..ead3ad4 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_50_ffi.yaml.world.2.expect
@@ -39,6 +39,7 @@
ffi::unsized,
ffi::sizeOf,
ffi::Dart_NativeMessageHandler,
+ ffi::Abi,
ffi::Allocator,
ffi::AllocatorAlloc,
ffi::Array,
@@ -112,6 +113,7 @@
ffi::unsized,
ffi::sizeOf,
ffi::Dart_NativeMessageHandler,
+ ffi::Abi,
ffi::Allocator,
ffi::AllocatorAlloc,
ffi::Array,
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
index 0a88f78..0f9dc6d 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
@@ -25,5 +25,5 @@
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)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
index 0dc519f..edf8c40 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
@@ -52,5 +52,5 @@
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)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
index c47d067..732d282 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
@@ -25,5 +25,5 @@
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)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
index 6a48895..a445d62 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
@@ -52,5 +52,5 @@
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)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect
index 0dd2727..eaeea63 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect
@@ -33,5 +33,5 @@
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)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
index 036c491..c77db0d 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
@@ -84,5 +84,5 @@
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)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect
index 8c3d96b..b6819cb 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect
@@ -33,5 +33,5 @@
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)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
index 8d6be3c..7de8504 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
@@ -84,5 +84,5 @@
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)
diff --git a/pkg/vm/lib/transformations/ffi/abi.dart b/pkg/vm/lib/transformations/ffi/abi.dart
index 795574a..04bc8e2 100644
--- a/pkg/vm/lib/transformations/ffi/abi.dart
+++ b/pkg/vm/lib/transformations/ffi/abi.dart
@@ -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,
@@ -36,108 +38,209 @@
windows,
}
-/// Application binary interface.
+/// An application binary interface (ABI).
///
-/// The Dart VM can run on a variety of [Abi]s, see [supportedAbis].
+/// 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 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.
///
-/// Has an entry for all Abis. Empty entries document that every native
-/// type is aligned to it's own size in this ABI.
+/// 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 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.
@@ -170,6 +273,6 @@
// > 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 = {};
diff --git a/pkg/vm/lib/transformations/ffi/common.dart b/pkg/vm/lib/transformations/ffi/common.dart
index 7627a59..54ffd5c 100644
--- a/pkg/vm/lib/transformations/ffi/common.dart
+++ b/pkg/vm/lib/transformations/ffi/common.dart
@@ -547,7 +547,7 @@
return InstanceInvocation(
InstanceAccessKind.Instance,
intListConstantExpression([
- for (final abi in supportedAbisOrdered) values[abi]!,
+ for (final abi in Abi.values) values[abi]!,
]),
listElementAt.name,
Arguments([StaticInvocation(abiMethod, Arguments([]))]),
diff --git a/pkg/vm/lib/transformations/ffi/definitions.dart b/pkg/vm/lib/transformations/ffi/definitions.dart
index c11b710..29ae1d9 100644
--- a/pkg/vm/lib/transformations/ffi/definitions.dart
+++ b/pkg/vm/lib/transformations/ffi/definitions.dart
@@ -849,8 +849,7 @@
void _addSizeOfField(Class compound, IndexedClass? indexedClass,
[Map<Abi, int>? sizes = null]) {
if (sizes == null) {
- sizes =
- Map.fromEntries(supportedAbisOrdered.map((abi) => MapEntry(abi, 0)));
+ sizes = {for (var abi in Abi.values) abi: 0};
}
final name = Name("#sizeOf");
final getterReference = indexedClass?.lookupGetterReference(name);
@@ -1096,14 +1095,14 @@
if (size == WORD_SIZE) {
return wordSize;
}
- return Map.fromEntries(
- supportedAbisOrdered.map((abi) => MapEntry(abi, size)));
+ return {for (var abi in Abi.values) abi: size};
}
@override
- Map<Abi, int> get alignment =>
- Map.fromEntries(supportedAbisOrdered.map((abi) =>
- MapEntry(abi, nonSizeAlignment[abi]![nativeType] ?? size[abi]!)));
+ Map<Abi, int> get alignment => {
+ for (var abi in Abi.values)
+ abi: nonSizeAlignment[abi]![nativeType] ?? size[abi]!
+ };
@override
Constant generateConstant(FfiTransformer transformer) =>
@@ -1324,8 +1323,9 @@
factory StructNativeTypeCfe(Class clazz, List<NativeTypeCfe> members,
{int? packing}) {
- final layout = Map.fromEntries(supportedAbisOrdered
- .map((abi) => MapEntry(abi, _calculateLayout(members, packing, abi))));
+ final layout = {
+ for (var abi in Abi.values) abi: _calculateLayout(members, packing, abi)
+ };
return StructNativeTypeCfe._(clazz, members, packing, layout);
}
@@ -1360,8 +1360,9 @@
class UnionNativeTypeCfe extends CompoundNativeTypeCfe {
factory UnionNativeTypeCfe(Class clazz, List<NativeTypeCfe> members) {
- final layout = Map.fromEntries(supportedAbisOrdered
- .map((abi) => MapEntry(abi, _calculateLayout(members, abi))));
+ final layout = {
+ for (var abi in Abi.values) abi: _calculateLayout(members, abi)
+ };
return UnionNativeTypeCfe._(clazz, members, layout);
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
index 463adf9..db77666 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
@@ -22,6 +22,6 @@
synthetic constructor •() → self::Class
: super core::Object::•()
;
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3252,getterSelectorId:3253] method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::Enum e) → core::int
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3254,getterSelectorId:3255] method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::Enum e) → core::int
return [@vm.inferred-type.metadata=!] e.{core::_Enum::index}{core::int};
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
index 3a69351..3aa20dc 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
@@ -51,6 +51,6 @@
synthetic constructor •() → self::ConstClass
: super core::Object::•()
;
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3256,getterSelectorId:3257] method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::ConstEnum e) → core::int
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3258,getterSelectorId:3259] method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::ConstEnum e) → core::int
return [@vm.inferred-type.metadata=!] e.{core::_Enum::index}{core::int};
}
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index 8816c44..14180b6 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -228,6 +228,14 @@
"Recognized method: IR graph is built in the flow graph builder.")
external int _abi();
+@patch
+@pragma("vm:entry-point")
+class Abi {
+ @patch
+ @pragma("vm:prefer-inline")
+ factory Abi.current() => values[_abi()];
+}
+
/// Copies data byte-wise from [source] to [target].
///
/// [source] and [target] should either be [Pointer] or [TypedData].
@@ -943,14 +951,14 @@
@patch
T operator [](int index) {
throw ArgumentError(
- "S ($T) should be a subtype of Struct at compile-time.");
+ "T ($T) should be a subtype of Struct at compile-time.");
}
}
extension UnionArray<T extends Union> on Array<T> {
@patch
T operator [](int index) {
- throw ArgumentError("S ($T) should be a subtype of Union at compile-time.");
+ throw ArgumentError("T ($T) should be a subtype of Union at compile-time.");
}
}
diff --git a/sdk/lib/ffi/abi.dart b/sdk/lib/ffi/abi.dart
new file mode 100644
index 0000000..f5cba04
--- /dev/null
+++ b/sdk/lib/ffi/abi.dart
@@ -0,0 +1,160 @@
+// 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.
+
+part of dart.ffi;
+
+/// 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 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.
+ ///
+ /// Does not contain a `macosIA32`. We have stopped supporting 32-bit MacOS.
+ ///
+ /// Includes [windowsArm64], even though it is currently not supported.
+ /// Support has been requested for Flutter.
+ /// https://github.com/flutter/flutter/issues/53120
+ // TODO(http://dartbug.com/47824): Remove the above comment when supported.
+ 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 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 _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);
+}
+
+/// The hardware architectures the Dart VM runs on.
+enum _Architecture {
+ arm,
+ arm64,
+ ia32,
+ x64,
+}
+
+/// The operating systems the Dart VM runs on.
+enum _OS {
+ android,
+ fuchsia,
+ ios,
+ linux,
+ macos,
+ windows,
+}
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index fa98c88..d3d19c2 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -15,12 +15,13 @@
import 'dart:isolate';
import 'dart:typed_data';
-part "native_type.dart";
-part "allocation.dart";
-part "annotations.dart";
-part "dynamic_library.dart";
-part "struct.dart";
-part "union.dart";
+part 'abi.dart';
+part 'native_type.dart';
+part 'allocation.dart';
+part 'annotations.dart';
+part 'dynamic_library.dart';
+part 'struct.dart';
+part 'union.dart';
/// Number of bytes used by native type T.
///
@@ -29,12 +30,12 @@
/// This function must be invoked with a compile-time constant [T].
external int sizeOf<T extends NativeType>();
-/// Represents a pointer into the native C memory corresponding to "NULL", e.g.
+/// Represents a pointer into the native C memory corresponding to 'NULL', e.g.
/// a pointer with address 0.
final Pointer<Never> nullptr = Pointer.fromAddress(0);
/// Represents a pointer into the native C memory. Cannot be extended.
-@pragma("vm:entry-point")
+@pragma('vm:entry-point')
class Pointer<T extends NativeType> extends NativeType {
/// Construction from raw integer.
external factory Pointer.fromAddress(int ptr);
@@ -56,7 +57,7 @@
/// Does not accept dynamic invocations -- where the type of the receiver is
/// [dynamic].
external static Pointer<NativeFunction<T>> fromFunction<T extends Function>(
- @DartRepresentationOf("T") Function f,
+ @DartRepresentationOf('T') Function f,
[Object? exceptionalReturn]);
/// Access to the raw pointer value.
@@ -150,7 +151,7 @@
on Pointer<NativeFunction<NF>> {
/// Convert to Dart function, automatically marshalling the arguments
/// and return value.
- external DF asFunction<@DartRepresentationOf("NF") DF extends Function>(
+ external DF asFunction<@DartRepresentationOf('NF') DF extends Function>(
{bool isLeaf: false});
}
@@ -827,7 +828,7 @@
///
/// Example:
///```dart template:none
-/// @FfiNative<Int64 Function(Int64, Int64)>("FfiNative_Sum", isLeaf:true)
+/// @FfiNative<Int64 Function(Int64, Int64)>('FfiNative_Sum', isLeaf:true)
/// external int sum(int a, int b);
///```
/// Calling such functions will throw an exception if no resolver
@@ -844,7 +845,7 @@
// Bootstrapping native for getting the FFI native C function pointer to look
// up the FFI resolver.
-@pragma("vm:external-name", "Ffi_GetFfiNativeResolver")
+@pragma('vm:external-name', 'Ffi_GetFfiNativeResolver')
external Pointer<NativeFunction<IntPtr Function(Handle, Handle, IntPtr)>>
_get_ffi_native_resolver<T extends NativeFunction>();
diff --git a/sdk/lib/ffi/ffi_sources.gni b/sdk/lib/ffi/ffi_sources.gni
index 4152f91..f7b2838 100644
--- a/sdk/lib/ffi/ffi_sources.gni
+++ b/sdk/lib/ffi/ffi_sources.gni
@@ -6,6 +6,7 @@
"ffi.dart",
# The above file needs to be first as it lists the parts below.
+ "abi.dart",
"allocation.dart",
"annotations.dart",
"dynamic_library.dart",
diff --git a/tests/ffi/abi_test.dart b/tests/ffi/abi_test.dart
new file mode 100644
index 0000000..15c6776
--- /dev/null
+++ b/tests/ffi/abi_test.dart
@@ -0,0 +1,24 @@
+// 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 'dart:ffi';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+
+void main() {
+ testCurrent();
+ testPlatformVersionCompatibility();
+}
+
+void testCurrent() {
+ final currentAbi = Abi.current();
+ Expect.isTrue(Abi.values.contains(currentAbi));
+}
+
+void testPlatformVersionCompatibility() {
+ final abiStringFromPlatformVersion = Platform.version.split('"')[1];
+ final abiStringFromCurrent = Abi.current().toString();
+ Expect.equals(abiStringFromPlatformVersion, abiStringFromCurrent);
+}
diff --git a/tests/ffi_2/abi_test.dart b/tests/ffi_2/abi_test.dart
new file mode 100644
index 0000000..d9c152e
--- /dev/null
+++ b/tests/ffi_2/abi_test.dart
@@ -0,0 +1,26 @@
+// 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.
+
+// @dart = 2.9
+
+import 'dart:ffi';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+
+void main() {
+ testCurrent();
+ testPlatformVersionCompatibility();
+}
+
+void testCurrent() {
+ final currentAbi = Abi.current();
+ Expect.isTrue(Abi.values.contains(currentAbi));
+}
+
+void testPlatformVersionCompatibility() {
+ final abiStringFromPlatformVersion = Platform.version.split('"')[1];
+ final abiStringFromCurrent = Abi.current().toString();
+ Expect.equals(abiStringFromPlatformVersion, abiStringFromCurrent);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 3f42e93..4d4dd33 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 68
+PRERELEASE 69
PRERELEASE_PATCH 0
\ No newline at end of file