9
9
*/
10
10
package org .truffleruby .language .arguments ;
11
11
12
+ import com .oracle .truffle .api .dsl .Idempotent ;
12
13
import com .oracle .truffle .api .dsl .ImportStatic ;
13
14
import com .oracle .truffle .api .dsl .NeverDefault ;
14
15
import org .truffleruby .language .NoImplicitCastsToLong ;
18
19
19
20
import com .oracle .truffle .api .CompilerDirectives ;
20
21
import com .oracle .truffle .api .dsl .Cached ;
22
+ import com .oracle .truffle .api .dsl .Cached .Shared ;
21
23
import com .oracle .truffle .api .dsl .NodeChild ;
22
24
import com .oracle .truffle .api .dsl .Specialization ;
23
25
import com .oracle .truffle .api .dsl .TypeSystemReference ;
@@ -34,68 +36,89 @@ public abstract class ProfileArgumentNode extends RubyContextSourceNode {
34
36
35
37
protected abstract RubyNode getChildNode ();
36
38
37
- @ Specialization (guards = "value == cachedValue" , limit = "1 " )
38
- boolean cacheBoolean (boolean value ,
39
- @ Cached ("value" ) boolean cachedValue ) {
40
- return cachedValue ;
39
+ @ Specialization (guards = "guardBoolean( value, cachedValue) " )
40
+ boolean doBoolean (boolean value ,
41
+ @ Cached ("createCachedValue( value) " ) @ Shared Object cachedValue ) {
42
+ return ( boolean ) cachedValue ;
41
43
}
42
44
43
- @ Specialization (guards = "value == cachedValue" , limit = "1 " )
44
- int cacheInt (int value ,
45
- @ Cached ("value" ) int cachedValue ) {
46
- return cachedValue ;
45
+ @ Specialization (guards = "guardInt( value, cachedValue) " )
46
+ int doInt (int value ,
47
+ @ Cached ("createCachedValue( value) " ) @ Shared Object cachedValue ) {
48
+ return ( int ) cachedValue ;
47
49
}
48
50
49
- @ Specialization (guards = "value == cachedValue" , limit = "1 " )
50
- long cacheLong (long value ,
51
- @ Cached ("value" ) long cachedValue ) {
52
- return cachedValue ;
51
+ @ Specialization (guards = "guardLong( value, cachedValue) " )
52
+ long doLong (long value ,
53
+ @ Cached ("createCachedValue( value) " ) @ Shared Object cachedValue ) {
54
+ return ( long ) cachedValue ;
53
55
}
54
56
55
- @ Specialization (guards = "exactCompare (value, cachedValue)" , limit = "1 " )
56
- double cacheDouble (double value ,
57
- @ Cached ("value" ) double cachedValue ) {
58
- return cachedValue ;
57
+ @ Specialization (guards = "guardDouble (value, cachedValue)" )
58
+ double doDouble (double value ,
59
+ @ Cached ("createCachedValue( value) " ) @ Shared Object cachedValue ) {
60
+ return ( double ) cachedValue ;
59
61
}
60
62
61
- @ Specialization (
62
- guards = { "isExact(object, cachedClass)" , "!isPrimitiveClass(cachedClass)" },
63
- limit = "1" )
64
- Object cacheClass (Object object ,
65
- @ Cached ("getClassOrObject(object)" ) Class <?> cachedClass ) {
63
+ @ Specialization (guards = { "guardClass(value, cachedValue)" , "!isPrimitiveClass(cachedValue)" })
64
+ Object doClass (Object value ,
65
+ @ Cached ("createCachedValue(value)" ) @ Shared Object cachedValue ) {
66
+ assert RubyGuards .assertIsValidRubyValue (value );
66
67
// The cast is only useful for the compiler.
67
68
if (CompilerDirectives .inInterpreter ()) {
68
- return object ;
69
+ return value ;
69
70
} else {
70
- return CompilerDirectives .castExact (object , cachedClass );
71
+ return CompilerDirectives .castExact (value , ( Class <?>) cachedValue );
71
72
}
72
73
}
73
74
74
- @ Specialization (replaces = { "cacheBoolean" , "cacheInt" , "cacheLong" , "cacheDouble" , "cacheClass" })
75
- Object unprofiled (Object object ) {
76
- assert RubyGuards .assertIsValidRubyValue (object );
77
- return object ;
78
- }
79
-
80
- protected static boolean exactCompare (double a , double b ) {
81
- // -0.0 == 0.0, but you can tell the difference through other means, so we need to differentiate.
82
- return Double .doubleToRawLongBits (a ) == Double .doubleToRawLongBits (b );
75
+ @ Specialization (replaces = { "doBoolean" , "doInt" , "doLong" , "doDouble" , "doClass" })
76
+ Object doGeneric (Object value ) {
77
+ assert RubyGuards .assertIsValidRubyValue (value );
78
+ return value ;
83
79
}
84
80
81
+ /** The reason this method is used for all cached arguments is that Truffle DSL forces us to use same cache
82
+ * initializer for all @Shared arguments. Otherwise, it throws an error. */
85
83
@ NeverDefault
86
- protected static Class <?> getClassOrObject (Object value ) {
84
+ static Object createCachedValue (Object value ) {
85
+ if (RubyGuards .isPrimitive (value )) {
86
+ return value ;
87
+ }
88
+
87
89
return value == null ? Objects .class : value .getClass ();
88
90
}
89
91
90
- @ Override
91
- public String toString () {
92
- return "Profiled(" + getChildNode () + ")" ;
92
+ static boolean guardBoolean (boolean value , Object cachedValue ) {
93
+ return cachedValue instanceof Boolean cachedBoolean && value == cachedBoolean ;
94
+ }
95
+
96
+ static boolean guardInt (int value , Object cachedValue ) {
97
+ return cachedValue instanceof Integer cachedInt && value == cachedInt ;
98
+ }
99
+
100
+ static boolean guardLong (long value , Object cachedValue ) {
101
+ return cachedValue instanceof Long cachedLong && value == cachedLong ;
102
+ }
103
+
104
+ static boolean guardDouble (double value , Object cachedValue ) {
105
+ return cachedValue instanceof Double cachedDouble &&
106
+ // -0.0 == 0.0, but you can tell the difference through other means, so we need to differentiate.
107
+ Double .doubleToRawLongBits (value ) == Double .doubleToRawLongBits (cachedDouble );
108
+ }
109
+
110
+ static boolean guardClass (Object value , Object cachedValue ) {
111
+ return cachedValue instanceof Class <?> cachedClass && CompilerDirectives .isExact (value , cachedClass );
112
+ }
113
+
114
+ @ Idempotent
115
+ static boolean isPrimitiveClass (Object cachedValue ) {
116
+ return RubyGuards .isPrimitiveClass ((Class <?>) cachedValue );
93
117
}
94
118
95
119
@ Override
96
120
public RubyNode cloneUninitialized () {
97
121
var copy = ProfileArgumentNodeGen .create (getChildNode ().cloneUninitialized ());
98
122
return copy .copyFlags (this );
99
123
}
100
-
101
124
}
0 commit comments