Skip to content

Commit c35ad71

Browse files
author
Nicolas Laurent
committed
profile OrAssignConstantNode
1 parent a6594a9 commit c35ad71

File tree

1 file changed

+34
-5
lines changed

1 file changed

+34
-5
lines changed

src/main/java/org/truffleruby/language/constants/OrAssignConstantNode.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
package org.truffleruby.language.constants;
1111

1212
import com.oracle.truffle.api.CompilerDirectives;
13+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
1314
import com.oracle.truffle.api.frame.VirtualFrame;
15+
import com.oracle.truffle.api.profiles.ConditionProfile;
1416
import org.truffleruby.core.cast.BooleanCastNode;
1517
import org.truffleruby.core.cast.BooleanCastNodeGen;
1618
import org.truffleruby.core.module.RubyModule;
@@ -29,6 +31,26 @@ public class OrAssignConstantNode extends RubyContextSourceNode {
2931
@Child protected WriteConstantNode writeConstant;
3032
@Child private BooleanCastNode cast;
3133

34+
private enum ExecuteCounter {
35+
NEVER,
36+
ONCE,
37+
MANY;
38+
39+
public ExecuteCounter next() {
40+
if (this == NEVER) {
41+
return ONCE;
42+
} else {
43+
return MANY;
44+
}
45+
}
46+
47+
}
48+
49+
@CompilationFinal private ExecuteCounter executeCounter = ExecuteCounter.NEVER;
50+
private final ConditionProfile triviallyUndefined = ConditionProfile.create();
51+
private final ConditionProfile defined = ConditionProfile.create();
52+
private final ConditionProfile truthy = ConditionProfile.create();
53+
3254
public OrAssignConstantNode(ReadConstantNode readConstant, WriteConstantNode writeConstant) {
3355
this.readConstant = readConstant;
3456
this.writeConstant = writeConstant;
@@ -37,7 +59,14 @@ public OrAssignConstantNode(ReadConstantNode readConstant, WriteConstantNode wri
3759
@Override
3860
public Object execute(VirtualFrame frame) {
3961

40-
if (readConstant.isModuleTriviallyUndefined(frame, getLanguage(), getContext())) {
62+
if (executeCounter != ExecuteCounter.MANY) {
63+
// Make sure to reset the profiles after the first execution, as we expect the first execution to write
64+
// the constant and subsequent execution to simply read it.
65+
CompilerDirectives.transferToInterpreterAndInvalidate();
66+
executeCounter = executeCounter.next();
67+
}
68+
69+
if (triviallyUndefined.profile(readConstant.isModuleTriviallyUndefined(frame, getLanguage(), getContext()))) {
4170
// It might not be defined because of autoloaded constants (maybe other reasons?),
4271
// simply attempt writing (which will trigger autoloads if required).
4372
// Since we didn't evaluate the module part yet, no side-effects can occur.
@@ -53,12 +82,12 @@ public Object execute(VirtualFrame frame) {
5382

5483
// Next we check if the constant itself is defined, and if it is, we get its value.
5584
final RubyConstant constant = readConstant.getConstantIfDefined(module);
56-
final Object value = constant == null
57-
? null
58-
: readConstant.getConstant(module, constant);
85+
final Object value = defined.profile(constant != null)
86+
? readConstant.getConstant(module, constant)
87+
: null;
5988

6089
// Write if the constant is undefined or if its value is falsy.
61-
if (constant == null || !castToBoolean(value)) {
90+
if (!defined.profile(constant != null) || !truthy.profile(castToBoolean(value))) {
6291
return writeConstant.execute(frame, module);
6392
} else {
6493
return value;

0 commit comments

Comments
 (0)