OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 int offset = scope()->num_parameters() * kPointerSize; | 223 int offset = scope()->num_parameters() * kPointerSize; |
224 __ add(r2, fp, | 224 __ add(r2, fp, |
225 Operand(StandardFrameConstants::kCallerSPOffset + offset)); | 225 Operand(StandardFrameConstants::kCallerSPOffset + offset)); |
226 __ mov(r1, Operand(Smi::FromInt(scope()->num_parameters()))); | 226 __ mov(r1, Operand(Smi::FromInt(scope()->num_parameters()))); |
227 __ Push(r3, r2, r1); | 227 __ Push(r3, r2, r1); |
228 | 228 |
229 // Arguments to ArgumentsAccessStub: | 229 // Arguments to ArgumentsAccessStub: |
230 // function, receiver address, parameter count. | 230 // function, receiver address, parameter count. |
231 // The stub will rewrite receiever and parameter count if the previous | 231 // The stub will rewrite receiever and parameter count if the previous |
232 // stack frame was an arguments adapter frame. | 232 // stack frame was an arguments adapter frame. |
233 ArgumentsAccessStub::Type type; | 233 ArgumentsAccessStub stub( |
234 if (is_strict_mode()) { | 234 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT |
235 type = ArgumentsAccessStub::NEW_STRICT; | 235 : ArgumentsAccessStub::NEW_NON_STRICT); |
236 } else if (function()->has_duplicate_parameters()) { | |
237 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; | |
238 } else { | |
239 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST; | |
240 } | |
241 ArgumentsAccessStub stub(type); | |
242 __ CallStub(&stub); | 236 __ CallStub(&stub); |
243 | 237 |
| 238 Variable* arguments_shadow = scope()->arguments_shadow(); |
| 239 if (arguments_shadow != NULL) { |
| 240 // Duplicate the value; move-to-slot operation might clobber registers. |
| 241 __ mov(r3, r0); |
| 242 Move(arguments_shadow->AsSlot(), r3, r1, r2); |
| 243 } |
244 Move(arguments->AsSlot(), r0, r1, r2); | 244 Move(arguments->AsSlot(), r0, r1, r2); |
245 } | 245 } |
246 | 246 |
247 if (FLAG_trace) { | 247 if (FLAG_trace) { |
248 __ CallRuntime(Runtime::kTraceEnter, 0); | 248 __ CallRuntime(Runtime::kTraceEnter, 0); |
249 } | 249 } |
250 | 250 |
251 // Visit the declarations and body unless there is an illegal | 251 // Visit the declarations and body unless there is an illegal |
252 // redeclaration. | 252 // redeclaration. |
253 if (scope()->HasIllegalRedeclaration()) { | 253 if (scope()->HasIllegalRedeclaration()) { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { | 376 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { |
377 codegen()->Move(result_register(), slot); | 377 codegen()->Move(result_register(), slot); |
378 __ push(result_register()); | 378 __ push(result_register()); |
379 } | 379 } |
380 | 380 |
381 | 381 |
382 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { | 382 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { |
383 // For simplicity we always test the accumulator register. | 383 // For simplicity we always test the accumulator register. |
384 codegen()->Move(result_register(), slot); | 384 codegen()->Move(result_register(), slot); |
385 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 385 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
386 codegen()->DoTest(true_label_, false_label_, fall_through_); | 386 codegen()->DoTest(this); |
387 } | 387 } |
388 | 388 |
389 | 389 |
390 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { | 390 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { |
391 } | 391 } |
392 | 392 |
393 | 393 |
394 void FullCodeGenerator::AccumulatorValueContext::Plug( | 394 void FullCodeGenerator::AccumulatorValueContext::Plug( |
395 Heap::RootListIndex index) const { | 395 Heap::RootListIndex index) const { |
396 __ LoadRoot(result_register(), index); | 396 __ LoadRoot(result_register(), index); |
(...skipping 13 matching lines...) Expand all Loading... |
410 true_label_, | 410 true_label_, |
411 false_label_); | 411 false_label_); |
412 if (index == Heap::kUndefinedValueRootIndex || | 412 if (index == Heap::kUndefinedValueRootIndex || |
413 index == Heap::kNullValueRootIndex || | 413 index == Heap::kNullValueRootIndex || |
414 index == Heap::kFalseValueRootIndex) { | 414 index == Heap::kFalseValueRootIndex) { |
415 if (false_label_ != fall_through_) __ b(false_label_); | 415 if (false_label_ != fall_through_) __ b(false_label_); |
416 } else if (index == Heap::kTrueValueRootIndex) { | 416 } else if (index == Heap::kTrueValueRootIndex) { |
417 if (true_label_ != fall_through_) __ b(true_label_); | 417 if (true_label_ != fall_through_) __ b(true_label_); |
418 } else { | 418 } else { |
419 __ LoadRoot(result_register(), index); | 419 __ LoadRoot(result_register(), index); |
420 codegen()->DoTest(true_label_, false_label_, fall_through_); | 420 codegen()->DoTest(this); |
421 } | 421 } |
422 } | 422 } |
423 | 423 |
424 | 424 |
425 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { | 425 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { |
426 } | 426 } |
427 | 427 |
428 | 428 |
429 void FullCodeGenerator::AccumulatorValueContext::Plug( | 429 void FullCodeGenerator::AccumulatorValueContext::Plug( |
430 Handle<Object> lit) const { | 430 Handle<Object> lit) const { |
(...skipping 26 matching lines...) Expand all Loading... |
457 } | 457 } |
458 } else if (lit->IsSmi()) { | 458 } else if (lit->IsSmi()) { |
459 if (Smi::cast(*lit)->value() == 0) { | 459 if (Smi::cast(*lit)->value() == 0) { |
460 if (false_label_ != fall_through_) __ b(false_label_); | 460 if (false_label_ != fall_through_) __ b(false_label_); |
461 } else { | 461 } else { |
462 if (true_label_ != fall_through_) __ b(true_label_); | 462 if (true_label_ != fall_through_) __ b(true_label_); |
463 } | 463 } |
464 } else { | 464 } else { |
465 // For simplicity we always test the accumulator register. | 465 // For simplicity we always test the accumulator register. |
466 __ mov(result_register(), Operand(lit)); | 466 __ mov(result_register(), Operand(lit)); |
467 codegen()->DoTest(true_label_, false_label_, fall_through_); | 467 codegen()->DoTest(this); |
468 } | 468 } |
469 } | 469 } |
470 | 470 |
471 | 471 |
472 void FullCodeGenerator::EffectContext::DropAndPlug(int count, | 472 void FullCodeGenerator::EffectContext::DropAndPlug(int count, |
473 Register reg) const { | 473 Register reg) const { |
474 ASSERT(count > 0); | 474 ASSERT(count > 0); |
475 __ Drop(count); | 475 __ Drop(count); |
476 } | 476 } |
477 | 477 |
(...skipping 15 matching lines...) Expand all Loading... |
493 } | 493 } |
494 | 494 |
495 | 495 |
496 void FullCodeGenerator::TestContext::DropAndPlug(int count, | 496 void FullCodeGenerator::TestContext::DropAndPlug(int count, |
497 Register reg) const { | 497 Register reg) const { |
498 ASSERT(count > 0); | 498 ASSERT(count > 0); |
499 // For simplicity we always test the accumulator register. | 499 // For simplicity we always test the accumulator register. |
500 __ Drop(count); | 500 __ Drop(count); |
501 __ Move(result_register(), reg); | 501 __ Move(result_register(), reg); |
502 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 502 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
503 codegen()->DoTest(true_label_, false_label_, fall_through_); | 503 codegen()->DoTest(this); |
504 } | 504 } |
505 | 505 |
506 | 506 |
507 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, | 507 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, |
508 Label* materialize_false) const { | 508 Label* materialize_false) const { |
509 ASSERT(materialize_true == materialize_false); | 509 ASSERT(materialize_true == materialize_false); |
510 __ bind(materialize_true); | 510 __ bind(materialize_true); |
511 } | 511 } |
512 | 512 |
513 | 513 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
571 true_label_, | 571 true_label_, |
572 false_label_); | 572 false_label_); |
573 if (flag) { | 573 if (flag) { |
574 if (true_label_ != fall_through_) __ b(true_label_); | 574 if (true_label_ != fall_through_) __ b(true_label_); |
575 } else { | 575 } else { |
576 if (false_label_ != fall_through_) __ b(false_label_); | 576 if (false_label_ != fall_through_) __ b(false_label_); |
577 } | 577 } |
578 } | 578 } |
579 | 579 |
580 | 580 |
581 void FullCodeGenerator::DoTest(Label* if_true, | 581 void FullCodeGenerator::DoTest(Expression* condition, |
| 582 Label* if_true, |
582 Label* if_false, | 583 Label* if_false, |
583 Label* fall_through) { | 584 Label* fall_through) { |
584 if (CpuFeatures::IsSupported(VFP3)) { | 585 if (CpuFeatures::IsSupported(VFP3)) { |
585 ToBooleanStub stub(result_register()); | 586 ToBooleanStub stub(result_register()); |
586 __ CallStub(&stub); | 587 __ CallStub(&stub); |
587 __ tst(result_register(), result_register()); | 588 __ tst(result_register(), result_register()); |
588 } else { | 589 } else { |
589 // Call the runtime to find the boolean value of the source and then | 590 // Call the runtime to find the boolean value of the source and then |
590 // translate it into control flow to the pair of labels. | 591 // translate it into control flow to the pair of labels. |
591 __ push(result_register()); | 592 __ push(result_register()); |
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1248 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | 1249 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
1249 __ jmp(done); | 1250 __ jmp(done); |
1250 } | 1251 } |
1251 } | 1252 } |
1252 } | 1253 } |
1253 } | 1254 } |
1254 } | 1255 } |
1255 | 1256 |
1256 | 1257 |
1257 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1258 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
1258 // Three cases: non-this global variables, lookup slots, and all other | 1259 // Four cases: non-this global variables, lookup slots, all other |
1259 // types of slots. | 1260 // types of slots, and parameters that rewrite to explicit property |
| 1261 // accesses on the arguments object. |
1260 Slot* slot = var->AsSlot(); | 1262 Slot* slot = var->AsSlot(); |
1261 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); | 1263 Property* property = var->AsProperty(); |
1262 | 1264 |
1263 if (slot == NULL) { | 1265 if (var->is_global() && !var->is_this()) { |
1264 Comment cmnt(masm_, "Global variable"); | 1266 Comment cmnt(masm_, "Global variable"); |
1265 // Use inline caching. Variable name is passed in r2 and the global | 1267 // Use inline caching. Variable name is passed in r2 and the global |
1266 // object (receiver) in r0. | 1268 // object (receiver) in r0. |
1267 __ ldr(r0, GlobalObjectOperand()); | 1269 __ ldr(r0, GlobalObjectOperand()); |
1268 __ mov(r2, Operand(var->name())); | 1270 __ mov(r2, Operand(var->name())); |
1269 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1271 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
1270 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); | 1272 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); |
1271 context()->Plug(r0); | 1273 context()->Plug(r0); |
1272 | 1274 |
1273 } else if (slot->type() == Slot::LOOKUP) { | 1275 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
1274 Label done, slow; | 1276 Label done, slow; |
1275 | 1277 |
1276 // Generate code for loading from variables potentially shadowed | 1278 // Generate code for loading from variables potentially shadowed |
1277 // by eval-introduced variables. | 1279 // by eval-introduced variables. |
1278 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1280 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
1279 | 1281 |
1280 __ bind(&slow); | 1282 __ bind(&slow); |
1281 Comment cmnt(masm_, "Lookup slot"); | 1283 Comment cmnt(masm_, "Lookup slot"); |
1282 __ mov(r1, Operand(var->name())); | 1284 __ mov(r1, Operand(var->name())); |
1283 __ Push(cp, r1); // Context and name. | 1285 __ Push(cp, r1); // Context and name. |
1284 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1286 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
1285 __ bind(&done); | 1287 __ bind(&done); |
1286 | 1288 |
1287 context()->Plug(r0); | 1289 context()->Plug(r0); |
1288 | 1290 |
1289 } else { | 1291 } else if (slot != NULL) { |
1290 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1292 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
1291 ? "Context slot" | 1293 ? "Context slot" |
1292 : "Stack slot"); | 1294 : "Stack slot"); |
1293 if (var->mode() == Variable::CONST) { | 1295 if (var->mode() == Variable::CONST) { |
1294 // Constants may be the hole value if they have not been initialized. | 1296 // Constants may be the hole value if they have not been initialized. |
1295 // Unhole them. | 1297 // Unhole them. |
1296 MemOperand slot_operand = EmitSlotSearch(slot, r0); | 1298 MemOperand slot_operand = EmitSlotSearch(slot, r0); |
1297 __ ldr(r0, slot_operand); | 1299 __ ldr(r0, slot_operand); |
1298 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 1300 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
1299 __ cmp(r0, ip); | 1301 __ cmp(r0, ip); |
1300 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | 1302 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
1301 context()->Plug(r0); | 1303 context()->Plug(r0); |
1302 } else { | 1304 } else { |
1303 context()->Plug(slot); | 1305 context()->Plug(slot); |
1304 } | 1306 } |
| 1307 } else { |
| 1308 Comment cmnt(masm_, "Rewritten parameter"); |
| 1309 ASSERT_NOT_NULL(property); |
| 1310 // Rewritten parameter accesses are of the form "slot[literal]". |
| 1311 |
| 1312 // Assert that the object is in a slot. |
| 1313 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); |
| 1314 ASSERT_NOT_NULL(object_var); |
| 1315 Slot* object_slot = object_var->AsSlot(); |
| 1316 ASSERT_NOT_NULL(object_slot); |
| 1317 |
| 1318 // Load the object. |
| 1319 Move(r1, object_slot); |
| 1320 |
| 1321 // Assert that the key is a smi. |
| 1322 Literal* key_literal = property->key()->AsLiteral(); |
| 1323 ASSERT_NOT_NULL(key_literal); |
| 1324 ASSERT(key_literal->handle()->IsSmi()); |
| 1325 |
| 1326 // Load the key. |
| 1327 __ mov(r0, Operand(key_literal->handle())); |
| 1328 |
| 1329 // Call keyed load IC. It has arguments key and receiver in r0 and r1. |
| 1330 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1331 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
| 1332 context()->Plug(r0); |
1305 } | 1333 } |
1306 } | 1334 } |
1307 | 1335 |
1308 | 1336 |
1309 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1337 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
1310 Comment cmnt(masm_, "[ RegExpLiteral"); | 1338 Comment cmnt(masm_, "[ RegExpLiteral"); |
1311 Label materialized; | 1339 Label materialized; |
1312 // Registers will be used as follows: | 1340 // Registers will be used as follows: |
1313 // r5 = materialized value (RegExp literal) | 1341 // r5 = materialized value (RegExp literal) |
1314 // r4 = JS function, literals array | 1342 // r4 = JS function, literals array |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1535 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1563 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
1536 Comment cmnt(masm_, "[ Assignment"); | 1564 Comment cmnt(masm_, "[ Assignment"); |
1537 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1565 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
1538 // on the left-hand side. | 1566 // on the left-hand side. |
1539 if (!expr->target()->IsValidLeftHandSide()) { | 1567 if (!expr->target()->IsValidLeftHandSide()) { |
1540 VisitForEffect(expr->target()); | 1568 VisitForEffect(expr->target()); |
1541 return; | 1569 return; |
1542 } | 1570 } |
1543 | 1571 |
1544 // Left-hand side can only be a property, a global or a (parameter or local) | 1572 // Left-hand side can only be a property, a global or a (parameter or local) |
1545 // slot. | 1573 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
1546 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1574 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
1547 LhsKind assign_type = VARIABLE; | 1575 LhsKind assign_type = VARIABLE; |
1548 Property* property = expr->target()->AsProperty(); | 1576 Property* property = expr->target()->AsProperty(); |
1549 if (property != NULL) { | 1577 if (property != NULL) { |
1550 assign_type = (property->key()->IsPropertyName()) | 1578 assign_type = (property->key()->IsPropertyName()) |
1551 ? NAMED_PROPERTY | 1579 ? NAMED_PROPERTY |
1552 : KEYED_PROPERTY; | 1580 : KEYED_PROPERTY; |
1553 } | 1581 } |
1554 | 1582 |
1555 // Evaluate LHS expression. | 1583 // Evaluate LHS expression. |
1556 switch (assign_type) { | 1584 switch (assign_type) { |
1557 case VARIABLE: | 1585 case VARIABLE: |
1558 // Nothing to do here. | 1586 // Nothing to do here. |
1559 break; | 1587 break; |
1560 case NAMED_PROPERTY: | 1588 case NAMED_PROPERTY: |
1561 if (expr->is_compound()) { | 1589 if (expr->is_compound()) { |
1562 // We need the receiver both on the stack and in the accumulator. | 1590 // We need the receiver both on the stack and in the accumulator. |
1563 VisitForAccumulatorValue(property->obj()); | 1591 VisitForAccumulatorValue(property->obj()); |
1564 __ push(result_register()); | 1592 __ push(result_register()); |
1565 } else { | 1593 } else { |
1566 VisitForStackValue(property->obj()); | 1594 VisitForStackValue(property->obj()); |
1567 } | 1595 } |
1568 break; | 1596 break; |
1569 case KEYED_PROPERTY: | 1597 case KEYED_PROPERTY: |
1570 if (expr->is_compound()) { | 1598 if (expr->is_compound()) { |
1571 VisitForStackValue(property->obj()); | 1599 if (property->is_arguments_access()) { |
1572 VisitForAccumulatorValue(property->key()); | 1600 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1601 __ ldr(r0, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0)); |
| 1602 __ push(r0); |
| 1603 __ mov(r0, Operand(property->key()->AsLiteral()->handle())); |
| 1604 } else { |
| 1605 VisitForStackValue(property->obj()); |
| 1606 VisitForAccumulatorValue(property->key()); |
| 1607 } |
1573 __ ldr(r1, MemOperand(sp, 0)); | 1608 __ ldr(r1, MemOperand(sp, 0)); |
1574 __ push(r0); | 1609 __ push(r0); |
1575 } else { | 1610 } else { |
1576 VisitForStackValue(property->obj()); | 1611 if (property->is_arguments_access()) { |
1577 VisitForStackValue(property->key()); | 1612 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1613 __ ldr(r1, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0)); |
| 1614 __ mov(r0, Operand(property->key()->AsLiteral()->handle())); |
| 1615 __ Push(r1, r0); |
| 1616 } else { |
| 1617 VisitForStackValue(property->obj()); |
| 1618 VisitForStackValue(property->key()); |
| 1619 } |
1578 } | 1620 } |
1579 break; | 1621 break; |
1580 } | 1622 } |
1581 | 1623 |
1582 // For compound assignments we need another deoptimization point after the | 1624 // For compound assignments we need another deoptimization point after the |
1583 // variable/property load. | 1625 // variable/property load. |
1584 if (expr->is_compound()) { | 1626 if (expr->is_compound()) { |
1585 { AccumulatorValueContext context(this); | 1627 { AccumulatorValueContext context(this); |
1586 switch (assign_type) { | 1628 switch (assign_type) { |
1587 case VARIABLE: | 1629 case VARIABLE: |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1774 | 1816 |
1775 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1817 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
1776 // Invalid left-hand sides are rewritten to have a 'throw | 1818 // Invalid left-hand sides are rewritten to have a 'throw |
1777 // ReferenceError' on the left-hand side. | 1819 // ReferenceError' on the left-hand side. |
1778 if (!expr->IsValidLeftHandSide()) { | 1820 if (!expr->IsValidLeftHandSide()) { |
1779 VisitForEffect(expr); | 1821 VisitForEffect(expr); |
1780 return; | 1822 return; |
1781 } | 1823 } |
1782 | 1824 |
1783 // Left-hand side can only be a property, a global or a (parameter or local) | 1825 // Left-hand side can only be a property, a global or a (parameter or local) |
1784 // slot. | 1826 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
1785 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1827 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
1786 LhsKind assign_type = VARIABLE; | 1828 LhsKind assign_type = VARIABLE; |
1787 Property* prop = expr->AsProperty(); | 1829 Property* prop = expr->AsProperty(); |
1788 if (prop != NULL) { | 1830 if (prop != NULL) { |
1789 assign_type = (prop->key()->IsPropertyName()) | 1831 assign_type = (prop->key()->IsPropertyName()) |
1790 ? NAMED_PROPERTY | 1832 ? NAMED_PROPERTY |
1791 : KEYED_PROPERTY; | 1833 : KEYED_PROPERTY; |
1792 } | 1834 } |
1793 | 1835 |
1794 switch (assign_type) { | 1836 switch (assign_type) { |
(...skipping 10 matching lines...) Expand all Loading... |
1805 __ pop(r0); // Restore value. | 1847 __ pop(r0); // Restore value. |
1806 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); | 1848 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); |
1807 Handle<Code> ic = is_strict_mode() | 1849 Handle<Code> ic = is_strict_mode() |
1808 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1850 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
1809 : isolate()->builtins()->StoreIC_Initialize(); | 1851 : isolate()->builtins()->StoreIC_Initialize(); |
1810 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 1852 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); |
1811 break; | 1853 break; |
1812 } | 1854 } |
1813 case KEYED_PROPERTY: { | 1855 case KEYED_PROPERTY: { |
1814 __ push(r0); // Preserve value. | 1856 __ push(r0); // Preserve value. |
1815 VisitForStackValue(prop->obj()); | 1857 if (prop->is_synthetic()) { |
1816 VisitForAccumulatorValue(prop->key()); | 1858 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
1817 __ mov(r1, r0); | 1859 ASSERT(prop->key()->AsLiteral() != NULL); |
1818 __ pop(r2); | 1860 { AccumulatorValueContext for_object(this); |
| 1861 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); |
| 1862 } |
| 1863 __ mov(r2, r0); |
| 1864 __ mov(r1, Operand(prop->key()->AsLiteral()->handle())); |
| 1865 } else { |
| 1866 VisitForStackValue(prop->obj()); |
| 1867 VisitForAccumulatorValue(prop->key()); |
| 1868 __ mov(r1, r0); |
| 1869 __ pop(r2); |
| 1870 } |
1819 __ pop(r0); // Restore value. | 1871 __ pop(r0); // Restore value. |
1820 Handle<Code> ic = is_strict_mode() | 1872 Handle<Code> ic = is_strict_mode() |
1821 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 1873 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
1822 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 1874 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
1823 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 1875 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); |
1824 break; | 1876 break; |
1825 } | 1877 } |
1826 } | 1878 } |
1827 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1879 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
1828 context()->Plug(r0); | 1880 context()->Plug(r0); |
1829 } | 1881 } |
1830 | 1882 |
1831 | 1883 |
1832 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1884 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
1833 Token::Value op) { | 1885 Token::Value op) { |
| 1886 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 1887 // here. |
1834 ASSERT(var != NULL); | 1888 ASSERT(var != NULL); |
1835 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1889 ASSERT(var->is_global() || var->AsSlot() != NULL); |
1836 | 1890 |
1837 if (var->is_global()) { | 1891 if (var->is_global()) { |
1838 ASSERT(!var->is_this()); | 1892 ASSERT(!var->is_this()); |
1839 // Assignment to a global variable. Use inline caching for the | 1893 // Assignment to a global variable. Use inline caching for the |
1840 // assignment. Right-hand-side value is passed in r0, variable name in | 1894 // assignment. Right-hand-side value is passed in r0, variable name in |
1841 // r2, and the global object in r1. | 1895 // r2, and the global object in r1. |
1842 __ mov(r2, Operand(var->name())); | 1896 __ mov(r2, Operand(var->name())); |
1843 __ ldr(r1, GlobalObjectOperand()); | 1897 __ ldr(r1, GlobalObjectOperand()); |
(...skipping 1919 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3763 SetSourcePosition(expr->position()); | 3817 SetSourcePosition(expr->position()); |
3764 | 3818 |
3765 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 3819 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
3766 // as the left-hand side. | 3820 // as the left-hand side. |
3767 if (!expr->expression()->IsValidLeftHandSide()) { | 3821 if (!expr->expression()->IsValidLeftHandSide()) { |
3768 VisitForEffect(expr->expression()); | 3822 VisitForEffect(expr->expression()); |
3769 return; | 3823 return; |
3770 } | 3824 } |
3771 | 3825 |
3772 // Expression can only be a property, a global or a (parameter or local) | 3826 // Expression can only be a property, a global or a (parameter or local) |
3773 // slot. | 3827 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
3774 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 3828 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
3775 LhsKind assign_type = VARIABLE; | 3829 LhsKind assign_type = VARIABLE; |
3776 Property* prop = expr->expression()->AsProperty(); | 3830 Property* prop = expr->expression()->AsProperty(); |
3777 // In case of a property we use the uninitialized expression context | 3831 // In case of a property we use the uninitialized expression context |
3778 // of the key to detect a named property. | 3832 // of the key to detect a named property. |
3779 if (prop != NULL) { | 3833 if (prop != NULL) { |
3780 assign_type = | 3834 assign_type = |
3781 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 3835 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
3782 } | 3836 } |
3783 | 3837 |
3784 // Evaluate expression and get value. | 3838 // Evaluate expression and get value. |
3785 if (assign_type == VARIABLE) { | 3839 if (assign_type == VARIABLE) { |
3786 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 3840 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
3787 AccumulatorValueContext context(this); | 3841 AccumulatorValueContext context(this); |
3788 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); | 3842 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); |
3789 } else { | 3843 } else { |
3790 // Reserve space for result of postfix operation. | 3844 // Reserve space for result of postfix operation. |
3791 if (expr->is_postfix() && !context()->IsEffect()) { | 3845 if (expr->is_postfix() && !context()->IsEffect()) { |
3792 __ mov(ip, Operand(Smi::FromInt(0))); | 3846 __ mov(ip, Operand(Smi::FromInt(0))); |
3793 __ push(ip); | 3847 __ push(ip); |
3794 } | 3848 } |
3795 if (assign_type == NAMED_PROPERTY) { | 3849 if (assign_type == NAMED_PROPERTY) { |
3796 // Put the object both on the stack and in the accumulator. | 3850 // Put the object both on the stack and in the accumulator. |
3797 VisitForAccumulatorValue(prop->obj()); | 3851 VisitForAccumulatorValue(prop->obj()); |
3798 __ push(r0); | 3852 __ push(r0); |
3799 EmitNamedPropertyLoad(prop); | 3853 EmitNamedPropertyLoad(prop); |
3800 } else { | 3854 } else { |
3801 VisitForStackValue(prop->obj()); | 3855 if (prop->is_arguments_access()) { |
3802 VisitForAccumulatorValue(prop->key()); | 3856 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); |
| 3857 __ ldr(r0, EmitSlotSearch(obj_proxy->var()->AsSlot(), r0)); |
| 3858 __ push(r0); |
| 3859 __ mov(r0, Operand(prop->key()->AsLiteral()->handle())); |
| 3860 } else { |
| 3861 VisitForStackValue(prop->obj()); |
| 3862 VisitForAccumulatorValue(prop->key()); |
| 3863 } |
3803 __ ldr(r1, MemOperand(sp, 0)); | 3864 __ ldr(r1, MemOperand(sp, 0)); |
3804 __ push(r0); | 3865 __ push(r0); |
3805 EmitKeyedPropertyLoad(prop); | 3866 EmitKeyedPropertyLoad(prop); |
3806 } | 3867 } |
3807 } | 3868 } |
3808 | 3869 |
3809 // We need a second deoptimization point after loading the value | 3870 // We need a second deoptimization point after loading the value |
3810 // in case evaluating the property load my have a side effect. | 3871 // in case evaluating the property load my have a side effect. |
3811 if (assign_type == VARIABLE) { | 3872 if (assign_type == VARIABLE) { |
3812 PrepareForBailout(expr->expression(), TOS_REG); | 3873 PrepareForBailout(expr->expression(), TOS_REG); |
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4304 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 4365 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
4305 __ add(pc, r1, Operand(masm_->CodeObject())); | 4366 __ add(pc, r1, Operand(masm_->CodeObject())); |
4306 } | 4367 } |
4307 | 4368 |
4308 | 4369 |
4309 #undef __ | 4370 #undef __ |
4310 | 4371 |
4311 } } // namespace v8::internal | 4372 } } // namespace v8::internal |
4312 | 4373 |
4313 #endif // V8_TARGET_ARCH_ARM | 4374 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |