[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