Skip to content

Commit

Permalink
Showing 10 changed files with 79 additions and 52 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -83,7 +83,7 @@ target
test/pom.xml
test/prawn
test/rails
test/testapp/testapp
test/jruby/testapp/testapp
tool/nailgun/Makefile
tool/nailgun/config.log
tool/nailgun/config.status
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/AbstractRubyMethod.java
Original file line number Diff line number Diff line change
@@ -106,7 +106,7 @@ public String getMethodName() {

@JRubyMethod(name = "owner")
public IRubyObject owner(ThreadContext context) {
return method.getRealMethod().getDefinedClass();
return implementationModule;
}

@JRubyMethod(name = "source_location")
5 changes: 0 additions & 5 deletions core/src/main/java/org/jruby/RubyMethod.java
Original file line number Diff line number Diff line change
@@ -312,11 +312,6 @@ public IRubyObject receiver(ThreadContext context) {
return receiver;
}

@JRubyMethod
public IRubyObject owner(ThreadContext context) {
return implementationModule;
}

@JRubyMethod
public IRubyObject source_location(ThreadContext context) {
Ruby runtime = context.runtime;
63 changes: 47 additions & 16 deletions core/src/main/java/org/jruby/ext/bigdecimal/RubyBigDecimal.java
Original file line number Diff line number Diff line change
@@ -652,10 +652,11 @@ else if ( lastSign > s ) {
try {
decimal = new BigDecimal(str, s, e - s + 1, mathContext);
}
catch (ArithmeticException ex) {
return checkOverUnderFlow(context.runtime, ex, false);
}
catch (NumberFormatException ex) {
if (isOverflowExceptionMode(context.runtime)) throw context.runtime.newFloatDomainError("exponent overflow");

decimal = BigDecimal.ZERO;
throw context.runtime.newArgumentError("invalid value for BigDecimal(): \"" + arg + "\"");
}

// MRI behavior: -0 and +0 are two different things
@@ -935,12 +936,12 @@ private RubyBigDecimal multImpl(final Ruby runtime, RubyBigDecimal val) {
result = value.multiply(val.value, mathContext);
}
catch (ArithmeticException ex) {
return checkOverUnderFlow(runtime, ex);
return checkOverUnderFlow(runtime, ex, false);
}
return new RubyBigDecimal(runtime, result).setResult(0);
}

private static RubyBigDecimal checkOverUnderFlow(final Ruby runtime, final ArithmeticException ex) {
private static RubyBigDecimal checkOverUnderFlow(final Ruby runtime, final ArithmeticException ex, boolean nullDefault) {
String message = ex.getMessage();
if (message == null) message = "";
message = message.toLowerCase(Locale.ENGLISH);
@@ -952,6 +953,7 @@ private static RubyBigDecimal checkOverUnderFlow(final Ruby runtime, final Arith
if (isOverflowExceptionMode(runtime)) throw runtime.newFloatDomainError(message);
return newInfinity(runtime, 1); // TODO sign?
}
if (nullDefault) return null;
throw runtime.newFloatDomainError(message);
}

@@ -1339,19 +1341,36 @@ private IRubyObject cmp(ThreadContext context, final IRubyObject arg, final char
final int e;
RubyBigDecimal rb = getVpValue(context, arg, false);
if (rb == null) {
IRubyObject cmp = callCoerced(context, sites(context).op_cmp, arg, false);
if ( cmp.isNil() ) { // arg.coerce failed
if (op == '*') return context.nil;
if (op == '=' || isNaN()) return context.fals;
throw context.runtime.newArgumentError("comparison of BigDecimal with "+ errMessageType(context, arg) +" failed");
String id = "!=";
switch (op) {
case '*':
if (falsyEqlCheck(context, arg)) return context.nil;
return callCoerced(context, sites(context).op_cmp, arg, false);
case '=': {
if (falsyEqlCheck(context, arg)) return context.fals;
IRubyObject res = callCoerced(context, sites(context).op_eql, arg, false);
return context.runtime.newBoolean(res != context.nil && res != context.fals);
}
case '!':
if (falsyEqlCheck(context, arg)) return context.tru;
/* id = "!="; */ break;
case 'G': id = ">="; break;
case 'L': id = "<="; break;
case '<': id = "<"; break;
case '>': id = ">"; break;
}
e = RubyNumeric.fix2int(cmp);
} else {
if (isNaN() || rb.isNaN()) return (op == '*') ? context.nil : context.fals;

e = infinitySign != 0 || rb.infinitySign != 0 ? infinitySign - rb.infinitySign : value.compareTo(rb.value);
IRubyObject cmp = callCoerced(context, id, arg);
if (cmp == context.nil) { // arg.coerce failed
throw context.runtime.newArgumentError("comparison of BigDecimal with "+ errMessageType(context, arg) +" failed");
}
return cmp;
}
switch(op) {

if (isNaN() || rb.isNaN()) return (op == '*') ? context.nil : context.fals;
e = infinitySign != 0 || rb.infinitySign != 0 ? infinitySign - rb.infinitySign : value.compareTo(rb.value);

switch (op) {
case '*': return context.runtime.newFixnum(e);
case '=': return context.runtime.newBoolean(e == 0);
case '!': return context.runtime.newBoolean(e != 0);
@@ -1363,18 +1382,30 @@ private IRubyObject cmp(ThreadContext context, final IRubyObject arg, final char
return context.nil;
}

// NOTE: otherwise `BD == nil` etc gets ___reeeaaally___ slow (due exception throwing)
private static boolean falsyEqlCheck(final ThreadContext context, final IRubyObject arg) {
return arg == context.nil || arg == context.fals || arg == context.tru;
}

@Override
@JRubyMethod(name = "<=>", required = 1)
public IRubyObject op_cmp(ThreadContext context, IRubyObject arg) {
return cmp(context, arg, '*');
}

// NOTE: do not use BigDecimal#equals since ZERO.equals(new BD('0.0')) -> false
@Override
@JRubyMethod(name = {"eql?", "==", "==="}, required = 1)
@JRubyMethod(name = {"eql?", "=="}, required = 1)
public IRubyObject eql_p(ThreadContext context, IRubyObject arg) {
return cmp(context, arg, '=');
}

@Override
@JRubyMethod(name = "===", required = 1) // same as == (eql?)
public IRubyObject op_eqq(ThreadContext context, IRubyObject arg) {
return cmp(context, arg, '=');
}

@JRubyMethod(name = "<", required = 1)
public IRubyObject op_lt(ThreadContext context, IRubyObject arg) {
return cmp(context, arg, '<');
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/runtime/JavaSites.java
Original file line number Diff line number Diff line change
@@ -369,6 +369,7 @@ public static class IRRuntimeHelpersSites {
public static class BigDecimalSites {
public final CallSite op_plus = new FunctionalCachingCallSite("+");
public final CallSite op_cmp = new FunctionalCachingCallSite("<=>");
public final CallSite op_eql = new FunctionalCachingCallSite("==");
public final CallSite divmod = new FunctionalCachingCallSite("divmod");
public final CallSite op_times = new FunctionalCachingCallSite("*");
public final CallSite div = new FunctionalCachingCallSite("div");
30 changes: 3 additions & 27 deletions core/src/main/java/org/jruby/util/ShellLauncher.java
Original file line number Diff line number Diff line change
@@ -411,38 +411,14 @@ private static File findPathFile(Ruby runtime, String fname, String[] path, bool
return pathFile;
}

/**
* This is an older version of the path-finding logic used by our pure-Java process launching in backquote,
* system, etc. The newer version below, used by native process launching, appears to break execution of commands
* in the current working directory, e.g. "./testapp".
*
* MRI: Older version of logic for dln_find_exe_r used by popen logic
*/
public static File findPathExecutable(Ruby runtime, String fname) {
RubyHash env = (RubyHash) runtime.getObject().getConstant("ENV");
IRubyObject pathObject = env.op_aref(runtime.getCurrentContext(), RubyString.newString(runtime, PATH_ENV));
String[] pathNodes = null;
if (pathObject == null) {
pathNodes = DEFAULT_PATH; // ASSUME: not modified by callee
}
else {
String pathSeparator = System.getProperty("path.separator");
String path = pathObject.toString();
if (Platform.IS_WINDOWS) {
// Windows-specific behavior
path = "." + pathSeparator + path;
}
pathNodes = path.split(pathSeparator);
}
return findPathFile(runtime, fname, pathNodes, true);
return findPathExecutable(runtime, fname, pathObject);
}

/**
* Search for the given executable using the given PATH or one provided by system defaults.
*
* This is the updated version of MRI: dln_find_exe_r logic.
*/
public static File dlnFindExe(Ruby runtime, String fname, IRubyObject pathObject) {
// MRI: Hopefully close to dln_find_exe_r used by popen logic
public static File findPathExecutable(Ruby runtime, String fname, IRubyObject pathObject) {
String[] pathNodes;

if (pathObject == null || pathObject.isNil()) {
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/util/io/PopenExecutor.java
Original file line number Diff line number Diff line change
@@ -2011,7 +2011,7 @@ public int compare(String o1, String o2) {
}

private static String dlnFindExeR(Ruby runtime, String fname, IRubyObject path) {
File exePath = ShellLauncher.dlnFindExe(runtime, fname, path);
File exePath = ShellLauncher.findPathExecutable(runtime, fname, path);
return exePath != null ? exePath.getAbsolutePath() : null;
}

14 changes: 14 additions & 0 deletions test/jruby/test_array.rb
Original file line number Diff line number Diff line change
@@ -62,4 +62,18 @@ def test_collect_concurrency
end
end

# GH-5141
def test_concat_self
arr = [1]
arr.concat(arr)
arr.concat(arr)
arr.concat(arr)
assert_equal [1, 1, 1, 1, 1, 1, 1, 1], arr

arr = [1, 2]
arr.concat(arr)
arr.concat(arr)
assert_equal [1, 2, 1, 2, 1, 2, 1, 2], arr
end

end
11 changes: 11 additions & 0 deletions test/jruby/test_big_decimal.rb
Original file line number Diff line number Diff line change
@@ -478,6 +478,17 @@ def test_new # from MRI test_bigdecimal.rb
assert_positive_infinite(BigDecimal("1E1111111111111111111"))
end

def test_eqq_eql
assert_equal false, BigDecimal('1000.0') == nil
assert_equal true, BigDecimal('11000.0') != nil
assert_equal true, BigDecimal('12000.0') != true
assert_equal false, BigDecimal('1000.0').eql?(false)
assert_equal false, BigDecimal('0.0000') === nil
assert_raise(ArgumentError) { BigDecimal('1.001') >= true }
assert_raise(ArgumentError) { BigDecimal('2.200') < false }
assert_raise(ArgumentError) { BigDecimal('3.003') >= nil }
end

private

def assert_nan(x)
1 change: 0 additions & 1 deletion test/mri/excludes/TestBigDecimal.rb
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@
exclude :test_BigMath_log_under_gc_stress, "needs investigation"
exclude :test_div, "does not pass due precision differences (ported to test/jruby/test_big_decimal.rb)"

exclude :test_global_new_with_invalid_string, "error change in 2.4?"
exclude :test_limit, "needs investigation"
exclude :test_marshal, "needs investigation"
exclude :test_new, "BigDecimal('_1_1_1') parses fine while in MRI raises"

0 comments on commit 242f976

Please sign in to comment.