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: 8be11edf9f26
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8723a89a746c
Choose a head ref
  • 4 commits
  • 9 files changed
  • 1 contributor

Commits on Jan 17, 2018

  1. introduce long overloads for common (integer) ops + start using them

    ... as a side effect op_pow(long) got resurrected for Fixnum/Bignum
    kares committed Jan 17, 2018
    Copy the full SHA
    e0de0f0 View commit details
  2. Copy the full SHA
    73eeb44 View commit details
  3. Copy the full SHA
    363aa82 View commit details
  4. Copy the full SHA
    8723a89 View commit details
66 changes: 37 additions & 29 deletions core/src/main/java/org/jruby/RubyBignum.java
Original file line number Diff line number Diff line change
@@ -438,6 +438,7 @@ public IRubyObject op_plus(ThreadContext context, IRubyObject other) {
return addOther(context, other);
}

@Override
public final IRubyObject op_plus(ThreadContext context, long other) {
BigInteger result = value.add(BigInteger.valueOf(other));
if (other > 0 && value.signum() > 0) return new RubyBignum(context.runtime, result);
@@ -475,6 +476,7 @@ public IRubyObject op_minus(ThreadContext context, IRubyObject other) {
return subtractOther(context, other);
}

@Override
public final IRubyObject op_minus(ThreadContext context, long other) {
BigInteger result = value.subtract(BigInteger.valueOf(other));
if (value.signum() < 0 && other > 0) return new RubyBignum(context.runtime, result);
@@ -517,6 +519,7 @@ public final IRubyObject op_mul19(ThreadContext context, IRubyObject other) {
return op_mul(context, other);
}

@Override
public final IRubyObject op_mul(ThreadContext context, long other) {
return bignorm(context.runtime, value.multiply(long2big(other)));
}
@@ -546,6 +549,10 @@ private IRubyObject op_divide(ThreadContext context, IRubyObject other, boolean
return coerceBin(context, slash ? sites(context).op_quo : sites(context).div, other);
}

return divideImpl(runtime, otherValue);
}

private RubyInteger divideImpl(Ruby runtime, BigInteger otherValue) {
if (otherValue.signum() == 0) throw runtime.newZeroDivisionError();

final BigInteger result;
@@ -566,6 +573,10 @@ public IRubyObject op_div(ThreadContext context, IRubyObject other) {
return op_divide(context, other, true);
}

public IRubyObject op_div(ThreadContext context, long other) {
return divideImpl(context.runtime, long2big(other));
}

/** rb_big_idiv
*
*/
@@ -574,6 +585,11 @@ public IRubyObject idiv(ThreadContext context, IRubyObject other) {
return op_divide(context, other, false);
}

@Override
public IRubyObject idiv(ThreadContext context, long other) {
return divideImpl(context.runtime, long2big(other));
}

/** rb_big_divmod
*
*/
@@ -716,32 +732,37 @@ public IRubyObject op_pow(ThreadContext context, IRubyObject other) {
d = ((RubyBignum) other).getDoubleValue();
context.runtime.getWarnings().warn(ID.MAY_BE_TOO_BIG, "in a**b, b may be too big");
} else if (other instanceof RubyFixnum) {
long yy = other.convertToInteger().getLongValue();
if (yy < 0)
return RubyRational.newRationalRaw(runtime, this).op_expt(context, other);
else {
int xbits = value.bitLength();
int BIGLEN_LIMIT = 32*1024*1024;

if ((xbits > BIGLEN_LIMIT) ||
(xbits * yy > BIGLEN_LIMIT)) {
runtime.getWarnings().warn("in a**b, b may be too big");
d = (double)yy;
}
else {
return newBignum(runtime, value.pow((int)yy));
}
}
return op_pow(context, other.convertToInteger().getLongValue());
} else {
return coerceBin(context, sites(context).op_exp, other);
}
return pow(runtime, d);
}

private RubyNumeric pow(final Ruby runtime, final double d) {
double pow = Math.pow(big2dbl(this), d);
if (Double.isInfinite(pow)) {
return RubyFloat.newFloat(runtime, pow);
}
return RubyNumeric.dbl2ival(runtime, pow);
}

private static final int BIGLEN_LIMIT = 32 * 1024 * 1024;

public final IRubyObject op_pow(final ThreadContext context, final long other) {
if (other < 0) {
return RubyRational.newRationalRaw(context.runtime, this).op_expt(context, other);
}
final int xbits = value.bitLength();
if ((xbits > BIGLEN_LIMIT) || (xbits * other > BIGLEN_LIMIT)) {
context.runtime.getWarnings().warn("in a**b, b may be too big");
return pow(context.runtime, (double) other);
}
else {
return newBignum(context.runtime, value.pow((int) other));
}
}

private void warnIfPowExponentTooBig(final ThreadContext context, final long other) {
// MRI issuses warning here on (RBIGNUM(x)->len * SIZEOF_BDIGITS * yy > 1024*1024)
if ( ((value.bitLength() + 7) / 8) * 4 * Math.abs((double) other) > 1024 * 1024 ) {
@@ -1124,19 +1145,6 @@ public boolean isImmediate() {
return true;
}

@Deprecated
public final IRubyObject op_pow(final ThreadContext context, final long other) {
if (other >= 0) {
if (other <= Integer.MAX_VALUE) { // only have BigInteger#pow(int)
return bignorm(context.runtime, value.pow((int) other)); // num2int is also implemented
}
warnIfPowExponentTooBig(context, other);
return RubyFloat.newFloat(context.runtime, Math.pow(big2dbl(this), (double) other));
}
// (other < 0)
return RubyRational.newRationalRaw(context.runtime, this).op_expt(context, other);
}

private static JavaSites.BignumSites sites(ThreadContext context) {
return context.sites.Bignum;
}
35 changes: 21 additions & 14 deletions core/src/main/java/org/jruby/RubyFixnum.java
Original file line number Diff line number Diff line change
@@ -467,6 +467,7 @@ public IRubyObject op_plus(ThreadContext context, IRubyObject other) {
return addOther(context, other);
}

@Override
public IRubyObject op_plus(ThreadContext context, long otherValue) {
long result = value + otherValue;
if (Helpers.additionOverflowed(value, otherValue, result)) {
@@ -492,17 +493,17 @@ public IRubyObject op_plus_two(ThreadContext context) {
return newFixnum(context.runtime, result);
}

private IRubyObject addFixnum(ThreadContext context, RubyFixnum other) {
private RubyInteger addFixnum(ThreadContext context, RubyFixnum other) {
long otherValue = other.value;
long result = value + otherValue;
if (Helpers.additionOverflowed(value, otherValue, result)) {
return addAsBignum(context, other);
return (RubyInteger) addAsBignum(context, other);
}
return newFixnum(context.runtime, result);
}

private IRubyObject addAsBignum(ThreadContext context, RubyFixnum other) {
return RubyBignum.newBignum(context.runtime, value).op_plus(context, other);
return RubyBignum.newBignum(context.runtime, value).op_plus(context, other.value);
}

private IRubyObject addAsBignum(ThreadContext context, long other) {
@@ -511,7 +512,7 @@ private IRubyObject addAsBignum(ThreadContext context, long other) {

private IRubyObject addOther(ThreadContext context, IRubyObject other) {
if (other instanceof RubyBignum) {
return ((RubyBignum) other).op_plus(context, this);
return ((RubyBignum) other).op_plus(context, this.value);
}
if (other instanceof RubyFloat) {
return context.runtime.newFloat((double) value + ((RubyFloat) other).getDoubleValue());
@@ -530,6 +531,7 @@ public IRubyObject op_minus(ThreadContext context, IRubyObject other) {
return subtractOther(context, other);
}

@Override
public IRubyObject op_minus(ThreadContext context, long otherValue) {
long result = value - otherValue;
if (Helpers.subtractionOverflowed(value, otherValue, result)) {
@@ -588,21 +590,21 @@ private IRubyObject subtractOther(ThreadContext context, IRubyObject other) {
public IRubyObject op_mul(ThreadContext context, IRubyObject other) {
if (other instanceof RubyFixnum) {
return op_mul(context, ((RubyFixnum) other).value);
} else {
return multiplyOther(context, other);
}
return multiplyOther(context, other);
}

private IRubyObject multiplyOther(ThreadContext context, IRubyObject other) {
Ruby runtime = context.runtime;
if (other instanceof RubyBignum) {
return ((RubyBignum) other).op_mul(context, this);
return ((RubyBignum) other).op_mul(context, this.value);
} else if (other instanceof RubyFloat) {
return runtime.newFloat((double) value * ((RubyFloat) other).getDoubleValue());
}
return coerceBin(context, sites(context).op_times, other);
}

@Override
public IRubyObject op_mul(ThreadContext context, long otherValue) {
// See JRUBY-6612 for reasons for these different cases.
// The problem is that these Java long calculations overflow:
@@ -653,13 +655,18 @@ public IRubyObject idiv(ThreadContext context, IRubyObject other) {
return idiv(context, other, sites(context).div);
}

@Override
public IRubyObject idiv(ThreadContext context, long other) {
return idivLong(context, value, other);
}

@Override
public IRubyObject op_div(ThreadContext context, IRubyObject other) {
return idiv(context, other, sites(context).op_quo);
}

public IRubyObject op_div(ThreadContext context, long other) {
return idiv(context, other, "/");
return idivLong(context, value, other);
}

@Override
@@ -697,13 +704,14 @@ public IRubyObject idiv(ThreadContext context, IRubyObject other, CallSite site)
return coerceBin(context, site, other);
}

@Deprecated
public IRubyObject idiv(ThreadContext context, long y, String method) {
long x = value;

return idivLong(context, x, y);
}

private IRubyObject idivLong(ThreadContext context, long x, long y) {
private RubyInteger idivLong(ThreadContext context, long x, long y) {
final Ruby runtime = context.runtime;
if (y == 0) {
throw runtime.newZeroDivisionError();
@@ -818,15 +826,14 @@ public IRubyObject op_pow(ThreadContext context, IRubyObject other) {
return numFuncall(context, complex, sites(context).op_exp_complex, other);
}
if (other instanceof RubyFixnum) {
return powerFixnum(context, other);
return powerFixnum(context, (RubyFixnum) other);
}
}
return powerOther(context, other);
}

public IRubyObject op_pow(ThreadContext context, long other) {
// FIXME this needs to do the right thing for 1.9 mode before we can use it
throw context.runtime.newRuntimeError("bug: using direct op_pow(long) in 1.8 mode");
return powerFixnum(context, RubyFixnum.newFixnum(context.runtime, other));
}

@Deprecated
@@ -857,10 +864,10 @@ private IRubyObject powerOther(ThreadContext context, IRubyObject other) {
return coerceBin(context, sites(context).op_exp, other);
}

private IRubyObject powerFixnum(ThreadContext context, IRubyObject other) {
private IRubyObject powerFixnum(ThreadContext context, RubyFixnum other) {
Ruby runtime = context.runtime;
long a = value;
long b = ((RubyFixnum) other).value;
long b = other.value;
if (b < 0) {
RubyRational rational = RubyRational.newRationalRaw(runtime, this);
return numFuncall(context, rational, sites(context).op_exp_rational, other);
14 changes: 13 additions & 1 deletion core/src/main/java/org/jruby/RubyInteger.java
Original file line number Diff line number Diff line change
@@ -484,7 +484,7 @@ protected IRubyObject roundShared(ThreadContext context, int ndigits, RoundingMo
/* then int_pow overflow */
return RubyFixnum.zero(runtime);
}
h = (RubyNumeric) f.idiv(context, int2fix(runtime, 2));
h = (RubyNumeric) f.idiv(context, 2);
r = (RubyNumeric) this.op_mod(context, f);
n = (RubyNumeric) this.op_minus(context, r);
r = (RubyNumeric) r.op_cmp(context, h);
@@ -684,12 +684,24 @@ public IRubyObject denominator(ThreadContext context) {
@JRubyMethod(name = "+")
public abstract IRubyObject op_plus(ThreadContext context, IRubyObject other);

public IRubyObject op_plus(ThreadContext context, long other) {
return op_plus(context, RubyFixnum.newFixnum(context.runtime, other));
}

@JRubyMethod(name = "-")
public abstract IRubyObject op_minus(ThreadContext context, IRubyObject other);

public IRubyObject op_minus(ThreadContext context, long other) {
return op_minus(context, RubyFixnum.newFixnum(context.runtime, other));
}

@JRubyMethod(name = "*")
public abstract IRubyObject op_mul(ThreadContext context, IRubyObject other);

public IRubyObject op_mul(ThreadContext context, long other) {
return op_mul(context, RubyFixnum.newFixnum(context.runtime, other));
}

// MRI: rb_int_idiv, polymorphism handles fixnum vs bignum
@JRubyMethod(name = "div")
@Override
6 changes: 5 additions & 1 deletion core/src/main/java/org/jruby/RubyNumeric.java
Original file line number Diff line number Diff line change
@@ -248,7 +248,7 @@ public static IRubyObject dbl2num(Ruby runtime, double val) {
/**
* MRI: macro DBL2IVAL
*/
public static IRubyObject dbl2ival(Ruby runtime, double val) {
public static RubyInteger dbl2ival(Ruby runtime, double val) {
if (fixable(runtime, val)) {
return RubyFixnum.newFixnum(runtime, (long) val);
}
@@ -760,6 +760,10 @@ public IRubyObject idiv(ThreadContext context, IRubyObject other) {
return div(context, other);
}

public IRubyObject idiv(ThreadContext context, long other) {
return idiv(context, RubyFixnum.newFixnum(context.runtime, other));
}

/** num_divmod
*
*/
36 changes: 15 additions & 21 deletions core/src/main/java/org/jruby/RubyRational.java
Original file line number Diff line number Diff line change
@@ -246,8 +246,8 @@ private static IRubyObject canonicalizeInternal(ThreadContext context, IRubyObje
}

IRubyObject gcd = f_gcd(context, num, den);
IRubyObject _num = f_idiv(context, num, gcd); // TODO use RubyInteger#fdiv
IRubyObject _den = f_idiv(context, den, gcd); // TODO use RubyInteger#fdiv
IRubyObject _num = num.idiv(context, gcd);
IRubyObject _den = den.idiv(context, gcd);

if (Numeric.CANON && canonicalization && f_one_p(context, _den)) {
return _num;
@@ -426,11 +426,11 @@ public IRubyObject denominator(ThreadContext context) {
return den;
}

public IRubyObject getNumerator() {
public RubyInteger getNumerator() {
return num;
}

public IRubyObject getDenominator() {
public RubyInteger getDenominator() {
return den;
}

@@ -883,12 +883,9 @@ public IRubyObject round(ThreadContext context) {

@JRubyMethod(name = "round")
public IRubyObject round(ThreadContext context, IRubyObject n) {
Ruby runtime = context.runtime;

IRubyObject opts = ArgsUtil.getOptionsArg(runtime, n);
if (!opts.isNil()) {
n = context.nil;
}
IRubyObject opts = ArgsUtil.getOptionsArg(context.runtime, n);
if (opts != context.nil) n = context.nil;

RoundingMode mode = RubyNumeric.getRoundingMode(context, opts);

@@ -914,7 +911,7 @@ private IRubyObject roundCommon(ThreadContext context, IRubyObject n, RoundingMo
Ruby runtime = context.runtime;
IRubyObject b, s;

if (n.isNil()) {
if (n == context.nil) {
return doRound(context, mode);
}

@@ -971,7 +968,6 @@ private IRubyObject doRound(ThreadContext context, RoundingMode mode) {

// MRI: nurat_round_half_down
private RubyInteger roundHalfDown(ThreadContext context) {
Ruby runtime = context.runtime;

RubyInteger num = this.num, den = this.den;
IRubyObject neg;
@@ -982,9 +978,9 @@ private RubyInteger roundHalfDown(ThreadContext context) {
num = (RubyInteger) num.op_uminus(context);
}

num = (RubyInteger) ((RubyInteger) num.op_mul(context, RubyFixnum.two(runtime))).op_plus(context, den);
num = (RubyInteger) num.op_minus(context, RubyFixnum.one(runtime));
den = (RubyInteger) den.op_mul(context, RubyFixnum.two(runtime));
num = (RubyInteger) ((RubyInteger) num.op_mul(context, 2)).op_plus(context, den);
num = (RubyInteger) num.op_minus(context, 1);
den = (RubyInteger) den.op_mul(context, 2);
num = (RubyInteger) num.idiv(context, den);

if (neg.isTrue())
@@ -995,7 +991,6 @@ private RubyInteger roundHalfDown(ThreadContext context) {

// MRI: nurat_round_half_even
private RubyInteger roundHalfEven(ThreadContext context) {
Ruby runtime = context.runtime;

RubyInteger num = this.num, den = this.den;
IRubyObject neg;
@@ -1007,12 +1002,12 @@ private RubyInteger roundHalfEven(ThreadContext context) {
num = (RubyInteger) num.op_uminus(context);
}

num = (RubyInteger) ((RubyInteger) num.op_mul(context, RubyFixnum.two(runtime))).op_plus(context, den);
den = (RubyInteger) den.op_mul(context, RubyFixnum.two(runtime));
num = (RubyInteger) ((RubyInteger) num.op_mul(context, 2)).op_plus(context, den);
den = (RubyInteger) den.op_mul(context, 2);
qr = (RubyArray) num.divmod(context, den);
num = (RubyInteger) qr.eltOk(0);
if (((RubyInteger) qr.eltOk(1)).zero_p(context).isTrue()) {
num = (RubyInteger) num.op_and(context, RubyFixnum.newFixnum(runtime, ~1L));
num = (RubyInteger) num.op_and(context, RubyFixnum.newFixnum(context.runtime, ~1L));
}

if (neg.isTrue()) {
@@ -1024,7 +1019,6 @@ private RubyInteger roundHalfEven(ThreadContext context) {

// MRI: nurat_round_half_up
private RubyInteger roundHalfUp(ThreadContext context) {
Ruby runtime = context.runtime;

RubyInteger num = this.num, den = this.den;
IRubyObject neg;
@@ -1035,8 +1029,8 @@ private RubyInteger roundHalfUp(ThreadContext context) {
num = (RubyInteger) num.op_uminus(context);
}

num = (RubyInteger) ((RubyInteger) num.op_mul(context, RubyFixnum.two(runtime))).op_plus(context, den);
den = (RubyInteger) den.op_mul(context, RubyFixnum.two(runtime));
num = (RubyInteger) ((RubyInteger) num.op_mul(context, 2)).op_plus(context, den);
den = (RubyInteger) den.op_mul(context, 2);
num = (RubyInteger) num.idiv(context, den);

if (neg.isTrue()) {
14 changes: 14 additions & 0 deletions core/src/main/java/org/jruby/ext/set/RubySortedSet.java
Original file line number Diff line number Diff line change
@@ -143,6 +143,20 @@ public RubyArray to_a(final ThreadContext context) {
return sort(context); // instead of this.hash.keys();
}

@Override
public IRubyObject initialize_dup(ThreadContext context, IRubyObject orig) {
super.initialize_dup(context, orig);
if (this != orig) order.addAll(((RubySortedSet) orig).order);
return this;
}

@Override
public IRubyObject initialize_clone(ThreadContext context, IRubyObject orig) {
super.initialize_clone(context, orig);
if (this != orig) order.addAll(((RubySortedSet) orig).order);
return this;
}

// NOTE: weirdly Set/SortedSet in Ruby do not have sort!

@Override
4 changes: 2 additions & 2 deletions core/src/main/java/org/jruby/util/Numeric.java
Original file line number Diff line number Diff line change
@@ -506,7 +506,7 @@ public static IRubyObject int_pow(ThreadContext context, long x, long y) {
do {
while (y % 2 == 0) {
if (!fitSqrtLong(x)) {
IRubyObject v = RubyBignum.newBignum(runtime, x).op_pow(context, RubyFixnum.newFixnum(runtime, y));
IRubyObject v = RubyBignum.newBignum(runtime, x).op_pow(context, y);
if (z != 1) v = RubyBignum.newBignum(runtime, neg ? -z : z).op_mul(context, v);
return v;
}
@@ -515,7 +515,7 @@ public static IRubyObject int_pow(ThreadContext context, long x, long y) {
}

if (multiplyOverflows(x, z)) {
IRubyObject v = RubyBignum.newBignum(runtime, x).op_pow(context, RubyFixnum.newFixnum(runtime, y));
IRubyObject v = RubyBignum.newBignum(runtime, x).op_pow(context, y);
if (z != 1) v = RubyBignum.newBignum(runtime, neg ? -z : z).op_mul(context, v);
return v;
}
6 changes: 3 additions & 3 deletions core/src/main/java/org/jruby/util/RubyDateFormatter.java
Original file line number Diff line number Diff line change
@@ -332,13 +332,13 @@ public List<Token> compilePattern(ByteList pattern, boolean dateLibrary) {
}
}
} catch (IOException e) {
e.printStackTrace();
throw new AssertionError(e); // IOException never happens
}

return compiledPattern;
}

static enum FieldType {
enum FieldType {
NUMERIC('0', 0),
NUMERIC2('0', 2),
NUMERIC2BLANK(' ', 2),
@@ -517,7 +517,7 @@ public ByteList formatToByteList(List<Token> compiledPattern, DateTime dt, long
} else { // Date, DateTime
int prec = width - 3;
final ThreadContext context = runtime.getCurrentContext(); // TODO really need the dynamic nature here?
IRubyObject power = runtime.newFixnum(10).callMethod(context, "**", runtime.newFixnum(prec));
IRubyObject power = runtime.newFixnum(10).op_pow(context, prec);
IRubyObject truncated = sub_millis.callMethod(context, "numerator").callMethod(context, "*", power);
truncated = truncated.callMethod(context, "/", sub_millis.callMethod(context, "denominator"));
long decimals = truncated.convertToInteger().getLongValue();
11 changes: 11 additions & 0 deletions test/jruby/test_set.rb
Original file line number Diff line number Diff line change
@@ -103,6 +103,17 @@ def test_dup
assert_equal 2, dup.size
end

def test_dup_to_a
set = Set[1, 2]
assert_equal set.to_a, set.dup.to_a
assert_equal set.to_a, set.clone.dup.to_a

set = SortedSet[2, 1, 3]
dup = set.dup
assert_equal set.to_a, dup.to_a
assert_equal [1, 2, 3], dup.clone.to_a
end

def test_to_java
assert set = Set.new.to_java
assert set.toString.start_with?('#<Set:0x')