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(), CONST, NULL, &ignored); | 257 VariableProxy* proxy = scope()->function(); |
| 258 ASSERT(proxy->var()->mode() == CONST || |
| 259 proxy->var()->mode() == CONST_HARMONY); |
| 260 EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored); |
258 } | 261 } |
259 VisitDeclarations(scope()->declarations()); | 262 VisitDeclarations(scope()->declarations()); |
260 } | 263 } |
261 | 264 |
262 { Comment cmnt(masm_, "[ Stack check"); | 265 { Comment cmnt(masm_, "[ Stack check"); |
263 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 266 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
264 Label ok; | 267 Label ok; |
265 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 268 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
266 __ j(above_equal, &ok, Label::kNear); | 269 __ j(above_equal, &ok, Label::kNear); |
267 StackCheckStub stub; | 270 StackCheckStub stub; |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 | 680 |
678 | 681 |
679 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 682 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
680 VariableMode mode, | 683 VariableMode mode, |
681 FunctionLiteral* function, | 684 FunctionLiteral* function, |
682 int* global_count) { | 685 int* global_count) { |
683 // If it was not possible to allocate the variable at compile time, we | 686 // 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 | 687 // need to "declare" it at runtime to make sure it actually exists in the |
685 // local context. | 688 // local context. |
686 Variable* variable = proxy->var(); | 689 Variable* variable = proxy->var(); |
| 690 bool binding_needs_init = |
| 691 mode == CONST || mode == CONST_HARMONY || mode == LET; |
687 switch (variable->location()) { | 692 switch (variable->location()) { |
688 case Variable::UNALLOCATED: | 693 case Variable::UNALLOCATED: |
689 ++(*global_count); | 694 ++(*global_count); |
690 break; | 695 break; |
691 | 696 |
692 case Variable::PARAMETER: | 697 case Variable::PARAMETER: |
693 case Variable::LOCAL: | 698 case Variable::LOCAL: |
694 if (function != NULL) { | 699 if (function != NULL) { |
695 Comment cmnt(masm_, "[ Declaration"); | 700 Comment cmnt(masm_, "[ Declaration"); |
696 VisitForAccumulatorValue(function); | 701 VisitForAccumulatorValue(function); |
697 __ movq(StackOperand(variable), result_register()); | 702 __ movq(StackOperand(variable), result_register()); |
698 } else if (mode == CONST || mode == LET) { | 703 } else if (binding_needs_init) { |
699 Comment cmnt(masm_, "[ Declaration"); | 704 Comment cmnt(masm_, "[ Declaration"); |
700 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 705 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
701 __ movq(StackOperand(variable), kScratchRegister); | 706 __ movq(StackOperand(variable), kScratchRegister); |
702 } | 707 } |
703 break; | 708 break; |
704 | 709 |
705 case Variable::CONTEXT: | 710 case Variable::CONTEXT: |
706 // The variable in the decl always resides in the current function | 711 // The variable in the decl always resides in the current function |
707 // context. | 712 // context. |
708 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 713 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
(...skipping 12 matching lines...) Expand all Loading... |
721 int offset = Context::SlotOffset(variable->index()); | 726 int offset = Context::SlotOffset(variable->index()); |
722 // We know that we have written a function, which is not a smi. | 727 // We know that we have written a function, which is not a smi. |
723 __ RecordWriteContextSlot(rsi, | 728 __ RecordWriteContextSlot(rsi, |
724 offset, | 729 offset, |
725 result_register(), | 730 result_register(), |
726 rcx, | 731 rcx, |
727 kDontSaveFPRegs, | 732 kDontSaveFPRegs, |
728 EMIT_REMEMBERED_SET, | 733 EMIT_REMEMBERED_SET, |
729 OMIT_SMI_CHECK); | 734 OMIT_SMI_CHECK); |
730 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 735 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
731 } else if (mode == CONST || mode == LET) { | 736 } else if (binding_needs_init) { |
732 Comment cmnt(masm_, "[ Declaration"); | 737 Comment cmnt(masm_, "[ Declaration"); |
733 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 738 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
734 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); | 739 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); |
735 // No write barrier since the hole value is in old space. | 740 // No write barrier since the hole value is in old space. |
736 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 741 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
737 } | 742 } |
738 break; | 743 break; |
739 | 744 |
740 case Variable::LOOKUP: { | 745 case Variable::LOOKUP: { |
741 Comment cmnt(masm_, "[ Declaration"); | 746 Comment cmnt(masm_, "[ Declaration"); |
742 __ push(rsi); | 747 __ push(rsi); |
743 __ Push(variable->name()); | 748 __ Push(variable->name()); |
744 // Declaration nodes are always introduced in one of three modes. | 749 // Declaration nodes are always introduced in one of four modes. |
745 ASSERT(mode == VAR || mode == CONST || mode == LET); | 750 ASSERT(mode == VAR || |
746 PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; | 751 mode == CONST || |
| 752 mode == CONST_HARMONY || |
| 753 mode == LET); |
| 754 PropertyAttributes attr = |
| 755 (mode == CONST || mode == CONST_HARMONY) ? READ_ONLY : NONE; |
747 __ Push(Smi::FromInt(attr)); | 756 __ Push(Smi::FromInt(attr)); |
748 // Push initial value, if any. | 757 // Push initial value, if any. |
749 // Note: For variables we must not push an initial value (such as | 758 // Note: For variables we must not push an initial value (such as |
750 // 'undefined') because we may have a (legal) redeclaration and we | 759 // 'undefined') because we may have a (legal) redeclaration and we |
751 // must not destroy the current value. | 760 // must not destroy the current value. |
752 if (function != NULL) { | 761 if (function != NULL) { |
753 VisitForStackValue(function); | 762 VisitForStackValue(function); |
754 } else if (mode == CONST || mode == LET) { | 763 } else if (binding_needs_init) { |
755 __ PushRoot(Heap::kTheHoleValueRootIndex); | 764 __ PushRoot(Heap::kTheHoleValueRootIndex); |
756 } else { | 765 } else { |
757 __ Push(Smi::FromInt(0)); // Indicates no initial value. | 766 __ Push(Smi::FromInt(0)); // Indicates no initial value. |
758 } | 767 } |
759 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 768 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
760 break; | 769 break; |
761 } | 770 } |
762 } | 771 } |
763 } | 772 } |
764 | 773 |
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1175 // eval-introduced variables. Eval is used a lot without | 1184 // eval-introduced variables. Eval is used a lot without |
1176 // introducing variables. In those cases, we do not want to | 1185 // introducing variables. In those cases, we do not want to |
1177 // perform a runtime call for all variables in the scope | 1186 // perform a runtime call for all variables in the scope |
1178 // containing the eval. | 1187 // containing the eval. |
1179 if (var->mode() == DYNAMIC_GLOBAL) { | 1188 if (var->mode() == DYNAMIC_GLOBAL) { |
1180 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1189 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
1181 __ jmp(done); | 1190 __ jmp(done); |
1182 } else if (var->mode() == DYNAMIC_LOCAL) { | 1191 } else if (var->mode() == DYNAMIC_LOCAL) { |
1183 Variable* local = var->local_if_not_shadowed(); | 1192 Variable* local = var->local_if_not_shadowed(); |
1184 __ movq(rax, ContextSlotOperandCheckExtensions(local, slow)); | 1193 __ movq(rax, ContextSlotOperandCheckExtensions(local, slow)); |
1185 if (local->mode() == CONST || local->mode() == LET) { | 1194 if (local->mode() == CONST || |
| 1195 local->mode() == CONST_HARMONY || |
| 1196 local->mode() == LET) { |
1186 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1197 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
1187 __ j(not_equal, done); | 1198 __ j(not_equal, done); |
1188 if (local->mode() == CONST) { | 1199 if (local->mode() == CONST) { |
1189 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1200 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
1190 } else { // LET | 1201 } else { // LET || CONST_HARMONY |
1191 __ Push(var->name()); | 1202 __ Push(var->name()); |
1192 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1203 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1193 } | 1204 } |
1194 } | 1205 } |
1195 __ jmp(done); | 1206 __ jmp(done); |
1196 } | 1207 } |
1197 } | 1208 } |
1198 | 1209 |
1199 | 1210 |
1200 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1211 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
(...skipping 13 matching lines...) Expand all Loading... |
1214 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1225 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
1215 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1226 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
1216 context()->Plug(rax); | 1227 context()->Plug(rax); |
1217 break; | 1228 break; |
1218 } | 1229 } |
1219 | 1230 |
1220 case Variable::PARAMETER: | 1231 case Variable::PARAMETER: |
1221 case Variable::LOCAL: | 1232 case Variable::LOCAL: |
1222 case Variable::CONTEXT: { | 1233 case Variable::CONTEXT: { |
1223 Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot"); | 1234 Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot"); |
1224 if (var->mode() != LET && var->mode() != CONST) { | 1235 if (!var->binding_needs_init()) { |
1225 context()->Plug(var); | 1236 context()->Plug(var); |
1226 } else { | 1237 } else { |
1227 // Let and const need a read barrier. | 1238 // Let and const need a read barrier. |
1228 Label done; | 1239 Label done; |
1229 GetVar(rax, var); | 1240 GetVar(rax, var); |
1230 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1241 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
1231 __ j(not_equal, &done, Label::kNear); | 1242 __ j(not_equal, &done, Label::kNear); |
1232 if (var->mode() == LET) { | 1243 if (var->mode() == LET || var->mode() == CONST_HARMONY) { |
| 1244 // Throw a reference error when using an uninitialized let/const |
| 1245 // binding in harmony mode. |
1233 __ Push(var->name()); | 1246 __ Push(var->name()); |
1234 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1247 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1235 } else { // CONST | 1248 } else { |
| 1249 // Uninitalized const bindings outside of harmony mode are unholed. |
| 1250 ASSERT(var->mode() == CONST); |
1236 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1251 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
1237 } | 1252 } |
1238 __ bind(&done); | 1253 __ bind(&done); |
1239 context()->Plug(rax); | 1254 context()->Plug(rax); |
1240 } | 1255 } |
1241 break; | 1256 break; |
1242 } | 1257 } |
1243 | 1258 |
1244 case Variable::LOOKUP: { | 1259 case Variable::LOOKUP: { |
1245 Label done, slow; | 1260 Label done, slow; |
(...skipping 601 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1847 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1862 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1848 __ bind(&assign); | 1863 __ bind(&assign); |
1849 __ movq(location, rax); | 1864 __ movq(location, rax); |
1850 if (var->IsContextSlot()) { | 1865 if (var->IsContextSlot()) { |
1851 __ movq(rdx, rax); | 1866 __ movq(rdx, rax); |
1852 __ RecordWriteContextSlot( | 1867 __ RecordWriteContextSlot( |
1853 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); | 1868 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); |
1854 } | 1869 } |
1855 } | 1870 } |
1856 | 1871 |
1857 } else if (var->mode() != CONST) { | 1872 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
1858 // Assignment to var or initializing assignment to let. | 1873 // Assignment to var or initializing assignment to let/const |
| 1874 // in harmony mode. |
1859 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1875 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1860 MemOperand location = VarOperand(var, rcx); | 1876 MemOperand location = VarOperand(var, rcx); |
1861 if (FLAG_debug_code && op == Token::INIT_LET) { | 1877 if (FLAG_debug_code && op == Token::INIT_LET) { |
1862 // Check for an uninitialized let binding. | 1878 // Check for an uninitialized let binding. |
1863 __ movq(rdx, location); | 1879 __ movq(rdx, location); |
1864 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 1880 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
1865 __ Check(equal, "Let binding re-initialization."); | 1881 __ Check(equal, "Let binding re-initialization."); |
1866 } | 1882 } |
1867 // Perform the assignment. | 1883 // Perform the assignment. |
1868 __ movq(location, rax); | 1884 __ movq(location, rax); |
(...skipping 2367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4236 *context_length = 0; | 4252 *context_length = 0; |
4237 return previous_; | 4253 return previous_; |
4238 } | 4254 } |
4239 | 4255 |
4240 | 4256 |
4241 #undef __ | 4257 #undef __ |
4242 | 4258 |
4243 } } // namespace v8::internal | 4259 } } // namespace v8::internal |
4244 | 4260 |
4245 #endif // V8_TARGET_ARCH_X64 | 4261 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |