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

Side by Side Diff: src/x64/full-codegen-x64.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, 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
« no previous file with comments | « src/variables.cc ('k') | test/mjsunit/harmony/block-conflicts.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 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/variables.cc ('k') | test/mjsunit/harmony/block-conflicts.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698