Skip to content

Commit d3ff03e

Browse files
committed
[GR-19220] Call divmod when coercion to Float fails for sleep (#2289)
PullRequest: truffleruby/2496
2 parents 8e19a71 + 2edfa95 commit d3ff03e

File tree

5 files changed

+25
-73
lines changed

5 files changed

+25
-73
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Compatibility:
7070
* Improved compatibility of `Signal.trap` and `Kernel#trap` (#2287, @chrisseaton).
7171
* Implemented `GC.stat(:total_allocated_objects)` as `0` (#2292, @chrisseaton).
7272
* `ObjectSpace::WeakMap` now supports immediate and frozen values as both keys and values (#2267).
73+
* Call `divmod` when coercion to `Float` fails for `#sleep` (#2289, @LillianZ).
7374

7475
Performance:
7576

spec/ruby/core/kernel/sleep_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
sleep(Rational(1, 999)).should >= 0
2323
end
2424

25+
it "accepts any Object that reponds to divmod" do
26+
o = Object.new
27+
def o.divmod(*); [0, 0.001]; end
28+
sleep(o).should >= 0
29+
end
30+
2531
it "raises an ArgumentError when passed a negative duration" do
2632
-> { sleep(-0.1) }.should raise_error(ArgumentError)
2733
-> { sleep(-1) }.should raise_error(ArgumentError)

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,22 @@
99
*/
1010
package org.truffleruby.core.cast;
1111

12+
import com.oracle.truffle.api.dsl.Cached;
1213
import org.truffleruby.language.Nil;
1314
import org.truffleruby.language.RubyContextSourceNode;
1415
import org.truffleruby.language.NotProvided;
1516
import org.truffleruby.language.RubyDynamicObject;
1617
import org.truffleruby.language.RubyNode;
1718
import org.truffleruby.language.control.RaiseException;
1819

19-
import com.oracle.truffle.api.CompilerDirectives;
2020
import com.oracle.truffle.api.dsl.NodeChild;
2121
import com.oracle.truffle.api.dsl.Specialization;
2222
import com.oracle.truffle.api.profiles.ConditionProfile;
23+
import org.truffleruby.language.dispatch.DispatchNode;
2324

2425
@NodeChild(value = "duration", type = RubyNode.class)
2526
public abstract class DurationToMillisecondsNode extends RubyContextSourceNode {
2627

27-
@Child NumericToFloatNode floatCastNode;
28-
2928
private final ConditionProfile durationLessThanZeroProfile = ConditionProfile.create();
3029
private final boolean acceptsNil;
3130

@@ -65,12 +64,14 @@ protected long durationNil(Nil duration) {
6564
}
6665

6766
@Specialization
68-
protected long duration(RubyDynamicObject duration) {
69-
if (floatCastNode == null) {
70-
CompilerDirectives.transferToInterpreterAndInvalidate();
71-
floatCastNode = insert(NumericToFloatNodeGen.create());
72-
}
73-
return duration(floatCastNode.executeDouble(duration));
67+
protected Object duration(RubyDynamicObject duration,
68+
@Cached DispatchNode durationToMilliseconds,
69+
@Cached ToLongNode toLongNode) {
70+
final Object milliseconds = durationToMilliseconds.call(
71+
coreLibrary().truffleKernelOperationsModule,
72+
"convert_duration_to_milliseconds",
73+
duration);
74+
return validate(toLongNode.execute(milliseconds));
7475
}
7576

7677
private long validate(long durationInMillis) {

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

Lines changed: 0 additions & 64 deletions
This file was deleted.

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ def self.to_enum_with_size(enum, method, size_method)
2222
enum.to_enum(method) { enum.send(size_method) }
2323
end
2424

25+
def self.convert_duration_to_milliseconds(duration)
26+
unless duration.respond_to?(:divmod)
27+
raise TypeError, "can't convert #{duration.class} into time interval"
28+
end
29+
a, b = duration.divmod(1)
30+
((a + b) * 1000)
31+
end
32+
2533
def self.define_hooked_variable(name, getter, setter, defined = proc { 'global-variable' })
2634
define_hooked_variable_with_is_defined(name, getter, setter, defined)
2735
end

0 commit comments

Comments
 (0)