OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_ARM | 5 #if V8_TARGET_ARCH_ARM |
6 | 6 |
7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 742 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 __ CompareRoot(r1, Heap::kWithContextMapRootIndex); | 753 __ CompareRoot(r1, Heap::kWithContextMapRootIndex); |
754 __ Check(ne, kDeclarationInWithContext); | 754 __ Check(ne, kDeclarationInWithContext); |
755 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); | 755 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); |
756 __ Check(ne, kDeclarationInCatchContext); | 756 __ Check(ne, kDeclarationInCatchContext); |
757 } | 757 } |
758 } | 758 } |
759 | 759 |
760 | 760 |
761 void FullCodeGenerator::VisitVariableDeclaration( | 761 void FullCodeGenerator::VisitVariableDeclaration( |
762 VariableDeclaration* declaration) { | 762 VariableDeclaration* declaration) { |
763 // If it was not possible to allocate the variable at compile time, we | |
764 // need to "declare" it at runtime to make sure it actually exists in the | |
765 // local context. | |
766 VariableProxy* proxy = declaration->proxy(); | 763 VariableProxy* proxy = declaration->proxy(); |
767 VariableMode mode = declaration->mode(); | |
768 Variable* variable = proxy->var(); | 764 Variable* variable = proxy->var(); |
769 bool hole_init = mode == LET || mode == CONST; | |
770 switch (variable->location()) { | 765 switch (variable->location()) { |
771 case VariableLocation::GLOBAL: | 766 case VariableLocation::GLOBAL: |
772 case VariableLocation::UNALLOCATED: { | 767 case VariableLocation::UNALLOCATED: { |
773 DCHECK(!variable->binding_needs_init()); | 768 DCHECK(!variable->binding_needs_init()); |
774 FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); | 769 FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); |
775 DCHECK(!slot.IsInvalid()); | 770 DCHECK(!slot.IsInvalid()); |
776 globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); | 771 globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); |
777 globals_->Add(isolate()->factory()->undefined_value(), zone()); | 772 globals_->Add(isolate()->factory()->undefined_value(), zone()); |
778 break; | 773 break; |
779 } | 774 } |
780 case VariableLocation::PARAMETER: | 775 case VariableLocation::PARAMETER: |
781 case VariableLocation::LOCAL: | 776 case VariableLocation::LOCAL: |
782 if (hole_init) { | 777 if (variable->binding_needs_init()) { |
783 Comment cmnt(masm_, "[ VariableDeclaration"); | 778 Comment cmnt(masm_, "[ VariableDeclaration"); |
784 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); | 779 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); |
785 __ str(r0, StackOperand(variable)); | 780 __ str(r0, StackOperand(variable)); |
786 } | 781 } |
787 break; | 782 break; |
788 | 783 |
789 case VariableLocation::CONTEXT: | 784 case VariableLocation::CONTEXT: |
790 if (hole_init) { | 785 if (variable->binding_needs_init()) { |
791 Comment cmnt(masm_, "[ VariableDeclaration"); | 786 Comment cmnt(masm_, "[ VariableDeclaration"); |
792 EmitDebugCheckDeclarationContext(variable); | 787 EmitDebugCheckDeclarationContext(variable); |
793 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); | 788 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); |
794 __ str(r0, ContextMemOperand(cp, variable->index())); | 789 __ str(r0, ContextMemOperand(cp, variable->index())); |
795 // No write barrier since the_hole_value is in old space. | 790 // No write barrier since the_hole_value is in old space. |
796 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | 791 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); |
797 } | 792 } |
798 break; | 793 break; |
799 | 794 |
800 case VariableLocation::LOOKUP: { | 795 case VariableLocation::LOOKUP: { |
801 Comment cmnt(masm_, "[ VariableDeclaration"); | 796 Comment cmnt(masm_, "[ VariableDeclaration"); |
802 DCHECK_EQ(VAR, mode); | 797 DCHECK_EQ(VAR, variable->mode()); |
803 DCHECK(!hole_init); | 798 DCHECK(!variable->binding_needs_init()); |
804 __ mov(r2, Operand(variable->name())); | 799 __ mov(r2, Operand(variable->name())); |
805 __ Push(r2); | 800 __ Push(r2); |
806 __ CallRuntime(Runtime::kDeclareEvalVar); | 801 __ CallRuntime(Runtime::kDeclareEvalVar); |
807 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); | 802 PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS); |
808 break; | 803 break; |
809 } | 804 } |
810 } | 805 } |
811 } | 806 } |
812 | 807 |
813 | 808 |
(...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1264 // introducing variables. In those cases, we do not want to | 1259 // introducing variables. In those cases, we do not want to |
1265 // perform a runtime call for all variables in the scope | 1260 // perform a runtime call for all variables in the scope |
1266 // containing the eval. | 1261 // containing the eval. |
1267 Variable* var = proxy->var(); | 1262 Variable* var = proxy->var(); |
1268 if (var->mode() == DYNAMIC_GLOBAL) { | 1263 if (var->mode() == DYNAMIC_GLOBAL) { |
1269 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow); | 1264 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow); |
1270 __ jmp(done); | 1265 __ jmp(done); |
1271 } else if (var->mode() == DYNAMIC_LOCAL) { | 1266 } else if (var->mode() == DYNAMIC_LOCAL) { |
1272 Variable* local = var->local_if_not_shadowed(); | 1267 Variable* local = var->local_if_not_shadowed(); |
1273 __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow)); | 1268 __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow)); |
1274 if (local->mode() == LET || local->mode() == CONST) { | 1269 if (local->binding_needs_init()) { |
1275 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); | 1270 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); |
1276 __ b(ne, done); | 1271 __ b(ne, done); |
1277 __ mov(r0, Operand(var->name())); | 1272 __ mov(r0, Operand(var->name())); |
1278 __ push(r0); | 1273 __ push(r0); |
1279 __ CallRuntime(Runtime::kThrowReferenceError); | 1274 __ CallRuntime(Runtime::kThrowReferenceError); |
| 1275 } else { |
| 1276 __ jmp(done); |
1280 } | 1277 } |
1281 __ jmp(done); | |
1282 } | 1278 } |
1283 } | 1279 } |
1284 | 1280 |
1285 | 1281 |
1286 void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy, | 1282 void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy, |
1287 TypeofMode typeof_mode) { | 1283 TypeofMode typeof_mode) { |
1288 #ifdef DEBUG | 1284 #ifdef DEBUG |
1289 Variable* var = proxy->var(); | 1285 Variable* var = proxy->var(); |
1290 DCHECK(var->IsUnallocatedOrGlobalSlot() || | 1286 DCHECK(var->IsUnallocatedOrGlobalSlot() || |
1291 (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL)); | 1287 (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL)); |
(...skipping 22 matching lines...) Expand all Loading... |
1314 break; | 1310 break; |
1315 } | 1311 } |
1316 | 1312 |
1317 case VariableLocation::PARAMETER: | 1313 case VariableLocation::PARAMETER: |
1318 case VariableLocation::LOCAL: | 1314 case VariableLocation::LOCAL: |
1319 case VariableLocation::CONTEXT: { | 1315 case VariableLocation::CONTEXT: { |
1320 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); | 1316 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); |
1321 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" | 1317 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" |
1322 : "[ Stack variable"); | 1318 : "[ Stack variable"); |
1323 if (NeedsHoleCheckForLoad(proxy)) { | 1319 if (NeedsHoleCheckForLoad(proxy)) { |
1324 // Let and const need a read barrier. | 1320 // Throw a reference error when using an uninitialized let/const |
| 1321 // binding in harmony mode. |
| 1322 Label done; |
1325 GetVar(r0, var); | 1323 GetVar(r0, var); |
1326 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); | 1324 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); |
1327 if (var->mode() == LET || var->mode() == CONST) { | 1325 __ b(ne, &done); |
1328 // Throw a reference error when using an uninitialized let/const | 1326 __ mov(r0, Operand(var->name())); |
1329 // binding in harmony mode. | 1327 __ push(r0); |
1330 Label done; | 1328 __ CallRuntime(Runtime::kThrowReferenceError); |
1331 __ b(ne, &done); | 1329 __ bind(&done); |
1332 __ mov(r0, Operand(var->name())); | |
1333 __ push(r0); | |
1334 __ CallRuntime(Runtime::kThrowReferenceError); | |
1335 __ bind(&done); | |
1336 } | |
1337 context()->Plug(r0); | 1330 context()->Plug(r0); |
1338 break; | 1331 break; |
1339 } | 1332 } |
1340 context()->Plug(var); | 1333 context()->Plug(var); |
1341 break; | 1334 break; |
1342 } | 1335 } |
1343 | 1336 |
1344 case VariableLocation::LOOKUP: { | 1337 case VariableLocation::LOOKUP: { |
1345 Comment cmnt(masm_, "[ Lookup variable"); | 1338 Comment cmnt(masm_, "[ Lookup variable"); |
1346 Label done, slow; | 1339 Label done, slow; |
(...skipping 811 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2158 | 2151 |
2159 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, | 2152 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, |
2160 FeedbackVectorSlot slot) { | 2153 FeedbackVectorSlot slot) { |
2161 if (var->IsUnallocated()) { | 2154 if (var->IsUnallocated()) { |
2162 // Global var, const, or let. | 2155 // Global var, const, or let. |
2163 __ mov(StoreDescriptor::NameRegister(), Operand(var->name())); | 2156 __ mov(StoreDescriptor::NameRegister(), Operand(var->name())); |
2164 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); | 2157 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); |
2165 EmitLoadStoreICSlot(slot); | 2158 EmitLoadStoreICSlot(slot); |
2166 CallStoreIC(); | 2159 CallStoreIC(); |
2167 | 2160 |
2168 } else if (var->mode() == LET && op != Token::INIT) { | 2161 } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) { |
2169 // Non-initializing assignment to let variable needs a write barrier. | |
2170 DCHECK(!var->IsLookupSlot()); | 2162 DCHECK(!var->IsLookupSlot()); |
2171 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 2163 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
2172 Label assign; | |
2173 MemOperand location = VarOperand(var, r1); | 2164 MemOperand location = VarOperand(var, r1); |
2174 __ ldr(r3, location); | 2165 // Perform an initialization check for lexically declared variables. |
2175 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); | 2166 if (var->binding_needs_init()) { |
2176 __ b(ne, &assign); | 2167 Label assign; |
2177 __ mov(r3, Operand(var->name())); | 2168 __ ldr(r3, location); |
2178 __ push(r3); | 2169 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); |
2179 __ CallRuntime(Runtime::kThrowReferenceError); | 2170 __ b(ne, &assign); |
2180 // Perform the assignment. | 2171 __ mov(r3, Operand(var->name())); |
2181 __ bind(&assign); | 2172 __ push(r3); |
2182 EmitStoreToStackLocalOrContextSlot(var, location); | 2173 __ CallRuntime(Runtime::kThrowReferenceError); |
2183 | 2174 __ bind(&assign); |
2184 } else if (var->mode() == CONST && op != Token::INIT) { | 2175 } |
2185 // Assignment to const variable needs a write barrier. | 2176 if (var->mode() == CONST) { |
2186 DCHECK(!var->IsLookupSlot()); | 2177 __ CallRuntime(Runtime::kThrowConstAssignError); |
2187 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 2178 } else { |
2188 Label const_error; | 2179 EmitStoreToStackLocalOrContextSlot(var, location); |
2189 MemOperand location = VarOperand(var, r1); | 2180 } |
2190 __ ldr(r3, location); | |
2191 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); | |
2192 __ b(ne, &const_error); | |
2193 __ mov(r3, Operand(var->name())); | |
2194 __ push(r3); | |
2195 __ CallRuntime(Runtime::kThrowReferenceError); | |
2196 __ bind(&const_error); | |
2197 __ CallRuntime(Runtime::kThrowConstAssignError); | |
2198 | |
2199 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { | 2181 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { |
2200 // Initializing assignment to const {this} needs a write barrier. | 2182 // Initializing assignment to const {this} needs a write barrier. |
2201 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 2183 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
2202 Label uninitialized_this; | 2184 Label uninitialized_this; |
2203 MemOperand location = VarOperand(var, r1); | 2185 MemOperand location = VarOperand(var, r1); |
2204 __ ldr(r3, location); | 2186 __ ldr(r3, location); |
2205 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); | 2187 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); |
2206 __ b(eq, &uninitialized_this); | 2188 __ b(eq, &uninitialized_this); |
2207 __ mov(r0, Operand(var->name())); | 2189 __ mov(r0, Operand(var->name())); |
2208 __ Push(r0); | 2190 __ Push(r0); |
(...skipping 1631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3840 DCHECK(interrupt_address == | 3822 DCHECK(interrupt_address == |
3841 isolate->builtins()->OnStackReplacement()->entry()); | 3823 isolate->builtins()->OnStackReplacement()->entry()); |
3842 return ON_STACK_REPLACEMENT; | 3824 return ON_STACK_REPLACEMENT; |
3843 } | 3825 } |
3844 | 3826 |
3845 | 3827 |
3846 } // namespace internal | 3828 } // namespace internal |
3847 } // namespace v8 | 3829 } // namespace v8 |
3848 | 3830 |
3849 #endif // V8_TARGET_ARCH_ARM | 3831 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |