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 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 if (scope()->HasIllegalRedeclaration()) { | 250 if (scope()->HasIllegalRedeclaration()) { |
251 Comment cmnt(masm_, "[ Declarations"); | 251 Comment cmnt(masm_, "[ Declarations"); |
252 scope()->VisitIllegalRedeclaration(this); | 252 scope()->VisitIllegalRedeclaration(this); |
253 | 253 |
254 } else { | 254 } else { |
255 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 255 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
256 { Comment cmnt(masm_, "[ Declarations"); | 256 { Comment cmnt(masm_, "[ Declarations"); |
257 // For named function expressions, declare the function name as a | 257 // For named function expressions, declare the function name as a |
258 // constant. | 258 // constant. |
259 if (scope()->is_function_scope() && scope()->function() != NULL) { | 259 if (scope()->is_function_scope() && scope()->function() != NULL) { |
260 VariableProxy* proxy = scope()->function(); | 260 VariableDeclaration* function = scope()->function(); |
261 ASSERT(proxy->var()->mode() == CONST || | 261 ASSERT(function->proxy()->var()->mode() == CONST || |
262 proxy->var()->mode() == CONST_HARMONY); | 262 function->proxy()->var()->mode() == CONST_HARMONY); |
263 ASSERT(proxy->var()->location() != Variable::UNALLOCATED); | 263 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); |
264 EmitDeclaration(proxy, proxy->var()->mode(), NULL); | 264 VisitVariableDeclaration(function); |
265 } | 265 } |
266 VisitDeclarations(scope()->declarations()); | 266 VisitDeclarations(scope()->declarations()); |
267 } | 267 } |
268 | 268 |
269 { Comment cmnt(masm_, "[ Stack check"); | 269 { Comment cmnt(masm_, "[ Stack check"); |
270 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 270 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
271 Label ok; | 271 Label ok; |
272 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 272 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
273 __ j(above_equal, &ok, Label::kNear); | 273 __ j(above_equal, &ok, Label::kNear); |
274 StackCheckStub stub; | 274 StackCheckStub stub; |
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
746 if (should_normalize) __ jmp(&skip, Label::kNear); | 746 if (should_normalize) __ jmp(&skip, Label::kNear); |
747 PrepareForBailout(expr, TOS_REG); | 747 PrepareForBailout(expr, TOS_REG); |
748 if (should_normalize) { | 748 if (should_normalize) { |
749 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 749 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
750 Split(equal, if_true, if_false, NULL); | 750 Split(equal, if_true, if_false, NULL); |
751 __ bind(&skip); | 751 __ bind(&skip); |
752 } | 752 } |
753 } | 753 } |
754 | 754 |
755 | 755 |
756 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 756 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { |
757 VariableMode mode, | 757 // The variable in the declaration always resides in the current function |
758 FunctionLiteral* function) { | 758 // context. |
| 759 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 760 if (FLAG_debug_code) { |
| 761 // Check that we're not inside a with or catch context. |
| 762 __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset)); |
| 763 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); |
| 764 __ Check(not_equal, "Declaration in with context."); |
| 765 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); |
| 766 __ Check(not_equal, "Declaration in catch context."); |
| 767 } |
| 768 } |
| 769 |
| 770 |
| 771 void FullCodeGenerator::VisitVariableDeclaration( |
| 772 VariableDeclaration* declaration) { |
759 // If it was not possible to allocate the variable at compile time, we | 773 // If it was not possible to allocate the variable at compile time, we |
760 // need to "declare" it at runtime to make sure it actually exists in the | 774 // need to "declare" it at runtime to make sure it actually exists in the |
761 // local context. | 775 // local context. |
| 776 VariableProxy* proxy = declaration->proxy(); |
| 777 VariableMode mode = declaration->mode(); |
762 Variable* variable = proxy->var(); | 778 Variable* variable = proxy->var(); |
763 bool binding_needs_init = (function == NULL) && | 779 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; |
764 (mode == CONST || mode == CONST_HARMONY || mode == LET); | |
765 switch (variable->location()) { | 780 switch (variable->location()) { |
766 case Variable::UNALLOCATED: | 781 case Variable::UNALLOCATED: |
767 ++global_count_; | 782 globals_->Add(variable->name()); |
| 783 globals_->Add(variable->binding_needs_init() |
| 784 ? isolate()->factory()->the_hole_value() |
| 785 : isolate()->factory()->undefined_value()); |
768 break; | 786 break; |
769 | 787 |
770 case Variable::PARAMETER: | 788 case Variable::PARAMETER: |
771 case Variable::LOCAL: | 789 case Variable::LOCAL: |
772 if (function != NULL) { | 790 if (hole_init) { |
773 Comment cmnt(masm_, "[ Declaration"); | 791 Comment cmnt(masm_, "[ VariableDeclaration"); |
774 VisitForAccumulatorValue(function); | |
775 __ movq(StackOperand(variable), result_register()); | |
776 } else if (binding_needs_init) { | |
777 Comment cmnt(masm_, "[ Declaration"); | |
778 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 792 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
779 __ movq(StackOperand(variable), kScratchRegister); | 793 __ movq(StackOperand(variable), kScratchRegister); |
780 } | 794 } |
781 break; | 795 break; |
782 | 796 |
783 case Variable::CONTEXT: | 797 case Variable::CONTEXT: |
784 // The variable in the decl always resides in the current function | 798 if (hole_init) { |
785 // context. | 799 Comment cmnt(masm_, "[ VariableDeclaration"); |
786 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 800 EmitDebugCheckDeclarationContext(variable); |
787 if (FLAG_debug_code) { | |
788 // Check that we're not inside a with or catch context. | |
789 __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset)); | |
790 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); | |
791 __ Check(not_equal, "Declaration in with context."); | |
792 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); | |
793 __ Check(not_equal, "Declaration in catch context."); | |
794 } | |
795 if (function != NULL) { | |
796 Comment cmnt(masm_, "[ Declaration"); | |
797 VisitForAccumulatorValue(function); | |
798 __ movq(ContextOperand(rsi, variable->index()), result_register()); | |
799 int offset = Context::SlotOffset(variable->index()); | |
800 // We know that we have written a function, which is not a smi. | |
801 __ RecordWriteContextSlot(rsi, | |
802 offset, | |
803 result_register(), | |
804 rcx, | |
805 kDontSaveFPRegs, | |
806 EMIT_REMEMBERED_SET, | |
807 OMIT_SMI_CHECK); | |
808 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | |
809 } else if (binding_needs_init) { | |
810 Comment cmnt(masm_, "[ Declaration"); | |
811 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 801 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
812 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); | 802 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); |
813 // No write barrier since the hole value is in old space. | 803 // No write barrier since the hole value is in old space. |
814 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 804 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
815 } | 805 } |
816 break; | 806 break; |
817 | 807 |
818 case Variable::LOOKUP: { | 808 case Variable::LOOKUP: { |
819 Comment cmnt(masm_, "[ Declaration"); | 809 Comment cmnt(masm_, "[ VariableDeclaration"); |
820 __ push(rsi); | 810 __ push(rsi); |
821 __ Push(variable->name()); | 811 __ Push(variable->name()); |
822 // Declaration nodes are always introduced in one of four modes. | 812 // Declaration nodes are always introduced in one of four modes. |
823 ASSERT(mode == VAR || | 813 ASSERT(mode == VAR || mode == LET || |
824 mode == CONST || | 814 mode == CONST || mode == CONST_HARMONY); |
825 mode == CONST_HARMONY || | |
826 mode == LET); | |
827 PropertyAttributes attr = | 815 PropertyAttributes attr = |
828 (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE; | 816 (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE; |
829 __ Push(Smi::FromInt(attr)); | 817 __ Push(Smi::FromInt(attr)); |
830 // Push initial value, if any. | 818 // Push initial value, if any. |
831 // Note: For variables we must not push an initial value (such as | 819 // Note: For variables we must not push an initial value (such as |
832 // 'undefined') because we may have a (legal) redeclaration and we | 820 // 'undefined') because we may have a (legal) redeclaration and we |
833 // must not destroy the current value. | 821 // must not destroy the current value. |
834 if (function != NULL) { | 822 if (hole_init) { |
835 VisitForStackValue(function); | |
836 } else if (binding_needs_init) { | |
837 __ PushRoot(Heap::kTheHoleValueRootIndex); | 823 __ PushRoot(Heap::kTheHoleValueRootIndex); |
838 } else { | 824 } else { |
839 __ Push(Smi::FromInt(0)); // Indicates no initial value. | 825 __ Push(Smi::FromInt(0)); // Indicates no initial value. |
840 } | 826 } |
841 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 827 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
842 break; | 828 break; |
843 } | 829 } |
844 } | 830 } |
845 } | 831 } |
846 | 832 |
847 | 833 |
| 834 void FullCodeGenerator::VisitFunctionDeclaration( |
| 835 FunctionDeclaration* declaration) { |
| 836 VariableProxy* proxy = declaration->proxy(); |
| 837 Variable* variable = proxy->var(); |
| 838 switch (variable->location()) { |
| 839 case Variable::UNALLOCATED: { |
| 840 globals_->Add(variable->name()); |
| 841 Handle<SharedFunctionInfo> function = |
| 842 Compiler::BuildFunctionInfo(declaration->fun(), script()); |
| 843 // Check for stack-overflow exception. |
| 844 if (function.is_null()) return SetStackOverflow(); |
| 845 globals_->Add(function); |
| 846 break; |
| 847 } |
| 848 |
| 849 case Variable::PARAMETER: |
| 850 case Variable::LOCAL: { |
| 851 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 852 VisitForAccumulatorValue(declaration->fun()); |
| 853 __ movq(StackOperand(variable), result_register()); |
| 854 break; |
| 855 } |
| 856 |
| 857 case Variable::CONTEXT: { |
| 858 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 859 EmitDebugCheckDeclarationContext(variable); |
| 860 VisitForAccumulatorValue(declaration->fun()); |
| 861 __ movq(ContextOperand(rsi, variable->index()), result_register()); |
| 862 int offset = Context::SlotOffset(variable->index()); |
| 863 // We know that we have written a function, which is not a smi. |
| 864 __ RecordWriteContextSlot(rsi, |
| 865 offset, |
| 866 result_register(), |
| 867 rcx, |
| 868 kDontSaveFPRegs, |
| 869 EMIT_REMEMBERED_SET, |
| 870 OMIT_SMI_CHECK); |
| 871 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
| 872 break; |
| 873 } |
| 874 |
| 875 case Variable::LOOKUP: { |
| 876 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 877 __ push(rsi); |
| 878 __ Push(variable->name()); |
| 879 __ Push(Smi::FromInt(NONE)); |
| 880 VisitForStackValue(declaration->fun()); |
| 881 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 882 break; |
| 883 } |
| 884 } |
| 885 } |
| 886 |
| 887 |
| 888 void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { |
| 889 VariableProxy* proxy = declaration->proxy(); |
| 890 Variable* variable = proxy->var(); |
| 891 Handle<JSModule> instance = declaration->module()->interface()->Instance(); |
| 892 ASSERT(!instance.is_null()); |
| 893 |
| 894 switch (variable->location()) { |
| 895 case Variable::UNALLOCATED: { |
| 896 Comment cmnt(masm_, "[ ModuleDeclaration"); |
| 897 globals_->Add(variable->name()); |
| 898 globals_->Add(instance); |
| 899 Visit(declaration->module()); |
| 900 break; |
| 901 } |
| 902 |
| 903 case Variable::CONTEXT: { |
| 904 Comment cmnt(masm_, "[ ModuleDeclaration"); |
| 905 EmitDebugCheckDeclarationContext(variable); |
| 906 __ Move(ContextOperand(rsi, variable->index()), instance); |
| 907 Visit(declaration->module()); |
| 908 break; |
| 909 } |
| 910 |
| 911 case Variable::PARAMETER: |
| 912 case Variable::LOCAL: |
| 913 case Variable::LOOKUP: |
| 914 UNREACHABLE(); |
| 915 } |
| 916 } |
| 917 |
| 918 |
| 919 void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) { |
| 920 VariableProxy* proxy = declaration->proxy(); |
| 921 Variable* variable = proxy->var(); |
| 922 switch (variable->location()) { |
| 923 case Variable::UNALLOCATED: |
| 924 // TODO(rossberg) |
| 925 break; |
| 926 |
| 927 case Variable::CONTEXT: { |
| 928 Comment cmnt(masm_, "[ ImportDeclaration"); |
| 929 EmitDebugCheckDeclarationContext(variable); |
| 930 // TODO(rossberg) |
| 931 break; |
| 932 } |
| 933 |
| 934 case Variable::PARAMETER: |
| 935 case Variable::LOCAL: |
| 936 case Variable::LOOKUP: |
| 937 UNREACHABLE(); |
| 938 } |
| 939 } |
| 940 |
| 941 |
| 942 void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { |
| 943 // TODO(rossberg) |
| 944 } |
| 945 |
| 946 |
848 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 947 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
849 // Call the runtime to declare the globals. | 948 // Call the runtime to declare the globals. |
850 __ push(rsi); // The context is the first argument. | 949 __ push(rsi); // The context is the first argument. |
851 __ Push(pairs); | 950 __ Push(pairs); |
852 __ Push(Smi::FromInt(DeclareGlobalsFlags())); | 951 __ Push(Smi::FromInt(DeclareGlobalsFlags())); |
853 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 952 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
854 // Return value is ignored. | 953 // Return value is ignored. |
855 } | 954 } |
856 | 955 |
857 | 956 |
(...skipping 3547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4405 } | 4504 } |
4406 | 4505 |
4407 | 4506 |
4408 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 4507 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
4409 __ movq(dst, ContextOperand(rsi, context_index)); | 4508 __ movq(dst, ContextOperand(rsi, context_index)); |
4410 } | 4509 } |
4411 | 4510 |
4412 | 4511 |
4413 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { | 4512 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { |
4414 Scope* declaration_scope = scope()->DeclarationScope(); | 4513 Scope* declaration_scope = scope()->DeclarationScope(); |
4415 if (declaration_scope->is_global_scope()) { | 4514 if (declaration_scope->is_global_scope() || |
| 4515 declaration_scope->is_module_scope()) { |
4416 // Contexts nested in the global context have a canonical empty function | 4516 // Contexts nested in the global context have a canonical empty function |
4417 // as their closure, not the anonymous closure containing the global | 4517 // as their closure, not the anonymous closure containing the global |
4418 // code. Pass a smi sentinel and let the runtime look up the empty | 4518 // code. Pass a smi sentinel and let the runtime look up the empty |
4419 // function. | 4519 // function. |
4420 __ Push(Smi::FromInt(0)); | 4520 __ Push(Smi::FromInt(0)); |
4421 } else if (declaration_scope->is_eval_scope()) { | 4521 } else if (declaration_scope->is_eval_scope()) { |
4422 // Contexts created by a call to eval have the same closure as the | 4522 // Contexts created by a call to eval have the same closure as the |
4423 // context calling eval, not the anonymous closure containing the eval | 4523 // context calling eval, not the anonymous closure containing the eval |
4424 // code. Fetch it from the context. | 4524 // code. Fetch it from the context. |
4425 __ push(ContextOperand(rsi, Context::CLOSURE_INDEX)); | 4525 __ push(ContextOperand(rsi, Context::CLOSURE_INDEX)); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4487 *context_length = 0; | 4587 *context_length = 0; |
4488 return previous_; | 4588 return previous_; |
4489 } | 4589 } |
4490 | 4590 |
4491 | 4591 |
4492 #undef __ | 4592 #undef __ |
4493 | 4593 |
4494 } } // namespace v8::internal | 4594 } } // namespace v8::internal |
4495 | 4595 |
4496 #endif // V8_TARGET_ARCH_X64 | 4596 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |