OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 #ifdef DEBUG | 141 #ifdef DEBUG |
142 if (strlen(FLAG_stop_at) > 0 && | 142 if (strlen(FLAG_stop_at) > 0 && |
143 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 143 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
144 __ Debug("stop-at", __LINE__, BREAK); | 144 __ Debug("stop-at", __LINE__, BREAK); |
145 } | 145 } |
146 #endif | 146 #endif |
147 | 147 |
148 // Sloppy mode functions and builtins need to replace the receiver with the | 148 // Sloppy mode functions and builtins need to replace the receiver with the |
149 // global proxy when called as functions (without an explicit receiver | 149 // global proxy when called as functions (without an explicit receiver |
150 // object). | 150 // object). |
151 if (info->is_sloppy_mode() && !info->is_native()) { | 151 if (info->strict_mode() == SLOPPY && !info->is_native()) { |
152 Label ok; | 152 Label ok; |
153 int receiver_offset = info->scope()->num_parameters() * kXRegSizeInBytes; | 153 int receiver_offset = info->scope()->num_parameters() * kXRegSizeInBytes; |
154 __ Peek(x10, receiver_offset); | 154 __ Peek(x10, receiver_offset); |
155 __ JumpIfNotRoot(x10, Heap::kUndefinedValueRootIndex, &ok); | 155 __ JumpIfNotRoot(x10, Heap::kUndefinedValueRootIndex, &ok); |
156 | 156 |
157 __ Ldr(x10, GlobalObjectMemOperand()); | 157 __ Ldr(x10, GlobalObjectMemOperand()); |
158 __ Ldr(x10, FieldMemOperand(x10, GlobalObject::kGlobalReceiverOffset)); | 158 __ Ldr(x10, FieldMemOperand(x10, GlobalObject::kGlobalReceiverOffset)); |
159 __ Poke(x10, receiver_offset); | 159 __ Poke(x10, receiver_offset); |
160 | 160 |
161 __ Bind(&ok); | 161 __ Bind(&ok); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 int offset = num_parameters * kPointerSize; | 244 int offset = num_parameters * kPointerSize; |
245 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset + offset); | 245 __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset + offset); |
246 __ Mov(x1, Operand(Smi::FromInt(num_parameters))); | 246 __ Mov(x1, Operand(Smi::FromInt(num_parameters))); |
247 __ Push(x3, x2, x1); | 247 __ Push(x3, x2, x1); |
248 | 248 |
249 // Arguments to ArgumentsAccessStub: | 249 // Arguments to ArgumentsAccessStub: |
250 // function, receiver address, parameter count. | 250 // function, receiver address, parameter count. |
251 // The stub will rewrite receiver and parameter count if the previous | 251 // The stub will rewrite receiver and parameter count if the previous |
252 // stack frame was an arguments adapter frame. | 252 // stack frame was an arguments adapter frame. |
253 ArgumentsAccessStub::Type type; | 253 ArgumentsAccessStub::Type type; |
254 if (!is_sloppy_mode()) { | 254 if (strict_mode() == STRICT) { |
255 type = ArgumentsAccessStub::NEW_STRICT; | 255 type = ArgumentsAccessStub::NEW_STRICT; |
256 } else if (function()->has_duplicate_parameters()) { | 256 } else if (function()->has_duplicate_parameters()) { |
257 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW; | 257 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW; |
258 } else { | 258 } else { |
259 type = ArgumentsAccessStub::NEW_SLOPPY_FAST; | 259 type = ArgumentsAccessStub::NEW_SLOPPY_FAST; |
260 } | 260 } |
261 ArgumentsAccessStub stub(type); | 261 ArgumentsAccessStub stub(type); |
262 __ CallStub(&stub); | 262 __ CallStub(&stub); |
263 | 263 |
264 SetVar(arguments, x0, x1, x2); | 264 SetVar(arguments, x0, x1, x2); |
265 } | 265 } |
266 | 266 |
267 if (FLAG_trace) { | 267 if (FLAG_trace) { |
268 __ CallRuntime(Runtime::kTraceEnter, 0); | 268 __ CallRuntime(Runtime::kTraceEnter, 0); |
269 } | 269 } |
270 | 270 |
271 | 271 |
272 // Visit the declarations and body unless there is an illegal | 272 // Visit the declarations and body unless there is an illegal |
273 // redeclaration. | 273 // redeclaration. |
274 if (scope()->HasIllegalRedeclaration()) { | 274 if (scope()->HasIllegalRedeclaration()) { |
275 Comment cmnt(masm_, "[ Declarations"); | 275 Comment cmnt(masm_, "[ Declarations"); |
276 scope()->VisitIllegalRedeclaration(this); | 276 scope()->VisitIllegalRedeclaration(this); |
277 | 277 |
278 } else { | 278 } else { |
279 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); | 279 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); |
280 { Comment cmnt(masm_, "[ Declarations"); | 280 { Comment cmnt(masm_, "[ Declarations"); |
281 if (scope()->is_function_scope() && scope()->function() != NULL) { | 281 if (scope()->is_function_scope() && scope()->function() != NULL) { |
282 VariableDeclaration* function = scope()->function(); | 282 VariableDeclaration* function = scope()->function(); |
283 ASSERT(function->proxy()->var()->mode() == CONST || | 283 ASSERT(function->proxy()->var()->mode() == CONST || |
284 function->proxy()->var()->mode() == CONST_HARMONY); | 284 function->proxy()->var()->mode() == CONST_LEGACY); |
285 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); | 285 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); |
286 VisitVariableDeclaration(function); | 286 VisitVariableDeclaration(function); |
287 } | 287 } |
288 VisitDeclarations(scope()->declarations()); | 288 VisitDeclarations(scope()->declarations()); |
289 } | 289 } |
290 } | 290 } |
291 | 291 |
292 { Comment cmnt(masm_, "[ Stack check"); | 292 { Comment cmnt(masm_, "[ Stack check"); |
293 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); | 293 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); |
294 Label ok; | 294 Label ok; |
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
785 | 785 |
786 | 786 |
787 void FullCodeGenerator::VisitVariableDeclaration( | 787 void FullCodeGenerator::VisitVariableDeclaration( |
788 VariableDeclaration* declaration) { | 788 VariableDeclaration* declaration) { |
789 // If it was not possible to allocate the variable at compile time, we | 789 // If it was not possible to allocate the variable at compile time, we |
790 // need to "declare" it at runtime to make sure it actually exists in the | 790 // need to "declare" it at runtime to make sure it actually exists in the |
791 // local context. | 791 // local context. |
792 VariableProxy* proxy = declaration->proxy(); | 792 VariableProxy* proxy = declaration->proxy(); |
793 VariableMode mode = declaration->mode(); | 793 VariableMode mode = declaration->mode(); |
794 Variable* variable = proxy->var(); | 794 Variable* variable = proxy->var(); |
795 bool hole_init = (mode == CONST) || (mode == CONST_HARMONY) || (mode == LET); | 795 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY; |
796 | 796 |
797 switch (variable->location()) { | 797 switch (variable->location()) { |
798 case Variable::UNALLOCATED: | 798 case Variable::UNALLOCATED: |
799 globals_->Add(variable->name(), zone()); | 799 globals_->Add(variable->name(), zone()); |
800 globals_->Add(variable->binding_needs_init() | 800 globals_->Add(variable->binding_needs_init() |
801 ? isolate()->factory()->the_hole_value() | 801 ? isolate()->factory()->the_hole_value() |
802 : isolate()->factory()->undefined_value(), | 802 : isolate()->factory()->undefined_value(), |
803 zone()); | 803 zone()); |
804 break; | 804 break; |
805 | 805 |
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1319 // nested functions that don't need literals cloning. If we're running with | 1319 // nested functions that don't need literals cloning. If we're running with |
1320 // the --always-opt or the --prepare-always-opt flag, we need to use the | 1320 // the --always-opt or the --prepare-always-opt flag, we need to use the |
1321 // runtime function so that the new function we are creating here gets a | 1321 // runtime function so that the new function we are creating here gets a |
1322 // chance to have its code optimized and doesn't just get a copy of the | 1322 // chance to have its code optimized and doesn't just get a copy of the |
1323 // existing unoptimized code. | 1323 // existing unoptimized code. |
1324 if (!FLAG_always_opt && | 1324 if (!FLAG_always_opt && |
1325 !FLAG_prepare_always_opt && | 1325 !FLAG_prepare_always_opt && |
1326 !pretenure && | 1326 !pretenure && |
1327 scope()->is_function_scope() && | 1327 scope()->is_function_scope() && |
1328 info->num_literals() == 0) { | 1328 info->num_literals() == 0) { |
1329 FastNewClosureStub stub(info->language_mode(), info->is_generator()); | 1329 FastNewClosureStub stub(info->strict_mode(), info->is_generator()); |
1330 __ Mov(x2, Operand(info)); | 1330 __ Mov(x2, Operand(info)); |
1331 __ CallStub(&stub); | 1331 __ CallStub(&stub); |
1332 } else { | 1332 } else { |
1333 __ Mov(x11, Operand(info)); | 1333 __ Mov(x11, Operand(info)); |
1334 __ LoadRoot(x10, pretenure ? Heap::kTrueValueRootIndex | 1334 __ LoadRoot(x10, pretenure ? Heap::kTrueValueRootIndex |
1335 : Heap::kFalseValueRootIndex); | 1335 : Heap::kFalseValueRootIndex); |
1336 __ Push(cp, x11, x10); | 1336 __ Push(cp, x11, x10); |
1337 __ CallRuntime(Runtime::kNewClosure, 3); | 1337 __ CallRuntime(Runtime::kNewClosure, 3); |
1338 } | 1338 } |
1339 context()->Plug(x0); | 1339 context()->Plug(x0); |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1435 // eval-introduced variables. Eval is used a lot without | 1435 // eval-introduced variables. Eval is used a lot without |
1436 // introducing variables. In those cases, we do not want to | 1436 // introducing variables. In those cases, we do not want to |
1437 // perform a runtime call for all variables in the scope | 1437 // perform a runtime call for all variables in the scope |
1438 // containing the eval. | 1438 // containing the eval. |
1439 if (var->mode() == DYNAMIC_GLOBAL) { | 1439 if (var->mode() == DYNAMIC_GLOBAL) { |
1440 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1440 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
1441 __ B(done); | 1441 __ B(done); |
1442 } else if (var->mode() == DYNAMIC_LOCAL) { | 1442 } else if (var->mode() == DYNAMIC_LOCAL) { |
1443 Variable* local = var->local_if_not_shadowed(); | 1443 Variable* local = var->local_if_not_shadowed(); |
1444 __ Ldr(x0, ContextSlotOperandCheckExtensions(local, slow)); | 1444 __ Ldr(x0, ContextSlotOperandCheckExtensions(local, slow)); |
1445 if (local->mode() == LET || | 1445 if (local->mode() == LET || local->mode() == CONST || |
1446 local->mode() == CONST || | 1446 local->mode() == CONST_LEGACY) { |
1447 local->mode() == CONST_HARMONY) { | |
1448 __ JumpIfNotRoot(x0, Heap::kTheHoleValueRootIndex, done); | 1447 __ JumpIfNotRoot(x0, Heap::kTheHoleValueRootIndex, done); |
1449 if (local->mode() == CONST) { | 1448 if (local->mode() == CONST_LEGACY) { |
1450 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); | 1449 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); |
1451 } else { // LET || CONST_HARMONY | 1450 } else { // LET || CONST |
1452 __ Mov(x0, Operand(var->name())); | 1451 __ Mov(x0, Operand(var->name())); |
1453 __ Push(x0); | 1452 __ Push(x0); |
1454 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1453 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1455 } | 1454 } |
1456 } | 1455 } |
1457 __ B(done); | 1456 __ B(done); |
1458 } | 1457 } |
1459 } | 1458 } |
1460 | 1459 |
1461 | 1460 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1508 // binding is initialized: | 1507 // binding is initialized: |
1509 // function() { f(); let x = 1; function f() { x = 2; } } | 1508 // function() { f(); let x = 1; function f() { x = 2; } } |
1510 // | 1509 // |
1511 bool skip_init_check; | 1510 bool skip_init_check; |
1512 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) { | 1511 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) { |
1513 skip_init_check = false; | 1512 skip_init_check = false; |
1514 } else { | 1513 } else { |
1515 // Check that we always have valid source position. | 1514 // Check that we always have valid source position. |
1516 ASSERT(var->initializer_position() != RelocInfo::kNoPosition); | 1515 ASSERT(var->initializer_position() != RelocInfo::kNoPosition); |
1517 ASSERT(proxy->position() != RelocInfo::kNoPosition); | 1516 ASSERT(proxy->position() != RelocInfo::kNoPosition); |
1518 skip_init_check = var->mode() != CONST && | 1517 skip_init_check = var->mode() != CONST_LEGACY && |
1519 var->initializer_position() < proxy->position(); | 1518 var->initializer_position() < proxy->position(); |
1520 } | 1519 } |
1521 | 1520 |
1522 if (!skip_init_check) { | 1521 if (!skip_init_check) { |
1523 // Let and const need a read barrier. | 1522 // Let and const need a read barrier. |
1524 GetVar(x0, var); | 1523 GetVar(x0, var); |
1525 Label done; | 1524 Label done; |
1526 __ JumpIfNotRoot(x0, Heap::kTheHoleValueRootIndex, &done); | 1525 __ JumpIfNotRoot(x0, Heap::kTheHoleValueRootIndex, &done); |
1527 if (var->mode() == LET || var->mode() == CONST_HARMONY) { | 1526 if (var->mode() == LET || var->mode() == CONST) { |
1528 // Throw a reference error when using an uninitialized let/const | 1527 // Throw a reference error when using an uninitialized let/const |
1529 // binding in harmony mode. | 1528 // binding in harmony mode. |
1530 __ Mov(x0, Operand(var->name())); | 1529 __ Mov(x0, Operand(var->name())); |
1531 __ Push(x0); | 1530 __ Push(x0); |
1532 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1531 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1533 __ Bind(&done); | 1532 __ Bind(&done); |
1534 } else { | 1533 } else { |
1535 // Uninitalized const bindings outside of harmony mode are unholed. | 1534 // Uninitalized const bindings outside of harmony mode are unholed. |
1536 ASSERT(var->mode() == CONST); | 1535 ASSERT(var->mode() == CONST_LEGACY); |
1537 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); | 1536 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); |
1538 __ Bind(&done); | 1537 __ Bind(&done); |
1539 } | 1538 } |
1540 context()->Plug(x0); | 1539 context()->Plug(x0); |
1541 break; | 1540 break; |
1542 } | 1541 } |
1543 } | 1542 } |
1544 context()->Plug(var); | 1543 context()->Plug(var); |
1545 break; | 1544 break; |
1546 } | 1545 } |
(...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2137 __ Mov(x2, Operand(prop->key()->AsLiteral()->value())); | 2136 __ Mov(x2, Operand(prop->key()->AsLiteral()->value())); |
2138 CallStoreIC(); | 2137 CallStoreIC(); |
2139 break; | 2138 break; |
2140 } | 2139 } |
2141 case KEYED_PROPERTY: { | 2140 case KEYED_PROPERTY: { |
2142 __ Push(x0); // Preserve value. | 2141 __ Push(x0); // Preserve value. |
2143 VisitForStackValue(prop->obj()); | 2142 VisitForStackValue(prop->obj()); |
2144 VisitForAccumulatorValue(prop->key()); | 2143 VisitForAccumulatorValue(prop->key()); |
2145 __ Mov(x1, x0); | 2144 __ Mov(x1, x0); |
2146 __ Pop(x2, x0); | 2145 __ Pop(x2, x0); |
2147 Handle<Code> ic = is_sloppy_mode() | 2146 Handle<Code> ic = strict_mode() == SLOPPY |
2148 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2147 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
2149 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2148 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
2150 CallIC(ic); | 2149 CallIC(ic); |
2151 break; | 2150 break; |
2152 } | 2151 } |
2153 } | 2152 } |
2154 context()->Plug(x0); | 2153 context()->Plug(x0); |
2155 } | 2154 } |
2156 | 2155 |
2157 | 2156 |
2158 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( | 2157 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( |
2159 Variable* var, MemOperand location) { | 2158 Variable* var, MemOperand location) { |
2160 __ Str(result_register(), location); | 2159 __ Str(result_register(), location); |
2161 if (var->IsContextSlot()) { | 2160 if (var->IsContextSlot()) { |
2162 // RecordWrite may destroy all its register arguments. | 2161 // RecordWrite may destroy all its register arguments. |
2163 __ Mov(x10, result_register()); | 2162 __ Mov(x10, result_register()); |
2164 int offset = Context::SlotOffset(var->index()); | 2163 int offset = Context::SlotOffset(var->index()); |
2165 __ RecordWriteContextSlot( | 2164 __ RecordWriteContextSlot( |
2166 x1, offset, x10, x11, kLRHasBeenSaved, kDontSaveFPRegs); | 2165 x1, offset, x10, x11, kLRHasBeenSaved, kDontSaveFPRegs); |
2167 } | 2166 } |
2168 } | 2167 } |
2169 | 2168 |
2170 | 2169 |
2171 void FullCodeGenerator::EmitCallStoreContextSlot( | 2170 void FullCodeGenerator::EmitCallStoreContextSlot( |
2172 Handle<String> name, LanguageMode mode) { | 2171 Handle<String> name, StrictMode strict_mode) { |
2173 __ Mov(x11, Operand(name)); | 2172 __ Mov(x11, Operand(name)); |
2174 __ Mov(x10, Operand(Smi::FromInt(mode))); | 2173 __ Mov(x10, Operand(Smi::FromInt(strict_mode))); |
2175 // jssp[0] : mode. | 2174 // jssp[0] : mode. |
2176 // jssp[8] : name. | 2175 // jssp[8] : name. |
2177 // jssp[16] : context. | 2176 // jssp[16] : context. |
2178 // jssp[24] : value. | 2177 // jssp[24] : value. |
2179 __ Push(x0, cp, x11, x10); | 2178 __ Push(x0, cp, x11, x10); |
2180 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 2179 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
2181 } | 2180 } |
2182 | 2181 |
2183 | 2182 |
2184 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 2183 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
2185 Token::Value op) { | 2184 Token::Value op) { |
2186 ASM_LOCATION("FullCodeGenerator::EmitVariableAssignment"); | 2185 ASM_LOCATION("FullCodeGenerator::EmitVariableAssignment"); |
2187 if (var->IsUnallocated()) { | 2186 if (var->IsUnallocated()) { |
2188 // Global var, const, or let. | 2187 // Global var, const, or let. |
2189 __ Mov(x2, Operand(var->name())); | 2188 __ Mov(x2, Operand(var->name())); |
2190 __ Ldr(x1, GlobalObjectMemOperand()); | 2189 __ Ldr(x1, GlobalObjectMemOperand()); |
2191 CallStoreIC(); | 2190 CallStoreIC(); |
2192 | 2191 |
2193 } else if (op == Token::INIT_CONST) { | 2192 } else if (op == Token::INIT_CONST_LEGACY) { |
2194 // Const initializers need a write barrier. | 2193 // Const initializers need a write barrier. |
2195 ASSERT(!var->IsParameter()); // No const parameters. | 2194 ASSERT(!var->IsParameter()); // No const parameters. |
2196 if (var->IsLookupSlot()) { | 2195 if (var->IsLookupSlot()) { |
2197 __ Push(x0); | 2196 __ Push(x0); |
2198 __ Mov(x0, Operand(var->name())); | 2197 __ Mov(x0, Operand(var->name())); |
2199 __ Push(cp, x0); // Context and name. | 2198 __ Push(cp, x0); // Context and name. |
2200 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 2199 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
2201 } else { | 2200 } else { |
2202 ASSERT(var->IsStackLocal() || var->IsContextSlot()); | 2201 ASSERT(var->IsStackLocal() || var->IsContextSlot()); |
2203 Label skip; | 2202 Label skip; |
2204 MemOperand location = VarOperand(var, x1); | 2203 MemOperand location = VarOperand(var, x1); |
2205 __ Ldr(x10, location); | 2204 __ Ldr(x10, location); |
2206 __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &skip); | 2205 __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &skip); |
2207 EmitStoreToStackLocalOrContextSlot(var, location); | 2206 EmitStoreToStackLocalOrContextSlot(var, location); |
2208 __ Bind(&skip); | 2207 __ Bind(&skip); |
2209 } | 2208 } |
2210 | 2209 |
2211 } else if (var->mode() == LET && op != Token::INIT_LET) { | 2210 } else if (var->mode() == LET && op != Token::INIT_LET) { |
2212 // Non-initializing assignment to let variable needs a write barrier. | 2211 // Non-initializing assignment to let variable needs a write barrier. |
2213 if (var->IsLookupSlot()) { | 2212 if (var->IsLookupSlot()) { |
2214 EmitCallStoreContextSlot(var->name(), language_mode()); | 2213 EmitCallStoreContextSlot(var->name(), strict_mode()); |
2215 } else { | 2214 } else { |
2216 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2215 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
2217 Label assign; | 2216 Label assign; |
2218 MemOperand location = VarOperand(var, x1); | 2217 MemOperand location = VarOperand(var, x1); |
2219 __ Ldr(x10, location); | 2218 __ Ldr(x10, location); |
2220 __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &assign); | 2219 __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &assign); |
2221 __ Mov(x10, Operand(var->name())); | 2220 __ Mov(x10, Operand(var->name())); |
2222 __ Push(x10); | 2221 __ Push(x10); |
2223 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 2222 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
2224 // Perform the assignment. | 2223 // Perform the assignment. |
2225 __ Bind(&assign); | 2224 __ Bind(&assign); |
2226 EmitStoreToStackLocalOrContextSlot(var, location); | 2225 EmitStoreToStackLocalOrContextSlot(var, location); |
2227 } | 2226 } |
2228 | 2227 |
2229 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { | 2228 } else if (!var->is_const_mode() || op == Token::INIT_CONST) { |
2230 // Assignment to var or initializing assignment to let/const | 2229 // Assignment to var or initializing assignment to let/const |
2231 // in harmony mode. | 2230 // in harmony mode. |
2232 if (var->IsLookupSlot()) { | 2231 if (var->IsLookupSlot()) { |
2233 EmitCallStoreContextSlot(var->name(), language_mode()); | 2232 EmitCallStoreContextSlot(var->name(), strict_mode()); |
2234 } else { | 2233 } else { |
2235 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2234 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
2236 MemOperand location = VarOperand(var, x1); | 2235 MemOperand location = VarOperand(var, x1); |
2237 if (FLAG_debug_code && op == Token::INIT_LET) { | 2236 if (FLAG_debug_code && op == Token::INIT_LET) { |
2238 __ Ldr(x10, location); | 2237 __ Ldr(x10, location); |
2239 __ CompareRoot(x10, Heap::kTheHoleValueRootIndex); | 2238 __ CompareRoot(x10, Heap::kTheHoleValueRootIndex); |
2240 __ Check(eq, kLetBindingReInitialization); | 2239 __ Check(eq, kLetBindingReInitialization); |
2241 } | 2240 } |
2242 EmitStoreToStackLocalOrContextSlot(var, location); | 2241 EmitStoreToStackLocalOrContextSlot(var, location); |
2243 } | 2242 } |
(...skipping 23 matching lines...) Expand all Loading... |
2267 | 2266 |
2268 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2267 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
2269 ASM_LOCATION("FullCodeGenerator::EmitKeyedPropertyAssignment"); | 2268 ASM_LOCATION("FullCodeGenerator::EmitKeyedPropertyAssignment"); |
2270 // Assignment to a property, using a keyed store IC. | 2269 // Assignment to a property, using a keyed store IC. |
2271 | 2270 |
2272 // Record source code position before IC call. | 2271 // Record source code position before IC call. |
2273 SetSourcePosition(expr->position()); | 2272 SetSourcePosition(expr->position()); |
2274 // TODO(all): Could we pass this in registers rather than on the stack? | 2273 // TODO(all): Could we pass this in registers rather than on the stack? |
2275 __ Pop(x1, x2); // Key and object holding the property. | 2274 __ Pop(x1, x2); // Key and object holding the property. |
2276 | 2275 |
2277 Handle<Code> ic = is_sloppy_mode() | 2276 Handle<Code> ic = strict_mode() == SLOPPY |
2278 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2277 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
2279 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2278 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
2280 CallIC(ic, expr->AssignmentFeedbackId()); | 2279 CallIC(ic, expr->AssignmentFeedbackId()); |
2281 | 2280 |
2282 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2281 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
2283 context()->Plug(x0); | 2282 context()->Plug(x0); |
2284 } | 2283 } |
2285 | 2284 |
2286 | 2285 |
2287 void FullCodeGenerator::VisitProperty(Property* expr) { | 2286 void FullCodeGenerator::VisitProperty(Property* expr) { |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2445 } | 2444 } |
2446 | 2445 |
2447 // Prepare to push the receiver of the enclosing function. | 2446 // Prepare to push the receiver of the enclosing function. |
2448 int receiver_offset = 2 + info_->scope()->num_parameters(); | 2447 int receiver_offset = 2 + info_->scope()->num_parameters(); |
2449 __ Ldr(x11, MemOperand(fp, receiver_offset * kPointerSize)); | 2448 __ Ldr(x11, MemOperand(fp, receiver_offset * kPointerSize)); |
2450 | 2449 |
2451 // Push. | 2450 // Push. |
2452 __ Push(x10, x11); | 2451 __ Push(x10, x11); |
2453 | 2452 |
2454 // Prepare to push the language mode. | 2453 // Prepare to push the language mode. |
2455 __ Mov(x10, Operand(Smi::FromInt(language_mode()))); | 2454 __ Mov(x10, Operand(Smi::FromInt(strict_mode()))); |
2456 // Prepare to push the start position of the scope the calls resides in. | 2455 // Prepare to push the start position of the scope the calls resides in. |
2457 __ Mov(x11, Operand(Smi::FromInt(scope()->start_position()))); | 2456 __ Mov(x11, Operand(Smi::FromInt(scope()->start_position()))); |
2458 | 2457 |
2459 // Push. | 2458 // Push. |
2460 __ Push(x10, x11); | 2459 __ Push(x10, x11); |
2461 | 2460 |
2462 // Do the runtime call. | 2461 // Do the runtime call. |
2463 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); | 2462 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); |
2464 } | 2463 } |
2465 | 2464 |
(...skipping 1419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3885 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3884 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
3886 switch (expr->op()) { | 3885 switch (expr->op()) { |
3887 case Token::DELETE: { | 3886 case Token::DELETE: { |
3888 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3887 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
3889 Property* property = expr->expression()->AsProperty(); | 3888 Property* property = expr->expression()->AsProperty(); |
3890 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 3889 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
3891 | 3890 |
3892 if (property != NULL) { | 3891 if (property != NULL) { |
3893 VisitForStackValue(property->obj()); | 3892 VisitForStackValue(property->obj()); |
3894 VisitForStackValue(property->key()); | 3893 VisitForStackValue(property->key()); |
3895 StrictModeFlag strict_mode_flag = (language_mode() == SLOPPY_MODE) | 3894 __ Mov(x10, Operand(Smi::FromInt(strict_mode()))); |
3896 ? kSloppyMode : kStrictMode; | |
3897 __ Mov(x10, Operand(Smi::FromInt(strict_mode_flag))); | |
3898 __ Push(x10); | 3895 __ Push(x10); |
3899 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3896 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
3900 context()->Plug(x0); | 3897 context()->Plug(x0); |
3901 } else if (proxy != NULL) { | 3898 } else if (proxy != NULL) { |
3902 Variable* var = proxy->var(); | 3899 Variable* var = proxy->var(); |
3903 // Delete of an unqualified identifier is disallowed in strict mode | 3900 // Delete of an unqualified identifier is disallowed in strict mode |
3904 // but "delete this" is allowed. | 3901 // but "delete this" is allowed. |
3905 ASSERT(language_mode() == SLOPPY_MODE || var->is_this()); | 3902 ASSERT(strict_mode() == SLOPPY || var->is_this()); |
3906 if (var->IsUnallocated()) { | 3903 if (var->IsUnallocated()) { |
3907 __ Ldr(x12, GlobalObjectMemOperand()); | 3904 __ Ldr(x12, GlobalObjectMemOperand()); |
3908 __ Mov(x11, Operand(var->name())); | 3905 __ Mov(x11, Operand(var->name())); |
3909 __ Mov(x10, Operand(Smi::FromInt(kSloppyMode))); | 3906 __ Mov(x10, Operand(Smi::FromInt(SLOPPY))); |
3910 __ Push(x12, x11, x10); | 3907 __ Push(x12, x11, x10); |
3911 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3908 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
3912 context()->Plug(x0); | 3909 context()->Plug(x0); |
3913 } else if (var->IsStackAllocated() || var->IsContextSlot()) { | 3910 } else if (var->IsStackAllocated() || var->IsContextSlot()) { |
3914 // Result of deleting non-global, non-dynamic variables is false. | 3911 // Result of deleting non-global, non-dynamic variables is false. |
3915 // The subexpression does not have side effects. | 3912 // The subexpression does not have side effects. |
3916 context()->Plug(var->is_this()); | 3913 context()->Plug(var->is_this()); |
3917 } else { | 3914 } else { |
3918 // Non-global variable. Call the runtime to try to delete from the | 3915 // Non-global variable. Call the runtime to try to delete from the |
3919 // context where the variable was introduced. | 3916 // context where the variable was introduced. |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4156 context()->PlugTOS(); | 4153 context()->PlugTOS(); |
4157 } | 4154 } |
4158 } else { | 4155 } else { |
4159 context()->Plug(x0); | 4156 context()->Plug(x0); |
4160 } | 4157 } |
4161 break; | 4158 break; |
4162 } | 4159 } |
4163 case KEYED_PROPERTY: { | 4160 case KEYED_PROPERTY: { |
4164 __ Pop(x1); // Key. | 4161 __ Pop(x1); // Key. |
4165 __ Pop(x2); // Receiver. | 4162 __ Pop(x2); // Receiver. |
4166 Handle<Code> ic = is_sloppy_mode() | 4163 Handle<Code> ic = strict_mode() == SLOPPY |
4167 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4164 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
4168 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4165 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
4169 CallIC(ic, expr->CountStoreFeedbackId()); | 4166 CallIC(ic, expr->CountStoreFeedbackId()); |
4170 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4167 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
4171 if (expr->is_postfix()) { | 4168 if (expr->is_postfix()) { |
4172 if (!context()->IsEffect()) { | 4169 if (!context()->IsEffect()) { |
4173 context()->PlugTOS(); | 4170 context()->PlugTOS(); |
4174 } | 4171 } |
4175 } else { | 4172 } else { |
4176 context()->Plug(x0); | 4173 context()->Plug(x0); |
(...skipping 807 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4984 return previous_; | 4981 return previous_; |
4985 } | 4982 } |
4986 | 4983 |
4987 | 4984 |
4988 #undef __ | 4985 #undef __ |
4989 | 4986 |
4990 | 4987 |
4991 } } // namespace v8::internal | 4988 } } // namespace v8::internal |
4992 | 4989 |
4993 #endif // V8_TARGET_ARCH_A64 | 4990 #endif // V8_TARGET_ARCH_A64 |
OLD | NEW |