Skip to content

Commit e840004

Browse files
committed
[GR-17457] Split TRegex warning option into two: when compilation to TRegex fail, and when a Regexp match could not use TRegex
PullRequest: truffleruby/2776
2 parents 3219bdb + cf08d31 commit e840004

File tree

8 files changed

+54
-40
lines changed

8 files changed

+54
-40
lines changed

lib/truffle/strscan.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,9 @@ def scan_internal(pattern, advance_pos, getstr, headonly)
314314
end
315315
raise ArgumentError, 'uninitialized StringScanner object' unless @string
316316

317-
@match = Truffle::RegexpOperations.match_onwards pattern, @string, pos, headonly
317+
md = Truffle::RegexpOperations.match_in_region pattern, @string, pos, @string.bytesize, headonly, pos
318+
Primitive.matchdata_fixup_positions(md, pos) if md
319+
@match = md
318320
return nil unless @match
319321

320322
fin = Primitive.match_data_byte_end(@match, 0)

src/main/java/org/truffleruby/core/regexp/TRegexCache.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121
import org.jcodings.specific.USASCIIEncoding;
2222
import org.jcodings.specific.UTF8Encoding;
2323
import org.truffleruby.RubyContext;
24+
import org.truffleruby.core.regexp.TruffleRegexpNodes.TRegexCompileNode;
2425
import org.truffleruby.core.rope.CannotConvertBinaryRubyStringToJavaString;
2526
import org.truffleruby.core.rope.Rope;
2627
import org.truffleruby.core.rope.RopeBuilder;
2728
import org.truffleruby.core.rope.RopeOperations;
2829
import org.truffleruby.language.Nil;
2930
import org.truffleruby.language.control.DeferredRaiseException;
30-
import org.truffleruby.language.dispatch.DispatchNode;
3131

