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 = WrapToken(dispenser_.GetBreakContinueToken()); | |
236 break; | |
237 case CMD_THROW: | |
238 if (throw_token_) return throw_token_; | |
239 token = WrapToken(TokenDispenserForFinally::kThrowToken); | |
240 throw_token_ = token; | |
241 break; | |
242 case CMD_RETURN: | |
243 if (return_token_) return return_token_; | |
244 token = WrapToken(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* WrapToken(int token_id) { |
Michael Starzinger
2016/02/05 13:44:57
nit: Can we call this "NewPathToken" instead? Beca
Jarin
2016/02/05 13:55:07
Done.
| |
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 owner_->jsgraph()->Constant( |
Michael Starzinger
2016/02/05 13:44:57
nit: "return WrapToken(TokenDispenserForFinally::k
Jarin
2016/02/05 13:55:08
Done.
| |
282 TokenDispenserForFinally::kFallThroughToken); | |
263 } | 283 } |
264 Node* NewPathDispatchCondition(Node* t1, Node* t2) { | 284 Node* NewPathDispatchCondition(Node* t1, Node* t2) { |
265 // TODO(mstarzinger): This should be machine()->WordEqual(), but our Phi | 285 // TODO(mstarzinger): This should be machine()->WordEqual(), but our Phi |
266 // nodes all have kRepTagged|kTypeAny, which causes representation mismatch. | 286 // nodes all have kRepTagged|kTypeAny, which causes representation mismatch. |
267 return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2); | 287 return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2); |
268 } | 288 } |
269 | 289 |
270 private: | 290 private: |
291 TokenDispenserForFinally dispenser_; | |
271 AstGraphBuilder* owner_; | 292 AstGraphBuilder* owner_; |
272 ZoneVector<Entry> deferred_; | 293 ZoneVector<Entry> deferred_; |
294 Node* return_token_; | |
295 Node* throw_token_; | |
273 }; | 296 }; |
274 | 297 |
275 | 298 |
276 // Control scope implementation for a BreakableStatement. | 299 // Control scope implementation for a BreakableStatement. |
277 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope { | 300 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope { |
278 public: | 301 public: |
279 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target, | 302 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target, |
280 ControlBuilder* control) | 303 ControlBuilder* control) |
281 : ControlScope(owner), target_(target), control_(control) {} | 304 : ControlScope(owner), target_(target), control_(control) {} |
282 | 305 |
(...skipping 1197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1480 // - ReturnStatement: It represents the return value being returned. | 1503 // - ReturnStatement: It represents the return value being returned. |
1481 // - ThrowStatement: It represents the exception being thrown. | 1504 // - ThrowStatement: It represents the exception being thrown. |
1482 // - BreakStatement/ContinueStatement: Filled with the hole. | 1505 // - BreakStatement/ContinueStatement: Filled with the hole. |
1483 // - Falling through into finally-block: Filled with the hole. | 1506 // - Falling through into finally-block: Filled with the hole. |
1484 Node* result = try_control.GetResultValueNode(); | 1507 Node* result = try_control.GetResultValueNode(); |
1485 Node* token = try_control.GetDispatchTokenNode(); | 1508 Node* token = try_control.GetDispatchTokenNode(); |
1486 | 1509 |
1487 // The result value, dispatch token and message is expected on the operand | 1510 // The result value, dispatch token and message is expected on the operand |
1488 // stack (this is in sync with FullCodeGenerator::EnterFinallyBlock). | 1511 // stack (this is in sync with FullCodeGenerator::EnterFinallyBlock). |
1489 Node* message = NewNode(javascript()->LoadMessage()); | 1512 Node* message = NewNode(javascript()->LoadMessage()); |
1490 environment()->Push(token); // TODO(mstarzinger): Cook token! | 1513 environment()->Push(token); // TODO(mstarzinger): Cook token! |
Michael Starzinger
2016/02/05 13:44:58
nit: Can we drop this TODO?
Jarin
2016/02/05 13:55:08
Done.
| |
1491 environment()->Push(result); | 1514 environment()->Push(result); |
1492 environment()->Push(message); | 1515 environment()->Push(message); |
1493 | 1516 |
1494 // Clear message object as we enter the finally block. | 1517 // Clear message object as we enter the finally block. |
1495 Node* the_hole = jsgraph()->TheHoleConstant(); | 1518 Node* the_hole = jsgraph()->TheHoleConstant(); |
1496 NewNode(javascript()->StoreMessage(), the_hole); | 1519 NewNode(javascript()->StoreMessage(), the_hole); |
1497 | 1520 |
1498 // Evaluate the finally-block. | 1521 // Evaluate the finally-block. |
1499 Visit(stmt->finally_block()); | 1522 Visit(stmt->finally_block()); |
1500 try_control.EndFinally(); | 1523 try_control.EndFinally(); |
1501 | 1524 |
1502 // The result value, dispatch token and message is restored from the operand | 1525 // The result value, dispatch token and message is restored from the operand |
1503 // stack (this is in sync with FullCodeGenerator::ExitFinallyBlock). | 1526 // stack (this is in sync with FullCodeGenerator::ExitFinallyBlock). |
1504 message = environment()->Pop(); | 1527 message = environment()->Pop(); |
1505 result = environment()->Pop(); | 1528 result = environment()->Pop(); |
1506 token = environment()->Pop(); // TODO(mstarzinger): Uncook token! | 1529 token = environment()->Pop(); // TODO(mstarzinger): Uncook token! |
Michael Starzinger
2016/02/05 13:44:57
nit: Can we drop this TODO?
Jarin
2016/02/05 13:55:07
Done.
| |
1507 NewNode(javascript()->StoreMessage(), message); | 1530 NewNode(javascript()->StoreMessage(), message); |
1508 | 1531 |
1509 // Dynamic dispatch after the finally-block. | 1532 // Dynamic dispatch after the finally-block. |
1510 commands->ApplyDeferredCommands(token, result); | 1533 commands->ApplyDeferredCommands(token, result); |
1511 | 1534 |
1512 // TODO(mstarzinger): Remove bailout once everything works. | 1535 // TODO(mstarzinger): Remove bailout once everything works. |
1513 if (!FLAG_turbo_try_finally) SetStackOverflow(); | 1536 if (!FLAG_turbo_try_finally) SetStackOverflow(); |
1514 } | 1537 } |
1515 | 1538 |
1516 | 1539 |
(...skipping 2825 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4342 // Phi does not exist yet, introduce one. | 4365 // Phi does not exist yet, introduce one. |
4343 value = NewPhi(inputs, value, control); | 4366 value = NewPhi(inputs, value, control); |
4344 value->ReplaceInput(inputs - 1, other); | 4367 value->ReplaceInput(inputs - 1, other); |
4345 } | 4368 } |
4346 return value; | 4369 return value; |
4347 } | 4370 } |
4348 | 4371 |
4349 } // namespace compiler | 4372 } // namespace compiler |
4350 } // namespace internal | 4373 } // namespace internal |
4351 } // namespace v8 | 4374 } // namespace v8 |
OLD | NEW |