Version 2.12.0-57.0.dev
Merge commit 'b0ccaf75a3e189bf566efcb6bc9872ea0ab75120' into 'dev'
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index d8894c8..f000bb7 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -8,7 +8,6 @@
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
-import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 59aaebb..e72baca 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -9,7 +9,6 @@
import 'package:analysis_server/src/services/completion/dart/contribution_sorter.dart';
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
-import 'package:analyzer_plugin/protocol/protocol_constants.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/edit/assists_test.dart b/pkg/analysis_server/test/edit/assists_test.dart
index 438a81e..3ab55f3 100644
--- a/pkg/analysis_server/test/edit/assists_test.dart
+++ b/pkg/analysis_server/test/edit/assists_test.dart
@@ -8,7 +8,6 @@
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
-import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index 19588f5..660af49 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -8,7 +8,6 @@
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
-import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 64e8480..006ce0b 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -23,7 +23,6 @@
import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
-import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
diff --git a/pkg/analysis_server/test/plugin/protocol_dart_test.dart b/pkg/analysis_server/test/plugin/protocol_dart_test.dart
index 2fdf1c5..d693387 100644
--- a/pkg/analysis_server/test/plugin/protocol_dart_test.dart
+++ b/pkg/analysis_server/test/plugin/protocol_dart_test.dart
@@ -4,14 +4,8 @@
import 'package:analysis_server/plugin/protocol/protocol_dart.dart';
import 'package:analyzer/dart/ast/ast.dart' as engine;
-import 'package:analyzer/dart/ast/visitor.dart' as engine;
import 'package:analyzer/dart/element/element.dart' as engine;
-import 'package:analyzer/dart/element/type.dart' as engine;
-import 'package:analyzer/error/error.dart' as engine;
-import 'package:analyzer/src/dart/ast/utilities.dart' as engine;
import 'package:analyzer/src/dart/element/element.dart' as engine;
-import 'package:analyzer/src/error/codes.dart' as engine;
-import 'package:analyzer/src/generated/source.dart' as engine;
import 'package:analyzer/src/generated/testing/element_search.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
diff --git a/pkg/analysis_server/test/protocol_server_test.dart b/pkg/analysis_server/test/protocol_server_test.dart
index 0ce5609..b355d68 100644
--- a/pkg/analysis_server/test/protocol_server_test.dart
+++ b/pkg/analysis_server/test/protocol_server_test.dart
@@ -9,9 +9,7 @@
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
-import 'package:analyzer/dart/ast/ast.dart' as engine;
import 'package:analyzer/dart/element/element.dart' as engine;
-import 'package:analyzer/dart/element/type.dart' as engine;
import 'package:analyzer/diagnostic/diagnostic.dart';
import 'package:analyzer/error/error.dart' as engine;
import 'package:analyzer/src/dart/analysis/results.dart' as engine;
diff --git a/pkg/analysis_server/test/src/domain_abstract_test.dart b/pkg/analysis_server/test/src/domain_abstract_test.dart
index eb1fdb9..46c9aa6 100644
--- a/pkg/analysis_server/test/src/domain_abstract_test.dart
+++ b/pkg/analysis_server/test/src/domain_abstract_test.dart
@@ -6,7 +6,6 @@
import 'package:analysis_server/src/plugin/plugin_manager.dart';
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
-import 'package:analyzer_plugin/protocol/protocol_constants.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/plugin/notification_manager_test.dart b/pkg/analysis_server/test/src/plugin/notification_manager_test.dart
index 88fd799..3157c0c 100644
--- a/pkg/analysis_server/test/src/plugin/notification_manager_test.dart
+++ b/pkg/analysis_server/test/src/plugin/notification_manager_test.dart
@@ -7,9 +7,7 @@
import 'package:analysis_server/src/channel/channel.dart';
import 'package:analysis_server/src/plugin/notification_manager.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
-import 'package:analyzer_plugin/protocol/protocol_constants.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/plugin/request_converter_test.dart b/pkg/analysis_server/test/src/plugin/request_converter_test.dart
index 78d9858..7ba3049 100644
--- a/pkg/analysis_server/test/src/plugin/request_converter_test.dart
+++ b/pkg/analysis_server/test/src/plugin/request_converter_test.dart
@@ -4,7 +4,6 @@
import 'package:analysis_server/protocol/protocol_generated.dart' as server;
import 'package:analysis_server/src/plugin/request_converter.dart';
-import 'package:analysis_server/src/protocol/protocol_internal.dart' as server;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:test/test.dart';
diff --git a/pkg/analysis_server/test/src/plugin/result_converter_test.dart b/pkg/analysis_server/test/src/plugin/result_converter_test.dart
index d45118b..220ca9a 100644
--- a/pkg/analysis_server/test/src/plugin/result_converter_test.dart
+++ b/pkg/analysis_server/test/src/plugin/result_converter_test.dart
@@ -4,7 +4,6 @@
import 'package:analysis_server/protocol/protocol_generated.dart' as server;
import 'package:analysis_server/src/plugin/result_converter.dart';
-import 'package:analysis_server/src/protocol/protocol_internal.dart' as server;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:test/test.dart';
diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
index e2229b4..a97d843 100644
--- a/pkg/dartdev/lib/dartdev.dart
+++ b/pkg/dartdev/lib/dartdev.dart
@@ -156,8 +156,10 @@
final Analytics analytics;
@override
- final ArgParser argParser =
- ArgParser(usageLineLength: dartdevUsageLineLength);
+ final ArgParser argParser = ArgParser(
+ usageLineLength: dartdevUsageLineLength,
+ allowTrailingOptions: false,
+ );
static const String dartdevDescription =
'A command-line utility for Dart development';
diff --git a/pkg/dartdev/lib/src/commands/fix.dart b/pkg/dartdev/lib/src/commands/fix.dart
index 11dbee4..9f4d350 100644
--- a/pkg/dartdev/lib/src/commands/fix.dart
+++ b/pkg/dartdev/lib/src/commands/fix.dart
@@ -6,6 +6,7 @@
import 'dart:io' as io;
import 'package:analysis_server_client/protocol.dart' hide AnalysisError;
+import 'package:intl/intl.dart';
import 'package:path/path.dart' as path;
import '../analysis_server.dart';
@@ -26,8 +27,8 @@
@override
FutureOr<int> run() async {
- log.stdout('\n*** The `fix` command is provisional and subject to change '
- 'or removal in future releases. ***\n');
+ log.stdout('\n${log.ansi.emphasized('Note:')} The `fix` command is '
+ 'provisional and subject to change or removal in future releases.\n');
var dryRun = argResults['dry-run'];
if (argResults.rest.length - (dryRun ? 1 : 0) > 1) {
@@ -43,8 +44,9 @@
var modeText = dryRun ? ' (dry run)' : '';
+ final projectName = path.basename(path.canonicalize(dir.path));
var progress = log.progress(
- 'Computing fixes in ${path.basename(path.canonicalize(dir.path))}$modeText');
+ 'Computing fixes in ${log.ansi.emphasized(projectName)}$modeText');
var server = AnalysisServer(
io.Directory(sdk.sdkPath),
@@ -88,22 +90,30 @@
});
});
- log.stdout(
- '\n$fixCount proposed ${_pluralFix(fixCount)} in $fileCount ${pluralize("file", fileCount)}.\n');
+ log.stdout('');
+
+ final bullet = log.ansi.bullet;
for (var detail in details) {
log.stdout(path.relative(detail.path, from: dir.path));
- for (var fix in detail.fixes) {
- log.stdout(
- ' ${fix.code} • ${fix.occurrences} ${_pluralFix(fix.occurrences)}');
+ final fixes = detail.fixes.toList();
+ fixes.sort((a, b) => a.code.compareTo(b.code));
+ for (var fix in fixes) {
+ log.stdout(' ${fix.code} $bullet '
+ '${_format(fix.occurrences)} ${_pluralFix(fix.occurrences)}');
}
+ log.stdout('');
}
+
+ log.stdout('${_format(fixCount)} proposed ${_pluralFix(fixCount)} '
+ 'in ${_format(fileCount)} ${pluralize("file", fileCount)}.');
} else {
progress = log.progress('Applying fixes');
var fileCount = await _applyFixes(edits);
progress.finish(showTiming: true);
if (fileCount > 0) {
- log.stdout('Fixed $fileCount ${pluralize("file", fileCount)}.');
+ log.stdout(
+ 'Fixed ${_format(fileCount)} ${pluralize("file", fileCount)}.');
}
}
}
@@ -125,4 +135,8 @@
}
String _pluralFix(int count) => count == 1 ? 'fix' : 'fixes';
+
+ static final NumberFormat _numberFormat = NumberFormat.decimalPattern();
+
+ static String _format(int value) => _numberFormat.format(value);
}
diff --git a/pkg/dartdev/pubspec.yaml b/pkg/dartdev/pubspec.yaml
index aea30a3..d6347db 100644
--- a/pkg/dartdev/pubspec.yaml
+++ b/pkg/dartdev/pubspec.yaml
@@ -15,6 +15,7 @@
dart2native:
path: ../dart2native
dart_style: any
+ intl: any
meta:
path: ../meta
nnbd_migration:
diff --git a/pkg/dartdev/test/commands/fix_test.dart b/pkg/dartdev/test/commands/fix_test.dart
index 101edbf..ff885d6 100644
--- a/pkg/dartdev/test/commands/fix_test.dart
+++ b/pkg/dartdev/test/commands/fix_test.dart
@@ -4,6 +4,7 @@
import 'dart:io';
+import 'package:cli_util/cli_logging.dart';
import 'package:test/test.dart';
import '../utils.dart';
@@ -15,6 +16,8 @@
void defineFix() {
TestProject p;
+ final bullet = Logger.standard().ansi.bullet;
+
setUp(() => p = null);
tearDown(() => p?.dispose());
@@ -67,8 +70,8 @@
expect(result.stderr, isEmpty);
expect(result.stdout, contains('3 proposed fixes in 1 file.'));
expect(result.stdout, contains('lib${Platform.pathSeparator}main.dart'));
- expect(result.stdout, contains(' annotate_overrides • 1 fix'));
- expect(result.stdout, contains(' prefer_single_quotes • 2 fixes'));
+ expect(result.stdout, contains(' annotate_overrides $bullet 1 fix'));
+ expect(result.stdout, contains(' prefer_single_quotes $bullet 2 fixes'));
});
test('.', () {
diff --git a/pkg/dartdev/test/no_such_file_test.dart b/pkg/dartdev/test/no_such_file_test.dart
new file mode 100644
index 0000000..1641dfc
--- /dev/null
+++ b/pkg/dartdev/test/no_such_file_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2020, 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 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+ TestProject p;
+
+ tearDown(() => p?.dispose());
+
+ test('Ensure parsing fails after encountering invalid file', () {
+ // Regression test for https://github.com/dart-lang/sdk/issues/43991
+ p = project();
+ final noArgsResult = p.runSync('foo.dart', []);
+ expect(noArgsResult.stderr, isNotEmpty);
+ expect(noArgsResult.stdout, isEmpty);
+ expect(noArgsResult.exitCode, 64);
+
+ final argsResult = p.runSync('foo.dart', ['--bar']);
+ expect(argsResult.stderr, noArgsResult.stderr);
+ expect(argsResult.stdout, isEmpty);
+ expect(argsResult.exitCode, 64);
+ });
+
+ test('Providing --snapshot VM option with invalid script fails gracefully',
+ () {
+ // Regression test for https://github.com/dart-lang/sdk/issues/43785
+ p = project();
+ final result = p.runSync('--snapshot=abc', ['foo.dart']);
+ expect(result.stderr, isNotEmpty);
+ expect(result.stderr,
+ contains("Error when reading 'foo.dart': No such file or directory"));
+ expect(result.stdout, isEmpty);
+ expect(result.exitCode, 254);
+ });
+}
diff --git a/pkg/dartdev/test/test_all.dart b/pkg/dartdev/test/test_all.dart
index 291bd05..2576ac9 100644
--- a/pkg/dartdev/test/test_all.dart
+++ b/pkg/dartdev/test/test_all.dart
@@ -18,6 +18,7 @@
import 'commands/test_test.dart' as test;
import 'core_test.dart' as core;
import 'experiments_test.dart' as experiments;
+import 'no_such_file_test.dart' as no_such_file;
import 'sdk_test.dart' as sdk;
import 'smoke/implicit_smoke_test.dart' as implicit_smoke;
import 'smoke/invalid_smoke_test.dart' as invalid_smoke;
@@ -37,6 +38,7 @@
implicit_smoke.main();
invalid_smoke.main();
migrate.main();
+ no_such_file.main();
pub.main();
run.main();
compile.main();
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
index 92cca7c..eb746a7 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
@@ -12,7 +12,6 @@
import 'package:_fe_analyzer_shared/src/messages/codes.dart' show Message, Code;
import 'package:dev_compiler/dev_compiler.dart';
-import 'package:dev_compiler/src/compiler/js_names.dart' as js_ast;
import 'package:dev_compiler/src/js_ast/js_ast.dart' as js_ast;
import 'package:dev_compiler/src/kernel/compiler.dart';
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index eb2f225..d22ded9 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -151,8 +151,7 @@
ChangedStructureNotifier changedStructureNotifier}) {
for (var library in libraries) {
_CovarianceTransformer(library).transform();
- JsInteropChecks(
- coreTypes,
+ JsInteropChecks(coreTypes,
diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>)
.visitLibrary(library);
}
diff --git a/runtime/bin/ffi_test/ffi_test_functions.cc b/runtime/bin/ffi_test/ffi_test_functions.cc
index 3304154..57d6a01 100644
--- a/runtime/bin/ffi_test/ffi_test_functions.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions.cc
@@ -610,8 +610,8 @@
}
// A struct designed to exercise all kinds of alignment rules.
-// Note that offset32A (System V ia32) aligns doubles on 4 bytes while offset32B
-// (Arm 32 bit and MSVC ia32) aligns on 8 bytes.
+// Note that offset32A (System V ia32, iOS arm) aligns doubles on 4 bytes while
+// offset32B (Arm 32 bit and MSVC ia32) aligns on 8 bytes.
// TODO(37271): Support nested structs.
// TODO(37470): Add uncommon primitive data types when we want to support them.
struct VeryLargeStruct {
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index 452346f..2e962c1 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -478,6 +478,7 @@
bool is_potential_file_path = true;
#endif // !defined(DART_PRECOMPILED_RUNTIME)
if (Options::disable_dart_dev() ||
+ (Options::snapshot_filename() != nullptr) ||
(is_potential_file_path && !enable_vm_service_)) {
*script_name = Utils::StrDup(argv[i]);
run_script = true;
diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni
index c4572df..ad10b9c 100644
--- a/runtime/vm/compiler/compiler_sources.gni
+++ b/runtime/vm/compiler/compiler_sources.gni
@@ -179,6 +179,7 @@
"backend/typed_data_aot_test.cc",
"backend/yield_position_test.cc",
"cha_test.cc",
+ "ffi/native_type_vm_test.cc",
"frontend/kernel_binary_flowgraph_test.cc",
"frontend/multiple_entrypoints_test.cc",
"write_barrier_elimination_test.cc",
diff --git a/runtime/vm/compiler/ffi/native_location.h b/runtime/vm/compiler/ffi/native_location.h
index 3437e5c..614798a 100644
--- a/runtime/vm/compiler/ffi/native_location.h
+++ b/runtime/vm/compiler/ffi/native_location.h
@@ -11,6 +11,7 @@
#include "platform/assert.h"
#include "vm/compiler/ffi/native_type.h"
+#include "vm/compiler/runtime_api.h"
#include "vm/constants.h"
#include "vm/growable_array.h"
@@ -24,10 +25,6 @@
namespace compiler {
-namespace target {
-extern const int kWordSize;
-}
-
namespace ffi {
class NativeRegistersLocation;
diff --git a/runtime/vm/compiler/ffi/native_type.cc b/runtime/vm/compiler/ffi/native_type.cc
index db06400..20c33dd 100644
--- a/runtime/vm/compiler/ffi/native_type.cc
+++ b/runtime/vm/compiler/ffi/native_type.cc
@@ -14,6 +14,10 @@
#include "vm/compiler/backend/locations.h"
#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
+#if !defined(FFI_UNIT_TESTS)
+#include "vm/symbols.h"
+#endif
+
namespace dart {
namespace compiler {
@@ -25,6 +29,11 @@
return static_cast<const NativePrimitiveType&>(*this);
}
+const NativeCompoundType& NativeType::AsCompound() const {
+ ASSERT(IsCompound());
+ return static_cast<const NativeCompoundType&>(*this);
+}
+
bool NativePrimitiveType::IsInt() const {
switch (representation_) {
case kInt8:
@@ -127,6 +136,57 @@
}
}
+static bool ContainsHomogenuousFloatsInternal(const NativeTypes& types);
+
+// Keep consistent with
+// pkg/vm/lib/transformations/ffi_definitions.dart:_calculateSizeAndOffsets.
+NativeCompoundType& NativeCompoundType::FromNativeTypes(
+ Zone* zone,
+ const NativeTypes& members) {
+ intptr_t offset = 0;
+
+ const intptr_t kAtLeast1ByteAligned = 1;
+ // If this struct is nested in another struct, it should be aligned to the
+ // largest alignment of its members.
+ intptr_t alignment_field = kAtLeast1ByteAligned;
+ // If this struct is passed on the stack, it should be aligned to the largest
+ // alignment of its members when passing those members on the stack.
+ intptr_t alignment_stack = kAtLeast1ByteAligned;
+#if defined(TARGET_OS_MACOS_IOS) && defined(TARGET_ARCH_ARM64)
+ // On iOS64 stack values can be less aligned than wordSize, which deviates
+ // from the arm64 ABI.
+ ASSERT(CallingConventions::kArgumentStackAlignment == kAlignedToValueSize);
+ // Because the arm64 ABI aligns primitives to word size on the stack, every
+ // struct will be automatically aligned to word size. iOS64 does not align
+ // the primitives to word size, so we set structs to align to word size for
+ // iOS64.
+ // However, homogenous structs are treated differently. They are aligned to
+ // their member alignment. (Which is 4 in case of a homogenous float).
+ // Source: manual testing.
+ if (!ContainsHomogenuousFloatsInternal(members)) {
+ alignment_stack = compiler::target::kWordSize;
+ }
+#endif
+
+ auto& member_offsets =
+ *new (zone) ZoneGrowableArray<intptr_t>(zone, members.length());
+ for (intptr_t i = 0; i < members.length(); i++) {
+ const NativeType& member = *members[i];
+ const intptr_t member_size = member.SizeInBytes();
+ const intptr_t member_align_field = member.AlignmentInBytesField();
+ const intptr_t member_align_stack = member.AlignmentInBytesStack();
+ offset = Utils::RoundUp(offset, member_align_field);
+ member_offsets.Add(offset);
+ offset += member_size;
+ alignment_field = Utils::Maximum(alignment_field, member_align_field);
+ alignment_stack = Utils::Maximum(alignment_stack, member_align_stack);
+ }
+ const intptr_t size = Utils::RoundUp(offset, alignment_field);
+
+ return *new (zone) NativeCompoundType(members, member_offsets, size,
+ alignment_field, alignment_stack);
+}
+
#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
bool NativePrimitiveType::IsExpressibleAsRepresentation() const {
switch (representation_) {
@@ -139,7 +199,7 @@
case kInt32:
case kUint32:
case kInt64:
- case kUint64:
+ case kUint64: // We don't actually have a kUnboxedUint64.
case kFloat:
case kDouble:
return true;
@@ -179,6 +239,23 @@
return other.AsPrimitive().representation_ == representation_;
}
+bool NativeCompoundType::Equals(const NativeType& other) const {
+ if (!other.IsCompound()) {
+ return false;
+ }
+ const auto& other_compound = other.AsCompound();
+ const auto& other_members = other_compound.members_;
+ if (other_members.length() != members_.length()) {
+ return false;
+ }
+ for (intptr_t i = 0; i < members_.length(); i++) {
+ if (!members_[i]->Equals(*other_members[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
static PrimitiveType split_fundamental(PrimitiveType in) {
switch (in) {
case kInt16:
@@ -243,16 +320,52 @@
}
}
+static bool IsPredefinedFfiCid(classid_t class_id) {
+ switch (class_id) {
+#define CASE_FFI_CID_TRUE(name) \
+ case kFfi##name##Cid: \
+ return true;
+ CLASS_LIST_FFI(CASE_FFI_CID_TRUE)
+ default:
+ return false;
+ }
+ UNREACHABLE();
+}
+
NativeType& NativeType::FromTypedDataClassId(Zone* zone, classid_t class_id) {
- // TODO(36730): Support composites.
+ ASSERT(IsPredefinedFfiCid(class_id));
const auto fundamental_rep = TypeRepresentation(class_id);
return *new (zone) NativePrimitiveType(fundamental_rep);
}
#if !defined(FFI_UNIT_TESTS)
NativeType& NativeType::FromAbstractType(Zone* zone, const AbstractType& type) {
- // TODO(36730): Support composites.
- return NativeType::FromTypedDataClassId(zone, type.type_class_id());
+ const classid_t class_id = type.type_class_id();
+ if (IsPredefinedFfiCid(class_id)) {
+ return NativeType::FromTypedDataClassId(zone, class_id);
+ }
+
+ // User-defined structs.
+ const auto& cls = Class::Handle(zone, type.type_class());
+
+ auto& options = Object::Handle(zone);
+ Library::FindPragma(dart::Thread::Current(), /*only_core=*/false, cls,
+ Symbols::vm_ffi_struct_fields(), &options);
+ ASSERT(!options.IsNull());
+ ASSERT(options.IsArray());
+
+ const auto& field_types = Array::Cast(options);
+ auto& field_type = AbstractType::Handle(zone);
+ auto& field_native_types = *new (zone) ZoneGrowableArray<const NativeType*>(
+ zone, field_types.Length());
+ for (intptr_t i = 0; i < field_types.Length(); i++) {
+ field_type ^= field_types.At(i);
+ const NativeType& field_native_type =
+ NativeType::FromAbstractType(zone, field_type);
+ field_native_types.Add(&field_native_type);
+ }
+
+ return NativeCompoundType::FromNativeTypes(zone, field_native_types);
}
#endif
@@ -281,15 +394,15 @@
}
#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS)
-const char* NativeType::ToCString(Zone* zone) const {
+const char* NativeType::ToCString(Zone* zone, bool multi_line) const {
ZoneTextBuffer textBuffer(zone);
- PrintTo(&textBuffer);
+ PrintTo(&textBuffer, multi_line);
return textBuffer.buffer();
}
#if !defined(FFI_UNIT_TESTS)
-const char* NativeType::ToCString() const {
- return ToCString(Thread::Current()->zone());
+const char* NativeType::ToCString(bool multi_line) const {
+ return ToCString(Thread::Current()->zone(), multi_line);
}
#endif
@@ -324,11 +437,11 @@
}
}
-void NativeType::PrintTo(BaseTextBuffer* f) const {
+void NativeType::PrintTo(BaseTextBuffer* f, bool multi_line) const {
f->AddString("I");
}
-void NativePrimitiveType::PrintTo(BaseTextBuffer* f) const {
+void NativePrimitiveType::PrintTo(BaseTextBuffer* f, bool multi_line) const {
f->Printf("%s", PrimitiveTypeToCString(representation_));
}
@@ -338,6 +451,35 @@
return textBuffer.buffer();
}
+void NativeCompoundType::PrintTo(BaseTextBuffer* f, bool multi_line) const {
+ f->AddString("Compound(");
+ f->Printf("size: %" Pd ", ", SizeInBytes());
+ f->Printf("field alignment: %" Pd ", ", AlignmentInBytesField());
+ f->Printf("stack alignment: %" Pd ", ", AlignmentInBytesStack());
+ f->AddString("members: {");
+ if (multi_line) {
+ f->AddString("\n ");
+ }
+ for (intptr_t i = 0; i < members_.length(); i++) {
+ if (i > 0) {
+ if (multi_line) {
+ f->AddString(",\n ");
+ } else {
+ f->AddString(", ");
+ }
+ }
+ f->Printf("%" Pd ": ", member_offsets_[i]);
+ members_[i]->PrintTo(f);
+ }
+ if (multi_line) {
+ f->AddString("\n");
+ }
+ f->AddString("})");
+ if (multi_line) {
+ f->AddString("\n");
+ }
+}
+
#if !defined(FFI_UNIT_TESTS)
const char* NativeFunctionType::ToCString() const {
return ToCString(Thread::Current()->zone());
@@ -356,6 +498,88 @@
return_type_.PrintTo(f);
}
+bool NativeCompoundType::ContainsOnlyFloats(intptr_t offset_in_bytes,
+ intptr_t size_in_bytes) const {
+ ASSERT(size_in_bytes >= 0);
+ const intptr_t first_byte = offset_in_bytes;
+ const intptr_t last_byte = offset_in_bytes + size_in_bytes - 1;
+ for (intptr_t i = 0; i < members_.length(); i++) {
+ const intptr_t member_first_byte = member_offsets_[i];
+ const intptr_t member_last_byte =
+ member_first_byte + members_[i]->SizeInBytes() - 1;
+ if ((first_byte <= member_first_byte && member_first_byte <= last_byte) ||
+ (first_byte <= member_last_byte && member_last_byte <= last_byte)) {
+ if (members_[i]->IsPrimitive() && !members_[i]->IsFloat()) {
+ return false;
+ }
+ if (members_[i]->IsCompound()) {
+ const auto& nested = members_[i]->AsCompound();
+ const bool nested_only_floats = nested.ContainsOnlyFloats(
+ offset_in_bytes - member_first_byte, size_in_bytes);
+ if (!nested_only_floats) {
+ return false;
+ }
+ }
+ }
+ if (member_first_byte > last_byte) {
+ // None of the remaining members fits the range.
+ break;
+ }
+ }
+ return true;
+}
+
+intptr_t NativeCompoundType::NumberOfWordSizeChunksOnlyFloat() const {
+ // O(n^2) implementation, but only invoked for small structs.
+ ASSERT(SizeInBytes() <= 16);
+ const intptr_t size = SizeInBytes();
+ intptr_t float_only_chunks = 0;
+ for (intptr_t offset = 0; offset < size;
+ offset += compiler::target::kWordSize) {
+ if (ContainsOnlyFloats(
+ offset, Utils::Minimum<intptr_t>(size - offset,
+ compiler::target::kWordSize))) {
+ float_only_chunks++;
+ }
+ }
+ return float_only_chunks;
+}
+
+intptr_t NativeCompoundType::NumberOfWordSizeChunksNotOnlyFloat() const {
+ const intptr_t total_chunks =
+ Utils::RoundUp(SizeInBytes(), compiler::target::kWordSize) /
+ compiler::target::kWordSize;
+ return total_chunks - NumberOfWordSizeChunksOnlyFloat();
+}
+
+static void ContainsHomogenuousFloatsRecursive(const NativeTypes& types,
+ bool* only_float,
+ bool* only_double) {
+ for (intptr_t i = 0; i < types.length(); i++) {
+ const auto& member_type = types.At(i);
+ if (member_type->IsPrimitive()) {
+ PrimitiveType type = member_type->AsPrimitive().representation();
+ *only_float = *only_float && (type == kFloat);
+ *only_double = *only_double && (type == kDouble);
+ }
+ if (member_type->IsCompound()) {
+ ContainsHomogenuousFloatsRecursive(member_type->AsCompound().members(),
+ only_float, only_double);
+ }
+ }
+}
+
+static bool ContainsHomogenuousFloatsInternal(const NativeTypes& types) {
+ bool only_float = true;
+ bool only_double = true;
+ ContainsHomogenuousFloatsRecursive(types, &only_float, &only_double);
+ return (only_double || only_float) && types.length() > 0;
+}
+
+bool NativeCompoundType::ContainsHomogenuousFloats() const {
+ return ContainsHomogenuousFloatsInternal(this->members());
+}
+
const NativeType& NativeType::WidenTo4Bytes(Zone* zone) const {
if (IsInt() && SizeInBytes() <= 2) {
if (IsSigned()) {
diff --git a/runtime/vm/compiler/ffi/native_type.h b/runtime/vm/compiler/ffi/native_type.h
index 3c11341..eaf4129 100644
--- a/runtime/vm/compiler/ffi/native_type.h
+++ b/runtime/vm/compiler/ffi/native_type.h
@@ -26,6 +26,7 @@
namespace ffi {
class NativePrimitiveType;
+class NativeCompoundType;
// NativeTypes are the types used in calling convention specifications:
// integers, floats, and composites.
@@ -40,17 +41,15 @@
//
// Instead, NativeTypes support representations not supported in Dart's unboxed
// Representations, such as:
-// * Primitive types:
+// * Primitive types (https://en.cppreference.com/w/cpp/language/types):
// * int8_t
// * int16_t
// * uint8_t
// * uint16t
// * void
-// * Compound types:
+// * Compound types (https://en.cppreference.com/w/cpp/language/type):
// * Struct
// * Union
-//
-// TODO(36730): Add composites.
class NativeType : public ZoneAllocated {
public:
#if !defined(FFI_UNIT_TESTS)
@@ -65,6 +64,8 @@
virtual bool IsPrimitive() const { return false; }
const NativePrimitiveType& AsPrimitive() const;
+ virtual bool IsCompound() const { return false; }
+ const NativeCompoundType& AsCompound() const;
virtual bool IsInt() const { return false; }
virtual bool IsFloat() const { return false; }
@@ -106,10 +107,10 @@
// Otherwise, return original representation.
const NativeType& WidenTo4Bytes(Zone* zone) const;
- virtual void PrintTo(BaseTextBuffer* f) const;
- const char* ToCString(Zone* zone) const;
+ virtual void PrintTo(BaseTextBuffer* f, bool multi_line = false) const;
+ const char* ToCString(Zone* zone, bool multi_line = false) const;
#if !defined(FFI_UNIT_TESTS)
- const char* ToCString() const;
+ const char* ToCString(bool multi_line = false) const;
#endif
virtual ~NativeType() {}
@@ -166,7 +167,7 @@
virtual bool Equals(const NativeType& other) const;
virtual NativePrimitiveType& Split(Zone* zone, intptr_t part) const;
- virtual void PrintTo(BaseTextBuffer* f) const;
+ virtual void PrintTo(BaseTextBuffer* f, bool multi_line = false) const;
virtual ~NativePrimitiveType() {}
@@ -176,6 +177,72 @@
using NativeTypes = ZoneGrowableArray<const NativeType*>;
+// Struct
+//
+// TODO(dartbug.com/38491): Support unions.
+// TODO(dartbug.com/37271): Support nested compound types.
+// TODO(dartbug.com/35763): Support inline fixed-length arrays.
+class NativeCompoundType : public NativeType {
+ public:
+ static NativeCompoundType& FromNativeTypes(Zone* zone,
+ const NativeTypes& members);
+
+ const NativeTypes& members() const { return members_; }
+ const ZoneGrowableArray<intptr_t>& member_offsets() const {
+ return member_offsets_;
+ }
+
+ virtual bool IsCompound() const { return true; }
+
+ virtual intptr_t SizeInBytes() const { return size_; }
+ virtual intptr_t AlignmentInBytesField() const { return alignment_field_; }
+ virtual intptr_t AlignmentInBytesStack() const { return alignment_stack_; }
+
+ virtual bool Equals(const NativeType& other) const;
+
+ virtual void PrintTo(BaseTextBuffer* f, bool multi_line = false) const;
+
+ // Whether a range within a struct contains only floats.
+ //
+ // Useful for determining whether struct is passed in FP registers on x64.
+ bool ContainsOnlyFloats(intptr_t offset_in_bytes,
+ intptr_t size_in_bytes) const;
+
+ // Returns how many word-sized chuncks _only_ contain floats.
+ //
+ // Useful for determining whether struct is passed in FP registers on x64.
+ intptr_t NumberOfWordSizeChunksOnlyFloat() const;
+
+ // Returns how many word-sized chunks do not _only_ contain floats.
+ //
+ // Useful for determining whether struct is passed in FP registers on x64.
+ intptr_t NumberOfWordSizeChunksNotOnlyFloat() const;
+
+ // Whether this type has only same-size floating point members.
+ //
+ // Useful for determining whether struct is passed in FP registers in hardfp
+ // and arm64.
+ bool ContainsHomogenuousFloats() const;
+
+ private:
+ NativeCompoundType(const NativeTypes& members,
+ const ZoneGrowableArray<intptr_t>& member_offsets,
+ intptr_t size,
+ intptr_t alignment_field,
+ intptr_t alignment_stack)
+ : members_(members),
+ member_offsets_(member_offsets),
+ size_(size),
+ alignment_field_(alignment_field),
+ alignment_stack_(alignment_stack) {}
+
+ const NativeTypes& members_;
+ const ZoneGrowableArray<intptr_t>& member_offsets_;
+ const intptr_t size_;
+ const intptr_t alignment_field_;
+ const intptr_t alignment_stack_;
+};
+
class NativeFunctionType : public ZoneAllocated {
public:
NativeFunctionType(const NativeTypes& argument_types,
diff --git a/runtime/vm/compiler/ffi/native_type_test.cc b/runtime/vm/compiler/ffi/native_type_test.cc
index abf275d..66fa987 100644
--- a/runtime/vm/compiler/ffi/native_type_test.cc
+++ b/runtime/vm/compiler/ffi/native_type_test.cc
@@ -4,12 +4,44 @@
#include "vm/compiler/ffi/unit_test.h"
+#include "platform/syslog.h"
#include "vm/compiler/ffi/native_type.h"
+#include "vm/compiler/runtime_api.h"
namespace dart {
namespace compiler {
namespace ffi {
+const NativeCompoundType& RunStructTest(dart::Zone* zone,
+ const char* name,
+ const NativeTypes& member_types) {
+ const auto& struct_type =
+ NativeCompoundType::FromNativeTypes(zone, member_types);
+
+ const char* test_result = struct_type.ToCString(zone, /*multi_line=*/true);
+
+ const int kFilePathLength = 100;
+ char expectation_file_path[kFilePathLength];
+ Utils::SNPrint(expectation_file_path, kFilePathLength,
+ "runtime/vm/compiler/ffi/unit_tests/%s/%s_%s.expect", name,
+ kArch, kOs);
+
+ if (TestCaseBase::update_expectations) {
+ Syslog::Print("Updating %s\n", expectation_file_path);
+ WriteToFile(expectation_file_path, test_result);
+ }
+
+ char* expectation_file_contents = nullptr;
+ ReadFromFile(expectation_file_path, &expectation_file_contents);
+ EXPECT_NOTNULL(expectation_file_contents);
+ if (expectation_file_contents != nullptr) {
+ EXPECT_STREQ(expectation_file_contents, test_result);
+ free(expectation_file_contents);
+ }
+
+ return struct_type;
+}
+
UNIT_TEST_CASE_WITH_ZONE(NativeType) {
const auto& native_type = *new (Z) NativePrimitiveType(kInt8);
@@ -20,6 +52,107 @@
EXPECT_STREQ("int8", native_type.ToCString(Z));
}
+UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_int8x10) {
+ const auto& int8type = *new (Z) NativePrimitiveType(kInt8);
+
+ auto& members = *new (Z) NativeTypes(Z, 10);
+ members.Add(&int8type);
+ members.Add(&int8type);
+ members.Add(&int8type);
+ members.Add(&int8type);
+ members.Add(&int8type);
+ members.Add(&int8type);
+ members.Add(&int8type);
+ members.Add(&int8type);
+ members.Add(&int8type);
+ members.Add(&int8type);
+
+ const auto& struct_type = RunStructTest(Z, "struct_int8x10", members);
+
+ EXPECT(!struct_type.ContainsHomogenuousFloats());
+ EXPECT(!struct_type.ContainsOnlyFloats(0, 8));
+ EXPECT_EQ(0, struct_type.NumberOfWordSizeChunksOnlyFloat());
+ EXPECT_EQ(
+ Utils::RoundUp(struct_type.SizeInBytes(), compiler::target::kWordSize) /
+ compiler::target::kWordSize,
+ struct_type.NumberOfWordSizeChunksNotOnlyFloat());
+}
+
+UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_floatx4) {
+ const auto& float_type = *new (Z) NativePrimitiveType(kFloat);
+
+ auto& members = *new (Z) NativeTypes(Z, 4);
+ members.Add(&float_type);
+ members.Add(&float_type);
+ members.Add(&float_type);
+ members.Add(&float_type);
+
+ const auto& struct_type = RunStructTest(Z, "struct_floatx4", members);
+
+ // This is a homogenous float in the arm and arm64 ABIs.
+ //
+ // On Arm64 iOS stack alignment of homogenous floats is not word size see
+ // runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_ios.expect.
+ EXPECT(struct_type.ContainsHomogenuousFloats());
+
+ // On x64, 8-byte parts of the chunks contain only floats and will be passed
+ // in FPU registers.
+ EXPECT(struct_type.ContainsOnlyFloats(0, 8));
+ EXPECT(struct_type.ContainsOnlyFloats(8, 8));
+ EXPECT_EQ(struct_type.SizeInBytes() / compiler::target::kWordSize,
+ struct_type.NumberOfWordSizeChunksOnlyFloat());
+ EXPECT_EQ(0, struct_type.NumberOfWordSizeChunksNotOnlyFloat());
+}
+
+// A struct designed to exercise all kinds of alignment rules.
+// Note that offset32A (System V ia32, iOS arm) aligns doubles on 4 bytes while
+// offset32B (Arm 32 bit and MSVC ia32) aligns on 8 bytes.
+// TODO(37271): Support nested structs.
+// TODO(37470): Add uncommon primitive data types when we want to support them.
+struct VeryLargeStruct {
+ // size32 size64 offset32A offset32B offset64
+ int8_t a; // 1 0 0 0
+ int16_t b; // 2 2 2 2
+ int32_t c; // 4 4 4 4
+ int64_t d; // 8 8 8 8
+ uint8_t e; // 1 16 16 16
+ uint16_t f; // 2 18 18 18
+ uint32_t g; // 4 20 20 20
+ uint64_t h; // 8 24 24 24
+ intptr_t i; // 4 8 32 32 32
+ double j; // 8 36 40 40
+ float k; // 4 44 48 48
+ VeryLargeStruct* parent; // 4 8 48 52 56
+ intptr_t numChildren; // 4 8 52 56 64
+ VeryLargeStruct* children; // 4 8 56 60 72
+ int8_t smallLastField; // 1 60 64 80
+ // sizeof 64 72 88
+};
+
+UNIT_TEST_CASE_WITH_ZONE(NativeCompoundType_VeryLargeStruct) {
+ const auto& intptr_type = *new (Z) NativePrimitiveType(
+ compiler::target::kWordSize == 4 ? kInt32 : kInt64);
+
+ auto& members = *new (Z) NativeTypes(Z, 15);
+ members.Add(new (Z) NativePrimitiveType(kInt8));
+ members.Add(new (Z) NativePrimitiveType(kInt16));
+ members.Add(new (Z) NativePrimitiveType(kInt32));
+ members.Add(new (Z) NativePrimitiveType(kInt64));
+ members.Add(new (Z) NativePrimitiveType(kUint8));
+ members.Add(new (Z) NativePrimitiveType(kUint16));
+ members.Add(new (Z) NativePrimitiveType(kUint32));
+ members.Add(new (Z) NativePrimitiveType(kUint64));
+ members.Add(&intptr_type);
+ members.Add(new (Z) NativePrimitiveType(kDouble));
+ members.Add(new (Z) NativePrimitiveType(kFloat));
+ members.Add(&intptr_type);
+ members.Add(&intptr_type);
+ members.Add(&intptr_type);
+ members.Add(new (Z) NativePrimitiveType(kInt8));
+
+ RunStructTest(Z, "struct_VeryLargeStruct", members);
+}
+
} // namespace ffi
} // namespace compiler
} // namespace dart
diff --git a/runtime/vm/compiler/ffi/native_type_vm_test.cc b/runtime/vm/compiler/ffi/native_type_vm_test.cc
new file mode 100644
index 0000000..52f0835
--- /dev/null
+++ b/runtime/vm/compiler/ffi/native_type_vm_test.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2020, 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.
+
+#include "vm/compiler/ffi/native_type.h"
+
+#include "vm/compiler/backend/il_test_helper.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+namespace compiler {
+namespace ffi {
+
+ISOLATE_UNIT_TEST_CASE(Ffi_NativeType_Primitive_FromAbstractType) {
+ Zone* Z = thread->zone();
+
+ const auto& ffi_library = Library::Handle(Library::FfiLibrary());
+ const auto& int8_class = Class::Handle(GetClass(ffi_library, "Int8"));
+ const auto& int8_type = Type::Handle(int8_class.DeclarationType());
+ const auto& native_type = NativeType::FromAbstractType(Z, int8_type);
+
+ EXPECT_EQ(1, native_type.SizeInBytes());
+ EXPECT_STREQ("int8", native_type.ToCString());
+ EXPECT(native_type.IsInt());
+ EXPECT(native_type.IsPrimitive());
+}
+
+// Test that we construct `NativeType` correctly from `Type`.
+ISOLATE_UNIT_TEST_CASE(Ffi_NativeType_Struct_FromAbstractType) {
+ Zone* Z = thread->zone();
+
+ const char* kScript =
+ R"(
+ import 'dart:ffi';
+
+ class MyStruct extends Struct {
+ @Int8()
+ external int a0;
+
+ external Pointer<Int8> a1;
+ }
+ )";
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+ const auto& struct_class = Class::Handle(GetClass(root_library, "MyStruct"));
+ const auto& struct_type = Type::Handle(struct_class.DeclarationType());
+
+ const auto& native_type =
+ NativeType::FromAbstractType(Z, struct_type).AsCompound();
+
+ EXPECT_EQ(2, native_type.members().length());
+
+ const auto& int8_type = *new (Z) NativePrimitiveType(kInt8);
+ EXPECT(int8_type.Equals(*native_type.members()[0]));
+
+ EXPECT_EQ(compiler::target::kWordSize,
+ native_type.members()[1]->SizeInBytes());
+}
+
+} // namespace ffi
+} // namespace compiler
+} // namespace dart
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_android.expect
new file mode 100644
index 0000000..ca69b6c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_android.expect
@@ -0,0 +1,17 @@
+Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int64,
+ 40: double,
+ 48: float,
+ 56: int64,
+ 64: int64,
+ 72: int64,
+ 80: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_ios.expect
new file mode 100644
index 0000000..ca69b6c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_ios.expect
@@ -0,0 +1,17 @@
+Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int64,
+ 40: double,
+ 48: float,
+ 56: int64,
+ 64: int64,
+ 72: int64,
+ 80: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_linux.expect
new file mode 100644
index 0000000..ca69b6c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_linux.expect
@@ -0,0 +1,17 @@
+Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int64,
+ 40: double,
+ 48: float,
+ 56: int64,
+ 64: int64,
+ 72: int64,
+ 80: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_macos.expect
new file mode 100644
index 0000000..ca69b6c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_macos.expect
@@ -0,0 +1,17 @@
+Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int64,
+ 40: double,
+ 48: float,
+ 56: int64,
+ 64: int64,
+ 72: int64,
+ 80: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_android.expect
new file mode 100644
index 0000000..124e769
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_android.expect
@@ -0,0 +1,17 @@
+Compound(size: 72, field alignment: 8, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int32,
+ 40: double,
+ 48: float,
+ 52: int32,
+ 56: int32,
+ 60: int32,
+ 64: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_ios.expect
new file mode 100644
index 0000000..44136f8
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_ios.expect
@@ -0,0 +1,17 @@
+Compound(size: 64, field alignment: 4, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int32,
+ 36: double,
+ 44: float,
+ 48: int32,
+ 52: int32,
+ 56: int32,
+ 60: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_linux.expect
new file mode 100644
index 0000000..124e769
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm_linux.expect
@@ -0,0 +1,17 @@
+Compound(size: 72, field alignment: 8, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int32,
+ 40: double,
+ 48: float,
+ 52: int32,
+ 56: int32,
+ 60: int32,
+ 64: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_android.expect
new file mode 100644
index 0000000..24fa174
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_android.expect
@@ -0,0 +1,17 @@
+Compound(size: 64, field alignment: 4, stack alignment: 4, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int32,
+ 36: double,
+ 44: float,
+ 48: int32,
+ 52: int32,
+ 56: int32,
+ 60: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_linux.expect
new file mode 100644
index 0000000..24fa174
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_linux.expect
@@ -0,0 +1,17 @@
+Compound(size: 64, field alignment: 4, stack alignment: 4, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int32,
+ 36: double,
+ 44: float,
+ 48: int32,
+ 52: int32,
+ 56: int32,
+ 60: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_win.expect
new file mode 100644
index 0000000..e0bd22c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_win.expect
@@ -0,0 +1,17 @@
+Compound(size: 72, field alignment: 8, stack alignment: 4, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int32,
+ 40: double,
+ 48: float,
+ 52: int32,
+ 56: int32,
+ 60: int32,
+ 64: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_ios.expect
new file mode 100644
index 0000000..ca69b6c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_ios.expect
@@ -0,0 +1,17 @@
+Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int64,
+ 40: double,
+ 48: float,
+ 56: int64,
+ 64: int64,
+ 72: int64,
+ 80: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_linux.expect
new file mode 100644
index 0000000..ca69b6c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_linux.expect
@@ -0,0 +1,17 @@
+Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int64,
+ 40: double,
+ 48: float,
+ 56: int64,
+ 64: int64,
+ 72: int64,
+ 80: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_macos.expect
new file mode 100644
index 0000000..ca69b6c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_macos.expect
@@ -0,0 +1,17 @@
+Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int64,
+ 40: double,
+ 48: float,
+ 56: int64,
+ 64: int64,
+ 72: int64,
+ 80: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_win.expect
new file mode 100644
index 0000000..ca69b6c
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_win.expect
@@ -0,0 +1,17 @@
+Compound(size: 88, field alignment: 8, stack alignment: 8, members: {
+ 0: int8,
+ 2: int16,
+ 4: int32,
+ 8: int64,
+ 16: uint8,
+ 18: uint16,
+ 20: uint32,
+ 24: uint64,
+ 32: int64,
+ 40: double,
+ 48: float,
+ 56: int64,
+ 64: int64,
+ 72: int64,
+ 80: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_android.expect
new file mode 100644
index 0000000..025609f
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_android.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_ios.expect
new file mode 100644
index 0000000..db47a46
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_ios.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_linux.expect
new file mode 100644
index 0000000..025609f
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_linux.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_macos.expect
new file mode 100644
index 0000000..025609f
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_macos.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_android.expect
new file mode 100644
index 0000000..db47a46
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_android.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_ios.expect
new file mode 100644
index 0000000..db47a46
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_ios.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_linux.expect
new file mode 100644
index 0000000..db47a46
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm_linux.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_android.expect
new file mode 100644
index 0000000..db47a46
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_android.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_linux.expect
new file mode 100644
index 0000000..db47a46
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_linux.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_win.expect
new file mode 100644
index 0000000..db47a46
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_win.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 4, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_ios.expect
new file mode 100644
index 0000000..025609f
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_ios.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_linux.expect
new file mode 100644
index 0000000..025609f
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_linux.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_macos.expect
new file mode 100644
index 0000000..025609f
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_macos.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_win.expect
new file mode 100644
index 0000000..025609f
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_win.expect
@@ -0,0 +1,6 @@
+Compound(size: 16, field alignment: 4, stack alignment: 8, members: {
+ 0: float,
+ 4: float,
+ 8: float,
+ 12: float
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_android.expect
new file mode 100644
index 0000000..146893d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_android.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_ios.expect
new file mode 100644
index 0000000..146893d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_ios.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_linux.expect
new file mode 100644
index 0000000..146893d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_linux.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_macos.expect
new file mode 100644
index 0000000..146893d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_macos.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_android.expect
new file mode 100644
index 0000000..c7c2467
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_android.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_ios.expect
new file mode 100644
index 0000000..c7c2467
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_ios.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_linux.expect
new file mode 100644
index 0000000..c7c2467
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm_linux.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_android.expect
new file mode 100644
index 0000000..c7c2467
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_android.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_linux.expect
new file mode 100644
index 0000000..c7c2467
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_linux.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_win.expect
new file mode 100644
index 0000000..c7c2467
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_win.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 4, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_ios.expect
new file mode 100644
index 0000000..146893d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_ios.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_linux.expect
new file mode 100644
index 0000000..146893d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_linux.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_macos.expect
new file mode 100644
index 0000000..146893d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_macos.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_win.expect
new file mode 100644
index 0000000..146893d
--- /dev/null
+++ b/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_win.expect
@@ -0,0 +1,12 @@
+Compound(size: 10, field alignment: 1, stack alignment: 8, members: {
+ 0: int8,
+ 1: int8,
+ 2: int8,
+ 3: int8,
+ 4: int8,
+ 5: int8,
+ 6: int8,
+ 7: int8,
+ 8: int8,
+ 9: int8
+})
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index 1827e82..eba92da 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -285,7 +285,7 @@
kAlignedToWordSize;
// How fields in composites are aligned.
-#if defined(_WIN32)
+#if defined(TARGET_OS_WINDOWS)
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
#else
static constexpr AlignmentStrategy kFieldAlignment =
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 0a40d7d..a1db78b 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -493,7 +493,8 @@
V(vm_non_nullable_result_type, "vm:non-nullable-result-type") \
V(vm_recognized, "vm:recognized") \
V(vm_trace_entrypoints, "vm:testing.unsafe.trace-entrypoints-fn") \
- V(vm_procedure_attributes_metadata, "vm.procedure-attributes.metadata")
+ V(vm_procedure_attributes_metadata, "vm.procedure-attributes.metadata") \
+ V(vm_ffi_struct_fields, "vm:ffi:struct-fields")
// Contains a list of frequently used strings in a canonicalized form. This
// list is kept in the vm_isolate in order to share the copy across isolates
diff --git a/tools/VERSION b/tools/VERSION
index 3545891..5a845c02 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 56
+PRERELEASE 57
PRERELEASE_PATCH 0
\ No newline at end of file