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 __ LoadRoot(ip, Heap::kStackLimitRootIndex); | 281 __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
282 __ cmp(sp, Operand(ip)); | 282 __ cmp(sp, Operand(ip)); |
283 __ b(hs, &ok); | 283 __ b(hs, &ok); |
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
773 PrepareForBailout(expr, TOS_REG); | 773 PrepareForBailout(expr, TOS_REG); |
774 if (should_normalize) { | 774 if (should_normalize) { |
775 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 775 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
776 __ cmp(r0, ip); | 776 __ cmp(r0, ip); |
777 Split(eq, if_true, if_false, NULL); | 777 Split(eq, if_true, if_false, NULL); |
778 __ bind(&skip); | 778 __ bind(&skip); |
779 } | 779 } |
780 } | 780 } |
781 | 781 |
782 | 782 |
783 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 783 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { |
784 VariableMode mode, | 784 // The variable in the declaration always resides in the current function |
785 FunctionLiteral* function) { | 785 // context. |
| 786 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 787 if (FLAG_debug_code) { |
| 788 // Check that we're not inside a with or catch context. |
| 789 __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); |
| 790 __ CompareRoot(r1, Heap::kWithContextMapRootIndex); |
| 791 __ Check(ne, "Declaration in with context."); |
| 792 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); |
| 793 __ Check(ne, "Declaration in catch context."); |
| 794 } |
| 795 } |
| 796 |
| 797 |
| 798 void FullCodeGenerator::VisitVariableDeclaration( |
| 799 VariableDeclaration* declaration) { |
786 // If it was not possible to allocate the variable at compile time, we | 800 // If it was not possible to allocate the variable at compile time, we |
787 // need to "declare" it at runtime to make sure it actually exists in the | 801 // need to "declare" it at runtime to make sure it actually exists in the |
788 // local context. | 802 // local context. |
| 803 VariableProxy* proxy = declaration->proxy(); |
| 804 VariableMode mode = declaration->mode(); |
789 Variable* variable = proxy->var(); | 805 Variable* variable = proxy->var(); |
790 bool binding_needs_init = (function == NULL) && | 806 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; |
791 (mode == CONST || mode == CONST_HARMONY || mode == LET); | |
792 switch (variable->location()) { | 807 switch (variable->location()) { |
793 case Variable::UNALLOCATED: | 808 case Variable::UNALLOCATED: |
794 ++global_count_; | 809 globals_->Add(variable->name()); |
| 810 globals_->Add(variable->binding_needs_init() |
| 811 ? isolate()->factory()->the_hole_value() |
| 812 : isolate()->factory()->undefined_value()); |
795 break; | 813 break; |
796 | 814 |
797 case Variable::PARAMETER: | 815 case Variable::PARAMETER: |
798 case Variable::LOCAL: | 816 case Variable::LOCAL: |
799 if (function != NULL) { | 817 if (hole_init) { |
800 Comment cmnt(masm_, "[ Declaration"); | 818 Comment cmnt(masm_, "[ VariableDeclaration"); |
801 VisitForAccumulatorValue(function); | |
802 __ str(result_register(), StackOperand(variable)); | |
803 } else if (binding_needs_init) { | |
804 Comment cmnt(masm_, "[ Declaration"); | |
805 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 819 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
806 __ str(ip, StackOperand(variable)); | 820 __ str(ip, StackOperand(variable)); |
807 } | 821 } |
808 break; | 822 break; |
809 | 823 |
810 case Variable::CONTEXT: | 824 case Variable::CONTEXT: |
811 // The variable in the decl always resides in the current function | 825 if (hole_init) { |
812 // context. | 826 Comment cmnt(masm_, "[ VariableDeclaration"); |
813 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 827 EmitDebugCheckDeclarationContext(variable); |
814 if (FLAG_debug_code) { | |
815 // Check that we're not inside a with or catch context. | |
816 __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); | |
817 __ CompareRoot(r1, Heap::kWithContextMapRootIndex); | |
818 __ Check(ne, "Declaration in with context."); | |
819 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); | |
820 __ Check(ne, "Declaration in catch context."); | |
821 } | |
822 if (function != NULL) { | |
823 Comment cmnt(masm_, "[ Declaration"); | |
824 VisitForAccumulatorValue(function); | |
825 __ str(result_register(), ContextOperand(cp, variable->index())); | |
826 int offset = Context::SlotOffset(variable->index()); | |
827 // We know that we have written a function, which is not a smi. | |
828 __ RecordWriteContextSlot(cp, | |
829 offset, | |
830 result_register(), | |
831 r2, | |
832 kLRHasBeenSaved, | |
833 kDontSaveFPRegs, | |
834 EMIT_REMEMBERED_SET, | |
835 OMIT_SMI_CHECK); | |
836 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | |
837 } else if (binding_needs_init) { | |
838 Comment cmnt(masm_, "[ Declaration"); | |
839 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 828 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
840 __ str(ip, ContextOperand(cp, variable->index())); | 829 __ str(ip, ContextOperand(cp, variable->index())); |
841 // No write barrier since the_hole_value is in old space. | 830 // No write barrier since the_hole_value is in old space. |
842 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 831 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
843 } | 832 } |
844 break; | 833 break; |
845 | 834 |
846 case Variable::LOOKUP: { | 835 case Variable::LOOKUP: { |
847 Comment cmnt(masm_, "[ Declaration"); | 836 Comment cmnt(masm_, "[ VariableDeclaration"); |
848 __ mov(r2, Operand(variable->name())); | 837 __ mov(r2, Operand(variable->name())); |
849 // Declaration nodes are always introduced in one of four modes. | 838 // Declaration nodes are always introduced in one of four modes. |
850 ASSERT(mode == VAR || | 839 ASSERT(mode == VAR || mode == LET || |
851 mode == CONST || | 840 mode == CONST || mode == CONST_HARMONY); |
852 mode == CONST_HARMONY || | |
853 mode == LET); | |
854 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) | 841 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) |
855 ? READ_ONLY : NONE; | 842 ? READ_ONLY : NONE; |
856 __ mov(r1, Operand(Smi::FromInt(attr))); | 843 __ mov(r1, Operand(Smi::FromInt(attr))); |
857 // Push initial value, if any. | 844 // Push initial value, if any. |
858 // Note: For variables we must not push an initial value (such as | 845 // Note: For variables we must not push an initial value (such as |
859 // 'undefined') because we may have a (legal) redeclaration and we | 846 // 'undefined') because we may have a (legal) redeclaration and we |
860 // must not destroy the current value. | 847 // must not destroy the current value. |
861 if (function != NULL) { | 848 if (hole_init) { |
862 __ Push(cp, r2, r1); | |
863 // Push initial value for function declaration. | |
864 VisitForStackValue(function); | |
865 } else if (binding_needs_init) { | |
866 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); | 849 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); |
867 __ Push(cp, r2, r1, r0); | 850 __ Push(cp, r2, r1, r0); |
868 } else { | 851 } else { |
869 __ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value. | 852 __ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value. |
870 __ Push(cp, r2, r1, r0); | 853 __ Push(cp, r2, r1, r0); |
871 } | 854 } |
872 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 855 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
873 break; | 856 break; |
874 } | 857 } |
875 } | 858 } |
876 } | 859 } |
877 | 860 |
878 | 861 |
| 862 void FullCodeGenerator::VisitFunctionDeclaration( |
| 863 FunctionDeclaration* declaration) { |
| 864 VariableProxy* proxy = declaration->proxy(); |
| 865 Variable* variable = proxy->var(); |
| 866 switch (variable->location()) { |
| 867 case Variable::UNALLOCATED: { |
| 868 globals_->Add(variable->name()); |
| 869 Handle<SharedFunctionInfo> function = |
| 870 Compiler::BuildFunctionInfo(declaration->fun(), script()); |
| 871 // Check for stack-overflow exception. |
| 872 if (function.is_null()) return SetStackOverflow(); |
| 873 globals_->Add(function); |
| 874 break; |
| 875 } |
| 876 |
| 877 case Variable::PARAMETER: |
| 878 case Variable::LOCAL: { |
| 879 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 880 VisitForAccumulatorValue(declaration->fun()); |
| 881 __ str(result_register(), StackOperand(variable)); |
| 882 break; |
| 883 } |
| 884 |
| 885 case Variable::CONTEXT: { |
| 886 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 887 EmitDebugCheckDeclarationContext(variable); |
| 888 VisitForAccumulatorValue(declaration->fun()); |
| 889 __ str(result_register(), ContextOperand(cp, variable->index())); |
| 890 int offset = Context::SlotOffset(variable->index()); |
| 891 // We know that we have written a function, which is not a smi. |
| 892 __ RecordWriteContextSlot(cp, |
| 893 offset, |
| 894 result_register(), |
| 895 r2, |
| 896 kLRHasBeenSaved, |
| 897 kDontSaveFPRegs, |
| 898 EMIT_REMEMBERED_SET, |
| 899 OMIT_SMI_CHECK); |
| 900 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
| 901 break; |
| 902 } |
| 903 |
| 904 case Variable::LOOKUP: { |
| 905 Comment cmnt(masm_, "[ FunctionDeclaration"); |
| 906 __ mov(r2, Operand(variable->name())); |
| 907 __ mov(r1, Operand(Smi::FromInt(NONE))); |
| 908 __ Push(cp, r2, r1); |
| 909 // Push initial value for function declaration. |
| 910 VisitForStackValue(declaration->fun()); |
| 911 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 912 break; |
| 913 } |
| 914 } |
| 915 } |
| 916 |
| 917 |
| 918 void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { |
| 919 VariableProxy* proxy = declaration->proxy(); |
| 920 Variable* variable = proxy->var(); |
| 921 Handle<JSModule> instance = declaration->module()->interface()->Instance(); |
| 922 ASSERT(!instance.is_null()); |
| 923 |
| 924 switch (variable->location()) { |
| 925 case Variable::UNALLOCATED: { |
| 926 Comment cmnt(masm_, "[ ModuleDeclaration"); |
| 927 globals_->Add(variable->name()); |
| 928 globals_->Add(instance); |
| 929 Visit(declaration->module()); |
| 930 break; |
| 931 } |
| 932 |
| 933 case Variable::CONTEXT: { |
| 934 Comment cmnt(masm_, "[ ModuleDeclaration"); |
| 935 EmitDebugCheckDeclarationContext(variable); |
| 936 __ mov(r1, Operand(instance)); |
| 937 __ str(r1, ContextOperand(cp, variable->index())); |
| 938 Visit(declaration->module()); |
| 939 break; |
| 940 } |
| 941 |
| 942 case Variable::PARAMETER: |
| 943 case Variable::LOCAL: |
| 944 case Variable::LOOKUP: |
| 945 UNREACHABLE(); |
| 946 } |
| 947 } |
| 948 |
| 949 |
| 950 void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) { |
| 951 VariableProxy* proxy = declaration->proxy(); |
| 952 Variable* variable = proxy->var(); |
| 953 switch (variable->location()) { |
| 954 case Variable::UNALLOCATED: |
| 955 // TODO(rossberg) |
| 956 break; |
| 957 |
| 958 case Variable::CONTEXT: { |
| 959 Comment cmnt(masm_, "[ ImportDeclaration"); |
| 960 EmitDebugCheckDeclarationContext(variable); |
| 961 // TODO(rossberg) |
| 962 break; |
| 963 } |
| 964 |
| 965 case Variable::PARAMETER: |
| 966 case Variable::LOCAL: |
| 967 case Variable::LOOKUP: |
| 968 UNREACHABLE(); |
| 969 } |
| 970 } |
| 971 |
| 972 |
| 973 void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { |
| 974 // TODO(rossberg) |
| 975 } |
| 976 |
| 977 |
879 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 978 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
880 // Call the runtime to declare the globals. | 979 // Call the runtime to declare the globals. |
881 // The context is the first argument. | 980 // The context is the first argument. |
882 __ mov(r1, Operand(pairs)); | 981 __ mov(r1, Operand(pairs)); |
883 __ mov(r0, Operand(Smi::FromInt(DeclareGlobalsFlags()))); | 982 __ mov(r0, Operand(Smi::FromInt(DeclareGlobalsFlags()))); |
884 __ Push(cp, r1, r0); | 983 __ Push(cp, r1, r0); |
885 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 984 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
886 // Return value is ignored. | 985 // Return value is ignored. |
887 } | 986 } |
888 | 987 |
(...skipping 3550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4439 } | 4538 } |
4440 | 4539 |
4441 | 4540 |
4442 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 4541 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
4443 __ ldr(dst, ContextOperand(cp, context_index)); | 4542 __ ldr(dst, ContextOperand(cp, context_index)); |
4444 } | 4543 } |
4445 | 4544 |
4446 | 4545 |
4447 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { | 4546 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { |
4448 Scope* declaration_scope = scope()->DeclarationScope(); | 4547 Scope* declaration_scope = scope()->DeclarationScope(); |
4449 if (declaration_scope->is_global_scope()) { | 4548 if (declaration_scope->is_global_scope() || |
| 4549 declaration_scope->is_module_scope()) { |
4450 // Contexts nested in the global context have a canonical empty function | 4550 // Contexts nested in the global context have a canonical empty function |
4451 // as their closure, not the anonymous closure containing the global | 4551 // as their closure, not the anonymous closure containing the global |
4452 // code. Pass a smi sentinel and let the runtime look up the empty | 4552 // code. Pass a smi sentinel and let the runtime look up the empty |
4453 // function. | 4553 // function. |
4454 __ mov(ip, Operand(Smi::FromInt(0))); | 4554 __ mov(ip, Operand(Smi::FromInt(0))); |
4455 } else if (declaration_scope->is_eval_scope()) { | 4555 } else if (declaration_scope->is_eval_scope()) { |
4456 // Contexts created by a call to eval have the same closure as the | 4556 // Contexts created by a call to eval have the same closure as the |
4457 // context calling eval, not the anonymous closure containing the eval | 4557 // context calling eval, not the anonymous closure containing the eval |
4458 // code. Fetch it from the context. | 4558 // code. Fetch it from the context. |
4459 __ ldr(ip, ContextOperand(cp, Context::CLOSURE_INDEX)); | 4559 __ ldr(ip, ContextOperand(cp, Context::CLOSURE_INDEX)); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4519 *context_length = 0; | 4619 *context_length = 0; |
4520 return previous_; | 4620 return previous_; |
4521 } | 4621 } |
4522 | 4622 |
4523 | 4623 |
4524 #undef __ | 4624 #undef __ |
4525 | 4625 |
4526 } } // namespace v8::internal | 4626 } } // namespace v8::internal |
4527 | 4627 |
4528 #endif // V8_TARGET_ARCH_ARM | 4628 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |