Skip to content

Commit ffeea56

Browse files
committed
[GR-29744] Fix ReferenceEqualNode to never compare Boolean by identity
PullRequest: truffleruby/2469
2 parents 6e03d1f + c3c5131 commit ffeea56

19 files changed

+55
-101
lines changed

src/main/java/org/truffleruby/cext/IsNativeObjectNode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import static org.truffleruby.cext.ValueWrapperManager.isMallocAligned;
1313

14+
import com.oracle.truffle.api.dsl.Fallback;
1415
import org.truffleruby.language.RubyBaseNode;
1516

1617
import com.oracle.truffle.api.dsl.GenerateUncached;
@@ -29,7 +30,7 @@ protected boolean isNativeObjectTaggedObject(long handle) {
2930
return isMallocAligned(handle) && handle < ValueWrapperManager.ALLOCATION_BASE;
3031
}
3132

32-
@Specialization(guards = "!isLong(handle)")
33+
@Fallback
3334
protected boolean isNativeObjectFallback(Object handle) {
3435
return false;
3536
}

src/main/java/org/truffleruby/core/MathNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ protected double function(double a, NotProvided b) {
467467
return doFunction(a);
468468
}
469469

470-
@Specialization(guards = { "!isRubyBignum(a)", "!isBasicNumber(a)" })
470+
@Specialization(guards = { "!isRubyBignum(a)", "!isImplicitLongOrDouble(a)" })
471471
protected double function(Object a, NotProvided b,
472472
@Cached ToFNode toFNode) {
473473
if (!isANode.executeIsA(a, coreLibrary().numericClass)) {

src/main/java/org/truffleruby/core/array/ArrayNodes.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ protected RubyArray mulEmpty(RubyArray array, long count) {
212212
0);
213213
}
214214

215-
@Specialization(guards = { "!isInteger(count)", "!isLong(count)" })
215+
@Specialization(guards = { "!isImplicitLong(count)" })
216216
protected Object fallback(RubyArray array, Object count) {
217217
return FAILURE;
218218
}
@@ -245,7 +245,7 @@ protected Object at(RubyArray array, long index) {
245245
return nil;
246246
}
247247

248-
@Specialization(guards = "!isBasicInteger(index)")
248+
@Specialization(guards = "!isImplicitLong(index)")
249249
protected Object at(RubyArray array, Object index,
250250
@Cached ToLongNode toLongNode,
251251
@Cached FixnumLowerNode lowerNode,
@@ -284,7 +284,7 @@ protected Object indexRange(RubyArray array, RubyRange range, NotProvided length
284284
return readSlice.executeReadSlice(array, startLength[0], len);
285285
}
286286

287-
@Specialization(guards = { "!isInteger(index)", "!isRubyRange(index)" })
287+
@Specialization(guards = { "!isImplicitInteger(index)", "!isRubyRange(index)" })
288288
protected Object indexFallback(RubyArray array, Object index, NotProvided length,
289289
@Cached AtNode accessWithIndexConversion) {
290290
return accessWithIndexConversion.executeAt(array, index);
@@ -303,7 +303,7 @@ protected Object slice(RubyArray array, int start, int length,
303303
return readSliceNode.executeReadSlice(array, start, length);
304304
}
305305

306-
@Specialization(guards = { "wasProvided(length)", "!isInteger(start) || !isInteger(length)" })
306+
@Specialization(guards = { "wasProvided(length)", "!isImplicitInteger(start) || !isImplicitInteger(length)" })
307307
protected Object sliceFallback(RubyArray array, Object start, Object length,
308308
@Cached ToIntNode indexToInt,
309309
@Cached ToIntNode lengthToInt) {
@@ -359,7 +359,7 @@ protected Object setRange(RubyArray array, RubyRange range, Object value, NotPro
359359
return executeIntIndices(array, start, length, value);
360360
}
361361

362-
@Specialization(guards = { "!isInteger(start)", "!isRubyRange(start)" })
362+
@Specialization(guards = { "!isImplicitInteger(start)", "!isRubyRange(start)" })
363363
protected Object fallbackBinary(RubyArray array, Object start, Object value, NotProvided unused,
364364
@Cached ToIntNode toInt) {
365365
return executeIntIndex(array, toInt.execute(start), value, unused);
@@ -423,7 +423,8 @@ protected Object setTernary(RubyArray array, int start, int length, Object repla
423423
return replacement;
424424
}
425425

426-
@Specialization(guards = { "!isInteger(start) || !isInteger(length)", "wasProvided(replacement)" })
426+
@Specialization(
427+
guards = { "!isImplicitInteger(start) || !isImplicitInteger(length)", "wasProvided(replacement)" })
427428
protected Object fallbackTernary(RubyArray array, Object start, Object length, Object replacement,
428429
@Cached ToIntNode startToInt,
429430
@Cached ToIntNode lengthToInt) {
@@ -1133,7 +1134,7 @@ protected RubyArray initializeWithSizeAndValue(RubyArray array, int size, Object
11331134
}
11341135

11351136
@Specialization(
1136-
guards = { "wasProvided(size)", "!isInteger(size)", "!isLong(size)", "wasProvided(fillingValue)" })
1137+
guards = { "wasProvided(size)", "!isImplicitLong(size)", "wasProvided(fillingValue)" })
11371138
protected RubyArray initializeSizeOther(RubyArray array, Object size, Object fillingValue, Nil block) {
11381139
int intSize = toInt(size);
11391140
return executeInitialize(array, intSize, fillingValue, block);
@@ -1173,7 +1174,7 @@ protected RubyArray initializeFromArray(
11731174
}
11741175

11751176
@Specialization(
1176-
guards = { "!isInteger(object)", "!isLong(object)", "wasProvided(object)", "!isRubyArray(object)" })
1177+
guards = { "!isImplicitLong(object)", "wasProvided(object)", "!isRubyArray(object)" })
11771178
protected RubyArray initialize(RubyArray array, Object object, NotProvided unusedValue, Nil block) {
11781179
RubyArray copy = null;
11791180
if (respondToToAry(getLanguage(), object)) {
@@ -1608,7 +1609,7 @@ protected RubyArray popNotEmptyUnsharedStorage(RubyArray array, int n,
16081609
return createArray(popped, numPop);
16091610
}
16101611

1611-
@Specialization(guards = { "wasProvided(n)", "!isInteger(n)", "!isLong(n)" })
1612+
@Specialization(guards = { "wasProvided(n)", "!isImplicitInteger(n)" })
16121613
protected Object popNToInt(RubyArray array, Object n,
16131614
@Cached ToIntNode toIntNode) {
16141615
return executePop(array, toIntNode.execute(n));
@@ -2038,7 +2039,7 @@ protected Object shiftMany(RubyArray array, int n,
20382039
return createArray(result, numShift);
20392040
}
20402041

2041-
@Specialization(guards = { "wasProvided(n)", "!isInteger(n)", "!isLong(n)" })
2042+
@Specialization(guards = { "wasProvided(n)", "!isImplicitInteger(n)" })
20422043
protected Object shiftNToInt(RubyArray array, Object n,
20432044
@Cached ToIntNode toIntNode) {
20442045
return executeShift(array, toIntNode.execute(n));

src/main/java/org/truffleruby/core/basicobject/BasicObjectNodes.java

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import com.oracle.truffle.api.RootCallTarget;
1313
import com.oracle.truffle.api.dsl.CachedLanguage;
14+
import com.oracle.truffle.api.dsl.Fallback;
1415
import com.oracle.truffle.api.object.Shape;
1516
import org.truffleruby.Layouts;
1617
import org.truffleruby.RubyContext;
@@ -113,6 +114,9 @@ protected boolean equal(VirtualFrame frame, Object a, Object b) {
113114

114115
}
115116

117+
/** This node is not trivial because primitives must be compared by value and never by identity. Also, this node
118+
* must consider (byte) n and (short) n and (int) n and (long) n equal, as well as (float) n and (double) n. So even
119+
* if a and b have different classes they might still be equal if they are primitives. */
116120
@CoreMethod(names = { "equal?", "==" }, required = 1)
117121
public abstract static class ReferenceEqualNode extends CoreMethodArrayArgumentsNode {
118122

@@ -142,57 +146,16 @@ protected boolean equal(double a, double b) {
142146
return Double.doubleToRawLongBits(a) == Double.doubleToRawLongBits(b);
143147
}
144148

145-
@Specialization
146-
protected boolean equal(RubyDynamicObject a, RubyDynamicObject b) {
149+
@Specialization(guards = { "a.getClass() == b.getClass()", "!isPrimitive(a)" }) // since a and b have the same class, implies !isPrimitive(b)
150+
protected boolean equalSameClassNonPrimitive(Object a, Object b) {
147151
return a == b;
148152
}
149153

150-
@Specialization(
151-
guards = {
152-
"isNotRubyDynamicObject(a)",
153-
"isNotRubyDynamicObject(b)",
154-
"!sameClass(a, b)",
155-
"isNotIntLong(a) || isNotIntLong(b)" })
156-
protected boolean equalIncompatiblePrimitiveTypes(Object a, Object b) {
157-
return false;
158-
}
159-
160-
@Specialization(
161-
guards = {
162-
"isNotRubyDynamicObject(a)",
163-
"isNotRubyDynamicObject(b)",
164-
"sameClass(a, b)",
165-
"isNotIntLongDouble(a) || isNotIntLongDouble(b)" })
166-
protected boolean equalOtherSameClass(Object a, Object b) {
167-
return a == b;
168-
}
169-
170-
@Specialization(guards = "isNotRubyDynamicObject(a)")
171-
protected boolean equal(Object a, RubyDynamicObject b) {
172-
return false;
173-
}
174-
175-
@Specialization(guards = "isNotRubyDynamicObject(b)")
176-
protected boolean equal(RubyDynamicObject a, Object b) {
154+
@Fallback
155+
protected boolean fallback(Object a, Object b) {
177156
return false;
178157
}
179158

180-
protected boolean isNotRubyDynamicObject(Object value) {
181-
return !(value instanceof RubyDynamicObject);
182-
}
183-
184-
protected boolean sameClass(Object a, Object b) {
185-
return a.getClass() == b.getClass();
186-
}
187-
188-
protected boolean isNotIntLong(Object v) {
189-
return !(v instanceof Integer) && !(v instanceof Long);
190-
}
191-
192-
protected boolean isNotIntLongDouble(Object v) {
193-
return !(v instanceof Integer) && !(v instanceof Long) && !(v instanceof Double);
194-
}
195-
196159
}
197160

198161
@GenerateUncached

src/main/java/org/truffleruby/core/cast/IntegerCastNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ protected int doLongToBig(long value,
5050
context.getCoreExceptions().rangeError("long too big to convert into `int'", this));
5151
}
5252

53-
@Specialization(guards = "!isBasicInteger(value)")
53+
@Specialization(guards = "!isImplicitLong(value)")
5454
protected int doBasicObject(Object value,
5555
@CachedContext(RubyLanguage.class) RubyContext context) {
5656
throw new RaiseException(

src/main/java/org/truffleruby/core/cast/LongCastNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ protected long doLong(long value) {
4343
}
4444

4545
@TruffleBoundary
46-
@Specialization(guards = "!isBasicInteger(value)")
46+
@Specialization(guards = "!isImplicitLong(value)")
4747
protected long doBasicObject(Object value,
4848
@CachedContext(RubyLanguage.class) RubyContext context) {
4949
throw new RaiseException(

src/main/java/org/truffleruby/core/cast/ToFNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ protected double coerceRubyBignum(RubyBignum value) {
5151
return BigIntegerOps.doubleValue(value);
5252
}
5353

54-
@Specialization(guards = { "!isRubyBignum(object)", "!isBasicNumber(object)" })
54+
@Specialization(guards = { "!isRubyBignum(object)", "!isImplicitLongOrDouble(object)" })
5555
protected double coerceObject(Object object,
5656
@Cached BranchProfile errorProfile) {
5757
if (toFNode == null) {

src/main/java/org/truffleruby/core/cast/ToIntNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ protected long coerceNil(Nil value) {
107107
coreExceptions().typeError("no implicit conversion from nil to integer", this));
108108
}
109109

110-
@Specialization(guards = { "!isRubyInteger(object)", "!isDouble(object)", "!isNil(object)" })
110+
@Specialization(guards = { "!isRubyInteger(object)", "!isImplicitDouble(object)", "!isNil(object)" })
111111
protected int coerceObject(Object object,
112112
@Cached DispatchNode toIntNode,
113113
@Cached ToIntNode fitNode) {

src/main/java/org/truffleruby/core/cast/ToLongNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ protected long coerceNil(Nil nil) {
7777
coreExceptions().typeError("no implicit conversion from nil to integer", this));
7878
}
7979

80-
@Specialization(guards = { "!isRubyInteger(object)", "!isDouble(object)", "!isNil(object)" })
80+
@Specialization(guards = { "!isRubyInteger(object)", "!isImplicitDouble(object)", "!isNil(object)" })
8181
protected long coerceObject(Object object,
8282
@Cached DispatchNode toIntNode,
8383
@Cached ToLongNode fitNode) {

src/main/java/org/truffleruby/core/format/format/FormatFloatHumanReadableNode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@
2020
public abstract class FormatFloatHumanReadableNode extends FormatNode {
2121

2222
@TruffleBoundary
23-
@Specialization(guards = "isInteger(value)")
23+
@Specialization(guards = "isIntegerValue(value)")
2424
protected byte[] formatInteger(double value) {
2525
return RopeOperations.encodeAsciiBytes(String.valueOf((long) value));
2626
}
2727

2828
@TruffleBoundary
29-
@Specialization(guards = "!isInteger(value)")
29+
@Specialization(guards = "!isIntegerValue(value)")
3030
protected byte[] format(double value) {
3131
return RopeOperations.encodeAsciiBytes(String.valueOf(value));
3232
}
3333

34-
protected boolean isInteger(double value) {
34+
protected boolean isIntegerValue(double value) {
3535
/** General approach taken from StackOverflow:
3636
* http://stackoverflow.com/questions/703396/how-to-nicely-format-floating-numbers-to-string-without-unnecessary
3737
* -decimal-0 Answers provided by JasonD (http://stackoverflow.com/users/1288598/jasond) and Darthenius

0 commit comments

Comments
 (0)