10
10
package org .truffleruby .language .constants ;
11
11
12
12
import com .oracle .truffle .api .CompilerDirectives ;
13
- import com .oracle .truffle .api .CompilerDirectives .CompilationFinal ;
14
13
import com .oracle .truffle .api .frame .VirtualFrame ;
15
14
import com .oracle .truffle .api .profiles .ConditionProfile ;
16
15
import org .truffleruby .core .cast .BooleanCastNode ;
17
16
import org .truffleruby .core .cast .BooleanCastNodeGen ;
18
17
import org .truffleruby .core .module .RubyModule ;
19
18
import org .truffleruby .language .RubyConstant ;
20
19
import org .truffleruby .language .RubyContextSourceNode ;
20
+ import org .truffleruby .utils .RunTwiceBranchProfile ;
21
21
22
22
/** e.g. for {@code module::FOO ||= 1}
23
23
*
@@ -31,25 +31,9 @@ public class OrAssignConstantNode extends RubyContextSourceNode {
31
31
@ Child protected WriteConstantNode writeConstant ;
32
32
@ Child private BooleanCastNode cast ;
33
33
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
34
private final ConditionProfile triviallyUndefined = ConditionProfile .create ();
51
35
private final ConditionProfile defined = ConditionProfile .create ();
52
- private final ConditionProfile truthy = ConditionProfile . create ();
36
+ private final RunTwiceBranchProfile writeTwiceProfile = new RunTwiceBranchProfile ();
53
37
54
38
public OrAssignConstantNode (ReadConstantNode readConstant , WriteConstantNode writeConstant ) {
55
39
this .readConstant = readConstant ;
@@ -59,17 +43,11 @@ public OrAssignConstantNode(ReadConstantNode readConstant, WriteConstantNode wri
59
43
@ Override
60
44
public Object execute (VirtualFrame frame ) {
61
45
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
46
if (triviallyUndefined .profile (readConstant .isModuleTriviallyUndefined (frame , getLanguage (), getContext ()))) {
70
47
// It might not be defined because of autoloaded constants (maybe other reasons?),
71
48
// simply attempt writing (which will trigger autoloads if required).
72
49
// Since we didn't evaluate the module part yet, no side-effects can occur.
50
+ writeTwiceProfile .enter ();
73
51
return writeConstant .execute (frame );
74
52
}
75
53
@@ -82,12 +60,16 @@ public Object execute(VirtualFrame frame) {
82
60
83
61
// Next we check if the constant itself is defined, and if it is, we get its value.
84
62
final RubyConstant constant = readConstant .getConstantIfDefined (module );
85
- final Object value = defined .profile (constant != null )
63
+
64
+ final boolean isDefined = defined .profile (constant != null );
65
+
66
+ final Object value = isDefined
86
67
? readConstant .getConstant (module , constant )
87
68
: null ;
88
69
89
70
// Write if the constant is undefined or if its value is falsy.
90
- if (!defined .profile (constant != null ) || !truthy .profile (castToBoolean (value ))) {
71
+ if (!isDefined || !castToBoolean (value )) {
72
+ writeTwiceProfile .enter ();
91
73
return writeConstant .execute (frame , module );
92
74
} else {
93
75
return value ;
0 commit comments