Commit 475d178f authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[interpreter] Add ReThrow bytecode for try-finally support.

This adds an explicit ReThrow bytecode to be used in the modelling of
try-finally statements. An exception that is being re-thrown should not
trigger message object creation or location computation and hence cannot
use the existing Throw bytecode.

R=rmcilroy@chromium.org
TEST=cctest/test-interpreter/InterpreterTryFinally
BUG=v8:4674
LOG=n

Review URL: https://codereview.chromium.org/1621673002

Cr-Commit-Position: refs/heads/master@{#33472}
parent 35dfeb2c
......@@ -1368,6 +1368,17 @@ void BytecodeGraphBuilder::VisitThrow(
}
void BytecodeGraphBuilder::VisitReThrow(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* value = environment()->LookupAccumulator();
NewNode(javascript()->CallRuntime(Runtime::kReThrow), value);
Node* control = NewNode(common()->Throw(), value);
environment()->RecordAfterState(control, &states);
UpdateControlDependencyToLeaveFunction(control);
}
void BytecodeGraphBuilder::BuildBinaryOp(
const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
......
......@@ -960,6 +960,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Throw() {
}
BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() {
Output(Bytecode::kReThrow);
exit_seen_in_block_ = true;
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
Output(Bytecode::kReturn);
exit_seen_in_block_ = true;
......
......@@ -217,6 +217,7 @@ class BytecodeArrayBuilder final {
BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
BytecodeArrayBuilder& Throw();
BytecodeArrayBuilder& ReThrow();
BytecodeArrayBuilder& Return();
// Complex flow control.
......
......@@ -209,8 +209,7 @@ class BytecodeGenerator::ControlScopeForTopLevel final
generator()->builder()->Return();
return true;
case CMD_RETHROW:
// TODO(mstarzinger): Should be a ReThrow instead.
generator()->builder()->Throw();
generator()->builder()->ReThrow();
return true;
}
return false;
......@@ -291,7 +290,7 @@ class BytecodeGenerator::ControlScopeForTryCatch final
public:
ControlScopeForTryCatch(BytecodeGenerator* generator,
TryCatchBuilder* try_catch_builder)
: ControlScope(generator), try_catch_builder_(try_catch_builder) {}
: ControlScope(generator) {}
protected:
bool Execute(Command command, Statement* statement) override {
......@@ -301,16 +300,11 @@ class BytecodeGenerator::ControlScopeForTryCatch final
case CMD_RETURN:
break;
case CMD_RETHROW:
// TODO(mstarzinger): Test and implement this!
USE(try_catch_builder_);
UNIMPLEMENTED();
generator()->builder()->ReThrow();
return true;
}
return false;
}
private:
TryCatchBuilder* try_catch_builder_;
};
......
......@@ -247,6 +247,7 @@ namespace interpreter {
\
/* Non-local flow control */ \
V(Throw, OperandType::kNone) \
V(ReThrow, OperandType::kNone) \
V(Return, OperandType::kNone)
......
......@@ -1751,6 +1751,17 @@ void Interpreter::DoThrow(compiler::InterpreterAssembler* assembler) {
}
// ReThrow
//
// Re-throws the exception in the accumulator.
void Interpreter::DoReThrow(compiler::InterpreterAssembler* assembler) {
Node* exception = __ GetAccumulator();
__ CallRuntime(Runtime::kReThrow, exception);
// We shouldn't ever return from a throw.
__ Abort(kUnexpectedReturnFromThrow);
}
// Return
//
// Return the value in the accumulator.
......
......@@ -4372,7 +4372,7 @@ TEST(TryFinally) {
B(JumpIfTrue), U8(4), //
B(Jump), U8(5), //
B(Ldar), R(2), //
B(Throw), //
B(ReThrow), //
B(LdaUndefined), //
B(Return), //
},
......@@ -4413,7 +4413,7 @@ TEST(TryFinally) {
B(JumpIfTrue), U8(4), //
B(Jump), U8(5), //
B(Ldar), R(3), //
B(Throw), //
B(ReThrow), //
B(LdaUndefined), //
B(Return), //
},
......@@ -4465,7 +4465,7 @@ TEST(TryFinally) {
B(JumpIfTrue), U8(4), //
B(Jump), U8(5), //
B(Ldar), R(3), //
B(Throw), //
B(ReThrow), //
B(LdaUndefined), //
B(Return), //
},
......
......@@ -2075,6 +2075,10 @@ TEST(InterpreterTryFinally) {
" try { a = 2; continue; } finally { a = 3; }"
"} return a + i;",
factory->NewStringFromStaticChars("R23")),
std::make_pair("var a = 1; try { a = 2;"
" try { a = 3; throw 23; } finally { a = 4; }"
"} catch(e) { a = a + e; } return a;",
factory->NewStringFromStaticChars("R27")),
};
const char* try_wrapper =
......
......@@ -200,10 +200,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
.JumpIfFalse(&start);
// Emit throw in it's own basic block so that the rest of the code isn't
// omitted due to being dead.
// Emit throw and re-throw in it's own basic block so that the rest of the
// code isn't omitted due to being dead.
BytecodeLabel after_throw;
builder.Jump(&after_throw).Throw().Bind(&after_throw);
BytecodeLabel after_rethrow;
builder.Jump(&after_rethrow).ReThrow().Bind(&after_rethrow);
builder.ForInPrepare(reg)
.ForInDone(reg, reg)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment