Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 940aefcaa9aa
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 48b70554cd1c
Choose a head ref

Commits on Jan 18, 2015

  1. [Truffle] Float#abs

    chrisseaton committed Jan 18, 2015
    Copy the full SHA
    cc5fa69 View commit details
  2. [Truffle] Float#angle

    chrisseaton committed Jan 18, 2015
    Copy the full SHA
    291fb2d View commit details
  3. [Truffle] Float#arg

    chrisseaton committed Jan 18, 2015
    Copy the full SHA
    de2b4bc View commit details

Commits on Jan 22, 2015

  1. Merge branch 'master' into truffle-float

    Conflicts:
    	truffle/src/main/java/org/jruby/truffle/nodes/core/BasicObjectNodes.java
    	truffle/src/main/java/org/jruby/truffle/nodes/rubinius/RubiniusPrimitiveManager.java
    chrisseaton committed Jan 22, 2015
    Copy the full SHA
    230f019 View commit details

Commits on Jan 24, 2015

  1. Copy the full SHA
    10839a9 View commit details
  2. [Truffle] Float#ceil

    chrisseaton committed Jan 24, 2015
    Copy the full SHA
    81d2e88 View commit details
  3. Copy the full SHA
    888e340 View commit details
  4. [Truffle] Float#coerce

    chrisseaton committed Jan 24, 2015
    Copy the full SHA
    aff913f View commit details

Commits on Jan 25, 2015

  1. Copy the full SHA
    0ef0dd8 View commit details
  2. Copy the full SHA
    44b096b View commit details
  3. Copy the full SHA
    ad57df6 View commit details
  4. [Truffle] Float#/

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    76efcfd View commit details
  5. [Truffle] Float#divmod

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    0aabb79 View commit details
  6. [Truffle] Float#eql?

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    d3275fe View commit details
  7. [Truffle] Float#**

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    b8279ab View commit details
  8. [Truffle] Float#fdiv

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    84b1be2 View commit details
  9. [Truffle] Float#finite?

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    813ee83 View commit details
  10. [Truffle] Float#floor

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    a942818 View commit details
  11. Copy the full SHA
    e65f582 View commit details
  12. [Truffle] Float#hash

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    df24eed View commit details
  13. [Truffle] Float#infinite?

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    91b0116 View commit details
  14. [Truffle] Float#magnitude

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    b49b781 View commit details
  15. [Truffle] Float#-

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    02ae386 View commit details
  16. [Truffle] Float#modulo

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    a93f985 View commit details
  17. [Truffle] Float#*

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    783b25a View commit details
  18. [Truffle] Float#nan?

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    2368841 View commit details
  19. [Truffle] Float#numerator

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    aba3097 View commit details
  20. [Truffle] Float#phase

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    523d0ff View commit details
  21. [Truffle] Float#+

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    27151b8 View commit details
  22. [Truffle] Float#quo

    chrisseaton committed Jan 25, 2015
    Copy the full SHA
    55579b3 View commit details
  23. Copy the full SHA
    4e64c1b View commit details
  24. Copy the full SHA
    48b7055 View commit details
