Skip to content

Commit d9dcb14

Browse files
committed
Move MatchNode next to its usage
1 parent 2409d97 commit d9dcb14

File tree

1 file changed

+105
-105
lines changed

1 file changed

+105
-105
lines changed

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

Lines changed: 105 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,111 @@ static Object matchInRegion(
949949
}
950950
}
951951

952+
public abstract static class MatchNode extends RubyBaseNode {
953+
954+
public abstract Object execute(RubyRegexp regexp, Object string, Matcher matcher, int from, int to,
955+
boolean onlyMatchAtStart, int start, boolean createMatchData);
956+
957+
// Creating a MatchData will store a copy of the source string. It's tempting to use a rope here, but a bit
958+
// inconvenient because we can't work with ropes directly in Ruby and some MatchData methods are nicely
959+
// implemented using the source string data. We mustn't allow the source string's contents to change, however, so we must ensure that we have
960+
// a private copy of that string. Since the source string would otherwise be a reference to string held outside
961+
// the MatchData object, it would be possible for the source string to be modified externally.
962+
//
963+
// Ex. x = "abc"; x =~ /(.*)/; x.upcase!
964+
//
965+
// Without a private copy, the MatchData's source could be modified to be upcased when it should remain the
966+
// same as when the MatchData was created.
967+
@Specialization
968+
Object match(
969+
RubyRegexp regexp,
970+
Object string,
971+
Matcher matcher,
972+
int from,
973+
int to,
974+
boolean onlyMatchAtStart,
975+
int start,
976+
boolean createMatchData,
977+
@Cached LazyDispatchNode stringDupNode,
978+
@Cached InlinedConditionProfile createMatchDataProfile,
979+
@Cached InlinedConditionProfile mismatchProfile,
980+
@Cached InlinedConditionProfile nonZeroStart,
981+
@Cached FixupMatchDataStartNode fixupMatchDataStartNode) {
982+
if (getContext().getOptions().REGEXP_INSTRUMENT_MATCH) {
983+
TruffleRegexpNodes.instrumentMatch(
984+
MATCHED_REGEXPS_JONI,
985+
regexp,
986+
string,
987+
onlyMatchAtStart,
988+
getContext().getOptions().REGEXP_INSTRUMENT_MATCH_DETAILED);
989+
}
990+
991+
int match = runMatch(matcher, from, to, onlyMatchAtStart);
992+
993+
if (createMatchDataProfile.profile(this, createMatchData)) {
994+
if (mismatchProfile.profile(this, match == Matcher.FAILED)) {
995+
return nil;
996+
}
997+
998+
assert match >= 0;
999+
1000+
final MultiRegion region = getMatcherEagerRegion(matcher);
1001+
assert assertValidRegion(region);
1002+
1003+
var dupedString = stringDupNode.get(this).call(string, "dup");
1004+
RubyMatchData result = new RubyMatchData(
1005+
coreLibrary().matchDataClass,
1006+
getLanguage().matchDataShape,
1007+
regexp,
1008+
dupedString,
1009+
region);
1010+
AllocationTracing.trace(result, this);
1011+
1012+
if (nonZeroStart.profile(this, start != 0)) {
1013+
fixupMatchDataStartNode.execute(this, result, start);
1014+
}
1015+
1016+
return result;
1017+
} else {
1018+
return match != Matcher.FAILED;
1019+
}
1020+
}
1021+
1022+
@TruffleBoundary
1023+
private int runMatch(Matcher matcher, int from, int to, boolean onlyMatchAtStart) {
1024+
// Keep status as RUN because MRI has an uninterruptible Regexp engine
1025+
if (onlyMatchAtStart) {
1026+
return getContext().getThreadManager().runUntilResultKeepStatus(this,
1027+
unused -> matcher.matchInterruptible(from, to, Option.DEFAULT), null);
1028+
} else {
1029+
return getContext().getThreadManager().runUntilResultKeepStatus(this,
1030+
unused -> matcher.searchInterruptible(from, to, Option.DEFAULT), null);
1031+
}
1032+
}
1033+
1034+
/** Is equivalent to {@link org.graalvm.shadowed.org.joni.Matcher#getEagerRegion()} but returns MultiRegion
1035+
* instead of abstract Region class */
1036+
private MultiRegion getMatcherEagerRegion(Matcher matcher) {
1037+
Region eagerRegion = matcher.getEagerRegion();
1038+
1039+
if (eagerRegion instanceof SingleRegion singleRegion) {
1040+
return new MultiRegion(singleRegion.getBeg(0), singleRegion.getEnd(0));
1041+
} else if (eagerRegion instanceof MultiRegion multiRegion) {
1042+
return multiRegion;
1043+
} else {
1044+
throw CompilerDirectives.shouldNotReachHere();
1045+
}
1046+
}
1047+
1048+
private boolean assertValidRegion(MultiRegion region) {
1049+
for (int i = 0; i < region.getNumRegs(); i++) {
1050+
assert region.getBeg(i) >= 0 || region.getBeg(i) == RubyMatchData.MISSING;
1051+
assert region.getEnd(i) >= 0 || region.getEnd(i) == RubyMatchData.MISSING;
1052+
}
1053+
return true;
1054+
}
1055+
}
1056+
9521057
@GenerateCached(false)
9531058
@GenerateInline
9541059
public abstract static class LazyMatchInRegionJoniNode extends RubyBaseNode {
@@ -1182,111 +1287,6 @@ Object isLinearTime(RubyRegexp regexp,
11821287
}
11831288
}
11841289

