OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 | 452 |
453 | 453 |
454 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { | 454 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { |
455 Heap::RootListIndex value_root_index = | 455 Heap::RootListIndex value_root_index = |
456 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; | 456 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; |
457 __ PushRoot(value_root_index); | 457 __ PushRoot(value_root_index); |
458 } | 458 } |
459 | 459 |
460 | 460 |
461 void FullCodeGenerator::TestContext::Plug(bool flag) const { | 461 void FullCodeGenerator::TestContext::Plug(bool flag) const { |
462 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 462 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, true, NULL, NULL); |
463 if (flag) { | 463 if (flag) { |
464 if (true_label_ != fall_through_) __ jmp(true_label_); | 464 if (true_label_ != fall_through_) __ jmp(true_label_); |
465 } else { | 465 } else { |
466 if (false_label_ != fall_through_) __ jmp(false_label_); | 466 if (false_label_ != fall_through_) __ jmp(false_label_); |
467 } | 467 } |
468 } | 468 } |
469 | 469 |
470 | 470 |
471 void FullCodeGenerator::DoTest(Label* if_true, | 471 void FullCodeGenerator::DoTest(Label* if_true, |
472 Label* if_false, | 472 Label* if_false, |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | 548 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; |
549 __ RecordWrite(scratch1, offset, src, scratch2); | 549 __ RecordWrite(scratch1, offset, src, scratch2); |
550 } | 550 } |
551 } | 551 } |
552 | 552 |
553 | 553 |
554 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 554 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
555 bool should_normalize, | 555 bool should_normalize, |
556 Label* if_true, | 556 Label* if_true, |
557 Label* if_false) { | 557 Label* if_false) { |
| 558 // Only prepare for bailouts before splits if we're in a test |
| 559 // context. Otherwise, we let the Visit function deal with the |
| 560 // preparation to avoid preparing with the same AST id twice. |
| 561 if (!context()->IsTest() || !info_->IsOptimizable()) return; |
| 562 |
| 563 NearLabel skip; |
| 564 if (should_normalize) __ jmp(&skip); |
| 565 |
| 566 ForwardBailoutStack* current = forward_bailout_stack_; |
| 567 while (current != NULL) { |
| 568 PrepareForBailout(current->expr(), state); |
| 569 current = current->parent(); |
| 570 } |
| 571 |
| 572 if (should_normalize) { |
| 573 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 574 Split(equal, if_true, if_false, NULL); |
| 575 __ bind(&skip); |
| 576 } |
558 } | 577 } |
559 | 578 |
560 | 579 |
561 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 580 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
562 Variable::Mode mode, | 581 Variable::Mode mode, |
563 FunctionLiteral* function) { | 582 FunctionLiteral* function) { |
564 Comment cmnt(masm_, "[ Declaration"); | 583 Comment cmnt(masm_, "[ Declaration"); |
565 ASSERT(variable != NULL); // Must have been resolved. | 584 ASSERT(variable != NULL); // Must have been resolved. |
566 Slot* slot = variable->AsSlot(); | 585 Slot* slot = variable->AsSlot(); |
567 Property* prop = variable->AsProperty(); | 586 Property* prop = variable->AsProperty(); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
662 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); | 681 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); |
663 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 682 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
664 // Return value is ignored. | 683 // Return value is ignored. |
665 } | 684 } |
666 | 685 |
667 | 686 |
668 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 687 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
669 Comment cmnt(masm_, "[ SwitchStatement"); | 688 Comment cmnt(masm_, "[ SwitchStatement"); |
670 Breakable nested_statement(this, stmt); | 689 Breakable nested_statement(this, stmt); |
671 SetStatementPosition(stmt); | 690 SetStatementPosition(stmt); |
| 691 |
672 // Keep the switch value on the stack until a case matches. | 692 // Keep the switch value on the stack until a case matches. |
673 VisitForStackValue(stmt->tag()); | 693 VisitForStackValue(stmt->tag()); |
| 694 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
674 | 695 |
675 ZoneList<CaseClause*>* clauses = stmt->cases(); | 696 ZoneList<CaseClause*>* clauses = stmt->cases(); |
676 CaseClause* default_clause = NULL; // Can occur anywhere in the list. | 697 CaseClause* default_clause = NULL; // Can occur anywhere in the list. |
677 | 698 |
678 Label next_test; // Recycled for each test. | 699 Label next_test; // Recycled for each test. |
679 // Compile all the tests with branches to their bodies. | 700 // Compile all the tests with branches to their bodies. |
680 for (int i = 0; i < clauses->length(); i++) { | 701 for (int i = 0; i < clauses->length(); i++) { |
681 CaseClause* clause = clauses->at(i); | 702 CaseClause* clause = clauses->at(i); |
682 // The default is not a test, but remember it as final fall through. | 703 // The default is not a test, but remember it as final fall through. |
683 if (clause->is_default()) { | 704 if (clause->is_default()) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
728 | 749 |
729 // Compile all the case bodies. | 750 // Compile all the case bodies. |
730 for (int i = 0; i < clauses->length(); i++) { | 751 for (int i = 0; i < clauses->length(); i++) { |
731 Comment cmnt(masm_, "[ Case body"); | 752 Comment cmnt(masm_, "[ Case body"); |
732 CaseClause* clause = clauses->at(i); | 753 CaseClause* clause = clauses->at(i); |
733 __ bind(clause->body_target()->entry_label()); | 754 __ bind(clause->body_target()->entry_label()); |
734 VisitStatements(clause->statements()); | 755 VisitStatements(clause->statements()); |
735 } | 756 } |
736 | 757 |
737 __ bind(nested_statement.break_target()); | 758 __ bind(nested_statement.break_target()); |
| 759 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
738 } | 760 } |
739 | 761 |
740 | 762 |
741 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 763 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
742 Comment cmnt(masm_, "[ ForInStatement"); | 764 Comment cmnt(masm_, "[ ForInStatement"); |
743 SetStatementPosition(stmt); | 765 SetStatementPosition(stmt); |
744 | 766 |
745 Label loop, exit; | 767 Label loop, exit; |
746 ForIn loop_statement(this, stmt); | 768 ForIn loop_statement(this, stmt); |
747 increment_loop_depth(); | 769 increment_loop_depth(); |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1217 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 1239 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
1218 // Fall through. | 1240 // Fall through. |
1219 case ObjectLiteral::Property::COMPUTED: | 1241 case ObjectLiteral::Property::COMPUTED: |
1220 if (key->handle()->IsSymbol()) { | 1242 if (key->handle()->IsSymbol()) { |
1221 VisitForAccumulatorValue(value); | 1243 VisitForAccumulatorValue(value); |
1222 __ Move(rcx, key->handle()); | 1244 __ Move(rcx, key->handle()); |
1223 __ movq(rdx, Operand(rsp, 0)); | 1245 __ movq(rdx, Operand(rsp, 0)); |
1224 if (property->emit_store()) { | 1246 if (property->emit_store()) { |
1225 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1247 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
1226 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1248 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1249 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
1227 } | 1250 } |
1228 break; | 1251 break; |
1229 } | 1252 } |
1230 // Fall through. | 1253 // Fall through. |
1231 case ObjectLiteral::Property::PROTOTYPE: | 1254 case ObjectLiteral::Property::PROTOTYPE: |
1232 __ push(Operand(rsp, 0)); // Duplicate receiver. | 1255 __ push(Operand(rsp, 0)); // Duplicate receiver. |
1233 VisitForStackValue(key); | 1256 VisitForStackValue(key); |
1234 VisitForStackValue(value); | 1257 VisitForStackValue(value); |
1235 if (property->emit_store()) { | 1258 if (property->emit_store()) { |
1236 __ CallRuntime(Runtime::kSetProperty, 3); | 1259 __ CallRuntime(Runtime::kSetProperty, 3); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1304 VisitForAccumulatorValue(subexpr); | 1327 VisitForAccumulatorValue(subexpr); |
1305 | 1328 |
1306 // Store the subexpression value in the array's elements. | 1329 // Store the subexpression value in the array's elements. |
1307 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 1330 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
1308 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 1331 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
1309 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1332 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
1310 __ movq(FieldOperand(rbx, offset), result_register()); | 1333 __ movq(FieldOperand(rbx, offset), result_register()); |
1311 | 1334 |
1312 // Update the write barrier for the array store. | 1335 // Update the write barrier for the array store. |
1313 __ RecordWrite(rbx, offset, result_register(), rcx); | 1336 __ RecordWrite(rbx, offset, result_register(), rcx); |
| 1337 |
| 1338 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
1314 } | 1339 } |
1315 | 1340 |
1316 if (result_saved) { | 1341 if (result_saved) { |
1317 context()->PlugTOS(); | 1342 context()->PlugTOS(); |
1318 } else { | 1343 } else { |
1319 context()->Plug(rax); | 1344 context()->Plug(rax); |
1320 } | 1345 } |
1321 } | 1346 } |
1322 | 1347 |
1323 | 1348 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1376 break; | 1401 break; |
1377 case NAMED_PROPERTY: | 1402 case NAMED_PROPERTY: |
1378 EmitNamedPropertyLoad(property); | 1403 EmitNamedPropertyLoad(property); |
1379 break; | 1404 break; |
1380 case KEYED_PROPERTY: | 1405 case KEYED_PROPERTY: |
1381 EmitKeyedPropertyLoad(property); | 1406 EmitKeyedPropertyLoad(property); |
1382 break; | 1407 break; |
1383 } | 1408 } |
1384 } | 1409 } |
1385 | 1410 |
| 1411 // For property compound assignments we need another deoptimization |
| 1412 // point after the property load. |
| 1413 if (property != NULL) { |
| 1414 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); |
| 1415 } |
| 1416 |
1386 Token::Value op = expr->binary_op(); | 1417 Token::Value op = expr->binary_op(); |
1387 ConstantOperand constant = ShouldInlineSmiCase(op) | 1418 ConstantOperand constant = ShouldInlineSmiCase(op) |
1388 ? GetConstantOperand(op, expr->target(), expr->value()) | 1419 ? GetConstantOperand(op, expr->target(), expr->value()) |
1389 : kNoConstants; | 1420 : kNoConstants; |
1390 ASSERT(constant == kRightConstant || constant == kNoConstants); | 1421 ASSERT(constant == kRightConstant || constant == kNoConstants); |
1391 if (constant == kNoConstants) { | 1422 if (constant == kNoConstants) { |
1392 __ push(rax); // Left operand goes on the stack. | 1423 __ push(rax); // Left operand goes on the stack. |
1393 VisitForAccumulatorValue(expr->value()); | 1424 VisitForAccumulatorValue(expr->value()); |
1394 } | 1425 } |
1395 | 1426 |
1396 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1427 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
1397 ? OVERWRITE_RIGHT | 1428 ? OVERWRITE_RIGHT |
1398 : NO_OVERWRITE; | 1429 : NO_OVERWRITE; |
1399 SetSourcePosition(expr->position() + 1); | 1430 SetSourcePosition(expr->position() + 1); |
1400 AccumulatorValueContext context(this); | 1431 AccumulatorValueContext context(this); |
1401 if (ShouldInlineSmiCase(op)) { | 1432 if (ShouldInlineSmiCase(op)) { |
1402 EmitInlineSmiBinaryOp(expr, | 1433 EmitInlineSmiBinaryOp(expr, |
1403 op, | 1434 op, |
1404 mode, | 1435 mode, |
1405 expr->target(), | 1436 expr->target(), |
1406 expr->value(), | 1437 expr->value(), |
1407 constant); | 1438 constant); |
1408 } else { | 1439 } else { |
1409 EmitBinaryOp(op, mode); | 1440 EmitBinaryOp(op, mode); |
1410 } | 1441 } |
| 1442 // Deoptimization point in case the binary operation may have side effects. |
| 1443 PrepareForBailout(expr->binary_operation(), TOS_REG); |
1411 } else { | 1444 } else { |
1412 VisitForAccumulatorValue(expr->value()); | 1445 VisitForAccumulatorValue(expr->value()); |
1413 } | 1446 } |
1414 | 1447 |
1415 // Record source position before possible IC call. | 1448 // Record source position before possible IC call. |
1416 SetSourcePosition(expr->position()); | 1449 SetSourcePosition(expr->position()); |
1417 | 1450 |
1418 // Store the value. | 1451 // Store the value. |
1419 switch (assign_type) { | 1452 switch (assign_type) { |
1420 case VARIABLE: | 1453 case VARIABLE: |
1421 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), | 1454 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), |
1422 expr->op()); | 1455 expr->op()); |
| 1456 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
1423 context()->Plug(rax); | 1457 context()->Plug(rax); |
1424 break; | 1458 break; |
1425 case NAMED_PROPERTY: | 1459 case NAMED_PROPERTY: |
1426 EmitNamedPropertyAssignment(expr); | 1460 EmitNamedPropertyAssignment(expr); |
1427 break; | 1461 break; |
1428 case KEYED_PROPERTY: | 1462 case KEYED_PROPERTY: |
1429 EmitKeyedPropertyAssignment(expr); | 1463 EmitKeyedPropertyAssignment(expr); |
1430 break; | 1464 break; |
1431 } | 1465 } |
1432 } | 1466 } |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1522 __ pop(rdx); | 1556 __ pop(rdx); |
1523 stub.GenerateCall(masm_, rdx, rax); | 1557 stub.GenerateCall(masm_, rdx, rax); |
1524 } else { | 1558 } else { |
1525 __ push(result_register()); | 1559 __ push(result_register()); |
1526 __ CallStub(&stub); | 1560 __ CallStub(&stub); |
1527 } | 1561 } |
1528 context()->Plug(rax); | 1562 context()->Plug(rax); |
1529 } | 1563 } |
1530 | 1564 |
1531 | 1565 |
1532 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_id) { | 1566 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
1533 // Invalid left-hand sides are rewritten to have a 'throw | 1567 // Invalid left-hand sides are rewritten to have a 'throw |
1534 // ReferenceError' on the left-hand side. | 1568 // ReferenceError' on the left-hand side. |
1535 if (!expr->IsValidLeftHandSide()) { | 1569 if (!expr->IsValidLeftHandSide()) { |
1536 VisitForEffect(expr); | 1570 VisitForEffect(expr); |
1537 return; | 1571 return; |
1538 } | 1572 } |
1539 | 1573 |
1540 // Left-hand side can only be a property, a global or a (parameter or local) | 1574 // Left-hand side can only be a property, a global or a (parameter or local) |
1541 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1575 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
1542 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1576 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
(...skipping 27 matching lines...) Expand all Loading... |
1570 VisitForStackValue(prop->obj()); | 1604 VisitForStackValue(prop->obj()); |
1571 VisitForAccumulatorValue(prop->key()); | 1605 VisitForAccumulatorValue(prop->key()); |
1572 __ movq(rcx, rax); | 1606 __ movq(rcx, rax); |
1573 __ pop(rdx); | 1607 __ pop(rdx); |
1574 __ pop(rax); | 1608 __ pop(rax); |
1575 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1609 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
1576 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1610 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
1577 break; | 1611 break; |
1578 } | 1612 } |
1579 } | 1613 } |
| 1614 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
1580 context()->Plug(rax); | 1615 context()->Plug(rax); |
1581 } | 1616 } |
1582 | 1617 |
1583 | 1618 |
1584 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1619 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
1585 Token::Value op) { | 1620 Token::Value op) { |
1586 // Left-hand sides that rewrite to explicit property accesses do not reach | 1621 // Left-hand sides that rewrite to explicit property accesses do not reach |
1587 // here. | 1622 // here. |
1588 ASSERT(var != NULL); | 1623 ASSERT(var != NULL); |
1589 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1624 ASSERT(var->is_global() || var->AsSlot() != NULL); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1681 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1716 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
1682 | 1717 |
1683 // If the assignment ends an initialization block, revert to fast case. | 1718 // If the assignment ends an initialization block, revert to fast case. |
1684 if (expr->ends_initialization_block()) { | 1719 if (expr->ends_initialization_block()) { |
1685 __ push(rax); // Result of assignment, saved even if not needed. | 1720 __ push(rax); // Result of assignment, saved even if not needed. |
1686 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1721 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
1687 __ CallRuntime(Runtime::kToFastProperties, 1); | 1722 __ CallRuntime(Runtime::kToFastProperties, 1); |
1688 __ pop(rax); | 1723 __ pop(rax); |
1689 __ Drop(1); | 1724 __ Drop(1); |
1690 } | 1725 } |
| 1726 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
1691 context()->Plug(rax); | 1727 context()->Plug(rax); |
1692 } | 1728 } |
1693 | 1729 |
1694 | 1730 |
1695 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1731 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
1696 // Assignment to a property, using a keyed store IC. | 1732 // Assignment to a property, using a keyed store IC. |
1697 | 1733 |
1698 // If the assignment starts a block of assignments to the same object, | 1734 // If the assignment starts a block of assignments to the same object, |
1699 // change to slow case to avoid the quadratic behavior of repeatedly | 1735 // change to slow case to avoid the quadratic behavior of repeatedly |
1700 // adding fast properties. | 1736 // adding fast properties. |
(...skipping 18 matching lines...) Expand all Loading... |
1719 | 1755 |
1720 // If the assignment ends an initialization block, revert to fast case. | 1756 // If the assignment ends an initialization block, revert to fast case. |
1721 if (expr->ends_initialization_block()) { | 1757 if (expr->ends_initialization_block()) { |
1722 __ pop(rdx); | 1758 __ pop(rdx); |
1723 __ push(rax); // Result of assignment, saved even if not needed. | 1759 __ push(rax); // Result of assignment, saved even if not needed. |
1724 __ push(rdx); | 1760 __ push(rdx); |
1725 __ CallRuntime(Runtime::kToFastProperties, 1); | 1761 __ CallRuntime(Runtime::kToFastProperties, 1); |
1726 __ pop(rax); | 1762 __ pop(rax); |
1727 } | 1763 } |
1728 | 1764 |
| 1765 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
1729 context()->Plug(rax); | 1766 context()->Plug(rax); |
1730 } | 1767 } |
1731 | 1768 |
1732 | 1769 |
1733 void FullCodeGenerator::VisitProperty(Property* expr) { | 1770 void FullCodeGenerator::VisitProperty(Property* expr) { |
1734 Comment cmnt(masm_, "[ Property"); | 1771 Comment cmnt(masm_, "[ Property"); |
1735 Expression* key = expr->key(); | 1772 Expression* key = expr->key(); |
1736 | 1773 |
1737 if (key->IsPropertyName()) { | 1774 if (key->IsPropertyName()) { |
1738 VisitForAccumulatorValue(expr->obj()); | 1775 VisitForAccumulatorValue(expr->obj()); |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2016 | 2053 |
2017 VisitForAccumulatorValue(args->at(0)); | 2054 VisitForAccumulatorValue(args->at(0)); |
2018 | 2055 |
2019 Label materialize_true, materialize_false; | 2056 Label materialize_true, materialize_false; |
2020 Label* if_true = NULL; | 2057 Label* if_true = NULL; |
2021 Label* if_false = NULL; | 2058 Label* if_false = NULL; |
2022 Label* fall_through = NULL; | 2059 Label* fall_through = NULL; |
2023 context()->PrepareTest(&materialize_true, &materialize_false, | 2060 context()->PrepareTest(&materialize_true, &materialize_false, |
2024 &if_true, &if_false, &fall_through); | 2061 &if_true, &if_false, &fall_through); |
2025 | 2062 |
| 2063 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2026 __ JumpIfSmi(rax, if_true); | 2064 __ JumpIfSmi(rax, if_true); |
2027 __ jmp(if_false); | 2065 __ jmp(if_false); |
2028 | 2066 |
2029 context()->Plug(if_true, if_false); | 2067 context()->Plug(if_true, if_false); |
2030 } | 2068 } |
2031 | 2069 |
2032 | 2070 |
2033 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { | 2071 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { |
2034 ASSERT(args->length() == 1); | 2072 ASSERT(args->length() == 1); |
2035 | 2073 |
2036 VisitForAccumulatorValue(args->at(0)); | 2074 VisitForAccumulatorValue(args->at(0)); |
2037 | 2075 |
2038 Label materialize_true, materialize_false; | 2076 Label materialize_true, materialize_false; |
2039 Label* if_true = NULL; | 2077 Label* if_true = NULL; |
2040 Label* if_false = NULL; | 2078 Label* if_false = NULL; |
2041 Label* fall_through = NULL; | 2079 Label* fall_through = NULL; |
2042 context()->PrepareTest(&materialize_true, &materialize_false, | 2080 context()->PrepareTest(&materialize_true, &materialize_false, |
2043 &if_true, &if_false, &fall_through); | 2081 &if_true, &if_false, &fall_through); |
2044 | 2082 |
| 2083 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2045 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax); | 2084 Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax); |
2046 Split(non_negative_smi, if_true, if_false, fall_through); | 2085 Split(non_negative_smi, if_true, if_false, fall_through); |
2047 | 2086 |
2048 context()->Plug(if_true, if_false); | 2087 context()->Plug(if_true, if_false); |
2049 } | 2088 } |
2050 | 2089 |
2051 | 2090 |
2052 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { | 2091 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { |
2053 ASSERT(args->length() == 1); | 2092 ASSERT(args->length() == 1); |
2054 | 2093 |
(...skipping 11 matching lines...) Expand all Loading... |
2066 __ j(equal, if_true); | 2105 __ j(equal, if_true); |
2067 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 2106 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
2068 // Undetectable objects behave like undefined when tested with typeof. | 2107 // Undetectable objects behave like undefined when tested with typeof. |
2069 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2108 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
2070 Immediate(1 << Map::kIsUndetectable)); | 2109 Immediate(1 << Map::kIsUndetectable)); |
2071 __ j(not_zero, if_false); | 2110 __ j(not_zero, if_false); |
2072 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 2111 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
2073 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); | 2112 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); |
2074 __ j(below, if_false); | 2113 __ j(below, if_false); |
2075 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); | 2114 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); |
| 2115 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2076 Split(below_equal, if_true, if_false, fall_through); | 2116 Split(below_equal, if_true, if_false, fall_through); |
2077 | 2117 |
2078 context()->Plug(if_true, if_false); | 2118 context()->Plug(if_true, if_false); |
2079 } | 2119 } |
2080 | 2120 |
2081 | 2121 |
2082 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { | 2122 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { |
2083 ASSERT(args->length() == 1); | 2123 ASSERT(args->length() == 1); |
2084 | 2124 |
2085 VisitForAccumulatorValue(args->at(0)); | 2125 VisitForAccumulatorValue(args->at(0)); |
2086 | 2126 |
2087 Label materialize_true, materialize_false; | 2127 Label materialize_true, materialize_false; |
2088 Label* if_true = NULL; | 2128 Label* if_true = NULL; |
2089 Label* if_false = NULL; | 2129 Label* if_false = NULL; |
2090 Label* fall_through = NULL; | 2130 Label* fall_through = NULL; |
2091 context()->PrepareTest(&materialize_true, &materialize_false, | 2131 context()->PrepareTest(&materialize_true, &materialize_false, |
2092 &if_true, &if_false, &fall_through); | 2132 &if_true, &if_false, &fall_through); |
2093 | 2133 |
2094 __ JumpIfSmi(rax, if_false); | 2134 __ JumpIfSmi(rax, if_false); |
2095 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 2135 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); |
| 2136 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2096 Split(above_equal, if_true, if_false, fall_through); | 2137 Split(above_equal, if_true, if_false, fall_through); |
2097 | 2138 |
2098 context()->Plug(if_true, if_false); | 2139 context()->Plug(if_true, if_false); |
2099 } | 2140 } |
2100 | 2141 |
2101 | 2142 |
2102 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { | 2143 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { |
2103 ASSERT(args->length() == 1); | 2144 ASSERT(args->length() == 1); |
2104 | 2145 |
2105 VisitForAccumulatorValue(args->at(0)); | 2146 VisitForAccumulatorValue(args->at(0)); |
2106 | 2147 |
2107 Label materialize_true, materialize_false; | 2148 Label materialize_true, materialize_false; |
2108 Label* if_true = NULL; | 2149 Label* if_true = NULL; |
2109 Label* if_false = NULL; | 2150 Label* if_false = NULL; |
2110 Label* fall_through = NULL; | 2151 Label* fall_through = NULL; |
2111 context()->PrepareTest(&materialize_true, &materialize_false, | 2152 context()->PrepareTest(&materialize_true, &materialize_false, |
2112 &if_true, &if_false, &fall_through); | 2153 &if_true, &if_false, &fall_through); |
2113 | 2154 |
2114 __ JumpIfSmi(rax, if_false); | 2155 __ JumpIfSmi(rax, if_false); |
2115 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 2156 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
2116 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2157 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
2117 Immediate(1 << Map::kIsUndetectable)); | 2158 Immediate(1 << Map::kIsUndetectable)); |
| 2159 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2118 Split(not_zero, if_true, if_false, fall_through); | 2160 Split(not_zero, if_true, if_false, fall_through); |
2119 | 2161 |
2120 context()->Plug(if_true, if_false); | 2162 context()->Plug(if_true, if_false); |
2121 } | 2163 } |
2122 | 2164 |
2123 | 2165 |
2124 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( | 2166 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( |
2125 ZoneList<Expression*>* args) { | 2167 ZoneList<Expression*>* args) { |
2126 ASSERT(args->length() == 1); | 2168 ASSERT(args->length() == 1); |
2127 | 2169 |
2128 VisitForAccumulatorValue(args->at(0)); | 2170 VisitForAccumulatorValue(args->at(0)); |
2129 | 2171 |
2130 Label materialize_true, materialize_false; | 2172 Label materialize_true, materialize_false; |
2131 Label* if_true = NULL; | 2173 Label* if_true = NULL; |
2132 Label* if_false = NULL; | 2174 Label* if_false = NULL; |
2133 Label* fall_through = NULL; | 2175 Label* fall_through = NULL; |
2134 context()->PrepareTest(&materialize_true, &materialize_false, | 2176 context()->PrepareTest(&materialize_true, &materialize_false, |
2135 &if_true, &if_false, &fall_through); | 2177 &if_true, &if_false, &fall_through); |
2136 | 2178 |
2137 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only | 2179 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only |
2138 // used in a few functions in runtime.js which should not normally be hit by | 2180 // used in a few functions in runtime.js which should not normally be hit by |
2139 // this compiler. | 2181 // this compiler. |
| 2182 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2140 __ jmp(if_false); | 2183 __ jmp(if_false); |
2141 context()->Plug(if_true, if_false); | 2184 context()->Plug(if_true, if_false); |
2142 } | 2185 } |
2143 | 2186 |
2144 | 2187 |
2145 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { | 2188 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { |
2146 ASSERT(args->length() == 1); | 2189 ASSERT(args->length() == 1); |
2147 | 2190 |
2148 VisitForAccumulatorValue(args->at(0)); | 2191 VisitForAccumulatorValue(args->at(0)); |
2149 | 2192 |
2150 Label materialize_true, materialize_false; | 2193 Label materialize_true, materialize_false; |
2151 Label* if_true = NULL; | 2194 Label* if_true = NULL; |
2152 Label* if_false = NULL; | 2195 Label* if_false = NULL; |
2153 Label* fall_through = NULL; | 2196 Label* fall_through = NULL; |
2154 context()->PrepareTest(&materialize_true, &materialize_false, | 2197 context()->PrepareTest(&materialize_true, &materialize_false, |
2155 &if_true, &if_false, &fall_through); | 2198 &if_true, &if_false, &fall_through); |
2156 | 2199 |
2157 __ JumpIfSmi(rax, if_false); | 2200 __ JumpIfSmi(rax, if_false); |
2158 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); | 2201 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); |
| 2202 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2159 Split(equal, if_true, if_false, fall_through); | 2203 Split(equal, if_true, if_false, fall_through); |
2160 | 2204 |
2161 context()->Plug(if_true, if_false); | 2205 context()->Plug(if_true, if_false); |
2162 } | 2206 } |
2163 | 2207 |
2164 | 2208 |
2165 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { | 2209 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { |
2166 ASSERT(args->length() == 1); | 2210 ASSERT(args->length() == 1); |
2167 | 2211 |
2168 VisitForAccumulatorValue(args->at(0)); | 2212 VisitForAccumulatorValue(args->at(0)); |
2169 | 2213 |
2170 Label materialize_true, materialize_false; | 2214 Label materialize_true, materialize_false; |
2171 Label* if_true = NULL; | 2215 Label* if_true = NULL; |
2172 Label* if_false = NULL; | 2216 Label* if_false = NULL; |
2173 Label* fall_through = NULL; | 2217 Label* fall_through = NULL; |
2174 context()->PrepareTest(&materialize_true, &materialize_false, | 2218 context()->PrepareTest(&materialize_true, &materialize_false, |
2175 &if_true, &if_false, &fall_through); | 2219 &if_true, &if_false, &fall_through); |
2176 | 2220 |
2177 __ JumpIfSmi(rax, if_false); | 2221 __ JumpIfSmi(rax, if_false); |
2178 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx); | 2222 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx); |
| 2223 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2179 Split(equal, if_true, if_false, fall_through); | 2224 Split(equal, if_true, if_false, fall_through); |
2180 | 2225 |
2181 context()->Plug(if_true, if_false); | 2226 context()->Plug(if_true, if_false); |
2182 } | 2227 } |
2183 | 2228 |
2184 | 2229 |
2185 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { | 2230 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { |
2186 ASSERT(args->length() == 1); | 2231 ASSERT(args->length() == 1); |
2187 | 2232 |
2188 VisitForAccumulatorValue(args->at(0)); | 2233 VisitForAccumulatorValue(args->at(0)); |
2189 | 2234 |
2190 Label materialize_true, materialize_false; | 2235 Label materialize_true, materialize_false; |
2191 Label* if_true = NULL; | 2236 Label* if_true = NULL; |
2192 Label* if_false = NULL; | 2237 Label* if_false = NULL; |
2193 Label* fall_through = NULL; | 2238 Label* fall_through = NULL; |
2194 context()->PrepareTest(&materialize_true, &materialize_false, | 2239 context()->PrepareTest(&materialize_true, &materialize_false, |
2195 &if_true, &if_false, &fall_through); | 2240 &if_true, &if_false, &fall_through); |
2196 | 2241 |
2197 __ JumpIfSmi(rax, if_false); | 2242 __ JumpIfSmi(rax, if_false); |
2198 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx); | 2243 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx); |
| 2244 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2199 Split(equal, if_true, if_false, fall_through); | 2245 Split(equal, if_true, if_false, fall_through); |
2200 | 2246 |
2201 context()->Plug(if_true, if_false); | 2247 context()->Plug(if_true, if_false); |
2202 } | 2248 } |
2203 | 2249 |
2204 | 2250 |
2205 | 2251 |
2206 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { | 2252 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { |
2207 ASSERT(args->length() == 0); | 2253 ASSERT(args->length() == 0); |
2208 | 2254 |
(...skipping 11 matching lines...) Expand all Loading... |
2220 Label check_frame_marker; | 2266 Label check_frame_marker; |
2221 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), | 2267 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), |
2222 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2268 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
2223 __ j(not_equal, &check_frame_marker); | 2269 __ j(not_equal, &check_frame_marker); |
2224 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); | 2270 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); |
2225 | 2271 |
2226 // Check the marker in the calling frame. | 2272 // Check the marker in the calling frame. |
2227 __ bind(&check_frame_marker); | 2273 __ bind(&check_frame_marker); |
2228 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), | 2274 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), |
2229 Smi::FromInt(StackFrame::CONSTRUCT)); | 2275 Smi::FromInt(StackFrame::CONSTRUCT)); |
| 2276 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2230 Split(equal, if_true, if_false, fall_through); | 2277 Split(equal, if_true, if_false, fall_through); |
2231 | 2278 |
2232 context()->Plug(if_true, if_false); | 2279 context()->Plug(if_true, if_false); |
2233 } | 2280 } |
2234 | 2281 |
2235 | 2282 |
2236 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { | 2283 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { |
2237 ASSERT(args->length() == 2); | 2284 ASSERT(args->length() == 2); |
2238 | 2285 |
2239 // Load the two objects into registers and perform the comparison. | 2286 // Load the two objects into registers and perform the comparison. |
2240 VisitForStackValue(args->at(0)); | 2287 VisitForStackValue(args->at(0)); |
2241 VisitForAccumulatorValue(args->at(1)); | 2288 VisitForAccumulatorValue(args->at(1)); |
2242 | 2289 |
2243 Label materialize_true, materialize_false; | 2290 Label materialize_true, materialize_false; |
2244 Label* if_true = NULL; | 2291 Label* if_true = NULL; |
2245 Label* if_false = NULL; | 2292 Label* if_false = NULL; |
2246 Label* fall_through = NULL; | 2293 Label* fall_through = NULL; |
2247 context()->PrepareTest(&materialize_true, &materialize_false, | 2294 context()->PrepareTest(&materialize_true, &materialize_false, |
2248 &if_true, &if_false, &fall_through); | 2295 &if_true, &if_false, &fall_through); |
2249 | 2296 |
2250 __ pop(rbx); | 2297 __ pop(rbx); |
2251 __ cmpq(rax, rbx); | 2298 __ cmpq(rax, rbx); |
| 2299 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2252 Split(equal, if_true, if_false, fall_through); | 2300 Split(equal, if_true, if_false, fall_through); |
2253 | 2301 |
2254 context()->Plug(if_true, if_false); | 2302 context()->Plug(if_true, if_false); |
2255 } | 2303 } |
2256 | 2304 |
2257 | 2305 |
2258 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2306 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
2259 ASSERT(args->length() == 1); | 2307 ASSERT(args->length() == 1); |
2260 | 2308 |
2261 // ArgumentsAccessStub expects the key in rdx and the formal | 2309 // ArgumentsAccessStub expects the key in rdx and the formal |
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2815 | 2863 |
2816 Label materialize_true, materialize_false; | 2864 Label materialize_true, materialize_false; |
2817 Label* if_true = NULL; | 2865 Label* if_true = NULL; |
2818 Label* if_false = NULL; | 2866 Label* if_false = NULL; |
2819 Label* fall_through = NULL; | 2867 Label* fall_through = NULL; |
2820 context()->PrepareTest(&materialize_true, &materialize_false, | 2868 context()->PrepareTest(&materialize_true, &materialize_false, |
2821 &if_true, &if_false, &fall_through); | 2869 &if_true, &if_false, &fall_through); |
2822 | 2870 |
2823 __ testl(FieldOperand(rax, String::kHashFieldOffset), | 2871 __ testl(FieldOperand(rax, String::kHashFieldOffset), |
2824 Immediate(String::kContainsCachedArrayIndexMask)); | 2872 Immediate(String::kContainsCachedArrayIndexMask)); |
| 2873 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
2825 __ j(zero, if_true); | 2874 __ j(zero, if_true); |
2826 __ jmp(if_false); | 2875 __ jmp(if_false); |
2827 | 2876 |
2828 context()->Plug(if_true, if_false); | 2877 context()->Plug(if_true, if_false); |
2829 } | 2878 } |
2830 | 2879 |
2831 | 2880 |
2832 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { | 2881 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { |
2833 ASSERT(args->length() == 1); | 2882 ASSERT(args->length() == 1); |
2834 | 2883 |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2936 | 2985 |
2937 case Token::NOT: { | 2986 case Token::NOT: { |
2938 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 2987 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
2939 Label materialize_true, materialize_false; | 2988 Label materialize_true, materialize_false; |
2940 Label* if_true = NULL; | 2989 Label* if_true = NULL; |
2941 Label* if_false = NULL; | 2990 Label* if_false = NULL; |
2942 Label* fall_through = NULL; | 2991 Label* fall_through = NULL; |
2943 // Notice that the labels are swapped. | 2992 // Notice that the labels are swapped. |
2944 context()->PrepareTest(&materialize_true, &materialize_false, | 2993 context()->PrepareTest(&materialize_true, &materialize_false, |
2945 &if_false, &if_true, &fall_through); | 2994 &if_false, &if_true, &fall_through); |
| 2995 if (context()->IsTest()) ForwardBailoutToChild(expr); |
2946 VisitForControl(expr->expression(), if_true, if_false, fall_through); | 2996 VisitForControl(expr->expression(), if_true, if_false, fall_through); |
2947 context()->Plug(if_false, if_true); // Labels swapped. | 2997 context()->Plug(if_false, if_true); // Labels swapped. |
2948 break; | 2998 break; |
2949 } | 2999 } |
2950 | 3000 |
2951 case Token::TYPEOF: { | 3001 case Token::TYPEOF: { |
2952 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 3002 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
2953 { StackValueContext context(this); | 3003 { StackValueContext context(this); |
2954 VisitForTypeofValue(expr->expression()); | 3004 VisitForTypeofValue(expr->expression()); |
2955 } | 3005 } |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3057 EmitNamedPropertyLoad(prop); | 3107 EmitNamedPropertyLoad(prop); |
3058 } else { | 3108 } else { |
3059 VisitForStackValue(prop->obj()); | 3109 VisitForStackValue(prop->obj()); |
3060 VisitForAccumulatorValue(prop->key()); | 3110 VisitForAccumulatorValue(prop->key()); |
3061 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack | 3111 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack |
3062 __ push(rax); // Copy of key, needed for later store. | 3112 __ push(rax); // Copy of key, needed for later store. |
3063 EmitKeyedPropertyLoad(prop); | 3113 EmitKeyedPropertyLoad(prop); |
3064 } | 3114 } |
3065 } | 3115 } |
3066 | 3116 |
| 3117 // We need a second deoptimization point after loading the value |
| 3118 // in case evaluating the property load my have a side effect. |
| 3119 PrepareForBailout(expr->increment(), TOS_REG); |
| 3120 |
3067 // Call ToNumber only if operand is not a smi. | 3121 // Call ToNumber only if operand is not a smi. |
3068 NearLabel no_conversion; | 3122 NearLabel no_conversion; |
3069 Condition is_smi; | 3123 Condition is_smi; |
3070 is_smi = masm_->CheckSmi(rax); | 3124 is_smi = masm_->CheckSmi(rax); |
3071 __ j(is_smi, &no_conversion); | 3125 __ j(is_smi, &no_conversion); |
3072 __ push(rax); | 3126 __ push(rax); |
3073 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 3127 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
3074 __ bind(&no_conversion); | 3128 __ bind(&no_conversion); |
3075 | 3129 |
3076 // Save result for postfix expressions. | 3130 // Save result for postfix expressions. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3126 __ bind(&done); | 3180 __ bind(&done); |
3127 | 3181 |
3128 // Store the value returned in rax. | 3182 // Store the value returned in rax. |
3129 switch (assign_type) { | 3183 switch (assign_type) { |
3130 case VARIABLE: | 3184 case VARIABLE: |
3131 if (expr->is_postfix()) { | 3185 if (expr->is_postfix()) { |
3132 // Perform the assignment as if via '='. | 3186 // Perform the assignment as if via '='. |
3133 { EffectContext context(this); | 3187 { EffectContext context(this); |
3134 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3188 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
3135 Token::ASSIGN); | 3189 Token::ASSIGN); |
| 3190 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3136 context.Plug(rax); | 3191 context.Plug(rax); |
3137 } | 3192 } |
3138 // For all contexts except kEffect: We have the result on | 3193 // For all contexts except kEffect: We have the result on |
3139 // top of the stack. | 3194 // top of the stack. |
3140 if (!context()->IsEffect()) { | 3195 if (!context()->IsEffect()) { |
3141 context()->PlugTOS(); | 3196 context()->PlugTOS(); |
3142 } | 3197 } |
3143 } else { | 3198 } else { |
3144 // Perform the assignment as if via '='. | 3199 // Perform the assignment as if via '='. |
3145 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3200 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
3146 Token::ASSIGN); | 3201 Token::ASSIGN); |
| 3202 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3147 context()->Plug(rax); | 3203 context()->Plug(rax); |
3148 } | 3204 } |
3149 break; | 3205 break; |
3150 case NAMED_PROPERTY: { | 3206 case NAMED_PROPERTY: { |
3151 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 3207 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
3152 __ pop(rdx); | 3208 __ pop(rdx); |
3153 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 3209 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
3154 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3210 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3211 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3155 if (expr->is_postfix()) { | 3212 if (expr->is_postfix()) { |
3156 if (!context()->IsEffect()) { | 3213 if (!context()->IsEffect()) { |
3157 context()->PlugTOS(); | 3214 context()->PlugTOS(); |
3158 } | 3215 } |
3159 } else { | 3216 } else { |
3160 context()->Plug(rax); | 3217 context()->Plug(rax); |
3161 } | 3218 } |
3162 break; | 3219 break; |
3163 } | 3220 } |
3164 case KEYED_PROPERTY: { | 3221 case KEYED_PROPERTY: { |
3165 __ pop(rcx); | 3222 __ pop(rcx); |
3166 __ pop(rdx); | 3223 __ pop(rdx); |
3167 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 3224 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
3168 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3225 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3226 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3169 if (expr->is_postfix()) { | 3227 if (expr->is_postfix()) { |
3170 if (!context()->IsEffect()) { | 3228 if (!context()->IsEffect()) { |
3171 context()->PlugTOS(); | 3229 context()->PlugTOS(); |
3172 } | 3230 } |
3173 } else { | 3231 } else { |
3174 context()->Plug(rax); | 3232 context()->Plug(rax); |
3175 } | 3233 } |
3176 break; | 3234 break; |
3177 } | 3235 } |
3178 } | 3236 } |
3179 } | 3237 } |
3180 | 3238 |
3181 | 3239 |
3182 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 3240 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
3183 VariableProxy* proxy = expr->AsVariableProxy(); | 3241 VariableProxy* proxy = expr->AsVariableProxy(); |
3184 ASSERT(!context()->IsEffect()); | 3242 ASSERT(!context()->IsEffect()); |
3185 ASSERT(!context()->IsTest()); | 3243 ASSERT(!context()->IsTest()); |
3186 | 3244 |
3187 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3245 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
3188 Comment cmnt(masm_, "Global variable"); | 3246 Comment cmnt(masm_, "Global variable"); |
3189 __ Move(rcx, proxy->name()); | 3247 __ Move(rcx, proxy->name()); |
3190 __ movq(rax, GlobalObjectOperand()); | 3248 __ movq(rax, GlobalObjectOperand()); |
3191 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3249 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
3192 // Use a regular load, not a contextual load, to avoid a reference | 3250 // Use a regular load, not a contextual load, to avoid a reference |
3193 // error. | 3251 // error. |
3194 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3252 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3253 PrepareForBailout(expr, TOS_REG); |
3195 context()->Plug(rax); | 3254 context()->Plug(rax); |
3196 } else if (proxy != NULL && | 3255 } else if (proxy != NULL && |
3197 proxy->var()->AsSlot() != NULL && | 3256 proxy->var()->AsSlot() != NULL && |
3198 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | 3257 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { |
3199 Label done, slow; | 3258 Label done, slow; |
3200 | 3259 |
3201 // Generate code for loading from variables potentially shadowed | 3260 // Generate code for loading from variables potentially shadowed |
3202 // by eval-introduced variables. | 3261 // by eval-introduced variables. |
3203 Slot* slot = proxy->var()->AsSlot(); | 3262 Slot* slot = proxy->var()->AsSlot(); |
3204 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); | 3263 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
3205 | 3264 |
3206 __ bind(&slow); | 3265 __ bind(&slow); |
3207 __ push(rsi); | 3266 __ push(rsi); |
3208 __ Push(proxy->name()); | 3267 __ Push(proxy->name()); |
3209 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3268 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3269 PrepareForBailout(expr, TOS_REG); |
3210 __ bind(&done); | 3270 __ bind(&done); |
3211 | 3271 |
3212 context()->Plug(rax); | 3272 context()->Plug(rax); |
3213 } else { | 3273 } else { |
3214 // This expression cannot throw a reference error at the top level. | 3274 // This expression cannot throw a reference error at the top level. |
3215 Visit(expr); | 3275 Visit(expr); |
3216 } | 3276 } |
3217 } | 3277 } |
3218 | 3278 |
3219 | 3279 |
(...skipping 10 matching lines...) Expand all Loading... |
3230 if (right_literal == NULL) return false; | 3290 if (right_literal == NULL) return false; |
3231 Handle<Object> right_literal_value = right_literal->handle(); | 3291 Handle<Object> right_literal_value = right_literal->handle(); |
3232 if (!right_literal_value->IsString()) return false; | 3292 if (!right_literal_value->IsString()) return false; |
3233 UnaryOperation* left_unary = left->AsUnaryOperation(); | 3293 UnaryOperation* left_unary = left->AsUnaryOperation(); |
3234 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | 3294 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
3235 Handle<String> check = Handle<String>::cast(right_literal_value); | 3295 Handle<String> check = Handle<String>::cast(right_literal_value); |
3236 | 3296 |
3237 { AccumulatorValueContext context(this); | 3297 { AccumulatorValueContext context(this); |
3238 VisitForTypeofValue(left_unary->expression()); | 3298 VisitForTypeofValue(left_unary->expression()); |
3239 } | 3299 } |
| 3300 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3240 | 3301 |
3241 if (check->Equals(Heap::number_symbol())) { | 3302 if (check->Equals(Heap::number_symbol())) { |
3242 Condition is_smi = masm_->CheckSmi(rax); | 3303 Condition is_smi = masm_->CheckSmi(rax); |
3243 __ j(is_smi, if_true); | 3304 __ j(is_smi, if_true); |
3244 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 3305 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
3245 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); | 3306 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); |
3246 Split(equal, if_true, if_false, fall_through); | 3307 Split(equal, if_true, if_false, fall_through); |
3247 } else if (check->Equals(Heap::string_symbol())) { | 3308 } else if (check->Equals(Heap::string_symbol())) { |
3248 Condition is_smi = masm_->CheckSmi(rax); | 3309 Condition is_smi = masm_->CheckSmi(rax); |
3249 __ j(is_smi, if_false); | 3310 __ j(is_smi, if_false); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3323 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { | 3384 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { |
3324 context()->Plug(if_true, if_false); | 3385 context()->Plug(if_true, if_false); |
3325 return; | 3386 return; |
3326 } | 3387 } |
3327 | 3388 |
3328 VisitForStackValue(expr->left()); | 3389 VisitForStackValue(expr->left()); |
3329 switch (op) { | 3390 switch (op) { |
3330 case Token::IN: | 3391 case Token::IN: |
3331 VisitForStackValue(expr->right()); | 3392 VisitForStackValue(expr->right()); |
3332 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 3393 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 3394 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
3333 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 3395 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
3334 Split(equal, if_true, if_false, fall_through); | 3396 Split(equal, if_true, if_false, fall_through); |
3335 break; | 3397 break; |
3336 | 3398 |
3337 case Token::INSTANCEOF: { | 3399 case Token::INSTANCEOF: { |
3338 VisitForStackValue(expr->right()); | 3400 VisitForStackValue(expr->right()); |
3339 InstanceofStub stub(InstanceofStub::kNoFlags); | 3401 InstanceofStub stub(InstanceofStub::kNoFlags); |
3340 __ CallStub(&stub); | 3402 __ CallStub(&stub); |
| 3403 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3341 __ testq(rax, rax); | 3404 __ testq(rax, rax); |
3342 // The stub returns 0 for true. | 3405 // The stub returns 0 for true. |
3343 Split(zero, if_true, if_false, fall_through); | 3406 Split(zero, if_true, if_false, fall_through); |
3344 break; | 3407 break; |
3345 } | 3408 } |
3346 | 3409 |
3347 default: { | 3410 default: { |
3348 VisitForAccumulatorValue(expr->right()); | 3411 VisitForAccumulatorValue(expr->right()); |
3349 Condition cc = no_condition; | 3412 Condition cc = no_condition; |
3350 bool strict = false; | 3413 bool strict = false; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3389 __ SmiCompare(rdx, rax); | 3452 __ SmiCompare(rdx, rax); |
3390 Split(cc, if_true, if_false, NULL); | 3453 Split(cc, if_true, if_false, NULL); |
3391 __ bind(&slow_case); | 3454 __ bind(&slow_case); |
3392 } | 3455 } |
3393 | 3456 |
3394 CompareFlags flags = inline_smi_code | 3457 CompareFlags flags = inline_smi_code |
3395 ? NO_SMI_COMPARE_IN_STUB | 3458 ? NO_SMI_COMPARE_IN_STUB |
3396 : NO_COMPARE_FLAGS; | 3459 : NO_COMPARE_FLAGS; |
3397 CompareStub stub(cc, strict, flags); | 3460 CompareStub stub(cc, strict, flags); |
3398 __ CallStub(&stub); | 3461 __ CallStub(&stub); |
| 3462 |
| 3463 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3399 __ testq(rax, rax); | 3464 __ testq(rax, rax); |
3400 Split(cc, if_true, if_false, fall_through); | 3465 Split(cc, if_true, if_false, fall_through); |
3401 } | 3466 } |
3402 } | 3467 } |
3403 | 3468 |
3404 // Convert the result of the comparison into one expected for this | 3469 // Convert the result of the comparison into one expected for this |
3405 // expression's context. | 3470 // expression's context. |
3406 context()->Plug(if_true, if_false); | 3471 context()->Plug(if_true, if_false); |
3407 } | 3472 } |
3408 | 3473 |
3409 | 3474 |
3410 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { | 3475 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { |
3411 Comment cmnt(masm_, "[ CompareToNull"); | 3476 Comment cmnt(masm_, "[ CompareToNull"); |
3412 Label materialize_true, materialize_false; | 3477 Label materialize_true, materialize_false; |
3413 Label* if_true = NULL; | 3478 Label* if_true = NULL; |
3414 Label* if_false = NULL; | 3479 Label* if_false = NULL; |
3415 Label* fall_through = NULL; | 3480 Label* fall_through = NULL; |
3416 context()->PrepareTest(&materialize_true, &materialize_false, | 3481 context()->PrepareTest(&materialize_true, &materialize_false, |
3417 &if_true, &if_false, &fall_through); | 3482 &if_true, &if_false, &fall_through); |
3418 | 3483 |
3419 VisitForAccumulatorValue(expr->expression()); | 3484 VisitForAccumulatorValue(expr->expression()); |
| 3485 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3420 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 3486 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
3421 if (expr->is_strict()) { | 3487 if (expr->is_strict()) { |
3422 Split(equal, if_true, if_false, fall_through); | 3488 Split(equal, if_true, if_false, fall_through); |
3423 } else { | 3489 } else { |
3424 __ j(equal, if_true); | 3490 __ j(equal, if_true); |
3425 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 3491 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
3426 __ j(equal, if_true); | 3492 __ j(equal, if_true); |
3427 Condition is_smi = masm_->CheckSmi(rax); | 3493 Condition is_smi = masm_->CheckSmi(rax); |
3428 __ j(is_smi, if_false); | 3494 __ j(is_smi, if_false); |
3429 // It can be an undetectable object. | 3495 // It can be an undetectable object. |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3521 __ ret(0); | 3587 __ ret(0); |
3522 } | 3588 } |
3523 | 3589 |
3524 | 3590 |
3525 #undef __ | 3591 #undef __ |
3526 | 3592 |
3527 | 3593 |
3528 } } // namespace v8::internal | 3594 } } // namespace v8::internal |
3529 | 3595 |
3530 #endif // V8_TARGET_ARCH_X64 | 3596 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |