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 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 if (scope()->HasIllegalRedeclaration()) { | 259 if (scope()->HasIllegalRedeclaration()) { |
260 Comment cmnt(masm_, "[ Declarations"); | 260 Comment cmnt(masm_, "[ Declarations"); |
261 scope()->VisitIllegalRedeclaration(this); | 261 scope()->VisitIllegalRedeclaration(this); |
262 | 262 |
263 } else { | 263 } else { |
264 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 264 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
265 { Comment cmnt(masm_, "[ Declarations"); | 265 { Comment cmnt(masm_, "[ Declarations"); |
266 // For named function expressions, declare the function name as a | 266 // For named function expressions, declare the function name as a |
267 // constant. | 267 // constant. |
268 if (scope()->is_function_scope() && scope()->function() != NULL) { | 268 if (scope()->is_function_scope() && scope()->function() != NULL) { |
269 VariableProxy* proxy = scope()->function(); | 269 VariableDeclaration* function = scope()->function(); |
270 ASSERT(proxy->var()->mode() == CONST || | 270 ASSERT(function->proxy()->var()->mode() == CONST || |
271 proxy->var()->mode() == CONST_HARMONY); | 271 function->proxy()->var()->mode() == CONST_HARMONY); |
272 ASSERT(proxy->var()->location() != Variable::UNALLOCATED); | 272 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); |
273 EmitDeclaration(proxy, proxy->var()->mode(), NULL); | 273 VisitVariableDeclaration(function); |
274 } | 274 } |
275 VisitDeclarations(scope()->declarations()); | 275 VisitDeclarations(scope()->declarations()); |
276 } | 276 } |
277 | 277 |
278 { Comment cmnt(masm_, "[ Stack check"); | 278 { Comment cmnt(masm_, "[ Stack check"); |
279 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 279 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
280 Label ok; | 280 Label ok; |
281 ExternalReference stack_limit = | 281 ExternalReference stack_limit = |
282 ExternalReference::address_of_stack_limit(isolate()); | 282 ExternalReference::address_of_stack_limit(isolate()); |
283 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 283 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
743 if (should_normalize) __ jmp(&skip, Label::kNear); | 743 if (should_normalize) __ jmp(&skip, Label::kNear); |
744 PrepareForBailout(expr, TOS_REG); | 744 PrepareForBailout(expr, TOS_REG); |
745 if (should_normalize) { | 745 if (should_normalize) { |
746 __ cmp(eax, isolate()->factory()->true_value()); | 746 __ cmp(eax, isolate()->factory()->true_value()); |
747 Split(equal, if_true, if_false, NULL); | 747 Split(equal, if_true, if_false, NULL); |
748 __ bind(&skip); | 748 __ bind(&skip); |
749 } | 749 } |
750 } | 750 } |
751 | 751 |
752 | 752 |
753 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 753 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { |
754 VariableMode mode, | 754 // The variable in the declaration always resides in the current function |
755 FunctionLiteral* function) { | 755 // context. |
| 756 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 757 if (FLAG_debug_code) { |
| 758 // Check that we're not inside a with or catch context. |
| 759 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); |
| 760 __ cmp(ebx, isolate()->factory()->with_context_map()); |
| 761 __ Check(not_equal, "Declaration in with context."); |
| 762 __ cmp(ebx, isolate()->factory()->catch_context_map()); |
| 763 __ Check(not_equal, "Declaration in catch context."); |
| 764 } |
| 765 } |
| 766 |
| 767 |
| 768 void FullCodeGenerator::VisitVariableDeclaration( |
| 769 VariableDeclaration* declaration) { |
756 // If it was not possible to allocate the variable at compile time, we | 770 // If it was not possible to allocate the variable at compile time, we |
757 // need to "declare" it at runtime to make sure it actually exists in the | 771 // need to "declare" it at runtime to make sure it actually exists in the |
758 // local context. | 772 // local context. |
| 773 VariableProxy* proxy = declaration->proxy(); |
| 774 VariableMode mode = declaration->mode(); |
759 Variable* variable = proxy->var(); | 775 Variable* variable = proxy->var(); |
760 bool binding_needs_init = (function == NULL) && | 776 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; |
761 (mode == CONST || mode == CONST_HARMONY || mode == LET); | |
762 switch (variable->location()) { | 777 switch (variable->location()) { |
763 case Variable::UNALLOCATED: | 778 case Variable::UNALLOCATED: |
764 ++global_count_; | 779 ++global_count_; |
765 break; | 780 break; |
766 | 781 |
767 case Variable::PARAMETER: | 782 case Variable::PARAMETER: |
768 case Variable::LOCAL: | 783 case Variable::LOCAL: |
769 if (function != NULL) { | 784 if (hole_init) { |
770 Comment cmnt(masm_, "[ Declaration"); | 785 Comment cmnt(masm_, "[ VariableDeclaration"); |
771 VisitForAccumulatorValue(function); | |
772 __ mov(StackOperand(variable), result_register()); | |
773 } else if (binding_needs_init) { | |
774 Comment cmnt(masm_, "[ Declaration"); | |
775 __ mov(StackOperand(variable), | 786 __ mov(StackOperand(variable), |
776 Immediate(isolate()->factory()->the_hole_value())); | 787 Immediate(isolate()->factory()->the_hole_value())); |
777 } | 788 } |
778 break; | 789 break; |
779 | 790 |
780 case Variable::CONTEXT: | 791 case Variable::CONTEXT: |
781 // The variable in the decl always resides in the current function | 792 if (hole_init) { |
782 // context. | 793 Comment cmnt(masm_, "[ VariableDeclaration"); |
783 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 794 EmitDebugCheckDeclarationContext(variable); |
784 if (FLAG_debug_code) { | |
785 // Check that we're not inside a with or catch context. | |
786 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); | |
787 __ cmp(ebx, isolate()->factory()->with_context_map()); | |
788 __ Check(not_equal, "Declaration in with context."); | |
789 __ cmp(ebx, isolate()->factory()->catch_context_map()); | |
790 __ Check(not_equal, "Declaration in catch context."); | |
791 } | |
792 if (function != NULL) { | |
793 Comment cmnt(masm_, "[ Declaration"); | |
794 VisitForAccumulatorValue(function); | |
795 __ mov(ContextOperand(esi, variable->index()), result_register()); | |
796 // We know that we have written a function, which is not a smi. | |
797 __ RecordWriteContextSlot(esi, | |
798 Context::SlotOffset(variable->index()), | |
799 result_register(), | |
800 ecx, | |
801 kDontSaveFPRegs, | |
802 EMIT_REMEMBERED_SET, | |
803 OMIT_SMI_CHECK); | |
804 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | |
805 } else if (binding_needs_init) { | |
806 Comment cmnt(masm_, "[ Declaration"); | |
807 __ mov(ContextOperand(esi, variable->index()), | 795 __ mov(ContextOperand(esi, variable->index()), |
808 Immediate(isolate()->factory()->the_hole_value())); | 796 Immediate(isolate()->factory()->the_hole_value())); |
809 // No write barrier since the hole value is in old space. | 797 // No write barrier since the hole value is in old space. |
810 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 798 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
811 } | 799 } |
812 break; | 800 break; |
813 | 801 |
814 case Variable::LOOKUP: { | 802 case Variable::LOOKUP: { |
815 Comment cmnt(masm_, "[ Declaration"); | 803 Comment cmnt(masm_, "[ VariableDeclaration"); |
816 __ push(esi); | 804 __ push(esi); |
817 __ push(Immediate(variable->name())); | 805 __ push(Immediate(variable->name())); |
818 // Declaration nodes are always introduced in one of four modes. | 806 // VariableDeclaration nodes are always introduced in one of four modes. |
819 ASSERT(mode == VAR || | 807 ASSERT(mode == VAR || mode == LET || |
820 mode == CONST || | 808 mode == CONST || mode == CONST_HARMONY); |
821 mode == CONST_HARMONY || | |
822 mode == LET); | |
823 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) | 809 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) |
824 ? READ_ONLY : NONE; | 810 ? READ_ONLY : NONE; |
825 __ push(Immediate(Smi::FromInt(attr))); | 811 __ push(Immediate(Smi::FromInt(attr))); |
826 // Push initial value, if any. | 812 // Push initial value, if any. |
827 // Note: For variables we must not push an initial value (such as | 813 // Note: For variables we must not push an initial value (such as |
828 // 'undefined') because we may have a (legal) redeclaration and we | 814 // 'undefined') because we may have a (legal) redeclaration and we |
829 // must not destroy the current value. | 815 // must not destroy the current value. |
830 if (function != NULL) { | 816 if (hole_init) { |
831 VisitForStackValue(function); | |
832 } else if (binding_needs_init) { | |
833 __ push(Immediate(isolate()->factory()->the_hole_value())); | 817 __ push(Immediate(isolate()->factory()->the_hole_value())); |
834 } else { | 818 } else { |
835 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. | 819 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. |
836 } | 820 } |
837 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 821 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
838 break; | 822 break; |
839 } | 823 } |
840 } | 824 } |
841 } | 825 } |
842 | 826 |
843 | 827 |
| 828 void FullCodeGenerator::VisitFunctionDeclaration( |
| 829 FunctionDeclaration* 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::PARAMETER: |
| 838 case Variable::LOCAL: { |
| 839 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 840 VisitForAccumulatorValue(declaration->fun()); |
| 841 __ mov(StackOperand(variable), result_register()); |
| 842 break; |
| 843 } |
| 844 |
| 845 case Variable::CONTEXT: { |
| 846 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 847 EmitDebugCheckDeclarationContext(variable); |
| 848 VisitForAccumulatorValue(declaration->fun()); |
| 849 __ mov(ContextOperand(esi, variable->index()), result_register()); |
| 850 // We know that we have written a function, which is not a smi. |
| 851 __ RecordWriteContextSlot(esi, |
| 852 Context::SlotOffset(variable->index()), |
| 853 result_register(), |
| 854 ecx, |
| 855 kDontSaveFPRegs, |
| 856 EMIT_REMEMBERED_SET, |
| 857 OMIT_SMI_CHECK); |
| 858 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
| 859 break; |
| 860 } |
| 861 |
| 862 case Variable::LOOKUP: { |
| 863 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 864 __ push(esi); |
| 865 __ push(Immediate(variable->name())); |
| 866 __ push(Immediate(Smi::FromInt(NONE))); |
| 867 VisitForStackValue(declaration->fun()); |
| 868 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 869 break; |
| 870 } |
| 871 } |
| 872 } |
| 873 |
| 874 |
| 875 void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { |
| 876 VariableProxy* proxy = declaration->proxy(); |
| 877 Variable* variable = proxy->var(); |
| 878 switch (variable->location()) { |
| 879 case Variable::UNALLOCATED: |
| 880 ++global_count_; |
| 881 break; |
| 882 |
| 883 case Variable::CONTEXT: { |
| 884 Comment cmnt(masm_, "[ ModuleDeclaration"); |
| 885 EmitDebugCheckDeclarationContext(variable); |
| 886 // TODO(rossberg): initialize module instance object |
| 887 break; |
| 888 } |
| 889 |
| 890 case Variable::PARAMETER: |
| 891 case Variable::LOCAL: |
| 892 case Variable::LOOKUP: |
| 893 UNREACHABLE(); |
| 894 } |
| 895 } |
| 896 |
| 897 |
| 898 void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) { |
| 899 VariableProxy* proxy = declaration->proxy(); |
| 900 Variable* variable = proxy->var(); |
| 901 switch (variable->location()) { |
| 902 case Variable::UNALLOCATED: |
| 903 ++global_count_; |
| 904 break; |
| 905 |
| 906 case Variable::CONTEXT: { |
| 907 Comment cmnt(masm_, "[ ImportDeclaration"); |
| 908 EmitDebugCheckDeclarationContext(variable); |
| 909 // TODO(rossberg) |
| 910 break; |
| 911 } |
| 912 |
| 913 case Variable::PARAMETER: |
| 914 case Variable::LOCAL: |
| 915 case Variable::LOOKUP: |
| 916 UNREACHABLE(); |
| 917 } |
| 918 } |
| 919 |
| 920 |
| 921 void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { |
| 922 // TODO(rossberg) |
| 923 } |
| 924 |
| 925 |
844 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 926 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
845 // Call the runtime to declare the globals. | 927 // Call the runtime to declare the globals. |
846 __ push(esi); // The context is the first argument. | 928 __ push(esi); // The context is the first argument. |
847 __ push(Immediate(pairs)); | 929 __ push(Immediate(pairs)); |
848 __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags()))); | 930 __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags()))); |
849 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 931 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
850 // Return value is ignored. | 932 // Return value is ignored. |
851 } | 933 } |
852 | 934 |
853 | 935 |
(...skipping 3626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4480 *context_length = 0; | 4562 *context_length = 0; |
4481 return previous_; | 4563 return previous_; |
4482 } | 4564 } |
4483 | 4565 |
4484 | 4566 |
4485 #undef __ | 4567 #undef __ |
4486 | 4568 |
4487 } } // namespace v8::internal | 4569 } } // namespace v8::internal |
4488 | 4570 |
4489 #endif // V8_TARGET_ARCH_IA32 | 4571 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |