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