Skip to content

Commit 6d62795

Browse files
committed
Add more specs for inline caching of dynamically created Regexp
1 parent 7fe36be commit 6d62795

File tree

3 files changed

+243
-7
lines changed

3 files changed

+243
-7
lines changed

spec/truffle/regexp/inline_caching_spec.rb

Lines changed: 242 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,31 @@
2020
Warning[:performance] = @performance_warnings
2121
end
2222

23-
it "Regexp.union with 1 argument" do
23+
it "Regexp.new" do
2424
# Check that separate call sites with fixed input does not warn
25+
-> {
26+
Regexp.new("a")
27+
Regexp.new("b")
28+
Regexp.new("c")
29+
Regexp.new("d")
30+
Regexp.new("e")
31+
Regexp.new("f")
32+
Regexp.new("g")
33+
Regexp.new("h")
34+
Regexp.new("i")
35+
Regexp.new("j")
36+
}.should_not complain
37+
38+
# Check that calling it with many different inputs has the warning
39+
-> {
40+
("a".."z").each do |pattern|
41+
Regexp.new(pattern)
42+
end
43+
}.should complain(/unbounded creation of regexps/)
44+
end
45+
46+
it "Regexp.union with 1 argument" do
47+
# Check that separate call sites with fixed input do not warn
2548
-> {
2649
Regexp.union("a")
2750
Regexp.union("b")
@@ -35,7 +58,7 @@
3558
Regexp.union("j")
3659
}.should_not complain
3760

