Version 2.16.0-124.0.dev
Merge commit '4b5798d9d40197d1db5f89203f87524d6c600cb6' into 'dev'
diff --git a/DEPS b/DEPS
index 7f81b03..727fe76 100644
--- a/DEPS
+++ b/DEPS
@@ -108,7 +108,7 @@
"dart_style_rev": "08b0294d0a500d5c02168ef57dcb8868d0c3cb48",
"dartdoc_rev" : "ff0d94bdb87f11c04a7e0ddab811bf94211b08a4",
- "devtools_rev" : "f2ede24a4ea666d4832d78b813c7d4e376aa77d0",
+ "devtools_rev" : "85932bb66aa782c4b2c528be7718960bf256ffb7",
"jsshell_tag": "version:88.0",
"ffi_rev": "4dd32429880a57b64edaf54c9d5af8a9fa9a4ffb",
"fixnum_rev": "16d3890c6dc82ca629659da1934e412292508bba",
diff --git a/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart b/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart
index bd175b9..18f1072 100644
--- a/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart
+++ b/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart
@@ -23,6 +23,7 @@
AnalyzerOptions.errors: EmptyProducer(),
AnalyzerOptions.exclude: EmptyProducer(),
AnalyzerOptions.language: MapProducer({
+ AnalyzerOptions.strictCasts: EmptyProducer(),
AnalyzerOptions.strictInference: EmptyProducer(),
AnalyzerOptions.strictRawTypes: EmptyProducer(),
}),
diff --git a/pkg/analysis_server/lib/src/services/correction/sort_members.dart b/pkg/analysis_server/lib/src/services/correction/sort_members.dart
index 9908244..d257984 100644
--- a/pkg/analysis_server/lib/src/services/correction/sort_members.dart
+++ b/pkg/analysis_server/lib/src/services/correction/sort_members.dart
@@ -94,15 +94,17 @@
void _sortClassesMembers() {
for (var unitMember in unit.declarations) {
if (unitMember is ClassOrMixinDeclaration) {
- _sortClassMembers(unitMember);
+ _sortClassMembers(unitMember.members);
+ } else if (unitMember is ExtensionDeclaration) {
+ _sortClassMembers(unitMember.members);
}
}
}
/// Sorts all members of the given [classDeclaration].
- void _sortClassMembers(ClassOrMixinDeclaration classDeclaration) {
+ void _sortClassMembers(List<ClassMember> membersToSort) {
var members = <_MemberInfo>[];
- for (var member in classDeclaration.members) {
+ for (var member in membersToSort) {
_MemberKind kind;
var isStatic = false;
String name;
diff --git a/pkg/analysis_server/test/services/correction/sort_members_test.dart b/pkg/analysis_server/test/services/correction/sort_members_test.dart
index f5062c7..2d3b8a2 100644
--- a/pkg/analysis_server/test/services/correction/sort_members_test.dart
+++ b/pkg/analysis_server/test/services/correction/sort_members_test.dart
@@ -21,7 +21,7 @@
class SortMembersTest extends AbstractSingleUnitTest {
LineInfo? lineInfo;
- Future<void> test_classMembers_accessor() async {
+ Future<void> test_class_accessor() async {
await _parseTestUnit(r'''
class A {
set c(x) {}
@@ -45,7 +45,7 @@
''');
}
- Future<void> test_classMembers_accessor_static() async {
+ Future<void> test_class_accessor_static() async {
await _parseTestUnit(r'''
class A {
get a => null;
@@ -65,7 +65,7 @@
''');
}
- Future<void> test_classMembers_constructor() async {
+ Future<void> test_class_constructor() async {
await _parseTestUnit(r'''
class A {
A.c() { }
@@ -85,7 +85,7 @@
''');
}
- Future<void> test_classMembers_external_constructorMethod() async {
+ Future<void> test_class_external_constructorMethod() async {
await _parseTestUnit(r'''
class Chart {
external Pie();
@@ -101,7 +101,7 @@
''');
}
- Future<void> test_classMembers_field() async {
+ Future<void> test_class_field() async {
await _parseTestUnit(r'''
class A {
String c;
@@ -121,7 +121,7 @@
''');
}
- Future<void> test_classMembers_field_static() async {
+ Future<void> test_class_field_static() async {
await _parseTestUnit(r'''
class A {
int b;
@@ -141,7 +141,7 @@
''');
}
- Future<void> test_classMembers_method() async {
+ Future<void> test_class_method() async {
await _parseTestUnit(r'''
class A {
c() {}
@@ -159,7 +159,7 @@
''');
}
- Future<void> test_classMembers_method_emptyLine() async {
+ Future<void> test_class_method_emptyLine() async {
await _parseTestUnit(r'''
class A {
b() {}
@@ -177,7 +177,7 @@
''');
}
- Future<void> test_classMembers_method_ignoreCase() async {
+ Future<void> test_class_method_ignoreCase() async {
await _parseTestUnit(r'''
class A {
m_C() {}
@@ -195,7 +195,7 @@
''');
}
- Future<void> test_classMembers_method_static() async {
+ Future<void> test_class_method_static() async {
await _parseTestUnit(r'''
class A {
static a() {}
@@ -211,7 +211,7 @@
''');
}
- Future<void> test_classMembers_mix() async {
+ Future<void> test_class_mix() async {
await _parseTestUnit(r'''
class A {
/// static field public
@@ -311,7 +311,7 @@
''');
}
- Future<void> test_classMembers_trailingComments() async {
+ Future<void> test_class_trailingComments() async {
await _parseTestUnit(r'''
class A { // classA
// instanceA
@@ -585,6 +585,398 @@
''');
}
+ Future<void> test_extension_accessor() async {
+ await _parseTestUnit(r'''
+extension E on int {
+ set c(x) {}
+ set a(x) {}
+ get a => null;
+ get b => null;
+ set b(x) {}
+ get c => null;
+}
+''');
+ // validate change
+ _assertSort(r'''
+extension E on int {
+ get a => null;
+ set a(x) {}
+ get b => null;
+ set b(x) {}
+ get c => null;
+ set c(x) {}
+}
+''');
+ }
+
+ Future<void> test_extension_accessor_static() async {
+ await _parseTestUnit(r'''
+extension E on int {
+ get a => null;
+ set a(x) {}
+ static get b => null;
+ static set b(x) {}
+}
+''');
+ // validate change
+ _assertSort(r'''
+extension E on int {
+ static get b => null;
+ static set b(x) {}
+ get a => null;
+ set a(x) {}
+}
+''');
+ }
+
+ Future<void> test_extension_field_static() async {
+ await _parseTestUnit(r'''
+extension E on int {
+ int b;
+ int a;
+ static int d;
+ static int c;
+}
+''');
+ // validate change
+ _assertSort(r'''
+extension E on int {
+ static int d;
+ static int c;
+ int b;
+ int a;
+}
+''');
+ }
+
+ Future<void> test_extension_method() async {
+ await _parseTestUnit(r'''
+extension E on int {
+ c() {}
+ a() {}
+ b() {}
+}
+''');
+ // validate change
+ _assertSort(r'''
+extension E on int {
+ a() {}
+ b() {}
+ c() {}
+}
+''');
+ }
+
+ Future<void> test_extension_method_emptyLine() async {
+ await _parseTestUnit(r'''
+extension E on int {
+ b() {}
+
+ a() {}
+}
+''');
+ // validate change
+ _assertSort(r'''
+extension E on int {
+ a() {}
+
+ b() {}
+}
+''');
+ }
+
+ Future<void> test_extension_method_ignoreCase() async {
+ await _parseTestUnit(r'''
+extension E on int {
+ m_C() {}
+ m_a() {}
+ m_B() {}
+}
+''');
+ // validate change
+ _assertSort(r'''
+extension E on int {
+ m_a() {}
+ m_B() {}
+ m_C() {}
+}
+''');
+ }
+
+ Future<void> test_extension_method_static() async {
+ await _parseTestUnit(r'''
+extension E on int {
+ static a() {}
+ b() {}
+}
+''');
+ // validate change
+ _assertSort(r'''
+extension E on int {
+ b() {}
+ static a() {}
+}
+''');
+ }
+
+ Future<void> test_mixin_accessor() async {
+ await _parseTestUnit(r'''
+mixin M {
+ set c(x) {}
+ set a(x) {}
+ get a => null;
+ get b => null;
+ set b(x) {}
+ get c => null;
+}
+''');
+ // validate change
+ _assertSort(r'''
+mixin M {
+ get a => null;
+ set a(x) {}
+ get b => null;
+ set b(x) {}
+ get c => null;
+ set c(x) {}
+}
+''');
+ }
+
+ Future<void> test_mixin_accessor_static() async {
+ await _parseTestUnit(r'''
+mixin M {
+ get a => null;
+ set a(x) {}
+ static get b => null;
+ static set b(x) {}
+}
+''');
+ // validate change
+ _assertSort(r'''
+mixin M {
+ static get b => null;
+ static set b(x) {}
+ get a => null;
+ set a(x) {}
+}
+''');
+ }
+
+ Future<void> test_mixin_field() async {
+ await _parseTestUnit(r'''
+mixin M {
+ String c;
+ int a;
+ void toString() => null;
+ double b;
+}
+''');
+ // validate change
+ _assertSort(r'''
+mixin M {
+ String c;
+ int a;
+ double b;
+ void toString() => null;
+}
+''');
+ }
+
+ Future<void> test_mixin_field_static() async {
+ await _parseTestUnit(r'''
+mixin M {
+ int b;
+ int a;
+ static int d;
+ static int c;
+}
+''');
+ // validate change
+ _assertSort(r'''
+mixin M {
+ static int d;
+ static int c;
+ int b;
+ int a;
+}
+''');
+ }
+
+ Future<void> test_mixin_method() async {
+ await _parseTestUnit(r'''
+mixin M {
+ c() {}
+ a() {}
+ b() {}
+}
+''');
+ // validate change
+ _assertSort(r'''
+mixin M {
+ a() {}
+ b() {}
+ c() {}
+}
+''');
+ }
+
+ Future<void> test_mixin_method_emptyLine() async {
+ await _parseTestUnit(r'''
+mixin M {
+ b() {}
+
+ a() {}
+}
+''');
+ // validate change
+ _assertSort(r'''
+mixin M {
+ a() {}
+
+ b() {}
+}
+''');
+ }
+
+ Future<void> test_mixin_method_ignoreCase() async {
+ await _parseTestUnit(r'''
+mixin M {
+ m_C() {}
+ m_a() {}
+ m_B() {}
+}
+''');
+ // validate change
+ _assertSort(r'''
+mixin M {
+ m_a() {}
+ m_B() {}
+ m_C() {}
+}
+''');
+ }
+
+ Future<void> test_mixin_method_static() async {
+ await _parseTestUnit(r'''
+mixin M {
+ static a() {}
+ b() {}
+}
+''');
+ // validate change
+ _assertSort(r'''
+mixin M {
+ b() {}
+ static a() {}
+}
+''');
+ }
+
+ Future<void> test_mixin_mix() async {
+ await _parseTestUnit(r'''
+mixin M {
+ /// static field public
+ static int nnn;
+ /// static field private
+ static int _nnn;
+ /// instance getter public
+ int get nnn => null;
+ /// instance setter public
+ set nnn(x) {}
+ /// instance getter private
+ int get _nnn => null;
+ /// instance setter private
+ set _nnn(x) {}
+ /// instance method public
+ nnn() {}
+ /// instance method private
+ _nnn() {}
+ /// static method public
+ static nnn() {}
+ /// static method private
+ static _nnn() {}
+ /// static getter public
+ static int get nnn => null;
+ /// static setter public
+ static set nnn(x) {}
+ /// static getter private
+ static int get _nnn => null;
+ /// static setter private
+ static set _nnn(x) {}
+ /// instance field public
+ int nnn;
+ /// instance field private
+ int _nnn;
+}
+''');
+ // validate change
+ _assertSort(r'''
+mixin M {
+ /// static field public
+ static int nnn;
+ /// static field private
+ static int _nnn;
+ /// static getter public
+ static int get nnn => null;
+ /// static setter public
+ static set nnn(x) {}
+ /// static getter private
+ static int get _nnn => null;
+ /// static setter private
+ static set _nnn(x) {}
+ /// instance field public
+ int nnn;
+ /// instance field private
+ int _nnn;
+ /// instance getter public
+ int get nnn => null;
+ /// instance setter public
+ set nnn(x) {}
+ /// instance getter private
+ int get _nnn => null;
+ /// instance setter private
+ set _nnn(x) {}
+ /// instance method public
+ nnn() {}
+ /// instance method private
+ _nnn() {}
+ /// static method public
+ static nnn() {}
+ /// static method private
+ static _nnn() {}
+}
+''');
+ }
+
+ Future<void> test_mixin_trailingComments() async {
+ await _parseTestUnit(r'''
+mixin M { // mixinM
+ // instanceA
+ int instanceA; // instanceA
+ // foo()
+ void foo() {} // foo()
+ // staticA
+ static int staticA; // staticA
+ // static_b
+ static int static_b; // static_b
+}
+''');
+ // validate change
+ _assertSort(r'''
+mixin M { // mixinM
+ // staticA
+ static int staticA; // staticA
+ // static_b
+ static int static_b; // static_b
+ // instanceA
+ int instanceA; // instanceA
+ // foo()
+ void foo() {} // foo()
+}
+''');
+ }
+
Future<void> test_mixinMembers_method() async {
await _parseTestUnit(r'''
mixin A {
diff --git a/pkg/telemetry/analysis_options.yaml b/pkg/telemetry/analysis_options.yaml
index 0fcad72..bb2ae44 100644
--- a/pkg/telemetry/analysis_options.yaml
+++ b/pkg/telemetry/analysis_options.yaml
@@ -1,8 +1,8 @@
include: package:lints/recommended.yaml
analyzer:
- strong-mode:
- implicit-casts: false
+ language:
+ strict-casts: true
linter:
rules:
- unawaited_futures
diff --git a/runtime/tests/vm/dart/print_object_layout_script.dart b/runtime/tests/vm/dart/print_object_layout_script.dart
new file mode 100644
index 0000000..d063d6a
--- /dev/null
+++ b/runtime/tests/vm/dart/print_object_layout_script.dart
@@ -0,0 +1,25 @@
+// 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.
+
+// Test script for print_object_layout_test.dart
+
+class ClassA {
+ String fieldA1 = 'a';
+ int fieldA2 = 1;
+}
+
+class ClassB extends ClassA {
+ String fieldB1 = 'b';
+ int fieldB2 = 2;
+ int unusedB3 = 3;
+ static int staticB4 = 4;
+}
+
+@pragma('vm:never-inline')
+useFields(ClassB obj) =>
+ "${obj.fieldA1}${obj.fieldA2}${obj.fieldB1}${obj.fieldB2}${ClassB.staticB4}";
+
+main() {
+ useFields(ClassB());
+}
diff --git a/runtime/tests/vm/dart/print_object_layout_test.dart b/runtime/tests/vm/dart/print_object_layout_test.dart
new file mode 100644
index 0000000..5aa0ee3
--- /dev/null
+++ b/runtime/tests/vm/dart/print_object_layout_test.dart
@@ -0,0 +1,92 @@
+// 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.
+
+// OtherResources=print_object_layout_script.dart
+
+// Test for --print-object-layout-to option of gen_snapshot.
+
+import 'dart:convert' show jsonDecode;
+import 'dart:math' show max;
+import 'dart:io' show File, Platform;
+
+import 'package:expect/expect.dart';
+import 'package:path/path.dart' as path;
+import 'snapshot_test_helper.dart';
+
+verifyObjectLayout(String path) {
+ final classes = jsonDecode(File(path).readAsStringSync());
+ var sizeA, fieldsA;
+ var sizeB, fieldsB;
+ for (var cls in classes) {
+ if (cls['class'] == 'ClassA') {
+ sizeA = cls['size'].toInt();
+ fieldsA = cls['fields'];
+ print(cls);
+ } else if (cls['class'] == 'ClassB') {
+ sizeB = cls['size'].toInt();
+ fieldsB = cls['fields'];
+ print(cls);
+ }
+ }
+ Expect.isNotNull(sizeA);
+ Expect.isTrue(sizeA > 0);
+ Expect.isTrue(fieldsA.length == 2);
+ int maxOffsetA = 0;
+ for (var field in fieldsA) {
+ String fieldName = field['field'];
+ Expect.isTrue(fieldName == 'fieldA1' || fieldName == 'fieldA2');
+ int offset = field['offset'].toInt();
+ Expect.isTrue((offset > 0) && (offset < sizeA));
+ maxOffsetA = max(offset, maxOffsetA);
+ }
+
+ Expect.isNotNull(sizeB);
+ Expect.isTrue(sizeB > 0);
+ Expect.isTrue(sizeA < sizeB);
+ Expect.isTrue(fieldsB.length == 3);
+ for (var field in fieldsB) {
+ String fieldName = field['field'];
+ if (fieldName == 'staticB4') {
+ Expect.isTrue(field['static']);
+ } else {
+ Expect.isTrue(fieldName == 'fieldB1' || fieldName == 'fieldB2');
+ int offset = field['offset'].toInt();
+ Expect.isTrue((offset > 0) && (offset < sizeB));
+ Expect.isTrue(offset > maxOffsetA);
+ }
+ }
+}
+
+main() async {
+ // We don't have access to the SDK on Android.
+ if (Platform.isAndroid) {
+ print('Skipping test on Android');
+ return;
+ }
+
+ final testScriptUri =
+ Platform.script.resolve('print_object_layout_script.dart');
+
+ await withTempDir((String temp) async {
+ final appDillPath = path.join(temp, 'app.dill');
+ final snapshotPath = path.join(temp, 'aot.snapshot');
+ final objectLayoutPath = path.join(temp, 'layout.json');
+
+ await runGenKernel('BUILD DILL FILE', [
+ '--aot',
+ '--link-platform',
+ '--output=$appDillPath',
+ testScriptUri.toFilePath(),
+ ]);
+
+ await runGenSnapshot('GENERATE SNAPSHOT', [
+ '--snapshot-kind=app-aot-elf',
+ '--elf=$snapshotPath',
+ '--print-object-layout-to=$objectLayoutPath',
+ appDillPath,
+ ]);
+
+ verifyObjectLayout(objectLayoutPath);
+ });
+}
diff --git a/runtime/tests/vm/dart_2/print_object_layout_script.dart b/runtime/tests/vm/dart_2/print_object_layout_script.dart
new file mode 100644
index 0000000..397fd1c
--- /dev/null
+++ b/runtime/tests/vm/dart_2/print_object_layout_script.dart
@@ -0,0 +1,27 @@
+// 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
+
+// Test script for print_object_layout_test.dart
+
+class ClassA {
+ String fieldA1 = 'a';
+ int fieldA2 = 1;
+}
+
+class ClassB extends ClassA {
+ String fieldB1 = 'b';
+ int fieldB2 = 2;
+ int unusedB3 = 3;
+ static int staticB4 = 4;
+}
+
+@pragma('vm:never-inline')
+useFields(ClassB obj) =>
+ "${obj.fieldA1}${obj.fieldA2}${obj.fieldB1}${obj.fieldB2}${ClassB.staticB4}";
+
+main() {
+ useFields(ClassB());
+}
diff --git a/runtime/tests/vm/dart_2/print_object_layout_test.dart b/runtime/tests/vm/dart_2/print_object_layout_test.dart
new file mode 100644
index 0000000..5f0f43e
--- /dev/null
+++ b/runtime/tests/vm/dart_2/print_object_layout_test.dart
@@ -0,0 +1,94 @@
+// 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
+
+// OtherResources=print_object_layout_script.dart
+
+// Test for --print-object-layout-to option of gen_snapshot.
+
+import 'dart:convert' show jsonDecode;
+import 'dart:math' show max;
+import 'dart:io' show File, Platform;
+
+import 'package:expect/expect.dart';
+import 'package:path/path.dart' as path;
+import 'snapshot_test_helper.dart';
+
+verifyObjectLayout(String path) {
+ final classes = jsonDecode(File(path).readAsStringSync());
+ var sizeA, fieldsA;
+ var sizeB, fieldsB;
+ for (var cls in classes) {
+ if (cls['class'] == 'ClassA') {
+ sizeA = cls['size'].toInt();
+ fieldsA = cls['fields'];
+ print(cls);
+ } else if (cls['class'] == 'ClassB') {
+ sizeB = cls['size'].toInt();
+ fieldsB = cls['fields'];
+ print(cls);
+ }
+ }
+ Expect.isNotNull(sizeA);
+ Expect.isTrue(sizeA > 0);
+ Expect.isTrue(fieldsA.length == 2);
+ int maxOffsetA = 0;
+ for (var field in fieldsA) {
+ String fieldName = field['field'];
+ Expect.isTrue(fieldName == 'fieldA1' || fieldName == 'fieldA2');
+ int offset = field['offset'].toInt();
+ Expect.isTrue((offset > 0) && (offset < sizeA));
+ maxOffsetA = max(offset, maxOffsetA);
+ }
+
+ Expect.isNotNull(sizeB);
+ Expect.isTrue(sizeB > 0);
+ Expect.isTrue(sizeA < sizeB);
+ Expect.isTrue(fieldsB.length == 3);
+ for (var field in fieldsB) {
+ String fieldName = field['field'];
+ if (fieldName == 'staticB4') {
+ Expect.isTrue(field['static']);
+ } else {
+ Expect.isTrue(fieldName == 'fieldB1' || fieldName == 'fieldB2');
+ int offset = field['offset'].toInt();
+ Expect.isTrue((offset > 0) && (offset < sizeB));
+ Expect.isTrue(offset > maxOffsetA);
+ }
+ }
+}
+
+main() async {
+ // We don't have access to the SDK on Android.
+ if (Platform.isAndroid) {
+ print('Skipping test on Android');
+ return;
+ }
+
+ final testScriptUri =
+ Platform.script.resolve('print_object_layout_script.dart');
+
+ await withTempDir((String temp) async {
+ final appDillPath = path.join(temp, 'app.dill');
+ final snapshotPath = path.join(temp, 'aot.snapshot');
+ final objectLayoutPath = path.join(temp, 'layout.json');
+
+ await runGenKernel('BUILD DILL FILE', [
+ '--aot',
+ '--link-platform',
+ '--output=$appDillPath',
+ testScriptUri.toFilePath(),
+ ]);
+
+ await runGenSnapshot('GENERATE SNAPSHOT', [
+ '--snapshot-kind=app-aot-elf',
+ '--elf=$snapshotPath',
+ '--print-object-layout-to=$objectLayoutPath',
+ appDillPath,
+ ]);
+
+ verifyObjectLayout(objectLayoutPath);
+ });
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index f4bc06c..6380213 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -20,6 +20,7 @@
dart/isolates/fast_object_copy_test: Pass, Slow # Slow due to doing a lot of transitive object copies.
dart/minimal_kernel_test: Pass, Slow # Spawns several subprocesses
dart/null_safety_autodetection_in_kernel_compiler_test: Pass, Slow # Spawns several subprocesses
+dart/print_object_layout_test: Pass, Slow # Spawns several subprocesses
dart/slow_path_shared_stub_test: Pass, Slow # Uses --shared-slow-path-triggers-gc flag.
dart/snapshot_version_test: Skip # This test is a Dart1 test (script snapshot)
dart/stack_overflow_shared_test: Pass, Slow # Uses --shared-slow-path-triggers-gc flag.
@@ -32,6 +33,7 @@
dart_2/isolates/fast_object_copy_test: Pass, Slow # Slow due to doing a lot of transitive object copies.
dart_2/minimal_kernel_test: Pass, Slow # Spawns several subprocesses
dart_2/null_safety_autodetection_in_kernel_compiler_test: Pass, Slow # Spawns several subprocesses
+dart_2/print_object_layout_test: Pass, Slow # Spawns several subprocesses
dart_2/slow_path_shared_stub_test: Pass, Slow # Uses --shared-slow-path-triggers-gc flag.
dart_2/snapshot_version_test: Skip # This test is a Dart1 test (script snapshot)
dart_2/stack_overflow_shared_test: Pass, Slow # Uses --shared-slow-path-triggers-gc flag.
@@ -55,10 +57,12 @@
dart/kernel_determinism_test: SkipSlow
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
dart/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
+dart/print_object_layout_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
dart_2/appjit*: SkipByDesign # Test needs to a particular opt-counter value
dart_2/kernel_determinism_test: SkipSlow
dart_2/minimal_kernel_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
dart_2/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
+dart_2/print_object_layout_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
[ $builder_tag == tsan ]
dart/appjit_cha_deopt_test: SkipSlow
@@ -127,12 +131,14 @@
dart/b162922506_test: SkipSlow # Generates very large input file
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow in debug mode
dart/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow in debug mode
+dart/print_object_layout_test: SkipSlow # gen_kernel is too slow in debug mode
dart/spawn_shutdown_test: Pass, Slow # VM Shutdown test, It can take some time for all the isolates to shutdown in a Debug build.
dart/type_casts_with_null_safety_autodetection_test: Pass, Slow # Very slow in debug mode, uses --optimization-counter-threshold=10
dart_2/appjit_cha_deopt_test: Pass, Slow # Quite slow in debug mode, uses --optimization-counter-threshold=100
dart_2/b162922506_test: SkipSlow # Generates very large input file
dart_2/minimal_kernel_test: SkipSlow # gen_kernel is too slow in debug mode
dart_2/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow in debug mode
+dart_2/print_object_layout_test: SkipSlow # gen_kernel is too slow in debug mode
dart_2/spawn_shutdown_test: Pass, Slow # VM Shutdown test, It can take some time for all the isolates to shutdown in a Debug build.
[ $mode == product ]
@@ -245,12 +251,14 @@
dart/data_uri_spawn_test: Skip # Please triage.
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow on simulated architectures
dart/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow on simulated architectures
+dart/print_object_layout_test: SkipSlow # gen_kernel is too slow on simulated architectures
dart/snapshot_version_test: RuntimeError # Please triage.
dart_2/appjit*: SkipSlow # DFE too slow
dart_2/b162922506_test: SkipSlow # Generates large input file
dart_2/data_uri_spawn_test: Skip # Please triage.
dart_2/minimal_kernel_test: SkipSlow # gen_kernel is too slow on simulated architectures
dart_2/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow on simulated architectures
+dart_2/print_object_layout_test: SkipSlow # gen_kernel is too slow on simulated architectures
dart_2/snapshot_version_test: RuntimeError # Please triage.
[ $compiler == dartk && ($hot_reload || $hot_reload_rollback) ]
@@ -264,6 +272,7 @@
dart/kernel_determinism_test: SkipByDesign # Test needs to run from source
dart/minimal_kernel_test: SkipByDesign # Test needs to run from source
dart/null_safety_autodetection_in_kernel_compiler_test: SkipByDesign # Test needs to run from source
+dart/print_object_layout_test: SkipByDesign # Test needs to run from source
dart/regress_44026_test: SkipByDesign # Test needs to run from source
dart/snapshot_depfile_test: SkipByDesign # Test needs to run from source
dart/type_casts_with_null_safety_autodetection_test: SkipByDesign # Test needs to run from source
@@ -271,6 +280,7 @@
dart_2/kernel_determinism_test: SkipByDesign # Test needs to run from source
dart_2/minimal_kernel_test: SkipByDesign # Test needs to run from source
dart_2/null_safety_autodetection_in_kernel_compiler_test: SkipByDesign # Test needs to run from source
+dart_2/print_object_layout_test: SkipByDesign # Test needs to run from source
dart_2/snapshot_depfile_test: SkipByDesign # Test needs to run from source
[ $compiler == dartkp && ($arch == simarm || $arch == simarm64 || $arch == simarm64c) ]
@@ -430,6 +440,7 @@
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow in hot reload testing mode
dart/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow in hot reload testing mode
dart/print_flow_graph_determinism_test: SkipSlow
+dart/print_object_layout_test: SkipSlow # gen_kernel is too slow in hot reload testing mode
dart/slow_path_shared_stub_test: SkipSlow # Too slow with --shared-slow-path-triggers-gc flag and not relevant outside precompiled.
dart/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloads.
dart/spawn_shutdown_test: Skip # We can shutdown an isolate before it reloads.
@@ -441,6 +452,7 @@
dart_2/minimal_kernel_test: SkipSlow # gen_kernel is too slow in hot reload testing mode
dart_2/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow in hot reload testing mode
dart_2/print_flow_graph_determinism_test: SkipSlow
+dart_2/print_object_layout_test: SkipSlow # gen_kernel is too slow in hot reload testing mode
dart_2/slow_path_shared_stub_test: SkipSlow # Too slow with --shared-slow-path-triggers-gc flag and not relevant outside precompiled.
dart_2/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloads.
dart_2/spawn_shutdown_test: Skip # We can shutdown an isolate before it reloads.
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index a1c58c0..edec756 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -534,6 +534,70 @@
shared_class_table_->SetSizeAt(cid, size);
}
+#if defined(DART_PRECOMPILER)
+void ClassTable::PrintObjectLayout(const char* filename) {
+ Class& cls = Class::Handle();
+ Array& fields = Array::Handle();
+ Field& field = Field::Handle();
+
+ JSONWriter js;
+ js.OpenArray();
+ for (intptr_t i = ClassId::kObjectCid; i < top_; i++) {
+ if (!HasValidClassAt(i)) {
+ continue;
+ }
+ cls = At(i);
+ ASSERT(!cls.IsNull());
+ ASSERT(cls.id() != kIllegalCid);
+ ASSERT(cls.is_finalized()); // Precompiler already finalized all classes.
+ ASSERT(!cls.IsTopLevel());
+ js.OpenObject();
+ js.PrintProperty("class", cls.UserVisibleNameCString());
+ js.PrintProperty("size", cls.target_instance_size());
+ js.OpenArray("fields");
+ fields = cls.fields();
+ if (!fields.IsNull()) {
+ for (intptr_t i = 0, n = fields.Length(); i < n; ++i) {
+ field ^= fields.At(i);
+ js.OpenObject();
+ js.PrintProperty("field", field.UserVisibleNameCString());
+ if (field.is_static()) {
+ js.PrintPropertyBool("static", true);
+ } else {
+ js.PrintProperty("offset", field.TargetOffset());
+ }
+ js.CloseObject();
+ }
+ }
+ js.CloseArray();
+ js.CloseObject();
+ }
+ js.CloseArray();
+
+ auto file_open = Dart::file_open_callback();
+ auto file_write = Dart::file_write_callback();
+ auto file_close = Dart::file_close_callback();
+ if ((file_open == nullptr) || (file_write == nullptr) ||
+ (file_close == nullptr)) {
+ OS::PrintErr("warning: Could not access file callbacks.");
+ return;
+ }
+
+ void* file = file_open(filename, /*write=*/true);
+ if (file == nullptr) {
+ OS::PrintErr("warning: Failed to write object layout: %s\n", filename);
+ return;
+ }
+
+ char* output = nullptr;
+ intptr_t output_length = 0;
+ js.Steal(&output, &output_length);
+ file_write(output, output_length, file);
+ free(output);
+ file_close(file);
+}
+#endif // defined(DART_PRECOMPILER)
+
#ifndef PRODUCT
void ClassTable::PrintToJSONObject(JSONObject* object) {
Class& cls = Class::Handle();
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index e89b978..1e6ca5f 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -394,6 +394,10 @@
void Print();
+#if defined(DART_PRECOMPILER)
+ void PrintObjectLayout(const char* filename);
+#endif
+
#ifndef PRODUCT
// Describes layout of heap stats for code generation. See offset_extractor.cc
struct ArrayTraits {
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 3726ba2..930e8ad 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -67,6 +67,10 @@
"Print per-phase breakdown of time spent precompiling");
DEFINE_FLAG(bool, print_unique_targets, false, "Print unique dynamic targets");
DEFINE_FLAG(bool, print_gop, false, "Print global object pool");
+DEFINE_FLAG(charp,
+ print_object_layout_to,
+ nullptr,
+ "Print layout of Dart objects to the given file");
DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler.");
DEFINE_FLAG(
int,
@@ -469,6 +473,10 @@
FinalizeAllClasses();
ASSERT(Error::Handle(Z, T->sticky_error()).IsNull());
+ if (FLAG_print_object_layout_to != nullptr) {
+ IG->class_table()->PrintObjectLayout(FLAG_print_object_layout_to);
+ }
+
ClassFinalizer::SortClasses();
// Collects type usage information which allows us to decide when/how to
diff --git a/sdk/lib/_internal/vm/lib/array.dart b/sdk/lib/_internal/vm/lib/array.dart
index c897b67..ba48fbe 100644
--- a/sdk/lib/_internal/vm/lib/array.dart
+++ b/sdk/lib/_internal/vm/lib/array.dart
@@ -61,8 +61,11 @@
factory _List._ofGrowableList(_GrowableList<E> elements) {
final int length = elements.length;
final list = _List<E>(length);
- for (int i = 0; i < length; i++) {
- list[i] = elements[i];
+ // TODO(30102): Remove this loop zero-trip guard.
+ if (length > 0) {
+ for (int i = 0; i < length; i++) {
+ list[i] = elements[i];
+ }
}
return list;
}
@@ -70,8 +73,11 @@
factory _List._ofList(_List<E> elements) {
final int length = elements.length;
final list = _List<E>(length);
- for (int i = 0; i < length; i++) {
- list[i] = elements[i];
+ // TODO(30102): Remove this loop zero-trip guard.
+ if (length > 0) {
+ for (int i = 0; i < length; i++) {
+ list[i] = elements[i];
+ }
}
return list;
}
@@ -79,8 +85,11 @@
factory _List._ofImmutableList(_ImmutableList<E> elements) {
final int length = elements.length;
final list = _List<E>(length);
- for (int i = 0; i < length; i++) {
- list[i] = elements[i];
+ // TODO(30102): Remove this loop zero-trip guard.
+ if (length > 0) {
+ for (int i = 0; i < length; i++) {
+ list[i] = elements[i];
+ }
}
return list;
}
diff --git a/sdk/lib/_internal/vm/lib/growable_array.dart b/sdk/lib/_internal/vm/lib/growable_array.dart
index 516996f..c6d9e46 100644
--- a/sdk/lib/_internal/vm/lib/growable_array.dart
+++ b/sdk/lib/_internal/vm/lib/growable_array.dart
@@ -110,7 +110,10 @@
// Specialization of List.empty constructor for growable == true.
// Used by pkg/vm/lib/transformations/list_factory_specializer.dart.
@pragma("vm:prefer-inline")
- factory _GrowableList.empty() => _GrowableList(0);
+ factory _GrowableList.empty() {
+ // Specialization of `return _GrowableList(0);`.
+ return _GrowableList<T>._withData(_emptyList);
+ }
// Specialization of List.filled constructor for growable == true.
// Used by pkg/vm/lib/transformations/list_factory_specializer.dart.
@@ -154,43 +157,61 @@
factory _GrowableList._ofList(_List<T> elements) {
final int length = elements.length;
- final list = _GrowableList<T>(length);
- for (int i = 0; i < length; i++) {
- list[i] = elements[i];
+ if (length > 0) {
+ final data = _List(_adjustedCapacity(length));
+ for (int i = 0; i < length; i++) {
+ data[i] = elements[i];
+ }
+ final list = _GrowableList<T>._withData(data);
+ list._setLength(length);
+ return list;
}
- return list;
+ return _GrowableList<T>.empty();
}
factory _GrowableList._ofGrowableList(_GrowableList<T> elements) {
final int length = elements.length;
- final list = _GrowableList<T>(length);
- for (int i = 0; i < length; i++) {
- list[i] = elements[i];
+ if (length > 0) {
+ final data = _List(_adjustedCapacity(length));
+ for (int i = 0; i < length; i++) {
+ data[i] = elements[i];
+ }
+ final list = _GrowableList<T>._withData(data);
+ list._setLength(length);
+ return list;
}
- return list;
+ return _GrowableList<T>.empty();
}
factory _GrowableList._ofImmutableList(_ImmutableList<T> elements) {
final int length = elements.length;
- final list = _GrowableList<T>(length);
- for (int i = 0; i < length; i++) {
- list[i] = elements[i];
+ if (length > 0) {
+ final data = _List(_adjustedCapacity(length));
+ for (int i = 0; i < length; i++) {
+ data[i] = elements[i];
+ }
+ final list = _GrowableList<T>._withData(data);
+ list._setLength(length);
+ return list;
}
- return list;
+ return _GrowableList<T>.empty();
}
factory _GrowableList._ofEfficientLengthIterable(
EfficientLengthIterable<T> elements) {
final int length = elements.length;
- final list = _GrowableList<T>(length);
if (length > 0) {
+ final data = _List(_adjustedCapacity(length));
int i = 0;
for (var element in elements) {
- list[i++] = element;
+ data[i++] = element;
}
if (i != length) throw ConcurrentModificationError(elements);
+ final list = _GrowableList<T>._withData(data);
+ list._setLength(length);
+ return list;
}
- return list;
+ return _GrowableList<T>.empty();
}
factory _GrowableList._ofOther(Iterable<T> elements) {
@@ -358,11 +379,13 @@
// Use shared empty list as backing.
return _emptyList;
}
- // Round up size to the next odd number, since this is free
- // because of alignment requirements of the GC.
- return new _List(capacity | 1);
+ return _List(_adjustedCapacity(capacity));
}
+ // Round up size to the next odd number, since this is free
+ // because of alignment requirements of the GC.
+ static int _adjustedCapacity(int capacity) => capacity | 1;
+
// Grow from 0 to 3, and then double + 1.
int _nextCapacity(int old_capacity) => (old_capacity * 2) | 3;
@@ -501,14 +524,22 @@
}
List<T> toList({bool growable: true}) {
+ // TODO(sra): We should be able to replace the following with:
+ //
+ // return growable
+ // ? _GrowableList<T>._ofGrowableList(this)
+ // : _List<T>._ofGrowableList(this);
+ //
+ // However, the extra call causes a 5% regression in `ListCopy.toList.2`.
+
final length = this.length;
if (growable) {
if (length > 0) {
- final list = new _List(length);
+ final data = new _List(_adjustedCapacity(length));
for (int i = 0; i < length; i++) {
- list[i] = this[i];
+ data[i] = this[i];
}
- final result = new _GrowableList<T>._withData(list);
+ final result = new _GrowableList<T>._withData(data);
result._setLength(length);
return result;
}
diff --git a/tools/VERSION b/tools/VERSION
index 1745e69..041000b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 123
+PRERELEASE 124
PRERELEASE_PATCH 0
\ No newline at end of file