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

Commits on Jun 14, 2018

  1. Fixes #5162. Thread::Backtrace::Location#base_label for blocks differ…

    …s from MRI.
    
    This fix is not quite what I would have liked but I think the other issue we
    will need to consider at some point is that this data is not m17n safe.  So
    when we decide to fix that we will need to mangle differently and probably will
    be able to clean up this a bit.
    enebo committed Jun 14, 2018
    Copy the full SHA
    9bfd29f View commit details
  2. Fixes #5163. When Thread::Backtrace::Location#base_label and #label a…

    …re #== on MRI they are also #equal?
    
    Our desire for laziness was the cause of this issue.  In the future we will
    migrate to using symbol for methodNames to fully support M17n and this fix
    ickiness will be able to be deleted.  Largely we use basename for all cases
    except blocks.  In either case we save off the string we make so the equality
    property is preserved.
    
    With symbols the strings we have will always end up as the same string and
    equality will also be true.  The amount of API changes is a bit too much to
    do the m17n work now.
    enebo committed Jun 14, 2018
    Copy the full SHA
    d23a619 View commit details
  3. Whoops reversed logic.

    enebo committed Jun 14, 2018
    Copy the full SHA
    a60b38d View commit details
14 changes: 12 additions & 2 deletions core/src/main/java/org/jruby/RubyThread.java
Original file line number Diff line number Diff line change
@@ -78,6 +78,7 @@
import org.jruby.runtime.ObjectMarshal;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.ExecutionContext;
import org.jruby.runtime.backtrace.FrameType;
import org.jruby.runtime.backtrace.RubyStackTraceElement;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
@@ -462,6 +463,9 @@ public static RubyClass createThreadClass(Ruby runtime) {
}

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

public Location(Ruby runtime, RubyClass klass, RubyStackTraceElement element) {
super(runtime, klass);
this.element = element;
@@ -474,7 +478,8 @@ public IRubyObject absolute_path(ThreadContext context) {

@JRubyMethod
public IRubyObject base_label(ThreadContext context) {
return context.runtime.newString(element.getMethodName());
if (baseLabel == null) baseLabel = context.runtime.newString(element.getMethodName());
return baseLabel;
}

@JRubyMethod
@@ -484,7 +489,12 @@ public IRubyObject inspect(ThreadContext context) {

@JRubyMethod
public IRubyObject label(ThreadContext context) {
return context.runtime.newString(element.getMethodName());
if (element.getFrameType() == FrameType.BLOCK) {
if (label == null) label = context.runtime.newString("block in " + element.getMethodName());
return label;
}

return base_label(context);
}

@JRubyMethod
32 changes: 19 additions & 13 deletions core/src/main/java/org/jruby/runtime/backtrace/BacktraceData.java
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class BacktraceData implements Serializable {
@@ -73,19 +74,24 @@ private RubyStackTraceElement[] constructBacktrace(Map<String, Map<String, Strin
// Don't process .java files
if (!filename.endsWith(".java")) {

String decodedName = JavaNameMangler.decodeMethodForBacktrace(methodName);
List<String> mangledTuple = JavaNameMangler.decodeMethodTuple(methodName);
if (mangledTuple != null) {
FrameType type = JavaNameMangler.decodeFrameTypeFromMangledName(mangledTuple.get(1));
String decodedName = JavaNameMangler.decodeMethodName(type, mangledTuple);

if (decodedName != null) {
// construct Ruby trace element
RubyStackTraceElement rubyElement = new RubyStackTraceElement(className, decodedName, filename, line, false);
if (decodedName != null) {
// construct Ruby trace element
RubyStackTraceElement rubyElement = new RubyStackTraceElement(className, decodedName, filename, line, false, type);

// add duplicate if masking native and previous frame was native (Kernel#caller)
if (maskNative && dupFrame) {
dupFrame = false;
trace.add(new RubyStackTraceElement(className, dupFrameName, filename, line, false, type));
}
trace.add(rubyElement);
continue;

// add duplicate if masking native and previous frame was native (Kernel#caller)
if (maskNative && dupFrame) {
dupFrame = false;
trace.add(new RubyStackTraceElement(className, dupFrameName, filename, line, false));
}
trace.add(rubyElement);
continue;
}
}
}
@@ -122,20 +128,20 @@ private RubyStackTraceElement[] constructBacktrace(Map<String, Map<String, Strin
final String newName;
switch (frameType) {
case METHOD: newName = rubyFrame.method; break;
case BLOCK: newName = "block in " + rubyFrame.method; break;
case BLOCK: newName = rubyFrame.method; break;
case CLASS: newName = "<class:" + rubyFrame.method + '>'; break;
case MODULE: newName = "<module:" + rubyFrame.method + '>'; break;
case METACLASS: newName = "singleton class"; break;
case ROOT: newName = "<main>"; break;
case EVAL: newName = "<eval>"; break;
default: newName = rubyFrame.method;
}
RubyStackTraceElement rubyElement = new RubyStackTraceElement("RUBY", newName, rubyFrame.filename, rubyFrame.line + 1, false);
RubyStackTraceElement rubyElement = new RubyStackTraceElement("RUBY", newName, rubyFrame.filename, rubyFrame.line + 1, false, frameType);

// dup if masking native and previous frame was native
if (maskNative && dupFrame) {
dupFrame = false;
trace.add(new RubyStackTraceElement(rubyElement.getClassName(), dupFrameName, rubyElement.getFileName(), rubyElement.getLineNumber(), rubyElement.isBinding()));
trace.add(new RubyStackTraceElement(rubyElement.getClassName(), dupFrameName, rubyElement.getFileName(), rubyElement.getLineNumber(), rubyElement.isBinding(), rubyElement.getFrameType()));
}
trace.add(rubyElement);

41 changes: 36 additions & 5 deletions core/src/main/java/org/jruby/util/JavaNameMangler.java
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@
import org.jruby.ir.IRScope;
import org.jruby.ir.IRScriptBody;
import org.jruby.platform.Platform;
import org.jruby.runtime.backtrace.FrameType;

import java.io.IOException;
import java.util.List;
@@ -315,12 +316,9 @@ public static String encodeScopeForBacktrace(IRScope scope) {

public static final String VARARGS_MARKER = "$__VARARGS__";

@Deprecated
public static String decodeMethodForBacktrace(String methodName) {
if (!methodName.startsWith("RUBY$")) return null;

if (methodName.contains(VARARGS_MARKER)) return null;

final List<String> name = StringSupport.split(methodName, '$');
final List<String> name = decodeMethodTuple(methodName);
final String type = name.get(1); // e.g. RUBY $ class $ methodName
// root body gets named (root)
switch (type) {
@@ -334,4 +332,37 @@ public static String decodeMethodForBacktrace(String methodName) {
}
throw new IllegalStateException("unknown encoded method type '" + type + "' from " + methodName);
}

// returns location $ type $ methodName as 3 elements or null if this is an invalid mangled name
public static List<String> decodeMethodTuple(String methodName) {
if (!methodName.startsWith("RUBY$") || methodName.contains(VARARGS_MARKER)) return null;

return StringSupport.split(methodName, '$');
}

public static String decodeMethodName(FrameType type, List<String> mangledTuple) {
switch (type) {
case ROOT: return "<main>";
case METACLASS: return "singleton class";
case METHOD: return demangleMethodName(mangledTuple.get(2));
case BLOCK: return ""+demangleMethodNameInternal(mangledTuple.get(2));
case CLASS: return "<class:" + demangleMethodNameInternal(mangledTuple.get(2)) + '>';
case MODULE: return "<module:" + demangleMethodNameInternal(mangledTuple.get(2)) + '>';
}

return null; // not-reached
}

public static FrameType decodeFrameTypeFromMangledName(String type) {
switch (type) {
case "script": return FrameType.ROOT;
case "metaclass": return FrameType.METACLASS;
case "method": return FrameType.METHOD;
case "block": return FrameType.BLOCK;
case "class": return FrameType.MODULE;
case "module": return FrameType.CLASS;
}
throw new IllegalStateException("unknown encoded method type '" + type);

}
}