Version 2.4.1
* Cherry-pick 8b1efb2b7684e65bf77b28a51bfffe60404e5558 to stable
* Cherry-pick 5f627b7a54e32b5157cbcbfa760209cab5851252 to stable
* Cherry-pick dce0eeb4137c57b4840a05ac48af6236201ddad1 to stable
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b9554f5..ff294a5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,20 @@
-## 2.4.0 - 2019-06-24
+## 2.4.1 - 2019-08-07
+
+This is a patch version release which fixes a performance regression in JIT as
+well as a potential crash of our AOT compiler.
+
+### Dart VM
+
+* Working with `Int32List` could cause repeated deoptimizations leading to a big
+ performance regression in JIT mode. The Issue [37551][] was fixed.
+
+* Using a static getter with name `length` could cause a crash in our AOT
+ compiler. The Issue [35121][] was fixed.
+
+[37551]: https://github.com/dart-lang/sdk/issues/37551
+[35121]: https://github.com/dart-lang/sdk/issues/35121
+
+## 2.4.0 - 2019-06-27
### Core libraries
diff --git a/runtime/tests/vm/dart/regress_flutter35121_test.dart b/runtime/tests/vm/dart/regress_flutter35121_test.dart
new file mode 100644
index 0000000..a4d21b6
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_flutter35121_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, 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.
+
+// This is a regression test for
+// https://github.com/flutter/flutter/issues/35121
+
+class A {
+ static List<int> values = const [1, 2, 3];
+ static int get length => values.length;
+}
+
+main() {
+ print(A.length);
+}
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 5235005..17ca8c1 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -2632,12 +2632,13 @@
const bool value_needs_unboxing =
array_cid == kTypedDataInt8ArrayCid ||
array_cid == kTypedDataInt16ArrayCid ||
+ array_cid == kTypedDataInt32ArrayCid ||
array_cid == kTypedDataUint8ArrayCid ||
array_cid == kTypedDataUint8ClampedArrayCid ||
array_cid == kTypedDataUint16ArrayCid ||
+ array_cid == kTypedDataUint32ArrayCid ||
array_cid == kExternalTypedDataUint8ArrayCid ||
- array_cid == kExternalTypedDataUint8ClampedArrayCid ||
- array_cid == kTypedDataUint32ArrayCid;
+ array_cid == kExternalTypedDataUint8ClampedArrayCid;
if (value_check != NULL) {
// No store barrier needed because checked value is a smi, an unboxed mint,
@@ -2657,7 +2658,7 @@
} else if (value_needs_unboxing) {
Representation representation = kNoRepresentation;
switch (array_cid) {
- case kUnboxedInt32:
+ case kTypedDataInt32ArrayCid:
representation = kUnboxedInt32;
break;
case kTypedDataUint32ArrayCid:
diff --git a/runtime/vm/compiler/backend/inliner_test.cc b/runtime/vm/compiler/backend/inliner_test.cc
index 75609a4..f7dab8e 100644
--- a/runtime/vm/compiler/backend/inliner_test.cc
+++ b/runtime/vm/compiler/backend/inliner_test.cc
@@ -134,4 +134,64 @@
EXPECT(current->AsRedefinition()->Type()->ToCid() == kDynamicCid);
}
+ISOLATE_UNIT_TEST_CASE(Inliner_TypedData_Regress7551) {
+ const char* kScript = R"(
+ import 'dart:typed_data';
+
+ setValue(Int32List list, int value) {
+ list[0] = value;
+ }
+
+ main() {
+ final list = Int32List(10);
+ setValue(list, 0x1122334455);
+ }
+ )";
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+ const auto& function =
+ Function::Handle(GetFunction(root_library, "setValue"));
+
+ Invoke(root_library, "main");
+
+ TestPipeline pipeline(function, CompilerPass::kJIT);
+ FlowGraph* flow_graph = pipeline.RunPasses({
+ CompilerPass::kComputeSSA,
+ CompilerPass::kApplyICData,
+ CompilerPass::kTryOptimizePatterns,
+ CompilerPass::kSetOuterInliningId,
+ CompilerPass::kTypePropagation,
+ CompilerPass::kApplyClassIds,
+ CompilerPass::kInlining,
+ });
+
+ auto entry = flow_graph->graph_entry()->normal_entry();
+
+ EXPECT(entry->initial_definitions()->length() == 2);
+ EXPECT(entry->initial_definitions()->At(0)->IsParameter());
+ EXPECT(entry->initial_definitions()->At(1)->IsParameter());
+ ParameterInstr* list_param =
+ entry->initial_definitions()->At(0)->AsParameter();
+ ParameterInstr* value_param =
+ entry->initial_definitions()->At(1)->AsParameter();
+
+ ILMatcher cursor(flow_graph, entry);
+
+ CheckArrayBoundInstr* bounds_check_instr = nullptr;
+ UnboxInt32Instr* unbox_instr = nullptr;
+ StoreIndexedInstr* store_instr = nullptr;
+
+ RELEASE_ASSERT(cursor.TryMatch({
+ {kMoveGlob},
+ {kMatchAndMoveCheckArrayBound, &bounds_check_instr},
+ {kMatchAndMoveUnboxInt32, &unbox_instr},
+ {kMatchAndMoveStoreIndexed, &store_instr},
+ }));
+
+ RELEASE_ASSERT(unbox_instr->InputAt(0)->definition() == value_param);
+ RELEASE_ASSERT(store_instr->InputAt(0)->definition() == list_param);
+ RELEASE_ASSERT(store_instr->InputAt(2)->definition() == unbox_instr);
+ RELEASE_ASSERT(unbox_instr->is_truncating());
+}
+
} // namespace dart
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index de3c1b5..1c5c06c 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -1691,7 +1691,11 @@
}
void TypedDataSpecializer::VisitStaticCall(StaticCallInstr* call) {
- TryInlineCall(call);
+ const Function& function = call->function();
+ if (!function.is_static()) {
+ ASSERT(call->ArgumentCount() > 0);
+ TryInlineCall(call);
+ }
}
void TypedDataSpecializer::TryInlineCall(TemplateDartCall<0>* call) {
diff --git a/tools/VERSION b/tools/VERSION
index 5912f77..7eb71d3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -32,7 +32,7 @@
CHANNEL stable
MAJOR 2
MINOR 4
-PATCH 0
+PATCH 1
PRERELEASE 0
PRERELEASE_PATCH 0
ABI_VERSION 5