Skip to content

Commit 6e7cd1e

Browse files
committed
Move ForeignObject#{equal?,eql?} to BasicObject's ReferenceEqualNode node
* So it is also correct if the nodes are used directly, and better integrated with Ruby objects. * It also means #== is properly defined on foreign objects now.
1 parent 7823558 commit 6e7cd1e

File tree

5 files changed

+42
-17
lines changed

5 files changed

+42
-17
lines changed

spec/truffle/interop/fixtures/classes.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@
1111
module TruffleInteropSpecs
1212

1313
class Logger
14-
attr_reader :log
15-
1614
def initialize
1715
@log = []
1816
end
1917

2018
def <<(*args)
21-
@log << args
19+
@log << args unless @log.frozen?
20+
end
21+
22+
def log
23+
# Stop recording so messages caused by spec expectations are not included
24+
@log.freeze
2225
end
2326
end
2427

spec/truffle/interop/special_forms_spec.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@
287287
pfo.equal?(pfo).should == true
288288
l.log.should include(["isIdentical", pfo, :InteropLibrary])
289289

290+
pfo, _, l = proxy[Object.new]
290291
other = Object.new
291292
pfo.equal?(other).should == false
292293
l.log.should include(["isIdentical", other, :InteropLibrary])
@@ -297,6 +298,7 @@
297298
pfo.eql?(pfo).should == true
298299
l.log.should include(["isIdentical", pfo, :InteropLibrary])
299300

301+
pfo, _, l = proxy[Object.new]
300302
other = Object.new
301303
pfo.eql?(other).should == false
302304
l.log.should include(["isIdentical", other, :InteropLibrary])
@@ -312,7 +314,7 @@
312314
it doc['.object_id', 'uses `System.identityHashCode()` otherwise (which might not be unique)'] do
313315
pfo, _, l = proxy[42] # primitives have no identity in InteropLibrary
314316
pfo.object_id.should be_kind_of(Integer)
315-
l.log.should include(["isIdentical", pfo, :InteropLibrary]) # hasIdentity()
317+
l.log.should include(["isIdenticalOrUndefined", 42]) # hasIdentity()
316318
l.log.should_not include(["identityHashCode"])
317319
end
318320

@@ -326,7 +328,7 @@
326328
it doc['.__id__', 'uses `System.identityHashCode()` otherwise (which might not be unique)'] do
327329
pfo, _, l = proxy[42] # primitives have no identity in InteropLibrary
328330
pfo.__id__.should be_kind_of(Integer)
329-
l.log.should include(["isIdentical", pfo, :InteropLibrary]) # hasIdentity()
331+
l.log.should include(["isIdenticalOrUndefined", 42]) # hasIdentity()
330332
l.log.should_not include(["identityHashCode"])
331333
end
332334

@@ -340,7 +342,7 @@
340342
it doc['.hash', 'uses `System.identityHashCode()` otherwise (which might not be unique)'] do
341343
pfo, _, l = proxy[42] # primitives have no identity in InteropLibrary
342344
pfo.hash.should be_kind_of(Integer)
343-
l.log.should include(["isIdentical", pfo, :InteropLibrary]) # hasIdentity()
345+
l.log.should include(["isIdenticalOrUndefined", 42]) # hasIdentity()
344346
l.log.should_not include(["identityHashCode"])
345347
end
346348

src/main/.checkstyle_checks.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@
212212
</module>
213213
<module name="RegexpSinglelineJava">
214214
<property name="format" value='"isRuby(?!Value|DynamicObject|SymbolOrString|Rational|[^"]+\|\|)'/> <!-- Rational is not a builtin type -->
215-
<property name="message" value="Type the argument instead of using a positive is Ruby* guard."/>
215+
<property name="message" value="Type the argument instead of using a positive isRuby* guard."/>
216216
</module>
217217
<module name="RegexpSinglelineJava">
218218
<property name="format" value='"isNil'/>

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

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
package org.truffleruby.core.basicobject;
1111

1212
import com.oracle.truffle.api.RootCallTarget;
13-
import com.oracle.truffle.api.dsl.Fallback;
1413
import com.oracle.truffle.api.interop.InteropLibrary;
1514
import com.oracle.truffle.api.interop.UnsupportedMessageException;
1615
import com.oracle.truffle.api.object.Shape;
@@ -152,16 +151,42 @@ protected boolean equal(double a, double b) {
152151
return Double.doubleToRawLongBits(a) == Double.doubleToRawLongBits(b);
153152
}
154153

155-
@Specialization(guards = { "a.getClass() == b.getClass()", "!isPrimitive(a)" }) // since a and b have the same class, implies !isPrimitive(b)
156-
protected boolean equalSameClassNonPrimitive(Object a, Object b) {
154+
@Specialization(guards = { "isNonPrimitiveRubyObject(a)", "isNonPrimitiveRubyObject(b)" })
155+
protected boolean equalRubyObjects(Object a, Object b) {
157156
return a == b;
158157
}
159158

160-
@Fallback
161-
protected boolean fallback(Object a, Object b) {
159+
@Specialization(guards = { "isNonPrimitiveRubyObject(a)", "isPrimitive(b)" })
160+
protected boolean rubyObjectPrimitive(Object a, Object b) {
162161
return false;
163162
}
164163

164+
@Specialization(guards = { "isPrimitive(a)", "isNonPrimitiveRubyObject(b)" })
165+
protected boolean primitiveRubyObject(Object a, Object b) {
166+
return false;
167+
}
168+
169+
@Specialization(guards = { "isPrimitive(a)", "isPrimitive(b)", "!comparablePrimitives(a, b)" })
170+
protected boolean nonComparablePrimitives(Object a, Object b) {
171+
return false;
172+
}
173+
174+
@Specialization(guards = "isForeignObject(a) || isForeignObject(b)", limit = "getInteropCacheLimit()")
175+
protected boolean equalForeign(Object a, Object b,
176+
@CachedLibrary("a") InteropLibrary lhsInterop,
177+
@CachedLibrary("b") InteropLibrary rhsInterop) {
178+
return lhsInterop.isIdentical(a, b, rhsInterop);
179+
}
180+
181+
protected static boolean isNonPrimitiveRubyObject(Object object) {
182+
return object instanceof RubyDynamicObject || object instanceof ImmutableRubyObject;
183+
}
184+
185+
protected static boolean comparablePrimitives(Object a, Object b) {
186+
return (a instanceof Boolean && b instanceof Boolean) ||
187+
(RubyGuards.isImplicitLong(a) && RubyGuards.isImplicitLong(b)) ||
188+
(RubyGuards.isImplicitDouble(a) && RubyGuards.isImplicitDouble(b));
189+
}
165190
}
166191

167192
@GenerateUncached

src/main/ruby/truffleruby/core/truffle/polyglot.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,6 @@ def class
231231
end
232232
end
233233

234-
def equal?(other_object)
235-
Truffle::Interop.identical?(self, other_object)
236-
end
237-
alias_method :eql?, :equal?
238-
239234
def inspect
240235
recursive_string_for(self) if Truffle::ThreadOperations.detect_recursion self do
241236
return Truffle::InteropOperations.foreign_inspect_nonrecursive(self)

0 commit comments

Comments
 (0)