Skip to content

Commit 37d0ab4

Browse files
awesomeklingnico
authored andcommitted
LibJS: Allocate RegExp.{lastMatch,leftContext,rightContext} lazily
These properties are always substrings of the RegExp input string, and so we can store them as views and lazily construct strings if they're actually accessed (which most of the time they aren't). This avoids a bunch of unnecessary memory copying, saving roughly 2.1 seconds per iteration of Speedometer. (cherry picked from commit dbf52a1)
1 parent 5ff36ce commit 37d0ab4

File tree

2 files changed

+47
-12
lines changed

2 files changed

+47
-12
lines changed

Diff for: Userland/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@ void RegExpLegacyStaticProperties::invalidate()
1515
{
1616
m_input = {};
1717
m_last_match = {};
18+
m_last_match_string = {};
1819
m_last_paren = {};
1920
m_left_context = {};
21+
m_left_context_string = {};
2022
m_right_context = {};
23+
m_right_context_string = {};
2124
m_$1 = {};
2225
m_$2 = {};
2326
m_$3 = {};
@@ -92,7 +95,7 @@ void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf1
9295

9396
// 8. Set the value of C’s [[RegExpLastMatch]] internal slot to a String whose length is endIndex - startIndex and containing the code units from S with indices startIndex through endIndex - 1, in ascending order.
9497
auto last_match = string.view().substring_view(start_index, end_index - start_index);
95-
legacy_static_properties.set_last_match(Utf16String::create(last_match));
98+
legacy_static_properties.set_last_match(last_match);
9699

97100
// 9. If n > 0, set the value of C’s [[RegExpLastParen]] internal slot to the last element of capturedValues.
98101
if (group_count > 0) {
@@ -106,11 +109,11 @@ void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf1
106109

107110
// 11. Set the value of C’s [[RegExpLeftContext]] internal slot to a String whose length is startIndex and containing the code units from S with indices 0 through startIndex - 1, in ascending order.
108111
auto left_context = string.view().substring_view(0, start_index);
109-
legacy_static_properties.set_left_context(Utf16String::create(left_context));
112+
legacy_static_properties.set_left_context(left_context);
110113

111114
// 12. Set the value of C’s [[RegExpRightContext]] internal slot to a String whose length is len - endIndex and containing the code units from S with indices endIndex through len - 1, in ascending order.
112115
auto right_context = string.view().substring_view(end_index, len - end_index);
113-
legacy_static_properties.set_right_context(Utf16String::create(right_context));
116+
legacy_static_properties.set_right_context(right_context);
114117

115118
// 13. For each integer i such that 1 ≤ i ≤ 9
116119
for (size_t i = 1; i <= 9; i++) {

Diff for: Userland/Libraries/LibJS/Runtime/RegExpLegacyStaticProperties.h

+41-9
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,25 @@ namespace JS {
2323
class RegExpLegacyStaticProperties {
2424
public:
2525
Optional<Utf16String> const& input() const { return m_input; }
26-
Optional<Utf16String> const& last_match() const { return m_last_match; }
26+
Optional<Utf16String> const& last_match() const
27+
{
28+
if (!m_last_match_string.has_value())
29+
m_last_match_string = Utf16String::create(m_last_match);
30+
return m_last_match_string;
31+
}
2732
Optional<Utf16String> const& last_paren() const { return m_last_paren; }
28-
Optional<Utf16String> const& left_context() const { return m_left_context; }
29-
Optional<Utf16String> const& right_context() const { return m_right_context; }
33+
Optional<Utf16String> const& left_context() const
34+
{
35+
if (!m_left_context_string.has_value())
36+
m_left_context_string = Utf16String::create(m_left_context);
37+
return m_left_context_string;
38+
}
39+
Optional<Utf16String> const& right_context() const
40+
{
41+
if (!m_right_context_string.has_value())
42+
m_right_context_string = Utf16String::create(m_right_context);
43+
return m_right_context_string;
44+
}
3045
Optional<Utf16String> const& $1() const { return m_$1; }
3146
Optional<Utf16String> const& $2() const { return m_$2; }
3247
Optional<Utf16String> const& $3() const { return m_$3; }
@@ -38,10 +53,22 @@ class RegExpLegacyStaticProperties {
3853
Optional<Utf16String> const& $9() const { return m_$9; }
3954

4055
void set_input(Utf16String input) { m_input = move(input); }
41-
void set_last_match(Utf16String last_match) { m_last_match = move(last_match); }
56+
void set_last_match(Utf16View last_match)
57+
{
58+
m_last_match = last_match;
59+
m_last_match_string = {};
60+
}
4261
void set_last_paren(Utf16String last_paren) { m_last_paren = move(last_paren); }
43-
void set_left_context(Utf16String left_context) { m_left_context = move(left_context); }
44-
void set_right_context(Utf16String right_context) { m_right_context = move(right_context); }
62+
void set_left_context(Utf16View left_context)
63+
{
64+
m_left_context = left_context;
65+
m_left_context_string = {};
66+
}
67+
void set_right_context(Utf16View right_context)
68+
{
69+
m_right_context = right_context;
70+
m_right_context_string = {};
71+
}
4572
void set_$1(Utf16String value) { m_$1 = move(value); }
4673
void set_$2(Utf16String value) { m_$2 = move(value); }
4774
void set_$3(Utf16String value) { m_$3 = move(value); }
@@ -55,10 +82,7 @@ class RegExpLegacyStaticProperties {
5582

5683
private:
5784
Optional<Utf16String> m_input;
58-
Optional<Utf16String> m_last_match;
5985
Optional<Utf16String> m_last_paren;
60-
Optional<Utf16String> m_left_context;
61-
Optional<Utf16String> m_right_context;
6286
Optional<Utf16String> m_$1;
6387
Optional<Utf16String> m_$2;
6488
Optional<Utf16String> m_$3;
@@ -68,6 +92,14 @@ class RegExpLegacyStaticProperties {
6892
Optional<Utf16String> m_$7;
6993
Optional<Utf16String> m_$8;
7094
Optional<Utf16String> m_$9;
95+
96+
// NOTE: These are views into m_input and we only turn them into full strings if/when needed.
97+
Utf16View m_last_match;
98+
Utf16View m_left_context;
99+
Utf16View m_right_context;
100+
mutable Optional<Utf16String> m_last_match_string;
101+
mutable Optional<Utf16String> m_left_context_string;
102+
mutable Optional<Utf16String> m_right_context_string;
71103
};
72104

73105
ThrowCompletionOr<void> set_legacy_regexp_static_property(VM& vm, RegExpConstructor& constructor, Value this_value, void (RegExpLegacyStaticProperties::*property_setter)(Utf16String), Value value);

0 commit comments

Comments
 (0)