Showing with 458 additions and 206 deletions.
  1. +40 −5 core/src/main/ruby/jruby/truffle/core/float.rb
  2. +56 −0 core/src/main/ruby/jruby/truffle/core/rubinius/kernel/common/float.rb
  3. +8 −0 core/src/main/ruby/jruby/truffle/core/rubinius/kernel/common/numeric.rb
  4. +0 −4 spec/truffle/tags/core/float/abs_tags.txt
  5. +0 −8 spec/truffle/tags/core/float/angle_tags.txt
  6. +0 −8 spec/truffle/tags/core/float/arg_tags.txt
  7. +0 −1 spec/truffle/tags/core/float/ceil_tags.txt
  8. +0 −1 spec/truffle/tags/core/float/coerce_tags.txt
  9. +0 −7 spec/truffle/tags/core/float/comparison_tags.txt
  10. +0 −13 spec/truffle/tags/core/float/constants_tags.txt
  11. +0 −3 spec/truffle/tags/core/float/denominator_tags.txt
  12. +0 −6 spec/truffle/tags/core/float/divide_tags.txt
  13. +0 −6 spec/truffle/tags/core/float/divmod_tags.txt
  14. +0 −3 spec/truffle/tags/core/float/eql_tags.txt
  15. +0 −2 spec/truffle/tags/core/float/exponent_tags.txt
  16. +0 −14 spec/truffle/tags/core/float/fdiv_tags.txt
  17. +0 −4 spec/truffle/tags/core/float/finite_tags.txt
  18. +0 −1 spec/truffle/tags/core/float/float_tags.txt
  19. +0 −1 spec/truffle/tags/core/float/floor_tags.txt
  20. +0 −2 spec/truffle/tags/core/float/hash_tags.txt
  21. +0 −4 spec/truffle/tags/core/float/infinite_tags.txt
  22. +0 −4 spec/truffle/tags/core/float/magnitude_tags.txt
  23. +0 −1 spec/truffle/tags/core/float/minus_tags.txt
  24. +0 −14 spec/truffle/tags/core/float/modulo_tags.txt
  25. +0 −2 spec/truffle/tags/core/float/multiply_tags.txt
  26. +0 −1 spec/truffle/tags/core/float/nan_tags.txt
  27. +0 −5 spec/truffle/tags/core/float/numerator_tags.txt
  28. +0 −8 spec/truffle/tags/core/float/phase_tags.txt
  29. +0 −1 spec/truffle/tags/core/float/plus_tags.txt
  30. +0 −14 spec/truffle/tags/core/float/quo_tags.txt
  31. +0 −3 spec/truffle/tags/core/float/rationalize_tags.txt
  32. +0 −2 spec/truffle/tags/core/float/round_tags.txt
  33. +0 −1 spec/truffle/tags/core/float/to_r_tags.txt
  34. +0 −2 spec/truffle/tags/core/float/to_s_tags.txt
  35. +0 −5 spec/truffle/tags/core/float/uminus_tags.txt
  36. +0 −1 spec/truffle/tags/core/float/uplus_tags.txt
  37. +0 −1 spec/truffle/tags/core/float/zero_tags.txt
  38. +8 −0 truffle/src/main/java/org/jruby/truffle/nodes/RubyNode.java
  39. +123 −2 truffle/src/main/java/org/jruby/truffle/nodes/core/BasicObjectNodes.java
  40. +30 −1 truffle/src/main/java/org/jruby/truffle/nodes/core/BignumNodes.java
  41. +13 −0 truffle/src/main/java/org/jruby/truffle/nodes/core/FixnumNodes.java
  42. +94 −27 truffle/src/main/java/org/jruby/truffle/nodes/core/FloatNodes.java
  43. +21 −3 truffle/src/main/java/org/jruby/truffle/nodes/core/GeneralDivModNode.java
  44. +18 −11 truffle/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
  45. +40 −0 truffle/src/main/java/org/jruby/truffle/nodes/rubinius/FloatPrimitiveNodes.java
  46. +1 −0 truffle/src/main/java/org/jruby/truffle/nodes/rubinius/RubiniusPrimitiveManager.java
  47. +3 −2 truffle/src/main/java/org/jruby/truffle/nodes/rubinius/StringPrimitiveNodes.java
  48. +3 −2 truffle/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
45 changes: 40 additions & 5 deletions core/src/main/ruby/jruby/truffle/core/float.rb
Original file line number Diff line number Diff line change
@@ -6,14 +6,40 @@
# GNU General Public License version 2
# GNU Lesser General Public License version 2.1

# Copyright (c) 2007-2014, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

class Float

NAN = 0.0 / 0.0
INFINITY = 1.0 / 0.0
EPSILON = 2.2204460492503131e-16
RADIX = 2
ROUNDS = 1
MIN = 2.2250738585072014e-308
MIN = 4.9E-324
MAX = 1.7976931348623157e+308
MIN_EXP = -1021
MAX_EXP = 1024
@@ -22,10 +48,6 @@ class Float
DIG = 15
MANT_DIG = 53

def negative?
self < 0
end

# for Float ** Rational we would normally do Rational.convert(a) ** b, but
# this ends up being recursive using Rubinius' code, so we use this helper
# instead.
@@ -36,4 +58,17 @@ def pow_rational(rational)

private :pow_rational

def equal_fallback(other)
# Fallback from Rubinius' Float#==, after the primitive call

begin
b, a = math_coerce(other)
return a == b
rescue TypeError
return other == self
end
end

private :equal_fallback

end
Original file line number Diff line number Diff line change
@@ -41,4 +41,60 @@ def to_r
(f * (RADIX ** e)).to_r
end

def arg
if nan?
self
elsif negative?
Math::PI
else
0
end
end
alias_method :angle, :arg
alias_method :phase, :arg

def negative?
Rubinius.primitive :float_negative
raise PrimitiveFailure, "Float#negative primitive failed"
end

