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 |