OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 #ifdef DEBUG | 143 #ifdef DEBUG |
144 if (strlen(FLAG_stop_at) > 0 && | 144 if (strlen(FLAG_stop_at) > 0 && |
145 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 145 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
146 __ stop("stop-at"); | 146 __ stop("stop-at"); |
147 } | 147 } |
148 #endif | 148 #endif |
149 | 149 |
150 // Sloppy mode functions and builtins need to replace the receiver with the | 150 // Sloppy mode functions and builtins need to replace the receiver with the |
151 // global proxy when called as functions (without an explicit receiver | 151 // global proxy when called as functions (without an explicit receiver |
152 // object). | 152 // object). |
153 if (info->is_sloppy_mode() && !info->is_native()) { | 153 if (info->strict_mode() == SLOPPY && !info->is_native()) { |
154 Label ok; | 154 Label ok; |
155 int receiver_offset = info->scope()->num_parameters() * kPointerSize; | 155 int receiver_offset = info->scope()->num_parameters() * kPointerSize; |
156 __ ldr(r2, MemOperand(sp, receiver_offset)); | 156 __ ldr(r2, MemOperand(sp, receiver_offset)); |
157 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex); | 157 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex); |
158 __ b(ne, &ok); | 158 __ b(ne, &ok); |
159 | 159 |
160 __ ldr(r2, GlobalObjectOperand()); | 160 __ ldr(r2, GlobalObjectOperand()); |
161 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); | 161 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); |
162 | 162 |
163 __ str(r2, MemOperand(sp, receiver_offset)); | 163 __ str(r2, MemOperand(sp, receiver_offset)); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 __ add(r2, fp, | 257 __ add(r2, fp, |
258 Operand(StandardFrameConstants::kCallerSPOffset + offset)); | 258 Operand(StandardFrameConstants::kCallerSPOffset + offset)); |
259 __ mov(r1, Operand(Smi::FromInt(num_parameters))); | 259 __ mov(r1, Operand(Smi::FromInt(num_parameters))); |
260 __ Push(r3, r2, r1); | 260 __ Push(r3, r2, r1); |
261 | 261 |
262 // Arguments to ArgumentsAccessStub: | 262 // Arguments to ArgumentsAccessStub: |
263 // function, receiver address, parameter count. | 263 // function, receiver address, parameter count. |
264 // The stub will rewrite receiever and parameter count if the previous | 264 // The stub will rewrite receiever and parameter count if the previous |
265 // stack frame was an arguments adapter frame. | 265 // stack frame was an arguments adapter frame. |
266 ArgumentsAccessStub::Type type; | 266 ArgumentsAccessStub::Type type; |
267 if (!is_sloppy_mode()) { | 267 if (strict_mode() == STRICT) { |
268 type = ArgumentsAccessStub::NEW_STRICT; | 268 type = ArgumentsAccessStub::NEW_STRICT; |
269 } else if (function()->has_duplicate_parameters()) { | 269 } else if (function()->has_duplicate_parameters()) { |
270 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW; | 270 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW; |
271 } else { | 271 } else { |
272 type = ArgumentsAccessStub::NEW_SLOPPY_FAST; | 272 type = ArgumentsAccessStub::NEW_SLOPPY_FAST; |
273 } | 273 } |
274 ArgumentsAccessStub stub(type); | 274 ArgumentsAccessStub stub(type); |
275 __ CallStub(&stub); | 275 __ CallStub(&stub); |
276 | 276 |
277 SetVar(arguments, r0, r1, r2); | 277 SetVar(arguments, r0, r1, r2); |
(...skipping 10 matching lines...) Expand all Loading... |
288 scope()->VisitIllegalRedeclaration(this); | 288 scope()->VisitIllegalRedeclaration(this); |
289 | 289 |
290 } else { | 290 } else { |
291 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); | 291 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); |
292 { Comment cmnt(masm_, "[ Declarations"); | 292 { Comment cmnt(masm_, "[ Declarations"); |
293 // For named function expressions, declare the function name as a | 293 // For named function expressions, declare the function name as a |
294 // constant. | 294 // constant. |
295 if (scope()->is_function_scope() && scope()->function() != NULL) { | 295 if (scope()->is_function_scope() && scope()->function() != NULL) { |
296 VariableDeclaration* function = scope()->function(); | 296 VariableDeclaration* function = scope()->function(); |
297 ASSERT(function->proxy()->var()->mode() == CONST || | 297 ASSERT(function->proxy()->var()->mode() == CONST || |
298 function->proxy()->var()->mode() == CONST_HARMONY); | 298 function->proxy()->var()->mode() == CONST_LEGACY); |
299 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); | 299 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); |
300 VisitVariableDeclaration(function); | 300 VisitVariableDeclaration(function); |
301 } | 301 } |
302 VisitDeclarations(scope()->declarations()); | 302 VisitDeclarations(scope()->declarations()); |
303 } | 303 } |
304 | 304 |
305 { Comment cmnt(masm_, "[ Stack check"); | 305 { Comment cmnt(masm_, "[ Stack check"); |
306 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); | 306 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); |
307 Label ok; | 307 Label ok; |
308 __ LoadRoot(ip, Heap::kStackLimitRootIndex); | 308 __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
(...skipping 476 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 switch (variable->location()) { | 796 switch (variable->location()) { |
797 case Variable::UNALLOCATED: | 797 case Variable::UNALLOCATED: |
798 globals_->Add(variable->name(), zone()); | 798 globals_->Add(variable->name(), zone()); |
799 globals_->Add(variable->binding_needs_init() | 799 globals_->Add(variable->binding_needs_init() |
800 ? isolate()->factory()->the_hole_value() | 800 ? isolate()->factory()->the_hole_value() |
801 : isolate()->factory()->undefined_value(), | 801 : isolate()->factory()->undefined_value(), |
802 zone()); | 802 zone()); |
803 break; | 803 break; |
804 | 804 |
805 case Variable::PARAMETER: | 805 case Variable::PARAMETER: |
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1324 // space for nested functions that don't need literals cloning. If | 1324 // space for nested functions that don't need literals cloning. If |
1325 // we're running with the --always-opt or the --prepare-always-opt | 1325 // we're running with the --always-opt or the --prepare-always-opt |
1326 // flag, we need to use the runtime function so that the new function | 1326 // flag, we need to use the runtime function so that the new function |
1327 // we are creating here gets a chance to have its code optimized and | 1327 // we are creating here gets a chance to have its code optimized and |
1328 // doesn't just get a copy of the existing unoptimized code. | 1328 // doesn't just get a copy of the existing unoptimized code. |
1329 if (!FLAG_always_opt && | 1329 if (!FLAG_always_opt && |
1330 !FLAG_prepare_always_opt && | 1330 !FLAG_prepare_always_opt && |
1331 !pretenure && | 1331 !pretenure && |
1332 scope()->is_function_scope() && | 1332 scope()->is_function_scope() && |
1333 info->num_literals() == 0) { | 1333 info->num_literals() == 0) { |
1334 FastNewClosureStub stub(info->language_mode(), info->is_generator()); | 1334 FastNewClosureStub stub(info->strict_mode(), info->is_generator()); |
1335 __ mov(r2, Operand(info)); | 1335 __ mov(r2, Operand(info)); |
1336 __ CallStub(&stub); | 1336 __ CallStub(&stub); |
1337 } else { | 1337 } else { |
1338 __ mov(r0, Operand(info)); | 1338 __ mov(r0, Operand(info)); |
1339 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex | 1339 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex |
1340 : Heap::kFalseValueRootIndex); | 1340 : Heap::kFalseValueRootIndex); |
1341 __ Push(cp, r0, r1); | 1341 __ Push(cp, r0, r1); |
1342 __ CallRuntime(Runtime::kNewClosure, 3); | 1342 __ CallRuntime(Runtime::kNewClosure, 3); |
1343 } | 1343 } |
1344 context()->Plug(r0); | 1344 context()->Plug(r0); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1448 // eval-introduced variables. Eval is used a lot without | 1448 // eval-introduced variables. Eval is used a lot without |
1449 // introducing variables. In those cases, we do not want to | 1449 // introducing variables. In those cases, we do not want to |
1450 // perform a runtime call for all variables in the scope | 1450 // perform a runtime call for all variables in the scope |
1451 // containing the eval. | 1451 // containing the eval. |
1452 if (var->mode() == DYNAMIC_GLOBAL) { | 1452 if (var->mode() == DYNAMIC_GLOBAL) { |
1453 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1453 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
1454 __ jmp(done); | 1454 __ jmp(done); |
1455 } else if (var->mode() == DYNAMIC_LOCAL) { | 1455 } else if (var->mode() == DYNAMIC_LOCAL) { |
1456 Variable* local = var->local_if_not_shadowed(); | 1456 Variable* local = var->local_if_not_shadowed(); |
1457 __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow)); | 1457 __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow)); |
1458 if (local->mode() == LET || | 1458 if (local->mode() == LET || local->mode() == CONST || |
1459 local->mode() == CONST || | 1459 local->mode() == CONST_LEGACY) { |
1460 local->mode() == CONST_HARMONY) { | |
1461 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); | 1460 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); |
1462 if (local->mode() == CONST) { | 1461 if (local->mode() == CONST_LEGACY) { |
1463 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | 1462 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
1464 } else { // LET || CONST_HARMONY | 1463 } else { // LET || CONST |
1465 __ b(ne, done); | 1464 __ b(ne, done); |
1466 __ mov(r0, Operand(var->name())); | 1465 __ mov(r0, Operand(var->name())); |
1467 __ push(r0); | 1466 __ push(r0); |
1468 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1467 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1469 } | 1468 } |
1470 } | 1469 } |
1471 __ jmp(done); | 1470 __ jmp(done); |
1472 } | 1471 } |
1473 } | 1472 } |
1474 | 1473 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1521 // binding is initialized: | 1520 // binding is initialized: |
1522 // function() { f(); let x = 1; function f() { x = 2; } } | 1521 // function() { f(); let x = 1; function f() { x = 2; } } |
1523 // | 1522 // |
1524 bool skip_init_check; | 1523 bool skip_init_check; |
1525 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) { | 1524 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) { |
1526 skip_init_check = false; | 1525 skip_init_check = false; |
1527 } else { | 1526 } else { |
1528 // Check that we always have valid source position. | 1527 // Check that we always have valid source position. |
1529 ASSERT(var->initializer_position() != RelocInfo::kNoPosition); | 1528 ASSERT(var->initializer_position() != RelocInfo::kNoPosition); |
1530 ASSERT(proxy->position() != RelocInfo::kNoPosition); | 1529 ASSERT(proxy->position() != RelocInfo::kNoPosition); |
1531 skip_init_check = var->mode() != CONST && | 1530 skip_init_check = var->mode() != CONST_LEGACY && |
1532 var->initializer_position() < proxy->position(); | 1531 var->initializer_position() < proxy->position(); |
1533 } | 1532 } |
1534 | 1533 |
1535 if (!skip_init_check) { | 1534 if (!skip_init_check) { |
1536 // Let and const need a read barrier. | 1535 // Let and const need a read barrier. |
1537 GetVar(r0, var); | 1536 GetVar(r0, var); |
1538 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); | 1537 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); |
1539 if (var->mode() == LET || var->mode() == CONST_HARMONY) { | 1538 if (var->mode() == LET || var->mode() == CONST) { |
1540 // Throw a reference error when using an uninitialized let/const | 1539 // Throw a reference error when using an uninitialized let/const |
1541 // binding in harmony mode. | 1540 // binding in harmony mode. |
1542 Label done; | 1541 Label done; |
1543 __ b(ne, &done); | 1542 __ b(ne, &done); |
1544 __ mov(r0, Operand(var->name())); | 1543 __ mov(r0, Operand(var->name())); |
1545 __ push(r0); | 1544 __ push(r0); |
1546 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1545 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1547 __ bind(&done); | 1546 __ bind(&done); |
1548 } else { | 1547 } else { |
1549 // Uninitalized const bindings outside of harmony mode are unholed. | 1548 // Uninitalized const bindings outside of harmony mode are unholed. |
1550 ASSERT(var->mode() == CONST); | 1549 ASSERT(var->mode() == CONST_LEGACY); |
1551 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | 1550 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
1552 } | 1551 } |
1553 context()->Plug(r0); | 1552 context()->Plug(r0); |
1554 break; | 1553 break; |
1555 } | 1554 } |
1556 } | 1555 } |
1557 context()->Plug(var); | 1556 context()->Plug(var); |
1558 break; | 1557 break; |
1559 } | 1558 } |
1560 | 1559 |
(...skipping 877 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2438 __ mov(r2, Operand(prop->key()->AsLiteral()->value())); | 2437 __ mov(r2, Operand(prop->key()->AsLiteral()->value())); |
2439 CallStoreIC(); | 2438 CallStoreIC(); |
2440 break; | 2439 break; |
2441 } | 2440 } |
2442 case KEYED_PROPERTY: { | 2441 case KEYED_PROPERTY: { |
2443 __ push(r0); // Preserve value. | 2442 __ push(r0); // Preserve value. |
2444 VisitForStackValue(prop->obj()); | 2443 VisitForStackValue(prop->obj()); |
2445 VisitForAccumulatorValue(prop->key()); | 2444 VisitForAccumulatorValue(prop->key()); |
2446 __ mov(r1, r0); | 2445 __ mov(r1, r0); |
2447 __ Pop(r0, r2); // r0 = restored value. | 2446 __ Pop(r0, r2); // r0 = restored value. |
2448 Handle<Code> ic = is_sloppy_mode() | 2447 Handle<Code> ic = strict_mode() == SLOPPY |
2449 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2448 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
2450 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2449 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
2451 CallIC(ic); | 2450 CallIC(ic); |
2452 break; | 2451 break; |
2453 } | 2452 } |
2454 } | 2453 } |
2455 context()->Plug(r0); | 2454 context()->Plug(r0); |
2456 } | 2455 } |
2457 | 2456 |
2458 | 2457 |
2459 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( | 2458 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( |
2460 Variable* var, MemOperand location) { | 2459 Variable* var, MemOperand location) { |
2461 __ str(result_register(), location); | 2460 __ str(result_register(), location); |
2462 if (var->IsContextSlot()) { | 2461 if (var->IsContextSlot()) { |
2463 // RecordWrite may destroy all its register arguments. | 2462 // RecordWrite may destroy all its register arguments. |
2464 __ mov(r3, result_register()); | 2463 __ mov(r3, result_register()); |
2465 int offset = Context::SlotOffset(var->index()); | 2464 int offset = Context::SlotOffset(var->index()); |
2466 __ RecordWriteContextSlot( | 2465 __ RecordWriteContextSlot( |
2467 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); | 2466 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); |
2468 } | 2467 } |
2469 } | 2468 } |
2470 | 2469 |
2471 | 2470 |
2472 void FullCodeGenerator::EmitCallStoreContextSlot( | 2471 void FullCodeGenerator::EmitCallStoreContextSlot( |
2473 Handle<String> name, LanguageMode mode) { | 2472 Handle<String> name, StrictMode strict_mode) { |
2474 __ push(r0); // Value. | 2473 __ push(r0); // Value. |
2475 __ mov(r1, Operand(name)); | 2474 __ mov(r1, Operand(name)); |
2476 __ mov(r0, Operand(Smi::FromInt(mode))); | 2475 __ mov(r0, Operand(Smi::FromInt(strict_mode))); |
2477 __ Push(cp, r1, r0); // Context, name, strict mode. | 2476 __ Push(cp, r1, r0); // Context, name, strict mode. |
2478 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 2477 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
2479 } | 2478 } |
2480 | 2479 |
2481 | 2480 |
2482 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 2481 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) { |
2483 Token::Value op) { | |
2484 if (var->IsUnallocated()) { | 2482 if (var->IsUnallocated()) { |
2485 // Global var, const, or let. | 2483 // Global var, const, or let. |
2486 __ mov(r2, Operand(var->name())); | 2484 __ mov(r2, Operand(var->name())); |
2487 __ ldr(r1, GlobalObjectOperand()); | 2485 __ ldr(r1, GlobalObjectOperand()); |
2488 CallStoreIC(); | 2486 CallStoreIC(); |
2489 | 2487 |
2490 } else if (op == Token::INIT_CONST) { | 2488 } else if (op == Token::INIT_CONST_LEGACY) { |
2491 // Const initializers need a write barrier. | 2489 // Const initializers need a write barrier. |
2492 ASSERT(!var->IsParameter()); // No const parameters. | 2490 ASSERT(!var->IsParameter()); // No const parameters. |
2493 if (var->IsLookupSlot()) { | 2491 if (var->IsLookupSlot()) { |
2494 __ push(r0); | 2492 __ push(r0); |
2495 __ mov(r0, Operand(var->name())); | 2493 __ mov(r0, Operand(var->name())); |
2496 __ Push(cp, r0); // Context and name. | 2494 __ Push(cp, r0); // Context and name. |
2497 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 2495 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
2498 } else { | 2496 } else { |
2499 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2497 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
2500 Label skip; | 2498 Label skip; |
2501 MemOperand location = VarOperand(var, r1); | 2499 MemOperand location = VarOperand(var, r1); |
2502 __ ldr(r2, location); | 2500 __ ldr(r2, location); |
2503 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); | 2501 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); |
2504 __ b(ne, &skip); | 2502 __ b(ne, &skip); |
2505 EmitStoreToStackLocalOrContextSlot(var, location); | 2503 EmitStoreToStackLocalOrContextSlot(var, location); |
2506 __ bind(&skip); | 2504 __ bind(&skip); |
2507 } | 2505 } |
2508 | 2506 |
2509 } else if (var->mode() == LET && op != Token::INIT_LET) { | 2507 } else if (var->mode() == LET && op != Token::INIT_LET) { |
2510 // Non-initializing assignment to let variable needs a write barrier. | 2508 // Non-initializing assignment to let variable needs a write barrier. |
2511 if (var->IsLookupSlot()) { | 2509 if (var->IsLookupSlot()) { |
2512 EmitCallStoreContextSlot(var->name(), language_mode()); | 2510 EmitCallStoreContextSlot(var->name(), strict_mode()); |
2513 } else { | 2511 } else { |
2514 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2512 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
2515 Label assign; | 2513 Label assign; |
2516 MemOperand location = VarOperand(var, r1); | 2514 MemOperand location = VarOperand(var, r1); |
2517 __ ldr(r3, location); | 2515 __ ldr(r3, location); |
2518 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); | 2516 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); |
2519 __ b(ne, &assign); | 2517 __ b(ne, &assign); |
2520 __ mov(r3, Operand(var->name())); | 2518 __ mov(r3, Operand(var->name())); |
2521 __ push(r3); | 2519 __ push(r3); |
2522 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 2520 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
2523 // Perform the assignment. | 2521 // Perform the assignment. |
2524 __ bind(&assign); | 2522 __ bind(&assign); |
2525 EmitStoreToStackLocalOrContextSlot(var, location); | 2523 EmitStoreToStackLocalOrContextSlot(var, location); |
2526 } | 2524 } |
2527 | 2525 |
2528 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { | 2526 } else if (!var->is_const_mode() || op == Token::INIT_CONST) { |
2529 // Assignment to var or initializing assignment to let/const | 2527 // Assignment to var or initializing assignment to let/const |
2530 // in harmony mode. | 2528 // in harmony mode. |
2531 if (var->IsLookupSlot()) { | 2529 if (var->IsLookupSlot()) { |
2532 EmitCallStoreContextSlot(var->name(), language_mode()); | 2530 EmitCallStoreContextSlot(var->name(), strict_mode()); |
2533 } else { | 2531 } else { |
2534 ASSERT((var->IsStackAllocated() || var->IsContextSlot())); | 2532 ASSERT((var->IsStackAllocated() || var->IsContextSlot())); |
2535 MemOperand location = VarOperand(var, r1); | 2533 MemOperand location = VarOperand(var, r1); |
2536 if (generate_debug_code_ && op == Token::INIT_LET) { | 2534 if (generate_debug_code_ && op == Token::INIT_LET) { |
2537 // Check for an uninitialized let binding. | 2535 // Check for an uninitialized let binding. |
2538 __ ldr(r2, location); | 2536 __ ldr(r2, location); |
2539 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); | 2537 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); |
2540 __ Check(eq, kLetBindingReInitialization); | 2538 __ Check(eq, kLetBindingReInitialization); |
2541 } | 2539 } |
2542 EmitStoreToStackLocalOrContextSlot(var, location); | 2540 EmitStoreToStackLocalOrContextSlot(var, location); |
(...skipping 21 matching lines...) Expand all Loading... |
2564 } | 2562 } |
2565 | 2563 |
2566 | 2564 |
2567 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2565 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
2568 // Assignment to a property, using a keyed store IC. | 2566 // Assignment to a property, using a keyed store IC. |
2569 | 2567 |
2570 // Record source code position before IC call. | 2568 // Record source code position before IC call. |
2571 SetSourcePosition(expr->position()); | 2569 SetSourcePosition(expr->position()); |
2572 __ Pop(r2, r1); // r1 = key. | 2570 __ Pop(r2, r1); // r1 = key. |
2573 | 2571 |
2574 Handle<Code> ic = is_sloppy_mode() | 2572 Handle<Code> ic = strict_mode() == SLOPPY |
2575 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2573 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
2576 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2574 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
2577 CallIC(ic, expr->AssignmentFeedbackId()); | 2575 CallIC(ic, expr->AssignmentFeedbackId()); |
2578 | 2576 |
2579 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2577 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
2580 context()->Plug(r0); | 2578 context()->Plug(r0); |
2581 } | 2579 } |
2582 | 2580 |
2583 | 2581 |
2584 void FullCodeGenerator::VisitProperty(Property* expr) { | 2582 void FullCodeGenerator::VisitProperty(Property* expr) { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2737 if (arg_count > 0) { | 2735 if (arg_count > 0) { |
2738 __ ldr(r4, MemOperand(sp, arg_count * kPointerSize)); | 2736 __ ldr(r4, MemOperand(sp, arg_count * kPointerSize)); |
2739 } else { | 2737 } else { |
2740 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); | 2738 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); |
2741 } | 2739 } |
2742 | 2740 |
2743 // r3: the receiver of the enclosing function. | 2741 // r3: the receiver of the enclosing function. |
2744 int receiver_offset = 2 + info_->scope()->num_parameters(); | 2742 int receiver_offset = 2 + info_->scope()->num_parameters(); |
2745 __ ldr(r3, MemOperand(fp, receiver_offset * kPointerSize)); | 2743 __ ldr(r3, MemOperand(fp, receiver_offset * kPointerSize)); |
2746 | 2744 |
2747 // r2: the language mode. | 2745 // r2: strict mode. |
2748 __ mov(r2, Operand(Smi::FromInt(language_mode()))); | 2746 __ mov(r2, Operand(Smi::FromInt(strict_mode()))); |
2749 | 2747 |
2750 // r1: the start position of the scope the calls resides in. | 2748 // r1: the start position of the scope the calls resides in. |
2751 __ mov(r1, Operand(Smi::FromInt(scope()->start_position()))); | 2749 __ mov(r1, Operand(Smi::FromInt(scope()->start_position()))); |
2752 | 2750 |
2753 // Do the runtime call. | 2751 // Do the runtime call. |
2754 __ Push(r4, r3, r2, r1); | 2752 __ Push(r4, r3, r2, r1); |
2755 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); | 2753 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); |
2756 } | 2754 } |
2757 | 2755 |
2758 | 2756 |
(...skipping 1419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4178 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 4176 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
4179 switch (expr->op()) { | 4177 switch (expr->op()) { |
4180 case Token::DELETE: { | 4178 case Token::DELETE: { |
4181 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 4179 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
4182 Property* property = expr->expression()->AsProperty(); | 4180 Property* property = expr->expression()->AsProperty(); |
4183 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 4181 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
4184 | 4182 |
4185 if (property != NULL) { | 4183 if (property != NULL) { |
4186 VisitForStackValue(property->obj()); | 4184 VisitForStackValue(property->obj()); |
4187 VisitForStackValue(property->key()); | 4185 VisitForStackValue(property->key()); |
4188 StrictModeFlag strict_mode_flag = (language_mode() == SLOPPY_MODE) | 4186 __ mov(r1, Operand(Smi::FromInt(strict_mode()))); |
4189 ? kSloppyMode : kStrictMode; | |
4190 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag))); | |
4191 __ push(r1); | 4187 __ push(r1); |
4192 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 4188 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
4193 context()->Plug(r0); | 4189 context()->Plug(r0); |
4194 } else if (proxy != NULL) { | 4190 } else if (proxy != NULL) { |
4195 Variable* var = proxy->var(); | 4191 Variable* var = proxy->var(); |
4196 // Delete of an unqualified identifier is disallowed in strict mode | 4192 // Delete of an unqualified identifier is disallowed in strict mode |
4197 // but "delete this" is allowed. | 4193 // but "delete this" is allowed. |
4198 ASSERT(language_mode() == SLOPPY_MODE || var->is_this()); | 4194 ASSERT(strict_mode() == SLOPPY || var->is_this()); |
4199 if (var->IsUnallocated()) { | 4195 if (var->IsUnallocated()) { |
4200 __ ldr(r2, GlobalObjectOperand()); | 4196 __ ldr(r2, GlobalObjectOperand()); |
4201 __ mov(r1, Operand(var->name())); | 4197 __ mov(r1, Operand(var->name())); |
4202 __ mov(r0, Operand(Smi::FromInt(kSloppyMode))); | 4198 __ mov(r0, Operand(Smi::FromInt(SLOPPY))); |
4203 __ Push(r2, r1, r0); | 4199 __ Push(r2, r1, r0); |
4204 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 4200 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
4205 context()->Plug(r0); | 4201 context()->Plug(r0); |
4206 } else if (var->IsStackAllocated() || var->IsContextSlot()) { | 4202 } else if (var->IsStackAllocated() || var->IsContextSlot()) { |
4207 // Result of deleting non-global, non-dynamic variables is false. | 4203 // Result of deleting non-global, non-dynamic variables is false. |
4208 // The subexpression does not have side effects. | 4204 // The subexpression does not have side effects. |
4209 context()->Plug(var->is_this()); | 4205 context()->Plug(var->is_this()); |
4210 } else { | 4206 } else { |
4211 // Non-global variable. Call the runtime to try to delete from the | 4207 // Non-global variable. Call the runtime to try to delete from the |
4212 // context where the variable was introduced. | 4208 // context where the variable was introduced. |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4446 if (!context()->IsEffect()) { | 4442 if (!context()->IsEffect()) { |
4447 context()->PlugTOS(); | 4443 context()->PlugTOS(); |
4448 } | 4444 } |
4449 } else { | 4445 } else { |
4450 context()->Plug(r0); | 4446 context()->Plug(r0); |
4451 } | 4447 } |
4452 break; | 4448 break; |
4453 } | 4449 } |
4454 case KEYED_PROPERTY: { | 4450 case KEYED_PROPERTY: { |
4455 __ Pop(r2, r1); // r1 = key. r2 = receiver. | 4451 __ Pop(r2, r1); // r1 = key. r2 = receiver. |
4456 Handle<Code> ic = is_sloppy_mode() | 4452 Handle<Code> ic = strict_mode() == SLOPPY |
4457 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4453 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
4458 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4454 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
4459 CallIC(ic, expr->CountStoreFeedbackId()); | 4455 CallIC(ic, expr->CountStoreFeedbackId()); |
4460 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4456 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
4461 if (expr->is_postfix()) { | 4457 if (expr->is_postfix()) { |
4462 if (!context()->IsEffect()) { | 4458 if (!context()->IsEffect()) { |
4463 context()->PlugTOS(); | 4459 context()->PlugTOS(); |
4464 } | 4460 } |
4465 } else { | 4461 } else { |
4466 context()->Plug(r0); | 4462 context()->Plug(r0); |
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4918 ASSERT(Memory::uint32_at(interrupt_address_pointer) == | 4914 ASSERT(Memory::uint32_at(interrupt_address_pointer) == |
4919 reinterpret_cast<uint32_t>( | 4915 reinterpret_cast<uint32_t>( |
4920 isolate->builtins()->OsrAfterStackCheck()->entry())); | 4916 isolate->builtins()->OsrAfterStackCheck()->entry())); |
4921 return OSR_AFTER_STACK_CHECK; | 4917 return OSR_AFTER_STACK_CHECK; |
4922 } | 4918 } |
4923 | 4919 |
4924 | 4920 |
4925 } } // namespace v8::internal | 4921 } } // namespace v8::internal |
4926 | 4922 |
4927 #endif // V8_TARGET_ARCH_ARM | 4923 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |