| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/ast-graph-builder.h" | 5 #include "src/compiler/ast-graph-builder.h" |
| 6 | 6 |
| 7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
| 8 #include "src/compiler.h" | 8 #include "src/compiler.h" |
| 9 #include "src/compiler/ast-loop-assignment-analyzer.h" | 9 #include "src/compiler/ast-loop-assignment-analyzer.h" |
| 10 #include "src/compiler/control-builders.h" | 10 #include "src/compiler/control-builders.h" |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 int context_length() const { return context_length_; } | 199 int context_length() const { return context_length_; } |
| 200 int stack_height() const { return stack_height_; } | 200 int stack_height() const { return stack_height_; } |
| 201 | 201 |
| 202 private: | 202 private: |
| 203 AstGraphBuilder* builder_; | 203 AstGraphBuilder* builder_; |
| 204 ControlScope* outer_; | 204 ControlScope* outer_; |
| 205 int context_length_; | 205 int context_length_; |
| 206 int stack_height_; | 206 int stack_height_; |
| 207 }; | 207 }; |
| 208 | 208 |
| 209 | |
| 210 // Helper class for a try-finally control scope. It can record intercepted | 209 // Helper class for a try-finally control scope. It can record intercepted |
| 211 // control-flow commands that cause entry into a finally-block, and re-apply | 210 // control-flow commands that cause entry into a finally-block, and re-apply |
| 212 // them after again leaving that block. Special tokens are used to identify | 211 // them after again leaving that block. Special tokens are used to identify |
| 213 // paths going through the finally-block to dispatch after leaving the block. | 212 // paths going through the finally-block to dispatch after leaving the block. |
| 214 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject { | 213 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject { |
| 215 public: | 214 public: |
| 216 explicit DeferredCommands(AstGraphBuilder* owner) | 215 explicit DeferredCommands(AstGraphBuilder* owner) |
| 217 : owner_(owner), deferred_(owner->local_zone()) {} | 216 : owner_(owner), |
| 217 deferred_(owner->local_zone()), |
| 218 return_token_(nullptr), |
| 219 throw_token_(nullptr) {} |
| 218 | 220 |
| 219 // One recorded control-flow command. | 221 // One recorded control-flow command. |
| 220 struct Entry { | 222 struct Entry { |
| 221 Command command; // The command type being applied on this path. | 223 Command command; // The command type being applied on this path. |
| 222 Statement* statement; // The target statement for the command or {nullptr}. | 224 Statement* statement; // The target statement for the command or {nullptr}. |
| 223 Node* token; // A token identifying this particular path. | 225 Node* token; // A token identifying this particular path. |
| 224 }; | 226 }; |
| 225 | 227 |
| 226 // Records a control-flow command while entering the finally-block. This also | 228 // Records a control-flow command while entering the finally-block. This also |
| 227 // generates a new dispatch token that identifies one particular path. | 229 // generates a new dispatch token that identifies one particular path. |
| 228 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) { | 230 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) { |
| 229 Node* token = NewPathTokenForDeferredCommand(); | 231 Node* token = nullptr; |
| 232 switch (cmd) { |
| 233 case CMD_BREAK: |
| 234 case CMD_CONTINUE: |
| 235 token = NewPathToken(dispenser_.GetBreakContinueToken()); |
| 236 break; |
| 237 case CMD_THROW: |
| 238 if (throw_token_) return throw_token_; |
| 239 token = NewPathToken(TokenDispenserForFinally::kThrowToken); |
| 240 throw_token_ = token; |
| 241 break; |
| 242 case CMD_RETURN: |
| 243 if (return_token_) return return_token_; |
| 244 token = NewPathToken(TokenDispenserForFinally::kReturnToken); |
| 245 return_token_ = token; |
| 246 break; |
| 247 } |
| 248 DCHECK_NOT_NULL(token); |
| 230 deferred_.push_back({cmd, stmt, token}); | 249 deferred_.push_back({cmd, stmt, token}); |
| 231 return token; | 250 return token; |
| 232 } | 251 } |
| 233 | 252 |
| 234 // Returns the dispatch token to be used to identify the implicit fall-through | 253 // Returns the dispatch token to be used to identify the implicit fall-through |
| 235 // path at the end of a try-block into the corresponding finally-block. | 254 // path at the end of a try-block into the corresponding finally-block. |
| 236 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); } | 255 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); } |
| 237 | 256 |
| 238 // Applies all recorded control-flow commands after the finally-block again. | 257 // Applies all recorded control-flow commands after the finally-block again. |
| 239 // This generates a dynamic dispatch on the token from the entry point. | 258 // This generates a dynamic dispatch on the token from the entry point. |
| 240 void ApplyDeferredCommands(Node* token, Node* value) { | 259 void ApplyDeferredCommands(Node* token, Node* value) { |
| 241 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size())); | 260 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size())); |
| 242 dispatch.BeginSwitch(); | 261 dispatch.BeginSwitch(); |
| 243 for (size_t i = 0; i < deferred_.size(); ++i) { | 262 for (size_t i = 0; i < deferred_.size(); ++i) { |
| 244 Node* condition = NewPathDispatchCondition(token, deferred_[i].token); | 263 Node* condition = NewPathDispatchCondition(token, deferred_[i].token); |
| 245 dispatch.BeginLabel(static_cast<int>(i), condition); | 264 dispatch.BeginLabel(static_cast<int>(i), condition); |
| 246 dispatch.EndLabel(); | 265 dispatch.EndLabel(); |
| 247 } | 266 } |
| 248 for (size_t i = 0; i < deferred_.size(); ++i) { | 267 for (size_t i = 0; i < deferred_.size(); ++i) { |
| 249 dispatch.BeginCase(static_cast<int>(i)); | 268 dispatch.BeginCase(static_cast<int>(i)); |
| 250 owner_->execution_control()->PerformCommand( | 269 owner_->execution_control()->PerformCommand( |
| 251 deferred_[i].command, deferred_[i].statement, value); | 270 deferred_[i].command, deferred_[i].statement, value); |
| 252 dispatch.EndCase(); | 271 dispatch.EndCase(); |
| 253 } | 272 } |
| 254 dispatch.EndSwitch(); | 273 dispatch.EndSwitch(); |
| 255 } | 274 } |
| 256 | 275 |
| 257 protected: | 276 protected: |
| 258 Node* NewPathTokenForDeferredCommand() { | 277 Node* NewPathToken(int token_id) { |
| 259 return owner_->jsgraph()->Constant(static_cast<int>(deferred_.size())); | 278 return owner_->jsgraph()->Constant(token_id); |
| 260 } | 279 } |
| 261 Node* NewPathTokenForImplicitFallThrough() { | 280 Node* NewPathTokenForImplicitFallThrough() { |
| 262 return owner_->jsgraph()->Constant(-1); | 281 return NewPathToken(TokenDispenserForFinally::kFallThroughToken); |
| 263 } | 282 } |
| 264 Node* NewPathDispatchCondition(Node* t1, Node* t2) { | 283 Node* NewPathDispatchCondition(Node* t1, Node* t2) { |
| 265 // TODO(mstarzinger): This should be machine()->WordEqual(), but our Phi | 284 // TODO(mstarzinger): This should be machine()->WordEqual(), but our Phi |
| 266 // nodes all have kRepTagged|kTypeAny, which causes representation mismatch. | 285 // nodes all have kRepTagged|kTypeAny, which causes representation mismatch. |
| 267 return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2); | 286 return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2); |
| 268 } | 287 } |
| 269 | 288 |
| 270 private: | 289 private: |
| 290 TokenDispenserForFinally dispenser_; |
| 271 AstGraphBuilder* owner_; | 291 AstGraphBuilder* owner_; |
| 272 ZoneVector<Entry> deferred_; | 292 ZoneVector<Entry> deferred_; |
| 293 Node* return_token_; |
| 294 Node* throw_token_; |
| 273 }; | 295 }; |
| 274 | 296 |
| 275 | 297 |
| 276 // Control scope implementation for a BreakableStatement. | 298 // Control scope implementation for a BreakableStatement. |
| 277 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope { | 299 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope { |
| 278 public: | 300 public: |
| 279 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target, | 301 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target, |
| 280 ControlBuilder* control) | 302 ControlBuilder* control) |
| 281 : ControlScope(owner), target_(target), control_(control) {} | 303 : ControlScope(owner), target_(target), control_(control) {} |
| 282 | 304 |
| (...skipping 1197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1480 // - ReturnStatement: It represents the return value being returned. | 1502 // - ReturnStatement: It represents the return value being returned. |
| 1481 // - ThrowStatement: It represents the exception being thrown. | 1503 // - ThrowStatement: It represents the exception being thrown. |
| 1482 // - BreakStatement/ContinueStatement: Filled with the hole. | 1504 // - BreakStatement/ContinueStatement: Filled with the hole. |
| 1483 // - Falling through into finally-block: Filled with the hole. | 1505 // - Falling through into finally-block: Filled with the hole. |
| 1484 Node* result = try_control.GetResultValueNode(); | 1506 Node* result = try_control.GetResultValueNode(); |
| 1485 Node* token = try_control.GetDispatchTokenNode(); | 1507 Node* token = try_control.GetDispatchTokenNode(); |
| 1486 | 1508 |
| 1487 // The result value, dispatch token and message is expected on the operand | 1509 // The result value, dispatch token and message is expected on the operand |
| 1488 // stack (this is in sync with FullCodeGenerator::EnterFinallyBlock). | 1510 // stack (this is in sync with FullCodeGenerator::EnterFinallyBlock). |
| 1489 Node* message = NewNode(javascript()->LoadMessage()); | 1511 Node* message = NewNode(javascript()->LoadMessage()); |
| 1490 environment()->Push(token); // TODO(mstarzinger): Cook token! | 1512 environment()->Push(token); |
| 1491 environment()->Push(result); | 1513 environment()->Push(result); |
| 1492 environment()->Push(message); | 1514 environment()->Push(message); |
| 1493 | 1515 |
| 1494 // Clear message object as we enter the finally block. | 1516 // Clear message object as we enter the finally block. |
| 1495 Node* the_hole = jsgraph()->TheHoleConstant(); | 1517 Node* the_hole = jsgraph()->TheHoleConstant(); |
| 1496 NewNode(javascript()->StoreMessage(), the_hole); | 1518 NewNode(javascript()->StoreMessage(), the_hole); |
| 1497 | 1519 |
| 1498 // Evaluate the finally-block. | 1520 // Evaluate the finally-block. |
| 1499 Visit(stmt->finally_block()); | 1521 Visit(stmt->finally_block()); |
| 1500 try_control.EndFinally(); | 1522 try_control.EndFinally(); |
| 1501 | 1523 |
| 1502 // The result value, dispatch token and message is restored from the operand | 1524 // The result value, dispatch token and message is restored from the operand |
| 1503 // stack (this is in sync with FullCodeGenerator::ExitFinallyBlock). | 1525 // stack (this is in sync with FullCodeGenerator::ExitFinallyBlock). |
| 1504 message = environment()->Pop(); | 1526 message = environment()->Pop(); |
| 1505 result = environment()->Pop(); | 1527 result = environment()->Pop(); |
| 1506 token = environment()->Pop(); // TODO(mstarzinger): Uncook token! | 1528 token = environment()->Pop(); |
| 1507 NewNode(javascript()->StoreMessage(), message); | 1529 NewNode(javascript()->StoreMessage(), message); |
| 1508 | 1530 |
| 1509 // Dynamic dispatch after the finally-block. | 1531 // Dynamic dispatch after the finally-block. |
| 1510 commands->ApplyDeferredCommands(token, result); | 1532 commands->ApplyDeferredCommands(token, result); |
| 1511 | 1533 |
| 1512 // TODO(mstarzinger): Remove bailout once everything works. | 1534 // TODO(mstarzinger): Remove bailout once everything works. |
| 1513 if (!FLAG_turbo_try_finally) SetStackOverflow(); | 1535 if (!FLAG_turbo_try_finally) SetStackOverflow(); |
| 1514 } | 1536 } |
| 1515 | 1537 |
| 1516 | 1538 |
| (...skipping 2825 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4342 // Phi does not exist yet, introduce one. | 4364 // Phi does not exist yet, introduce one. |
| 4343 value = NewPhi(inputs, value, control); | 4365 value = NewPhi(inputs, value, control); |
| 4344 value->ReplaceInput(inputs - 1, other); | 4366 value->ReplaceInput(inputs - 1, other); |
| 4345 } | 4367 } |
| 4346 return value; | 4368 return value; |
| 4347 } | 4369 } |
| 4348 | 4370 |
| 4349 } // namespace compiler | 4371 } // namespace compiler |
| 4350 } // namespace internal | 4372 } // namespace internal |
| 4351 } // namespace v8 | 4373 } // namespace v8 |
| OLD | NEW |