OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 if (scope()->HasIllegalRedeclaration()) { | 275 if (scope()->HasIllegalRedeclaration()) { |
276 Comment cmnt(masm_, "[ Declarations"); | 276 Comment cmnt(masm_, "[ Declarations"); |
277 scope()->VisitIllegalRedeclaration(this); | 277 scope()->VisitIllegalRedeclaration(this); |
278 | 278 |
279 } else { | 279 } else { |
280 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 280 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
281 { Comment cmnt(masm_, "[ Declarations"); | 281 { Comment cmnt(masm_, "[ Declarations"); |
282 // For named function expressions, declare the function name as a | 282 // For named function expressions, declare the function name as a |
283 // constant. | 283 // constant. |
284 if (scope()->is_function_scope() && scope()->function() != NULL) { | 284 if (scope()->is_function_scope() && scope()->function() != NULL) { |
285 VariableProxy* proxy = scope()->function(); | 285 VariableDeclaration* function = scope()->function(); |
286 ASSERT(proxy->var()->mode() == CONST || | 286 ASSERT(function->proxy()->var()->mode() == CONST || |
287 proxy->var()->mode() == CONST_HARMONY); | 287 function->proxy()->var()->mode() == CONST_HARMONY); |
288 ASSERT(proxy->var()->location() != Variable::UNALLOCATED); | 288 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); |
289 EmitDeclaration(proxy, proxy->var()->mode(), NULL); | 289 VisitVariableDeclaration(function); |
290 } | 290 } |
291 VisitDeclarations(scope()->declarations()); | 291 VisitDeclarations(scope()->declarations()); |
292 } | 292 } |
293 | 293 |
294 { Comment cmnt(masm_, "[ Stack check"); | 294 { Comment cmnt(masm_, "[ Stack check"); |
295 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 295 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
296 Label ok; | 296 Label ok; |
297 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 297 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
298 __ j(above_equal, &ok, Label::kNear); | 298 __ j(above_equal, &ok, Label::kNear); |
299 StackCheckStub stub; | 299 StackCheckStub stub; |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
696 if (should_normalize) __ jmp(&skip, Label::kNear); | 696 if (should_normalize) __ jmp(&skip, Label::kNear); |
697 PrepareForBailout(expr, TOS_REG); | 697 PrepareForBailout(expr, TOS_REG); |
698 if (should_normalize) { | 698 if (should_normalize) { |
699 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 699 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
700 Split(equal, if_true, if_false, NULL); | 700 Split(equal, if_true, if_false, NULL); |
701 __ bind(&skip); | 701 __ bind(&skip); |
702 } | 702 } |
703 } | 703 } |
704 | 704 |
705 | 705 |
706 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 706 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { |
707 VariableMode mode, | 707 // The variable in the declaration always resides in the current function |
708 FunctionLiteral* function) { | 708 // context. |
| 709 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 710 if (FLAG_debug_code) { |
| 711 // Check that we're not inside a with or catch context. |
| 712 __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset)); |
| 713 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); |
| 714 __ Check(not_equal, "Declaration in with context."); |
| 715 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); |
| 716 __ Check(not_equal, "Declaration in catch context."); |
| 717 } |
| 718 } |
| 719 |
| 720 |
| 721 void FullCodeGenerator::VisitVariableDeclaration( |
| 722 VariableDeclaration* declaration) { |
709 // If it was not possible to allocate the variable at compile time, we | 723 // If it was not possible to allocate the variable at compile time, we |
710 // need to "declare" it at runtime to make sure it actually exists in the | 724 // need to "declare" it at runtime to make sure it actually exists in the |
711 // local context. | 725 // local context. |
| 726 VariableProxy* proxy = declaration->proxy(); |
| 727 VariableMode mode = declaration->mode(); |
712 Variable* variable = proxy->var(); | 728 Variable* variable = proxy->var(); |
713 bool binding_needs_init = (function == NULL) && | 729 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; |
714 (mode == CONST || mode == CONST_HARMONY || mode == LET); | |
715 switch (variable->location()) { | 730 switch (variable->location()) { |
716 case Variable::UNALLOCATED: | 731 case Variable::UNALLOCATED: |
717 ++global_count_; | 732 ++global_count_; |
718 break; | 733 break; |
719 | 734 |
720 case Variable::PARAMETER: | 735 case Variable::PARAMETER: |
721 case Variable::LOCAL: | 736 case Variable::LOCAL: |
722 if (function != NULL) { | 737 if (hole_init) { |
723 Comment cmnt(masm_, "[ Declaration"); | 738 Comment cmnt(masm_, "[ VariableDeclaration"); |
724 VisitForAccumulatorValue(function); | |
725 __ movq(StackOperand(variable), result_register()); | |
726 } else if (binding_needs_init) { | |
727 Comment cmnt(masm_, "[ Declaration"); | |
728 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 739 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
729 __ movq(StackOperand(variable), kScratchRegister); | 740 __ movq(StackOperand(variable), kScratchRegister); |
730 } | 741 } |
731 break; | 742 break; |
732 | 743 |
733 case Variable::CONTEXT: | 744 case Variable::CONTEXT: |
734 // The variable in the decl always resides in the current function | 745 if (hole_init) { |
735 // context. | 746 Comment cmnt(masm_, "[ VariableDeclaration"); |
736 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 747 EmitDebugCheckDeclarationContext(variable); |
737 if (FLAG_debug_code) { | |
738 // Check that we're not inside a with or catch context. | |
739 __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset)); | |
740 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); | |
741 __ Check(not_equal, "Declaration in with context."); | |
742 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); | |
743 __ Check(not_equal, "Declaration in catch context."); | |
744 } | |
745 if (function != NULL) { | |
746 Comment cmnt(masm_, "[ Declaration"); | |
747 VisitForAccumulatorValue(function); | |
748 __ movq(ContextOperand(rsi, variable->index()), result_register()); | |
749 int offset = Context::SlotOffset(variable->index()); | |
750 // We know that we have written a function, which is not a smi. | |
751 __ RecordWriteContextSlot(rsi, | |
752 offset, | |
753 result_register(), | |
754 rcx, | |
755 kDontSaveFPRegs, | |
756 EMIT_REMEMBERED_SET, | |
757 OMIT_SMI_CHECK); | |
758 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | |
759 } else if (binding_needs_init) { | |
760 Comment cmnt(masm_, "[ Declaration"); | |
761 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 748 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
762 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); | 749 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); |
763 // No write barrier since the hole value is in old space. | 750 // No write barrier since the hole value is in old space. |
764 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 751 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
765 } | 752 } |
766 break; | 753 break; |
767 | 754 |
768 case Variable::LOOKUP: { | 755 case Variable::LOOKUP: { |
769 Comment cmnt(masm_, "[ Declaration"); | 756 Comment cmnt(masm_, "[ VariableDeclaration"); |
770 __ push(rsi); | 757 __ push(rsi); |
771 __ Push(variable->name()); | 758 __ Push(variable->name()); |
772 // Declaration nodes are always introduced in one of four modes. | 759 // Declaration nodes are always introduced in one of four modes. |
773 ASSERT(mode == VAR || | 760 ASSERT(mode == VAR || mode == LET || |
774 mode == CONST || | 761 mode == CONST || mode == CONST_HARMONY); |
775 mode == CONST_HARMONY || | |
776 mode == LET); | |
777 PropertyAttributes attr = | 762 PropertyAttributes attr = |
778 (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE; | 763 (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE; |
779 __ Push(Smi::FromInt(attr)); | 764 __ Push(Smi::FromInt(attr)); |
780 // Push initial value, if any. | 765 // Push initial value, if any. |
781 // Note: For variables we must not push an initial value (such as | 766 // Note: For variables we must not push an initial value (such as |
782 // 'undefined') because we may have a (legal) redeclaration and we | 767 // 'undefined') because we may have a (legal) redeclaration and we |
783 // must not destroy the current value. | 768 // must not destroy the current value. |
784 if (function != NULL) { | 769 if (hole_init) { |
785 VisitForStackValue(function); | |
786 } else if (binding_needs_init) { | |
787 __ PushRoot(Heap::kTheHoleValueRootIndex); | 770 __ PushRoot(Heap::kTheHoleValueRootIndex); |
788 } else { | 771 } else { |
789 __ Push(Smi::FromInt(0)); // Indicates no initial value. | 772 __ Push(Smi::FromInt(0)); // Indicates no initial value. |
790 } | 773 } |
791 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 774 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
792 break; | 775 break; |
793 } | 776 } |
794 } | 777 } |
795 } | 778 } |
796 | 779 |
797 | 780 |
| 781 void FullCodeGenerator::VisitFunctionDeclaration( |
| 782 FunctionDeclaration* declaration) { |
| 783 VariableProxy* proxy = declaration->proxy(); |
| 784 Variable* variable = proxy->var(); |
| 785 switch (variable->location()) { |
| 786 case Variable::UNALLOCATED: |
| 787 ++global_count_; |
| 788 break; |
| 789 |
| 790 case Variable::PARAMETER: |
| 791 case Variable::LOCAL: { |
| 792 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 793 VisitForAccumulatorValue(declaration->fun()); |
| 794 __ movq(StackOperand(variable), result_register()); |
| 795 break; |
| 796 } |
| 797 |
| 798 case Variable::CONTEXT: { |
| 799 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 800 EmitDebugCheckDeclarationContext(variable); |
| 801 VisitForAccumulatorValue(declaration->fun()); |
| 802 __ movq(ContextOperand(rsi, variable->index()), result_register()); |
| 803 int offset = Context::SlotOffset(variable->index()); |
| 804 // We know that we have written a function, which is not a smi. |
| 805 __ RecordWriteContextSlot(rsi, |
| 806 offset, |
| 807 result_register(), |
| 808 rcx, |
| 809 kDontSaveFPRegs, |
| 810 EMIT_REMEMBERED_SET, |
| 811 OMIT_SMI_CHECK); |
| 812 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
| 813 break; |
| 814 } |
| 815 |
| 816 case Variable::LOOKUP: { |
| 817 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 818 __ push(rsi); |
| 819 __ Push(variable->name()); |
| 820 __ Push(Smi::FromInt(NONE)); |
| 821 VisitForStackValue(declaration->fun()); |
| 822 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 823 break; |
| 824 } |
| 825 } |
| 826 } |
| 827 |
| 828 |
| 829 void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { |
| 830 VariableProxy* proxy = declaration->proxy(); |
| 831 Variable* variable = proxy->var(); |
| 832 switch (variable->location()) { |
| 833 case Variable::UNALLOCATED: |
| 834 ++global_count_; |
| 835 break; |
| 836 |
| 837 case Variable::CONTEXT: { |
| 838 Comment cmnt(masm_, "[ ModuleDeclaration"); |
| 839 EmitDebugCheckDeclarationContext(variable); |
| 840 // TODO(rossberg): initialize module instance object |
| 841 break; |
| 842 } |
| 843 |
| 844 case Variable::PARAMETER: |
| 845 case Variable::LOCAL: |
| 846 case Variable::LOOKUP: |
| 847 UNREACHABLE(); |
| 848 } |
| 849 } |
| 850 |
| 851 |
| 852 void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) { |
| 853 VariableProxy* proxy = declaration->proxy(); |
| 854 Variable* variable = proxy->var(); |
| 855 switch (variable->location()) { |
| 856 case Variable::UNALLOCATED: |
| 857 ++global_count_; |
| 858 break; |
| 859 |
| 860 case Variable::CONTEXT: { |
| 861 Comment cmnt(masm_, "[ ImportDeclaration"); |
| 862 EmitDebugCheckDeclarationContext(variable); |
| 863 // TODO(rossberg) |
| 864 break; |
| 865 } |
| 866 |
| 867 case Variable::PARAMETER: |
| 868 case Variable::LOCAL: |
| 869 case Variable::LOOKUP: |
| 870 UNREACHABLE(); |
| 871 } |
| 872 } |
| 873 |
| 874 |
| 875 void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { |
| 876 // TODO(rossberg) |
| 877 } |
| 878 |
| 879 |
798 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 880 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
799 // Call the runtime to declare the globals. | 881 // Call the runtime to declare the globals. |
800 __ push(rsi); // The context is the first argument. | 882 __ push(rsi); // The context is the first argument. |
801 __ Push(pairs); | 883 __ Push(pairs); |
802 __ Push(Smi::FromInt(DeclareGlobalsFlags())); | 884 __ Push(Smi::FromInt(DeclareGlobalsFlags())); |
803 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 885 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
804 // Return value is ignored. | 886 // Return value is ignored. |
805 } | 887 } |
806 | 888 |
807 | 889 |
(...skipping 3606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4414 *context_length = 0; | 4496 *context_length = 0; |
4415 return previous_; | 4497 return previous_; |
4416 } | 4498 } |
4417 | 4499 |
4418 | 4500 |
4419 #undef __ | 4501 #undef __ |
4420 | 4502 |
4421 } } // namespace v8::internal | 4503 } } // namespace v8::internal |
4422 | 4504 |
4423 #endif // V8_TARGET_ARCH_X64 | 4505 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |