| 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 |