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

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

Powered by Google App Engine
This is Rietveld 408576698