Skip to content

Commit a164296

Browse files
committed
Refactor ProfileArgumentNode
1 parent 54e9635 commit a164296

File tree

1 file changed

+60
-37
lines changed

1 file changed

+60
-37
lines changed

src/main/java/org/truffleruby/language/arguments/ProfileArgumentNode.java

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010
package org.truffleruby.language.arguments;
1111

12+
import com.oracle.truffle.api.dsl.Idempotent;
1213
import com.oracle.truffle.api.dsl.ImportStatic;
1314
import com.oracle.truffle.api.dsl.NeverDefault;
1415
import org.truffleruby.language.NoImplicitCastsToLong;
@@ -18,6 +19,7 @@
1819

1920
import com.oracle.truffle.api.CompilerDirectives;
2021
import com.oracle.truffle.api.dsl.Cached;
22+
import com.oracle.truffle.api.dsl.Cached.Shared;
2123
import com.oracle.truffle.api.dsl.NodeChild;
2224
import com.oracle.truffle.api.dsl.Specialization;
2325
import com.oracle.truffle.api.dsl.TypeSystemReference;
@@ -34,68 +36,89 @@ public abstract class ProfileArgumentNode extends RubyContextSourceNode {
3436

3537
protected abstract RubyNode getChildNode();
3638

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;
4143
}
4244

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;
4749
}
4850

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;
5355
}
5456

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;
5961
}
6062

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);
6667
// The cast is only useful for the compiler.
6768
if (CompilerDirectives.inInterpreter()) {
68-
return object;
69+
return value;
6970
} else {
70-
return CompilerDirectives.castExact(object, cachedClass);
71+
return CompilerDirectives.castExact(value, (Class<?>) cachedValue);
7172
}
7273
}
7374

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;
8379
}
8480

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. */
8583
@NeverDefault
86-
protected static Class<?> getClassOrObject(Object value) {
84+
static Object createCachedValue(Object value) {
85+
if (RubyGuards.isPrimitive(value)) {
86+
return value;
87+
}
88+
8789
return value == null ? Objects.class : value.getClass();
8890
}
8991

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);
93117
}
94118

95119
@Override
96120
public RubyNode cloneUninitialized() {
97121
var copy = ProfileArgumentNodeGen.create(getChildNode().cloneUninitialized());
98122
return copy.copyFlags(this);
99123
}
100-
101124
}

0 commit comments

Comments
 (0)