1185-
public abstract static class MatchNode extends RubyBaseNode {
1186-
1187-
public abstract Object execute(RubyRegexp regexp, Object string, Matcher matcher,
1188-
int from, int to, boolean onlyMatchAtStart, int start, boolean createMatchData);
1189-
1190-
// Creating a MatchData will store a copy of the source string. It's tempting to use a rope here, but a bit
1191-
// inconvenient because we can't work with ropes directly in Ruby and some MatchData methods are nicely
1192-
// implemented using the source string data. We mustn't allow the source string's contents to change, however, so we must ensure that we have
1193-
// a private copy of that string. Since the source string would otherwise be a reference to string held outside
1194-
// the MatchData object, it would be possible for the source string to be modified externally.
1195-
//
1196-
// Ex. x = "abc"; x =~ /(.*)/; x.upcase!
1197-
//
1198-
// Without a private copy, the MatchData's source could be modified to be upcased when it should remain the
1199-
// same as when the MatchData was created.
1200-
@Specialization
1201-
Object match(
1202-
RubyRegexp regexp,
1203-
Object string,
1204-
Matcher matcher,
1205-
int from,
1206-
int to,
1207-
boolean onlyMatchAtStart,
1208-
int start,
1209-
boolean createMatchData,
1210-
@Cached LazyDispatchNode stringDupNode,
1211-
@Cached InlinedConditionProfile createMatchDataProfile,
1212-
@Cached InlinedConditionProfile mismatchProfile,
1213-
@Cached InlinedConditionProfile nonZeroStart,
1214-
@Cached FixupMatchDataStartNode fixupMatchDataStartNode) {
1215-
if (getContext().getOptions().REGEXP_INSTRUMENT_MATCH) {
1216-
TruffleRegexpNodes.instrumentMatch(
1217-
MATCHED_REGEXPS_JONI,
1218-
regexp,
1219-
string,
1220-
onlyMatchAtStart,
1221-
getContext().getOptions().REGEXP_INSTRUMENT_MATCH_DETAILED);
1222-
}
1223-
1224-
int match = runMatch(matcher, from, to, onlyMatchAtStart);
1225-
1226-
if (createMatchDataProfile.profile(this, createMatchData)) {
1227-
if (mismatchProfile.profile(this, match == Matcher.FAILED)) {
1228-
return nil;
1229-
}
1230-
1231-
assert match >= 0;
1232-
1233-
final MultiRegion region = getMatcherEagerRegion(matcher);
1234-
assert assertValidRegion(region);
1235-
1236-
var dupedString = stringDupNode.get(this).call(string, "dup");
1237-
RubyMatchData result = new RubyMatchData(
1238-
coreLibrary().matchDataClass,
1239-
getLanguage().matchDataShape,
1240-
regexp,
1241-
dupedString,
1242-
region);
1243-
AllocationTracing.trace(result, this);
1244-
1245-
if (nonZeroStart.profile(this, start != 0)) {
1246-
fixupMatchDataStartNode.execute(this, result, start);
1247-
}
1248-
1249-
return result;
1250-
} else {
1251-
return match != Matcher.FAILED;
1252-
}
1253-
}
1254-
1255-
@TruffleBoundary
1256-
private int runMatch(Matcher matcher, int from, int to, boolean onlyMatchAtStart) {
1257-
// Keep status as RUN because MRI has an uninterruptible Regexp engine
1258-
if (onlyMatchAtStart) {
1259-
return getContext().getThreadManager().runUntilResultKeepStatus(this,
1260-
unused -> matcher.matchInterruptible(from, to, Option.DEFAULT), null);
1261-
} else {
1262-
return getContext().getThreadManager().runUntilResultKeepStatus(this,
1263-
unused -> matcher.searchInterruptible(from, to, Option.DEFAULT), null);
1264-
}
1265-
}
1266-
1267-
/** Is equivalent to {@link org.graalvm.shadowed.org.joni.Matcher#getEagerRegion()} but returns MultiRegion
1268-
* instead of abstract Region class */
1269-
private MultiRegion getMatcherEagerRegion(Matcher matcher) {
1270-
Region eagerRegion = matcher.getEagerRegion();
1271-
1272-
if (eagerRegion instanceof SingleRegion singleRegion) {
1273-
return new MultiRegion(singleRegion.getBeg(0), singleRegion.getEnd(0));
1274-
} else if (eagerRegion instanceof MultiRegion multiRegion) {
1275-
return multiRegion;
1276-
} else {
1277-
throw CompilerDirectives.shouldNotReachHere();
1278-
}
1279-
}
1280-
1281-
private boolean assertValidRegion(MultiRegion region) {
1282-
for (int i = 0; i < region.getNumRegs(); i++) {
1283-
assert region.getBeg(i) >= 0 || region.getBeg(i) == RubyMatchData.MISSING;
1284-
assert region.getEnd(i) >= 0 || region.getEnd(i) == RubyMatchData.MISSING;
1285-
}
1286-
return true;
1287-
}
1288-
}
1289-
12901290
static final class MatchInfo {
12911291

12921292
private final RubyRegexp regex;

0 commit comments

Comments
 (0)