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.

Reply via email to