Skip to content

Commit 2ea2298

Browse files
committed
[GR-71243] TRegex: fix possible deopt loop in RegexObject.getExecCallTarget and RegexObject.getExecBooleanCallTarget.
PullRequest: graal/22568
2 parents 257b7aa + d23b1e6 commit 2ea2298

File tree

10 files changed

+75
-77
lines changed

10 files changed

+75
-77
lines changed

regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexBodyNode.java

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,42 +49,51 @@
4949
import com.oracle.truffle.api.instrumentation.StandardTags;
5050
import com.oracle.truffle.api.instrumentation.Tag;
5151
import com.oracle.truffle.api.nodes.ExecutableNode;
52+
import com.oracle.truffle.api.nodes.Node;
5253
import com.oracle.truffle.api.source.Source;
5354
import com.oracle.truffle.api.source.SourceSection;
5455
import com.oracle.truffle.regex.tregex.string.Encoding;
5556

5657
@GenerateWrapper
5758
public abstract class RegexBodyNode extends ExecutableNode implements InstrumentableNode {
5859

59-
protected final RegexSource source;
60-
private final RegexLanguage language;
61-
6260
private SourceSection sourceSection;
6361

64-
protected RegexBodyNode(RegexLanguage language, RegexSource source) {
62+
protected RegexBodyNode(RegexLanguage language) {
6563
super(language);
66-
this.source = source;
67-
this.language = language;
6864
}
6965

7066
protected RegexBodyNode(RegexBodyNode copy) {
71-
this(copy.language, copy.source);
67+
this(copy.getRegexLanguage());
68+
}
69+
70+
private RegexRootNode getRegexRootNode() {
71+
Node parent = getParent();
72+
if (parent instanceof RegexBodyNodeWrapper) {
73+
parent = parent.getParent();
74+
}
75+
assert parent != null;
76+
return (RegexRootNode) parent;
7277
}
7378

7479
public RegexSource getSource() {
75-
return source;
80+
RegexSource source1 = getRegexRootNode().getSource();
81+
CompilerAsserts.partialEvaluationConstant(source1);
82+
return source1;
7683
}
7784

7885
public RegexLanguage getRegexLanguage() {
79-
return language;
86+
return getRegexRootNode().getLanguage(RegexLanguage.class);
8087
}
8188

8289
public Encoding getEncoding() {
83-
return source.getEncoding();
90+
Encoding encoding = getSource().getEncoding();
91+
CompilerAsserts.partialEvaluationConstant(encoding);
92+
return encoding;
8493
}
8594

8695
public boolean isBooleanMatch() {
87-
boolean booleanMatch = source.getOptions().isBooleanMatch();
96+
boolean booleanMatch = getSource().getOptions().isBooleanMatch();
8897
CompilerAsserts.partialEvaluationConstant(booleanMatch);
8998
return booleanMatch;
9099
}
@@ -93,7 +102,7 @@ public boolean isBooleanMatch() {
93102
@Override
94103
public SourceSection getSourceSection() {
95104
if (sourceSection == null) {
96-
String patternSrc = source.toStringEscaped();
105+
String patternSrc = getSource().toStringEscaped();
97106
String name = patternSrc.length() > 30 ? patternSrc.substring(0, 30) + "..." : patternSrc;
98107
Source src = Source.newBuilder(RegexLanguage.ID, patternSrc, name).internal(true).mimeType("application/js-regex").build();
99108
sourceSection = src.createSection(0, patternSrc.length());
@@ -119,8 +128,8 @@ public WrapperNode createWrapper(ProbeNode probe) {
119128
@TruffleBoundary
120129
@Override
121130
public final String toString() {
122-
String src = source.toStringEscaped();
123-
return "tregex " + source.getSource().getName() + " " + getEngineLabel() + ": " + (src.length() > 30 ? src.substring(0, 30) + "..." : src);
131+
String src = getSource().toStringEscaped();
132+
return "tregex " + getSource().getSource().getName() + " " + getEngineLabel() + ": " + (src.length() > 30 ? src.substring(0, 30) + "..." : src);
124133
}
125134

126135
protected String getEngineLabel() {

regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexExecNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ public abstract class RegexExecNode extends RegexBodyNode {
5858
private @Child InputReadNode charAtNode;
5959

6060
public RegexExecNode(RegexLanguage language, RegexSource source, boolean mustCheckUTF16Surrogates) {
61-
super(language, source);
62-
this.mustCheckUTF16Surrogates = getEncoding().isUTF16() && mustCheckUTF16Surrogates;
61+
super(language);
62+
this.mustCheckUTF16Surrogates = source.getOptions().getEncoding().isUTF16() && mustCheckUTF16Surrogates;
6363
}
6464

6565
@Override

regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexObject.java

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
import com.oracle.truffle.api.CallTarget;
4444
import com.oracle.truffle.api.CompilerDirectives;
45-
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
4645
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4746
import com.oracle.truffle.api.RootCallTarget;
4847
import com.oracle.truffle.api.TruffleLanguage;
@@ -57,8 +56,6 @@
5756
import com.oracle.truffle.api.interop.InteropLibrary;
5857
import com.oracle.truffle.api.interop.TruffleObject;
5958
import com.oracle.truffle.api.interop.UnknownIdentifierException;
60-
import com.oracle.truffle.api.interop.UnsupportedMessageException;
61-
import com.oracle.truffle.api.interop.UnsupportedTypeException;
6259
import com.oracle.truffle.api.library.ExportLibrary;
6360
import com.oracle.truffle.api.library.ExportMessage;
6461
import com.oracle.truffle.api.nodes.DirectCallNode;
@@ -67,7 +64,6 @@
6764
import com.oracle.truffle.api.strings.TruffleString;
6865
import com.oracle.truffle.regex.literal.LiteralRegexExecNode;
6966
import com.oracle.truffle.regex.result.RegexResult;
70-
import com.oracle.truffle.regex.tregex.TRegexCompilationRequest;
7167
import com.oracle.truffle.regex.util.TruffleReadOnlyKeysArray;
7268

7369
/**
@@ -147,26 +143,26 @@ public final class RegexObject extends AbstractConstantKeysObject {
147143
private static final String PROP_IS_BACKTRACKING = "isBacktracking";
148144
private static final TruffleReadOnlyKeysArray KEYS = new TruffleReadOnlyKeysArray(PROP_EXEC, PROP_EXEC_BOOLEAN, PROP_PATTERN, PROP_FLAGS, PROP_GROUP_COUNT, PROP_GROUPS, PROP_IS_BACKTRACKING);
149145

150-
private final RegexLanguage language;
151146
private final RegexSource source;
152147
private final AbstractRegexObject flags;
153148
private final int numberOfCaptureGroups;
154149
private final AbstractRegexObject namedCaptureGroups;
155-
@CompilationFinal private RootCallTarget execRootCallTarget;
156-
@CompilationFinal private RootCallTarget execBooleanRootCallTarget;
150+
private final RootCallTarget execRootCallTarget;
151+
private final RootCallTarget execBooleanRootCallTarget;
157152
private final boolean backtracking;
158153

159-
public RegexObject(RegexExecNode execNode, RegexSource source, AbstractRegexObject flags, int numberOfCaptureGroups, AbstractRegexObject namedCaptureGroups) {
160-
this.language = execNode.getRegexLanguage();
154+
public RegexObject(RegexLanguage language, RegexSource source, RegexExecNode execNode, AbstractRegexObject flags, int numberOfCaptureGroups, AbstractRegexObject namedCaptureGroups) {
161155
this.source = source;
162156
this.flags = flags;
163157
this.numberOfCaptureGroups = numberOfCaptureGroups;
164158
this.namedCaptureGroups = namedCaptureGroups;
165-
RegexRootNode rootNode = new RegexRootNode(execNode.getRegexLanguage(), execNode);
166-
if (execNode.isBooleanMatch()) {
159+
RegexRootNode rootNode = new RegexRootNode(language, source, execNode);
160+
if (source.getOptions().isBooleanMatch()) {
161+
this.execRootCallTarget = new RegexRootNode(language, source.withoutBooleanMatch(), null).getCallTarget();
167162
this.execBooleanRootCallTarget = rootNode.getCallTarget();
168163
} else {
169164
this.execRootCallTarget = rootNode.getCallTarget();
165+
this.execBooleanRootCallTarget = new RegexRootNode(language, source.withBooleanMatch(), null).getCallTarget();
170166
}
171167
this.backtracking = execNode.isBacktracking();
172168
}
@@ -209,19 +205,10 @@ private static RegexRootNode getRootNode(RootCallTarget execRootCallTarget) {
209205
}
210206

211207
public CallTarget getExecCallTarget() {
212-
if (execRootCallTarget == null) {
213-
CompilerDirectives.transferToInterpreterAndInvalidate();
214-
execRootCallTarget = new RegexRootNode(language,
215-
new TRegexCompilationRequest(language, getRootNode(execBooleanRootCallTarget).getSource().withoutBooleanMatch()).compile()).getCallTarget();
216-
}
217208
return execRootCallTarget;
218209
}
219210

220211
public CallTarget getExecBooleanCallTarget() {
221-
if (execBooleanRootCallTarget == null) {
222-
CompilerDirectives.transferToInterpreterAndInvalidate();
223-
execBooleanRootCallTarget = new RegexRootNode(language, new TRegexCompilationRequest(language, getRootNode(execRootCallTarget).getSource().withBooleanMatch()).compile()).getCallTarget();
224-
}
225212
return execBooleanRootCallTarget;
226213
}
227214

@@ -313,8 +300,7 @@ static boolean isInvocable(RegexObject receiver, String symbol) {
313300

314301
@ExportMessage
315302
Object invokeMember(String member, Object[] args,
316-
@Cached InvokeCacheNode invokeCache)
317-
throws UnknownIdentifierException, ArityException, UnsupportedTypeException, UnsupportedMessageException {
303+
@Cached InvokeCacheNode invokeCache) throws UnknownIdentifierException, ArityException {
318304
checkArity(args);
319305
return invokeCache.execute(member, this, args);
320306
}
@@ -324,46 +310,45 @@ Object invokeMember(String member, Object[] args,
324310
@GenerateUncached
325311
abstract static class InvokeCacheNode extends Node {
326312

327-
abstract Object execute(String symbol, RegexObject receiver, Object[] args)
328-
throws UnsupportedMessageException, ArityException, UnsupportedTypeException, UnknownIdentifierException;
313+
abstract Object execute(String symbol, RegexObject receiver, Object[] args) throws UnknownIdentifierException;
329314

330315
@SuppressWarnings("unused")
331316
@Specialization(guards = {"symbol == cachedSymbol", "cachedSymbol.equals(PROP_EXEC)"}, limit = N_METHODS)
332317
Object execIdentity(String symbol, RegexObject receiver, Object[] args,
333318
@Cached("symbol") String cachedSymbol,
334-
@Cached @Shared ExecCompiledRegexNode execNode) throws UnsupportedMessageException, ArityException, UnsupportedTypeException {
319+
@Cached @Shared ExecCompiledRegexNode execNode) {
335320
return execNode.execute(receiver, args);
336321
}
337322

338323
@SuppressWarnings("unused")
339324
@Specialization(guards = {"symbol.equals(cachedSymbol)", "cachedSymbol.equals(PROP_EXEC)"}, limit = N_METHODS, replaces = "execIdentity")
340325
Object execEquals(String symbol, RegexObject receiver, Object[] args,
341326
@Cached("symbol") String cachedSymbol,
342-
@Cached @Shared ExecCompiledRegexNode execNode) throws UnsupportedMessageException, ArityException, UnsupportedTypeException {
327+
@Cached @Shared ExecCompiledRegexNode execNode) {
343328
return execNode.execute(receiver, args);
344329
}
345330

346331
@SuppressWarnings("unused")
347332
@Specialization(guards = {"symbol == cachedSymbol", "cachedSymbol.equals(PROP_EXEC_BOOLEAN)"}, limit = N_METHODS)
348333
boolean execBooleanIdentity(String symbol, RegexObject receiver, Object[] args,
349334
@Cached("symbol") String cachedSymbol,
350-
@Cached @Shared ExecBooleanCompiledRegexNode execBoolNode) throws UnsupportedMessageException, ArityException, UnsupportedTypeException {
335+
@Cached @Shared ExecBooleanCompiledRegexNode execBoolNode) {
351336
return execBoolNode.execute(receiver, args) != RegexResult.getNoMatchInstance();
352337
}
353338

354339
@SuppressWarnings("unused")
355340
@Specialization(guards = {"symbol.equals(cachedSymbol)", "cachedSymbol.equals(PROP_EXEC_BOOLEAN)"}, limit = N_METHODS, replaces = "execBooleanIdentity")
356341
boolean execBooleanEquals(String symbol, RegexObject receiver, Object[] args,
357342
@Cached("symbol") String cachedSymbol,
358-
@Cached @Shared ExecBooleanCompiledRegexNode execBoolNode) throws UnsupportedMessageException, ArityException, UnsupportedTypeException {
343+
@Cached @Shared ExecBooleanCompiledRegexNode execBoolNode) {
359344
return execBoolNode.execute(receiver, args) != RegexResult.getNoMatchInstance();
360345
}
361346

362347
@ReportPolymorphism.Megamorphic
363348
@Specialization(replaces = {"execEquals", "execBooleanEquals"})
364349
static Object invokeGeneric(String symbol, RegexObject receiver, Object[] args,
365350
@Cached @Shared ExecCompiledRegexNode execNode,
366-
@Cached @Shared ExecBooleanCompiledRegexNode execBoolNode) throws UnsupportedMessageException, ArityException, UnsupportedTypeException, UnknownIdentifierException {
351+
@Cached @Shared ExecBooleanCompiledRegexNode execBoolNode) throws UnknownIdentifierException {
367352
switch (symbol) {
368353
case PROP_EXEC:
369354
return execNode.execute(receiver, args);
@@ -393,7 +378,7 @@ boolean isExecutable() {
393378

394379
@ExportMessage
395380
Object execute(Object[] args,
396-
@Cached ExecCompiledRegexNode execNode) throws ArityException, UnsupportedTypeException, UnsupportedMessageException {
381+
@Cached ExecCompiledRegexNode execNode) throws ArityException {
397382
checkArity(args);
398383
return execNode.execute(regex, args);
399384
}
@@ -422,7 +407,7 @@ boolean isExecutable() {
422407

423408
@ExportMessage
424409
boolean execute(Object[] args,
425-
@Cached ExecBooleanCompiledRegexNode execNode) throws ArityException, UnsupportedTypeException, UnsupportedMessageException {
410+
@Cached ExecBooleanCompiledRegexNode execNode) throws ArityException {
426411
checkArity(args);
427412
return execNode.execute(regex, args) != RegexResult.getNoMatchInstance();
428413
}
@@ -439,7 +424,7 @@ public String toString() {
439424
@GenerateUncached
440425
abstract static class ExecCompiledRegexNode extends Node {
441426

442-
abstract Object execute(RegexObject receiver, Object[] args) throws UnsupportedMessageException, ArityException, UnsupportedTypeException;
427+
abstract Object execute(RegexObject receiver, Object[] args);
443428

444429
@SuppressWarnings("unused")
445430
@Specialization(guards = "receiver == cachedReceiver", limit = "4")
@@ -462,7 +447,7 @@ static Object doIndirectCall(RegexObject receiver, Object[] args,
462447
@GenerateUncached
463448
abstract static class ExecBooleanCompiledRegexNode extends Node {
464449

465-
abstract Object execute(RegexObject receiver, Object[] args) throws UnsupportedMessageException, ArityException, UnsupportedTypeException;
450+
abstract Object execute(RegexObject receiver, Object[] args);
466451

467452
@SuppressWarnings("unused")
468453
@Specialization(guards = "receiver == cachedReceiver", limit = "4")

regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/RegexRootNode.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,30 @@
4141
package com.oracle.truffle.regex;
4242

4343
import com.oracle.truffle.api.CompilerAsserts;
44+
import com.oracle.truffle.api.CompilerDirectives;
4445
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4546
import com.oracle.truffle.api.frame.FrameDescriptor;
4647
import com.oracle.truffle.api.frame.VirtualFrame;
4748
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
4849
import com.oracle.truffle.api.nodes.RootNode;
4950
import com.oracle.truffle.api.source.SourceSection;
51+
import com.oracle.truffle.regex.tregex.TRegexCompilationRequest;
5052

5153
public final class RegexRootNode extends RootNode {
5254

5355
public static final FrameDescriptor SHARED_EMPTY_FRAMEDESCRIPTOR = new FrameDescriptor();
5456

57+
private final RegexSource source;
5558
@Child private RegexBodyNode body;
5659

57-
public RegexRootNode(RegexLanguage language, RegexBodyNode body) {
60+
public RegexRootNode(RegexLanguage language, RegexSource source, RegexBodyNode body) {
5861
super(language, SHARED_EMPTY_FRAMEDESCRIPTOR);
62+
this.source = source;
5963
this.body = body;
6064
}
6165

6266
public RegexSource getSource() {
63-
return body.getSource();
67+
return source;
6468
}
6569

6670
public RegexBodyNode getBodyUnwrapped() {
@@ -72,11 +76,15 @@ public RegexBodyNode getBodyUnwrapped() {
7276

7377
@Override
7478
public SourceSection getSourceSection() {
75-
return body.getSourceSection();
79+
return body == null ? null : body.getSourceSection();
7680
}
7781

7882
@Override
7983
public Object execute(VirtualFrame frame) {
84+
if (body == null) {
85+
CompilerDirectives.transferToInterpreterAndInvalidate();
86+
body = insert(new TRegexCompilationRequest(getLanguage(RegexLanguage.class), source).compile());
87+
}
8088
return body.execute(frame);
8189
}
8290

regex/src/com.oracle.truffle.regex/src/com/oracle/truffle/regex/tregex/TRegexCompiler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public static RegexObject compile(RegexLanguage language, RegexSource source) th
8787
private static RegexObject doCompile(RegexLanguage language, RegexSource source) throws RegexSyntaxException {
8888
TRegexCompilationRequest compReq = new TRegexCompilationRequest(language, source);
8989
RegexExecNode execNode = compReq.compile();
90-
return new RegexObject(execNode, source, compReq.getAst().getFlavorSpecificFlags(), compReq.getAst().getNumberOfCaptureGroups(), compReq.getNamedCaptureGroups());
90+
return new RegexObject(language, source, execNode, compReq.getAst().getFlavorSpecificFlags(), compReq.getAst().getNumberOfCaptureGroups(), compReq.getNamedCaptureGroups());
9191
}
9292

9393
@TruffleBoundary

0 commit comments

Comments
 (0)