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

Commits on Feb 3, 2016

  1. Unverified

    This user has not yet uploaded their public signing key.
    Copy the full SHA
    f95660f View commit details
  2. Copy the full SHA
    a814711 View commit details
  3. Copy the full SHA
    3cf9827 View commit details
  4. Copy the full SHA
    52f1c2f View commit details
  5. Copy the full SHA
    85426a6 View commit details
  6. Copy the full SHA
    5aba3d1 View commit details
  7. Copy the full SHA
    5550655 View commit details
  8. Copy the full SHA
    8fb9760 View commit details
  9. Copy the full SHA
    e205b99 View commit details
  10. [Truffle] Typo.

    chrisseaton committed Feb 3, 2016
    Copy the full SHA
    4ed43ea View commit details
  11. Copy the full SHA
    2e9bd7d View commit details
1 change: 1 addition & 0 deletions spec/truffle/tags/core/io/sync_tags.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
fails:IO#sync is false by default for STDOUT
fails:IO#sync is true by default for STDERR
3 changes: 3 additions & 0 deletions test/truffle/integration/backtraces.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

ruby -X+T test/truffle/integration/backtraces/backtraces.rb
90 changes: 90 additions & 0 deletions test/truffle/integration/backtraces/backtraces.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. This
# code is released under a tri EPL/GPL/LGPL license. You can use it,
# redistribute it and/or modify it under the terms of the:
#
# Eclipse Public License version 1.0
# GNU General Public License version 2
# GNU Lesser General Public License version 2.1

def check(expected)
begin
yield
rescue Exception => exception
actual = exception.backtrace
end

while actual.size < expected.size
actual.push '(missing)'
end

while expected.size < actual.size
expected.push '(missing)'
end

success = true

expected.zip(actual).each do |e, a|
unless a.end_with?(e)
puts "Expected #{e}, actually #{a}"
success = false
end
end

unless success
exit 1
end
end

def m1(count)
if count.zero?
raise 'm1-message'
else
m1(count - 1)
end
end

expected = [
"/backtraces.rb:40:in `m1'",
"/backtraces.rb:42:in `m1'",
"/backtraces.rb:42:in `m1'",
"/backtraces.rb:42:in `m1'",
"/backtraces.rb:42:in `m1'",
"/backtraces.rb:42:in `m1'",
"/backtraces.rb:59:in `block in <main>'",
"/backtraces.rb:11:in `check'",
"/backtraces.rb:58:in `<main>'"
]

check(expected) do
m1(5)
end

expected = [
"/backtraces.rb:85:in `block (5 levels) in <main>'",
"/backtraces.rb:77:in `m2'",
"/backtraces.rb:84:in `block (4 levels) in <main>'",
"/backtraces.rb:83:in `tap'",
"/backtraces.rb:83:in `block (3 levels) in <main>'",
"/backtraces.rb:82:in `each'",
"/backtraces.rb:82:in `block (2 levels) in <main>'",
"/backtraces.rb:81:in `each'",
"/backtraces.rb:81:in `block in <main>'",
"/backtraces.rb:11:in `check'",
"/backtraces.rb:80:in `<main>'"
]

def m2
yield
end

check(expected) do
[1].each do |n|
{a: 1}.each do |k, v|
true.tap do |t|
m2 do
raise 'm2-message'
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ public abstract class ExceptionNodes {

@TruffleBoundary
public static DynamicObject backtraceAsRubyStringArray(RubyContext context, DynamicObject exception, Backtrace backtrace) {
final List<String> lines = new BacktraceFormatter(context, EnumSet.of(BacktraceFormatter.FormattingFlags.OMIT_FROM_PREFIX))
final List<String> lines = new BacktraceFormatter(context, EnumSet.of(BacktraceFormatter.FormattingFlags.OMIT_FROM_PREFIX, BacktraceFormatter.FormattingFlags.OMIT_EXCEPTION))
.formatBacktrace(context, exception, backtrace);

final Object[] array = new Object[lines.size()];
Original file line number Diff line number Diff line change
@@ -841,7 +841,7 @@ private RubyNode openModule(SourceSection sourceSection, RubyNode defineOrGetNod
}

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParseEnvironment(),
returnId, true, true, sharedMethodInfo, name, false, null);
returnId, true, true, sharedMethodInfo, name, 0, null);

final BodyTranslator moduleTranslator = new BodyTranslator(currentNode, context, this, newEnvironment, source, false);

