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/builtins/builtins-constructor.h" | 9 #include "src/builtins/builtins-constructor.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 builder()->LoadAccumulatorWithRegister(result_register_); | 192 builder()->LoadAccumulatorWithRegister(result_register_); |
193 execution_control()->PerformCommand(entry.command, entry.statement); | 193 execution_control()->PerformCommand(entry.command, entry.statement); |
194 } | 194 } |
195 dispatch.SetCaseTarget(static_cast<int>(deferred_.size())); | 195 dispatch.SetCaseTarget(static_cast<int>(deferred_.size())); |
196 } | 196 } |
197 | 197 |
198 BytecodeArrayBuilder* builder() { return generator_->builder(); } | 198 BytecodeArrayBuilder* builder() { return generator_->builder(); } |
199 ControlScope* execution_control() { return generator_->execution_control(); } | 199 ControlScope* execution_control() { return generator_->execution_control(); } |
200 | 200 |
201 private: | 201 private: |
202 BytecodeGenerator* generator_; | 202 BytecodeGenerator* generator_ = nullptr; |
rmcilroy
2017/02/07 17:24:41
Why was this change made? The constructor should s
| |
203 ZoneVector<Entry> deferred_; | 203 ZoneVector<Entry> deferred_; |
204 Register token_register_; | 204 Register token_register_; |
205 Register result_register_; | 205 Register result_register_; |
206 }; | 206 }; |
207 | 207 |
208 // Scoped class for dealing with control flow reaching the function level. | 208 // Scoped class for dealing with control flow reaching the function level. |
209 class BytecodeGenerator::ControlScopeForTopLevel final | 209 class BytecodeGenerator::ControlScopeForTopLevel final |
210 : public BytecodeGenerator::ControlScope { | 210 : public BytecodeGenerator::ControlScope { |
211 public: | 211 public: |
212 explicit ControlScopeForTopLevel(BytecodeGenerator* generator) | 212 explicit ControlScopeForTopLevel(BytecodeGenerator* generator) |
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
573 Handle<String> name; | 573 Handle<String> name; |
574 FeedbackVectorSlot slot; | 574 FeedbackVectorSlot slot; |
575 FeedbackVectorSlot literal_slot; | 575 FeedbackVectorSlot literal_slot; |
576 FunctionLiteral* func; | 576 FunctionLiteral* func; |
577 }; | 577 }; |
578 ZoneVector<Declaration> declarations_; | 578 ZoneVector<Declaration> declarations_; |
579 size_t constant_pool_entry_; | 579 size_t constant_pool_entry_; |
580 bool has_constant_pool_entry_; | 580 bool has_constant_pool_entry_; |
581 }; | 581 }; |
582 | 582 |
583 template <class T> | |
584 class TryBlockBuilder; | |
585 class BytecodeGenerator::SimpleTryCatchBuilder : private TryCatchBuilder { | |
586 public: | |
587 typedef ControlScopeForTryCatch TryControlScope; | |
588 | |
589 explicit SimpleTryCatchBuilder(BytecodeGenerator* generator, | |
590 HandlerTable::CatchPrediction catch_prediction) | |
591 : TryCatchBuilder(generator->builder(), catch_prediction), | |
592 generator_(generator) {} | |
593 | |
594 Register context() const { | |
595 DCHECK(context_.is_valid()); | |
596 return context_; | |
597 } | |
598 | |
599 private: | |
600 friend class TryBlockBuilder<SimpleTryCatchBuilder>; | |
601 friend class CatchBlockBuilder; | |
602 | |
603 void BeginTry(ControlScopeForTryCatch* scope) { | |
604 DCHECK_NULL(control_scope_); | |
605 control_scope_ = scope; | |
606 | |
607 // Preserve the context in a dedicated register, so that it can be restored | |
608 // when the handler is entered by the stack-unwinding machinery. | |
609 // TODO(mstarzinger): Be smarter about register allocation. | |
610 DCHECK(!context_.is_valid()); | |
611 context_ = generator_->register_allocator()->NewRegister(); | |
612 builder()->MoveRegister(Register::current_context(), context_); | |
613 | |
614 TryCatchBuilder::BeginTry(context_); | |
615 last_catch_prediction_ = generator_->catch_prediction_; | |
616 if (catch_prediction() != HandlerTable::UNCAUGHT) { | |
617 generator_->catch_prediction_ = catch_prediction(); | |
618 } | |
rmcilroy
2017/02/07 17:24:41
I'm not sure why we need to update the catch predi
| |
619 } | |
620 | |
621 void EndTry() { | |
622 DCHECK_NOT_NULL(control_scope_); | |
623 generator_->catch_prediction_ = last_catch_prediction_; | |
624 last_catch_prediction_ = HandlerTable::UNCAUGHT; | |
625 | |
626 TryCatchBuilder::EndTry(); | |
627 control_scope_ = nullptr; | |
628 } | |
629 | |
630 void BeginCatch() { | |
631 DCHECK_NULL(control_scope_); | |
632 DCHECK(context_.is_valid()); | |
633 } | |
634 | |
635 void EndCatch() { TryCatchBuilder::EndCatch(); } | |
636 | |
637 BytecodeGenerator* generator_; | |
638 Register context_; | |
639 ControlScopeForTryCatch* control_scope_ = nullptr; | |
640 HandlerTable::CatchPrediction last_catch_prediction_; | |
641 }; | |
642 | |
643 class BytecodeGenerator::SimpleTryFinallyBuilder : public TryFinallyBuilder { | |
rmcilroy
2017/02/07 17:24:41
I'm not sure on the naming, why is this SimpleTryF
| |
644 public: | |
645 typedef ControlScopeForTryFinally TryControlScope; | |
646 | |
647 explicit SimpleTryFinallyBuilder(BytecodeGenerator* generator) | |
648 : TryFinallyBuilder(generator->builder(), generator->catch_prediction_), | |
649 generator_(generator), | |
650 token_(generator->register_allocator()->NewRegister()), | |
651 result_(generator->register_allocator()->NewRegister()), | |
652 commands_(generator, token_, result_) { | |
653 // We keep a record of all paths that enter the finally-block to be able to | |
654 // dispatch to the correct continuation point after the statements in the | |
655 // finally-block have been evaluated. | |
656 // | |
657 // The try-finally construct can enter the finally-block in three ways: | |
658 // 1. By exiting the try-block normally, falling through at the end. | |
659 // 2. By exiting the try-block with a function-local control flow transfer | |
660 // (i.e. through break/continue/return statements). | |
661 // 3. By exiting the try-block with a thrown exception. | |
662 // | |
663 // The result register semantics depend on how the block was entered: | |
664 // - ReturnStatement: It represents the return value being returned. | |
665 // - ThrowStatement: It represents the exception being thrown. | |
666 // - BreakStatement/ContinueStatement: Undefined and not used. | |
667 // - Falling through into finally-block: Undefined and not used. | |
668 } | |
669 | |
670 private: | |
671 friend class TryBlockBuilder<SimpleTryFinallyBuilder>; | |
672 friend class FinallyBlockBuilder; | |
673 | |
674 void BeginTry(ControlScopeForTryFinally* control_scope) { | |
675 DCHECK_NULL(control_scope_); | |
676 control_scope_ = control_scope; | |
677 | |
678 // Preserve the context in a dedicated register, so that it can be restored | |
679 // when the handler is entered by the stack-unwinding machinery. | |
680 // TODO(mstarzinger): Be smarter about register allocation. | |
681 DCHECK(!context_or_message_.is_valid()); | |
682 context_or_message_ = generator_->register_allocator()->NewRegister(); | |
683 generator_->builder()->MoveRegister(Register::current_context(), | |
684 context_or_message_); | |
685 | |
686 TryFinallyBuilder::BeginTry(context_or_message_); | |
687 } | |
688 | |
689 void EndTry() { | |
690 DCHECK_NOT_NULL(control_scope_); | |
691 TryFinallyBuilder::EndTry(); | |
692 control_scope_ = nullptr; | |
693 | |
694 // Record fall-through and exception cases. | |
695 commands_.RecordFallThroughPath(); | |
696 TryFinallyBuilder::LeaveTry(); | |
697 TryFinallyBuilder::BeginHandler(); | |
698 commands_.RecordHandlerReThrowPath(); | |
699 } | |
700 | |
701 void BeginFinally() { | |
702 TryFinallyBuilder::BeginFinally(); | |
703 generator_->builder() | |
704 ->LoadTheHole() | |
705 .SetPendingMessage() | |
706 .StoreAccumulatorInRegister(context_or_message_); | |
707 } | |
708 | |
709 void EndFinally() { | |
710 TryFinallyBuilder::EndFinally(); | |
711 | |
712 // Pending message object is restored on exit. | |
713 generator_->builder() | |
714 ->LoadAccumulatorWithRegister(context_or_message_) | |
715 .SetPendingMessage(); | |
716 | |
717 // Dynamic dispatch after the finally-block. | |
718 commands_.ApplyDeferredCommands(); | |
719 } | |
720 | |
721 ControlScopeForTryFinally* control_scope_ = nullptr; | |
722 BytecodeGenerator* generator_; | |
723 Register token_; | |
724 Register result_; | |
725 ControlScope::DeferredCommands commands_; | |
726 Register context_or_message_; | |
727 }; | |
728 | |
729 template <class T> | |
730 class BytecodeGenerator::TryBlockBuilder { | |
rmcilroy
2017/02/07 17:24:41
I don't think the scoped builders are necessary, I
| |
731 public: | |
732 typedef T SimpleControlBuilder; | |
733 explicit TryBlockBuilder(SimpleControlBuilder& builder); | |
734 ~TryBlockBuilder(); | |
735 | |
736 private: | |
737 SimpleControlBuilder* builder_; | |
738 typename SimpleControlBuilder::TryControlScope scope_; | |
739 }; | |
740 | |
741 template <> | |
742 BytecodeGenerator::TryBlockBuilder<BytecodeGenerator::SimpleTryCatchBuilder>:: | |
743 TryBlockBuilder(SimpleTryCatchBuilder& builder) | |
744 : builder_(&builder), scope_(builder_->generator_, builder_) { | |
745 builder_->BeginTry(&scope_); | |
746 } | |
747 | |
748 template <> | |
749 BytecodeGenerator::TryBlockBuilder< | |
750 BytecodeGenerator::SimpleTryCatchBuilder>::~TryBlockBuilder() { | |
751 builder_->EndTry(); | |
752 } | |
753 | |
754 template <> | |
755 BytecodeGenerator::TryBlockBuilder<BytecodeGenerator::SimpleTryFinallyBuilder>:: | |
756 TryBlockBuilder(SimpleTryFinallyBuilder& builder) | |
757 : builder_(&builder), | |
758 scope_(builder_->generator_, builder_, &builder_->commands_) { | |
759 builder_->BeginTry(&scope_); | |
760 } | |
761 | |
762 template <> | |
763 BytecodeGenerator::TryBlockBuilder< | |
764 BytecodeGenerator::SimpleTryFinallyBuilder>::~TryBlockBuilder() { | |
765 builder_->EndTry(); | |
766 } | |
767 | |
768 class BytecodeGenerator::CatchBlockBuilder { | |
769 public: | |
770 explicit CatchBlockBuilder(SimpleTryCatchBuilder& builder) | |
771 : builder_(&builder) { | |
772 builder_->BeginCatch(); | |
773 } | |
774 | |
775 ~CatchBlockBuilder() { builder_->EndCatch(); } | |
776 | |
777 private: | |
778 SimpleTryCatchBuilder* builder_; | |
779 }; | |
780 | |
781 class BytecodeGenerator::FinallyBlockBuilder { | |
782 public: | |
783 explicit FinallyBlockBuilder(SimpleTryFinallyBuilder& builder) | |
784 : builder_(&builder) { | |
785 builder_->BeginFinally(); | |
786 } | |
787 | |
788 ~FinallyBlockBuilder() { builder_->EndFinally(); } | |
789 | |
790 private: | |
791 SimpleTryFinallyBuilder* builder_; | |
792 }; | |
793 | |
583 BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) | 794 BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) |
584 : zone_(info->zone()), | 795 : zone_(info->zone()), |
585 builder_(new (zone()) BytecodeArrayBuilder( | 796 builder_(new (zone()) BytecodeArrayBuilder( |
586 info->isolate(), info->zone(), info->num_parameters_including_this(), | 797 info->isolate(), info->zone(), info->num_parameters_including_this(), |
587 info->scope()->MaxNestedContextChainLength(), | 798 info->scope()->MaxNestedContextChainLength(), |
588 info->scope()->num_stack_slots(), info->literal(), | 799 info->scope()->num_stack_slots(), info->literal(), |
589 info->SourcePositionRecordingMode())), | 800 info->SourcePositionRecordingMode())), |
590 info_(info), | 801 info_(info), |
591 scope_(info->scope()), | 802 scope_(info->scope()), |
592 globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->zone())), | 803 globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->zone())), |
593 global_declarations_(0, info->zone()), | 804 global_declarations_(0, info->zone()), |
594 function_literals_(0, info->zone()), | 805 function_literals_(0, info->zone()), |
595 native_function_literals_(0, info->zone()), | 806 native_function_literals_(0, info->zone()), |
596 object_literals_(0, info->zone()), | 807 object_literals_(0, info->zone()), |
597 array_literals_(0, info->zone()), | 808 array_literals_(0, info->zone()), |
598 execution_control_(nullptr), | 809 execution_control_(nullptr), |
599 execution_context_(nullptr), | 810 execution_context_(nullptr), |
600 execution_result_(nullptr), | 811 execution_result_(nullptr), |
601 generator_resume_points_(info->literal()->yield_count(), info->zone()), | 812 generator_resume_points_(info->literal()->yield_count(), info->zone()), |
602 generator_state_(), | 813 generator_state_(), |
603 loop_depth_(0), | 814 loop_depth_(0), |
815 catch_prediction_(HandlerTable::UNCAUGHT), | |
604 home_object_symbol_(info->isolate()->factory()->home_object_symbol()), | 816 home_object_symbol_(info->isolate()->factory()->home_object_symbol()), |
605 iterator_symbol_(info->isolate()->factory()->iterator_symbol()), | 817 iterator_symbol_(info->isolate()->factory()->iterator_symbol()), |
606 prototype_string_(info->isolate()->factory()->prototype_string()), | 818 prototype_string_(info->isolate()->factory()->prototype_string()), |
607 empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()), | 819 empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()), |
608 undefined_string_( | 820 undefined_string_( |
609 info->isolate()->ast_string_constants()->undefined_string()) {} | 821 info->isolate()->ast_string_constants()->undefined_string()) {} |
610 | 822 |
611 Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) { | 823 Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) { |
612 AllocateDeferredConstants(isolate); | 824 AllocateDeferredConstants(isolate); |
613 if (HasStackOverflow()) return Handle<BytecodeArray>(); | 825 if (HasStackOverflow()) return Handle<BytecodeArray>(); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
689 if (scope()->NeedsContext()) { | 901 if (scope()->NeedsContext()) { |
690 // Push a new inner context scope for the function. | 902 // Push a new inner context scope for the function. |
691 BuildNewLocalActivationContext(); | 903 BuildNewLocalActivationContext(); |
692 ContextScope local_function_context(this, scope(), false); | 904 ContextScope local_function_context(this, scope(), false); |
693 BuildLocalActivationContextInitialization(); | 905 BuildLocalActivationContextInitialization(); |
694 GenerateBytecodeBody(); | 906 GenerateBytecodeBody(); |
695 } else { | 907 } else { |
696 GenerateBytecodeBody(); | 908 GenerateBytecodeBody(); |
697 } | 909 } |
698 | 910 |
699 // In generator functions, we may not have visited every yield in the AST | |
700 // since we skip some obviously dead code. Hence the generated bytecode may | |
701 // contain jumps to unbound labels (resume points that will never be used). | |
702 // We bind these now. | |
703 for (auto& label : generator_resume_points_) { | |
704 if (!label.is_bound()) builder()->Bind(&label); | |
705 } | |
706 | |
707 // Emit an implicit return instruction in case control flow can fall off the | 911 // Emit an implicit return instruction in case control flow can fall off the |
708 // end of the function without an explicit return being present on all paths. | 912 // end of the function without an explicit return being present on all paths. |
709 if (builder()->RequiresImplicitReturn()) { | 913 if (builder()->RequiresImplicitReturn()) { |
710 builder()->LoadUndefined(); | 914 builder()->LoadUndefined(); |
711 BuildReturn(); | 915 BuildReturn(); |
712 } | 916 } |
713 DCHECK(!builder()->RequiresImplicitReturn()); | 917 DCHECK(!builder()->RequiresImplicitReturn()); |
714 } | 918 } |
715 | 919 |
716 void BytecodeGenerator::GenerateBytecodeBody() { | 920 void BytecodeGenerator::GenerateBytecodeBody() { |
(...skipping 12 matching lines...) Expand all Loading... | |
729 | 933 |
730 // Emit tracing call if requested to do so. | 934 // Emit tracing call if requested to do so. |
731 if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter); | 935 if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter); |
732 | 936 |
733 // Visit declarations within the function scope. | 937 // Visit declarations within the function scope. |
734 VisitDeclarations(scope()->declarations()); | 938 VisitDeclarations(scope()->declarations()); |
735 | 939 |
736 // Emit initializing assignments for module namespace imports (if any). | 940 // Emit initializing assignments for module namespace imports (if any). |
737 VisitModuleNamespaceImports(); | 941 VisitModuleNamespaceImports(); |
738 | 942 |
943 FunctionLiteral* literal = info()->literal(); | |
944 | |
739 // Perform a stack-check before the body. | 945 // Perform a stack-check before the body. |
740 builder()->StackCheck(info()->literal()->start_position()); | 946 builder()->StackCheck(literal->start_position()); |
741 | 947 |
948 // Build assignment to variable <function name> if function is a named | |
949 // expression and the variable is used. | |
950 if (literal->is_named_expression()) { | |
951 Variable* function_var = scope()->function_var(); | |
952 if (function_var != nullptr && !function_var->IsUnallocated()) { | |
953 builder()->LoadAccumulatorWithRegister(Register::function_closure()); | |
954 BuildVariableAssignment(function_var, Token::INIT, | |
955 FeedbackVectorSlot::Invalid(), | |
956 HoleCheckMode::kElided); | |
957 } | |
958 } | |
959 | |
960 if (IsAsyncFunction(literal->kind())) { | |
961 return GenerateBytecodeBodyForAsyncFunction(literal); | |
962 } | |
963 if (IsGeneratorFunction(literal->kind())) { | |
964 return GenerateBytecodeBodyForGenerator(literal); | |
965 } | |
966 if (IsModule(literal->kind())) { | |
967 return GenerateBytecodeBodyForModule(literal); | |
968 } | |
969 | |
970 Block* parameter_init_block = literal->parameter_init_block(); | |
742 // Visit statements in the function body. | 971 // Visit statements in the function body. |
743 VisitStatements(info()->literal()->body()); | 972 if (parameter_init_block != nullptr) { |
973 VisitBlock(parameter_init_block); | |
974 } | |
975 VisitStatements(literal->body()); | |
976 } | |
977 | |
978 void BytecodeGenerator::BuildAllocateAndStoreJSGeneratorObject( | |
979 FunctionLiteral* literal, BuildJSGeneratorObject tag) { | |
980 RegisterAllocationScope register_scope(this); | |
981 RegisterList args = register_allocator()->NewRegisterList(2); | |
982 builder()->MoveRegister(Register::function_closure(), args[0]); | |
983 | |
984 int yield_position = literal->position(); | |
985 builder()->SetExpressionPosition(yield_position); | |
986 | |
987 if (IsArrowFunction(literal->kind())) { | |
988 // Lexical `this` | |
989 builder()->LoadUndefined().StoreAccumulatorInRegister(args[1]); | |
990 } else { | |
991 // Receiver parameter | |
992 builder()->MoveRegister(builder()->Parameter(0), args[1]); | |
993 } | |
994 builder()->CallRuntime(Runtime::kCreateJSGeneratorObject, args); | |
995 | |
996 Variable* var_generator = scope()->generator_object_var(); | |
997 DCHECK_NOT_NULL(var_generator); | |
998 | |
999 switch (tag) { | |
1000 case BuildJSGeneratorObject::kInitialYield: { | |
1001 Register generator = args[0]; | |
1002 builder()->StoreAccumulatorInRegister(generator); | |
1003 BuildVariableAssignment(var_generator, Token::INIT, | |
1004 FeedbackVectorSlot::Invalid(), | |
1005 HoleCheckMode::kElided); | |
1006 BuildYield(0, generator, generator); | |
1007 BuildYieldResumePoint(0, Yield::kOnExceptionThrow, generator, | |
1008 yield_position); | |
1009 break; | |
1010 } | |
1011 case BuildJSGeneratorObject::kNoInitialYield: { | |
1012 BuildVariableAssignment(var_generator, Token::INIT, | |
1013 FeedbackVectorSlot::Invalid(), | |
1014 HoleCheckMode::kElided); | |
1015 break; | |
1016 } | |
1017 } | |
1018 } | |
1019 | |
1020 void BytecodeGenerator::BuildAllocateAndStoreJSPromise() { | |
1021 Variable* var_promise = scope()->promise_var(); | |
1022 DCHECK_NOT_NULL(var_promise); | |
1023 | |
1024 RegisterAllocationScope register_scope(this); | |
1025 RegisterList args = register_allocator()->NewRegisterList(1); | |
1026 builder()->LoadUndefined().StoreAccumulatorInRegister(args[0]).CallJSRuntime( | |
1027 Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX, args); | |
1028 BuildVariableAssignment(var_promise, Token::INIT, | |
1029 FeedbackVectorSlot::Invalid(), | |
1030 HoleCheckMode::kElided); | |
1031 } | |
1032 | |
1033 void BytecodeGenerator::BindUnboundGeneratorResumePoints() { | |
1034 DCHECK(IsResumableFunction(info()->literal()->kind())); | |
1035 for (auto& label : generator_resume_points_) { | |
1036 if (!label.is_bound()) builder()->Bind(&label); | |
1037 } | |
1038 } | |
1039 | |
1040 void BytecodeGenerator::GenerateBytecodeBodyForGenerator( | |
1041 FunctionLiteral* literal) { | |
1042 DCHECK(IsGeneratorFunction(literal->kind())); | |
1043 | |
1044 // Desugar parameters before generator is allocated. | |
1045 Block* const parameter_init_block = literal->parameter_init_block(); | |
1046 if (parameter_init_block != nullptr) { | |
1047 // Initialize non-simple parameters before initial yield. | |
1048 VisitBlock(parameter_init_block); | |
1049 } | |
1050 | |
1051 { | |
1052 RegisterAllocationScope register_scope(this); | |
1053 SimpleTryFinallyBuilder try_control_builder(this); | |
1054 { // Try ... | |
1055 TryBlockBuilderForFinally try_builder(try_control_builder); | |
1056 BuildAllocateAndStoreJSGeneratorObject( | |
1057 literal, BuildJSGeneratorObject::kInitialYield); | |
1058 VisitStatements(literal->body()); | |
1059 } | |
1060 | |
1061 { // Finally ... | |
1062 FinallyBlockBuilder finally_builder(try_control_builder); | |
1063 Variable* var_generator = scope()->generator_object_var(); | |
1064 DCHECK_NOT_NULL(var_generator); | |
1065 | |
1066 RegisterAllocationScope register_scope(this); | |
1067 BuildVariableLoad(var_generator, FeedbackVectorSlot::Invalid(), | |
1068 HoleCheckMode::kElided); | |
1069 Register generator = register_allocator()->NewRegister(); | |
1070 builder()->StoreAccumulatorInRegister(generator).CallRuntime( | |
1071 Runtime::kInlineGeneratorClose, generator); | |
1072 } | |
1073 } | |
1074 | |
1075 // In generator functions, we may not have visited every yield in the AST | |
1076 // since we skip some obviously dead code. Hence the generated bytecode may | |
1077 // contain jumps to unbound labels (resume points that will never be used). | |
1078 // We bind these now. | |
1079 BindUnboundGeneratorResumePoints(); | |
1080 | |
1081 if (builder()->RequiresImplicitReturn()) { | |
1082 // Unreachable, but required for BytecodeArrayBuilder | |
1083 builder()->LoadUndefined().Return(); | |
1084 } | |
1085 DCHECK(!builder()->RequiresImplicitReturn()); | |
1086 } | |
1087 | |
1088 void BytecodeGenerator::GenerateBytecodeBodyForModule( | |
1089 FunctionLiteral* literal) { | |
1090 DCHECK(IsModule(literal->kind())); | |
1091 | |
1092 // Modules do not have non-simple parameters | |
1093 DCHECK_NULL(literal->parameter_init_block()); | |
1094 | |
1095 BuildAllocateAndStoreJSGeneratorObject(literal, | |
1096 BuildJSGeneratorObject::kInitialYield); | |
1097 VisitStatements(literal->body()); | |
1098 | |
1099 // In modules, we may not have visited every yield in the AST | |
1100 // since we skip some obviously dead code. Hence the generated bytecode may | |
1101 // contain jumps to unbound labels (resume points that will never be used). | |
1102 // We bind these now. | |
1103 BindUnboundGeneratorResumePoints(); | |
1104 } | |
1105 | |
1106 void BytecodeGenerator::GenerateBytecodeBodyForAsyncFunction( | |
1107 FunctionLiteral* literal) { | |
1108 DCHECK(IsAsyncFunction(literal->kind())); | |
1109 | |
1110 BuildAllocateAndStoreJSPromise(); | |
1111 | |
1112 { | |
1113 RegisterAllocationScope register_scope(this); | |
1114 SimpleTryCatchBuilder try_control_builder(this, HandlerTable::ASYNC_AWAIT); | |
1115 { | |
1116 TryBlockBuilderForCatch try_block(try_control_builder); | |
1117 | |
1118 Block* const parameter_init_block = literal->parameter_init_block(); | |
1119 if (parameter_init_block != nullptr) { | |
1120 // Initialize non-simple parameters if necessary, reject Promise in | |
1121 // case of exception | |
1122 RegisterAllocationScope register_scope(this); | |
1123 VisitBlock(parameter_init_block); | |
1124 } | |
1125 | |
1126 BuildAllocateAndStoreJSGeneratorObject( | |
1127 literal, BuildJSGeneratorObject::kNoInitialYield); | |
1128 | |
1129 // Finish generating function body | |
1130 VisitStatements(literal->body()); | |
1131 } | |
1132 | |
1133 { | |
1134 CatchBlockBuilder catch_block(try_control_builder); | |
1135 RegisterList args = register_allocator()->NewRegisterList(4); | |
1136 Register promise = args[1]; | |
1137 Register exception = args[2]; | |
1138 | |
1139 builder() | |
1140 ->StoreAccumulatorInRegister(exception) | |
1141 .LoadTheHole() | |
1142 .SetPendingMessage(); | |
1143 | |
1144 Variable* var_promise = scope()->promise_var(); | |
1145 DCHECK_NOT_NULL(var_promise); | |
1146 BuildVariableLoad(var_promise, FeedbackVectorSlot::Invalid(), | |
1147 HoleCheckMode::kElided); | |
1148 builder() | |
1149 ->StoreAccumulatorInRegister(promise) | |
1150 .LoadUndefined() | |
1151 .StoreAccumulatorInRegister(args[0]) | |
1152 .LoadFalse() | |
1153 .StoreAccumulatorInRegister(args[3]) | |
1154 .CallJSRuntime(Context::PROMISE_INTERNAL_REJECT_INDEX, args) | |
1155 .LoadAccumulatorWithRegister(promise) | |
1156 .Return(); | |
1157 } | |
1158 } | |
1159 | |
1160 // In async functions, we may not have visited every yield in the AST | |
1161 // since we skip some obviously dead code. Hence the generated bytecode may | |
1162 // contain jumps to unbound labels (resume points that will never be used). | |
1163 // We bind these now. | |
1164 BindUnboundGeneratorResumePoints(); | |
1165 | |
1166 if (builder()->RequiresImplicitReturn()) { | |
1167 // Unreachable, but required for BytecodeArrayBuilder | |
1168 builder()->LoadUndefined().Return(); | |
1169 } | |
1170 DCHECK(!builder()->RequiresImplicitReturn()); | |
744 } | 1171 } |
745 | 1172 |
746 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, | 1173 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, |
747 size_t size, | 1174 size_t size, |
748 ZoneVector<BytecodeLabel>& targets) { | 1175 ZoneVector<BytecodeLabel>& targets) { |
749 // TODO(neis): Optimize this by using a proper jump table. | 1176 // TODO(neis): Optimize this by using a proper jump table. |
750 DCHECK_LE(start_index + size, targets.size()); | 1177 DCHECK_LE(start_index + size, targets.size()); |
751 for (size_t i = start_index; i < start_index + size; i++) { | 1178 for (size_t i = start_index; i < start_index + size; i++) { |
752 builder() | 1179 builder() |
753 ->LoadLiteral(Smi::FromInt(static_cast<int>(i))) | 1180 ->LoadLiteral(Smi::FromInt(static_cast<int>(i))) |
(...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1328 VisitForAccumulatorValue(stmt->result_done()); | 1755 VisitForAccumulatorValue(stmt->result_done()); |
1329 loop_builder.BreakIfTrue(); | 1756 loop_builder.BreakIfTrue(); |
1330 | 1757 |
1331 VisitForEffect(stmt->assign_each()); | 1758 VisitForEffect(stmt->assign_each()); |
1332 VisitIterationBody(stmt, &loop_builder); | 1759 VisitIterationBody(stmt, &loop_builder); |
1333 loop_builder.JumpToHeader(loop_depth_); | 1760 loop_builder.JumpToHeader(loop_depth_); |
1334 loop_builder.EndLoop(); | 1761 loop_builder.EndLoop(); |
1335 } | 1762 } |
1336 | 1763 |
1337 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { | 1764 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
1338 TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction()); | 1765 SimpleTryCatchBuilder try_control_builder(this, stmt->catch_prediction()); |
1339 | |
1340 // Preserve the context in a dedicated register, so that it can be restored | |
1341 // when the handler is entered by the stack-unwinding machinery. | |
1342 // TODO(mstarzinger): Be smarter about register allocation. | |
1343 Register context = register_allocator()->NewRegister(); | |
1344 builder()->MoveRegister(Register::current_context(), context); | |
1345 | |
1346 // Evaluate the try-block inside a control scope. This simulates a handler | |
1347 // that is intercepting 'throw' control commands. | |
1348 try_control_builder.BeginTry(context); | |
1349 { | 1766 { |
1350 ControlScopeForTryCatch scope(this, &try_control_builder); | 1767 TryBlockBuilderForCatch try_block(try_control_builder); |
1351 Visit(stmt->try_block()); | 1768 Visit(stmt->try_block()); |
1352 } | 1769 } |
1353 try_control_builder.EndTry(); | |
1354 | 1770 |
1771 // Evaluate the catch-block. | |
1355 // Create a catch scope that binds the exception. | 1772 // Create a catch scope that binds the exception. |
1773 CatchBlockBuilder catch_block(try_control_builder); | |
1774 Register context = try_control_builder.context(); | |
1356 BuildNewLocalCatchContext(stmt->variable(), stmt->scope()); | 1775 BuildNewLocalCatchContext(stmt->variable(), stmt->scope()); |
1357 builder()->StoreAccumulatorInRegister(context); | 1776 builder()->StoreAccumulatorInRegister(context); |
1358 | 1777 |
1359 // If requested, clear message object as we enter the catch block. | 1778 // If requested, clear message object as we enter the catch block. |
1360 if (stmt->clear_pending_message()) { | 1779 if (stmt->clear_pending_message()) { |
1361 builder()->LoadTheHole().SetPendingMessage(); | 1780 builder()->LoadTheHole().SetPendingMessage(); |
1362 } | 1781 } |
1363 | 1782 |
1364 // Load the catch context into the accumulator. | 1783 // Load the catch context into the accumulator. |
1365 builder()->LoadAccumulatorWithRegister(context); | 1784 builder()->LoadAccumulatorWithRegister(context); |
1366 | |
1367 // Evaluate the catch-block. | |
1368 VisitInScope(stmt->catch_block(), stmt->scope()); | 1785 VisitInScope(stmt->catch_block(), stmt->scope()); |
1369 try_control_builder.EndCatch(); | |
1370 } | 1786 } |
1371 | 1787 |
1372 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | 1788 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
1373 TryFinallyBuilder try_control_builder(builder(), stmt->catch_prediction()); | 1789 SimpleTryFinallyBuilder try_control_builder(this); |
1374 | |
1375 // We keep a record of all paths that enter the finally-block to be able to | |
1376 // dispatch to the correct continuation point after the statements in the | |
1377 // finally-block have been evaluated. | |
1378 // | |
1379 // The try-finally construct can enter the finally-block in three ways: | |
1380 // 1. By exiting the try-block normally, falling through at the end. | |
1381 // 2. By exiting the try-block with a function-local control flow transfer | |
1382 // (i.e. through break/continue/return statements). | |
1383 // 3. By exiting the try-block with a thrown exception. | |
1384 // | |
1385 // The result register semantics depend on how the block was entered: | |
1386 // - ReturnStatement: It represents the return value being returned. | |
1387 // - ThrowStatement: It represents the exception being thrown. | |
1388 // - BreakStatement/ContinueStatement: Undefined and not used. | |
1389 // - Falling through into finally-block: Undefined and not used. | |
1390 Register token = register_allocator()->NewRegister(); | |
1391 Register result = register_allocator()->NewRegister(); | |
1392 ControlScope::DeferredCommands commands(this, token, result); | |
1393 | |
1394 // Preserve the context in a dedicated register, so that it can be restored | |
1395 // when the handler is entered by the stack-unwinding machinery. | |
1396 // TODO(mstarzinger): Be smarter about register allocation. | |
1397 Register context = register_allocator()->NewRegister(); | |
1398 builder()->MoveRegister(Register::current_context(), context); | |
1399 | |
1400 // Evaluate the try-block inside a control scope. This simulates a handler | |
1401 // that is intercepting all control commands. | |
1402 try_control_builder.BeginTry(context); | |
1403 { | 1790 { |
1404 ControlScopeForTryFinally scope(this, &try_control_builder, &commands); | 1791 TryBlockBuilderForFinally try_block(try_control_builder); |
1405 Visit(stmt->try_block()); | 1792 Visit(stmt->try_block()); |
1406 } | 1793 } |
1407 try_control_builder.EndTry(); | |
1408 | 1794 |
1409 // Record fall-through and exception cases. | 1795 FinallyBlockBuilder finally_block(try_control_builder); |
1410 commands.RecordFallThroughPath(); | |
1411 try_control_builder.LeaveTry(); | |
1412 try_control_builder.BeginHandler(); | |
1413 commands.RecordHandlerReThrowPath(); | |
1414 | |
1415 // Pending message object is saved on entry. | |
1416 try_control_builder.BeginFinally(); | |
1417 Register message = context; // Reuse register. | |
1418 | |
1419 // Clear message object as we enter the finally block. | |
1420 builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister( | |
1421 message); | |
1422 | |
1423 // Evaluate the finally-block. | |
1424 Visit(stmt->finally_block()); | 1796 Visit(stmt->finally_block()); |
1425 try_control_builder.EndFinally(); | |
1426 | |
1427 // Pending message object is restored on exit. | |
1428 builder()->LoadAccumulatorWithRegister(message).SetPendingMessage(); | |
1429 | |
1430 // Dynamic dispatch after the finally-block. | |
1431 commands.ApplyDeferredCommands(); | |
1432 } | 1797 } |
1433 | 1798 |
1434 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { | 1799 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { |
1435 builder()->SetStatementPosition(stmt); | 1800 builder()->SetStatementPosition(stmt); |
1436 builder()->Debugger(); | 1801 builder()->Debugger(); |
1437 } | 1802 } |
1438 | 1803 |
1439 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 1804 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
1440 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(), | 1805 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(), |
1441 scope()->is_function_scope()); | 1806 scope()->is_function_scope()); |
(...skipping 838 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2280 } | 2645 } |
2281 case KEYED_SUPER_PROPERTY: { | 2646 case KEYED_SUPER_PROPERTY: { |
2282 builder() | 2647 builder() |
2283 ->StoreAccumulatorInRegister(super_property_args[3]) | 2648 ->StoreAccumulatorInRegister(super_property_args[3]) |
2284 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); | 2649 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); |
2285 break; | 2650 break; |
2286 } | 2651 } |
2287 } | 2652 } |
2288 } | 2653 } |
2289 | 2654 |
2290 void BytecodeGenerator::VisitYield(Yield* expr) { | 2655 void BytecodeGenerator::BuildYield(int yield_id, Register generator, |
2291 builder()->SetExpressionPosition(expr); | 2656 Register value) { |
2292 Register value = VisitForRegisterValue(expr->expression()); | 2657 DCHECK_GE(yield_id, 0); |
2293 | 2658 DCHECK_LT(yield_id, generator_resume_points_.size()); |
2294 Register generator = VisitForRegisterValue(expr->generator_object()); | 2659 DCHECK(generator.is_valid()); |
2660 DCHECK(value.is_valid()); | |
2295 | 2661 |
2296 // Save context, registers, and state. Then return. | 2662 // Save context, registers, and state. Then return. |
2297 builder() | 2663 builder() |
2298 ->LoadLiteral(Smi::FromInt(expr->yield_id())) | 2664 ->LoadLiteral(Smi::FromInt(yield_id)) |
2299 .SuspendGenerator(generator) | 2665 .SuspendGenerator(generator) |
2300 .LoadAccumulatorWithRegister(value) | 2666 .LoadAccumulatorWithRegister(value) |
2301 .Return(); // Hard return (ignore any finally blocks). | 2667 .Return(); // Hard return (ignore any finally blocks). |
2668 } | |
2302 | 2669 |
2303 builder()->Bind(&(generator_resume_points_[expr->yield_id()])); | 2670 void BytecodeGenerator::BuildYieldResumePoint(int yield_id, |
2671 Yield::OnException on_exception, | |
2672 Register generator, | |
2673 int position) { | |
2674 DCHECK_GE(yield_id, 0); | |
2675 DCHECK_LT(yield_id, generator_resume_points_.size()); | |
2676 DCHECK(generator.is_valid()); | |
2677 | |
2678 DCHECK(!generator_resume_points_[yield_id].is_bound()); | |
2679 builder()->Bind(&(generator_resume_points_[yield_id])); | |
2304 // Upon resume, we continue here. | 2680 // Upon resume, we continue here. |
2305 | 2681 |
2306 { | 2682 { |
2307 RegisterAllocationScope register_scope(this); | 2683 RegisterAllocationScope register_scope(this); |
2308 | 2684 |
2309 // Update state to indicate that we have finished resuming. Loop headers | 2685 // Update state to indicate that we have finished resuming. Loop headers |
2310 // rely on this. | 2686 // rely on this. |
2311 builder() | 2687 builder() |
2312 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | 2688 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) |
2313 .StoreAccumulatorInRegister(generator_state_); | 2689 .StoreAccumulatorInRegister(generator_state_); |
2314 | 2690 |
2315 Register input = register_allocator()->NewRegister(); | 2691 Register input = register_allocator()->NewRegister(); |
2316 builder() | 2692 builder() |
2317 ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator) | 2693 ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator) |
2318 .StoreAccumulatorInRegister(input); | 2694 .StoreAccumulatorInRegister(input); |
2319 | 2695 |
2320 Register resume_mode = register_allocator()->NewRegister(); | 2696 Register resume_mode = register_allocator()->NewRegister(); |
2321 builder() | 2697 builder() |
2322 ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator) | 2698 ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator) |
2323 .StoreAccumulatorInRegister(resume_mode); | 2699 .StoreAccumulatorInRegister(resume_mode); |
2324 | 2700 |
2325 // Now dispatch on resume mode. | 2701 // Now dispatch on resume mode. |
2326 | 2702 |
2327 BytecodeLabel resume_with_next; | 2703 BytecodeLabel resume_with_next; |
2328 BytecodeLabel resume_with_return; | 2704 BytecodeLabel resume_with_return; |
2329 BytecodeLabel resume_with_throw; | 2705 BytecodeLabel resume_with_throw; |
2330 | 2706 |
2707 // TODO(caitp): Don't generate `resume_with_return` block for non-generators | |
2331 builder() | 2708 builder() |
2332 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) | 2709 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) |
2333 .CompareOperation(Token::EQ_STRICT, resume_mode) | 2710 .CompareOperation(Token::EQ_STRICT, resume_mode) |
2334 .JumpIfTrue(&resume_with_next) | 2711 .JumpIfTrue(&resume_with_next) |
2335 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow)) | 2712 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow)) |
2336 .CompareOperation(Token::EQ_STRICT, resume_mode) | 2713 .CompareOperation(Token::EQ_STRICT, resume_mode) |
2337 .JumpIfTrue(&resume_with_throw) | 2714 .JumpIfTrue(&resume_with_throw) |
2338 .Jump(&resume_with_return); | 2715 .Jump(&resume_with_return); |
2339 | 2716 |
2340 builder()->Bind(&resume_with_return); | 2717 builder()->Bind(&resume_with_return); |
2341 { | 2718 { |
2342 RegisterList args = register_allocator()->NewRegisterList(2); | 2719 RegisterList args = register_allocator()->NewRegisterList(2); |
2343 builder() | 2720 builder() |
2344 ->MoveRegister(input, args[0]) | 2721 ->MoveRegister(input, args[0]) |
2345 .LoadTrue() | 2722 .LoadTrue() |
2346 .StoreAccumulatorInRegister(args[1]) | 2723 .StoreAccumulatorInRegister(args[1]) |
2347 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); | 2724 .CallRuntime(Runtime::kInlineCreateIterResultObject, args); |
2348 execution_control()->ReturnAccumulator(); | 2725 execution_control()->ReturnAccumulator(); |
2349 } | 2726 } |
2350 | 2727 |
2351 builder()->Bind(&resume_with_throw); | 2728 builder()->Bind(&resume_with_throw); |
2352 builder()->SetExpressionPosition(expr); | 2729 builder()->SetExpressionPosition(position); |
2353 builder()->LoadAccumulatorWithRegister(input); | 2730 builder()->LoadAccumulatorWithRegister(input); |
2354 if (expr->rethrow_on_exception()) { | 2731 if (on_exception == Yield::kOnExceptionRethrow) { |
2355 builder()->ReThrow(); | 2732 builder()->ReThrow(); |
2356 } else { | 2733 } else { |
2357 builder()->Throw(); | 2734 builder()->Throw(); |
2358 } | 2735 } |
2359 | 2736 |
2360 builder()->Bind(&resume_with_next); | 2737 builder()->Bind(&resume_with_next); |
2361 builder()->LoadAccumulatorWithRegister(input); | 2738 builder()->LoadAccumulatorWithRegister(input); |
2362 } | 2739 } |
2363 } | 2740 } |
2364 | 2741 |
2742 void BytecodeGenerator::VisitYield(Yield* expr) { | |
2743 Register generator = VisitForRegisterValue(expr->generator_object()); | |
2744 | |
2745 builder()->SetExpressionPosition(expr); | |
2746 Register value = VisitForRegisterValue(expr->expression()); | |
2747 | |
2748 BuildYield(expr->yield_id(), generator, value); | |
2749 BuildYieldResumePoint(expr->yield_id(), expr->on_exception(), generator, | |
2750 expr->position()); | |
2751 } | |
2752 | |
2365 void BytecodeGenerator::VisitThrow(Throw* expr) { | 2753 void BytecodeGenerator::VisitThrow(Throw* expr) { |
2366 VisitForAccumulatorValue(expr->exception()); | 2754 VisitForAccumulatorValue(expr->exception()); |
2367 builder()->SetExpressionPosition(expr); | 2755 builder()->SetExpressionPosition(expr); |
2368 builder()->Throw(); | 2756 builder()->Throw(); |
2369 } | 2757 } |
2370 | 2758 |
2371 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { | 2759 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { |
2372 LhsKind property_kind = Property::GetAssignType(expr); | 2760 LhsKind property_kind = Property::GetAssignType(expr); |
2373 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); | 2761 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); |
2374 builder()->SetExpressionPosition(expr); | 2762 builder()->SetExpressionPosition(expr); |
(...skipping 1002 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3377 } | 3765 } |
3378 | 3766 |
3379 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { | 3767 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { |
3380 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict | 3768 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict |
3381 : Runtime::kStoreKeyedToSuper_Sloppy; | 3769 : Runtime::kStoreKeyedToSuper_Sloppy; |
3382 } | 3770 } |
3383 | 3771 |
3384 } // namespace interpreter | 3772 } // namespace interpreter |
3385 } // namespace internal | 3773 } // namespace internal |
3386 } // namespace v8 | 3774 } // namespace v8 |
OLD | NEW |