def numerator
if nan?
NAN
elsif infinite? == 1
INFINITY
elsif infinite? == -1
-INFINITY
else
super
end
end

def denominator
if infinite? || nan?
1
else
super
end
end

alias_method :quo, :/
alias_method :modulo, :%

def finite?
not (nan? or infinite?)
end

def rationalize(eps=undefined)
if undefined.equal?(eps)
f, n = Math.frexp self
f = Math.ldexp(f, Float::MANT_DIG).to_i
n -= Float::MANT_DIG

Rational.new(2 * f, 1 << (1 - n)).rationalize(Rational.new(1, 1 << (1 - n)))
else
to_r.rationalize(eps)
end
end

end
Original file line number Diff line number Diff line change
@@ -112,4 +112,12 @@ def real?
true
end

def numerator
to_r.numerator
end

def denominator
to_r.denominator
end

end
4 changes: 0 additions & 4 deletions spec/truffle/tags/core/float/abs_tags.txt

This file was deleted.

8 changes: 0 additions & 8 deletions spec/truffle/tags/core/float/angle_tags.txt

This file was deleted.

8 changes: 0 additions & 8 deletions spec/truffle/tags/core/float/arg_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/float/ceil_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/float/coerce_tags.txt

This file was deleted.

7 changes: 0 additions & 7 deletions spec/truffle/tags/core/float/comparison_tags.txt

This file was deleted.

13 changes: 0 additions & 13 deletions spec/truffle/tags/core/float/constants_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions spec/truffle/tags/core/float/denominator_tags.txt

This file was deleted.

6 changes: 0 additions & 6 deletions spec/truffle/tags/core/float/divide_tags.txt

This file was deleted.

6 changes: 0 additions & 6 deletions spec/truffle/tags/core/float/divmod_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions spec/truffle/tags/core/float/eql_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/float/exponent_tags.txt

This file was deleted.

14 changes: 0 additions & 14 deletions spec/truffle/tags/core/float/fdiv_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/core/float/finite_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/float/float_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/float/floor_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/float/hash_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/core/float/infinite_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/core/float/magnitude_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/float/minus_tags.txt

This file was deleted.

14 changes: 0 additions & 14 deletions spec/truffle/tags/core/float/modulo_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/float/multiply_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/float/nan_tags.txt

This file was deleted.

5 changes: 0 additions & 5 deletions spec/truffle/tags/core/float/numerator_tags.txt

This file was deleted.

8 changes: 0 additions & 8 deletions spec/truffle/tags/core/float/phase_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/float/plus_tags.txt

This file was deleted.

14 changes: 0 additions & 14 deletions spec/truffle/tags/core/float/quo_tags.txt

This file was deleted.

3 changes: 0 additions & 3 deletions spec/truffle/tags/core/float/rationalize_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
fails:Float#rationalize returns self as a simplified Rational with no argument
fails:Float#rationalize simplifies self to the degree specified by a Rational argument
fails:Float#rationalize simplifies self to the degree specified by a Float argument
fails:Float#rationalize raises a FloatDomainError for Infinity
fails:Float#rationalize raises a FloatDomainError for NaN
fails:Float#rationalize raises ArgumentError when passed more than one argument
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/float/round_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
fails:Float#round returns the nearest Integer
fails:Float#round raises FloatDomainError for exceptional values
fails:Float#round rounds self to an optionally given precision
fails:Float#round returns zero when passed a negative argument with magitude greater the magitude of the whole number portion of the Float
fails:Float#round raises a TypeError when its argument can not be converted to an Integer
1 change: 0 additions & 1 deletion spec/truffle/tags/core/float/to_r_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/float/to_s_tags.txt
Original file line number Diff line number Diff line change
@@ -11,5 +11,3 @@ fails:Float#to_s uses e format for a positive value with whole part having 18 si
fails:Float#to_s uses e format for a negative value with whole part having 18 significant figures
fails:Float#to_s uses non-e format for a positive value with whole part having 17 significant figures
fails:Float#to_s uses non-e format for a negative value with whole part having 17 significant figures
fails:Float#to_s returns a String in US-ASCII encoding when Encoding.default_internal is nil
fails:Float#to_s returns a String in US-ASCII encoding when Encoding.default_internal is not nil
5 changes: 0 additions & 5 deletions spec/truffle/tags/core/float/uminus_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/float/uplus_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/float/zero_tags.txt

This file was deleted.

8 changes: 8 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/nodes/RubyNode.java
Original file line number Diff line number Diff line change
@@ -272,6 +272,14 @@ public boolean isRational(RubyBasicObject o) {
return o.getLogicalClass() == getContext().getCoreLibrary().getRationalClass();
}

