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 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 __ lea(rdx, | 219 __ lea(rdx, |
220 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); | 220 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); |
221 __ push(rdx); | 221 __ push(rdx); |
222 __ Push(Smi::FromInt(scope()->num_parameters())); | 222 __ Push(Smi::FromInt(scope()->num_parameters())); |
223 // Arguments to ArgumentsAccessStub: | 223 // Arguments to ArgumentsAccessStub: |
224 // function, receiver address, parameter count. | 224 // function, receiver address, parameter count. |
225 // The stub will rewrite receiver and parameter count if the previous | 225 // The stub will rewrite receiver and parameter count if the previous |
226 // stack frame was an arguments adapter frame. | 226 // stack frame was an arguments adapter frame. |
227 ArgumentsAccessStub stub( | 227 ArgumentsAccessStub stub( |
228 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT | 228 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT |
229 : ArgumentsAccessStub::NEW_NON_STRICT_SLOW); | 229 : ArgumentsAccessStub::NEW_NON_STRICT); |
230 __ CallStub(&stub); | 230 __ CallStub(&stub); |
231 | 231 |
| 232 Variable* arguments_shadow = scope()->arguments_shadow(); |
| 233 if (arguments_shadow != NULL) { |
| 234 // Store new arguments object in both "arguments" and ".arguments" slots. |
| 235 __ movq(rcx, rax); |
| 236 Move(arguments_shadow->AsSlot(), rcx, rbx, rdx); |
| 237 } |
232 Move(arguments->AsSlot(), rax, rbx, rdx); | 238 Move(arguments->AsSlot(), rax, rbx, rdx); |
233 } | 239 } |
234 | 240 |
235 if (FLAG_trace) { | 241 if (FLAG_trace) { |
236 __ CallRuntime(Runtime::kTraceEnter, 0); | 242 __ CallRuntime(Runtime::kTraceEnter, 0); |
237 } | 243 } |
238 | 244 |
239 // Visit the declarations and body unless there is an illegal | 245 // Visit the declarations and body unless there is an illegal |
240 // redeclaration. | 246 // redeclaration. |
241 if (scope()->HasIllegalRedeclaration()) { | 247 if (scope()->HasIllegalRedeclaration()) { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 | 370 |
365 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { | 371 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { |
366 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); | 372 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); |
367 __ push(slot_operand); | 373 __ push(slot_operand); |
368 } | 374 } |
369 | 375 |
370 | 376 |
371 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { | 377 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { |
372 codegen()->Move(result_register(), slot); | 378 codegen()->Move(result_register(), slot); |
373 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 379 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
374 codegen()->DoTest(true_label_, false_label_, fall_through_); | 380 codegen()->DoTest(this); |
375 } | 381 } |
376 | 382 |
377 | 383 |
378 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { | 384 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { |
379 } | 385 } |
380 | 386 |
381 | 387 |
382 void FullCodeGenerator::AccumulatorValueContext::Plug( | 388 void FullCodeGenerator::AccumulatorValueContext::Plug( |
383 Heap::RootListIndex index) const { | 389 Heap::RootListIndex index) const { |
384 __ LoadRoot(result_register(), index); | 390 __ LoadRoot(result_register(), index); |
(...skipping 12 matching lines...) Expand all Loading... |
397 true_label_, | 403 true_label_, |
398 false_label_); | 404 false_label_); |
399 if (index == Heap::kUndefinedValueRootIndex || | 405 if (index == Heap::kUndefinedValueRootIndex || |
400 index == Heap::kNullValueRootIndex || | 406 index == Heap::kNullValueRootIndex || |
401 index == Heap::kFalseValueRootIndex) { | 407 index == Heap::kFalseValueRootIndex) { |
402 if (false_label_ != fall_through_) __ jmp(false_label_); | 408 if (false_label_ != fall_through_) __ jmp(false_label_); |
403 } else if (index == Heap::kTrueValueRootIndex) { | 409 } else if (index == Heap::kTrueValueRootIndex) { |
404 if (true_label_ != fall_through_) __ jmp(true_label_); | 410 if (true_label_ != fall_through_) __ jmp(true_label_); |
405 } else { | 411 } else { |
406 __ LoadRoot(result_register(), index); | 412 __ LoadRoot(result_register(), index); |
407 codegen()->DoTest(true_label_, false_label_, fall_through_); | 413 codegen()->DoTest(this); |
408 } | 414 } |
409 } | 415 } |
410 | 416 |
411 | 417 |
412 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { | 418 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { |
413 } | 419 } |
414 | 420 |
415 | 421 |
416 void FullCodeGenerator::AccumulatorValueContext::Plug( | 422 void FullCodeGenerator::AccumulatorValueContext::Plug( |
417 Handle<Object> lit) const { | 423 Handle<Object> lit) const { |
(...skipping 24 matching lines...) Expand all Loading... |
442 } | 448 } |
443 } else if (lit->IsSmi()) { | 449 } else if (lit->IsSmi()) { |
444 if (Smi::cast(*lit)->value() == 0) { | 450 if (Smi::cast(*lit)->value() == 0) { |
445 if (false_label_ != fall_through_) __ jmp(false_label_); | 451 if (false_label_ != fall_through_) __ jmp(false_label_); |
446 } else { | 452 } else { |
447 if (true_label_ != fall_through_) __ jmp(true_label_); | 453 if (true_label_ != fall_through_) __ jmp(true_label_); |
448 } | 454 } |
449 } else { | 455 } else { |
450 // For simplicity we always test the accumulator register. | 456 // For simplicity we always test the accumulator register. |
451 __ Move(result_register(), lit); | 457 __ Move(result_register(), lit); |
452 codegen()->DoTest(true_label_, false_label_, fall_through_); | 458 codegen()->DoTest(this); |
453 } | 459 } |
454 } | 460 } |
455 | 461 |
456 | 462 |
457 void FullCodeGenerator::EffectContext::DropAndPlug(int count, | 463 void FullCodeGenerator::EffectContext::DropAndPlug(int count, |
458 Register reg) const { | 464 Register reg) const { |
459 ASSERT(count > 0); | 465 ASSERT(count > 0); |
460 __ Drop(count); | 466 __ Drop(count); |
461 } | 467 } |
462 | 468 |
(...skipping 15 matching lines...) Expand all Loading... |
478 } | 484 } |
479 | 485 |
480 | 486 |
481 void FullCodeGenerator::TestContext::DropAndPlug(int count, | 487 void FullCodeGenerator::TestContext::DropAndPlug(int count, |
482 Register reg) const { | 488 Register reg) const { |
483 ASSERT(count > 0); | 489 ASSERT(count > 0); |
484 // For simplicity we always test the accumulator register. | 490 // For simplicity we always test the accumulator register. |
485 __ Drop(count); | 491 __ Drop(count); |
486 __ Move(result_register(), reg); | 492 __ Move(result_register(), reg); |
487 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 493 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
488 codegen()->DoTest(true_label_, false_label_, fall_through_); | 494 codegen()->DoTest(this); |
489 } | 495 } |
490 | 496 |
491 | 497 |
492 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, | 498 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, |
493 Label* materialize_false) const { | 499 Label* materialize_false) const { |
494 ASSERT(materialize_true == materialize_false); | 500 ASSERT(materialize_true == materialize_false); |
495 __ bind(materialize_true); | 501 __ bind(materialize_true); |
496 } | 502 } |
497 | 503 |
498 | 504 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 true_label_, | 559 true_label_, |
554 false_label_); | 560 false_label_); |
555 if (flag) { | 561 if (flag) { |
556 if (true_label_ != fall_through_) __ jmp(true_label_); | 562 if (true_label_ != fall_through_) __ jmp(true_label_); |
557 } else { | 563 } else { |
558 if (false_label_ != fall_through_) __ jmp(false_label_); | 564 if (false_label_ != fall_through_) __ jmp(false_label_); |
559 } | 565 } |
560 } | 566 } |
561 | 567 |
562 | 568 |
563 void FullCodeGenerator::DoTest(Label* if_true, | 569 void FullCodeGenerator::DoTest(Expression* condition, |
| 570 Label* if_true, |
564 Label* if_false, | 571 Label* if_false, |
565 Label* fall_through) { | 572 Label* fall_through) { |
566 ToBooleanStub stub; | 573 ToBooleanStub stub; |
567 __ push(result_register()); | 574 __ push(result_register()); |
568 __ CallStub(&stub); | 575 __ CallStub(&stub); |
569 __ testq(rax, rax); | 576 __ testq(rax, rax); |
570 // The stub returns nonzero for true. | 577 // The stub returns nonzero for true. |
571 Split(not_zero, if_true, if_false, fall_through); | 578 Split(not_zero, if_true, if_false, fall_through); |
572 } | 579 } |
573 | 580 |
(...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1207 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | 1214 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
1208 __ jmp(done); | 1215 __ jmp(done); |
1209 } | 1216 } |
1210 } | 1217 } |
1211 } | 1218 } |
1212 } | 1219 } |
1213 } | 1220 } |
1214 | 1221 |
1215 | 1222 |
1216 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1223 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
1217 // Three cases: non-this global variables, lookup slots, and all other | 1224 // Four cases: non-this global variables, lookup slots, all other |
1218 // types of slots. | 1225 // types of slots, and parameters that rewrite to explicit property |
| 1226 // accesses on the arguments object. |
1219 Slot* slot = var->AsSlot(); | 1227 Slot* slot = var->AsSlot(); |
1220 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); | 1228 Property* property = var->AsProperty(); |
1221 | 1229 |
1222 if (slot == NULL) { | 1230 if (var->is_global() && !var->is_this()) { |
1223 Comment cmnt(masm_, "Global variable"); | 1231 Comment cmnt(masm_, "Global variable"); |
1224 // Use inline caching. Variable name is passed in rcx and the global | 1232 // Use inline caching. Variable name is passed in rcx and the global |
1225 // object on the stack. | 1233 // object on the stack. |
1226 __ Move(rcx, var->name()); | 1234 __ Move(rcx, var->name()); |
1227 __ movq(rax, GlobalObjectOperand()); | 1235 __ movq(rax, GlobalObjectOperand()); |
1228 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1236 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
1229 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); | 1237 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); |
1230 context()->Plug(rax); | 1238 context()->Plug(rax); |
1231 | 1239 |
1232 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1240 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
1233 Label done, slow; | 1241 Label done, slow; |
1234 | 1242 |
1235 // Generate code for loading from variables potentially shadowed | 1243 // Generate code for loading from variables potentially shadowed |
1236 // by eval-introduced variables. | 1244 // by eval-introduced variables. |
1237 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1245 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
1238 | 1246 |
1239 __ bind(&slow); | 1247 __ bind(&slow); |
1240 Comment cmnt(masm_, "Lookup slot"); | 1248 Comment cmnt(masm_, "Lookup slot"); |
1241 __ push(rsi); // Context. | 1249 __ push(rsi); // Context. |
1242 __ Push(var->name()); | 1250 __ Push(var->name()); |
1243 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1251 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
1244 __ bind(&done); | 1252 __ bind(&done); |
1245 | 1253 |
1246 context()->Plug(rax); | 1254 context()->Plug(rax); |
1247 | 1255 |
1248 } else { | 1256 } else if (slot != NULL) { |
1249 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1257 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
1250 ? "Context slot" | 1258 ? "Context slot" |
1251 : "Stack slot"); | 1259 : "Stack slot"); |
1252 if (var->mode() == Variable::CONST) { | 1260 if (var->mode() == Variable::CONST) { |
1253 // Constants may be the hole value if they have not been initialized. | 1261 // Constants may be the hole value if they have not been initialized. |
1254 // Unhole them. | 1262 // Unhole them. |
1255 Label done; | 1263 Label done; |
1256 MemOperand slot_operand = EmitSlotSearch(slot, rax); | 1264 MemOperand slot_operand = EmitSlotSearch(slot, rax); |
1257 __ movq(rax, slot_operand); | 1265 __ movq(rax, slot_operand); |
1258 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1266 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
1259 __ j(not_equal, &done, Label::kNear); | 1267 __ j(not_equal, &done, Label::kNear); |
1260 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1268 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
1261 __ bind(&done); | 1269 __ bind(&done); |
1262 context()->Plug(rax); | 1270 context()->Plug(rax); |
1263 } else { | 1271 } else { |
1264 context()->Plug(slot); | 1272 context()->Plug(slot); |
1265 } | 1273 } |
| 1274 |
| 1275 } else { |
| 1276 Comment cmnt(masm_, "Rewritten parameter"); |
| 1277 ASSERT_NOT_NULL(property); |
| 1278 // Rewritten parameter accesses are of the form "slot[literal]". |
| 1279 |
| 1280 // Assert that the object is in a slot. |
| 1281 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); |
| 1282 ASSERT_NOT_NULL(object_var); |
| 1283 Slot* object_slot = object_var->AsSlot(); |
| 1284 ASSERT_NOT_NULL(object_slot); |
| 1285 |
| 1286 // Load the object. |
| 1287 MemOperand object_loc = EmitSlotSearch(object_slot, rax); |
| 1288 __ movq(rdx, object_loc); |
| 1289 |
| 1290 // Assert that the key is a smi. |
| 1291 Literal* key_literal = property->key()->AsLiteral(); |
| 1292 ASSERT_NOT_NULL(key_literal); |
| 1293 ASSERT(key_literal->handle()->IsSmi()); |
| 1294 |
| 1295 // Load the key. |
| 1296 __ Move(rax, key_literal->handle()); |
| 1297 |
| 1298 // Do a keyed property load. |
| 1299 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1300 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
| 1301 context()->Plug(rax); |
1266 } | 1302 } |
1267 } | 1303 } |
1268 | 1304 |
1269 | 1305 |
1270 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1306 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
1271 Comment cmnt(masm_, "[ RegExpLiteral"); | 1307 Comment cmnt(masm_, "[ RegExpLiteral"); |
1272 Label materialized; | 1308 Label materialized; |
1273 // Registers will be used as follows: | 1309 // Registers will be used as follows: |
1274 // rdi = JS function. | 1310 // rdi = JS function. |
1275 // rcx = literals array. | 1311 // rcx = literals array. |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1488 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1524 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
1489 Comment cmnt(masm_, "[ Assignment"); | 1525 Comment cmnt(masm_, "[ Assignment"); |
1490 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1526 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
1491 // on the left-hand side. | 1527 // on the left-hand side. |
1492 if (!expr->target()->IsValidLeftHandSide()) { | 1528 if (!expr->target()->IsValidLeftHandSide()) { |
1493 VisitForEffect(expr->target()); | 1529 VisitForEffect(expr->target()); |
1494 return; | 1530 return; |
1495 } | 1531 } |
1496 | 1532 |
1497 // Left-hand side can only be a property, a global or a (parameter or local) | 1533 // Left-hand side can only be a property, a global or a (parameter or local) |
1498 // slot. | 1534 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
1499 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1535 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
1500 LhsKind assign_type = VARIABLE; | 1536 LhsKind assign_type = VARIABLE; |
1501 Property* property = expr->target()->AsProperty(); | 1537 Property* property = expr->target()->AsProperty(); |
1502 if (property != NULL) { | 1538 if (property != NULL) { |
1503 assign_type = (property->key()->IsPropertyName()) | 1539 assign_type = (property->key()->IsPropertyName()) |
1504 ? NAMED_PROPERTY | 1540 ? NAMED_PROPERTY |
1505 : KEYED_PROPERTY; | 1541 : KEYED_PROPERTY; |
1506 } | 1542 } |
1507 | 1543 |
1508 // Evaluate LHS expression. | 1544 // Evaluate LHS expression. |
1509 switch (assign_type) { | 1545 switch (assign_type) { |
1510 case VARIABLE: | 1546 case VARIABLE: |
1511 // Nothing to do here. | 1547 // Nothing to do here. |
1512 break; | 1548 break; |
1513 case NAMED_PROPERTY: | 1549 case NAMED_PROPERTY: |
1514 if (expr->is_compound()) { | 1550 if (expr->is_compound()) { |
1515 // We need the receiver both on the stack and in the accumulator. | 1551 // We need the receiver both on the stack and in the accumulator. |
1516 VisitForAccumulatorValue(property->obj()); | 1552 VisitForAccumulatorValue(property->obj()); |
1517 __ push(result_register()); | 1553 __ push(result_register()); |
1518 } else { | 1554 } else { |
1519 VisitForStackValue(property->obj()); | 1555 VisitForStackValue(property->obj()); |
1520 } | 1556 } |
1521 break; | 1557 break; |
1522 case KEYED_PROPERTY: { | 1558 case KEYED_PROPERTY: { |
1523 if (expr->is_compound()) { | 1559 if (expr->is_compound()) { |
1524 VisitForStackValue(property->obj()); | 1560 if (property->is_arguments_access()) { |
1525 VisitForAccumulatorValue(property->key()); | 1561 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1562 MemOperand slot_operand = |
| 1563 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); |
| 1564 __ push(slot_operand); |
| 1565 __ Move(rax, property->key()->AsLiteral()->handle()); |
| 1566 } else { |
| 1567 VisitForStackValue(property->obj()); |
| 1568 VisitForAccumulatorValue(property->key()); |
| 1569 } |
1526 __ movq(rdx, Operand(rsp, 0)); | 1570 __ movq(rdx, Operand(rsp, 0)); |
1527 __ push(rax); | 1571 __ push(rax); |
1528 } else { | 1572 } else { |
1529 VisitForStackValue(property->obj()); | 1573 if (property->is_arguments_access()) { |
1530 VisitForStackValue(property->key()); | 1574 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); |
| 1575 MemOperand slot_operand = |
| 1576 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); |
| 1577 __ push(slot_operand); |
| 1578 __ Push(property->key()->AsLiteral()->handle()); |
| 1579 } else { |
| 1580 VisitForStackValue(property->obj()); |
| 1581 VisitForStackValue(property->key()); |
| 1582 } |
1531 } | 1583 } |
1532 break; | 1584 break; |
1533 } | 1585 } |
1534 } | 1586 } |
1535 | 1587 |
1536 // For compound assignments we need another deoptimization point after the | 1588 // For compound assignments we need another deoptimization point after the |
1537 // variable/property load. | 1589 // variable/property load. |
1538 if (expr->is_compound()) { | 1590 if (expr->is_compound()) { |
1539 { AccumulatorValueContext context(this); | 1591 { AccumulatorValueContext context(this); |
1540 switch (assign_type) { | 1592 switch (assign_type) { |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1687 | 1739 |
1688 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1740 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
1689 // Invalid left-hand sides are rewritten to have a 'throw | 1741 // Invalid left-hand sides are rewritten to have a 'throw |
1690 // ReferenceError' on the left-hand side. | 1742 // ReferenceError' on the left-hand side. |
1691 if (!expr->IsValidLeftHandSide()) { | 1743 if (!expr->IsValidLeftHandSide()) { |
1692 VisitForEffect(expr); | 1744 VisitForEffect(expr); |
1693 return; | 1745 return; |
1694 } | 1746 } |
1695 | 1747 |
1696 // Left-hand side can only be a property, a global or a (parameter or local) | 1748 // Left-hand side can only be a property, a global or a (parameter or local) |
1697 // slot. | 1749 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
1698 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1750 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
1699 LhsKind assign_type = VARIABLE; | 1751 LhsKind assign_type = VARIABLE; |
1700 Property* prop = expr->AsProperty(); | 1752 Property* prop = expr->AsProperty(); |
1701 if (prop != NULL) { | 1753 if (prop != NULL) { |
1702 assign_type = (prop->key()->IsPropertyName()) | 1754 assign_type = (prop->key()->IsPropertyName()) |
1703 ? NAMED_PROPERTY | 1755 ? NAMED_PROPERTY |
1704 : KEYED_PROPERTY; | 1756 : KEYED_PROPERTY; |
1705 } | 1757 } |
1706 | 1758 |
1707 switch (assign_type) { | 1759 switch (assign_type) { |
(...skipping 10 matching lines...) Expand all Loading... |
1718 __ pop(rax); // Restore value. | 1770 __ pop(rax); // Restore value. |
1719 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1771 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
1720 Handle<Code> ic = is_strict_mode() | 1772 Handle<Code> ic = is_strict_mode() |
1721 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1773 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
1722 : isolate()->builtins()->StoreIC_Initialize(); | 1774 : isolate()->builtins()->StoreIC_Initialize(); |
1723 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 1775 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); |
1724 break; | 1776 break; |
1725 } | 1777 } |
1726 case KEYED_PROPERTY: { | 1778 case KEYED_PROPERTY: { |
1727 __ push(rax); // Preserve value. | 1779 __ push(rax); // Preserve value. |
1728 VisitForStackValue(prop->obj()); | 1780 if (prop->is_synthetic()) { |
1729 VisitForAccumulatorValue(prop->key()); | 1781 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
1730 __ movq(rcx, rax); | 1782 ASSERT(prop->key()->AsLiteral() != NULL); |
1731 __ pop(rdx); | 1783 { AccumulatorValueContext for_object(this); |
| 1784 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); |
| 1785 } |
| 1786 __ movq(rdx, rax); |
| 1787 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 1788 } else { |
| 1789 VisitForStackValue(prop->obj()); |
| 1790 VisitForAccumulatorValue(prop->key()); |
| 1791 __ movq(rcx, rax); |
| 1792 __ pop(rdx); |
| 1793 } |
1732 __ pop(rax); // Restore value. | 1794 __ pop(rax); // Restore value. |
1733 Handle<Code> ic = is_strict_mode() | 1795 Handle<Code> ic = is_strict_mode() |
1734 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 1796 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
1735 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 1797 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
1736 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 1798 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); |
1737 break; | 1799 break; |
1738 } | 1800 } |
1739 } | 1801 } |
1740 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1802 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
1741 context()->Plug(rax); | 1803 context()->Plug(rax); |
1742 } | 1804 } |
1743 | 1805 |
1744 | 1806 |
1745 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1807 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
1746 Token::Value op) { | 1808 Token::Value op) { |
| 1809 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 1810 // here. |
1747 ASSERT(var != NULL); | 1811 ASSERT(var != NULL); |
1748 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1812 ASSERT(var->is_global() || var->AsSlot() != NULL); |
1749 | 1813 |
1750 if (var->is_global()) { | 1814 if (var->is_global()) { |
1751 ASSERT(!var->is_this()); | 1815 ASSERT(!var->is_this()); |
1752 // Assignment to a global variable. Use inline caching for the | 1816 // Assignment to a global variable. Use inline caching for the |
1753 // assignment. Right-hand-side value is passed in rax, variable name in | 1817 // assignment. Right-hand-side value is passed in rax, variable name in |
1754 // rcx, and the global object on the stack. | 1818 // rcx, and the global object on the stack. |
1755 __ Move(rcx, var->name()); | 1819 __ Move(rcx, var->name()); |
1756 __ movq(rdx, GlobalObjectOperand()); | 1820 __ movq(rdx, GlobalObjectOperand()); |
(...skipping 1934 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3691 SetSourcePosition(expr->position()); | 3755 SetSourcePosition(expr->position()); |
3692 | 3756 |
3693 // Invalid left-hand-sides are rewritten to have a 'throw | 3757 // Invalid left-hand-sides are rewritten to have a 'throw |
3694 // ReferenceError' as the left-hand side. | 3758 // ReferenceError' as the left-hand side. |
3695 if (!expr->expression()->IsValidLeftHandSide()) { | 3759 if (!expr->expression()->IsValidLeftHandSide()) { |
3696 VisitForEffect(expr->expression()); | 3760 VisitForEffect(expr->expression()); |
3697 return; | 3761 return; |
3698 } | 3762 } |
3699 | 3763 |
3700 // Expression can only be a property, a global or a (parameter or local) | 3764 // Expression can only be a property, a global or a (parameter or local) |
3701 // slot. | 3765 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
3702 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 3766 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
3703 LhsKind assign_type = VARIABLE; | 3767 LhsKind assign_type = VARIABLE; |
3704 Property* prop = expr->expression()->AsProperty(); | 3768 Property* prop = expr->expression()->AsProperty(); |
3705 // In case of a property we use the uninitialized expression context | 3769 // In case of a property we use the uninitialized expression context |
3706 // of the key to detect a named property. | 3770 // of the key to detect a named property. |
3707 if (prop != NULL) { | 3771 if (prop != NULL) { |
3708 assign_type = | 3772 assign_type = |
3709 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 3773 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
3710 } | 3774 } |
3711 | 3775 |
3712 // Evaluate expression and get value. | 3776 // Evaluate expression and get value. |
3713 if (assign_type == VARIABLE) { | 3777 if (assign_type == VARIABLE) { |
3714 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 3778 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
3715 AccumulatorValueContext context(this); | 3779 AccumulatorValueContext context(this); |
3716 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); | 3780 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); |
3717 } else { | 3781 } else { |
3718 // Reserve space for result of postfix operation. | 3782 // Reserve space for result of postfix operation. |
3719 if (expr->is_postfix() && !context()->IsEffect()) { | 3783 if (expr->is_postfix() && !context()->IsEffect()) { |
3720 __ Push(Smi::FromInt(0)); | 3784 __ Push(Smi::FromInt(0)); |
3721 } | 3785 } |
3722 if (assign_type == NAMED_PROPERTY) { | 3786 if (assign_type == NAMED_PROPERTY) { |
3723 VisitForAccumulatorValue(prop->obj()); | 3787 VisitForAccumulatorValue(prop->obj()); |
3724 __ push(rax); // Copy of receiver, needed for later store. | 3788 __ push(rax); // Copy of receiver, needed for later store. |
3725 EmitNamedPropertyLoad(prop); | 3789 EmitNamedPropertyLoad(prop); |
3726 } else { | 3790 } else { |
3727 VisitForStackValue(prop->obj()); | 3791 if (prop->is_arguments_access()) { |
3728 VisitForAccumulatorValue(prop->key()); | 3792 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); |
| 3793 MemOperand slot_operand = |
| 3794 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); |
| 3795 __ push(slot_operand); |
| 3796 __ Move(rax, prop->key()->AsLiteral()->handle()); |
| 3797 } else { |
| 3798 VisitForStackValue(prop->obj()); |
| 3799 VisitForAccumulatorValue(prop->key()); |
| 3800 } |
3729 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack | 3801 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack |
3730 __ push(rax); // Copy of key, needed for later store. | 3802 __ push(rax); // Copy of key, needed for later store. |
3731 EmitKeyedPropertyLoad(prop); | 3803 EmitKeyedPropertyLoad(prop); |
3732 } | 3804 } |
3733 } | 3805 } |
3734 | 3806 |
3735 // We need a second deoptimization point after loading the value | 3807 // We need a second deoptimization point after loading the value |
3736 // in case evaluating the property load my have a side effect. | 3808 // in case evaluating the property load my have a side effect. |
3737 if (assign_type == VARIABLE) { | 3809 if (assign_type == VARIABLE) { |
3738 PrepareForBailout(expr->expression(), TOS_REG); | 3810 PrepareForBailout(expr->expression(), TOS_REG); |
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4237 __ ret(0); | 4309 __ ret(0); |
4238 } | 4310 } |
4239 | 4311 |
4240 | 4312 |
4241 #undef __ | 4313 #undef __ |
4242 | 4314 |
4243 | 4315 |
4244 } } // namespace v8::internal | 4316 } } // namespace v8::internal |
4245 | 4317 |
4246 #endif // V8_TARGET_ARCH_X64 | 4318 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |