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

Commits on Jun 18, 2018

  1. Copy the full SHA
    154555d View commit details
  2. [refactor] warn() backtrace generation

    trace-type could eventually optimize stack-trace retrieval
    kares committed Jun 18, 2018
    Copy the full SHA
    42446f8 View commit details
  3. [fix] regression on printing backtrace (location)

    "block in" part missing from backtrace() elements
    as well as in location.to_s
    
    regressed due 9bfd29f
    (also added some tests for related issues)
    kares committed Jun 18, 2018
    Copy the full SHA
    f87acc5 View commit details
34 changes: 15 additions & 19 deletions core/src/main/java/org/jruby/RubyKernel.java
Original file line number Diff line number Diff line change
@@ -65,7 +65,6 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.backtrace.BacktraceElement;
import org.jruby.runtime.backtrace.RubyStackTraceElement;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ArraySupport;
@@ -88,6 +87,7 @@

import static org.jruby.RubyBasicObject.UNDEF;
import static org.jruby.RubyEnumerator.enumeratorizeWithSize;
import static org.jruby.RubyInteger.singleCharByteList;
import static org.jruby.anno.FrameField.BLOCK;
import static org.jruby.anno.FrameField.FILENAME;
import static org.jruby.anno.FrameField.LASTLINE;
@@ -1227,37 +1227,38 @@ private static RaiseException uncaughtThrow(Ruby runtime, IRubyObject tag, IRuby

@JRubyMethod(module = true, visibility = PRIVATE)
public static IRubyObject warn(ThreadContext context, IRubyObject recv, IRubyObject _message) {
final Ruby runtime = context.runtime;

if (_message instanceof RubyArray) {
RubyArray messageArray = _message.convertToArray();
for (int i = 0; i < messageArray.size(); i++) warn(context, recv, messageArray.eltOk(i));
return context.nil;
}

RubyString message = _message.convertToString();
return warn(context, recv, _message.convertToString());
}

static IRubyObject warn(ThreadContext context, IRubyObject recv, RubyString message) {
final Ruby runtime = context.runtime;

if (!message.endsWithAsciiChar('\n')) {
message = (RubyString) message.op_plus19(context, runtime.newString("\n"));
message = (RubyString) message.op_plus19(context, runtime.newString(singleCharByteList((byte) '\n')));
}

if (recv == runtime.getWarning()) {
return RubyWarnings.warn(context, recv, message);
} else {
return sites(context).warn.call(context, recv, runtime.getWarning(), message);
}
return sites(context).warn.call(context, recv, runtime.getWarning(), message);
}

public static final String[] WARN_VALID_KEYS = {"uplevel"};
public static final String[] WARN_VALID_KEYS = { "uplevel" };

@JRubyMethod(module = true, rest = true, visibility = PRIVATE)
public static IRubyObject warn(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;

boolean kwargs = false;
int uplevel = -1;

if (args.length > 1) {
IRubyObject tmp = TypeConverter.checkHashType(context.runtime, args[args.length - 1]);
if (!tmp.isNil()) {
if (tmp != context.nil) {
kwargs = true;
IRubyObject[] rets = ArgsUtil.extractKeywordArgs(context, (RubyHash) tmp, WARN_VALID_KEYS);
uplevel = rets[0] == UNDEF ? 0 : RubyNumeric.num2int(rets[0]);
@@ -1266,20 +1267,15 @@ public static IRubyObject warn(ThreadContext context, IRubyObject recv, IRubyObj

// FIXME: This is not particularly efficient.
int numberOfMessages = kwargs ? args.length - 1 : args.length;
IRubyObject newline = runtime.newString("\n");

if (kwargs) {
RubyStackTraceElement[] elements = context.runtime.getInstanceConfig().getTraceType().getBacktrace(context).getBacktrace(context.runtime);

// User can ask for level higher than stack
if (elements.length <= uplevel + 1) uplevel = -1;
RubyStackTraceElement element = context.runtime.getInstanceConfig().getTraceType().getBacktraceElement(context, uplevel);

int index = uplevel + 1;
RubyString baseMessage = context.runtime.newString();
baseMessage.catString(elements[index].getFileName() + ":" + (elements[index].getLineNumber()) + ": warning: ");
baseMessage.catString(element.getFileName() + ':' + element.getLineNumber() + ": warning: ");

for (int i = 0; i < numberOfMessages; i++) {
warn(context, recv, baseMessage.op_plus19(context, args[i]));
warn(context, recv, (RubyString) baseMessage.op_plus19(context, args[i]));
}
} else {
for (int i = 0; i < numberOfMessages; i++) {
9 changes: 6 additions & 3 deletions core/src/main/java/org/jruby/RubyThread.java
Original file line number Diff line number Diff line change
@@ -463,8 +463,11 @@ public static RubyClass createThreadClass(Ruby runtime) {
}

public static class Location extends RubyObject {
private RubyString baseLabel = null;
private RubyString label = null;

private final RubyStackTraceElement element;

private transient RubyString baseLabel = null;
private transient RubyString label = null;

public Location(Ruby runtime, RubyClass klass, RubyStackTraceElement element) {
super(runtime, klass);
@@ -490,6 +493,7 @@ public IRubyObject inspect(ThreadContext context) {
@JRubyMethod
public IRubyObject label(ThreadContext context) {
if (element.getFrameType() == FrameType.BLOCK) {
// NOTE: "block in " + ... logic, now, also at RubyStackTraceElement.to_s_mri
if (label == null) label = context.runtime.newString("block in " + element.getMethodName());
return label;
}
@@ -528,7 +532,6 @@ public static RubyArray newLocationArray(Ruby runtime, RubyStackTraceElement[] e
return RubyArray.newArrayNoCopy(runtime, ary);
}

private final RubyStackTraceElement element;
}

/**
Original file line number Diff line number Diff line change
@@ -3,7 +3,9 @@
import org.jruby.RubyString;
import org.jruby.RubySymbol;
import org.jruby.runtime.ThreadContext;
import org.jruby.util.ByteList;
import org.jruby.util.CommonByteLists;
import org.jruby.util.ConvertBytes;

public class RubyStackTraceElement implements java.io.Serializable {
public static final RubyStackTraceElement[] EMPTY_ARRAY = new RubyStackTraceElement[0];
@@ -79,15 +81,17 @@ public String toString() {

public static RubyString to_s_mri(ThreadContext context, RubyStackTraceElement element) {
RubySymbol methodSym = context.runtime.newSymbol(element.getMethodName());
RubyString line = context.runtime.newString();
RubyString line = context.runtime.newString(new ByteList(methodSym.getBytes().length() + element.getFileName().length() + 18));

line.setEncoding(methodSym.getEncoding());

line.cat(element.getFileName().getBytes());
line.cat(CommonByteLists.COLON);
line.append(context.runtime.newFixnum(element.getLineNumber()));
line.cat(ConvertBytes.longToByteList(element.getLineNumber()));
line.cat(CommonByteLists.BACKTRACE_IN);
if (element.getFrameType() == FrameType.BLOCK) line.catString("block in ");
line.cat(methodSym.getBytes());
line.cat(new byte[] {'\''});
line.cat('\'');

return line;
}
18 changes: 10 additions & 8 deletions core/src/main/java/org/jruby/runtime/backtrace/TraceType.java
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@
import org.jruby.RubyClass;
import org.jruby.RubyException;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyString;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.log.Logger;
@@ -45,6 +44,16 @@ public BacktraceData getBacktrace(ThreadContext context) {
return gather.getBacktraceData(context);
}

public RubyStackTraceElement getBacktraceElement(ThreadContext context, int uplevel) {
// NOTE: could be optimized not to walk the whole stack
RubyStackTraceElement[] elements = getBacktrace(context).getBacktrace(context.runtime);

// User can ask for level higher than stack
if (elements.length <= uplevel + 1) uplevel = -1;

return elements[uplevel + 1];
}

/**
* Get an integrated Ruby/Java backtrace if the current Gather type is NORMAL
*
@@ -69,13 +78,6 @@ public static void logBacktrace(Ruby runtime, RubyStackTraceElement[] trace) {

renderBacktraceJRuby(runtime, trace, buffer, false);

// NOTE: other logXxx method do not remove the new-line
// ... but if this is desired they should do so as well
//final int len = buffer.length();
//if ( len > 0 && buffer.charAt(len - 1) == '\n' ) {
// buffer.setLength(len - 1); // remove last '\n'
//}

LOG.info(buffer.toString());
}

28 changes: 26 additions & 2 deletions test/jruby/test_thread_backtrace.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'test/unit'

class TestThreadBacktrace < Test::Unit::TestCase

def test_simple_backtrace
backtrace = Thread.new do
begin
@@ -11,9 +12,9 @@ def test_simple_backtrace
end.value

if $0 == __FILE__
expected = [ /test\/jruby\/test_thread_backtrace\.rb:7:in `block in test_simple_backtrace'/ ]
expected = [ /test\/jruby\/test_thread_backtrace\.rb:8:in `block in test_simple_backtrace'/ ]
else
expected = [ /test\/jruby\/test_thread_backtrace\.rb:7:in `block in test_simple_backtrace'/ ]
expected = [ /test\/jruby\/test_thread_backtrace\.rb:8:in `block in test_simple_backtrace'/ ]
end

puts " " + backtrace.join("\n ") if $VERBOSE
@@ -23,4 +24,27 @@ def test_simple_backtrace
"mismatched traces: #{backtrace[index].inspect} did not match #{pattern.inspect}"
end
end

def test_backtrace_location_label # GH-5162
[__method__].map do
location = Thread.current.backtrace_locations[1]
assert_equal 'test_backtrace_location_label', location.base_label
assert_equal 'block in test_backtrace_location_label', location.label
end
end


def test_backtrace_location_label_equal # GH-5163
location = Thread.current.backtrace_locations[1]
assert_equal __method__.to_s, location.base_label
assert_equal __method__.to_s, location.label
assert location.base_label.equal?(location.label)

assert_end_with "test/jruby/test_thread_backtrace.rb:38:in `test_backtrace_location_label_equal'", location.to_s
end

def assert_end_with(exp, str)
assert_operator str, :end_with?, exp
end

end