Skip to content

Commit dc120e7

Browse files
committed
[GR-19220] Avoid excessive splitting of nodes caused by a unique proc being created per call when a method reference would suffice (#3529)
PullRequest: truffleruby/4237
2 parents b4fe248 + 2d0171e commit dc120e7

File tree

2 files changed

+29
-27
lines changed

2 files changed

+29
-27
lines changed

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

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def split(string, pattern, limit, &orig_block)
4444
# To simplify the code, we present a single block
4545
# that either calls user (origin) block or adds a substring to the resulting array
4646
# See motivation: https://github.com/oracle/truffleruby/pull/2052#issuecomment-663449395
47-
block = orig_block || result.method(:<<).to_proc
47+
callable = orig_block || result.method(:<<)
4848

4949
return (orig_block ? string : result) if string.empty?
5050

@@ -57,7 +57,7 @@ def split(string, pattern, limit, &orig_block)
5757
if limit == 1
5858
dup_string = string.dup
5959

60-
block.call(dup_string)
60+
callable.call(dup_string)
6161
return orig_block ? dup_string : result
6262
end
6363

@@ -72,47 +72,48 @@ def split(string, pattern, limit, &orig_block)
7272
# See motivation: https://github.com/oracle/truffleruby/pull/2052#issuecomment-663494235
7373
return Primitive.string_awk_split string, awk_limit, orig_block
7474
elsif Primitive.is_a?(pattern, Regexp)
75-
split_type_regexp(string, pattern, limit, block)
75+
split_type_regexp(string, pattern, limit, callable)
7676
else
7777
pattern = StringValue(pattern)
7878

7979
valid_encoding?(string)
8080
valid_encoding?(pattern)
8181

8282
if pattern.empty?
83-
split_type_chars(string, limit, block)
83+
split_type_chars(string, limit, callable)
8484
else
85-
split_type_string(string, pattern, limit, block)
85+
split_type_string(string, pattern, limit, callable)
8686
end
8787
end
8888

8989
orig_block ? string : result
9090
end
91+
Truffle::Graal.always_split(instance_method(:split))
9192

9293
private
9394

9495
def valid_encoding?(string)
9596
raise ArgumentError, "invalid byte sequence in #{string.encoding.name}" unless string.valid_encoding?
9697
end
9798

98-
def split_type_chars(string, limit, block)
99+
def split_type_chars(string, limit, callable)
99100
if limit > 0
100101
last = string.size > (limit - 1) ? string[(limit - 1)..-1] : empty_string(string)
101102

102103
string.each_char.each_with_index do |char, index|
103104
break if index == limit - 1
104-
block.call(char)
105+
callable.call(char)
105106
end
106107

107-
block.call(last)
108+
callable.call(last)
108109
else
109-
string.each_char(&block)
110+
string.each_char { |c| callable.call(c) }
110111

111-
block.call(empty_string(string)) if tail_empty?(limit)
112+
callable.call(empty_string(string)) if tail_empty?(limit)
112113
end
113114
end
114115

115-
def split_type_string(string, pattern, limit, block)
116+
def split_type_string(string, pattern, limit, callable)
116117
pos = 0
117118
empty_count = 0
118119
limited = limit > 0
@@ -128,24 +129,24 @@ def split_type_string(string, pattern, limit, block)
128129
break unless nxt
129130

130131
match_size = nxt - pos
131-
empty_count = add_substring(string, ret, string.byteslice(pos, match_size), empty_count, block)
132+
empty_count = add_substring(string, ret, string.byteslice(pos, match_size), empty_count, callable)
132133

133134
pos = nxt + pat_size
134135
count += 1
135136
end
136137

137138
# No more separators, but we need to grab the last part still.
138-
empty_count = add_substring(string, ret, string.byteslice(pos, str_size - pos), empty_count, block)
139+
empty_count = add_substring(string, ret, string.byteslice(pos, str_size - pos), empty_count, callable)
139140

140141
if tail_empty?(limit)
141-
add_empty(string, ret, empty_count, block)
142+
add_empty(string, ret, empty_count, callable)
142143
end
143144
end
144145

145-
def split_type_regexp(string, pattern, limit, block)
146+
def split_type_regexp(string, pattern, limit, callable)
146147
# Handle // as a special case.
147148
if pattern.source.empty?
148-
return split_type_chars(string, limit, block)
149+
return split_type_chars(string, limit, callable)
149150
end
150151

151152
start = 0
@@ -164,12 +165,12 @@ def split_type_regexp(string, pattern, limit, block)
164165

165166
unless collapsed && (Primitive.match_data_byte_begin(match, 0) == last_match_end)
166167
substring = Truffle::RegexpOperations.pre_match_from(match, last_match_end)
167-
empty_count = add_substring(string, ret, substring, empty_count, block)
168+
empty_count = add_substring(string, ret, substring, empty_count, callable)
168169

169170
# length > 1 means there are captures
170171
if match.length > 1
171172
match.captures.compact.each do |capture|
172-
empty_count = add_substring(string, ret, capture, empty_count, block)
173+
empty_count = add_substring(string, ret, capture, empty_count, callable)
173174
end
174175
end
175176

@@ -186,31 +187,31 @@ def split_type_regexp(string, pattern, limit, block)
186187
end
187188

188189
if last_match
189-
empty_count = add_substring(string, ret, last_match.post_match, empty_count, block)
190+
empty_count = add_substring(string, ret, last_match.post_match, empty_count, callable)
190191
elsif ret.empty?
191-
empty_count = add_substring(string, ret, string.dup, empty_count, block)
192+
empty_count = add_substring(string, ret, string.dup, empty_count, callable)
192193
end
193194

194195
if tail_empty?(limit)
195-
add_empty(string, ret, empty_count, block)
196+
add_empty(string, ret, empty_count, callable)
196197
end
197198

198-
block ? string : ret
199+
callable ? string : ret
199200
end
200201

201202

202-
def add_substring(string, array, substring, empty_count, block)
203+
def add_substring(string, array, substring, empty_count, callable)
203204
return empty_count + 1 if substring.length == 0 # remember another one empty match
204205

205-
add_empty(string, array, empty_count, block)
206+
add_empty(string, array, empty_count, callable)
206207

207-
block.call(substring)
208+
callable.call(substring)
208209

209210
0 # always release all empties when we get non empty substring
210211
end
211212

212-
def add_empty(string, array, count, block)
213-
count.times { block.call(empty_string(string)) }
213+
def add_empty(string, array, count, callable)
214+
count.times { callable.call(empty_string(string)) }
214215
end
215216

216217
def empty_string(original)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ def scan(pattern, &block)
320320
def split(pattern = nil, limit = undefined, &block)
321321
Truffle::Splitter.split(Primitive.dup_as_string_instance(self), pattern, limit, &block)
322322
end
323+
Truffle::Graal.always_split(instance_method(:split))
323324

324325
def squeeze(*strings)
325326
str = Primitive.dup_as_string_instance(self)

0 commit comments

Comments
 (0)