Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(417)

Side by Side Diff: src/ia32/full-codegen-ia32.cc

Issue 7992005: Block scoped const variables. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Comments, function variable mode, preparser. Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.cc ('k') | src/messages.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/hydrogen.cc ('k') | src/messages.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698