public boolean isNaN(double value) {
return Double.isNaN(value);
}

public boolean isInfinity(double value) {
return Double.isInfinite(value);
}

// Copied from RubyTypesGen

@SuppressWarnings("static-method")
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
import org.jruby.truffle.nodes.cast.BooleanCastNodeFactory;
import org.jruby.truffle.nodes.dispatch.*;
import org.jruby.truffle.nodes.yield.YieldDispatchHeadNode;
import org.jruby.truffle.runtime.ObjectIDOperations;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.UndefinedPlaceholder;
import org.jruby.truffle.runtime.control.RaiseException;
@@ -54,6 +55,52 @@ public boolean not(boolean value) {

}


@CoreMethod(names = "==", required = 1)
public abstract static class EqualNode extends BinaryCoreMethodNode {

public EqualNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public EqualNode(EqualNode prev) {
super(prev);
}

@Specialization public boolean equal(boolean a, boolean b) { return a == b; }
@Specialization public boolean equal(int a, int b) { return a == b; }
@Specialization public boolean equal(long a, long b) { return a == b; }
@Specialization public boolean equal(double a, double b) { return a == b; }

@Specialization public boolean equal(RubyBasicObject a, RubyBasicObject b) {
return a == b;
}

@Specialization(guards = {"isNotRubyBasicObject(left)", "isNotRubyBasicObject(right)", "notSameClass"})
public boolean equal(Object a, Object b) {
return false;
}

@Specialization(guards = "isNotRubyBasicObject(left)")
public boolean equal(Object a, RubyBasicObject b) {
return false;
}

@Specialization(guards = "isNotRubyBasicObject(right)")
public boolean equal(RubyBasicObject a, Object b) {
return false;
}

protected boolean isNotRubyBasicObject(Object value) {
return !(value instanceof RubyBasicObject);
}

protected boolean notSameClass(Object a, Object b) {
return a.getClass() != b.getClass();
}

}