38-
# Check that calling it with many different inputs has the warning.
61+
# Check that calling it with many different inputs has the warning
3962
-> {
4063
("a".."z").each do |pattern|
4164
Regexp.union(pattern)
@@ -44,7 +67,7 @@
4467
end
4568

4669
it "Regexp.union with multiple arguments" do
47-
# Check that separate call sites with fixed input does not warn
70+
# Check that separate call sites with fixed input do not warn
4871
-> {
4972
Regexp.union("h", "a")
5073
Regexp.union("h", "b")
@@ -58,16 +81,25 @@
5881
Regexp.union("h", "j")
5982
}.should_not complain
6083

61-
# Check that calling it with many different inputs has the warning.
84+
# Check that calling it with many different inputs has the warning
6285
-> {
6386
("a".."z").each do |pattern|
6487
Regexp.union("h", pattern)
6588
end
6689
}.should complain(/unbounded creation of regexps/)
6790
end
6891

92+
it "interpolated Regexp" do
93+
# Check that calling it with many different inputs has the warning
94+
-> {
95+
("a".."z").each do |pattern|
96+
/ #{pattern} /
97+
end
98+
}.should complain(/unstable interpolated regexps/)
99+
end
100+
69101
it "String#scan" do
70-
# Check that separate call sites with fixed input does not warn
102+
# Check that separate call sites with fixed input do not warn
71103
-> {
72104
"zzz".scan("a")
73105
"zzz".scan("b")
@@ -81,13 +113,217 @@
81113
"zzz".scan("j")
82114
}.should_not complain
83115

84-
# Check that calling it with many different inputs has the warning.
116+
# Check that calling it with many different inputs has the warning
85117
-> {
86118
# "a".."z" and not just "a".."j" because there can be some late heuristic megamorphic splitting by TRegex (ExecCompiledRegexNode)
87119
("a".."z").each do |pattern|
88120
"zzz".scan(pattern)
89121
end
90122
}.should complain(/unbounded creation of regexps/)
91123
end
124+
125+
it "String#sub" do
126+
pattern = Class.new do
127+
def initialize(string) = @string = string
128+
def to_str = @string
129+
end
130+
131+
# Check that separate call sites with fixed input do not warn
132+
-> {
133+
"zzz".sub(pattern.new("a"), "replacement")
134+
"zzz".sub(pattern.new("b"), "replacement")
135+
"zzz".sub(pattern.new("c"), "replacement")
136+
"zzz".sub(pattern.new("d"), "replacement")
137+
"zzz".sub(pattern.new("e"), "replacement")
138+
"zzz".sub(pattern.new("f"), "replacement")
139+
"zzz".sub(pattern.new("g"), "replacement")
140+
"zzz".sub(pattern.new("h"), "replacement")
141+
"zzz".sub(pattern.new("i"), "replacement")
142+
"zzz".sub(pattern.new("j"), "replacement")
143+
}.should_not complain
144+
145+
# Check that calling it with many different inputs has the warning
146+
-> {
147+
("a".."z").each do |s|
148+
"zzz".sub(pattern.new(s), "replacement")
149+
end
150+
}.should complain(/unbounded creation of regexps/)
151+
end
152+
153+
it "String#sub!" do
154+
pattern = Class.new do
155+
def initialize(string) = @string = string
156+
def to_str = @string
157+
end
158+
159+
# Check that separate call sites with fixed input do not warn
160+
-> {
161+
"zzz".sub!(pattern.new("a"), "replacement")
162+
"zzz".sub!(pattern.new("b"), "replacement")
163+
"zzz".sub!(pattern.new("c"), "replacement")
164+
"zzz".sub!(pattern.new("d"), "replacement")
165+
"zzz".sub!(pattern.new("e"), "replacement")
166+
"zzz".sub!(pattern.new("f"), "replacement")
167+
"zzz".sub!(pattern.new("g"), "replacement")
168+
"zzz".sub!(pattern.new("h"), "replacement")
169+
"zzz".sub!(pattern.new("i"), "replacement")
170+
"zzz".sub!(pattern.new("j"), "replacement")
171+
}.should_not complain
172+
173+
# Check that calling it with many different inputs has the warning
174+
-> {
175+
("a".."z").each do |s|
176+
"zzz".sub!(pattern.new(s), "replacement")
177+
end
178+
}.should complain(/unbounded creation of regexps/)
179+
end
180+
181+
it "String#gsub" do
182+
pattern = Class.new do
183+
def initialize(string) = @string = string
184+
def to_str = @string
185+
end
186+
187+
# Check that separate call sites with fixed input do not warn
188+
-> {
189+
"zzz".gsub(pattern.new("a"), "replacement")
190+
"zzz".gsub(pattern.new("b"), "replacement")
191+
"zzz".gsub(pattern.new("c"), "replacement")
192+
"zzz".gsub(pattern.new("d"), "replacement")
193+
"zzz".gsub(pattern.new("e"), "replacement")
194+
"zzz".gsub(pattern.new("f"), "replacement")
195+
"zzz".gsub(pattern.new("g"), "replacement")
196+
"zzz".gsub(pattern.new("h"), "replacement")
197+
"zzz".gsub(pattern.new("i"), "replacement")
198+
"zzz".gsub(pattern.new("j"), "replacement")
199+
}.should_not complain
200+
201+
# Check that calling it with many different inputs has the warning
202+
-> {
203+
("a".."z").each do |s|
204+
"zzz".gsub(pattern.new(s), "replacement")
205+
end
206+
}.should complain(/unbounded creation of regexps/)
207+
end
208+
209+
it "String#gsub!" do
210+
pattern = Class.new do
211+
def initialize(string) = @string = string
212+
def to_str = @string
213+
end
214+
215+
# Check that separate call sites with fixed input do not warn
216+
-> {
217+
"zzz".gsub!(pattern.new("a"), "replacement")
218+
"zzz".gsub!(pattern.new("b"), "replacement")
219+
"zzz".gsub!(pattern.new("c"), "replacement")
220+
"zzz".gsub!(pattern.new("d"), "replacement")
221+
"zzz".gsub!(pattern.new("e"), "replacement")
222+
"zzz".gsub!(pattern.new("f"), "replacement")
223+
"zzz".gsub!(pattern.new("g"), "replacement")
224+
"zzz".gsub!(pattern.new("h"), "replacement")
225+
"zzz".gsub!(pattern.new("i"), "replacement")
226+
"zzz".gsub!(pattern.new("j"), "replacement")
227+
}.should_not complain
228+
229+
# Check that calling it with many different inputs has the warning
230+
-> {
231+
("a".."z").each do |s|
232+
"zzz".gsub!(pattern.new(s), "replacement")
233+
end
234+
}.should complain(/unbounded creation of regexps/)
235+
end
236+
237+
it "String#match" do
238+
# Check that separate call sites with fixed input do not warn
239+
-> {
240+
"zzz".match("a")
241+
"zzz".match("b")
242+
"zzz".match("c")
243+
"zzz".match("d")
244+
"zzz".match("e")
245+
"zzz".match("f")
246+
"zzz".match("g")
247+
"zzz".match("h")
248+
"zzz".match("i")
249+
"zzz".match("j")
250+
}.should_not complain
251+
252+
# Check that calling it with many different inputs has the warning
253+
-> {
254+
("a".."z").each do |pattern|
255+
"zzz".match(pattern)
256+
end
257+
}.should complain(/unbounded creation of regexps/)
258+
end
259+
260+
it "String#match?" do
261+
# Check that separate call sites with fixed input do not warn
262+
-> {
263+
"zzz".match?("a")
264+
"zzz".match?("b")
265+
"zzz".match?("c")
266+
"zzz".match?("d")
267+
"zzz".match?("e")
268+
"zzz".match?("f")
269+
"zzz".match?("g")
270+
"zzz".match?("h")
271+
"zzz".match?("i")
272+
"zzz".match?("j")
273+
}.should_not complain
274+
275+
# Check that calling it with many different inputs has the warning
276+
-> {
277+
("a".."z").each do |pattern|
278+
"zzz".match?(pattern)
279+
end
280+
}.should complain(/unbounded creation of regexps/)
281+
end
282+
283+
it "Symbol#match" do
284+
# Check that separate call sites with fixed input do not warn
285+
-> {
286+
:zzz.match("a")
287+
:zzz.match("b")
288+
:zzz.match("c")
289+
:zzz.match("d")
290+
:zzz.match("e")
291+
:zzz.match("f")
292+
:zzz.match("g")
293+
:zzz.match("h")
294+
:zzz.match("i")
295+
:zzz.match("j")
296+
}.should_not complain
297+
298+
# Check that calling it with many different inputs has the warning
299+
-> {
300+
("a".."z").each do |pattern|
301+
:zzz.match(pattern)
302+
end
303+
}.should complain(/unbounded creation of regexps/)
304+
end
305+
306+
it "Symbol#match?" do
307+
# Check that separate call sites with fixed input do not warn
308+
-> {
309+
:zzz.match?("a")
310+
:zzz.match?("b")
311+
:zzz.match?("c")
312+
:zzz.match?("d")
313+
:zzz.match?("e")
314+
:zzz.match?("f")
315+
:zzz.match?("g")
316+
:zzz.match?("h")
317+
:zzz.match?("i")
318+
:zzz.match?("j")
319+
}.should_not complain
320+
321+
# Check that calling it with many different inputs has the warning
322+
-> {
323+
("a".."z").each do |pattern|
324+
:zzz.match?(pattern)
325+
end
326+
}.should complain(/unbounded creation of regexps/)
327+
end
92328
end
93329
end

src/main/ruby/truffleruby/core/regexp.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ def self.new(pattern, opts = undefined, encoding = nil)
184184
end
185185
Truffle::Graal.always_split(method(:new))
186186

187-
188187
class << self
189188
alias_method :compile, :new
190189
end

src/main/ruby/truffleruby/core/symbol.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def length
8888
def match(*args, &block)
8989
to_s.match(*args, &block)
9090
end
91+
Truffle::Graal.always_split(instance_method(:match))
9192

9293
def =~(pattern)
9394
str = to_s

0 commit comments

Comments
 (0)