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

Commits on Apr 25, 2018

  1. Copy the full SHA
    a9aa369 View commit details
  2. Copy the full SHA
    50ba1a4 View commit details
  3. Actually bind Exception#full_message and add kwarg logic.

    Note: we do not have reversed traces yet.
    headius committed Apr 25, 2018
    Copy the full SHA
    225be09 View commit details
  4. Copy the full SHA
    5443d09 View commit details
36 changes: 36 additions & 0 deletions core/src/main/java/org/jruby/RubyException.java
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@

import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.ast.util.ArgsUtil;
import org.jruby.exceptions.Exception;
import org.jruby.exceptions.JumpException.FlowControlException;
import org.jruby.exceptions.RaiseException;
@@ -52,6 +53,7 @@
import org.jruby.runtime.component.VariableEntry;
import org.jruby.runtime.marshal.MarshalStream;
import org.jruby.runtime.marshal.UnmarshalStream;
import org.jruby.util.TypeConverter;

import java.io.IOException;
import java.io.PrintStream;
@@ -69,6 +71,7 @@ public class RubyException extends RubyObject {
public static final int TRACE_HEAD = 8;
public static final int TRACE_TAIL = 4;
public static final int TRACE_MAX = RubyException.TRACE_HEAD + RubyException.TRACE_TAIL + 6;
public static final String[] FULL_MESSAGE_KEYS = {"highlight", "order"};
protected BacktraceData backtraceData;
IRubyObject message;
// We initialize this to UNDEF to know whether cause has been initialized (from ruby space we will just see nil
@@ -174,10 +177,43 @@ public static IRubyObject newException(ThreadContext context, RubyClass exceptio
return exceptionClass.callMethod(context, "new", message.convertToString());
}

@JRubyMethod
public IRubyObject full_message(ThreadContext context) {
return RubyString.newString(context.runtime, TraceType.Format.MRI.printBacktrace(this, false));
}

@JRubyMethod
public IRubyObject full_message(ThreadContext context, IRubyObject opts) {
Ruby runtime = context.runtime;
IRubyObject optArg = ArgsUtil.getOptionsArg(runtime, opts);
boolean highlight = false;
boolean reverse = false;

if (!optArg.isNil()) {
IRubyObject[] highlightOrder = ArgsUtil.extractKeywordArgs(context, (RubyHash) optArg, FULL_MESSAGE_KEYS);

IRubyObject vHigh = highlightOrder[0];
if (vHigh == UNDEF) vHigh = context.nil;
if (vHigh != context.nil && vHigh != context.fals && vHigh != context.tru) {
throw runtime.newArgumentError("expected true or false as highlight: " + vHigh);
}
highlight = vHigh.isTrue();

IRubyObject vOrder = highlightOrder[1];
if (vOrder != UNDEF) {
vOrder = TypeConverter.checkID(vOrder);
if (vOrder == runtime.newSymbol("bottom")) reverse = true;
else if (vOrder == runtime.newSymbol("top")) reverse = false;
else {
throw runtime.newArgumentError("expected :top or :bottom as order: " + vOrder);
}
}
}

// TODO: reverse
return RubyString.newString(runtime, TraceType.Format.MRI.printBacktrace(this, highlight));
}

@JRubyMethod(optional = 2, visibility = PRIVATE)
public IRubyObject initialize(IRubyObject[] args, Block block) {
if ( args.length == 1 ) setMessage(args[0]);
112 changes: 64 additions & 48 deletions core/src/main/java/org/jruby/RubyFloat.java
Original file line number Diff line number Diff line change
@@ -38,7 +38,6 @@

package org.jruby;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.Locale;
@@ -48,7 +47,6 @@
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.ast.util.ArgsUtil;
import org.jruby.runtime.Arity;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.JavaSites.FloatSites;
import org.jruby.runtime.ObjectAllocator;
@@ -63,7 +61,6 @@
import static org.jruby.util.Numeric.f_abs;
import static org.jruby.util.Numeric.f_add;
import static org.jruby.util.Numeric.f_expt;
import static org.jruby.util.Numeric.f_lshift;
import static org.jruby.util.Numeric.f_mul;
import static org.jruby.util.Numeric.f_negate;
import static org.jruby.util.Numeric.f_negative_p;
@@ -90,6 +87,7 @@ public class RubyFloat extends RubyNumeric {
public static final double EPSILON = 2.2204460492503131e-16;
public static final double INFINITY = Double.POSITIVE_INFINITY;
public static final double NAN = Double.NaN;
public static final int FLOAT_DIG = DIG + 2;

public static RubyClass createFloatClass(Ruby runtime) {
RubyClass floatc = runtime.defineClass("Float", runtime.getNumeric(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
@@ -855,26 +853,32 @@ public IRubyObject floor(ThreadContext context, IRubyObject digits) {
return ((RubyInteger) truncate(context)).floor(context, digits);
}

Ruby runtime = context.runtime;
number = value;

if (number == 0.0) {
return ndigits > 0 ? this : RubyFixnum.zero(runtime);
}

if (ndigits > 0) {
RubyNumeric[] num = {this};
Ruby runtime = context.runtime;
if (floatInvariantRound(runtime, number, ndigits, num)) return num[0];
long[] binexp = {0};
frexp(number, binexp);
if (floatRoundOverflow(ndigits, binexp)) return num[0];
if (number > 0.0 && floatRoundUnderflow(ndigits, binexp))
return newFloat(runtime, 0.0);
f = Math.pow(10, ndigits);
f = Math.floor(number * f) / f;
return dbl2num(runtime, f);
} else {
RubyInteger num = dbl2ival(runtime, Math.floor(number));
if (ndigits < 0) num = (RubyInteger) num.floor(context, digits);
return num;
}

return floor(context);
}

// MRI: float_invariant_round
private static boolean floatInvariantRound(Ruby runtime, double number, int ndigits, RubyNumeric[] num) {
int float_dig = DIG+2;
long[] binexp = {0L};

frexp(number, binexp);
// MRI: float_round_overflow
private static boolean floatRoundOverflow(int ndigits, long[] binexp) {

/* Let `exp` be such that `number` is written as:"0.#{digits}e#{exp}",
i.e. such that 10 ** (exp - 1) <= |number| < 10 ** exp
@@ -894,13 +898,16 @@ private static boolean floatInvariantRound(Ruby runtime, double number, int ndig
If ndigits + ceil(binexp/(3 or 4)) < 0 the result is 0
*/

if (Double.isInfinite(number) || Double.isNaN(number) ||
(ndigits >= float_dig - (binexp[0] > 0 ? binexp[0] / 4 : binexp[0] / 3 - 1))) {
if (ndigits >= FLOAT_DIG - (binexp[0] > 0 ? binexp[0] / 4 : binexp[0] / 3 - 1)) {
return true;
}

return false;
}

// MRI: float_round_underflow
private static boolean floatRoundUnderflow(int ndigits, long[] binexp) {
if (ndigits < - (binexp[0] > 0 ? binexp[0] / 3 + 1 : binexp[0] / 4)) {
num[0] = RubyFixnum.zero(runtime);
return true;
}

@@ -928,20 +935,25 @@ public IRubyObject ceil(ThreadContext context, IRubyObject digits) {

number = value;

if (ndigits < 0) {
return ((RubyInteger) dbl2ival(runtime, Math.ceil(number))).ceil(context, digits);
if (number == 0.0) {
return ndigits > 0 ? this : RubyFixnum.zero(runtime);
}

if (ndigits == 0) {
return dbl2ival(runtime, Math.ceil(number));
if (ndigits > 0) {
long[] binexp = {0};
frexp(number, binexp);
if (floatRoundOverflow(ndigits, binexp)) return this;
if (number < 0.0 && floatRoundUnderflow(ndigits, binexp))
return newFloat(runtime, 0.0);
f = Math.pow(10, ndigits);
f = Math.ceil(number * f) / f;
return newFloat(runtime, f);
}
else {
IRubyObject num = dbl2ival(runtime, Math.ceil(number));
if (ndigits < 0) num = ((RubyInteger) num).ceil(context, digits);
return num;
}

RubyNumeric[] num = {this};
if (floatInvariantRound(runtime, number, ndigits, num)) return num[0];

f = Math.pow(10, ndigits);

return RubyFloat.newFloat(runtime, Math.ceil(number * f) / f);
}

/**
@@ -950,7 +962,7 @@ public IRubyObject ceil(ThreadContext context, IRubyObject digits) {
@Override
@JRubyMethod(name = "round")
public IRubyObject round(ThreadContext context) {
return roundShared(context, RoundingMode.HALF_UP, 0);
return roundShared(context, 0, RoundingMode.HALF_UP);
}

/**
@@ -969,7 +981,7 @@ public IRubyObject round(ThreadContext context, IRubyObject arg0) {

RoundingMode roundingMode = getRoundingMode(context, opts);

return roundShared(context, roundingMode, digits);
return roundShared(context, digits, roundingMode);
}

/**
@@ -986,35 +998,39 @@ public IRubyObject round(ThreadContext context, IRubyObject _digits, IRubyObject

RoundingMode roundingMode = getRoundingMode(context, opts);

return roundShared(context, roundingMode, digits);
return roundShared(context, digits, roundingMode);
}

private IRubyObject roundShared(ThreadContext context, RoundingMode roundingMode, int ndigits) {
/*
* MRI: flo_round main body
*/
public IRubyObject roundShared(ThreadContext context, int ndigits, RoundingMode mode) {
Ruby runtime = context.runtime;
double number, f, x;

if (Double.isInfinite(value)) {
if (ndigits <= 0) throw context.runtime.newFloatDomainError(value < 0 ? "-Infinity" : "Infinity");
return this;
}
number = value;

if (Double.isNaN(value)) {
if (ndigits <= 0) throw context.runtime.newFloatDomainError("NaN");
return this;
if (number == 0.0) {
return ndigits > 0 ? this : RubyFixnum.zero(runtime);
}

if (ndigits < 0) {
return ((RubyInteger) truncate(context)).round(context, ndigits);
return ((RubyInteger) to_int(context)).roundShared(context, ndigits, mode);
}
number = value;
if (ndigits == 0) {
x = doRound(context, roundingMode, number, 1.0);
return dbl2ival(context.runtime, x);
x = doRound(context, mode, number, 1.0);
return dbl2ival(runtime, x);
}
RubyNumeric[] num = {this};
if (floatInvariantRound(context.runtime, number, ndigits, num)) return num[0];
f = Math.pow(10, ndigits);
x = doRound(context, roundingMode, number, f);
return dbl2num(context.runtime, x / f);
if (Double.isFinite(value)) {
long[] binexp = {0};
frexp(number, binexp);
if (floatRoundOverflow(ndigits, binexp)) return this;
if (floatRoundUnderflow(ndigits, binexp)) return newFloat(runtime, 0);
f = Math.pow(10, ndigits);
x = doRound(context, mode, number, f);
return newFloat(runtime, x / f);
}

return this;
}

private static double doRound(ThreadContext context, RoundingMode roundingMode, double number, double scale) {
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyInteger.java
Original file line number Diff line number Diff line change
@@ -485,7 +485,7 @@ public IRubyObject round(ThreadContext context, int ndigits) {
/*
* MRI: rb_int_round
*/
private RubyNumeric roundShared(ThreadContext context, int ndigits, RoundingMode roundingMode) {
public RubyNumeric roundShared(ThreadContext context, int ndigits, RoundingMode roundingMode) {
Ruby runtime = context.runtime;

RubyNumeric f, h, n, r;
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyKernel.java
Original file line number Diff line number Diff line change
@@ -888,7 +888,7 @@ public static IRubyObject raise(ThreadContext context, IRubyObject recv, IRubyOb
printExceptionSummary(runtime, raise.getException());
}

if (forceCause || argc > 0 && raise.getException().getCause() == UNDEF && cause != raise.getException()) {
if (forceCause || argc > 0 && raise.getException().getCause() == null && cause != raise.getException()) {
raise.getException().setCause(cause);
}

2 changes: 2 additions & 0 deletions test/mri/excludes/TestException.rb
Original file line number Diff line number Diff line change
@@ -17,3 +17,5 @@
exclude :test_redefined_backtrace, "Our backtrace is lazily set up and the flow does not work with this change"
exclude :test_stackoverflow, reason
exclude :test_too_many_args_in_eval, "MRI raises SystemStackError for huge number of args, for some reason"
exclude :test_warning_warn, "we warn a line at a time"
exclude :test_warning_warn_circular_require_backtrace, "we do not support #path objects in loaded features"