@CoreMethod(names = "!=", required = 1)
public abstract static class NotEqualNode extends CoreMethodNode {

@@ -76,7 +123,81 @@ public boolean equal(VirtualFrame frame, Object a, Object b) {

}

@CoreMethod(names = {"equal?", "=="}, required = 1)
@CoreMethod(names = "__id__")
public abstract static class IDNode extends CoreMethodNode {

public IDNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public IDNode(IDNode prev) {
super(prev);
}

public abstract Object executeObjectID(VirtualFrame frame, Object value);

@Specialization
public int objectID(RubyNilClass nil) {
return ObjectIDOperations.NIL;
}

@Specialization(guards = "isTrue")
public int objectIDTrue(boolean value) {
return ObjectIDOperations.TRUE;
}

@Specialization(guards = "!isTrue")
public int objectIDFalse(boolean value) {
return ObjectIDOperations.FALSE;
}

@Specialization
public long objectID(int value) {
return ObjectIDOperations.smallFixnumToID(value);
}

@Specialization(rewriteOn = ArithmeticException.class)
public long objectIDSmallFixnumOverflow(long value) {
return ObjectIDOperations.smallFixnumToIDOverflow(value);
}

/* TODO: Ideally we would have this instead of the code below to speculate better. [GRAAL-903]
@Specialization(guards = "isSmallFixnum")
public long objectIDSmallFixnum(long value) {
return ObjectIDOperations.smallFixnumToID(value);
}
@Specialization(guards = "!isSmallFixnum")
public Object objectIDLargeFixnum(long value) {
return ObjectIDOperations.largeFixnumToID(getContext(), value);
} */

@Specialization
public Object objectID(long value) {
if (isSmallFixnum(value)) {
return ObjectIDOperations.smallFixnumToID(value);
} else {
return ObjectIDOperations.largeFixnumToID(getContext(), value);
}
}

@Specialization
public RubyBignum objectID(double value) {
return ObjectIDOperations.floatToID(getContext(), value);
}

@Specialization
public long objectID(RubyBasicObject object) {
return object.getObjectID();
}

protected boolean isSmallFixnum(long fixnum) {
return ObjectIDOperations.isSmallFixnum(fixnum);
}

}

@CoreMethod(names = "equal?", required = 1)
public abstract static class ReferenceEqualNode extends BinaryCoreMethodNode {

public ReferenceEqualNode(RubyContext context, SourceSection sourceSection) {
@@ -92,7 +213,7 @@ public ReferenceEqualNode(ReferenceEqualNode prev) {
@Specialization public boolean equal(boolean a, boolean b) { return a == b; }
@Specialization public boolean equal(int a, int b) { return a == b; }
@Specialization public boolean equal(long a, long b) { return a == b; }
@Specialization public boolean equal(double a, double b) { return a == b; }
@Specialization public boolean equal(double a, double b) { return Double.doubleToRawLongBits(a) == Double.doubleToRawLongBits(b); }

@Specialization public boolean equal(RubyBasicObject a, RubyBasicObject b) {
return a == b;
Original file line number Diff line number Diff line change
@@ -11,11 +11,16 @@

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.BranchProfile;

import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyBignum;
import org.jruby.truffle.runtime.core.RubyString;

@@ -256,12 +261,17 @@ public Object mod(RubyBignum a, RubyBignum b) {
@CoreMethod(names = "<", required = 1)
public abstract static class LessNode extends CoreMethodNode {

@Child private CallDispatchHeadNode rationalConvertNode;
@Child private CallDispatchHeadNode rationalLessNode;

public LessNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public LessNode(LessNode prev) {
super(prev);
rationalConvertNode = prev.rationalConvertNode;
rationalLessNode = prev.rationalLessNode;
}

@Specialization
@@ -283,6 +293,19 @@ public boolean less(RubyBignum a, double b) {
public boolean less(RubyBignum a, RubyBignum b) {
return a.compare(b) < 0;
}

@Specialization(guards = "isRational(arguments[1])")
public Object pow(VirtualFrame frame, Object a, RubyBasicObject b) {
if (rationalConvertNode == null) {
CompilerDirectives.transferToInterpreter();
rationalConvertNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext(), true));
rationalLessNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

final Object aRational = rationalConvertNode.call(frame, getContext().getCoreLibrary().getRationalClass(), "convert", null, a, 1);

return rationalLessNode.call(frame, aRational, "<", null, b);
}
}

@CoreMethod(names = "<=", required = 1)
@@ -352,6 +375,8 @@ public boolean equal(RubyBignum a, RubyBignum b) {
@CoreMethod(names = "<=>", required = 1)
public abstract static class CompareNode extends CoreMethodNode {

private final ConditionProfile negativeInfinityProfile = ConditionProfile.createBinaryProfile();

public CompareNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}
@@ -372,7 +397,11 @@ public int compare(RubyBignum a, long b) {

@Specialization
public int compare(RubyBignum a, double b) {
return Double.compare(a.doubleValue(), b);
if (negativeInfinityProfile.profile(Double.isInfinite(b) && b < 0)) {
return 1;
} else {
return Double.compare(a.doubleValue(), b);
}
}

@Specialization
Original file line number Diff line number Diff line change
@@ -1305,6 +1305,11 @@ public int leftShift(int a, int b) {
return a << b;
}

@Specialization(guards = {"isPositive(arguments[1])", "canShiftIntoInt"})
public int leftShift(int a, long b) {
return a << b;
}

@Specialization(guards = {"isPositive(arguments[1])", "canShiftIntoLong"})
public long leftShiftToLong(int a, int b) {
return leftShiftToLong((long) a, b);
@@ -1361,6 +1366,10 @@ static boolean canShiftIntoInt(int a, int b) {
return Integer.numberOfLeadingZeros(a) - b > 0;
}

static boolean canShiftIntoInt(int a, long b) {
return Integer.numberOfLeadingZeros(a) - b > 0;
}

static boolean canShiftIntoLong(int a, int b) {
return canShiftIntoLong((long) a, b);
}
@@ -1373,6 +1382,10 @@ static boolean isPositive(int value) {
return value >= 0;
}

static boolean isPositive(long value) {
return value >= 0;
}

static boolean isStrictlyNegative(int value) {
return value < 0;
}
121 changes: 94 additions & 27 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/FloatNodes.java
Original file line number Diff line number Diff line change
@@ -267,7 +267,7 @@ public double div(double a, RubyBignum b) {
public Object div(VirtualFrame frame, double a, Object b) {
if (redoCoercedNode == null) {
CompilerDirectives.transferToInterpreter();
redoCoercedNode = DispatchHeadNodeFactory.createMethodCall(getContext(), true);
redoCoercedNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext(), true));
}

return redoCoercedNode.call(frame, a, "redo_coerced", null, getContext().getSymbolTable().getSymbol("/"), b);
@@ -278,6 +278,8 @@ public Object div(VirtualFrame frame, double a, Object b) {
@CoreMethod(names = "%", required = 1)
public abstract static class ModNode extends CoreMethodNode {

private ConditionProfile lessThanZeroProfile = ConditionProfile.createBinaryProfile();

public ModNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}
@@ -287,56 +289,71 @@ public ModNode(ModNode prev) {
}

@Specialization
public double mod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") int b) {
throw new UnsupportedOperationException();
public double mod(double a, int b) {
return mod(a, (double) b);
}

@Specialization
public double mod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") long b) {
throw new UnsupportedOperationException();
public double mod(double a, long b) {
return mod(a, (double) b);
}

@Specialization
public double mod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") double b) {
throw new UnsupportedOperationException();
public double mod(double a, double b) {
if (b == 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().zeroDivisionError(this));
}

double result = Math.IEEEremainder(a, b);

if (lessThanZeroProfile.profile(b * result < 0)) {
result += b;
}

return result;
}

@Specialization
public double mod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") RubyBignum b) {
throw new UnsupportedOperationException();
public double mod(double a, RubyBignum b) {
return mod(a, b.doubleValue());
}

}

@CoreMethod(names = "divmod", required = 1)
public abstract static class DivModNode extends CoreMethodNode {

@Child private GeneralDivModNode divModNode;

public DivModNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
divModNode = new GeneralDivModNode(context, sourceSection);
}

public DivModNode(DivModNode prev) {
super(prev);
divModNode = prev.divModNode;
}

@Specialization
public RubyArray divMod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") int b) {
throw new UnsupportedOperationException();
public RubyArray divMod(double a, int b) {
return divModNode.execute(a, b);
}

@Specialization
public RubyArray divMod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") long b) {
throw new UnsupportedOperationException();
public RubyArray divMod(double a, long b) {
return divModNode.execute(a, b);
}

@Specialization
public RubyArray divMod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") double b) {
throw new UnsupportedOperationException();
public RubyArray divMod(double a, double b) {
return divModNode.execute(a, b);
}

@Specialization
public RubyArray divMod(@SuppressWarnings("unused") double a, @SuppressWarnings("unused") RubyBignum b) {
throw new UnsupportedOperationException();
public RubyArray divMod(double a, RubyBignum b) {
return divModNode.execute(a, b);
}

}
@@ -373,7 +390,7 @@ public boolean less(double a, RubyBignum b) {
}

@Specialization(guards = "!isRubyBignum(arguments[1])")
public boolean less(@SuppressWarnings("unused") double a, RubyBasicObject other) {
public boolean less(double a, RubyBasicObject other) {
throw new RaiseException(new RubyException(
getContext().getCoreLibrary().getArgumentErrorClass(),
getContext().makeString(String.format("comparison of Float with %s failed", other.getLogicalClass().getName())),
@@ -414,7 +431,7 @@ public boolean lessEqual(double a, RubyBignum b) {
}

@Specialization(guards = "!isRubyBignum(arguments[1])")
public boolean less(@SuppressWarnings("unused") double a, RubyBasicObject other) {
public boolean less(double a, RubyBasicObject other) {
throw new RaiseException(new RubyException(
getContext().getCoreLibrary().getArgumentErrorClass(),
getContext().makeString(String.format("comparison of Float with %s failed", other.getLogicalClass().getName())),
@@ -426,6 +443,8 @@ public boolean less(@SuppressWarnings("unused") double a, RubyBasicObject other)
@CoreMethod(names = "==", required = 1)
public abstract static class EqualNode extends CoreMethodNode {

@Child private CallDispatchHeadNode fallbackCallNode;

public EqualNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}
@@ -455,9 +474,13 @@ public boolean equal(double a, RubyBignum b) {
}

@Specialization(guards = "!isRubyBignum(arguments[1])")
public boolean less(@SuppressWarnings("unused") double a, RubyBasicObject other) {
// TODO (nirvdrum Dec. 1, 2014): This is a stub. There is one case where this should return 'true', but it's not a trivial fix.
return false;
public Object equal(VirtualFrame frame, double a, RubyBasicObject b) {
if (fallbackCallNode == null) {
CompilerDirectives.transferToInterpreter();
fallbackCallNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext(), true));
}

return fallbackCallNode.call(frame, a, "equal_fallback", null, b);
}
}

@@ -472,10 +495,50 @@ public CompareNode(CompareNode prev) {
super(prev);
}

@Specialization
@Specialization(guards = "isNaN(arguments[0])")
public RubyNilClass compareFirstNaN(double a, Object b) {
return getContext().getCoreLibrary().getNilObject();
}

@Specialization(guards = "isNaN(arguments[1])")
public RubyNilClass compareSecondNaN(Object a, double b) {
return getContext().getCoreLibrary().getNilObject();
}

@Specialization(guards = {"!isNaN(arguments[0])"})
public int compare(double a, int b) {
return Double.compare(a, b);
}

@Specialization(guards = {"!isNaN(arguments[0])"})
public int compare(double a, long b) {
return Double.compare(a, b);
}

@Specialization(guards = "isInfinity(arguments[0])")
public int compareInfinity(double a, RubyBignum b) {
if (a < 0) {
return -1;
} else {
return +1;
}
}

@Specialization(guards = {"!isNaN(arguments[0])", "!isInfinity(arguments[0])"})
public int compare(double a, RubyBignum b) {
return Double.compare(a, b.doubleValue());
}

@Specialization(guards = {"!isNaN(arguments[0])", "!isNaN(arguments[1])"})
public int compare(double a, double b) {
return Double.compare(a, b);
}

@Specialization(guards = {"!isNaN(arguments[0])", "!isRubyBignum(arguments[1])"})
public RubyNilClass compare(double a, RubyBasicObject b) {
return getContext().getCoreLibrary().getNilObject();
}

}

@CoreMethod(names = ">=", required = 1)
@@ -510,7 +573,7 @@ public boolean greaterEqual(double a, RubyBignum b) {
}

@Specialization(guards = "!isRubyBignum(arguments[1])")
public boolean less(@SuppressWarnings("unused") double a, RubyBasicObject other) {
public boolean less(double a, RubyBasicObject other) {
throw new RaiseException(new RubyException(
getContext().getCoreLibrary().getArgumentErrorClass(),
getContext().makeString(String.format("comparison of Float with %s failed", other.getLogicalClass().getName())),
@@ -551,7 +614,7 @@ public boolean equal(double a, RubyBignum b) {
}

@Specialization(guards = "!isRubyBignum(arguments[1])")
public boolean less(@SuppressWarnings("unused") double a, RubyBasicObject other) {
public boolean less(double a, RubyBasicObject other) {
throw new RaiseException(new RubyException(
getContext().getCoreLibrary().getArgumentErrorClass(),
getContext().makeString(String.format("comparison of Float with %s failed", other.getLogicalClass().getName())),
@@ -581,17 +644,21 @@ public double abs(double n) {
@CoreMethod(names = "ceil")
public abstract static class CeilNode extends CoreMethodNode {

@Child private FixnumOrBignumNode fixnumOrBignum;

public CeilNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
fixnumOrBignum = new FixnumOrBignumNode(context, sourceSection);
}

public CeilNode(CeilNode prev) {
super(prev);
fixnumOrBignum = prev.fixnumOrBignum;
}

@Specialization
public double ceil(double n) {
return Math.ceil(n);
public Object ceil(double n) {
return fixnumOrBignum.fixnumOrBignum(Math.ceil(n));
}

}
Original file line number Diff line number Diff line change
@@ -47,8 +47,8 @@ public RubyArray execute(int a, long b) {
return divMod(a, b);
}

public RubyArray execute(int a, BigInteger b) {
return divMod(BigInteger.valueOf(a), b);
public RubyArray execute(int a, RubyBignum b) {
return divMod(BigInteger.valueOf(a), b.bigIntegerValue());
}

public RubyArray execute(int a, double b) {
@@ -83,6 +83,22 @@ public RubyArray execute(RubyBignum a, RubyBignum b) {
return divMod(a.bigIntegerValue(), b.bigIntegerValue());
}

public RubyArray execute(double a, int b) {
return divMod(a, b);
}

public RubyArray execute(double a, long b) {
return divMod(a, b);
}

public RubyArray execute(double a, RubyBignum b) {
return divMod(a, b.doubleValue());
}

public RubyArray execute(double a, double b) {
return divMod(a, b);
}

/*
* div-mod algorithms copied from org.jruby.RubyFixnum, org.jruby.RubyBignum and org.jrubyRubyFloat. See license
* and contributors there.
@@ -151,7 +167,9 @@ private RubyArray divMod(double a, double b) {
mod += b;
}

return new RubyArray(getContext().getCoreLibrary().getArrayClass(), new Object[]{div, mod}, 2);
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), new Object[]{
fixnumOrBignumQuotient.fixnumOrBignum(div),
mod}, 2);
}

@CompilerDirectives.TruffleBoundary
29 changes: 18 additions & 11 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.source.SourceSection;

import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.common.IRubyWarnings;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyNode;
@@ -127,6 +128,8 @@ public abstract static class SameOrEqualNode extends CoreMethodNode {
@Child private BasicObjectNodes.ReferenceEqualNode referenceEqualNode;
@Child private CallDispatchHeadNode equalNode;

private final ConditionProfile sameProfile = ConditionProfile.createBinaryProfile();

public SameOrEqualNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}
@@ -135,29 +138,33 @@ public SameOrEqualNode(SameOrEqualNode prev) {
super(prev);
}

protected boolean areSame(VirtualFrame frame, Object left, Object right) {
public abstract boolean executeSameOrEqual(VirtualFrame frame, Object a, Object b);

@Specialization
public boolean sameOrEqual(VirtualFrame frame, Object a, Object b) {
if (sameProfile.profile(areSame(frame, a, b))) {
return true;
} else {
return areEqual(frame, a, b);
}
}

private boolean areSame(VirtualFrame frame, Object left, Object right) {
if (referenceEqualNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
referenceEqualNode = insert(BasicObjectNodesFactory.ReferenceEqualNodeFactory.create(getContext(), getSourceSection(), null, null));
}

return referenceEqualNode.executeReferenceEqual(frame, left, right);
}

protected boolean areEqual(VirtualFrame frame, Object left, Object right) {
private boolean areEqual(VirtualFrame frame, Object left, Object right) {
if (equalNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
equalNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext(), false, false, null));
}
return equalNode.callBoolean(frame, left, "==", null, right);
}

public abstract boolean executeSameOrEqual(VirtualFrame frame, Object a, Object b);

@Specialization
public boolean sameOrEqual(VirtualFrame frame, Object a, Object b) {
if (areSame(frame, a, b))
return true;
return areEqual(frame, a, b);
return equalNode.callBoolean(frame, left, "==", null, right);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.rubinius;

import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.runtime.RubyContext;

/**
* Rubinius primitives associated with the Ruby {@code Float} class.
*/
public abstract class FloatPrimitiveNodes {

@RubiniusPrimitive(name = "float_negative")
public static abstract class FloatNegativePrimitiveNode extends RubiniusPrimitiveNode {

public FloatNegativePrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public FloatNegativePrimitiveNode(FloatNegativePrimitiveNode prev) {
super(prev);
}

@Specialization
public boolean floatNegative(double value) {
// Edge-cases: 0, NaN and infinity can all be negative
return (Double.doubleToLongBits(value) >>> 63) == 1;
}

}

}
Original file line number Diff line number Diff line change
@@ -47,6 +47,7 @@ public static RubiniusPrimitiveManager create() {
nodeFactories.addAll(TimePrimitiveNodesFactory.getFactories());
nodeFactories.addAll(StringPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(FixnumPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(FloatPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(EncodingPrimitiveNodesFactory.getFactories());

final Map<String, RubiniusPrimitiveConstructor> primitives = new HashMap<>();
Original file line number Diff line number Diff line change
@@ -59,8 +59,9 @@ public StringToFPrimitiveNode(StringToFPrimitiveNode prev) {
}

@Specialization
public RubyString stringToF(RubyString string) {
throw new UnsupportedOperationException("string_to_f");
public double stringToF(RubyString string) {
notDesignedForCompilation();
return Double.parseDouble(string.toString());
}

}
Original file line number Diff line number Diff line change
@@ -200,6 +200,9 @@ public void initialize() {
standardErrorClass = new RubyClass(context, objectClass, exceptionClass, "StandardError");
standardErrorClass.setAllocator(new RubyException.ExceptionAllocator());

rangeErrorClass = new RubyClass(context, objectClass, standardErrorClass, "RangeError");
rangeErrorClass.setAllocator(new RubyException.ExceptionAllocator());

RubyClass signalExceptionClass = new RubyClass(context, objectClass, exceptionClass, "SignalException");
signalExceptionClass.setAllocator(new RubyException.ExceptionAllocator());

@@ -255,8 +258,6 @@ public void initialize() {
procClass.setAllocator(new RubyProc.ProcAllocator());
processClass = new RubyClass(context, objectClass, objectClass, "Process");
rangeClass = new RubyClass(context, objectClass, objectClass, "Range");
rangeErrorClass = new RubyClass(context, objectClass, standardErrorClass, "RangeError");
rangeErrorClass.setAllocator(new RubyException.ExceptionAllocator());
rationalClass = new RubyClass(context, objectClass, numericClass, "Rational");
regexpClass = new RubyClass(context, objectClass, objectClass, "Regexp");
regexpClass.setAllocator(new RubyRegexp.RegexpAllocator());