[vm, irregexp] Cache the backtracking stack on the isolate to avoid memory leaks in jemalloc.

Bug: https://github.com/flutter/flutter/issues/29007
Change-Id: Ic08e6cdad087cb063350b0738a65f426e67864d0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100500
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 92e2c88..73f97414 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -949,7 +949,8 @@
       catch_entry_moves_cache_(),
       embedder_entry_points_(NULL),
       obfuscation_map_(NULL),
-      reverse_pc_lookup_cache_(nullptr) {
+      reverse_pc_lookup_cache_(nullptr),
+      irregexp_backtrack_stack_(nullptr) {
   FlagsCopyFrom(api_flags);
   SetErrorsFatal(true);
   set_compilation_allowed(true);
@@ -981,6 +982,9 @@
   // RELEASE_ASSERT(reload_context_ == NULL);
 #endif  // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
 
+  delete[] irregexp_backtrack_stack_;
+  irregexp_backtrack_stack_ = nullptr;
+
   delete reverse_pc_lookup_cache_;
   reverse_pc_lookup_cache_ = nullptr;
 
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index af038ff..2782cd6 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -734,6 +734,18 @@
     reverse_pc_lookup_cache_ = table;
   }
 
+  // This doesn't belong here, but to avoid triggering bugs in jemalloc we
+  // allocate the irregexpinterpreter's stack once per isolate instead of once
+  // per regexp execution.
+  // See https://github.com/flutter/flutter/issues/29007
+  static constexpr intptr_t kIrregexpBacktrackStackSize = 1 << 16;
+  intptr_t* irregexp_backtrack_stack() {
+    if (irregexp_backtrack_stack_ == nullptr) {
+      irregexp_backtrack_stack_ = new intptr_t[kIrregexpBacktrackStackSize];
+    }
+    return irregexp_backtrack_stack_;
+  }
+
   // Isolate-specific flag handling.
   static void FlagsInitialize(Dart_IsolateFlags* api_flags);
   void FlagsCopyTo(Dart_IsolateFlags* api_flags) const;
@@ -1046,6 +1058,8 @@
 
   ReversePcLookupCache* reverse_pc_lookup_cache_;
 
+  intptr_t* irregexp_backtrack_stack_;
+
   static Dart_IsolateCreateCallback create_callback_;
   static Dart_IsolateShutdownCallback shutdown_callback_;
   static Dart_IsolateCleanupCallback cleanup_callback_;
diff --git a/runtime/vm/regexp_assembler_bytecode.cc b/runtime/vm/regexp_assembler_bytecode.cc
index 8288e1b..7a55573 100644
--- a/runtime/vm/regexp_assembler_bytecode.cc
+++ b/runtime/vm/regexp_assembler_bytecode.cc
@@ -492,7 +492,7 @@
       TypedData::Handle(zone, regexp.bytecode(is_one_byte, sticky));
   ASSERT(!bytecode.IsNull());
   IrregexpInterpreter::IrregexpResult result =
-      IrregexpInterpreter::Match(bytecode, subject, raw_output, index, zone);
+      IrregexpInterpreter::Match(bytecode, subject, raw_output, index);
 
   if (result == IrregexpInterpreter::RE_SUCCESS) {
     // Copy capture results to the start of the registers array.
diff --git a/runtime/vm/regexp_interpreter.cc b/runtime/vm/regexp_interpreter.cc
index 94c44ec..e3443cd 100644
--- a/runtime/vm/regexp_interpreter.cc
+++ b/runtime/vm/regexp_interpreter.cc
@@ -127,8 +127,8 @@
 // matching terminates.
 class BacktrackStack {
  public:
-  explicit BacktrackStack(Zone* zone) {
-    data_ = zone->Alloc<intptr_t>(kBacktrackStackSize);
+  explicit BacktrackStack(Isolate* isolate) {
+    data_ = isolate->irregexp_backtrack_stack();
   }
 
   intptr_t* data() const { return data_; }
@@ -136,7 +136,8 @@
   intptr_t max_size() const { return kBacktrackStackSize; }
 
  private:
-  static const intptr_t kBacktrackStackSize = 1 << 16;
+  static constexpr intptr_t kBacktrackStackSize =
+      Isolate::kIrregexpBacktrackStackSize;
 
   intptr_t* data_;
 
@@ -148,13 +149,12 @@
                                                     const String& subject,
                                                     int32_t* registers,
                                                     intptr_t current,
-                                                    uint32_t current_char,
-                                                    Zone* zone) {
+                                                    uint32_t current_char) {
   const uint8_t* pc = code_base;
   // BacktrackStack ensures that the memory allocated for the backtracking stack
   // is returned to the system or cached if there is no stack being cached at
   // the moment.
-  BacktrackStack backtrack_stack(zone);
+  BacktrackStack backtrack_stack(Isolate::Current());
   intptr_t* backtrack_stack_base = backtrack_stack.data();
   intptr_t* backtrack_sp = backtrack_stack_base;
   intptr_t backtrack_stack_space = backtrack_stack.max_size();
@@ -619,8 +619,7 @@
     const TypedData& bytecode,
     const String& subject,
     int32_t* registers,
-    intptr_t start_position,
-    Zone* zone) {
+    intptr_t start_position) {
   NoSafepointScope no_safepoint;
   const uint8_t* code_base = reinterpret_cast<uint8_t*>(bytecode.DataAddr(0));
 
@@ -631,10 +630,10 @@
 
   if (subject.IsOneByteString() || subject.IsExternalOneByteString()) {
     return RawMatch<uint8_t>(code_base, subject, registers, start_position,
-                             previous_char, zone);
+                             previous_char);
   } else if (subject.IsTwoByteString() || subject.IsExternalTwoByteString()) {
     return RawMatch<uint16_t>(code_base, subject, registers, start_position,
-                              previous_char, zone);
+                              previous_char);
   } else {
     UNREACHABLE();
     return IrregexpInterpreter::RE_FAILURE;
diff --git a/runtime/vm/regexp_interpreter.h b/runtime/vm/regexp_interpreter.h
index 9e4e567..7a29fa0 100644
--- a/runtime/vm/regexp_interpreter.h
+++ b/runtime/vm/regexp_interpreter.h
@@ -20,8 +20,7 @@
   static IrregexpResult Match(const TypedData& bytecode,
                               const String& subject,
                               int32_t* captures,
-                              intptr_t start_position,
-                              Zone* zone);
+                              intptr_t start_position);
 };
 
 }  // namespace dart