3232
public final class TRegexCache {
3333

@@ -60,12 +60,13 @@ public Object getBinaryRegex(boolean atStart) {
6060
}
6161

6262
@TruffleBoundary
63-
public Object compile(RubyContext context, RubyRegexp regexp, boolean atStart, Encoding encoding) {
63+
public Object compile(RubyContext context, RubyRegexp regexp, boolean atStart, Encoding encoding,
64+
TRegexCompileNode node) {
6465
Object tregex = compileTRegex(context, regexp, atStart, encoding);
6566
if (tregex == null) {
6667
tregex = Nil.INSTANCE;
67-
if (context.getOptions().WARN_TRUFFLE_REGEX_FALLBACK) {
68-
DispatchNode.getUncached().call(
68+
if (context.getOptions().WARN_TRUFFLE_REGEX_COMPILE_FALLBACK) {
69+
node.getWarnOnFallbackNode().call(
6970
context.getCoreLibrary().truffleRegexpOperationsModule,
7071
"warn_fallback_regex",
7172
regexp,

src/main/java/org/truffleruby/core/regexp/TruffleRegexpNodes.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ protected Object usASCII(RubyRegexp regexp, boolean atStart, Encoding encoding)
254254
if (tregex != null) {
255255
return tregex;
256256
} else {
257-
return regexp.tregexCache.compile(getContext(), regexp, atStart, encoding);
257+
return regexp.tregexCache.compile(getContext(), regexp, atStart, encoding, this);
258258
}
259259
}
260260

@@ -264,7 +264,7 @@ protected Object latin1(RubyRegexp regexp, boolean atStart, Encoding encoding) {
264264
if (tregex != null) {
265265
return tregex;
266266
} else {
267-
return regexp.tregexCache.compile(getContext(), regexp, atStart, encoding);
267+
return regexp.tregexCache.compile(getContext(), regexp, atStart, encoding, this);
268268
}
269269
}
270270

@@ -274,7 +274,7 @@ protected Object utf8(RubyRegexp regexp, boolean atStart, Encoding encoding) {
274274
if (tregex != null) {
275275
return tregex;
276276
} else {
277-
return regexp.tregexCache.compile(getContext(), regexp, atStart, encoding);
277+
return regexp.tregexCache.compile(getContext(), regexp, atStart, encoding, this);
278278
}
279279
}
280280

@@ -284,7 +284,7 @@ protected Object binary(RubyRegexp regexp, boolean atStart, Encoding encoding) {
284284
if (tregex != null) {
285285
return tregex;
286286
} else {
287-
return regexp.tregexCache.compile(getContext(), regexp, atStart, encoding);
287+
return regexp.tregexCache.compile(getContext(), regexp, atStart, encoding, this);
288288
}
289289
}
290290

@@ -298,6 +298,13 @@ protected Object other(RubyRegexp regexp, boolean atStart, Encoding encoding) {
298298
return nil;
299299
}
300300

301+
DispatchNode getWarnOnFallbackNode() {
302+
if (warnOnFallbackNode == null) {
303+
CompilerDirectives.transferToInterpreterAndInvalidate();
304+
warnOnFallbackNode = insert(DispatchNode.create());
305+
}
306+
return warnOnFallbackNode;
307+
}
301308
}
302309

303310
public abstract static class RegexpStatsNode extends CoreMethodArrayArgumentsNode {
@@ -417,15 +424,15 @@ protected Object matchInRegionTRegex(
417424
@CachedLibrary(limit = "2") RubyStringLibrary libString,
418425
@Cached("createIdentityProfile()") IntValueProfile groupCountProfile) {
419426
final Rope rope = libString.getRope(string);
420-
Object tRegex = null;
427+
final Object tRegex;
421428

422429
if (tRegexIncompatibleProfile
423430
.profile(toPos < fromPos || toPos != rope.byteLength() || startPos != 0 || fromPos < 0) ||
424431
tRegexCouldNotCompileProfile.profile((tRegex = tRegexCompileNode.executeTRegexCompile(
425432
regexp,
426433
atStart,
427434
checkEncodingNode.executeCheckEncoding(regexp, string))) == nil)) {
428-
return fallbackToJoni(regexp, string, fromPos, toPos, atStart, startPos, tRegex);
435+
return fallbackToJoni(regexp, string, fromPos, toPos, atStart, startPos);
429436
}
430437

431438
final byte[] bytes = bytesNode.execute(rope);
@@ -455,9 +462,8 @@ protected Object matchInRegionTRegex(
455462
}
456463

457464
private Object fallbackToJoni(RubyRegexp regexp, Object string, int fromPos, int toPos, boolean atStart,
458-
int startPos, Object tRegex) {
459-
if (getContext().getOptions().WARN_TRUFFLE_REGEX_FALLBACK &&
460-
tRegex == null /* fallback due to arguments */) {
465+
int startPos) {
466+
if (getContext().getOptions().WARN_TRUFFLE_REGEX_MATCH_FALLBACK) {
461467
if (warnOnFallbackNode == null) {
462468
CompilerDirectives.transferToInterpreterAndInvalidate();
463469
warnOnFallbackNode = insert(DispatchNode.create());

src/main/java/org/truffleruby/options/Options.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,10 @@ public class Options {
131131
public final boolean WARN_EXPERIMENTAL;
132132
/** --use-truffle-regex=false */
133133
public final boolean USE_TRUFFLE_REGEX;
134-
/** --warn-truffle-regex-fallback=false */
135-
public final boolean WARN_TRUFFLE_REGEX_FALLBACK;
134+
/** --warn-truffle-regex-compile-fallback=false */
135+
public final boolean WARN_TRUFFLE_REGEX_COMPILE_FALLBACK;
136+
/** --warn-truffle-regex-match-fallback=false */
137+
public final boolean WARN_TRUFFLE_REGEX_MATCH_FALLBACK;
136138
/** --argv-globals=false */
137139
public final boolean ARGV_GLOBALS;
138140
/** --chomp-loop=false */
@@ -251,7 +253,8 @@ public Options(Env env, OptionValues options, LanguageOptions languageOptions) {
251253
WARN_DEPRECATED = options.get(OptionsCatalog.WARN_DEPRECATED_KEY);
252254
WARN_EXPERIMENTAL = options.get(OptionsCatalog.WARN_EXPERIMENTAL_KEY);
253255
USE_TRUFFLE_REGEX = options.get(OptionsCatalog.USE_TRUFFLE_REGEX_KEY);
254-
WARN_TRUFFLE_REGEX_FALLBACK = options.get(OptionsCatalog.WARN_TRUFFLE_REGEX_FALLBACK_KEY);
256+
WARN_TRUFFLE_REGEX_COMPILE_FALLBACK = options.get(OptionsCatalog.WARN_TRUFFLE_REGEX_COMPILE_FALLBACK_KEY);
257+
WARN_TRUFFLE_REGEX_MATCH_FALLBACK = options.get(OptionsCatalog.WARN_TRUFFLE_REGEX_MATCH_FALLBACK_KEY);
255258
ARGV_GLOBALS = options.get(OptionsCatalog.ARGV_GLOBALS_KEY);
256259
CHOMP_LOOP = options.get(OptionsCatalog.CHOMP_LOOP_KEY);
257260
GETS_LOOP = options.get(OptionsCatalog.GETS_LOOP_KEY);
@@ -395,8 +398,10 @@ public Object fromDescriptor(OptionDescriptor descriptor) {
395398
return WARN_EXPERIMENTAL;
396399
case "ruby.use-truffle-regex":
397400
return USE_TRUFFLE_REGEX;
398-
case "ruby.warn-truffle-regex-fallback":
399-
return WARN_TRUFFLE_REGEX_FALLBACK;
401+
case "ruby.warn-truffle-regex-compile-fallback":
402+
return WARN_TRUFFLE_REGEX_COMPILE_FALLBACK;
403+
case "ruby.warn-truffle-regex-match-fallback":
404+
return WARN_TRUFFLE_REGEX_MATCH_FALLBACK;
400405
case "ruby.argv-globals":
401406
return ARGV_GLOBALS;
402407
case "ruby.chomp-loop":

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1392,7 +1392,7 @@ def start_with?(*prefixes)
13921392
case original_prefix
13931393
when Regexp
13941394
Primitive.encoding_ensure_compatible(self, original_prefix)
1395-
match_data = Truffle::RegexpOperations.match_onwards(original_prefix, self, 0, true)
1395+
match_data = Truffle::RegexpOperations.match_in_region(original_prefix, self, 0, bytesize, true, 0)
13961396
Primitive.regexp_last_match_set(storage, match_data)
13971397
return true if match_data
13981398
else

src/main/ruby/truffleruby/core/truffle/regexp_operations.rb

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ module RegexpOperations
1818
Primitive.regexp_last_match_set(s, v)
1919
}
2020

21-
2221
def self.search_region(re, str, start_index, end_index, forward)
2322
raise TypeError, 'uninitialized regexp' unless Primitive.regexp_initialized?(re)
2423
raise ArgumentError, "invalid byte sequence in #{str.encoding}" unless str.valid_encoding?
@@ -34,16 +33,6 @@ def self.search_region(re, str, start_index, end_index, forward)
3433
match_in_region(re, str, from, to, false, 0)
3534
end
3635

37-
# This path is used by some string and scanner methods and allows
38-
# for at_start to be specified on the matcher. FIXME it might be
39-
# possible to refactor search region to offer the ability to
40-
# specify at start, we should investigate this at some point.
41-
def self.match_onwards(re, str, from, at_start)
42-
md = match_in_region(re, str, from, str.bytesize, at_start, from)
43-
Primitive.matchdata_fixup_positions(md, from) if md
44-
md
45-
end
46-
4736
def self.match(re, str, pos=0)
4837
return nil unless str
4938

@@ -64,7 +53,6 @@ def self.match_from(re, str, pos)
6453
Truffle::Boot.delay do
6554
COMPARE_ENGINES = Truffle::Boot.get_option('compare-regex-engines')
6655
USE_TRUFFLE_REGEX = Truffle::Boot.get_option('use-truffle-regex')
67-
WARN_TRUFFLE_REGEX_FALLBACK = Truffle::Boot.get_option('warn-truffle-regex-fallback')
6856

6957
if Truffle::Boot.get_option('regexp-instrument-creation') or Truffle::Boot.get_option('regexp-instrument-match')
7058
at_exit do

src/options.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ EXPERT:
146146

147147
# Controlling the regular expression engines
148148
USE_TRUFFLE_REGEX: [use-truffle-regex, boolean, false, 'Use the Truffle regular expression engine for Regexp objects']
149-
WARN_TRUFFLE_REGEX_FALLBACK: [warn-truffle-regex-fallback, boolean, false, 'Warn when Truffle Regex could not be used for a Regexp and instead Joni is used']
149+
WARN_TRUFFLE_REGEX_COMPILE_FALLBACK: [warn-truffle-regex-compile-fallback, boolean, false, 'Warn when a Ruby Regexp could not be compiled to a Truffle Regex and Joni is used instead']
150+
WARN_TRUFFLE_REGEX_MATCH_FALLBACK: [warn-truffle-regex-match-fallback, boolean, false, 'Warn every time Truffle Regex cannot be used for a Regexp match (and instead Joni is used)']
150151

151152
INTERNAL: # Options for debugging the TruffleRuby implementation
152153
EXPERIMENTAL:

src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ public class OptionsCatalog {
8484
public static final OptionKey<Boolean> WARN_DEPRECATED_KEY = new OptionKey<>(false);
8585
public static final OptionKey<Boolean> WARN_EXPERIMENTAL_KEY = new OptionKey<>(true);
8686
public static final OptionKey<Boolean> USE_TRUFFLE_REGEX_KEY = new OptionKey<>(false);
87-
public static final OptionKey<Boolean> WARN_TRUFFLE_REGEX_FALLBACK_KEY = new OptionKey<>(false);
87+
public static final OptionKey<Boolean> WARN_TRUFFLE_REGEX_COMPILE_FALLBACK_KEY = new OptionKey<>(false);
88+
public static final OptionKey<Boolean> WARN_TRUFFLE_REGEX_MATCH_FALLBACK_KEY = new OptionKey<>(false);
8889
public static final OptionKey<Boolean> ARGV_GLOBALS_KEY = new OptionKey<>(false);
8990
public static final OptionKey<Boolean> CHOMP_LOOP_KEY = new OptionKey<>(false);
9091
public static final OptionKey<Boolean> GETS_LOOP_KEY = new OptionKey<>(false);
@@ -606,9 +607,16 @@ public class OptionsCatalog {
606607
.stability(OptionStability.EXPERIMENTAL)
607608
.build();
608609

609-
public static final OptionDescriptor WARN_TRUFFLE_REGEX_FALLBACK = OptionDescriptor
610-
.newBuilder(WARN_TRUFFLE_REGEX_FALLBACK_KEY, "ruby.warn-truffle-regex-fallback")
611-
.help("Warn when Truffle Regex could not be used for a Regexp and instead Joni is used")
610+
public static final OptionDescriptor WARN_TRUFFLE_REGEX_COMPILE_FALLBACK = OptionDescriptor
611+
.newBuilder(WARN_TRUFFLE_REGEX_COMPILE_FALLBACK_KEY, "ruby.warn-truffle-regex-compile-fallback")
612+
.help("Warn when a Ruby Regexp could not be compiled to a Truffle Regex and Joni is used instead")
613+
.category(OptionCategory.EXPERT)
614+
.stability(OptionStability.EXPERIMENTAL)
615+
.build();
616+
617+
public static final OptionDescriptor WARN_TRUFFLE_REGEX_MATCH_FALLBACK = OptionDescriptor
618+
.newBuilder(WARN_TRUFFLE_REGEX_MATCH_FALLBACK_KEY, "ruby.warn-truffle-regex-match-fallback")
619+
.help("Warn every time Truffle Regex cannot be used for a Regexp match (and instead Joni is used)")
612620
.category(OptionCategory.EXPERT)
613621
.stability(OptionStability.EXPERIMENTAL)
614622
.build();
@@ -1247,8 +1255,10 @@ public static OptionDescriptor fromName(String name) {
12471255
return WARN_EXPERIMENTAL;
12481256
case "ruby.use-truffle-regex":
12491257
return USE_TRUFFLE_REGEX;
1250-
case "ruby.warn-truffle-regex-fallback":
1251-
return WARN_TRUFFLE_REGEX_FALLBACK;
1258+
case "ruby.warn-truffle-regex-compile-fallback":
1259+
return WARN_TRUFFLE_REGEX_COMPILE_FALLBACK;
1260+
case "ruby.warn-truffle-regex-match-fallback":
1261+
return WARN_TRUFFLE_REGEX_MATCH_FALLBACK;
12521262
case "ruby.argv-globals":
12531263
return ARGV_GLOBALS;
12541264
case "ruby.chomp-loop":
@@ -1464,7 +1474,8 @@ public static OptionDescriptor[] allDescriptors() {
14641474
WARN_DEPRECATED,
14651475
WARN_EXPERIMENTAL,
14661476
USE_TRUFFLE_REGEX,
1467-
WARN_TRUFFLE_REGEX_FALLBACK,
1477+
WARN_TRUFFLE_REGEX_COMPILE_FALLBACK,
1478+
WARN_TRUFFLE_REGEX_MATCH_FALLBACK,
14681479
ARGV_GLOBALS,
14691480
CHOMP_LOOP,
14701481
GETS_LOOP,

0 commit comments

Comments
 (0)