@@ -1211,7 +1211,7 @@ protected RubyNode translateMethodDefinition(SourceSection sourceSection, RubyNo
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, environment.getLexicalScope(), arity, methodName, false, argumentDescriptors, false, false, false);

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(
context, environment, environment.getParseEnvironment(), environment.getParseEnvironment().allocateReturnID(), true, true, sharedMethodInfo, methodName, false, null);
context, environment, environment.getParseEnvironment(), environment.getParseEnvironment().allocateReturnID(), true, true, sharedMethodInfo, methodName, 0, null);

// ownScopeForAssignments is the same for the defined method as the current one.

@@ -1842,7 +1842,7 @@ private RubyNode translateBlockLikeNode(org.jruby.ast.IterNode node, boolean isL

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(
context, environment, parseEnvironment, returnID, hasOwnScope, false,
sharedMethodInfo, namedMethodName, true, parseEnvironment.allocateBreakID());
sharedMethodInfo, namedMethodName, environment.getBlockDepth() + 1, parseEnvironment.allocateBreakID());
final MethodTranslator methodCompiler = new MethodTranslator(currentNode, context, this, newEnvironment, true, source, argsNode);

if (isProc) {
@@ -3019,7 +3019,11 @@ protected String getIdentifier() {
methodParent = methodParent.getParent();
}

return "block in " + methodParent.getNamedMethodName();
if (environment.getBlockDepth() > 1) {
return String.format("block (%d levels) in %s", environment.getBlockDepth(), methodParent.getNamedMethodName());
} else {
return String.format("block in %s", methodParent.getNamedMethodName());
}
} else {
return environment.getNamedMethodName();
}
Original file line number Diff line number Diff line change
@@ -135,7 +135,7 @@ private RubyRootNode parse(Node currentNode, RubyContext context, Source source,
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, parseEnvironment.getLexicalScope(), Arity.NO_ARGUMENTS, "<main>", false, null, false, false, false);

final TranslatorEnvironment environment = new TranslatorEnvironment(context, environmentForFrame(context, parentFrame),
parseEnvironment, parseEnvironment.allocateReturnID(), ownScopeForAssignments, false, sharedMethodInfo, sharedMethodInfo.getName(), false, null);
parseEnvironment, parseEnvironment.allocateReturnID(), ownScopeForAssignments, false, sharedMethodInfo, sharedMethodInfo.getName(), 0, null);

// Declare arguments as local variables in the top-level environment - we'll put the values there in a prelude

