Skip to content

Commit 09c9301

Browse files
rmacnak-googleCommit Queue
authored and
Commit Queue
committed
[vm] Weakly cache all RegExp per isolate group, instead of strongly caching 256 RegExp per isolate.
TEST=ci Bug: #51228 Change-Id: Ie2869585ae847ea154460122d7ec5af81ef7697c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/280521 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Alexander Aprelev <aam@google.com>
1 parent 85ee8db commit 09c9301

File tree

9 files changed

+472
-454
lines changed

9 files changed

+472
-454
lines changed

runtime/lib/regexp.cc

+38-15
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44

55
#include "platform/assert.h"
66
#include "vm/bootstrap_natives.h"
7+
#include "vm/canonical_tables.h"
78
#include "vm/exceptions.h"
89
#include "vm/native_entry.h"
910
#include "vm/object.h"
11+
#include "vm/object_store.h"
1012
#include "vm/regexp_assembler_bytecode.h"
1113
#include "vm/regexp_parser.h"
14+
#include "vm/reusable_handles.h"
1215
#include "vm/thread.h"
1316

1417
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -21,34 +24,54 @@ DEFINE_NATIVE_ENTRY(RegExp_factory, 0, 6) {
2124
ASSERT(
2225
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
2326
GET_NON_NULL_NATIVE_ARGUMENT(String, pattern, arguments->NativeArgAt(1));
24-
GET_NON_NULL_NATIVE_ARGUMENT(Instance, handle_multi_line,
25-
arguments->NativeArgAt(2));
26-
GET_NON_NULL_NATIVE_ARGUMENT(Instance, handle_case_sensitive,
27-
arguments->NativeArgAt(3));
28-
GET_NON_NULL_NATIVE_ARGUMENT(Instance, handle_unicode,
29-
arguments->NativeArgAt(4));
30-
GET_NON_NULL_NATIVE_ARGUMENT(Instance, handle_dot_all,
31-
arguments->NativeArgAt(5));
32-
bool ignore_case = handle_case_sensitive.ptr() != Bool::True().ptr();
33-
bool multi_line = handle_multi_line.ptr() == Bool::True().ptr();
34-
bool unicode = handle_unicode.ptr() == Bool::True().ptr();
35-
bool dot_all = handle_dot_all.ptr() == Bool::True().ptr();
3627

37-
RegExpFlags flags;
28+
bool multi_line = arguments->NativeArgAt(2) == Bool::True().ptr();
29+
bool ignore_case = arguments->NativeArgAt(3) != Bool::True().ptr();
30+
bool unicode = arguments->NativeArgAt(4) == Bool::True().ptr();
31+
bool dot_all = arguments->NativeArgAt(5) == Bool::True().ptr();
3832

33+
RegExpFlags flags;
34+
flags.SetGlobal(); // All dart regexps are global.
3935
if (ignore_case) flags.SetIgnoreCase();
4036
if (multi_line) flags.SetMultiLine();
4137
if (unicode) flags.SetUnicode();
4238
if (dot_all) flags.SetDotAll();
4339

40+
RegExpKey lookup_key(pattern, flags);
41+
RegExp& regexp = RegExp::Handle(thread->zone());
42+
{
43+
REUSABLE_OBJECT_HANDLESCOPE(thread);
44+
REUSABLE_SMI_HANDLESCOPE(thread);
45+
REUSABLE_WEAK_ARRAY_HANDLESCOPE(thread);
46+
Object& key = thread->ObjectHandle();
47+
Smi& value = thread->SmiHandle();
48+
WeakArray& data = thread->WeakArrayHandle();
49+
data = thread->isolate_group()->object_store()->regexp_table();
50+
CanonicalRegExpSet table(&key, &value, &data);
51+
regexp ^= table.GetOrNull(lookup_key);
52+
table.Release();
53+
if (!regexp.IsNull()) {
54+
return regexp.ptr();
55+
}
56+
}
57+
4458
// Parse the pattern once in order to throw any format exceptions within
4559
// the factory constructor. It is parsed again upon compilation.
4660
RegExpCompileData compileData;
4761
// Throws an exception on parsing failure.
4862
RegExpParser::ParseRegExp(pattern, flags, &compileData);
4963

50-
// Create a RegExp object containing only the initial parameters.
51-
return RegExpEngine::CreateRegExp(thread, pattern, flags);
64+
{
65+
SafepointMutexLocker ml(thread->isolate_group()->symbols_mutex());
66+
CanonicalRegExpSet table(
67+
thread->zone(),
68+
thread->isolate_group()->object_store()->regexp_table());
69+
regexp ^= table.InsertNewOrGet(lookup_key);
70+
thread->isolate_group()->object_store()->set_regexp_table(table.Release());
71+
}
72+
73+
ASSERT(regexp.flags() == flags);
74+
return regexp.ptr();
5275
}
5376

5477
DEFINE_NATIVE_ENTRY(RegExp_getPattern, 0, 1) {

runtime/vm/canonical_tables.cc

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "vm/canonical_tables.h"
66

7+
#include "vm/regexp.h"
8+
79
namespace dart {
810

911
bool MetadataMapTraits::IsMatch(const Object& a, const Object& b) {
@@ -111,4 +113,9 @@ ObjectPtr CanonicalInstanceTraits::NewKey(const CanonicalInstanceKey& obj) {
111113
return obj.key_.ptr();
112114
}
113115

116+
ObjectPtr CanonicalRegExpTraits::NewKey(const RegExpKey& key) {
117+
return RegExpEngine::CreateRegExp(Thread::Current(), key.pattern_,
118+
key.flags_);
119+
}
120+
114121
} // namespace dart

runtime/vm/canonical_tables.h

+41
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,47 @@ struct CanonicalFfiCallbackFunctionTraits {
430430
using FfiCallbackFunctionSet =
431431
UnorderedHashSet<CanonicalFfiCallbackFunctionTraits>;
432432

433+
class RegExpKey {
434+
public:
435+
RegExpKey(const String& pattern, RegExpFlags flags)
436+
: pattern_(pattern), flags_(flags) {}
437+
438+
bool Equals(const RegExp& other) const {
439+
return pattern_.Equals(String::Handle(other.pattern())) &&
440+
(flags_ == other.flags());
441+
}
442+
uword Hash() const {
443+
// Must agree with RegExp::CanonicalizeHash.
444+
return CombineHashes(pattern_.Hash(), flags_.value());
445+
}
446+
447+
const String& pattern_;
448+
RegExpFlags flags_;
449+
450+
private:
451+
DISALLOW_ALLOCATION();
452+
};
453+
454+
class CanonicalRegExpTraits {
455+
public:
456+
static const char* Name() { return "CanonicalRegExpTraits"; }
457+
static bool ReportStats() { return false; }
458+
static bool IsMatch(const Object& a, const Object& b) {
459+
return RegExp::Cast(a).CanonicalizeEquals(RegExp::Cast(b));
460+
}
461+
static bool IsMatch(const RegExpKey& a, const Object& b) {
462+
return a.Equals(RegExp::Cast(b));
463+
}
464+
static uword Hash(const Object& key) {
465+
return RegExp::Cast(key).CanonicalizeHash();
466+
}
467+
static uword Hash(const RegExpKey& key) { return key.Hash(); }
468+
static ObjectPtr NewKey(const RegExpKey& key);
469+
};
470+
471+
typedef UnorderedHashSet<CanonicalRegExpTraits, WeakAcqRelStorageTraits>
472+
CanonicalRegExpSet;
473+
433474
} // namespace dart
434475

435476
#endif // RUNTIME_VM_CANONICAL_TABLES_H_

0 commit comments

Comments
 (0)