Version 2.3.0-dev.0.5

* Cherry-pick 347b72c260949fa96ec5a45f3d6b1e2388ea245a to dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6338a5f..1c596d0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.3.0-dev.0.5
+
+* Cherry-pick 347b72c260949fa96ec5a45f3d6b1e2388ea245a to dev
+
 ## 2.3.0-dev.0.4
 
 * Cherry-pick d03323783a5a5a571916457fcf084d103fce86b3 to dev
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index 8227e48..2d95479 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -11,6 +11,7 @@
 #include "vm/handles_impl.h"
 #include "vm/heap/heap.h"
 #include "vm/os.h"
+#include "vm/virtual_memory.h"
 
 namespace dart {
 
@@ -21,25 +22,28 @@
  public:
   Segment* next() const { return next_; }
   intptr_t size() const { return size_; }
+  VirtualMemory* memory() const { return memory_; }
 
   uword start() { return address(sizeof(Segment)); }
   uword end() { return address(size_); }
 
   // Allocate or delete individual segments.
   static Segment* New(intptr_t size, Segment* next);
+  static Segment* NewLarge(intptr_t size, Segment* next);
   static void DeleteSegmentList(Segment* segment);
+  static void DeleteLargeSegmentList(Segment* segment);
   static void IncrementMemoryCapacity(uintptr_t size);
   static void DecrementMemoryCapacity(uintptr_t size);
 
  private:
   Segment* next_;
   intptr_t size_;
+  VirtualMemory* memory_;
+  void* alignment_;
 
   // Computes the address of the nth byte in this segment.
   uword address(int n) { return reinterpret_cast<uword>(this) + n; }
 
-  static void Delete(Segment* segment) { free(segment); }
-
   DISALLOW_IMPLICIT_CONSTRUCTORS(Segment);
 };
 
@@ -49,13 +53,36 @@
   if (result == NULL) {
     OUT_OF_MEMORY();
   }
-  ASSERT(Utils::IsAligned(result->start(), Zone::kAlignment));
 #ifdef DEBUG
   // Zap the entire allocated segment (including the header).
   memset(result, kZapUninitializedByte, size);
 #endif
   result->next_ = next;
   result->size_ = size;
+  result->memory_ = nullptr;
+  result->alignment_ = nullptr;  // Avoid unused variable warnings.
+  IncrementMemoryCapacity(size);
+  return result;
+}
+
+Zone::Segment* Zone::Segment::NewLarge(intptr_t size, Zone::Segment* next) {
+  size = Utils::RoundUp(size, VirtualMemory::PageSize());
+  VirtualMemory* memory = VirtualMemory::Allocate(size, false, "dart-zone");
+  if (memory == NULL) {
+    OUT_OF_MEMORY();
+  }
+  Segment* result = reinterpret_cast<Segment*>(memory->start());
+#ifdef DEBUG
+  // Zap the entire allocated segment (including the header).
+  memset(result, kZapUninitializedByte, size);
+#endif
+  result->next_ = next;
+  result->size_ = size;
+  result->memory_ = memory;
+  result->alignment_ = nullptr;  // Avoid unused variable warnings.
+
+  LSAN_REGISTER_ROOT_REGION(result, sizeof(*result));
+
   IncrementMemoryCapacity(size);
   return result;
 }
@@ -69,7 +96,23 @@
     // Zap the entire current segment (including the header).
     memset(current, kZapDeletedByte, current->size());
 #endif
-    Segment::Delete(current);
+    free(current);
+    current = next;
+  }
+}
+
+void Zone::Segment::DeleteLargeSegmentList(Segment* head) {
+  Segment* current = head;
+  while (current != NULL) {
+    DecrementMemoryCapacity(current->size());
+    Segment* next = current->next();
+    VirtualMemory* memory = current->memory();
+#ifdef DEBUG
+    // Zap the entire current segment (including the header).
+    memset(current, kZapDeletedByte, current->size());
+#endif
+    LSAN_UNREGISTER_ROOT_REGION(current, sizeof(*current));
+    delete memory;
     current = next;
   }
 }
@@ -129,7 +172,7 @@
     Segment::DeleteSegmentList(head_);
   }
   if (large_segments_ != NULL) {
-    Segment::DeleteSegmentList(large_segments_);
+    Segment::DeleteLargeSegmentList(large_segments_);
   }
 // Reset zone state.
 #ifdef DEBUG
@@ -214,9 +257,9 @@
   ASSERT(free_size < size);
 
   // Create a new large segment and chain it up.
