Version 2.10.3
* Cherry-pick 34b485c0c4ef3a1b24f89fb2af3ec6ec6837a401 to stable
* Cherry-pick aa329dc0d05b398ce57057a0d2842b7167130845 to stable
* Cherry-pick 32dfefbea17d92302147bec203324606200315f9 to stable
* Cherry-pick 13d2937f768180b083ce6ffdcf7d3cd9a4c5440a to stable
* Cherry-pick 50d36afc34e1f533b66ce02ccdf6cf693958355b to stable
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cac84bf..3113e34 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,25 @@
-## 2.10.2 - 2020-10-13
+## 2.10.3 - 2020-10-29
+
+This is a patch release that fixes the following issues:
+* breaking changes in Chrome 86 that affect DDC (issues [#43750][] and
+ [#43193][]).
+* compiler error causing incorrect use of positional parameters when named
+ parameters should be used instead (issues [flutter/flutter#65324][] and
+ [flutter/flutter#68092][]).
+* crashes and/or undefined behavor in AOT compiled code (issues [#43770][] and
+ [#43786][]).
+* AOT compilation of classes with more than 64 unboxed fields
+ (issue [flutter/flutter#67803][]).
+
+[#43750]: https://github.com/dart-lang/sdk/issues/43750
+[#43193]: https://github.com/dart-lang/sdk/issues/43193
+[flutter/flutter#65324]: https://github.com/flutter/flutter/issues/65324
+[flutter/flutter#68092]: https://github.com/flutter/flutter/issues/68092
+[#43770]: https://github.com/dart-lang/sdk/issues/43770
+[#43786]: https://github.com/dart-lang/sdk/issues/43786
+[flutter/flutter#67803]: https://github.com/flutter/flutter/issues/67803
+
+## 2.10.2 - 2020-10-15
This is a patch release that fixes a DDC compiler crash (issue [#43589]).
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
index 0aea072..28ac4f2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
@@ -155,7 +155,7 @@
}
for (int i = 0; i < namedParameters.length; i++) {
NamedType parameter = namedParameters[i];
- TypeBuilder type = positionalParameters[i].accept(this);
+ TypeBuilder type = parameter.type.accept(this);
formals[i + positionalParameters.length] = new FormalParameterBuilder(
null, 0, type, parameter.name, null, -1, null)
..kind = FormalParameterKind.optionalNamed;
diff --git a/pkg/front_end/testcases/general/flutter_issue68092/main.dart b/pkg/front_end/testcases/general/flutter_issue68092/main.dart
new file mode 100644
index 0000000..4ff4f3b
--- /dev/null
+++ b/pkg/front_end/testcases/general/flutter_issue68092/main.dart
@@ -0,0 +1,6 @@
+import 'main_lib.dart';
+
+void main() {
+ int f({int x}) => null;
+ Registry().register(f);
+}
diff --git a/pkg/front_end/testcases/general/flutter_issue68092/main.dart.outline.expect b/pkg/front_end/testcases/general/flutter_issue68092/main.dart.outline.expect
new file mode 100644
index 0000000..cfc2e45
--- /dev/null
+++ b/pkg/front_end/testcases/general/flutter_issue68092/main.dart.outline.expect
@@ -0,0 +1,32 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///main_lib.dart";
+
+static method main() → void
+ ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class DynamicDispatchRegistry<T extends core::Function* = core::Function*> extends core::Object {
+ synthetic constructor •() → self2::DynamicDispatchRegistry<self2::DynamicDispatchRegistry::T*>*
+ ;
+ method register(generic-covariant-impl self2::DynamicDispatchRegistry::T* function) → self2::DynamicDispatchRegistry::T*
+ ;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class Registry extends self2::DynamicDispatchRegistry<({x: core::int*}) →* core::int*> {
+ synthetic constructor •() → self2::Registry*
+ ;
+}
diff --git a/pkg/front_end/testcases/general/flutter_issue68092/main.dart.strong.expect b/pkg/front_end/testcases/general/flutter_issue68092/main.dart.strong.expect
new file mode 100644
index 0000000..317b261
--- /dev/null
+++ b/pkg/front_end/testcases/general/flutter_issue68092/main.dart.strong.expect
@@ -0,0 +1,43 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "main_lib.dart" as mai;
+
+import "org-dartlang-testcase:///main_lib.dart";
+
+static method main() → void {
+ function f({core::int* x = #C1}) → core::int*
+ return null;
+ new mai::Registry::•().{mai::DynamicDispatchRegistry::register}(f);
+}
+
+library;
+import self as mai;
+import "dart:core" as core;
+
+class DynamicDispatchRegistry<T extends core::Function* = core::Function*> extends core::Object {
+ synthetic constructor •() → mai::DynamicDispatchRegistry<mai::DynamicDispatchRegistry::T*>*
+ : super core::Object::•()
+ ;
+ method register(generic-covariant-impl mai::DynamicDispatchRegistry::T* function) → mai::DynamicDispatchRegistry::T*
+ return null;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class Registry extends mai::DynamicDispatchRegistry<({x: core::int*}) →* core::int*> {
+ synthetic constructor •() → mai::Registry*
+ : super mai::DynamicDispatchRegistry::•()
+ ;
+}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/general/flutter_issue68092/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/flutter_issue68092/main.dart.strong.transformed.expect
new file mode 100644
index 0000000..317b261
--- /dev/null
+++ b/pkg/front_end/testcases/general/flutter_issue68092/main.dart.strong.transformed.expect
@@ -0,0 +1,43 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "main_lib.dart" as mai;
+
+import "org-dartlang-testcase:///main_lib.dart";
+
+static method main() → void {
+ function f({core::int* x = #C1}) → core::int*
+ return null;
+ new mai::Registry::•().{mai::DynamicDispatchRegistry::register}(f);
+}
+
+library;
+import self as mai;
+import "dart:core" as core;
+
+class DynamicDispatchRegistry<T extends core::Function* = core::Function*> extends core::Object {
+ synthetic constructor •() → mai::DynamicDispatchRegistry<mai::DynamicDispatchRegistry::T*>*
+ : super core::Object::•()
+ ;
+ method register(generic-covariant-impl mai::DynamicDispatchRegistry::T* function) → mai::DynamicDispatchRegistry::T*
+ return null;
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class Registry extends mai::DynamicDispatchRegistry<({x: core::int*}) →* core::int*> {
+ synthetic constructor •() → mai::Registry*
+ : super mai::DynamicDispatchRegistry::•()
+ ;
+}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/general/flutter_issue68092/main.dart.textual_outline.expect b/pkg/front_end/testcases/general/flutter_issue68092/main.dart.textual_outline.expect
new file mode 100644
index 0000000..3e55fb8
--- /dev/null
+++ b/pkg/front_end/testcases/general/flutter_issue68092/main.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+import 'main_lib.dart';
+
+void main() {}
diff --git a/pkg/front_end/testcases/general/flutter_issue68092/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/flutter_issue68092/main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3e55fb8
--- /dev/null
+++ b/pkg/front_end/testcases/general/flutter_issue68092/main.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+import 'main_lib.dart';
+
+void main() {}
diff --git a/pkg/front_end/testcases/general/flutter_issue68092/main_lib.dart b/pkg/front_end/testcases/general/flutter_issue68092/main_lib.dart
new file mode 100644
index 0000000..e43e181
--- /dev/null
+++ b/pkg/front_end/testcases/general/flutter_issue68092/main_lib.dart
@@ -0,0 +1,5 @@
+class DynamicDispatchRegistry<T extends Function> {
+ T register(T function) => null;
+}
+
+class Registry extends DynamicDispatchRegistry<int Function({int x})> {}
diff --git a/pkg/front_end/testcases/general/flutter_issue68092/test.options b/pkg/front_end/testcases/general/flutter_issue68092/test.options
new file mode 100644
index 0000000..bfe6dc8
--- /dev/null
+++ b/pkg/front_end/testcases/general/flutter_issue68092/test.options
@@ -0,0 +1 @@
+main_lib.dart
\ No newline at end of file
diff --git a/runtime/tests/vm/dart/flutter_regression67803_test.dart b/runtime/tests/vm/dart/flutter_regression67803_test.dart
new file mode 100644
index 0000000..71abd70
--- /dev/null
+++ b/runtime/tests/vm/dart/flutter_regression67803_test.dart
@@ -0,0 +1,372 @@
+// 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:expect/expect.dart';
+
+final bool kTrue = int.parse('1') == 1;
+
+main() {
+ // Ensure fields are not inferred to be constants and ensure we use all fields
+ // (to avoid them being tree shaken).
+ final useAllFields = (kTrue ? foo : foo2).toString();
+ for (int i = 0; i <= 64; ++i) {
+ Expect.isTrue(useAllFields.contains('$i'));
+ }
+
+ // Ensure calling dyn:get:field64 returns the right value.
+ Expect.equals(64, ((kTrue ? foo : Baz(10)) as dynamic).field64);
+
+ // Ensure calling get:field64 returns the right value.
+ Expect.equals(64, (kTrue ? foo : Bar(10)).field64);
+
+ // Ensure potentially inlined, direct field load yield right value.
+ Expect.equals(64, (kTrue ? foo : foo2).field64);
+}
+
+final foo = Foo(
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64);
+
+final foo2 = Foo(
+ 2 * 0,
+ 2 * 1,
+ 2 * 2,
+ 2 * 3,
+ 2 * 4,
+ 2 * 5,
+ 2 * 6,
+ 2 * 7,
+ 2 * 8,
+ 2 * 9,
+ 2 * 10,
+ 2 * 11,
+ 2 * 12,
+ 2 * 13,
+ 2 * 14,
+ 2 * 15,
+ 2 * 16,
+ 2 * 17,
+ 2 * 18,
+ 2 * 19,
+ 2 * 20,
+ 2 * 21,
+ 2 * 22,
+ 2 * 23,
+ 2 * 24,
+ 2 * 25,
+ 2 * 26,
+ 2 * 27,
+ 2 * 28,
+ 2 * 29,
+ 2 * 30,
+ 2 * 31,
+ 2 * 32,
+ 2 * 33,
+ 2 * 34,
+ 2 * 35,
+ 2 * 36,
+ 2 * 37,
+ 2 * 38,
+ 2 * 39,
+ 2 * 40,
+ 2 * 41,
+ 2 * 42,
+ 2 * 43,
+ 2 * 44,
+ 2 * 45,
+ 2 * 46,
+ 2 * 47,
+ 2 * 48,
+ 2 * 49,
+ 2 * 50,
+ 2 * 51,
+ 2 * 52,
+ 2 * 53,
+ 2 * 54,
+ 2 * 55,
+ 2 * 56,
+ 2 * 57,
+ 2 * 58,
+ 2 * 59,
+ 2 * 60,
+ 2 * 61,
+ 2 * 62,
+ 2 * 63,
+ 2 * 64);
+
+class Bar {
+ final int field64;
+ Bar(this.field64);
+}
+
+class Baz {
+ final int field64;
+ Baz(this.field64);
+}
+
+class Foo implements Bar {
+ final int field0;
+ final int field1;
+ final int field2;
+ final int field3;
+ final int field4;
+ final int field5;
+ final int field6;
+ final int field7;
+ final int field8;
+ final int field9;
+ final int field10;
+ final int field11;
+ final int field12;
+ final int field13;
+ final int field14;
+ final int field15;
+ final int field16;
+ final int field17;
+ final int field18;
+ final int field19;
+ final int field20;
+ final int field21;
+ final int field22;
+ final int field23;
+ final int field24;
+ final int field25;
+ final int field26;
+ final int field27;
+ final int field28;
+ final int field29;
+ final int field30;
+ final int field31;
+ final int field32;
+ final int field33;
+ final int field34;
+ final int field35;
+ final int field36;
+ final int field37;
+ final int field38;
+ final int field39;
+ final int field40;
+ final int field41;
+ final int field42;
+ final int field43;
+ final int field44;
+ final int field45;
+ final int field46;
+ final int field47;
+ final int field48;
+ final int field49;
+ final int field50;
+ final int field51;
+ final int field52;
+ final int field53;
+ final int field54;
+ final int field55;
+ final int field56;
+ final int field57;
+ final int field58;
+ final int field59;
+ final int field60;
+ final int field61;
+ final int field62;
+ final int field63;
+ final int field64;
+
+ Foo(
+ this.field0,
+ this.field1,
+ this.field2,
+ this.field3,
+ this.field4,
+ this.field5,
+ this.field6,
+ this.field7,
+ this.field8,
+ this.field9,
+ this.field10,
+ this.field11,
+ this.field12,
+ this.field13,
+ this.field14,
+ this.field15,
+ this.field16,
+ this.field17,
+ this.field18,
+ this.field19,
+ this.field20,
+ this.field21,
+ this.field22,
+ this.field23,
+ this.field24,
+ this.field25,
+ this.field26,
+ this.field27,
+ this.field28,
+ this.field29,
+ this.field30,
+ this.field31,
+ this.field32,
+ this.field33,
+ this.field34,
+ this.field35,
+ this.field36,
+ this.field37,
+ this.field38,
+ this.field39,
+ this.field40,
+ this.field41,
+ this.field42,
+ this.field43,
+ this.field44,
+ this.field45,
+ this.field46,
+ this.field47,
+ this.field48,
+ this.field49,
+ this.field50,
+ this.field51,
+ this.field52,
+ this.field53,
+ this.field54,
+ this.field55,
+ this.field56,
+ this.field57,
+ this.field58,
+ this.field59,
+ this.field60,
+ this.field61,
+ this.field62,
+ this.field63,
+ this.field64);
+
+ toString() => '''
+ $field0;
+ $field1;
+ $field2;
+ $field3;
+ $field4;
+ $field5;
+ $field6;
+ $field7;
+ $field8;
+ $field9;
+ $field10;
+ $field11;
+ $field12;
+ $field13;
+ $field14;
+ $field15;
+ $field16;
+ $field17;
+ $field18;
+ $field19;
+ $field20;
+ $field21;
+ $field22;
+ $field23;
+ $field24;
+ $field25;
+ $field26;
+ $field27;
+ $field28;
+ $field29;
+ $field30;
+ $field31;
+ $field32;
+ $field33;
+ $field34;
+ $field35;
+ $field36;
+ $field37;
+ $field38;
+ $field39;
+ $field40;
+ $field41;
+ $field42;
+ $field43;
+ $field44;
+ $field45;
+ $field46;
+ $field47;
+ $field48;
+ $field49;
+ $field50;
+ $field51;
+ $field52;
+ $field53;
+ $field54;
+ $field55;
+ $field56;
+ $field57;
+ $field58;
+ $field59;
+ $field60;
+ $field61;
+ $field62;
+ $field63;
+ $field64;
+ ''';
+}
diff --git a/runtime/tests/vm/dart_2/flutter_regression67803_test.dart b/runtime/tests/vm/dart_2/flutter_regression67803_test.dart
new file mode 100644
index 0000000..71abd70
--- /dev/null
+++ b/runtime/tests/vm/dart_2/flutter_regression67803_test.dart
@@ -0,0 +1,372 @@
+// 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:expect/expect.dart';
+
+final bool kTrue = int.parse('1') == 1;
+
+main() {
+ // Ensure fields are not inferred to be constants and ensure we use all fields
+ // (to avoid them being tree shaken).
+ final useAllFields = (kTrue ? foo : foo2).toString();
+ for (int i = 0; i <= 64; ++i) {
+ Expect.isTrue(useAllFields.contains('$i'));
+ }
+
+ // Ensure calling dyn:get:field64 returns the right value.
+ Expect.equals(64, ((kTrue ? foo : Baz(10)) as dynamic).field64);
+
+ // Ensure calling get:field64 returns the right value.
+ Expect.equals(64, (kTrue ? foo : Bar(10)).field64);
+
+ // Ensure potentially inlined, direct field load yield right value.
+ Expect.equals(64, (kTrue ? foo : foo2).field64);
+}
+
+final foo = Foo(
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64);
+
+final foo2 = Foo(
+ 2 * 0,
+ 2 * 1,
+ 2 * 2,
+ 2 * 3,
+ 2 * 4,
+ 2 * 5,
+ 2 * 6,
+ 2 * 7,
+ 2 * 8,
+ 2 * 9,
+ 2 * 10,
+ 2 * 11,
+ 2 * 12,
+ 2 * 13,
+ 2 * 14,
+ 2 * 15,
+ 2 * 16,
+ 2 * 17,
+ 2 * 18,
+ 2 * 19,
+ 2 * 20,
+ 2 * 21,
+ 2 * 22,
+ 2 * 23,
+ 2 * 24,
+ 2 * 25,
+ 2 * 26,
+ 2 * 27,
+ 2 * 28,
+ 2 * 29,
+ 2 * 30,
+ 2 * 31,
+ 2 * 32,
+ 2 * 33,
+ 2 * 34,
+ 2 * 35,
+ 2 * 36,
+ 2 * 37,
+ 2 * 38,
+ 2 * 39,
+ 2 * 40,
+ 2 * 41,
+ 2 * 42,
+ 2 * 43,
+ 2 * 44,
+ 2 * 45,
+ 2 * 46,
+ 2 * 47,
+ 2 * 48,
+ 2 * 49,
+ 2 * 50,
+ 2 * 51,
+ 2 * 52,
+ 2 * 53,
+ 2 * 54,
+ 2 * 55,
+ 2 * 56,
+ 2 * 57,
+ 2 * 58,
+ 2 * 59,
+ 2 * 60,
+ 2 * 61,
+ 2 * 62,
+ 2 * 63,
+ 2 * 64);
+
+class Bar {
+ final int field64;
+ Bar(this.field64);
+}
+
+class Baz {
+ final int field64;
+ Baz(this.field64);
+}
+
+class Foo implements Bar {
+ final int field0;
+ final int field1;
+ final int field2;
+ final int field3;
+ final int field4;
+ final int field5;
+ final int field6;
+ final int field7;
+ final int field8;
+ final int field9;
+ final int field10;
+ final int field11;
+ final int field12;
+ final int field13;
+ final int field14;
+ final int field15;
+ final int field16;
+ final int field17;
+ final int field18;
+ final int field19;
+ final int field20;
+ final int field21;
+ final int field22;
+ final int field23;
+ final int field24;
+ final int field25;
+ final int field26;
+ final int field27;
+ final int field28;
+ final int field29;
+ final int field30;
+ final int field31;
+ final int field32;
+ final int field33;
+ final int field34;
+ final int field35;
+ final int field36;
+ final int field37;
+ final int field38;
+ final int field39;
+ final int field40;
+ final int field41;
+ final int field42;
+ final int field43;
+ final int field44;
+ final int field45;
+ final int field46;
+ final int field47;
+ final int field48;
+ final int field49;
+ final int field50;
+ final int field51;
+ final int field52;
+ final int field53;
+ final int field54;
+ final int field55;
+ final int field56;
+ final int field57;
+ final int field58;
+ final int field59;
+ final int field60;
+ final int field61;
+ final int field62;
+ final int field63;
+ final int field64;
+
+ Foo(
+ this.field0,
+ this.field1,
+ this.field2,
+ this.field3,
+ this.field4,
+ this.field5,
+ this.field6,
+ this.field7,
+ this.field8,
+ this.field9,
+ this.field10,
+ this.field11,
+ this.field12,
+ this.field13,
+ this.field14,
+ this.field15,
+ this.field16,
+ this.field17,
+ this.field18,
+ this.field19,
+ this.field20,
+ this.field21,
+ this.field22,
+ this.field23,
+ this.field24,
+ this.field25,
+ this.field26,
+ this.field27,
+ this.field28,
+ this.field29,
+ this.field30,
+ this.field31,
+ this.field32,
+ this.field33,
+ this.field34,
+ this.field35,
+ this.field36,
+ this.field37,
+ this.field38,
+ this.field39,
+ this.field40,
+ this.field41,
+ this.field42,
+ this.field43,
+ this.field44,
+ this.field45,
+ this.field46,
+ this.field47,
+ this.field48,
+ this.field49,
+ this.field50,
+ this.field51,
+ this.field52,
+ this.field53,
+ this.field54,
+ this.field55,
+ this.field56,
+ this.field57,
+ this.field58,
+ this.field59,
+ this.field60,
+ this.field61,
+ this.field62,
+ this.field63,
+ this.field64);
+
+ toString() => '''
+ $field0;
+ $field1;
+ $field2;
+ $field3;
+ $field4;
+ $field5;
+ $field6;
+ $field7;
+ $field8;
+ $field9;
+ $field10;
+ $field11;
+ $field12;
+ $field13;
+ $field14;
+ $field15;
+ $field16;
+ $field17;
+ $field18;
+ $field19;
+ $field20;
+ $field21;
+ $field22;
+ $field23;
+ $field24;
+ $field25;
+ $field26;
+ $field27;
+ $field28;
+ $field29;
+ $field30;
+ $field31;
+ $field32;
+ $field33;
+ $field34;
+ $field35;
+ $field36;
+ $field37;
+ $field38;
+ $field39;
+ $field40;
+ $field41;
+ $field42;
+ $field43;
+ $field44;
+ $field45;
+ $field46;
+ $field47;
+ $field48;
+ $field49;
+ $field50;
+ $field51;
+ $field52;
+ $field53;
+ $field54;
+ $field55;
+ $field56;
+ $field57;
+ $field58;
+ $field59;
+ $field60;
+ $field61;
+ $field62;
+ $field63;
+ $field64;
+ ''';
+}
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 9196b2d..4c16c3a 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -128,6 +128,20 @@
}
}
+Representation FlowGraph::UnboxedFieldRepresentationOf(const Field& field) {
+ switch (field.UnboxedFieldCid()) {
+ case kDoubleCid:
+ return kUnboxedDouble;
+ case kFloat32x4Cid:
+ return kUnboxedFloat32x4;
+ case kFloat64x2Cid:
+ return kUnboxedFloat64x2;
+ default:
+ RELEASE_ASSERT(field.is_non_nullable_integer());
+ return kUnboxedInt64;
+ }
+}
+
void FlowGraph::ReplaceCurrentInstruction(ForwardInstructionIterator* iterator,
Instruction* current,
Instruction* replacement) {
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index bac38c8..50ea5ec 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -147,6 +147,8 @@
static Representation ReturnRepresentationOf(const Function& function);
+ static Representation UnboxedFieldRepresentationOf(const Field& field);
+
// The number of variables (or boxes) inside the functions frame - meaning
// below the frame pointer. This does not include the expression stack.
intptr_t num_stack_locals() const {
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index aa5891d..22dd71c 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -1012,21 +1012,7 @@
ASSERT((index == 0) || (index == 1));
if ((index == 1) && IsUnboxedStore()) {
const Field& field = slot().field();
- const intptr_t cid = field.UnboxedFieldCid();
- switch (cid) {
- case kDoubleCid:
- return kUnboxedDouble;
- case kFloat32x4Cid:
- return kUnboxedFloat32x4;
- case kFloat64x2Cid:
- return kUnboxedFloat64x2;
- default:
- if (field.is_non_nullable_integer()) {
- return kUnboxedInt64;
- } else {
- UNREACHABLE();
- }
- }
+ return FlowGraph::UnboxedFieldRepresentationOf(field);
}
return kTagged;
}
diff --git a/runtime/vm/compiler/graph_intrinsifier.cc b/runtime/vm/compiler/graph_intrinsifier.cc
index 3f77aa2..9b38d1d 100644
--- a/runtime/vm/compiler/graph_intrinsifier.cc
+++ b/runtime/vm/compiler/graph_intrinsifier.cc
@@ -1102,8 +1102,23 @@
BlockBuilder builder(flow_graph, normal_entry);
auto receiver = builder.AddParameter(0, /*with_frame=*/false);
- auto field_value = builder.AddDefinition(new (zone) LoadFieldInstr(
+ Definition* field_value = builder.AddDefinition(new (zone) LoadFieldInstr(
new (zone) Value(receiver), slot, builder.TokenPos()));
+
+ // We only support cases where we do not have to create a box (whose
+ // allocation could fail).
+ ASSERT(function.HasUnboxedReturnValue() ||
+ !FlowGraphCompiler::IsUnboxedField(field));
+
+ // We might need to unbox the field value before returning.
+ if (function.HasUnboxedReturnValue() &&
+ !FlowGraphCompiler::IsUnboxedField(field)) {
+ ASSERT(FLAG_precompiled_mode);
+ field_value = builder.AddUnboxInstr(
+ FlowGraph::ReturnRepresentationOf(flow_graph->function()),
+ new Value(field_value), /*is_checked=*/true);
+ }
+
builder.AddReturn(new (zone) Value(field_value));
return true;
}
@@ -1142,25 +1157,9 @@
// We do not support storing to possibly guarded fields in JIT in graph
// intrinsics.
ASSERT(FLAG_precompiled_mode);
-
- Representation representation = kNoRepresentation;
- switch (field.guarded_cid()) {
- case kDoubleCid:
- representation = kUnboxedDouble;
- break;
- case kFloat32x4Cid:
- representation = kUnboxedFloat32x4;
- break;
- case kFloat64x2Cid:
- representation = kUnboxedFloat64x2;
- break;
- default:
- ASSERT(field.is_non_nullable_integer());
- representation = kUnboxedInt64;
- break;
- }
- value = builder.AddUnboxInstr(representation, new Value(value),
- /*is_checked=*/true);
+ value = builder.AddUnboxInstr(
+ FlowGraph::UnboxedFieldRepresentationOf(field), new Value(value),
+ /*is_checked=*/true);
}
builder.AddInstruction(new (zone) StoreInstanceFieldInstr(
diff --git a/runtime/vm/compiler/intrinsifier.cc b/runtime/vm/compiler/intrinsifier.cc
index 7277c21..d0bfc52 100644
--- a/runtime/vm/compiler/intrinsifier.cc
+++ b/runtime/vm/compiler/intrinsifier.cc
@@ -113,9 +113,9 @@
return false;
}
} else {
- // If the field is boxed, then the getter cannot return an unboxed value
- // either (if it could, we would know the field itself can be unboxed).
- RELEASE_ASSERT(!function.HasUnboxedReturnValue());
+ // If the field is boxed, then we can either return the box directly or
+ // unbox it and return unboxed representation.
+ return true;
}
} else {
ASSERT(is_setter);
diff --git a/runtime/vm/compiler/write_barrier_elimination.cc b/runtime/vm/compiler/write_barrier_elimination.cc
index 10b18c5..efc79e8 100644
--- a/runtime/vm/compiler/write_barrier_elimination.cc
+++ b/runtime/vm/compiler/write_barrier_elimination.cc
@@ -192,6 +192,8 @@
void WriteBarrierElimination::IndexDefinitions(Zone* zone) {
BitmapBuilder array_allocations;
+ GrowableArray<Definition*> create_array_worklist;
+
for (intptr_t i = 0; i < block_order_->length(); ++i) {
BlockEntryInstr* const block = block_order_->At(i);
if (auto join_block = block->AsJoinEntry()) {
@@ -209,8 +211,12 @@
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
if (Definition* current = it.Current()->AsDefinition()) {
if (IsUsable(current)) {
- array_allocations.Set(definition_count_, current->IsCreateArray());
+ const bool is_create_array = current->IsCreateArray();
+ array_allocations.Set(definition_count_, is_create_array);
definition_indices_.Insert({current, definition_count_++});
+ if (is_create_array) {
+ create_array_worklist.Add(current);
+ }
#if defined(DEBUG)
if (tracing_) {
THR_Print("Definition (%" Pd ") has index %" Pd ".\n",
@@ -222,6 +228,20 @@
}
}
+ while (!create_array_worklist.is_empty()) {
+ auto instr = create_array_worklist.RemoveLast();
+ for (Value::Iterator it(instr->input_use_list()); !it.Done();
+ it.Advance()) {
+ if (auto phi_use = it.Current()->instruction()->AsPhi()) {
+ const intptr_t index = Index(phi_use);
+ if (!array_allocations.Get(index)) {
+ array_allocations.Set(index, /*can_be_create_array=*/true);
+ create_array_worklist.Add(phi_use);
+ }
+ }
+ }
+ }
+
vector_ = new (zone) BitVector(zone, definition_count_);
vector_->SetAll();
array_allocations_mask_ = new (zone) BitVector(zone, definition_count_);
diff --git a/runtime/vm/compiler/write_barrier_elimination_test.cc b/runtime/vm/compiler/write_barrier_elimination_test.cc
index 88d4e7c..b86e827 100644
--- a/runtime/vm/compiler/write_barrier_elimination_test.cc
+++ b/runtime/vm/compiler/write_barrier_elimination_test.cc
@@ -12,7 +12,8 @@
DEBUG_ONLY(DECLARE_FLAG(bool, trace_write_barrier_elimination);)
ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_JoinSuccessors) {
- DEBUG_ONLY(FLAG_trace_write_barrier_elimination = true);
+ DEBUG_ONLY(
+ SetFlagScope<bool> sfs(&FLAG_trace_write_barrier_elimination, true));
const char* nullable_tag = TestCase::NullableTag();
const char* null_assert_tag = TestCase::NullAssertTag();
@@ -82,7 +83,8 @@
}
ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_AtLeastOnce) {
- DEBUG_ONLY(FLAG_trace_write_barrier_elimination = true);
+ DEBUG_ONLY(
+ SetFlagScope<bool> sfs(&FLAG_trace_write_barrier_elimination, true));
// Ensure that we process every block at least once during the analysis
// phase so that the out-sets will be initialized. If we don't process
// each block at least once, the store "c.next = n" will be marked
@@ -137,7 +139,8 @@
}
ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_Arrays) {
- DEBUG_ONLY(FLAG_trace_write_barrier_elimination = true);
+ DEBUG_ONLY(
+ SetFlagScope<bool> sfs(&FLAG_trace_write_barrier_elimination, true));
const char* nullable_tag = TestCase::NullableTag();
// Test that array allocations are not considered usable after a
@@ -204,4 +207,49 @@
EXPECT(store_into_array->ShouldEmitStoreBarrier() == true);
}
+ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_Regress43786) {
+ DEBUG_ONLY(
+ SetFlagScope<bool> sfs(&FLAG_trace_write_barrier_elimination, true));
+ const char* kScript = R"(
+ foo() {
+ final root = List<dynamic>.filled(128, null);
+ List<dynamic> last = root;
+ for (int i = 0; i < 10 * 1024; ++i) {
+ final nc = List(128);
+ last[0] = nc;
+ last = nc;
+ }
+ }
+
+ main() { foo(); }
+ )";
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+
+ Invoke(root_library, "main");
+
+ const auto& function = Function::Handle(GetFunction(root_library, "foo"));
+ TestPipeline pipeline(function, CompilerPass::kJIT);
+ FlowGraph* flow_graph = pipeline.RunPasses({});
+
+ auto entry = flow_graph->graph_entry()->normal_entry();
+ EXPECT(entry != nullptr);
+
+ StoreIndexedInstr* store_into_phi = nullptr;
+
+ ILMatcher cursor(flow_graph, entry);
+ RELEASE_ASSERT(cursor.TryMatch(
+ {
+ kMatchAndMoveCreateArray,
+ kMatchAndMoveGoto,
+ kMatchAndMoveBranchTrue,
+ kMatchAndMoveCreateArray,
+ {kMatchAndMoveStoreIndexed, &store_into_phi},
+ },
+ kMoveGlob));
+
+ EXPECT(store_into_phi->array()->definition()->IsPhi());
+ EXPECT(store_into_phi->ShouldEmitStoreBarrier());
+}
+
} // namespace dart
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
index 724b90a..8261822 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
@@ -435,6 +435,13 @@
return;
}
+ if (JS('!', '# === #.Object', jsType, global_)) {
+ var extName = JS<String>('!', '#.name', dartExtType);
+ _warn(
+ "Attempting to install properties from non-Object type '$extName' onto the native JS Object.");
+ return;
+ }
+
_installProperties(
jsProto, dartExtType, JS('', '#[#]', jsProto, _extensionType));
diff --git a/tools/VERSION b/tools/VERSION
index eb7dda6..baf9ffe 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -26,6 +26,6 @@
CHANNEL stable
MAJOR 2
MINOR 10
-PATCH 2
+PATCH 3
PRERELEASE 0
PRERELEASE_PATCH 0