Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/compiler/ast-graph-builder.cc

Issue 970253002: [turbofan] Fix exception being re-thrown after finally-block. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Sneak in alpha sorting. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/compiler/control-builders.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/compiler.h" 7 #include "src/compiler.h"
8 #include "src/compiler/ast-loop-assignment-analyzer.h" 8 #include "src/compiler/ast-loop-assignment-analyzer.h"
9 #include "src/compiler/control-builders.h" 9 #include "src/compiler/control-builders.h"
10 #include "src/compiler/linkage.h" 10 #include "src/compiler/linkage.h"
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 // paths going through the finally-block to dispatch after leaving the block. 205 // paths going through the finally-block to dispatch after leaving the block.
206 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject { 206 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject {
207 public: 207 public:
208 explicit DeferredCommands(AstGraphBuilder* owner) 208 explicit DeferredCommands(AstGraphBuilder* owner)
209 : owner_(owner), deferred_(owner->zone()) {} 209 : owner_(owner), deferred_(owner->zone()) {}
210 210
211 // One recorded control-flow command. 211 // One recorded control-flow command.
212 struct Entry { 212 struct Entry {
213 Command command; // The command type being applied on this path. 213 Command command; // The command type being applied on this path.
214 Statement* statement; // The target statement for the command or {NULL}. 214 Statement* statement; // The target statement for the command or {NULL}.
215 Node* value; // The passed value node for the command or {NULL}.
216 Node* token; // A token identifying this particular path. 215 Node* token; // A token identifying this particular path.
217 }; 216 };
218 217
219 // Records a control-flow command while entering the finally-block. This also 218 // Records a control-flow command while entering the finally-block. This also
220 // generates a new dispatch token that identifies one particular path. 219 // generates a new dispatch token that identifies one particular path.
221 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) { 220 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) {
222 Node* token = NewPathTokenForDeferredCommand(); 221 Node* token = NewPathTokenForDeferredCommand();
223 deferred_.push_back({cmd, stmt, value, token}); 222 deferred_.push_back({cmd, stmt, token});
224 return token; 223 return token;
225 } 224 }
226 225
227 // Returns the dispatch token to be used to identify the implicit fall-through 226 // Returns the dispatch token to be used to identify the implicit fall-through
228 // path at the end of a try-block into the corresponding finally-block. 227 // path at the end of a try-block into the corresponding finally-block.
229 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); } 228 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); }
230 229
231 // Applies all recorded control-flow commands after the finally-block again. 230 // Applies all recorded control-flow commands after the finally-block again.
232 // This generates a dynamic dispatch on the token from the entry point. 231 // This generates a dynamic dispatch on the token from the entry point.
233 void ApplyDeferredCommands(Node* token) { 232 void ApplyDeferredCommands(Node* token, Node* value) {
234 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size())); 233 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size()));
235 dispatch.BeginSwitch(); 234 dispatch.BeginSwitch();
236 for (size_t i = 0; i < deferred_.size(); ++i) { 235 for (size_t i = 0; i < deferred_.size(); ++i) {
237 Node* condition = NewPathDispatchCondition(token, deferred_[i].token); 236 Node* condition = NewPathDispatchCondition(token, deferred_[i].token);
238 dispatch.BeginLabel(static_cast<int>(i), condition); 237 dispatch.BeginLabel(static_cast<int>(i), condition);
239 dispatch.EndLabel(); 238 dispatch.EndLabel();
240 } 239 }
241 for (size_t i = 0; i < deferred_.size(); ++i) { 240 for (size_t i = 0; i < deferred_.size(); ++i) {
242 dispatch.BeginCase(static_cast<int>(i)); 241 dispatch.BeginCase(static_cast<int>(i));
243 owner_->execution_control()->PerformCommand( 242 owner_->execution_control()->PerformCommand(
244 deferred_[i].command, deferred_[i].statement, deferred_[i].value); 243 deferred_[i].command, deferred_[i].statement, value);
245 dispatch.EndCase(); 244 dispatch.EndCase();
246 } 245 }
247 dispatch.EndSwitch(); 246 dispatch.EndSwitch();
248 } 247 }
249 248
250 protected: 249 protected:
251 Node* NewPathTokenForDeferredCommand() { 250 Node* NewPathTokenForDeferredCommand() {
252 return owner_->jsgraph()->Constant(static_cast<int>(deferred_.size())); 251 return owner_->jsgraph()->Constant(static_cast<int>(deferred_.size()));
253 } 252 }
254 Node* NewPathTokenForImplicitFallThrough() { 253 Node* NewPathTokenForImplicitFallThrough() {
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 : ControlScope(owner), commands_(commands), control_(control) { 361 : ControlScope(owner), commands_(commands), control_(control) {
363 builder()->try_nesting_level_++; // Increment nesting. 362 builder()->try_nesting_level_++; // Increment nesting.
364 } 363 }
365 ~ControlScopeForFinally() { 364 ~ControlScopeForFinally() {
366 builder()->try_nesting_level_--; // Decrement nesting. 365 builder()->try_nesting_level_--; // Decrement nesting.
367 } 366 }
368 367
369 protected: 368 protected:
370 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE { 369 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
371 Node* token = commands_->RecordCommand(cmd, target, value); 370 Node* token = commands_->RecordCommand(cmd, target, value);
372 control_->LeaveTry(token); 371 control_->LeaveTry(token, value);
373 return true; 372 return true;
374 } 373 }
375 374
376 private: 375 private:
377 DeferredCommands* commands_; 376 DeferredCommands* commands_;
378 TryFinallyBuilder* control_; 377 TryFinallyBuilder* control_;
379 }; 378 };
380 379
381 380
382 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, 381 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
712 environment()->Trim(current->stack_height()); 711 environment()->Trim(current->stack_height());
713 if (current->Execute(command, target, value)) break; 712 if (current->Execute(command, target, value)) break;
714 current = current->outer_; 713 current = current->outer_;
715 } 714 }
716 builder()->set_environment(env); 715 builder()->set_environment(env);
717 DCHECK(current != NULL); // Always handled (unless stack is malformed). 716 DCHECK(current != NULL); // Always handled (unless stack is malformed).
718 } 717 }
719 718
720 719
721 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) { 720 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) {
722 PerformCommand(CMD_BREAK, stmt, nullptr); 721 PerformCommand(CMD_BREAK, stmt, builder()->jsgraph()->TheHoleConstant());
723 } 722 }
724 723
725 724
726 void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) { 725 void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) {
727 PerformCommand(CMD_CONTINUE, stmt, nullptr); 726 PerformCommand(CMD_CONTINUE, stmt, builder()->jsgraph()->TheHoleConstant());
728 } 727 }
729 728
730 729
731 void AstGraphBuilder::ControlScope::ReturnValue(Node* return_value) { 730 void AstGraphBuilder::ControlScope::ReturnValue(Node* return_value) {
732 PerformCommand(CMD_RETURN, nullptr, return_value); 731 PerformCommand(CMD_RETURN, nullptr, return_value);
733 } 732 }
734 733
735 734
736 void AstGraphBuilder::ControlScope::ThrowValue(Node* exception_value) { 735 void AstGraphBuilder::ControlScope::ThrowValue(Node* exception_value) {
737 PerformCommand(CMD_THROW, nullptr, exception_value); 736 PerformCommand(CMD_THROW, nullptr, exception_value);
(...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after
1255 1254
1256 // We keep a record of all paths that enter the finally-block to be able to 1255 // We keep a record of all paths that enter the finally-block to be able to
1257 // dispatch to the correct continuation point after the statements in the 1256 // dispatch to the correct continuation point after the statements in the
1258 // finally-block have been evaluated. 1257 // finally-block have been evaluated.
1259 // 1258 //
1260 // The try-finally construct can enter the finally-block in three ways: 1259 // The try-finally construct can enter the finally-block in three ways:
1261 // 1. By exiting the try-block normally, falling through at the end. 1260 // 1. By exiting the try-block normally, falling through at the end.
1262 // 2. By exiting the try-block with a function-local control flow transfer 1261 // 2. By exiting the try-block with a function-local control flow transfer
1263 // (i.e. through break/continue/return statements). 1262 // (i.e. through break/continue/return statements).
1264 // 3. By exiting the try-block with a thrown exception. 1263 // 3. By exiting the try-block with a thrown exception.
1264 Node* fallthrough_result = jsgraph()->TheHoleConstant();
1265 ControlScope::DeferredCommands* commands = 1265 ControlScope::DeferredCommands* commands =
1266 new (zone()) ControlScope::DeferredCommands(this); 1266 new (zone()) ControlScope::DeferredCommands(this);
1267 1267
1268 // Evaluate the try-block inside a control scope. This simulates a handler 1268 // Evaluate the try-block inside a control scope. This simulates a handler
1269 // that is intercepting all control commands. 1269 // that is intercepting all control commands.
1270 try_control.BeginTry(); 1270 try_control.BeginTry();
1271 { 1271 {
1272 ControlScopeForFinally scope(this, commands, &try_control); 1272 ControlScopeForFinally scope(this, commands, &try_control);
1273 Visit(stmt->try_block()); 1273 Visit(stmt->try_block());
1274 } 1274 }
1275 try_control.EndTry(commands->GetFallThroughToken()); 1275 try_control.EndTry(commands->GetFallThroughToken(), fallthrough_result);
1276
1277 // The result value semantics depend on how the block was entered:
1278 // - ReturnStatement: It represents the return value being returned.
1279 // - ThrowStatement: It represents the exception being thrown.
1280 // - BreakStatement/ContinueStatement: Filled with the hole.
1281 // - Falling through into finally-block: Filled with the hole.
1282 Node* result = try_control.GetResultValueNode();
1283
1284 // TODO(mstarzinger): See FullCodeGenerator::EnterFinallyBlock.
1285 environment()->Push(jsgraph()->SmiConstant(Code::kHeaderSize));
1286 environment()->Push(result);
1287 environment()->Push(jsgraph()->TheHoleConstant()); // pending_message_obj
1288 environment()->Push(jsgraph()->SmiConstant(0)); // has_pending_message
1289 environment()->Push(jsgraph()->TheHoleConstant()); // pending_message_script
1276 1290
1277 // Evaluate the finally-block. 1291 // Evaluate the finally-block.
1278 Visit(stmt->finally_block()); 1292 Visit(stmt->finally_block());
1279 try_control.EndFinally(); 1293 try_control.EndFinally();
1280 1294
1295 // TODO(mstarzinger): See FullCodeGenerator::ExitFinallyBlock.
1296 environment()->Drop(5);
1297
1281 // Dynamic dispatch after the finally-block. 1298 // Dynamic dispatch after the finally-block.
1282 Node* token = try_control.GetDispatchTokenNode(); 1299 Node* token = try_control.GetDispatchTokenNode();
1283 commands->ApplyDeferredCommands(token); 1300 commands->ApplyDeferredCommands(token, result);
1284 1301
1285 // TODO(mstarzinger): Remove bailout once everything works. 1302 // TODO(mstarzinger): Remove bailout once everything works.
1286 if (!FLAG_turbo_exceptions) SetStackOverflow(); 1303 if (!FLAG_turbo_exceptions) SetStackOverflow();
1287 } 1304 }
1288 1305
1289 1306
1290 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { 1307 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
1291 // TODO(turbofan): Do we really need a separate reloc-info for this? 1308 // TODO(turbofan): Do we really need a separate reloc-info for this?
1292 Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0)); 1309 Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0));
1293 PrepareFrameState(node, stmt->DebugBreakId()); 1310 PrepareFrameState(node, stmt->DebugBreakId());
(...skipping 1721 matching lines...) Expand 10 before | Expand all | Expand 10 after
3015 } 3032 }
3016 if (!environment()->IsMarkedAsUnreachable()) { 3033 if (!environment()->IsMarkedAsUnreachable()) {
3017 // Update the current control dependency for control-producing nodes. 3034 // Update the current control dependency for control-producing nodes.
3018 if (NodeProperties::IsControl(result)) { 3035 if (NodeProperties::IsControl(result)) {
3019 environment_->UpdateControlDependency(result); 3036 environment_->UpdateControlDependency(result);
3020 } 3037 }
3021 // Add implicit exception continuation for throwing nodes. 3038 // Add implicit exception continuation for throwing nodes.
3022 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) { 3039 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) {
3023 Node* on_exception = graph()->NewNode(common()->IfException(), result); 3040 Node* on_exception = graph()->NewNode(common()->IfException(), result);
3024 environment_->UpdateControlDependency(on_exception); 3041 environment_->UpdateControlDependency(on_exception);
3025 execution_control()->ThrowValue(jsgraph()->UndefinedConstant()); 3042 execution_control()->ThrowValue(result);
3026 } 3043 }
3027 // Add implicit success continuation for throwing nodes. 3044 // Add implicit success continuation for throwing nodes.
3028 if (!result->op()->HasProperty(Operator::kNoThrow)) { 3045 if (!result->op()->HasProperty(Operator::kNoThrow)) {
3029 Node* on_success = graph()->NewNode(common()->IfSuccess(), result); 3046 Node* on_success = graph()->NewNode(common()->IfSuccess(), result);
3030 environment_->UpdateControlDependency(on_success); 3047 environment_->UpdateControlDependency(on_success);
3031 } 3048 }
3032 } 3049 }
3033 } 3050 }
3034 3051
3035 return result; 3052 return result;
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
3233 // Phi does not exist yet, introduce one. 3250 // Phi does not exist yet, introduce one.
3234 value = NewPhi(inputs, value, control); 3251 value = NewPhi(inputs, value, control);
3235 value->ReplaceInput(inputs - 1, other); 3252 value->ReplaceInput(inputs - 1, other);
3236 } 3253 }
3237 return value; 3254 return value;
3238 } 3255 }
3239 3256
3240 } // namespace compiler 3257 } // namespace compiler
3241 } // namespace internal 3258 } // namespace internal
3242 } // namespace v8 3259 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | src/compiler/control-builders.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698