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