-  ASSERT(Utils::IsAligned(sizeof(Segment), kAlignment));
-  size += sizeof(Segment);  // Account for book keeping fields in size.
-  large_segments_ = Segment::New(size, large_segments_);
+  // Account for book keeping fields in size.
+  size += Utils::RoundUp(sizeof(Segment), kAlignment);
+  large_segments_ = Segment::NewLarge(size, large_segments_);
 
   uword result = Utils::RoundUp(large_segments_->start(), kAlignment);
   return result;
diff --git a/runtime/vm/zone_test.cc b/runtime/vm/zone_test.cc
index 5f8f783..a12b5ff 100644
--- a/runtime/vm/zone_test.cc
+++ b/runtime/vm/zone_test.cc
@@ -176,4 +176,66 @@
   EXPECT_EQ(0UL, ApiNativeScope::current_memory_usage());
 }
 
+#if !defined(PRODUCT)
+// Allow for pooling in the malloc implementation.
+static const int64_t kRssSlack = 20 * MB;
+#endif  // !defined(PRODUCT)
+
+// clang-format off
+static const size_t kSizes[] = {
+  64 * KB,
+  64 * KB + 2 * kWordSize,
+  64 * KB - 2 * kWordSize,
+  128 * KB,
+  128 * KB + 2 * kWordSize,
+  128 * KB - 2 * kWordSize,
+  256 * KB,
+  256 * KB + 2 * kWordSize,
+  256 * KB - 2 * kWordSize,
+  512 * KB,
+  512 * KB + 2 * kWordSize,
+  512 * KB - 2 * kWordSize,
+};
+// clang-format on
+
+TEST_CASE(StressMallocDirectly) {
+#if !defined(PRODUCT)
+  int64_t start_rss = Service::CurrentRSS();
+#endif  // !defined(PRODUCT)
+
+  void* allocations[ARRAY_SIZE(kSizes)];
+  for (size_t i = 0; i < ((3u * GB) / (512u * KB)); i++) {
+    for (size_t j = 0; j < ARRAY_SIZE(kSizes); j++) {
+      allocations[j] = malloc(kSizes[j]);
+    }
+    for (size_t j = 0; j < ARRAY_SIZE(kSizes); j++) {
+      free(allocations[j]);
+    }
+  }
+
+#if !defined(PRODUCT)
+  int64_t stop_rss = Service::CurrentRSS();
+  EXPECT_LT(stop_rss, start_rss + kRssSlack);
+#endif  // !defined(PRODUCT)
+}
+
+TEST_CASE(StressMallocThroughZones) {
+#if !defined(PRODUCT)
+  int64_t start_rss = Service::CurrentRSS();
+#endif  // !defined(PRODUCT)
+
+  for (size_t i = 0; i < ((3u * GB) / (512u * KB)); i++) {
+    StackZone stack_zone(Thread::Current());
+    Zone* zone = stack_zone.GetZone();
+    for (size_t j = 0; j < ARRAY_SIZE(kSizes); j++) {
+      zone->Alloc<uint8_t>(kSizes[j]);
+    }
+  }
+
+#if !defined(PRODUCT)
+  int64_t stop_rss = Service::CurrentRSS();
+  EXPECT_LT(stop_rss, start_rss + kRssSlack);
+#endif  // !defined(PRODUCT)
+}
+
 }  // namespace dart
diff --git a/tests/corelib_2/regexp/jemalloc_leak_backtracking_stack_test.dart b/tests/corelib_2/regexp/jemalloc_leak_backtracking_stack_test.dart
new file mode 100644
index 0000000..18c4621
--- /dev/null
+++ b/tests/corelib_2/regexp/jemalloc_leak_backtracking_stack_test.dart
@@ -0,0 +1,24 @@
+// 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.
+
+// Regression test for https://github.com/flutter/flutter/issues/29007
+
+String escape(String string) {
+  var regex = new RegExp("(\\?|\\\$|\\*|\\(|\\)|\\[)|\\+|\\.|\\\\");
+  return string.replaceAllMapped(
+      regex, (Match m) => "\\" + string.substring(m.start, m.end));
+}
+
+main() {
+  var text = """
+Yet but three? Come one more.
+Two of both kinds make up four.
+""";
+  var accumulate = 0;
+  for (var i = 0; i < 65536; i++) {
+    accumulate += escape(text).length;
+  }
+
+  print(accumulate);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 8802673..3cbb7b3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -34,6 +34,6 @@
 MINOR 3
 PATCH 0
 PRERELEASE 0
-PRERELEASE_PATCH 4
+PRERELEASE_PATCH 5
 ABI_VERSION 4
 OLDEST_SUPPORTED_ABI_VERSION 1