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 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 #ifdef DEBUG | 149 #ifdef DEBUG |
150 if (strlen(FLAG_stop_at) > 0 && | 150 if (strlen(FLAG_stop_at) > 0 && |
151 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 151 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
152 __ stop("stop-at"); | 152 __ stop("stop-at"); |
153 } | 153 } |
154 #endif | 154 #endif |
155 | 155 |
156 // Sloppy mode functions and builtins need to replace the receiver with the | 156 // Sloppy mode functions and builtins need to replace the receiver with the |
157 // global proxy when called as functions (without an explicit receiver | 157 // global proxy when called as functions (without an explicit receiver |
158 // object). | 158 // object). |
159 if (info->is_sloppy_mode() && !info->is_native()) { | 159 if (info->strict_mode() == SLOPPY && !info->is_native()) { |
160 Label ok; | 160 Label ok; |
161 int receiver_offset = info->scope()->num_parameters() * kPointerSize; | 161 int receiver_offset = info->scope()->num_parameters() * kPointerSize; |
162 __ lw(at, MemOperand(sp, receiver_offset)); | 162 __ lw(at, MemOperand(sp, receiver_offset)); |
163 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex); | 163 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex); |
164 __ Branch(&ok, ne, a2, Operand(at)); | 164 __ Branch(&ok, ne, a2, Operand(at)); |
165 | 165 |
166 __ lw(a2, GlobalObjectOperand()); | 166 __ lw(a2, GlobalObjectOperand()); |
167 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset)); | 167 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset)); |
168 | 168 |
169 __ sw(a2, MemOperand(sp, receiver_offset)); | 169 __ sw(a2, MemOperand(sp, receiver_offset)); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 __ Addu(a2, fp, | 264 __ Addu(a2, fp, |
265 Operand(StandardFrameConstants::kCallerSPOffset + offset)); | 265 Operand(StandardFrameConstants::kCallerSPOffset + offset)); |
266 __ li(a1, Operand(Smi::FromInt(num_parameters))); | 266 __ li(a1, Operand(Smi::FromInt(num_parameters))); |
267 __ Push(a3, a2, a1); | 267 __ Push(a3, a2, a1); |
268 | 268 |
269 // Arguments to ArgumentsAccessStub: | 269 // Arguments to ArgumentsAccessStub: |
270 // function, receiver address, parameter count. | 270 // function, receiver address, parameter count. |
271 // The stub will rewrite receiever and parameter count if the previous | 271 // The stub will rewrite receiever and parameter count if the previous |
272 // stack frame was an arguments adapter frame. | 272 // stack frame was an arguments adapter frame. |
273 ArgumentsAccessStub::Type type; | 273 ArgumentsAccessStub::Type type; |
274 if (!is_sloppy_mode()) { | 274 if (strict_mode() == STRICT) { |
275 type = ArgumentsAccessStub::NEW_STRICT; | 275 type = ArgumentsAccessStub::NEW_STRICT; |
276 } else if (function()->has_duplicate_parameters()) { | 276 } else if (function()->has_duplicate_parameters()) { |
277 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW; | 277 type = ArgumentsAccessStub::NEW_SLOPPY_SLOW; |
278 } else { | 278 } else { |
279 type = ArgumentsAccessStub::NEW_SLOPPY_FAST; | 279 type = ArgumentsAccessStub::NEW_SLOPPY_FAST; |
280 } | 280 } |
281 ArgumentsAccessStub stub(type); | 281 ArgumentsAccessStub stub(type); |
282 __ CallStub(&stub); | 282 __ CallStub(&stub); |
283 | 283 |
284 SetVar(arguments, v0, a1, a2); | 284 SetVar(arguments, v0, a1, a2); |
(...skipping 10 matching lines...) Expand all Loading... |
295 scope()->VisitIllegalRedeclaration(this); | 295 scope()->VisitIllegalRedeclaration(this); |
296 | 296 |
297 } else { | 297 } else { |
298 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); | 298 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); |
299 { Comment cmnt(masm_, "[ Declarations"); | 299 { Comment cmnt(masm_, "[ Declarations"); |
300 // For named function expressions, declare the function name as a | 300 // For named function expressions, declare the function name as a |
301 // constant. | 301 // constant. |
302 if (scope()->is_function_scope() && scope()->function() != NULL) { | 302 if (scope()->is_function_scope() && scope()->function() != NULL) { |
303 VariableDeclaration* function = scope()->function(); | 303 VariableDeclaration* function = scope()->function(); |
304 ASSERT(function->proxy()->var()->mode() == CONST || | 304 ASSERT(function->proxy()->var()->mode() == CONST || |
305 function->proxy()->var()->mode() == CONST_HARMONY); | 305 function->proxy()->var()->mode() == CONST_LEGACY); |
306 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); | 306 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED); |
307 VisitVariableDeclaration(function); | 307 VisitVariableDeclaration(function); |
308 } | 308 } |
309 VisitDeclarations(scope()->declarations()); | 309 VisitDeclarations(scope()->declarations()); |
310 } | 310 } |
311 | 311 |
312 { Comment cmnt(masm_, "[ Stack check"); | 312 { Comment cmnt(masm_, "[ Stack check"); |
313 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); | 313 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); |
314 Label ok; | 314 Label ok; |
315 __ LoadRoot(t0, Heap::kStackLimitRootIndex); | 315 __ LoadRoot(t0, Heap::kStackLimitRootIndex); |
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 | 796 |
797 | 797 |
798 void FullCodeGenerator::VisitVariableDeclaration( | 798 void FullCodeGenerator::VisitVariableDeclaration( |
799 VariableDeclaration* declaration) { | 799 VariableDeclaration* declaration) { |
800 // If it was not possible to allocate the variable at compile time, we | 800 // If it was not possible to allocate the variable at compile time, we |
801 // need to "declare" it at runtime to make sure it actually exists in the | 801 // need to "declare" it at runtime to make sure it actually exists in the |
802 // local context. | 802 // local context. |
803 VariableProxy* proxy = declaration->proxy(); | 803 VariableProxy* proxy = declaration->proxy(); |
804 VariableMode mode = declaration->mode(); | 804 VariableMode mode = declaration->mode(); |
805 Variable* variable = proxy->var(); | 805 Variable* variable = proxy->var(); |
806 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET; | 806 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY; |
807 switch (variable->location()) { | 807 switch (variable->location()) { |
808 case Variable::UNALLOCATED: | 808 case Variable::UNALLOCATED: |
809 globals_->Add(variable->name(), zone()); | 809 globals_->Add(variable->name(), zone()); |
810 globals_->Add(variable->binding_needs_init() | 810 globals_->Add(variable->binding_needs_init() |
811 ? isolate()->factory()->the_hole_value() | 811 ? isolate()->factory()->the_hole_value() |
812 : isolate()->factory()->undefined_value(), | 812 : isolate()->factory()->undefined_value(), |
813 zone()); | 813 zone()); |
814 break; | 814 break; |
815 | 815 |
816 case Variable::PARAMETER: | 816 case Variable::PARAMETER: |
(...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1329 // space for nested functions that don't need literals cloning. If | 1329 // space for nested functions that don't need literals cloning. If |
1330 // we're running with the --always-opt or the --prepare-always-opt | 1330 // we're running with the --always-opt or the --prepare-always-opt |
1331 // flag, we need to use the runtime function so that the new function | 1331 // flag, we need to use the runtime function so that the new function |
1332 // we are creating here gets a chance to have its code optimized and | 1332 // we are creating here gets a chance to have its code optimized and |
1333 // doesn't just get a copy of the existing unoptimized code. | 1333 // doesn't just get a copy of the existing unoptimized code. |
1334 if (!FLAG_always_opt && | 1334 if (!FLAG_always_opt && |
1335 !FLAG_prepare_always_opt && | 1335 !FLAG_prepare_always_opt && |
1336 !pretenure && | 1336 !pretenure && |
1337 scope()->is_function_scope() && | 1337 scope()->is_function_scope() && |
1338 info->num_literals() == 0) { | 1338 info->num_literals() == 0) { |
1339 FastNewClosureStub stub(info->language_mode(), info->is_generator()); | 1339 FastNewClosureStub stub(info->strict_mode(), info->is_generator()); |
1340 __ li(a2, Operand(info)); | 1340 __ li(a2, Operand(info)); |
1341 __ CallStub(&stub); | 1341 __ CallStub(&stub); |
1342 } else { | 1342 } else { |
1343 __ li(a0, Operand(info)); | 1343 __ li(a0, Operand(info)); |
1344 __ LoadRoot(a1, pretenure ? Heap::kTrueValueRootIndex | 1344 __ LoadRoot(a1, pretenure ? Heap::kTrueValueRootIndex |
1345 : Heap::kFalseValueRootIndex); | 1345 : Heap::kFalseValueRootIndex); |
1346 __ Push(cp, a0, a1); | 1346 __ Push(cp, a0, a1); |
1347 __ CallRuntime(Runtime::kNewClosure, 3); | 1347 __ CallRuntime(Runtime::kNewClosure, 3); |
1348 } | 1348 } |
1349 context()->Plug(v0); | 1349 context()->Plug(v0); |
(...skipping 98 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 __ Branch(done); | 1454 __ Branch(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 __ lw(v0, ContextSlotOperandCheckExtensions(local, slow)); | 1457 __ lw(v0, 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 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 1460 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
1462 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. | 1461 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. |
1463 if (local->mode() == CONST) { | 1462 if (local->mode() == CONST_LEGACY) { |
1464 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); | 1463 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); |
1465 __ Movz(v0, a0, at); // Conditional move: return Undefined if TheHole. | 1464 __ Movz(v0, a0, at); // Conditional move: return Undefined if TheHole. |
1466 } else { // LET || CONST_HARMONY | 1465 } else { // LET || CONST |
1467 __ Branch(done, ne, at, Operand(zero_reg)); | 1466 __ Branch(done, ne, at, Operand(zero_reg)); |
1468 __ li(a0, Operand(var->name())); | 1467 __ li(a0, Operand(var->name())); |
1469 __ push(a0); | 1468 __ push(a0); |
1470 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1469 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1471 } | 1470 } |
1472 } | 1471 } |
1473 __ Branch(done); | 1472 __ Branch(done); |
1474 } | 1473 } |
1475 } | 1474 } |
1476 | 1475 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1523 // binding is initialized: | 1522 // binding is initialized: |
1524 // function() { f(); let x = 1; function f() { x = 2; } } | 1523 // function() { f(); let x = 1; function f() { x = 2; } } |
1525 // | 1524 // |
1526 bool skip_init_check; | 1525 bool skip_init_check; |
1527 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) { | 1526 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) { |
1528 skip_init_check = false; | 1527 skip_init_check = false; |
1529 } else { | 1528 } else { |
1530 // Check that we always have valid source position. | 1529 // Check that we always have valid source position. |
1531 ASSERT(var->initializer_position() != RelocInfo::kNoPosition); | 1530 ASSERT(var->initializer_position() != RelocInfo::kNoPosition); |
1532 ASSERT(proxy->position() != RelocInfo::kNoPosition); | 1531 ASSERT(proxy->position() != RelocInfo::kNoPosition); |
1533 skip_init_check = var->mode() != CONST && | 1532 skip_init_check = var->mode() != CONST_LEGACY && |
1534 var->initializer_position() < proxy->position(); | 1533 var->initializer_position() < proxy->position(); |
1535 } | 1534 } |
1536 | 1535 |
1537 if (!skip_init_check) { | 1536 if (!skip_init_check) { |
1538 // Let and const need a read barrier. | 1537 // Let and const need a read barrier. |
1539 GetVar(v0, var); | 1538 GetVar(v0, var); |
1540 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 1539 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
1541 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. | 1540 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. |
1542 if (var->mode() == LET || var->mode() == CONST_HARMONY) { | 1541 if (var->mode() == LET || var->mode() == CONST) { |
1543 // Throw a reference error when using an uninitialized let/const | 1542 // Throw a reference error when using an uninitialized let/const |
1544 // binding in harmony mode. | 1543 // binding in harmony mode. |
1545 Label done; | 1544 Label done; |
1546 __ Branch(&done, ne, at, Operand(zero_reg)); | 1545 __ Branch(&done, ne, at, Operand(zero_reg)); |
1547 __ li(a0, Operand(var->name())); | 1546 __ li(a0, Operand(var->name())); |
1548 __ push(a0); | 1547 __ push(a0); |
1549 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1548 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1550 __ bind(&done); | 1549 __ bind(&done); |
1551 } else { | 1550 } else { |
1552 // Uninitalized const bindings outside of harmony mode are unholed. | 1551 // Uninitalized const bindings outside of harmony mode are unholed. |
1553 ASSERT(var->mode() == CONST); | 1552 ASSERT(var->mode() == CONST_LEGACY); |
1554 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); | 1553 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); |
1555 __ Movz(v0, a0, at); // Conditional move: Undefined if TheHole. | 1554 __ Movz(v0, a0, at); // Conditional move: Undefined if TheHole. |
1556 } | 1555 } |
1557 context()->Plug(v0); | 1556 context()->Plug(v0); |
1558 break; | 1557 break; |
1559 } | 1558 } |
1560 } | 1559 } |
1561 context()->Plug(var); | 1560 context()->Plug(var); |
1562 break; | 1561 break; |
1563 } | 1562 } |
(...skipping 888 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2452 __ li(a2, Operand(prop->key()->AsLiteral()->value())); | 2451 __ li(a2, Operand(prop->key()->AsLiteral()->value())); |
2453 CallStoreIC(); | 2452 CallStoreIC(); |
2454 break; | 2453 break; |
2455 } | 2454 } |
2456 case KEYED_PROPERTY: { | 2455 case KEYED_PROPERTY: { |
2457 __ push(result_register()); // Preserve value. | 2456 __ push(result_register()); // Preserve value. |
2458 VisitForStackValue(prop->obj()); | 2457 VisitForStackValue(prop->obj()); |
2459 VisitForAccumulatorValue(prop->key()); | 2458 VisitForAccumulatorValue(prop->key()); |
2460 __ mov(a1, result_register()); | 2459 __ mov(a1, result_register()); |
2461 __ Pop(a0, a2); // a0 = restored value. | 2460 __ Pop(a0, a2); // a0 = restored value. |
2462 Handle<Code> ic = is_sloppy_mode() | 2461 Handle<Code> ic = strict_mode() == SLOPPY |
2463 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2462 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
2464 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2463 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
2465 CallIC(ic); | 2464 CallIC(ic); |
2466 break; | 2465 break; |
2467 } | 2466 } |
2468 } | 2467 } |
2469 context()->Plug(v0); | 2468 context()->Plug(v0); |
2470 } | 2469 } |
2471 | 2470 |
2472 | 2471 |
2473 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( | 2472 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( |
2474 Variable* var, MemOperand location) { | 2473 Variable* var, MemOperand location) { |
2475 __ sw(result_register(), location); | 2474 __ sw(result_register(), location); |
2476 if (var->IsContextSlot()) { | 2475 if (var->IsContextSlot()) { |
2477 // RecordWrite may destroy all its register arguments. | 2476 // RecordWrite may destroy all its register arguments. |
2478 __ Move(a3, result_register()); | 2477 __ Move(a3, result_register()); |
2479 int offset = Context::SlotOffset(var->index()); | 2478 int offset = Context::SlotOffset(var->index()); |
2480 __ RecordWriteContextSlot( | 2479 __ RecordWriteContextSlot( |
2481 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); | 2480 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); |
2482 } | 2481 } |
2483 } | 2482 } |
2484 | 2483 |
2485 | 2484 |
2486 void FullCodeGenerator::EmitCallStoreContextSlot( | 2485 void FullCodeGenerator::EmitCallStoreContextSlot( |
2487 Handle<String> name, LanguageMode mode) { | 2486 Handle<String> name, StrictMode strict_mode) { |
2488 __ li(a1, Operand(name)); | 2487 __ li(a1, Operand(name)); |
2489 __ li(a0, Operand(Smi::FromInt(mode))); | 2488 __ li(a0, Operand(Smi::FromInt(strict_mode))); |
2490 __ Push(v0, cp, a1, a0); // Value, context, name, strict mode. | 2489 __ Push(v0, cp, a1, a0); // Value, context, name, strict mode. |
2491 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 2490 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
2492 } | 2491 } |
2493 | 2492 |
2494 | 2493 |
2495 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 2494 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op) { |
2496 Token::Value op) { | |
2497 if (var->IsUnallocated()) { | 2495 if (var->IsUnallocated()) { |
2498 // Global var, const, or let. | 2496 // Global var, const, or let. |
2499 __ mov(a0, result_register()); | 2497 __ mov(a0, result_register()); |
2500 __ li(a2, Operand(var->name())); | 2498 __ li(a2, Operand(var->name())); |
2501 __ lw(a1, GlobalObjectOperand()); | 2499 __ lw(a1, GlobalObjectOperand()); |
2502 CallStoreIC(); | 2500 CallStoreIC(); |
2503 | 2501 |
2504 } else if (op == Token::INIT_CONST) { | 2502 } else if (op == Token::INIT_CONST_LEGACY) { |
2505 // Const initializers need a write barrier. | 2503 // Const initializers need a write barrier. |
2506 ASSERT(!var->IsParameter()); // No const parameters. | 2504 ASSERT(!var->IsParameter()); // No const parameters. |
2507 if (var->IsLookupSlot()) { | 2505 if (var->IsLookupSlot()) { |
2508 __ li(a0, Operand(var->name())); | 2506 __ li(a0, Operand(var->name())); |
2509 __ Push(v0, cp, a0); // Context and name. | 2507 __ Push(v0, cp, a0); // Context and name. |
2510 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 2508 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
2511 } else { | 2509 } else { |
2512 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2510 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
2513 Label skip; | 2511 Label skip; |
2514 MemOperand location = VarOperand(var, a1); | 2512 MemOperand location = VarOperand(var, a1); |
2515 __ lw(a2, location); | 2513 __ lw(a2, location); |
2516 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 2514 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
2517 __ Branch(&skip, ne, a2, Operand(at)); | 2515 __ Branch(&skip, ne, a2, Operand(at)); |
2518 EmitStoreToStackLocalOrContextSlot(var, location); | 2516 EmitStoreToStackLocalOrContextSlot(var, location); |
2519 __ bind(&skip); | 2517 __ bind(&skip); |
2520 } | 2518 } |
2521 | 2519 |
2522 } else if (var->mode() == LET && op != Token::INIT_LET) { | 2520 } else if (var->mode() == LET && op != Token::INIT_LET) { |
2523 // Non-initializing assignment to let variable needs a write barrier. | 2521 // Non-initializing assignment to let variable needs a write barrier. |
2524 if (var->IsLookupSlot()) { | 2522 if (var->IsLookupSlot()) { |
2525 EmitCallStoreContextSlot(var->name(), language_mode()); | 2523 EmitCallStoreContextSlot(var->name(), strict_mode()); |
2526 } else { | 2524 } else { |
2527 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2525 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
2528 Label assign; | 2526 Label assign; |
2529 MemOperand location = VarOperand(var, a1); | 2527 MemOperand location = VarOperand(var, a1); |
2530 __ lw(a3, location); | 2528 __ lw(a3, location); |
2531 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 2529 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
2532 __ Branch(&assign, ne, a3, Operand(t0)); | 2530 __ Branch(&assign, ne, a3, Operand(t0)); |
2533 __ li(a3, Operand(var->name())); | 2531 __ li(a3, Operand(var->name())); |
2534 __ push(a3); | 2532 __ push(a3); |
2535 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 2533 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
2536 // Perform the assignment. | 2534 // Perform the assignment. |
2537 __ bind(&assign); | 2535 __ bind(&assign); |
2538 EmitStoreToStackLocalOrContextSlot(var, location); | 2536 EmitStoreToStackLocalOrContextSlot(var, location); |
2539 } | 2537 } |
2540 | 2538 |
2541 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { | 2539 } else if (!var->is_const_mode() || op == Token::INIT_CONST) { |
2542 // Assignment to var or initializing assignment to let/const | 2540 // Assignment to var or initializing assignment to let/const |
2543 // in harmony mode. | 2541 // in harmony mode. |
2544 if (var->IsLookupSlot()) { | 2542 if (var->IsLookupSlot()) { |
2545 EmitCallStoreContextSlot(var->name(), language_mode()); | 2543 EmitCallStoreContextSlot(var->name(), strict_mode()); |
2546 } else { | 2544 } else { |
2547 ASSERT((var->IsStackAllocated() || var->IsContextSlot())); | 2545 ASSERT((var->IsStackAllocated() || var->IsContextSlot())); |
2548 MemOperand location = VarOperand(var, a1); | 2546 MemOperand location = VarOperand(var, a1); |
2549 if (generate_debug_code_ && op == Token::INIT_LET) { | 2547 if (generate_debug_code_ && op == Token::INIT_LET) { |
2550 // Check for an uninitialized let binding. | 2548 // Check for an uninitialized let binding. |
2551 __ lw(a2, location); | 2549 __ lw(a2, location); |
2552 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 2550 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
2553 __ Check(eq, kLetBindingReInitialization, a2, Operand(t0)); | 2551 __ Check(eq, kLetBindingReInitialization, a2, Operand(t0)); |
2554 } | 2552 } |
2555 EmitStoreToStackLocalOrContextSlot(var, location); | 2553 EmitStoreToStackLocalOrContextSlot(var, location); |
(...skipping 28 matching lines...) Expand all Loading... |
2584 // Record source code position before IC call. | 2582 // Record source code position before IC call. |
2585 SetSourcePosition(expr->position()); | 2583 SetSourcePosition(expr->position()); |
2586 // Call keyed store IC. | 2584 // Call keyed store IC. |
2587 // The arguments are: | 2585 // The arguments are: |
2588 // - a0 is the value, | 2586 // - a0 is the value, |
2589 // - a1 is the key, | 2587 // - a1 is the key, |
2590 // - a2 is the receiver. | 2588 // - a2 is the receiver. |
2591 __ mov(a0, result_register()); | 2589 __ mov(a0, result_register()); |
2592 __ Pop(a2, a1); // a1 = key. | 2590 __ Pop(a2, a1); // a1 = key. |
2593 | 2591 |
2594 Handle<Code> ic = is_sloppy_mode() | 2592 Handle<Code> ic = strict_mode() == SLOPPY |
2595 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2593 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
2596 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2594 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
2597 CallIC(ic, expr->AssignmentFeedbackId()); | 2595 CallIC(ic, expr->AssignmentFeedbackId()); |
2598 | 2596 |
2599 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2597 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
2600 context()->Plug(v0); | 2598 context()->Plug(v0); |
2601 } | 2599 } |
2602 | 2600 |
2603 | 2601 |
2604 void FullCodeGenerator::VisitProperty(Property* expr) { | 2602 void FullCodeGenerator::VisitProperty(Property* expr) { |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2750 if (arg_count > 0) { | 2748 if (arg_count > 0) { |
2751 __ lw(t2, MemOperand(sp, arg_count * kPointerSize)); | 2749 __ lw(t2, MemOperand(sp, arg_count * kPointerSize)); |
2752 } else { | 2750 } else { |
2753 __ LoadRoot(t2, Heap::kUndefinedValueRootIndex); | 2751 __ LoadRoot(t2, Heap::kUndefinedValueRootIndex); |
2754 } | 2752 } |
2755 | 2753 |
2756 // t1: the receiver of the enclosing function. | 2754 // t1: the receiver of the enclosing function. |
2757 int receiver_offset = 2 + info_->scope()->num_parameters(); | 2755 int receiver_offset = 2 + info_->scope()->num_parameters(); |
2758 __ lw(t1, MemOperand(fp, receiver_offset * kPointerSize)); | 2756 __ lw(t1, MemOperand(fp, receiver_offset * kPointerSize)); |
2759 | 2757 |
2760 // t0: the language mode. | 2758 // t0: the strict mode. |
2761 __ li(t0, Operand(Smi::FromInt(language_mode()))); | 2759 __ li(t0, Operand(Smi::FromInt(strict_mode()))); |
2762 | 2760 |
2763 // a1: the start position of the scope the calls resides in. | 2761 // a1: the start position of the scope the calls resides in. |
2764 __ li(a1, Operand(Smi::FromInt(scope()->start_position()))); | 2762 __ li(a1, Operand(Smi::FromInt(scope()->start_position()))); |
2765 | 2763 |
2766 // Do the runtime call. | 2764 // Do the runtime call. |
2767 __ Push(t2, t1, t0, a1); | 2765 __ Push(t2, t1, t0, a1); |
2768 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); | 2766 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); |
2769 } | 2767 } |
2770 | 2768 |
2771 | 2769 |
(...skipping 1448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4220 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 4218 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
4221 switch (expr->op()) { | 4219 switch (expr->op()) { |
4222 case Token::DELETE: { | 4220 case Token::DELETE: { |
4223 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 4221 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
4224 Property* property = expr->expression()->AsProperty(); | 4222 Property* property = expr->expression()->AsProperty(); |
4225 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 4223 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
4226 | 4224 |
4227 if (property != NULL) { | 4225 if (property != NULL) { |
4228 VisitForStackValue(property->obj()); | 4226 VisitForStackValue(property->obj()); |
4229 VisitForStackValue(property->key()); | 4227 VisitForStackValue(property->key()); |
4230 StrictModeFlag strict_mode_flag = (language_mode() == SLOPPY_MODE) | 4228 __ li(a1, Operand(Smi::FromInt(strict_mode()))); |
4231 ? kSloppyMode : kStrictMode; | |
4232 __ li(a1, Operand(Smi::FromInt(strict_mode_flag))); | |
4233 __ push(a1); | 4229 __ push(a1); |
4234 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 4230 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
4235 context()->Plug(v0); | 4231 context()->Plug(v0); |
4236 } else if (proxy != NULL) { | 4232 } else if (proxy != NULL) { |
4237 Variable* var = proxy->var(); | 4233 Variable* var = proxy->var(); |
4238 // Delete of an unqualified identifier is disallowed in strict mode | 4234 // Delete of an unqualified identifier is disallowed in strict mode |
4239 // but "delete this" is allowed. | 4235 // but "delete this" is allowed. |
4240 ASSERT(language_mode() == SLOPPY_MODE || var->is_this()); | 4236 ASSERT(strict_mode() == SLOPPY || var->is_this()); |
4241 if (var->IsUnallocated()) { | 4237 if (var->IsUnallocated()) { |
4242 __ lw(a2, GlobalObjectOperand()); | 4238 __ lw(a2, GlobalObjectOperand()); |
4243 __ li(a1, Operand(var->name())); | 4239 __ li(a1, Operand(var->name())); |
4244 __ li(a0, Operand(Smi::FromInt(kSloppyMode))); | 4240 __ li(a0, Operand(Smi::FromInt(SLOPPY))); |
4245 __ Push(a2, a1, a0); | 4241 __ Push(a2, a1, a0); |
4246 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 4242 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
4247 context()->Plug(v0); | 4243 context()->Plug(v0); |
4248 } else if (var->IsStackAllocated() || var->IsContextSlot()) { | 4244 } else if (var->IsStackAllocated() || var->IsContextSlot()) { |
4249 // Result of deleting non-global, non-dynamic variables is false. | 4245 // Result of deleting non-global, non-dynamic variables is false. |
4250 // The subexpression does not have side effects. | 4246 // The subexpression does not have side effects. |
4251 context()->Plug(var->is_this()); | 4247 context()->Plug(var->is_this()); |
4252 } else { | 4248 } else { |
4253 // Non-global variable. Call the runtime to try to delete from the | 4249 // Non-global variable. Call the runtime to try to delete from the |
4254 // context where the variable was introduced. | 4250 // context where the variable was introduced. |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4493 context()->PlugTOS(); | 4489 context()->PlugTOS(); |
4494 } | 4490 } |
4495 } else { | 4491 } else { |
4496 context()->Plug(v0); | 4492 context()->Plug(v0); |
4497 } | 4493 } |
4498 break; | 4494 break; |
4499 } | 4495 } |
4500 case KEYED_PROPERTY: { | 4496 case KEYED_PROPERTY: { |
4501 __ mov(a0, result_register()); // Value. | 4497 __ mov(a0, result_register()); // Value. |
4502 __ Pop(a2, a1); // a1 = key, a2 = receiver. | 4498 __ Pop(a2, a1); // a1 = key, a2 = receiver. |
4503 Handle<Code> ic = is_sloppy_mode() | 4499 Handle<Code> ic = strict_mode() == SLOPPY |
4504 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4500 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
4505 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4501 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
4506 CallIC(ic, expr->CountStoreFeedbackId()); | 4502 CallIC(ic, expr->CountStoreFeedbackId()); |
4507 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4503 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
4508 if (expr->is_postfix()) { | 4504 if (expr->is_postfix()) { |
4509 if (!context()->IsEffect()) { | 4505 if (!context()->IsEffect()) { |
4510 context()->PlugTOS(); | 4506 context()->PlugTOS(); |
4511 } | 4507 } |
4512 } else { | 4508 } else { |
4513 context()->Plug(v0); | 4509 context()->Plug(v0); |
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4954 Assembler::target_address_at(pc_immediate_load_address)) == | 4950 Assembler::target_address_at(pc_immediate_load_address)) == |
4955 reinterpret_cast<uint32_t>( | 4951 reinterpret_cast<uint32_t>( |
4956 isolate->builtins()->OsrAfterStackCheck()->entry())); | 4952 isolate->builtins()->OsrAfterStackCheck()->entry())); |
4957 return OSR_AFTER_STACK_CHECK; | 4953 return OSR_AFTER_STACK_CHECK; |
4958 } | 4954 } |
4959 | 4955 |
4960 | 4956 |
4961 } } // namespace v8::internal | 4957 } } // namespace v8::internal |
4962 | 4958 |
4963 #endif // V8_TARGET_ARCH_MIPS | 4959 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |