| 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 |