Reviewers: jarin,
Description:
[turbofan] Fix exception being re-thrown after finally-block.
This makes sure that the implicit exception edges in the graph pass
the correct exception object and also fixes a bug in the dominance
relationship of the value entering the finally block and it's uses.
[email protected]
TEST=cctest/test-run-jsexceptions/FinallyBreak
Please review this at https://codereview.chromium.org/970253002/
Base URL: https://chromium.googlesource.com/v8/v8.git@master
Affected files (+42, -16 lines):
M src/compiler/ast-graph-builder.cc
M src/compiler/control-builders.h
M src/compiler/control-builders.cc
Index: src/compiler/ast-graph-builder.cc
diff --git a/src/compiler/ast-graph-builder.cc
b/src/compiler/ast-graph-builder.cc
index
b6c6e0fb3f5bc1a0f396d178d09931f978332bda..38b501d17bfb2ee5c0b68216625edce343a10b78
100644
--- a/src/compiler/ast-graph-builder.cc
+++ b/src/compiler/ast-graph-builder.cc
@@ -212,7 +212,6 @@ class AstGraphBuilder::ControlScope::DeferredCommands :
public ZoneObject {
struct Entry {
Command command; // The command type being applied on this path.
Statement* statement; // The target statement for the command or
{NULL}.
- Node* value; // The passed value node for the command or
{NULL}.
Node* token; // A token identifying this particular path.
};
@@ -220,7 +219,7 @@ class AstGraphBuilder::ControlScope::DeferredCommands :
public ZoneObject {
// generates a new dispatch token that identifies one particular path.
Node* RecordCommand(Command cmd, Statement* stmt, Node* value) {
Node* token = NewPathTokenForDeferredCommand();
- deferred_.push_back({cmd, stmt, value, token});
+ deferred_.push_back({cmd, stmt, token});
return token;
}
@@ -230,7 +229,7 @@ class AstGraphBuilder::ControlScope::DeferredCommands :
public ZoneObject {
// Applies all recorded control-flow commands after the finally-block
again.
// This generates a dynamic dispatch on the token from the entry point.
- void ApplyDeferredCommands(Node* token) {
+ void ApplyDeferredCommands(Node* token, Node* value) {
SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size()));
dispatch.BeginSwitch();
for (size_t i = 0; i < deferred_.size(); ++i) {
@@ -241,7 +240,7 @@ class AstGraphBuilder::ControlScope::DeferredCommands :
public ZoneObject {
for (size_t i = 0; i < deferred_.size(); ++i) {
dispatch.BeginCase(static_cast<int>(i));
owner_->execution_control()->PerformCommand(
- deferred_[i].command, deferred_[i].statement,
deferred_[i].value);
+ deferred_[i].command, deferred_[i].statement, value);
dispatch.EndCase();
}
dispatch.EndSwitch();
@@ -369,7 +368,7 @@ class AstGraphBuilder::ControlScopeForFinally : public
ControlScope {
protected:
virtual bool Execute(Command cmd, Statement* target, Node* value)
OVERRIDE {
Node* token = commands_->RecordCommand(cmd, target, value);
- control_->LeaveTry(token);
+ control_->LeaveTry(token, value);
return true;
}
@@ -719,12 +718,12 @@ void
AstGraphBuilder::ControlScope::PerformCommand(Command command,
void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) {
- PerformCommand(CMD_BREAK, stmt, nullptr);
+ PerformCommand(CMD_BREAK, stmt, builder()->jsgraph()->TheHoleConstant());
}
void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) {
- PerformCommand(CMD_CONTINUE, stmt, nullptr);
+ PerformCommand(CMD_CONTINUE, stmt,
builder()->jsgraph()->TheHoleConstant());
}
@@ -1262,6 +1261,7 @@ void
AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
// 2. By exiting the try-block with a function-local control flow
transfer
// (i.e. through break/continue/return statements).
// 3. By exiting the try-block with a thrown exception.
+ Node* fallthrough_result = jsgraph()->TheHoleConstant();
ControlScope::DeferredCommands* commands =
new (zone()) ControlScope::DeferredCommands(this);
@@ -1272,15 +1272,32 @@ void
AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
ControlScopeForFinally scope(this, commands, &try_control);
Visit(stmt->try_block());
}
- try_control.EndTry(commands->GetFallThroughToken());
+ try_control.EndTry(commands->GetFallThroughToken(), fallthrough_result);
+
+ // The result value semantics depend on how the block was entered:
+ // - ReturnStatement: It represents the return value being returned.
+ // - ThrowStatement: It represents the exception being thrown.
+ // - BreakStatement/ContinueStatement: Filled with the hole.
+ // - Falling through into finally-block: Filled with the hole.
+ Node* result = try_control.GetResultValueNode();
+
+ // TODO(mstarzinger): See FullCodeGenerator::EnterFinallyBlock.
+ environment()->Push(jsgraph()->SmiConstant(Code::kHeaderSize));
+ environment()->Push(result);
+ environment()->Push(jsgraph()->TheHoleConstant()); //
pending_message_obj
+ environment()->Push(jsgraph()->SmiConstant(0)); //
has_pending_message
+ environment()->Push(jsgraph()->TheHoleConstant()); //
pending_message_script
// Evaluate the finally-block.
Visit(stmt->finally_block());
try_control.EndFinally();
+ // TODO(mstarzinger): See FullCodeGenerator::ExitFinallyBlock.
+ environment()->Drop(5);
+
// Dynamic dispatch after the finally-block.
Node* token = try_control.GetDispatchTokenNode();
- commands->ApplyDeferredCommands(token);
+ commands->ApplyDeferredCommands(token, result);
// TODO(mstarzinger): Remove bailout once everything works.
if (!FLAG_turbo_exceptions) SetStackOverflow();
Index: src/compiler/control-builders.cc
diff --git a/src/compiler/control-builders.cc
b/src/compiler/control-builders.cc
index
2ace441e61eac82a83439ed2155a599128a290fb..0e4f1683b86668d5d623f88a56f192cad4bd6ada
100644
--- a/src/compiler/control-builders.cc
+++ b/src/compiler/control-builders.cc
@@ -179,21 +179,25 @@ void TryCatchBuilder::EndCatch() {
void TryFinallyBuilder::BeginTry() {
finally_environment_ = environment()->CopyAsUnreachable();
finally_environment_->Push(the_hole());
+ finally_environment_->Push(the_hole());
}
-void TryFinallyBuilder::LeaveTry(Node* token) {
+void TryFinallyBuilder::LeaveTry(Node* token, Node* value) {
+ environment()->Push(value);
environment()->Push(token);
finally_environment_->Merge(environment());
- environment()->Pop();
+ environment()->Drop(2);
}
-void TryFinallyBuilder::EndTry(Node* fallthrough_token) {
+void TryFinallyBuilder::EndTry(Node* fallthrough_token, Node* value) {
+ environment()->Push(value);
environment()->Push(fallthrough_token);
finally_environment_->Merge(environment());
- environment()->Pop();
+ environment()->Drop(2);
token_node_ = finally_environment_->Pop();
+ value_node_ = finally_environment_->Pop();
set_environment(finally_environment_);
}
Index: src/compiler/control-builders.h
diff --git a/src/compiler/control-builders.h
b/src/compiler/control-builders.h
index
c22ee04a98ee9220c8ad1c2163f9eb5bb51ae0d3..59970563fba45b99c69eaccd4908ce35c64532c8
100644
--- a/src/compiler/control-builders.h
+++ b/src/compiler/control-builders.h
@@ -167,20 +167,25 @@ class TryFinallyBuilder FINAL : public ControlBuilder
{
explicit TryFinallyBuilder(AstGraphBuilder* builder)
: ControlBuilder(builder),
finally_environment_(NULL),
- token_node_(NULL) {}
+ token_node_(NULL),
+ value_node_(NULL) {}
// Primitive control commands.
void BeginTry();
- void LeaveTry(Node* token);
- void EndTry(Node* token);
+ void LeaveTry(Node* token, Node* value);
+ void EndTry(Node* token, Node* value);
void EndFinally();
// Returns the dispatch token value inside the 'finally' body.
Node* GetDispatchTokenNode() const { return token_node_; }
+ // Returns the saved result value inside the 'finally' body.
+ Node* GetResultValueNode() const { return value_node_; }
+
private:
Environment* finally_environment_; // Environment for the 'finally'
body.
Node* token_node_; // Node for token in 'finally' body.
+ Node* value_node_; // Node for value in 'finally' body.
};
} // namespace compiler
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.