@@ -212,7 +212,7 @@ private TranslatorEnvironment environmentForFrame(RubyContext context, Materiali
final MaterializedFrame parent = RubyArguments.getDeclarationFrame(frame.getArguments());
// TODO(CS): how do we know if the frame is a block or not?
return new TranslatorEnvironment(context, environmentForFrame(context, parent), parseEnvironment,
parseEnvironment.allocateReturnID(), true, true, sharedMethodInfo, sharedMethodInfo.getName(), false, null, frame.getFrameDescriptor());
parseEnvironment.allocateReturnID(), true, true, sharedMethodInfo, sharedMethodInfo.getName(), 0, null, frame.getFrameDescriptor());
}
}

Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ public class TranslatorEnvironment {
private final List<FrameSlot> flipFlopStates = new ArrayList<>();

private final ReturnID returnID;
private final boolean isBlock;
private final int blockDepth;
private BreakID breakID;

private final boolean ownScopeForAssignments;
@@ -55,7 +55,7 @@ public class TranslatorEnvironment {

public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent, ParseEnvironment parseEnvironment,
ReturnID returnID, boolean ownScopeForAssignments, boolean neverAssignInParentScope,
SharedMethodInfo sharedMethodInfo, String namedMethodName, boolean isBlock, BreakID breakID,
SharedMethodInfo sharedMethodInfo, String namedMethodName, int blockDepth, BreakID breakID,
FrameDescriptor frameDescriptor) {
this.context = context;
this.parent = parent;
@@ -66,14 +66,14 @@ public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent,
this.neverAssignInParentScope = neverAssignInParentScope;
this.sharedMethodInfo = sharedMethodInfo;
this.namedMethodName = namedMethodName;
this.isBlock = isBlock;
this.blockDepth = blockDepth;
this.breakID = breakID;
}

public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent, ParseEnvironment parseEnvironment,
ReturnID returnID, boolean ownScopeForAssignments, boolean neverAssignInParentScope,
SharedMethodInfo methodIdentifier, String namedMethodName, boolean isBlock, BreakID breakID) {
this(context, parent, parseEnvironment, returnID, ownScopeForAssignments, neverAssignInParentScope, methodIdentifier, namedMethodName, isBlock, breakID,
SharedMethodInfo methodIdentifier, String namedMethodName, int blockDepth, BreakID breakID) {
this(context, parent, parseEnvironment, returnID, ownScopeForAssignments, neverAssignInParentScope, methodIdentifier, namedMethodName, blockDepth, breakID,
new FrameDescriptor(context.getCoreLibrary().getNilObject()));
}

@@ -107,7 +107,7 @@ public FrameSlot declareVar(String name) {
}

public FrameSlot declareVarWhereAllowed(String name) {
if (isBlock) {
if (isBlock()) {
return parent.declareVarWhereAllowed(name);
} else {
return declareVar(name);
@@ -216,7 +216,11 @@ public String getNamedMethodName() {
}

public boolean isBlock() {
return isBlock;
return blockDepth > 0;
}

public int getBlockDepth() {
return blockDepth;
}

public BreakID getBreakID() {
32 changes: 29 additions & 3 deletions truffle/src/main/java/org/jruby/truffle/runtime/RubyCallStack.java
Original file line number Diff line number Diff line change
@@ -16,8 +16,10 @@
import com.oracle.truffle.api.frame.FrameInstanceVisitor;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.language.arguments.RubyArguments;
import org.jruby.truffle.language.exceptions.DisablingBacktracesNode;
import org.jruby.truffle.nodes.LazyRubyRootNode;
import org.jruby.truffle.runtime.backtrace.Activation;
import org.jruby.truffle.runtime.backtrace.Backtrace;
import org.jruby.truffle.core.CoreSourceSection;
@@ -101,9 +103,7 @@ public Object visitFrame(FrameInstance frameInstance) {
return new Object();
}

// Multiple top level methods (require) introduce null call nodes - ignore them

if (frameInstance.getCallNode() != null && depth >= omit) {
if (!ignoreFrame(frameInstance) && depth >= omit) {
if (!filterNullSourceSection || !(frameInstance.getCallNode().getEncapsulatingSourceSection() == null || frameInstance.getCallNode().getEncapsulatingSourceSection().getSource() == null)) {
activations.add(new Activation(frameInstance.getCallNode(),
frameInstance.getFrame(FrameInstance.FrameAccess.MATERIALIZE, true).materialize()));
@@ -120,6 +120,32 @@ public Object visitFrame(FrameInstance frameInstance) {
return new Backtrace(activations.toArray(new Activation[activations.size()]));
}

private static boolean ignoreFrame(FrameInstance frameInstance) {
final Node callNode = frameInstance.getCallNode();

// Nodes with no call node are top-level - we may have multiple of them due to require

if (callNode == null) {
return true;
}

// Ignore the call to run_jruby_root

// TODO CS 2-Feb-16 should find a better way to detect this than a string

final SourceSection sourceSection = callNode.getEncapsulatingSourceSection();

if (sourceSection != null && sourceSection.getSource() != null && sourceSection.getSource().getName().equals("run_jruby_root")) {
return true;
}

if (callNode.getRootNode() instanceof LazyRubyRootNode) {
return true;
}

return false;
}

public static Node getTopMostUserCallNode() {
CompilerAsserts.neverPartOfCompilation();

Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.language.arguments.RubyArguments;
@@ -33,6 +34,7 @@ public class BacktraceFormatter {
public static final String OMITTED_UNUSED = "(omitted as the rescue expression was pure; use -Xtruffle.backtraces.omit_for_unused=false to disable)";

public enum FormattingFlags {
OMIT_EXCEPTION,
OMIT_FROM_PREFIX,
INCLUDE_CORE_FILES
}
@@ -138,7 +140,7 @@ private String formatInLine(List<Activation> activations, DynamicObject exceptio
builder.append("'");
}

if (exception != null) {
if (!flags.contains(FormattingFlags.OMIT_EXCEPTION) && exception != null) {
String message;
try {
Object messageObject = context.send(exception, "message", null);
@@ -236,7 +238,23 @@ private SourceSection nextUserSourceSection(List<Activation> activations, int n)
}

private boolean isCore(SourceSection sourceSection) {
return sourceSection == null || sourceSection.getSource() == null || (sourceSection.getSource().getPath() != null && sourceSection.getSource().getPath().startsWith(SourceLoader.TRUFFLE_SCHEME));
if (sourceSection == null) {
return true;
}

final Source source = sourceSection.getSource();

if (source == null) {
return true;
}

final String path = source.getPath();

if (path == null) {
return true;
}

return path.startsWith(SourceLoader.TRUFFLE_SCHEME);
}

}