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/compile-time-value.h" | 7 #include "src/ast/compile-time-value.h" |
8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/compilation-info.h" | 10 #include "src/compilation-info.h" |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 explicit ControlScopeForTopLevel(BytecodeGenerator* generator) | 210 explicit ControlScopeForTopLevel(BytecodeGenerator* generator) |
211 : ControlScope(generator) {} | 211 : ControlScope(generator) {} |
212 | 212 |
213 protected: | 213 protected: |
214 bool Execute(Command command, Statement* statement) override { | 214 bool Execute(Command command, Statement* statement) override { |
215 switch (command) { | 215 switch (command) { |
216 case CMD_BREAK: // We should never see break/continue in top-level. | 216 case CMD_BREAK: // We should never see break/continue in top-level. |
217 case CMD_CONTINUE: | 217 case CMD_CONTINUE: |
218 UNREACHABLE(); | 218 UNREACHABLE(); |
219 case CMD_RETURN: | 219 case CMD_RETURN: |
220 generator()->builder()->Return(); | 220 generator()->BuildReturn(); |
221 return true; | 221 return true; |
222 case CMD_RETHROW: | 222 case CMD_RETHROW: |
223 generator()->builder()->ReThrow(); | 223 generator()->BuildReThrow(); |
224 return true; | 224 return true; |
225 } | 225 } |
226 return false; | 226 return false; |
227 } | 227 } |
228 }; | 228 }; |
229 | 229 |
230 // Scoped class for enabling break inside blocks and switch blocks. | 230 // Scoped class for enabling break inside blocks and switch blocks. |
231 class BytecodeGenerator::ControlScopeForBreakable final | 231 class BytecodeGenerator::ControlScopeForBreakable final |
232 : public BytecodeGenerator::ControlScope { | 232 : public BytecodeGenerator::ControlScope { |
233 public: | 233 public: |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 : ControlScope(generator) {} | 304 : ControlScope(generator) {} |
305 | 305 |
306 protected: | 306 protected: |
307 bool Execute(Command command, Statement* statement) override { | 307 bool Execute(Command command, Statement* statement) override { |
308 switch (command) { | 308 switch (command) { |
309 case CMD_BREAK: | 309 case CMD_BREAK: |
310 case CMD_CONTINUE: | 310 case CMD_CONTINUE: |
311 case CMD_RETURN: | 311 case CMD_RETURN: |
312 break; | 312 break; |
313 case CMD_RETHROW: | 313 case CMD_RETHROW: |
314 generator()->builder()->ReThrow(); | 314 generator()->BuildReThrow(); |
315 return true; | 315 return true; |
316 } | 316 } |
317 return false; | 317 return false; |
318 } | 318 } |
319 }; | 319 }; |
320 | 320 |
321 // Scoped class for enabling control flow through try-finally constructs. | 321 // Scoped class for enabling control flow through try-finally constructs. |
322 class BytecodeGenerator::ControlScopeForTryFinally final | 322 class BytecodeGenerator::ControlScopeForTryFinally final |
323 : public BytecodeGenerator::ControlScope { | 323 : public BytecodeGenerator::ControlScope { |
324 public: | 324 public: |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
642 } | 642 } |
643 | 643 |
644 // In generator functions, we may not have visited every yield in the AST | 644 // In generator functions, we may not have visited every yield in the AST |
645 // since we skip some obviously dead code. Hence the generated bytecode may | 645 // since we skip some obviously dead code. Hence the generated bytecode may |
646 // contain jumps to unbound labels (resume points that will never be used). | 646 // contain jumps to unbound labels (resume points that will never be used). |
647 // We bind these now. | 647 // We bind these now. |
648 for (auto& label : generator_resume_points_) { | 648 for (auto& label : generator_resume_points_) { |
649 if (!label.is_bound()) builder()->Bind(&label); | 649 if (!label.is_bound()) builder()->Bind(&label); |
650 } | 650 } |
651 | 651 |
652 builder()->EnsureReturn(); | 652 // Emit an implicit return instruction in case control flow can fall off the |
| 653 // end of the function without an explicit return being present on all paths. |
| 654 if (builder()->RequiresImplicitReturn()) { |
| 655 builder()->LoadUndefined(); |
| 656 BuildReturn(); |
| 657 } |
| 658 DCHECK(!builder()->RequiresImplicitReturn()); |
653 } | 659 } |
654 | 660 |
655 void BytecodeGenerator::GenerateBytecodeBody() { | 661 void BytecodeGenerator::GenerateBytecodeBody() { |
656 // Build the arguments object if it is used. | 662 // Build the arguments object if it is used. |
657 VisitArgumentsObject(scope()->arguments()); | 663 VisitArgumentsObject(scope()->arguments()); |
658 | 664 |
659 // Build rest arguments array if it is used. | 665 // Build rest arguments array if it is used. |
660 Variable* rest_parameter = scope()->rest_parameter(); | 666 Variable* rest_parameter = scope()->rest_parameter(); |
661 VisitRestArgumentsArray(rest_parameter); | 667 VisitRestArgumentsArray(rest_parameter); |
662 | 668 |
663 // Build assignment to {.this_function} variable if it is used. | 669 // Build assignment to {.this_function} variable if it is used. |
664 VisitThisFunctionVariable(scope()->this_function_var()); | 670 VisitThisFunctionVariable(scope()->this_function_var()); |
665 | 671 |
666 // Build assignment to {new.target} variable if it is used. | 672 // Build assignment to {new.target} variable if it is used. |
667 VisitNewTargetVariable(scope()->new_target_var()); | 673 VisitNewTargetVariable(scope()->new_target_var()); |
668 | 674 |
669 // TODO(rmcilroy): Emit tracing call if requested to do so. | 675 // Emit tracing call if requested to do so. |
670 if (FLAG_trace) { | 676 if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter); |
671 UNIMPLEMENTED(); | |
672 } | |
673 | 677 |
674 // Visit declarations within the function scope. | 678 // Visit declarations within the function scope. |
675 VisitDeclarations(scope()->declarations()); | 679 VisitDeclarations(scope()->declarations()); |
676 | 680 |
677 // Perform a stack-check before the body. | 681 // Perform a stack-check before the body. |
678 builder()->StackCheck(info()->literal()->start_position()); | 682 builder()->StackCheck(info()->literal()->start_position()); |
679 | 683 |
680 // Visit statements in the function body. | 684 // Visit statements in the function body. |
681 VisitStatements(info()->literal()->body()); | 685 VisitStatements(info()->literal()->body()); |
682 } | 686 } |
(...skipping 1165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1848 } | 1852 } |
1849 } | 1853 } |
1850 } | 1854 } |
1851 | 1855 |
1852 void BytecodeGenerator::VisitVariableLoadForAccumulatorValue( | 1856 void BytecodeGenerator::VisitVariableLoadForAccumulatorValue( |
1853 Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) { | 1857 Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) { |
1854 ValueResultScope accumulator_result(this); | 1858 ValueResultScope accumulator_result(this); |
1855 VisitVariableLoad(variable, slot, typeof_mode); | 1859 VisitVariableLoad(variable, slot, typeof_mode); |
1856 } | 1860 } |
1857 | 1861 |
| 1862 void BytecodeGenerator::BuildReturn() { |
| 1863 if (FLAG_trace) { |
| 1864 RegisterAllocationScope register_scope(this); |
| 1865 Register result = register_allocator()->NewRegister(); |
| 1866 // Runtime returns {result} value, preserving accumulator. |
| 1867 builder()->StoreAccumulatorInRegister(result).CallRuntime( |
| 1868 Runtime::kTraceExit, result); |
| 1869 } |
| 1870 builder()->Return(); |
| 1871 } |
| 1872 |
| 1873 void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); } |
| 1874 |
1858 void BytecodeGenerator::BuildAbort(BailoutReason bailout_reason) { | 1875 void BytecodeGenerator::BuildAbort(BailoutReason bailout_reason) { |
1859 RegisterAllocationScope register_scope(this); | 1876 RegisterAllocationScope register_scope(this); |
1860 Register reason = register_allocator()->NewRegister(); | 1877 Register reason = register_allocator()->NewRegister(); |
1861 builder() | 1878 builder() |
1862 ->LoadLiteral(Smi::FromInt(static_cast<int>(bailout_reason))) | 1879 ->LoadLiteral(Smi::FromInt(static_cast<int>(bailout_reason))) |
1863 .StoreAccumulatorInRegister(reason) | 1880 .StoreAccumulatorInRegister(reason) |
1864 .CallRuntime(Runtime::kAbort, reason); | 1881 .CallRuntime(Runtime::kAbort, reason); |
1865 } | 1882 } |
1866 | 1883 |
1867 void BytecodeGenerator::BuildThrowReferenceError(Handle<String> name) { | 1884 void BytecodeGenerator::BuildThrowReferenceError(Handle<String> name) { |
(...skipping 1278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3146 } | 3163 } |
3147 | 3164 |
3148 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { | 3165 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { |
3149 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict | 3166 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict |
3150 : Runtime::kStoreKeyedToSuper_Sloppy; | 3167 : Runtime::kStoreKeyedToSuper_Sloppy; |
3151 } | 3168 } |
3152 | 3169 |
3153 } // namespace interpreter | 3170 } // namespace interpreter |
3154 } // namespace internal | 3171 } // namespace internal |
3155 } // namespace v8 | 3172 } // namespace v8 |
OLD | NEW |