Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/interpreter/bytecode-generator.h" | 5 #include "src/interpreter/bytecode-generator.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/interpreter/bytecode-register-allocator.h" | 9 #include "src/interpreter/bytecode-register-allocator.h" |
| 10 #include "src/interpreter/control-flow-builders.h" | 10 #include "src/interpreter/control-flow-builders.h" |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 class BytecodeGenerator::ControlScope BASE_EMBEDDED { | 81 class BytecodeGenerator::ControlScope BASE_EMBEDDED { |
| 82 public: | 82 public: |
| 83 explicit ControlScope(BytecodeGenerator* generator) | 83 explicit ControlScope(BytecodeGenerator* generator) |
| 84 : generator_(generator), outer_(generator->execution_control()) { | 84 : generator_(generator), outer_(generator->execution_control()) { |
| 85 generator_->set_execution_control(this); | 85 generator_->set_execution_control(this); |
| 86 } | 86 } |
| 87 virtual ~ControlScope() { generator_->set_execution_control(outer()); } | 87 virtual ~ControlScope() { generator_->set_execution_control(outer()); } |
| 88 | 88 |
| 89 void Break(Statement* stmt) { PerformCommand(CMD_BREAK, stmt); } | 89 void Break(Statement* stmt) { PerformCommand(CMD_BREAK, stmt); } |
| 90 void Continue(Statement* stmt) { PerformCommand(CMD_CONTINUE, stmt); } | 90 void Continue(Statement* stmt) { PerformCommand(CMD_CONTINUE, stmt); } |
| 91 void ReturnAccumulator() { PerformCommand(CMD_RETURN, nullptr); } | |
| 92 void ReThrowAccumulator() { PerformCommand(CMD_RETHROW, nullptr); } | |
| 93 | |
| 94 class DeferredCommands; | |
| 91 | 95 |
| 92 protected: | 96 protected: |
| 93 enum Command { CMD_BREAK, CMD_CONTINUE }; | 97 enum Command { CMD_BREAK, CMD_CONTINUE, CMD_RETURN, CMD_RETHROW }; |
| 94 void PerformCommand(Command command, Statement* statement); | 98 void PerformCommand(Command command, Statement* statement); |
| 95 virtual bool Execute(Command command, Statement* statement) = 0; | 99 virtual bool Execute(Command command, Statement* statement) = 0; |
| 96 | 100 |
| 97 BytecodeGenerator* generator() const { return generator_; } | 101 BytecodeGenerator* generator() const { return generator_; } |
| 98 ControlScope* outer() const { return outer_; } | 102 ControlScope* outer() const { return outer_; } |
| 99 | 103 |
| 100 private: | 104 private: |
| 101 BytecodeGenerator* generator_; | 105 BytecodeGenerator* generator_; |
| 102 ControlScope* outer_; | 106 ControlScope* outer_; |
| 103 | 107 |
| 104 DISALLOW_COPY_AND_ASSIGN(ControlScope); | 108 DISALLOW_COPY_AND_ASSIGN(ControlScope); |
| 105 }; | 109 }; |
| 106 | 110 |
| 107 | 111 |
| 112 // Helper class for a try-finally control scope. It can record intercepted | |
| 113 // control-flow commands that cause entry into a finally-block, and re-apply | |
| 114 // them after again leaving that block. Special tokens are used to identify | |
| 115 // paths going through the finally-block to dispatch after leaving the block. | |
| 116 class BytecodeGenerator::ControlScope::DeferredCommands final { | |
| 117 public: | |
| 118 DeferredCommands(BytecodeGenerator* generator, Register token_register, | |
| 119 Register result_register) | |
| 120 : generator_(generator), | |
| 121 deferred_(generator->zone()), | |
| 122 token_register_(token_register), | |
| 123 result_register_(result_register) {} | |
| 124 | |
| 125 // One recorded control-flow command. | |
| 126 struct Entry { | |
| 127 Command command; // The command type being applied on this path. | |
| 128 Statement* statement; // The target statement for the command or {nullptr}. | |
| 129 int token; // A token identifying this particular path. | |
| 130 }; | |
| 131 | |
| 132 // Records a control-flow command while entering the finally-block. This also | |
| 133 // generates a new dispatch token that identifies one particular path. | |
|
rmcilroy
2016/01/21 14:30:49
Add a comment that this expects the result to be i
Michael Starzinger
2016/01/22 10:18:11
Done.
| |
| 134 void RecordCommand(Command command, Statement* statement) { | |
| 135 int token = static_cast<int>(deferred_.size()); | |
| 136 deferred_.push_back({command, statement, token}); | |
| 137 builder()->StoreAccumulatorInRegister(result_register_); | |
|
rmcilroy
2016/01/21 14:30:49
nit - newline above here
Michael Starzinger
2016/01/22 10:18:11
Done.
| |
| 138 builder()->LoadLiteral(Smi::FromInt(token)); | |
| 139 builder()->StoreAccumulatorInRegister(token_register_); | |
| 140 } | |
| 141 | |
| 142 // Records the dispatch token to be used to identify the re-throw path when | |
| 143 // the finally-block has been entered through the exception handler. | |
|
rmcilroy
2016/01/21 14:30:49
Ditto (comment that exception should be in accumul
Michael Starzinger
2016/01/22 10:18:11
Done.
| |
| 144 void RecordHandlerReThrowPath() { | |
| 145 // The accumulator contains the exception object. | |
| 146 RecordCommand(CMD_RETHROW, nullptr); | |
| 147 } | |
| 148 | |
| 149 // Records the dispatch token to be used to identify the implicit fall-through | |
| 150 // path at the end of a try-block into the corresponding finally-block. | |
| 151 void RecordFallThroughPath() { | |
| 152 builder()->LoadLiteral(Smi::FromInt(-1)); | |
| 153 builder()->StoreAccumulatorInRegister(token_register_); | |
| 154 } | |
| 155 | |
| 156 // Applies all recorded control-flow commands after the finally-block again. | |
| 157 // This generates a dynamic dispatch on the token from the entry point. | |
| 158 void ApplyDeferredCommands() { | |
| 159 SwitchBuilder dispatch(builder(), static_cast<int>(deferred_.size() + 1)); | |
|
oth
2016/01/21 14:06:44
Comment on the +1.
Michael Starzinger
2016/01/21 14:24:53
Done.
| |
| 160 for (size_t i = 0; i < deferred_.size(); ++i) { | |
| 161 Entry& entry = deferred_[i]; | |
| 162 builder()->LoadLiteral(Smi::FromInt(entry.token)); | |
| 163 builder()->CompareOperation(Token::EQ_STRICT, token_register_, | |
| 164 Strength::WEAK); | |
| 165 dispatch.Case(static_cast<int>(i)); | |
| 166 } | |
| 167 dispatch.DefaultAt(static_cast<int>(deferred_.size())); | |
|
rmcilroy
2016/01/21 14:30:49
I'm guessing the default case here only for the fa
Michael Starzinger
2016/01/22 10:18:11
Acknowledged. Comment already added due to Orions
| |
| 168 for (size_t i = 0; i < deferred_.size(); ++i) { | |
| 169 Entry& entry = deferred_[i]; | |
| 170 dispatch.SetCaseTarget(static_cast<int>(i)); | |
| 171 builder()->LoadAccumulatorWithRegister(result_register_); | |
| 172 execution_control()->PerformCommand(entry.command, entry.statement); | |
| 173 } | |
| 174 dispatch.SetCaseTarget(static_cast<int>(deferred_.size())); | |
| 175 } | |
| 176 | |
| 177 BytecodeArrayBuilder* builder() { return generator_->builder(); } | |
| 178 ControlScope* execution_control() { return generator_->execution_control(); } | |
| 179 | |
| 180 private: | |
| 181 BytecodeGenerator* generator_; | |
| 182 ZoneVector<Entry> deferred_; | |
| 183 Register token_register_; | |
| 184 Register result_register_; | |
| 185 }; | |
| 186 | |
| 187 | |
| 188 // Scoped class for dealing with control flow reaching the function level. | |
| 189 class BytecodeGenerator::ControlScopeForTopLevel final | |
| 190 : public BytecodeGenerator::ControlScope { | |
| 191 public: | |
| 192 explicit ControlScopeForTopLevel(BytecodeGenerator* generator) | |
| 193 : ControlScope(generator) {} | |
| 194 | |
| 195 protected: | |
| 196 virtual bool Execute(Command command, Statement* statement) { | |
| 197 switch (command) { | |
| 198 case CMD_BREAK: | |
| 199 case CMD_CONTINUE: | |
| 200 break; | |
| 201 case CMD_RETURN: | |
| 202 generator()->builder()->Return(); | |
| 203 return true; | |
| 204 case CMD_RETHROW: | |
| 205 // TODO(mstarzinger): Should be a ReThrow instead. | |
| 206 generator()->builder()->Throw(); | |
| 207 return true; | |
| 208 } | |
| 209 return false; | |
| 210 } | |
| 211 }; | |
| 212 | |
| 213 | |
| 108 // Scoped class for enabling break inside blocks and switch blocks. | 214 // Scoped class for enabling break inside blocks and switch blocks. |
| 109 class BytecodeGenerator::ControlScopeForBreakable final | 215 class BytecodeGenerator::ControlScopeForBreakable final |
| 110 : public BytecodeGenerator::ControlScope { | 216 : public BytecodeGenerator::ControlScope { |
| 111 public: | 217 public: |
| 112 ControlScopeForBreakable(BytecodeGenerator* generator, | 218 ControlScopeForBreakable(BytecodeGenerator* generator, |
| 113 BreakableStatement* statement, | 219 BreakableStatement* statement, |
| 114 BreakableControlFlowBuilder* control_builder) | 220 BreakableControlFlowBuilder* control_builder) |
| 115 : ControlScope(generator), | 221 : ControlScope(generator), |
| 116 statement_(statement), | 222 statement_(statement), |
| 117 control_builder_(control_builder) {} | 223 control_builder_(control_builder) {} |
| 118 | 224 |
| 119 protected: | 225 protected: |
| 120 virtual bool Execute(Command command, Statement* statement) { | 226 virtual bool Execute(Command command, Statement* statement) { |
| 121 if (statement != statement_) return false; | 227 if (statement != statement_) return false; |
| 122 switch (command) { | 228 switch (command) { |
| 123 case CMD_BREAK: | 229 case CMD_BREAK: |
| 124 control_builder_->Break(); | 230 control_builder_->Break(); |
| 125 return true; | 231 return true; |
| 126 case CMD_CONTINUE: | 232 case CMD_CONTINUE: |
| 233 case CMD_RETURN: | |
| 234 case CMD_RETHROW: | |
| 127 break; | 235 break; |
| 128 } | 236 } |
| 129 return false; | 237 return false; |
| 130 } | 238 } |
| 131 | 239 |
| 132 private: | 240 private: |
| 133 Statement* statement_; | 241 Statement* statement_; |
| 134 BreakableControlFlowBuilder* control_builder_; | 242 BreakableControlFlowBuilder* control_builder_; |
| 135 }; | 243 }; |
| 136 | 244 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 150 protected: | 258 protected: |
| 151 virtual bool Execute(Command command, Statement* statement) { | 259 virtual bool Execute(Command command, Statement* statement) { |
| 152 if (statement != statement_) return false; | 260 if (statement != statement_) return false; |
| 153 switch (command) { | 261 switch (command) { |
| 154 case CMD_BREAK: | 262 case CMD_BREAK: |
| 155 loop_builder_->Break(); | 263 loop_builder_->Break(); |
| 156 return true; | 264 return true; |
| 157 case CMD_CONTINUE: | 265 case CMD_CONTINUE: |
| 158 loop_builder_->Continue(); | 266 loop_builder_->Continue(); |
| 159 return true; | 267 return true; |
| 268 case CMD_RETURN: | |
| 269 case CMD_RETHROW: | |
| 270 break; | |
| 160 } | 271 } |
| 161 return false; | 272 return false; |
| 162 } | 273 } |
| 163 | 274 |
| 164 private: | 275 private: |
| 165 Statement* statement_; | 276 Statement* statement_; |
| 166 LoopBuilder* loop_builder_; | 277 LoopBuilder* loop_builder_; |
| 167 }; | 278 }; |
| 168 | 279 |
| 169 | 280 |
| 281 // Scoped class for enabling 'throw' in try-catch constructs. | |
| 282 class BytecodeGenerator::ControlScopeForTryCatch final | |
| 283 : public BytecodeGenerator::ControlScope { | |
| 284 public: | |
| 285 ControlScopeForTryCatch(BytecodeGenerator* generator, | |
| 286 TryCatchBuilder* try_catch_builder) | |
| 287 : ControlScope(generator), try_catch_builder_(try_catch_builder) {} | |
| 288 | |
| 289 protected: | |
| 290 virtual bool Execute(Command command, Statement* statement) { | |
| 291 switch (command) { | |
| 292 case CMD_BREAK: | |
| 293 case CMD_CONTINUE: | |
| 294 case CMD_RETURN: | |
| 295 break; | |
| 296 case CMD_RETHROW: | |
| 297 USE(try_catch_builder_); | |
|
rmcilroy
2016/01/21 14:30:49
nit - add a TODO here for now?
Michael Starzinger
2016/01/22 10:18:11
Done.
| |
| 298 UNIMPLEMENTED(); | |
| 299 return true; | |
| 300 } | |
| 301 return false; | |
| 302 } | |
| 303 | |
| 304 private: | |
| 305 TryCatchBuilder* try_catch_builder_; | |
| 306 }; | |
| 307 | |
| 308 | |
| 309 // Scoped class for enabling control flow through try-finally constructs. | |
| 310 class BytecodeGenerator::ControlScopeForTryFinally final | |
| 311 : public BytecodeGenerator::ControlScope { | |
| 312 public: | |
| 313 ControlScopeForTryFinally(BytecodeGenerator* generator, | |
| 314 TryFinallyBuilder* try_finally_builder, | |
| 315 DeferredCommands* commands) | |
| 316 : ControlScope(generator), | |
| 317 try_finally_builder_(try_finally_builder), | |
| 318 commands_(commands) {} | |
| 319 | |
| 320 protected: | |
| 321 virtual bool Execute(Command command, Statement* statement) { | |
| 322 switch (command) { | |
| 323 case CMD_BREAK: | |
| 324 case CMD_CONTINUE: | |
| 325 case CMD_RETURN: | |
| 326 case CMD_RETHROW: | |
| 327 commands_->RecordCommand(command, statement); | |
| 328 try_finally_builder_->LeaveTry(); | |
| 329 return true; | |
| 330 } | |
| 331 return false; | |
| 332 } | |
| 333 | |
| 334 private: | |
| 335 TryFinallyBuilder* try_finally_builder_; | |
| 336 DeferredCommands* commands_; | |
| 337 }; | |
| 338 | |
| 339 | |
| 170 void BytecodeGenerator::ControlScope::PerformCommand(Command command, | 340 void BytecodeGenerator::ControlScope::PerformCommand(Command command, |
| 171 Statement* statement) { | 341 Statement* statement) { |
| 172 ControlScope* current = this; | 342 ControlScope* current = this; |
| 173 do { | 343 do { |
| 174 if (current->Execute(command, statement)) return; | 344 if (current->Execute(command, statement)) return; |
| 175 current = current->outer(); | 345 current = current->outer(); |
| 176 } while (current != nullptr); | 346 } while (current != nullptr); |
| 177 UNREACHABLE(); | 347 UNREACHABLE(); |
| 178 } | 348 } |
| 179 | 349 |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 } | 528 } |
| 359 | 529 |
| 360 | 530 |
| 361 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { | 531 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { |
| 362 set_info(info); | 532 set_info(info); |
| 363 set_scope(info->scope()); | 533 set_scope(info->scope()); |
| 364 | 534 |
| 365 // Initialize the incoming context. | 535 // Initialize the incoming context. |
| 366 ContextScope incoming_context(this, scope(), false); | 536 ContextScope incoming_context(this, scope(), false); |
| 367 | 537 |
| 538 // Initialize control scope. | |
| 539 ControlScopeForTopLevel control(this); | |
| 540 | |
| 368 builder()->set_parameter_count(info->num_parameters_including_this()); | 541 builder()->set_parameter_count(info->num_parameters_including_this()); |
| 369 builder()->set_locals_count(scope()->num_stack_slots()); | 542 builder()->set_locals_count(scope()->num_stack_slots()); |
| 370 builder()->set_context_count(scope()->MaxNestedContextChainLength()); | 543 builder()->set_context_count(scope()->MaxNestedContextChainLength()); |
| 371 | 544 |
| 372 // Build function context only if there are context allocated variables. | 545 // Build function context only if there are context allocated variables. |
| 373 if (scope()->NeedsContext()) { | 546 if (scope()->NeedsContext()) { |
| 374 // Push a new inner context scope for the function. | 547 // Push a new inner context scope for the function. |
| 375 VisitNewLocalFunctionContext(); | 548 VisitNewLocalFunctionContext(); |
| 376 ContextScope local_function_context(this, scope(), false); | 549 ContextScope local_function_context(this, scope(), false); |
| 377 VisitBuildLocalActivationContext(); | 550 VisitBuildLocalActivationContext(); |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 654 } | 827 } |
| 655 | 828 |
| 656 | 829 |
| 657 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { | 830 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
| 658 execution_control()->Break(stmt->target()); | 831 execution_control()->Break(stmt->target()); |
| 659 } | 832 } |
| 660 | 833 |
| 661 | 834 |
| 662 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 835 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
| 663 VisitForAccumulatorValue(stmt->expression()); | 836 VisitForAccumulatorValue(stmt->expression()); |
| 664 builder()->Return(); | 837 execution_control()->ReturnAccumulator(); |
| 665 } | 838 } |
| 666 | 839 |
| 667 | 840 |
| 668 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { | 841 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { |
| 669 UNIMPLEMENTED(); | 842 UNIMPLEMENTED(); |
| 670 } | 843 } |
| 671 | 844 |
| 672 | 845 |
| 673 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 846 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 674 // We need this scope because we visit for register values. We have to | 847 // We need this scope because we visit for register values. We have to |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 902 TryCatchBuilder try_control_builder(builder()); | 1075 TryCatchBuilder try_control_builder(builder()); |
| 903 | 1076 |
| 904 // Preserve the context in a dedicated register, so that it can be restored | 1077 // Preserve the context in a dedicated register, so that it can be restored |
| 905 // when the handler is entered by the stack-unwinding machinery. | 1078 // when the handler is entered by the stack-unwinding machinery. |
| 906 // TODO(mstarzinger): Be smarter about register allocation. | 1079 // TODO(mstarzinger): Be smarter about register allocation. |
| 907 Register context = register_allocator()->NewRegister(); | 1080 Register context = register_allocator()->NewRegister(); |
| 908 | 1081 |
| 909 // Evaluate the try-block inside a control scope. This simulates a handler | 1082 // Evaluate the try-block inside a control scope. This simulates a handler |
| 910 // that is intercepting 'throw' control commands. | 1083 // that is intercepting 'throw' control commands. |
| 911 try_control_builder.BeginTry(context); | 1084 try_control_builder.BeginTry(context); |
| 912 // TODO(mstarzinger): Control scope is missing! | 1085 { |
| 913 Visit(stmt->try_block()); | 1086 ControlScopeForTryCatch scope(this, &try_control_builder); |
| 1087 Visit(stmt->try_block()); | |
| 1088 } | |
| 914 try_control_builder.EndTry(); | 1089 try_control_builder.EndTry(); |
| 915 | 1090 |
| 916 // Clear message object as we enter the catch block. | 1091 // Clear message object as we enter the catch block. |
| 917 // TODO(mstarzinger): Implement this! | 1092 // TODO(mstarzinger): Implement this! |
| 918 | 1093 |
| 919 // Create a catch scope that binds the exception. | 1094 // Create a catch scope that binds the exception. |
| 920 VisitNewLocalCatchContext(stmt->variable()); | 1095 VisitNewLocalCatchContext(stmt->variable()); |
| 921 | 1096 |
| 922 // Evaluate the catch-block. | 1097 // Evaluate the catch-block. |
| 923 VisitInScope(stmt->catch_block(), stmt->scope()); | 1098 VisitInScope(stmt->catch_block(), stmt->scope()); |
| 924 try_control_builder.EndCatch(); | 1099 try_control_builder.EndCatch(); |
| 925 } | 1100 } |
| 926 | 1101 |
| 927 | 1102 |
| 928 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | 1103 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
| 929 TryFinallyBuilder try_control_builder(builder()); | 1104 TryFinallyBuilder try_control_builder(builder()); |
| 930 | 1105 |
| 1106 // We keep a record of all paths that enter the finally-block to be able to | |
| 1107 // dispatch to the correct continuation point after the statements in the | |
| 1108 // finally-block have been evaluated. | |
| 1109 // | |
| 1110 // The try-finally construct can enter the finally-block in three ways: | |
| 1111 // 1. By exiting the try-block normally, falling through at the end. | |
| 1112 // 2. By exiting the try-block with a function-local control flow transfer | |
| 1113 // (i.e. through break/continue/return statements). | |
| 1114 // 3. By exiting the try-block with a thrown exception. | |
| 1115 // | |
| 1116 // The result register semantics depend on how the block was entered: | |
| 1117 // - ReturnStatement: It represents the return value being returned. | |
| 1118 // - ThrowStatement: It represents the exception being thrown. | |
| 1119 // - BreakStatement/ContinueStatement: Undefined and not used. | |
| 1120 // - Falling through into finally-block: Undefined and not used. | |
| 1121 Register token = register_allocator()->NewRegister(); | |
| 1122 Register result = register_allocator()->NewRegister(); | |
| 1123 ControlScope::DeferredCommands commands(this, token, result); | |
| 1124 | |
| 931 // Preserve the context in a dedicated register, so that it can be restored | 1125 // Preserve the context in a dedicated register, so that it can be restored |
| 932 // when the handler is entered by the stack-unwinding machinery. | 1126 // when the handler is entered by the stack-unwinding machinery. |
| 933 // TODO(mstarzinger): Be smarter about register allocation. | 1127 // TODO(mstarzinger): Be smarter about register allocation. |
| 934 Register context = register_allocator()->NewRegister(); | 1128 Register context = register_allocator()->NewRegister(); |
| 935 | 1129 |
| 936 // Evaluate the try-block inside a control scope. This simulates a handler | 1130 // Evaluate the try-block inside a control scope. This simulates a handler |
| 937 // that is intercepting all control commands. | 1131 // that is intercepting all control commands. |
| 938 try_control_builder.BeginTry(context); | 1132 try_control_builder.BeginTry(context); |
| 939 // TODO(mstarzinger): Control scope is missing! | 1133 { |
| 940 Visit(stmt->try_block()); | 1134 ControlScopeForTryFinally scope(this, &try_control_builder, &commands); |
| 1135 Visit(stmt->try_block()); | |
| 1136 } | |
| 941 try_control_builder.EndTry(); | 1137 try_control_builder.EndTry(); |
| 942 | 1138 |
| 1139 // Record fall-through and exception cases. | |
| 1140 commands.RecordFallThroughPath(); | |
| 1141 try_control_builder.LeaveTry(); | |
| 1142 try_control_builder.BeginHandler(); | |
| 1143 commands.RecordHandlerReThrowPath(); | |
| 1144 try_control_builder.BeginFinally(); | |
|
rmcilroy
2016/01/21 14:30:49
nit - newline before BeginFinally (I think it woul
Michael Starzinger
2016/01/22 10:18:11
Done. Also note that there is still functionality
| |
| 1145 | |
| 943 // Clear message object as we enter the finally block. | 1146 // Clear message object as we enter the finally block. |
| 944 // TODO(mstarzinger): Implement this! | 1147 // TODO(mstarzinger): Implement this! |
| 945 | 1148 |
| 946 // Evaluate the finally-block. | 1149 // Evaluate the finally-block. |
| 947 Visit(stmt->finally_block()); | 1150 Visit(stmt->finally_block()); |
| 948 try_control_builder.EndFinally(); | 1151 try_control_builder.EndFinally(); |
| 1152 | |
| 1153 // Dynamic dispatch after the finally-block. | |
| 1154 commands.ApplyDeferredCommands(); | |
| 949 } | 1155 } |
| 950 | 1156 |
| 951 | 1157 |
| 952 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { | 1158 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { |
| 953 UNIMPLEMENTED(); | 1159 UNIMPLEMENTED(); |
| 954 } | 1160 } |
| 955 | 1161 |
| 956 | 1162 |
| 957 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 1163 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 958 // Find or build a shared function info. | 1164 // Find or build a shared function info. |
| (...skipping 1319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2278 } | 2484 } |
| 2279 | 2485 |
| 2280 | 2486 |
| 2281 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 2487 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
| 2282 return info()->feedback_vector()->GetIndex(slot); | 2488 return info()->feedback_vector()->GetIndex(slot); |
| 2283 } | 2489 } |
| 2284 | 2490 |
| 2285 } // namespace interpreter | 2491 } // namespace interpreter |
| 2286 } // namespace internal | 2492 } // namespace internal |
| 2287 } // namespace v8 | 2493 } // namespace v8 |
| OLD | NEW |