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 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 Comment cmnt(masm_, "[ Declarations"); | 259 Comment cmnt(masm_, "[ Declarations"); |
260 scope()->VisitIllegalRedeclaration(this); | 260 scope()->VisitIllegalRedeclaration(this); |
261 | 261 |
262 } else { | 262 } else { |
263 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 263 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
264 { Comment cmnt(masm_, "[ Declarations"); | 264 { Comment cmnt(masm_, "[ Declarations"); |
265 // For named function expressions, declare the function name as a | 265 // For named function expressions, declare the function name as a |
266 // constant. | 266 // constant. |
267 if (scope()->is_function_scope() && scope()->function() != NULL) { | 267 if (scope()->is_function_scope() && scope()->function() != NULL) { |
268 int ignored = 0; | 268 int ignored = 0; |
269 EmitDeclaration(scope()->function(), CONST, NULL, &ignored); | 269 VariableProxy* proxy = scope()->function(); |
| 270 ASSERT(proxy->var()->mode() == CONST || |
| 271 proxy->var()->mode() == CONST_HARMONY); |
| 272 EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored); |
270 } | 273 } |
271 VisitDeclarations(scope()->declarations()); | 274 VisitDeclarations(scope()->declarations()); |
272 } | 275 } |
273 | 276 |
274 { Comment cmnt(masm_, "[ Stack check"); | 277 { Comment cmnt(masm_, "[ Stack check"); |
275 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 278 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
276 Label ok; | 279 Label ok; |
277 ExternalReference stack_limit = | 280 ExternalReference stack_limit = |
278 ExternalReference::address_of_stack_limit(isolate()); | 281 ExternalReference::address_of_stack_limit(isolate()); |
279 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 282 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
(...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
704 | 707 |
705 | 708 |
706 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 709 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
707 VariableMode mode, | 710 VariableMode mode, |
708 FunctionLiteral* function, | 711 FunctionLiteral* function, |
709 int* global_count) { | 712 int* global_count) { |
710 // If it was not possible to allocate the variable at compile time, we | 713 // If it was not possible to allocate the variable at compile time, we |
711 // need to "declare" it at runtime to make sure it actually exists in the | 714 // need to "declare" it at runtime to make sure it actually exists in the |
712 // local context. | 715 // local context. |
713 Variable* variable = proxy->var(); | 716 Variable* variable = proxy->var(); |
| 717 bool binding_needs_init = |
| 718 mode == CONST || mode == CONST_HARMONY || mode == LET; |
714 switch (variable->location()) { | 719 switch (variable->location()) { |
715 case Variable::UNALLOCATED: | 720 case Variable::UNALLOCATED: |
716 ++(*global_count); | 721 ++(*global_count); |
717 break; | 722 break; |
718 | 723 |
719 case Variable::PARAMETER: | 724 case Variable::PARAMETER: |
720 case Variable::LOCAL: | 725 case Variable::LOCAL: |
721 if (function != NULL) { | 726 if (function != NULL) { |
722 Comment cmnt(masm_, "[ Declaration"); | 727 Comment cmnt(masm_, "[ Declaration"); |
723 VisitForAccumulatorValue(function); | 728 VisitForAccumulatorValue(function); |
724 __ mov(StackOperand(variable), result_register()); | 729 __ mov(StackOperand(variable), result_register()); |
725 } else if (mode == CONST || mode == LET) { | 730 } else if (binding_needs_init) { |
726 Comment cmnt(masm_, "[ Declaration"); | 731 Comment cmnt(masm_, "[ Declaration"); |
727 __ mov(StackOperand(variable), | 732 __ mov(StackOperand(variable), |
728 Immediate(isolate()->factory()->the_hole_value())); | 733 Immediate(isolate()->factory()->the_hole_value())); |
729 } | 734 } |
730 break; | 735 break; |
731 | 736 |
732 case Variable::CONTEXT: | 737 case Variable::CONTEXT: |
733 // The variable in the decl always resides in the current function | 738 // The variable in the decl always resides in the current function |
734 // context. | 739 // context. |
735 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 740 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
(...skipping 11 matching lines...) Expand all Loading... |
747 __ mov(ContextOperand(esi, variable->index()), result_register()); | 752 __ mov(ContextOperand(esi, variable->index()), result_register()); |
748 // We know that we have written a function, which is not a smi. | 753 // We know that we have written a function, which is not a smi. |
749 __ RecordWriteContextSlot(esi, | 754 __ RecordWriteContextSlot(esi, |
750 Context::SlotOffset(variable->index()), | 755 Context::SlotOffset(variable->index()), |
751 result_register(), | 756 result_register(), |
752 ecx, | 757 ecx, |
753 kDontSaveFPRegs, | 758 kDontSaveFPRegs, |
754 EMIT_REMEMBERED_SET, | 759 EMIT_REMEMBERED_SET, |
755 OMIT_SMI_CHECK); | 760 OMIT_SMI_CHECK); |
756 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 761 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
757 } else if (mode == CONST || mode == LET) { | 762 } else if (binding_needs_init) { |
758 Comment cmnt(masm_, "[ Declaration"); | 763 Comment cmnt(masm_, "[ Declaration"); |
759 __ mov(ContextOperand(esi, variable->index()), | 764 __ mov(ContextOperand(esi, variable->index()), |
760 Immediate(isolate()->factory()->the_hole_value())); | 765 Immediate(isolate()->factory()->the_hole_value())); |
761 // No write barrier since the hole value is in old space. | 766 // No write barrier since the hole value is in old space. |
762 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 767 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
763 } | 768 } |
764 break; | 769 break; |
765 | 770 |
766 case Variable::LOOKUP: { | 771 case Variable::LOOKUP: { |
767 Comment cmnt(masm_, "[ Declaration"); | 772 Comment cmnt(masm_, "[ Declaration"); |
768 __ push(esi); | 773 __ push(esi); |
769 __ push(Immediate(variable->name())); | 774 __ push(Immediate(variable->name())); |
770 // Declaration nodes are always introduced in one of three modes. | 775 // Declaration nodes are always introduced in one of four modes. |
771 ASSERT(mode == VAR || mode == CONST || mode == LET); | 776 ASSERT(mode == VAR || |
772 PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; | 777 mode == CONST || |
| 778 mode == CONST_HARMONY || |
| 779 mode == LET); |
| 780 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY) |
| 781 ? READ_ONLY : NONE; |
773 __ push(Immediate(Smi::FromInt(attr))); | 782 __ push(Immediate(Smi::FromInt(attr))); |
774 // Push initial value, if any. | 783 // Push initial value, if any. |
775 // Note: For variables we must not push an initial value (such as | 784 // Note: For variables we must not push an initial value (such as |
776 // 'undefined') because we may have a (legal) redeclaration and we | 785 // 'undefined') because we may have a (legal) redeclaration and we |
777 // must not destroy the current value. | 786 // must not destroy the current value. |
778 increment_stack_height(3); | 787 increment_stack_height(3); |
779 if (function != NULL) { | 788 if (function != NULL) { |
780 VisitForStackValue(function); | 789 VisitForStackValue(function); |
781 } else if (mode == CONST || mode == LET) { | 790 } else if (binding_needs_init) { |
782 __ push(Immediate(isolate()->factory()->the_hole_value())); | 791 __ push(Immediate(isolate()->factory()->the_hole_value())); |
783 increment_stack_height(); | 792 increment_stack_height(); |
784 } else { | 793 } else { |
785 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. | 794 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. |
786 increment_stack_height(); | 795 increment_stack_height(); |
787 } | 796 } |
788 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 797 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
789 decrement_stack_height(4); | 798 decrement_stack_height(4); |
790 break; | 799 break; |
791 } | 800 } |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1199 // introducing variables. In those cases, we do not want to | 1208 // introducing variables. In those cases, we do not want to |
1200 // perform a runtime call for all variables in the scope | 1209 // perform a runtime call for all variables in the scope |
1201 // containing the eval. | 1210 // containing the eval. |
1202 if (var->mode() == DYNAMIC_GLOBAL) { | 1211 if (var->mode() == DYNAMIC_GLOBAL) { |
1203 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1212 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
1204 __ jmp(done); | 1213 __ jmp(done); |
1205 } else if (var->mode() == DYNAMIC_LOCAL) { | 1214 } else if (var->mode() == DYNAMIC_LOCAL) { |
1206 Variable* local = var->local_if_not_shadowed(); | 1215 Variable* local = var->local_if_not_shadowed(); |
1207 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); | 1216 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); |
1208 if (local->mode() == CONST || | 1217 if (local->mode() == CONST || |
| 1218 local->mode() == CONST_HARMONY || |
1209 local->mode() == LET) { | 1219 local->mode() == LET) { |
1210 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1220 __ cmp(eax, isolate()->factory()->the_hole_value()); |
1211 __ j(not_equal, done); | 1221 __ j(not_equal, done); |
1212 if (local->mode() == CONST) { | 1222 if (local->mode() == CONST) { |
1213 __ mov(eax, isolate()->factory()->undefined_value()); | 1223 __ mov(eax, isolate()->factory()->undefined_value()); |
1214 } else { // LET | 1224 } else { // LET || CONST_HARMONY |
1215 __ push(Immediate(var->name())); | 1225 __ push(Immediate(var->name())); |
1216 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1226 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1217 } | 1227 } |
1218 } | 1228 } |
1219 __ jmp(done); | 1229 __ jmp(done); |
1220 } | 1230 } |
1221 } | 1231 } |
1222 | 1232 |
1223 | 1233 |
1224 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1234 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
(...skipping 15 matching lines...) Expand all Loading... |
1240 context()->Plug(eax); | 1250 context()->Plug(eax); |
1241 break; | 1251 break; |
1242 } | 1252 } |
1243 | 1253 |
1244 case Variable::PARAMETER: | 1254 case Variable::PARAMETER: |
1245 case Variable::LOCAL: | 1255 case Variable::LOCAL: |
1246 case Variable::CONTEXT: { | 1256 case Variable::CONTEXT: { |
1247 Comment cmnt(masm_, var->IsContextSlot() | 1257 Comment cmnt(masm_, var->IsContextSlot() |
1248 ? "Context variable" | 1258 ? "Context variable" |
1249 : "Stack variable"); | 1259 : "Stack variable"); |
1250 if (var->mode() != LET && var->mode() != CONST) { | 1260 if (!var->binding_needs_init()) { |
1251 context()->Plug(var); | 1261 context()->Plug(var); |
1252 } else { | 1262 } else { |
1253 // Let and const need a read barrier. | 1263 // Let and const need a read barrier. |
1254 Label done; | 1264 Label done; |
1255 GetVar(eax, var); | 1265 GetVar(eax, var); |
1256 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1266 __ cmp(eax, isolate()->factory()->the_hole_value()); |
1257 __ j(not_equal, &done, Label::kNear); | 1267 __ j(not_equal, &done, Label::kNear); |
1258 if (var->mode() == LET) { | 1268 if (var->mode() == LET || var->mode() == CONST_HARMONY) { |
| 1269 // Throw a reference error when using an uninitialized let/const |
| 1270 // binding in harmony mode. |
1259 __ push(Immediate(var->name())); | 1271 __ push(Immediate(var->name())); |
1260 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1272 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1261 } else { // CONST | 1273 } else { |
| 1274 // Uninitalized const bindings outside of harmony mode are unholed. |
| 1275 ASSERT(var->mode() == CONST); |
1262 __ mov(eax, isolate()->factory()->undefined_value()); | 1276 __ mov(eax, isolate()->factory()->undefined_value()); |
1263 } | 1277 } |
1264 __ bind(&done); | 1278 __ bind(&done); |
1265 context()->Plug(eax); | 1279 context()->Plug(eax); |
1266 } | 1280 } |
1267 break; | 1281 break; |
1268 } | 1282 } |
1269 | 1283 |
1270 case Variable::LOOKUP: { | 1284 case Variable::LOOKUP: { |
1271 Label done, slow; | 1285 Label done, slow; |
(...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1934 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1948 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1935 __ bind(&assign); | 1949 __ bind(&assign); |
1936 __ mov(location, eax); | 1950 __ mov(location, eax); |
1937 if (var->IsContextSlot()) { | 1951 if (var->IsContextSlot()) { |
1938 __ mov(edx, eax); | 1952 __ mov(edx, eax); |
1939 int offset = Context::SlotOffset(var->index()); | 1953 int offset = Context::SlotOffset(var->index()); |
1940 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); | 1954 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); |
1941 } | 1955 } |
1942 } | 1956 } |
1943 | 1957 |
1944 } else if (var->mode() != CONST) { | 1958 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
1945 // Assignment to var or initializing assignment to let. | 1959 // Assignment to var or initializing assignment to let/const |
| 1960 // in harmony mode. |
1946 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1961 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1947 MemOperand location = VarOperand(var, ecx); | 1962 MemOperand location = VarOperand(var, ecx); |
1948 if (FLAG_debug_code && op == Token::INIT_LET) { | 1963 if (FLAG_debug_code && op == Token::INIT_LET) { |
1949 // Check for an uninitialized let binding. | 1964 // Check for an uninitialized let binding. |
1950 __ mov(edx, location); | 1965 __ mov(edx, location); |
1951 __ cmp(edx, isolate()->factory()->the_hole_value()); | 1966 __ cmp(edx, isolate()->factory()->the_hole_value()); |
1952 __ Check(equal, "Let binding re-initialization."); | 1967 __ Check(equal, "Let binding re-initialization."); |
1953 } | 1968 } |
1954 // Perform the assignment. | 1969 // Perform the assignment. |
1955 __ mov(location, eax); | 1970 __ mov(location, eax); |
(...skipping 2430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4386 *context_length = 0; | 4401 *context_length = 0; |
4387 return previous_; | 4402 return previous_; |
4388 } | 4403 } |
4389 | 4404 |
4390 | 4405 |
4391 #undef __ | 4406 #undef __ |
4392 | 4407 |
4393 } } // namespace v8::internal | 4408 } } // namespace v8::internal |
4394 | 4409 |
4395 #endif // V8_TARGET_ARCH_IA32 | 4410 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |