OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 Comment cmnt(masm_, "[ Declarations"); | 247 Comment cmnt(masm_, "[ Declarations"); |
248 scope()->VisitIllegalRedeclaration(this); | 248 scope()->VisitIllegalRedeclaration(this); |
249 | 249 |
250 } else { | 250 } else { |
251 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 251 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
252 { Comment cmnt(masm_, "[ Declarations"); | 252 { Comment cmnt(masm_, "[ Declarations"); |
253 // For named function expressions, declare the function name as a | 253 // For named function expressions, declare the function name as a |
254 // constant. | 254 // constant. |
255 if (scope()->is_function_scope() && scope()->function() != NULL) { | 255 if (scope()->is_function_scope() && scope()->function() != NULL) { |
256 int ignored = 0; | 256 int ignored = 0; |
257 EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored); | 257 EmitDeclaration(scope()->function(), CONST, NULL, &ignored); |
258 } | 258 } |
259 VisitDeclarations(scope()->declarations()); | 259 VisitDeclarations(scope()->declarations()); |
260 } | 260 } |
261 | 261 |
262 { Comment cmnt(masm_, "[ Stack check"); | 262 { Comment cmnt(masm_, "[ Stack check"); |
263 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 263 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
264 Label ok; | 264 Label ok; |
265 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 265 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
266 __ j(above_equal, &ok, Label::kNear); | 266 __ j(above_equal, &ok, Label::kNear); |
267 StackCheckStub stub; | 267 StackCheckStub stub; |
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
670 | 670 |
671 if (should_normalize) { | 671 if (should_normalize) { |
672 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 672 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
673 Split(equal, if_true, if_false, NULL); | 673 Split(equal, if_true, if_false, NULL); |
674 __ bind(&skip); | 674 __ bind(&skip); |
675 } | 675 } |
676 } | 676 } |
677 | 677 |
678 | 678 |
679 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 679 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
680 Variable::Mode mode, | 680 VariableMode mode, |
681 FunctionLiteral* function, | 681 FunctionLiteral* function, |
682 int* global_count) { | 682 int* global_count) { |
683 // If it was not possible to allocate the variable at compile time, we | 683 // If it was not possible to allocate the variable at compile time, we |
684 // need to "declare" it at runtime to make sure it actually exists in the | 684 // need to "declare" it at runtime to make sure it actually exists in the |
685 // local context. | 685 // local context. |
686 Variable* variable = proxy->var(); | 686 Variable* variable = proxy->var(); |
687 switch (variable->location()) { | 687 switch (variable->location()) { |
688 case Variable::UNALLOCATED: | 688 case Variable::UNALLOCATED: |
689 ++(*global_count); | 689 ++(*global_count); |
690 break; | 690 break; |
691 | 691 |
692 case Variable::PARAMETER: | 692 case Variable::PARAMETER: |
693 case Variable::LOCAL: | 693 case Variable::LOCAL: |
694 if (function != NULL) { | 694 if (function != NULL) { |
695 Comment cmnt(masm_, "[ Declaration"); | 695 Comment cmnt(masm_, "[ Declaration"); |
696 VisitForAccumulatorValue(function); | 696 VisitForAccumulatorValue(function); |
697 __ movq(StackOperand(variable), result_register()); | 697 __ movq(StackOperand(variable), result_register()); |
698 } else if (mode == Variable::CONST || mode == Variable::LET) { | 698 } else if (mode == CONST || mode == LET) { |
699 Comment cmnt(masm_, "[ Declaration"); | 699 Comment cmnt(masm_, "[ Declaration"); |
700 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 700 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
701 __ movq(StackOperand(variable), kScratchRegister); | 701 __ movq(StackOperand(variable), kScratchRegister); |
702 } | 702 } |
703 break; | 703 break; |
704 | 704 |
705 case Variable::CONTEXT: | 705 case Variable::CONTEXT: |
706 // The variable in the decl always resides in the current function | 706 // The variable in the decl always resides in the current function |
707 // context. | 707 // context. |
708 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 708 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
(...skipping 12 matching lines...) Expand all Loading... |
721 int offset = Context::SlotOffset(variable->index()); | 721 int offset = Context::SlotOffset(variable->index()); |
722 // We know that we have written a function, which is not a smi. | 722 // We know that we have written a function, which is not a smi. |
723 __ RecordWriteContextSlot(rsi, | 723 __ RecordWriteContextSlot(rsi, |
724 offset, | 724 offset, |
725 result_register(), | 725 result_register(), |
726 rcx, | 726 rcx, |
727 kDontSaveFPRegs, | 727 kDontSaveFPRegs, |
728 EMIT_REMEMBERED_SET, | 728 EMIT_REMEMBERED_SET, |
729 OMIT_SMI_CHECK); | 729 OMIT_SMI_CHECK); |
730 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 730 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
731 } else if (mode == Variable::CONST || mode == Variable::LET) { | 731 } else if (mode == CONST || mode == LET) { |
732 Comment cmnt(masm_, "[ Declaration"); | 732 Comment cmnt(masm_, "[ Declaration"); |
733 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 733 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
734 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); | 734 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); |
735 // No write barrier since the hole value is in old space. | 735 // No write barrier since the hole value is in old space. |
736 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 736 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
737 } | 737 } |
738 break; | 738 break; |
739 | 739 |
740 case Variable::LOOKUP: { | 740 case Variable::LOOKUP: { |
741 Comment cmnt(masm_, "[ Declaration"); | 741 Comment cmnt(masm_, "[ Declaration"); |
742 __ push(rsi); | 742 __ push(rsi); |
743 __ Push(variable->name()); | 743 __ Push(variable->name()); |
744 // Declaration nodes are always introduced in one of three modes. | 744 // Declaration nodes are always introduced in one of three modes. |
745 ASSERT(mode == Variable::VAR || | 745 ASSERT(mode == VAR || mode == CONST || mode == LET); |
746 mode == Variable::CONST || | 746 PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; |
747 mode == Variable::LET); | |
748 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; | |
749 __ Push(Smi::FromInt(attr)); | 747 __ Push(Smi::FromInt(attr)); |
750 // Push initial value, if any. | 748 // Push initial value, if any. |
751 // Note: For variables we must not push an initial value (such as | 749 // Note: For variables we must not push an initial value (such as |
752 // 'undefined') because we may have a (legal) redeclaration and we | 750 // 'undefined') because we may have a (legal) redeclaration and we |
753 // must not destroy the current value. | 751 // must not destroy the current value. |
754 if (function != NULL) { | 752 if (function != NULL) { |
755 VisitForStackValue(function); | 753 VisitForStackValue(function); |
756 } else if (mode == Variable::CONST || mode == Variable::LET) { | 754 } else if (mode == CONST || mode == LET) { |
757 __ PushRoot(Heap::kTheHoleValueRootIndex); | 755 __ PushRoot(Heap::kTheHoleValueRootIndex); |
758 } else { | 756 } else { |
759 __ Push(Smi::FromInt(0)); // Indicates no initial value. | 757 __ Push(Smi::FromInt(0)); // Indicates no initial value. |
760 } | 758 } |
761 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 759 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
762 break; | 760 break; |
763 } | 761 } |
764 } | 762 } |
765 } | 763 } |
766 | 764 |
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1171 | 1169 |
1172 void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, | 1170 void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, |
1173 TypeofState typeof_state, | 1171 TypeofState typeof_state, |
1174 Label* slow, | 1172 Label* slow, |
1175 Label* done) { | 1173 Label* done) { |
1176 // Generate fast-case code for variables that might be shadowed by | 1174 // Generate fast-case code for variables that might be shadowed by |
1177 // eval-introduced variables. Eval is used a lot without | 1175 // eval-introduced variables. Eval is used a lot without |
1178 // introducing variables. In those cases, we do not want to | 1176 // introducing variables. In those cases, we do not want to |
1179 // perform a runtime call for all variables in the scope | 1177 // perform a runtime call for all variables in the scope |
1180 // containing the eval. | 1178 // containing the eval. |
1181 if (var->mode() == Variable::DYNAMIC_GLOBAL) { | 1179 if (var->mode() == DYNAMIC_GLOBAL) { |
1182 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1180 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
1183 __ jmp(done); | 1181 __ jmp(done); |
1184 } else if (var->mode() == Variable::DYNAMIC_LOCAL) { | 1182 } else if (var->mode() == DYNAMIC_LOCAL) { |
1185 Variable* local = var->local_if_not_shadowed(); | 1183 Variable* local = var->local_if_not_shadowed(); |
1186 __ movq(rax, ContextSlotOperandCheckExtensions(local, slow)); | 1184 __ movq(rax, ContextSlotOperandCheckExtensions(local, slow)); |
1187 if (local->mode() == Variable::CONST || | 1185 if (local->mode() == CONST || local->mode() == LET) { |
1188 local->mode() == Variable::LET) { | |
1189 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1186 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
1190 __ j(not_equal, done); | 1187 __ j(not_equal, done); |
1191 if (local->mode() == Variable::CONST) { | 1188 if (local->mode() == CONST) { |
1192 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1189 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
1193 } else { // Variable::LET | 1190 } else { // LET |
1194 __ Push(var->name()); | 1191 __ Push(var->name()); |
1195 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1192 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1196 } | 1193 } |
1197 } | 1194 } |
1198 __ jmp(done); | 1195 __ jmp(done); |
1199 } | 1196 } |
1200 } | 1197 } |
1201 | 1198 |
1202 | 1199 |
1203 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1200 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
(...skipping 13 matching lines...) Expand all Loading... |
1217 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1214 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
1218 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1215 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
1219 context()->Plug(rax); | 1216 context()->Plug(rax); |
1220 break; | 1217 break; |
1221 } | 1218 } |
1222 | 1219 |
1223 case Variable::PARAMETER: | 1220 case Variable::PARAMETER: |
1224 case Variable::LOCAL: | 1221 case Variable::LOCAL: |
1225 case Variable::CONTEXT: { | 1222 case Variable::CONTEXT: { |
1226 Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot"); | 1223 Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot"); |
1227 if (var->mode() != Variable::LET && var->mode() != Variable::CONST) { | 1224 if (var->mode() != LET && var->mode() != CONST) { |
1228 context()->Plug(var); | 1225 context()->Plug(var); |
1229 } else { | 1226 } else { |
1230 // Let and const need a read barrier. | 1227 // Let and const need a read barrier. |
1231 Label done; | 1228 Label done; |
1232 GetVar(rax, var); | 1229 GetVar(rax, var); |
1233 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1230 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
1234 __ j(not_equal, &done, Label::kNear); | 1231 __ j(not_equal, &done, Label::kNear); |
1235 if (var->mode() == Variable::LET) { | 1232 if (var->mode() == LET) { |
1236 __ Push(var->name()); | 1233 __ Push(var->name()); |
1237 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1234 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1238 } else { // Variable::CONST | 1235 } else { // CONST |
1239 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1236 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
1240 } | 1237 } |
1241 __ bind(&done); | 1238 __ bind(&done); |
1242 context()->Plug(rax); | 1239 context()->Plug(rax); |
1243 } | 1240 } |
1244 break; | 1241 break; |
1245 } | 1242 } |
1246 | 1243 |
1247 case Variable::LOOKUP: { | 1244 case Variable::LOOKUP: { |
1248 Label done, slow; | 1245 Label done, slow; |
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1775 // scope. However, unlike var initializers, const initializers are | 1772 // scope. However, unlike var initializers, const initializers are |
1776 // able to drill a hole to that function context, even from inside a | 1773 // able to drill a hole to that function context, even from inside a |
1777 // 'with' context. We thus bypass the normal static scope lookup for | 1774 // 'with' context. We thus bypass the normal static scope lookup for |
1778 // var->IsContextSlot(). | 1775 // var->IsContextSlot(). |
1779 __ push(rax); | 1776 __ push(rax); |
1780 __ push(rsi); | 1777 __ push(rsi); |
1781 __ Push(var->name()); | 1778 __ Push(var->name()); |
1782 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 1779 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
1783 } | 1780 } |
1784 | 1781 |
1785 } else if (var->mode() == Variable::LET && op != Token::INIT_LET) { | 1782 } else if (var->mode() == LET && op != Token::INIT_LET) { |
1786 // Non-initializing assignment to let variable needs a write barrier. | 1783 // Non-initializing assignment to let variable needs a write barrier. |
1787 if (var->IsLookupSlot()) { | 1784 if (var->IsLookupSlot()) { |
1788 __ push(rax); // Value. | 1785 __ push(rax); // Value. |
1789 __ push(rsi); // Context. | 1786 __ push(rsi); // Context. |
1790 __ Push(var->name()); | 1787 __ Push(var->name()); |
1791 __ Push(Smi::FromInt(strict_mode_flag())); | 1788 __ Push(Smi::FromInt(strict_mode_flag())); |
1792 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 1789 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1793 } else { | 1790 } else { |
1794 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 1791 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
1795 Label assign; | 1792 Label assign; |
1796 MemOperand location = VarOperand(var, rcx); | 1793 MemOperand location = VarOperand(var, rcx); |
1797 __ movq(rdx, location); | 1794 __ movq(rdx, location); |
1798 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 1795 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
1799 __ j(not_equal, &assign, Label::kNear); | 1796 __ j(not_equal, &assign, Label::kNear); |
1800 __ Push(var->name()); | 1797 __ Push(var->name()); |
1801 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1798 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1802 __ bind(&assign); | 1799 __ bind(&assign); |
1803 __ movq(location, rax); | 1800 __ movq(location, rax); |
1804 if (var->IsContextSlot()) { | 1801 if (var->IsContextSlot()) { |
1805 __ movq(rdx, rax); | 1802 __ movq(rdx, rax); |
1806 __ RecordWriteContextSlot( | 1803 __ RecordWriteContextSlot( |
1807 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); | 1804 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); |
1808 } | 1805 } |
1809 } | 1806 } |
1810 | 1807 |
1811 } else if (var->mode() != Variable::CONST) { | 1808 } else if (var->mode() != CONST) { |
1812 // Assignment to var or initializing assignment to let. | 1809 // Assignment to var or initializing assignment to let. |
1813 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1810 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1814 MemOperand location = VarOperand(var, rcx); | 1811 MemOperand location = VarOperand(var, rcx); |
1815 if (FLAG_debug_code && op == Token::INIT_LET) { | 1812 if (FLAG_debug_code && op == Token::INIT_LET) { |
1816 // Check for an uninitialized let binding. | 1813 // Check for an uninitialized let binding. |
1817 __ movq(rdx, location); | 1814 __ movq(rdx, location); |
1818 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 1815 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
1819 __ Check(equal, "Let binding re-initialization."); | 1816 __ Check(equal, "Let binding re-initialization."); |
1820 } | 1817 } |
1821 // Perform the assignment. | 1818 // Perform the assignment. |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2070 for (int i = 0; i < arg_count; i++) { | 2067 for (int i = 0; i < arg_count; i++) { |
2071 VisitForStackValue(args->at(i)); | 2068 VisitForStackValue(args->at(i)); |
2072 } | 2069 } |
2073 | 2070 |
2074 // If we know that eval can only be shadowed by eval-introduced | 2071 // If we know that eval can only be shadowed by eval-introduced |
2075 // variables we attempt to load the global eval function directly in | 2072 // variables we attempt to load the global eval function directly in |
2076 // generated code. If we succeed, there is no need to perform a | 2073 // generated code. If we succeed, there is no need to perform a |
2077 // context lookup in the runtime system. | 2074 // context lookup in the runtime system. |
2078 Label done; | 2075 Label done; |
2079 Variable* var = proxy->var(); | 2076 Variable* var = proxy->var(); |
2080 if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) { | 2077 if (!var->IsUnallocated() && var->mode() == DYNAMIC_GLOBAL) { |
2081 Label slow; | 2078 Label slow; |
2082 EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); | 2079 EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); |
2083 // Push the function and resolve eval. | 2080 // Push the function and resolve eval. |
2084 __ push(rax); | 2081 __ push(rax); |
2085 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); | 2082 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); |
2086 __ jmp(&done); | 2083 __ jmp(&done); |
2087 __ bind(&slow); | 2084 __ bind(&slow); |
2088 } | 2085 } |
2089 | 2086 |
2090 // Push a copy of the function (found below the arguments) and resolve | 2087 // Push a copy of the function (found below the arguments) and resolve |
(...skipping 2109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4200 *context_length = 0; | 4197 *context_length = 0; |
4201 return previous_; | 4198 return previous_; |
4202 } | 4199 } |
4203 | 4200 |
4204 | 4201 |
4205 #undef __ | 4202 #undef __ |
4206 | 4203 |
4207 } } // namespace v8::internal | 4204 } } // namespace v8::internal |
4208 | 4205 |
4209 #endif // V8_TARGET_ARCH_X64 | 4206 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |