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

Side by Side Diff: src/arm/full-codegen-arm.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 | « no previous file | src/ast.h » ('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 251 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 Comment cmnt(masm_, "[ Declarations"); 262 Comment cmnt(masm_, "[ Declarations");
263 scope()->VisitIllegalRedeclaration(this); 263 scope()->VisitIllegalRedeclaration(this);
264 264
265 } else { 265 } else {
266 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); 266 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
267 { Comment cmnt(masm_, "[ Declarations"); 267 { Comment cmnt(masm_, "[ Declarations");
268 // For named function expressions, declare the function name as a 268 // For named function expressions, declare the function name as a
269 // constant. 269 // constant.
270 if (scope()->is_function_scope() && scope()->function() != NULL) { 270 if (scope()->is_function_scope() && scope()->function() != NULL) {
271 int ignored = 0; 271 int ignored = 0;
272 EmitDeclaration(scope()->function(), CONST, NULL, &ignored); 272 VariableProxy* proxy = scope()->function();
273 ASSERT(proxy->var()->mode() == CONST ||
274 proxy->var()->mode() == CONST_HARMONY);
275 EmitDeclaration(proxy, proxy->var()->mode(), NULL, &ignored);
273 } 276 }
274 VisitDeclarations(scope()->declarations()); 277 VisitDeclarations(scope()->declarations());
275 } 278 }
276 279
277 { Comment cmnt(masm_, "[ Stack check"); 280 { Comment cmnt(masm_, "[ Stack check");
278 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); 281 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
279 Label ok; 282 Label ok;
280 __ LoadRoot(ip, Heap::kStackLimitRootIndex); 283 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
281 __ cmp(sp, Operand(ip)); 284 __ cmp(sp, Operand(ip));
282 __ b(hs, &ok); 285 __ b(hs, &ok);
(...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after
711 714
712 715
713 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, 716 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
714 VariableMode mode, 717 VariableMode mode,
715 FunctionLiteral* function, 718 FunctionLiteral* function,
716 int* global_count) { 719 int* global_count) {
717 // If it was not possible to allocate the variable at compile time, we 720 // If it was not possible to allocate the variable at compile time, we
718 // need to "declare" it at runtime to make sure it actually exists in the 721 // need to "declare" it at runtime to make sure it actually exists in the
719 // local context. 722 // local context.
720 Variable* variable = proxy->var(); 723 Variable* variable = proxy->var();
724 bool binding_needs_init =
725 mode == CONST || mode == CONST_HARMONY || mode == LET;
721 switch (variable->location()) { 726 switch (variable->location()) {
722 case Variable::UNALLOCATED: 727 case Variable::UNALLOCATED:
723 ++(*global_count); 728 ++(*global_count);
724 break; 729 break;
725 730
726 case Variable::PARAMETER: 731 case Variable::PARAMETER:
727 case Variable::LOCAL: 732 case Variable::LOCAL:
728 if (function != NULL) { 733 if (function != NULL) {
729 Comment cmnt(masm_, "[ Declaration"); 734 Comment cmnt(masm_, "[ Declaration");
730 VisitForAccumulatorValue(function); 735 VisitForAccumulatorValue(function);
731 __ str(result_register(), StackOperand(variable)); 736 __ str(result_register(), StackOperand(variable));
732 } else if (mode == CONST || mode == LET) { 737 } else if (binding_needs_init) {
733 Comment cmnt(masm_, "[ Declaration"); 738 Comment cmnt(masm_, "[ Declaration");
734 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 739 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
735 __ str(ip, StackOperand(variable)); 740 __ str(ip, StackOperand(variable));
736 } 741 }
737 break; 742 break;
738 743
739 case Variable::CONTEXT: 744 case Variable::CONTEXT:
740 // The variable in the decl always resides in the current function 745 // The variable in the decl always resides in the current function
741 // context. 746 // context.
742 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); 747 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
(...skipping 13 matching lines...) Expand all
756 // We know that we have written a function, which is not a smi. 761 // We know that we have written a function, which is not a smi.
757 __ RecordWriteContextSlot(cp, 762 __ RecordWriteContextSlot(cp,
758 offset, 763 offset,
759 result_register(), 764 result_register(),
760 r2, 765 r2,
761 kLRHasBeenSaved, 766 kLRHasBeenSaved,
762 kDontSaveFPRegs, 767 kDontSaveFPRegs,
763 EMIT_REMEMBERED_SET, 768 EMIT_REMEMBERED_SET,
764 OMIT_SMI_CHECK); 769 OMIT_SMI_CHECK);
765 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); 770 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
766 } else if (mode == CONST || mode == LET) { 771 } else if (binding_needs_init) {
767 Comment cmnt(masm_, "[ Declaration"); 772 Comment cmnt(masm_, "[ Declaration");
768 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 773 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
769 __ str(ip, ContextOperand(cp, variable->index())); 774 __ str(ip, ContextOperand(cp, variable->index()));
770 // No write barrier since the_hole_value is in old space. 775 // No write barrier since the_hole_value is in old space.
771 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); 776 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
772 } 777 }
773 break; 778 break;
774 779
775 case Variable::LOOKUP: { 780 case Variable::LOOKUP: {
776 Comment cmnt(masm_, "[ Declaration"); 781 Comment cmnt(masm_, "[ Declaration");
777 __ mov(r2, Operand(variable->name())); 782 __ mov(r2, Operand(variable->name()));
778 // Declaration nodes are always introduced in one of three modes. 783 // Declaration nodes are always introduced in one of four modes.
779 ASSERT(mode == VAR || mode == CONST || mode == LET); 784 ASSERT(mode == VAR ||
780 PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; 785 mode == CONST ||
786 mode == CONST_HARMONY ||
787 mode == LET);
788 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY)
789 ? READ_ONLY : NONE;
781 __ mov(r1, Operand(Smi::FromInt(attr))); 790 __ mov(r1, Operand(Smi::FromInt(attr)));
782 // Push initial value, if any. 791 // Push initial value, if any.
783 // Note: For variables we must not push an initial value (such as 792 // Note: For variables we must not push an initial value (such as
784 // 'undefined') because we may have a (legal) redeclaration and we 793 // 'undefined') because we may have a (legal) redeclaration and we
785 // must not destroy the current value. 794 // must not destroy the current value.
786 if (function != NULL) { 795 if (function != NULL) {
787 __ Push(cp, r2, r1); 796 __ Push(cp, r2, r1);
788 // Push initial value for function declaration. 797 // Push initial value for function declaration.
789 VisitForStackValue(function); 798 VisitForStackValue(function);
790 } else if (mode == CONST || mode == LET) { 799 } else if (binding_needs_init) {
791 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); 800 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
792 __ Push(cp, r2, r1, r0); 801 __ Push(cp, r2, r1, r0);
793 } else { 802 } else {
794 __ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value. 803 __ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value.
795 __ Push(cp, r2, r1, r0); 804 __ Push(cp, r2, r1, r0);
796 } 805 }
797 __ CallRuntime(Runtime::kDeclareContextSlot, 4); 806 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
798 break; 807 break;
799 } 808 }
800 } 809 }
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after
1217 // introducing variables. In those cases, we do not want to 1226 // introducing variables. In those cases, we do not want to
1218 // perform a runtime call for all variables in the scope 1227 // perform a runtime call for all variables in the scope
1219 // containing the eval. 1228 // containing the eval.
1220 if (var->mode() == DYNAMIC_GLOBAL) { 1229 if (var->mode() == DYNAMIC_GLOBAL) {
1221 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); 1230 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
1222 __ jmp(done); 1231 __ jmp(done);
1223 } else if (var->mode() == DYNAMIC_LOCAL) { 1232 } else if (var->mode() == DYNAMIC_LOCAL) {
1224 Variable* local = var->local_if_not_shadowed(); 1233 Variable* local = var->local_if_not_shadowed();
1225 __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow)); 1234 __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow));
1226 if (local->mode() == CONST || 1235 if (local->mode() == CONST ||
1236 local->mode() == CONST_HARMONY ||
1227 local->mode() == LET) { 1237 local->mode() == LET) {
1228 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); 1238 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
1229 if (local->mode() == CONST) { 1239 if (local->mode() == CONST) {
1230 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); 1240 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
1231 } else { // LET 1241 } else { // LET || CONST_HARMONY
1232 __ b(ne, done); 1242 __ b(ne, done);
1233 __ mov(r0, Operand(var->name())); 1243 __ mov(r0, Operand(var->name()));
1234 __ push(r0); 1244 __ push(r0);
1235 __ CallRuntime(Runtime::kThrowReferenceError, 1); 1245 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1236 } 1246 }
1237 } 1247 }
1238 __ jmp(done); 1248 __ jmp(done);
1239 } 1249 }
1240 } 1250 }
1241 1251
(...skipping 17 matching lines...) Expand all
1259 context()->Plug(r0); 1269 context()->Plug(r0);
1260 break; 1270 break;
1261 } 1271 }
1262 1272
1263 case Variable::PARAMETER: 1273 case Variable::PARAMETER:
1264 case Variable::LOCAL: 1274 case Variable::LOCAL:
1265 case Variable::CONTEXT: { 1275 case Variable::CONTEXT: {
1266 Comment cmnt(masm_, var->IsContextSlot() 1276 Comment cmnt(masm_, var->IsContextSlot()
1267 ? "Context variable" 1277 ? "Context variable"
1268 : "Stack variable"); 1278 : "Stack variable");
1269 if (var->mode() != LET && var->mode() != CONST) { 1279 if (!var->binding_needs_init()) {
1270 context()->Plug(var); 1280 context()->Plug(var);
1271 } else { 1281 } else {
1272 // Let and const need a read barrier. 1282 // Let and const need a read barrier.
1273 GetVar(r0, var); 1283 GetVar(r0, var);
1274 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); 1284 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
1275 if (var->mode() == LET) { 1285 if (var->mode() == LET || var->mode() == CONST_HARMONY) {
1286 // Throw a reference error when using an uninitialized let/const
1287 // binding in harmony mode.
1276 Label done; 1288 Label done;
1277 __ b(ne, &done); 1289 __ b(ne, &done);
1278 __ mov(r0, Operand(var->name())); 1290 __ mov(r0, Operand(var->name()));
1279 __ push(r0); 1291 __ push(r0);
1280 __ CallRuntime(Runtime::kThrowReferenceError, 1); 1292 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1281 __ bind(&done); 1293 __ bind(&done);
1282 } else { 1294 } else {
1295 // Uninitalized const bindings outside of harmony mode are unholed.
1296 ASSERT(var->mode() == CONST);
1283 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); 1297 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
1284 } 1298 }
1285 context()->Plug(r0); 1299 context()->Plug(r0);
1286 } 1300 }
1287 break; 1301 break;
1288 } 1302 }
1289 1303
1290 case Variable::LOOKUP: { 1304 case Variable::LOOKUP: {
1291 Label done, slow; 1305 Label done, slow;
1292 // Generate code for loading from variables potentially shadowed 1306 // Generate code for loading from variables potentially shadowed
(...skipping 647 matching lines...) Expand 10 before | Expand all | Expand 10 after
1940 __ str(result_register(), location); 1954 __ str(result_register(), location);
1941 if (var->IsContextSlot()) { 1955 if (var->IsContextSlot()) {
1942 // RecordWrite may destroy all its register arguments. 1956 // RecordWrite may destroy all its register arguments.
1943 __ mov(r3, result_register()); 1957 __ mov(r3, result_register());
1944 int offset = Context::SlotOffset(var->index()); 1958 int offset = Context::SlotOffset(var->index());
1945 __ RecordWriteContextSlot( 1959 __ RecordWriteContextSlot(
1946 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); 1960 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs);
1947 } 1961 }
1948 } 1962 }
1949 1963
1950 } else if (var->mode() != CONST) { 1964 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
1951 // Assignment to var or initializing assignment to let. 1965 // Assignment to var or initializing assignment to let/const
1966 // in harmony mode.
1952 if (var->IsStackAllocated() || var->IsContextSlot()) { 1967 if (var->IsStackAllocated() || var->IsContextSlot()) {
1953 MemOperand location = VarOperand(var, r1); 1968 MemOperand location = VarOperand(var, r1);
1954 if (FLAG_debug_code && op == Token::INIT_LET) { 1969 if (FLAG_debug_code && op == Token::INIT_LET) {
1955 // Check for an uninitialized let binding. 1970 // Check for an uninitialized let binding.
1956 __ ldr(r2, location); 1971 __ ldr(r2, location);
1957 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); 1972 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
1958 __ Check(eq, "Let binding re-initialization."); 1973 __ Check(eq, "Let binding re-initialization.");
1959 } 1974 }
1960 // Perform the assignment. 1975 // Perform the assignment.
1961 __ str(r0, location); 1976 __ str(r0, location);
(...skipping 2342 matching lines...) Expand 10 before | Expand all | Expand 10 after
4304 *context_length = 0; 4319 *context_length = 0;
4305 return previous_; 4320 return previous_;
4306 } 4321 }
4307 4322
4308 4323
4309 #undef __ 4324 #undef __
4310 4325
4311 } } // namespace v8::internal 4326 } } // namespace v8::internal
4312 4327
4313 #endif // V8_TARGET_ARCH_ARM 4328 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « no previous file | src/ast.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698