Skip to content

Commit

Permalink
[Truffle] Improve #throw.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed Oct 9, 2014
1 parent 52968be commit 25a1473
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 45 deletions.
61 changes: 31 additions & 30 deletions core/src/main/java/org/jruby/truffle/TruffleBridgeImpl.java
Expand Up @@ -23,10 +23,8 @@
import org.jruby.truffle.runtime.NilPlaceholder;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.backtrace.Backtrace;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyException;
import org.jruby.truffle.runtime.util.Supplier;
import org.jruby.truffle.translator.TranslatorDriver;

import java.io.IOException;
Expand Down Expand Up @@ -92,42 +90,45 @@ public TruffleMethod truffelize(DynamicMethod originalMethod, org.jruby.ast.Args
}

@Override
public Object execute(TranslatorDriver.ParserContext parserContext, Object self, MaterializedFrame parentFrame, org.jruby.ast.RootNode rootNode) {
try {
final String inputFile = rootNode.getPosition().getFile();
public Object execute(final TranslatorDriver.ParserContext parserContext, final Object self, final MaterializedFrame parentFrame, final org.jruby.ast.RootNode rootNode) {
return truffleContext.handlingTopLevelRaise(new Supplier<Object>() {

final Source source;
@Override
public Object get() {
return truffleContext.handlingTopLevelThrow(new Supplier<Object>() {

if (inputFile.equals("-e")) {
// Assume UTF-8 for the moment
source = Source.fromBytes(runtime.getInstanceConfig().inlineScript(), "-e", new BytesDecoder.UTF8BytesDecoder());
} else {
final byte[] bytes;
@Override
public Object get() {
final String inputFile = rootNode.getPosition().getFile();

try {
bytes = Files.readAllBytes(Paths.get(inputFile));
} catch (IOException e) {
throw new RuntimeException(e);
}
final Source source;

// Assume UTF-8 for the moment
if (inputFile.equals("-e")) {
// Assume UTF-8 for the moment
source = Source.fromBytes(runtime.getInstanceConfig().inlineScript(), "-e", new BytesDecoder.UTF8BytesDecoder());
} else {
final byte[] bytes;

source = Source.fromBytes(bytes, inputFile, new BytesDecoder.UTF8BytesDecoder());
}
try {
bytes = Files.readAllBytes(Paths.get(inputFile));
} catch (IOException e) {
throw new RuntimeException(e);
}

// Assume UTF-8 for the moment

final RubyRootNode parsedRootNode = truffleContext.getTranslator().parse(truffleContext, source, parserContext, parentFrame, null);
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(parsedRootNode);
return callTarget.call(RubyArguments.pack(null, parentFrame, self, null, new Object[]{}));
} catch (RaiseException e) {
// TODO(CS): what's this cast about?
final RubyException rubyException = (RubyException) e.getRubyException();
source = Source.fromBytes(bytes, inputFile, new BytesDecoder.UTF8BytesDecoder());
}

for (String line : Backtrace.DISPLAY_FORMATTER.format(truffleContext, rubyException, rubyException.getBacktrace())) {
System.err.println(line);
final RubyRootNode parsedRootNode = truffleContext.getTranslator().parse(truffleContext, source, parserContext, parentFrame, null);
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(parsedRootNode);
return callTarget.call(RubyArguments.pack(null, parentFrame, self, null, new Object[]{}));
}

});
}

return NilPlaceholder.INSTANCE;
}
}, NilPlaceholder.INSTANCE);
}

@Override
Expand Down
Expand Up @@ -29,6 +29,7 @@
import org.jruby.truffle.nodes.literal.*;
import org.jruby.truffle.nodes.yield.*;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.backtrace.Backtrace;
import org.jruby.truffle.runtime.control.*;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.core.RubyArray;
Expand Down Expand Up @@ -1791,9 +1792,9 @@ public Object doThrow(Object tag, Object value) {
notDesignedForCompilation();

if (value instanceof UndefinedPlaceholder) {
throw new ThrowException(tag, NilPlaceholder.INSTANCE);
throw new ThrowException(tag, NilPlaceholder.INSTANCE, RubyCallStack.getBacktrace(this));
} else {
throw new ThrowException(tag, value);
throw new ThrowException(tag, value, RubyCallStack.getBacktrace(this));
}
}

Expand Down
25 changes: 25 additions & 0 deletions core/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Expand Up @@ -29,10 +29,12 @@
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.debug.RubyASTProber;
import org.jruby.truffle.runtime.backtrace.Backtrace;
import org.jruby.truffle.runtime.control.*;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyBinding;
import org.jruby.truffle.runtime.core.RubyException;
import org.jruby.truffle.runtime.core.RubyModule;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.truffle.runtime.core.RubySymbol;
Expand Down Expand Up @@ -376,4 +378,27 @@ public Warnings getWarnings() {
return warnings;
}

public <T> T handlingTopLevelThrow(Supplier<T> run) {
try {
return run.get();
} catch (ThrowException e) {
throw new RaiseException(new RubyException(coreLibrary.getArgumentErrorClass(), makeString(String.format("uncaught throw \"%s\"", e.getTag())), e.getBacktrace()));
}
}

public <T> T handlingTopLevelRaise(Supplier<T> run, T defaultValue) {
try {
return run.get();
} catch (RaiseException e) {
// TODO(CS): what's this cast about?
final RubyException rubyException = (RubyException) e.getRubyException();

for (String line : Backtrace.DISPLAY_FORMATTER.format(this, rubyException, rubyException.getBacktrace())) {
System.err.println(line);
}

return defaultValue;
}
}

}
Expand Up @@ -11,6 +11,7 @@

import com.oracle.truffle.api.nodes.*;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.backtrace.Backtrace;

/**
* Controls throwing a value. Note that throwing is different to raising in Ruby, which is the
Expand All @@ -20,13 +21,15 @@ public class ThrowException extends ControlFlowException {

private final Object tag;
private final Object value;
private final Backtrace backtrace;

public ThrowException(Object tag, Object value) {
public ThrowException(Object tag, Object value, Backtrace backtrace) {
assert tag != null;
assert RubyContext.shouldObjectBeVisible(value);

this.tag = tag;
this.value = value;
this.backtrace = backtrace;
}

public Object getTag() {
Expand All @@ -37,6 +40,10 @@ public Object getValue() {
return value;
}

public Backtrace getBacktrace() {
return backtrace;
}

private static final long serialVersionUID = 8693305627979840677L;

}
Expand Up @@ -432,7 +432,7 @@ public RubyException argumentError(int passed, int required, Node currentNode) {
}

public RubyException localJumpError(String message, Node currentNode) {
return new RubyException(localJumpErrorClass, context.makeString(String.format("%s", message)), RubyCallStack.getBacktrace(currentNode));
return new RubyException(localJumpErrorClass, context.makeString(message), RubyCallStack.getBacktrace(currentNode));
}

public RubyException unexpectedReturn(Node currentNode) {
Expand Down Expand Up @@ -714,4 +714,8 @@ public RubyClass getIntegerClass() {
public RubiniusLibrary getRubiniusLibrary() {
return rubiniusLibrary;
}

public RubyClass getArgumentErrorClass() {
return argumentErrorClass;
}
}
25 changes: 17 additions & 8 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyThread.java
Expand Up @@ -16,6 +16,7 @@
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.control.ReturnException;
import org.jruby.truffle.runtime.subsystems.*;
import org.jruby.truffle.runtime.util.Supplier;

/**
* Represents the Ruby {@code Thread} class. Implemented using Java threads, but note that there is
Expand Down Expand Up @@ -57,21 +58,17 @@ public RubyThread(RubyClass rubyClass, ThreadManager manager) {
public void initialize(final RubyNode currentNode, RubyProc block) {
final RubyProc finalBlock = block;

initialize(new Runnable() {
initialize(currentNode, new Runnable() {

@Override
public void run() {
try {
finalBlock.rootCall();
} catch (ReturnException e) {
exception = getContext().getCoreLibrary().unexpectedReturn(currentNode);
}
finalBlock.rootCall();
}

});
}

public void initialize(Runnable runnable) {
public void initialize(final RubyNode currentNode, Runnable runnable) {
final RubyThread finalThread = this;
final Runnable finalRunnable = runnable;

Expand All @@ -83,7 +80,19 @@ public void run() {
finalThread.manager.enterGlobalLock(finalThread);

try {
finalRunnable.run();
getContext().handlingTopLevelThrow(new Supplier<Void>() {

@Override
public Void get() {
finalRunnable.run();
return null;
}

});
} catch (RaiseException e) {
exception = (RubyException) e.getRubyException();
} catch (ReturnException e) {
exception = getContext().getCoreLibrary().unexpectedReturn(currentNode);
} finally {
finalThread.manager.leaveGlobalLock();
finalThread.manager.unregisterThread(finalThread);
Expand Down
Expand Up @@ -94,7 +94,7 @@ public void defineFinalizer(RubyBasicObject object, RubyProc proc) {

finalizerThread = new RubyThread(context.getCoreLibrary().getThreadClass(), context.getThreadManager());

finalizerThread.initialize(new Runnable() {
finalizerThread.initialize(null, new Runnable() {

@Override
public void run() {
Expand Down
2 changes: 0 additions & 2 deletions spec/truffle/tags/language/throw_tags.txt
@@ -1,4 +1,2 @@
fails:The throw keyword does not convert strings to a symbol
fails:The throw keyword raises an ArgumentError if outside of scope of a matching catch
fails:The throw keyword raises a ArgumentError if used to exit a thread
fails:The throw keyword raises an ArgumentError if used to exit a thread

0 comments on commit 25a1473

Please sign in to comment.