9
9
*/
10
10
package org .truffleruby .language .constants ;
11
11
12
- import com .oracle .truffle .api .CompilerDirectives ;
12
+ import com .oracle .truffle .api .dsl .Cached ;
13
+ import com .oracle .truffle .api .dsl .Specialization ;
13
14
import com .oracle .truffle .api .frame .VirtualFrame ;
14
- import com .oracle .truffle .api .profiles .ConditionProfile ;
15
+ import com .oracle .truffle .api .profiles .InlinedConditionProfile ;
15
16
import org .truffleruby .core .cast .BooleanCastNode ;
16
- import org .truffleruby .core .cast .BooleanCastNodeGen ;
17
17
import org .truffleruby .core .module .RubyModule ;
18
18
import org .truffleruby .language .RubyConstant ;
19
19
import org .truffleruby .language .RubyContextSourceNode ;
26
26
* We need a separate class for this because we need to check if the constant is defined. Doing so will evaluate the
27
27
* module part, which will be evaluated again when assigning the constant. If evaluating the module part has any
28
28
* side-effect, this is incorrect and differs from MRI semantics. */
29
- public class OrAssignConstantNode extends RubyContextSourceNode {
29
+ public abstract class OrAssignConstantNode extends RubyContextSourceNode {
30
30
31
31
@ Child protected ReadConstantNode readConstant ;
32
32
@ Child protected WriteConstantNode writeConstant ;
33
- @ Child private BooleanCastNode cast ;
34
33
35
- private final ConditionProfile triviallyUndefined = ConditionProfile .create ();
36
- private final ConditionProfile defined = ConditionProfile .create ();
37
34
private final RunTwiceBranchProfile writeTwiceProfile = new RunTwiceBranchProfile ();
38
35
39
36
public OrAssignConstantNode (ReadConstantNode readConstant , WriteConstantNode writeConstant ) {
40
37
this .readConstant = readConstant ;
41
38
this .writeConstant = writeConstant ;
42
39
}
43
40
44
- @ Override
45
- public Object execute (VirtualFrame frame ) {
46
-
47
- if (triviallyUndefined .profile (readConstant .isModuleTriviallyUndefined (frame , getLanguage (), getContext ()))) {
41
+ @ Specialization
42
+ protected Object doOrAssignConstant (VirtualFrame frame ,
43
+ @ Cached BooleanCastNode booleanCastNode ,
44
+ @ Cached InlinedConditionProfile defined ,
45
+ @ Cached InlinedConditionProfile triviallyUndefined ) {
46
+ if (triviallyUndefined .profile (this ,
47
+ readConstant .isModuleTriviallyUndefined (frame , getLanguage (), getContext ()))) {
48
48
// It might not be defined because of autoloaded constants (maybe other reasons?),
49
49
// simply attempt writing (which will trigger autoloads if required).
50
50
// Since we didn't evaluate the module part yet, no side-effects can occur.
@@ -62,31 +62,23 @@ public Object execute(VirtualFrame frame) {
62
62
// Next we check if the constant itself is defined, and if it is, we get its value.
63
63
final RubyConstant constant = readConstant .getConstantIfDefined (module );
64
64
65
- final boolean isDefined = defined .profile (constant != null );
65
+ final boolean isDefined = defined .profile (this , constant != null );
66
66
67
67
final Object value = isDefined
68
68
? readConstant .getConstant (module , constant )
69
69
: null ;
70
70
71
71
// Write if the constant is undefined or if its value is falsy.
72
- if (!isDefined || !castToBoolean ( value )) {
72
+ if (!isDefined || !booleanCastNode . execute ( this , value )) {
73
73
writeTwiceProfile .enter ();
74
74
return writeConstant .execute (frame , module );
75
75
} else {
76
76
return value ;
77
77
}
78
78
}
79
79
80
- private boolean castToBoolean (final Object value ) {
81
- if (cast == null ) {
82
- CompilerDirectives .transferToInterpreterAndInvalidate ();
83
- cast = insert (BooleanCastNodeGen .create (null ));
84
- }
85
- return cast .execute (value );
86
- }
87
-
88
80
public RubyNode cloneUninitialized () {
89
- var copy = new OrAssignConstantNode (
81
+ var copy = OrAssignConstantNodeGen . create (
90
82
(ReadConstantNode ) readConstant .cloneUninitialized (),
91
83
(WriteConstantNode ) writeConstant .cloneUninitialized ());
92
84
return copy .copyFlags (this );
0 commit comments