Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 1433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1444 case kTypedDataFloat32x4ArrayCid: | 1444 case kTypedDataFloat32x4ArrayCid: |
| 1445 case kTypedDataFloat64x2ArrayCid: | 1445 case kTypedDataFloat64x2ArrayCid: |
| 1446 __ movups(element_address, locs()->in(2).fpu_reg()); | 1446 __ movups(element_address, locs()->in(2).fpu_reg()); |
| 1447 break; | 1447 break; |
| 1448 default: | 1448 default: |
| 1449 UNREACHABLE(); | 1449 UNREACHABLE(); |
| 1450 } | 1450 } |
| 1451 } | 1451 } |
| 1452 | 1452 |
| 1453 | 1453 |
| 1454 LocationSummary* GuardFieldInstr::MakeLocationSummary(Isolate* isolate, | 1454 LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Isolate* isolate, |
| 1455 bool opt) const { | 1455 bool opt) const { |
|
Florian Schneider
2014/05/28 14:57:36
Space alignment.
Vyacheslav Egorov (Google)
2014/05/29 17:36:51
Done.
| |
| 1456 const intptr_t kNumInputs = 1; | 1456 const intptr_t kNumInputs = 1; |
| 1457 LocationSummary* summary = new(isolate) LocationSummary( | 1457 LocationSummary* summary = new(isolate) LocationSummary( |
| 1458 isolate, kNumInputs, 0, LocationSummary::kNoCall); | 1458 isolate, kNumInputs, 0, LocationSummary::kNoCall); |
| 1459 summary->set_in(0, Location::RequiresRegister()); | 1459 summary->set_in(0, Location::RequiresRegister()); |
| 1460 const bool field_has_length = field().needs_length_check(); | 1460 |
| 1461 const bool need_value_temp_reg = | 1461 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1462 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) && | 1462 const intptr_t field_cid = field().guarded_cid(); |
| 1463 (field().guarded_cid() != kSmiCid))); | 1463 |
| 1464 if (need_value_temp_reg) { | 1464 const bool emit_full_guard = !opt || (field_cid == kIllegalCid); |
| 1465 const bool needs_value_cid_temp_reg = | |
| 1466 (value_cid == kDynamicCid) && (emit_full_guard || (field_cid != kSmiCid)); | |
| 1467 const bool needs_field_temp_reg = emit_full_guard; | |
| 1468 | |
| 1469 if (needs_value_cid_temp_reg) { | |
| 1465 summary->AddTemp(Location::RequiresRegister()); | 1470 summary->AddTemp(Location::RequiresRegister()); |
| 1466 } | 1471 } |
| 1467 const bool need_field_temp_reg = | 1472 |
| 1468 field_has_length || (field().guarded_cid() == kIllegalCid); | 1473 if (needs_field_temp_reg) { |
| 1469 if (need_field_temp_reg) { | |
| 1470 summary->AddTemp(Location::RequiresRegister()); | 1474 summary->AddTemp(Location::RequiresRegister()); |
| 1471 } | 1475 } |
| 1476 | |
| 1472 return summary; | 1477 return summary; |
| 1473 } | 1478 } |
| 1474 | 1479 |
| 1475 | 1480 |
| 1476 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1481 void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1482 const intptr_t value_cid = value()->Type()->ToCid(); | |
| 1477 const intptr_t field_cid = field().guarded_cid(); | 1483 const intptr_t field_cid = field().guarded_cid(); |
| 1478 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; | 1484 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; |
| 1479 const intptr_t field_length = field().guarded_list_length(); | |
| 1480 const bool field_has_length = field().needs_length_check(); | |
| 1481 const bool needs_value_temp_reg = | |
| 1482 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) && | |
| 1483 (field().guarded_cid() != kSmiCid))); | |
| 1484 const bool needs_field_temp_reg = | |
| 1485 field_has_length || (field().guarded_cid() == kIllegalCid); | |
| 1486 if (field_has_length) { | |
| 1487 // Currently, we should only see final fields that remember length. | |
| 1488 ASSERT(field().is_final()); | |
| 1489 } | |
| 1490 | 1485 |
| 1491 if (field_cid == kDynamicCid) { | 1486 if (field_cid == kDynamicCid) { |
| 1492 ASSERT(!compiler->is_optimizing()); | 1487 ASSERT(!compiler->is_optimizing()); |
| 1493 return; // Nothing to emit. | 1488 return; // Nothing to emit. |
| 1494 } | 1489 } |
| 1495 const intptr_t value_cid = value()->Type()->ToCid(); | 1490 |
| 1491 const bool emit_full_guard = | |
| 1492 !compiler->is_optimizing() || (field_cid == kIllegalCid); | |
| 1493 | |
| 1494 const bool needs_value_cid_temp_reg = | |
| 1495 (value_cid == kDynamicCid) && (emit_full_guard || (field_cid != kSmiCid)); | |
| 1496 | |
| 1497 const bool needs_field_temp_reg = emit_full_guard; | |
| 1496 | 1498 |
| 1497 Register value_reg = locs()->in(0).reg(); | 1499 Register value_reg = locs()->in(0).reg(); |
| 1498 | 1500 |
| 1499 Register value_cid_reg = needs_value_temp_reg ? | 1501 Register value_cid_reg = needs_value_cid_temp_reg ? |
| 1500 locs()->temp(0).reg() : kNoRegister; | 1502 locs()->temp(0).reg() : kNoRegister; |
| 1501 | 1503 |
| 1502 Register field_reg = needs_field_temp_reg ? | 1504 Register field_reg = needs_field_temp_reg ? |
| 1503 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; | 1505 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; |
| 1504 | 1506 |
| 1505 Label ok, fail_label; | 1507 Label ok, fail_label; |
| 1506 | 1508 |
| 1507 Label* deopt = compiler->is_optimizing() ? | 1509 Label* deopt = compiler->is_optimizing() ? |
| 1508 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; | 1510 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; |
| 1509 | 1511 |
| 1510 Label* fail = (deopt != NULL) ? deopt : &fail_label; | 1512 Label* fail = (deopt != NULL) ? deopt : &fail_label; |
| 1511 | 1513 |
| 1512 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) { | 1514 if (emit_full_guard) { |
| 1513 if (!compiler->is_optimizing() && (field_reg == kNoRegister)) { | |
| 1514 // Currently we can't have different location summaries for optimized | |
| 1515 // and non-optimized code. So instead we manually pick up a register | |
| 1516 // that is known to be free because we know how non-optimizing compiler | |
| 1517 // allocates registers. | |
| 1518 field_reg = EBX; | |
| 1519 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg)); | |
| 1520 } | |
| 1521 | |
| 1522 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); | 1515 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); |
| 1523 | 1516 |
| 1524 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); | 1517 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); |
| 1525 FieldAddress field_nullability_operand( | 1518 FieldAddress field_nullability_operand( |
| 1526 field_reg, Field::is_nullable_offset()); | 1519 field_reg, Field::is_nullable_offset()); |
| 1527 FieldAddress field_length_operand( | |
| 1528 field_reg, Field::guarded_list_length_offset()); | |
| 1529 | 1520 |
| 1530 if (value_cid == kDynamicCid) { | 1521 if (value_cid == kDynamicCid) { |
| 1531 if (value_cid_reg == kNoRegister) { | |
| 1532 ASSERT(!compiler->is_optimizing()); | |
| 1533 value_cid_reg = EDX; | |
| 1534 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg)); | |
| 1535 } | |
| 1536 | |
| 1537 LoadValueCid(compiler, value_cid_reg, value_reg); | 1522 LoadValueCid(compiler, value_cid_reg, value_reg); |
| 1538 Label skip_length_check; | |
| 1539 __ cmpl(value_cid_reg, field_cid_operand); | 1523 __ cmpl(value_cid_reg, field_cid_operand); |
| 1540 // Value CID != Field guard CID, skip length check. | 1524 __ j(EQUAL, &ok); |
| 1541 __ j(NOT_EQUAL, &skip_length_check); | |
| 1542 if (field_has_length) { | |
| 1543 // Field guard may have remembered list length, check it. | |
| 1544 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1545 __ pushl(value_cid_reg); | |
| 1546 __ movl(value_cid_reg, | |
| 1547 FieldAddress(value_reg, Array::length_offset())); | |
| 1548 __ cmpl(value_cid_reg, Immediate(Smi::RawValue(field_length))); | |
| 1549 __ popl(value_cid_reg); | |
| 1550 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1551 __ pushl(value_cid_reg); | |
| 1552 __ movl(value_cid_reg, | |
| 1553 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1554 __ cmpl(value_cid_reg, Immediate(Smi::RawValue(field_length))); | |
| 1555 __ popl(value_cid_reg); | |
| 1556 } else { | |
| 1557 ASSERT(field_cid == kIllegalCid); | |
| 1558 ASSERT(field_length == Field::kUnknownFixedLength); | |
| 1559 // At compile time we do not know the type of the field nor its | |
| 1560 // length. At execution time we may have set the class id and | |
| 1561 // list length so we compare the guarded length with the | |
| 1562 // list length here, without this check the list length could change | |
| 1563 // without triggering a deoptimization. | |
| 1564 Label check_array, length_compared, no_fixed_length; | |
| 1565 // If length is negative the length guard is either disabled or | |
| 1566 // has not been initialized, either way it is safe to skip the | |
| 1567 // length check. | |
| 1568 __ cmpl(field_length_operand, Immediate(Smi::RawValue(0))); | |
| 1569 __ j(LESS, &skip_length_check); | |
| 1570 __ cmpl(value_cid_reg, Immediate(kNullCid)); | |
| 1571 __ j(EQUAL, &no_fixed_length, Assembler::kNearJump); | |
| 1572 // Check for typed data array. | |
| 1573 __ cmpl(value_cid_reg, Immediate(kTypedDataInt32x4ArrayCid)); | |
| 1574 // Not a typed array or a regular array. | |
| 1575 __ j(GREATER, &no_fixed_length, Assembler::kNearJump); | |
| 1576 __ cmpl(value_cid_reg, Immediate(kTypedDataInt8ArrayCid)); | |
| 1577 // Could still be a regular array. | |
| 1578 __ j(LESS, &check_array, Assembler::kNearJump); | |
| 1579 __ pushl(value_cid_reg); | |
| 1580 __ movl(value_cid_reg, | |
| 1581 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1582 __ cmpl(field_length_operand, value_cid_reg); | |
| 1583 __ popl(value_cid_reg); | |
| 1584 __ jmp(&length_compared, Assembler::kNearJump); | |
| 1585 // Check for regular array. | |
| 1586 __ Bind(&check_array); | |
| 1587 __ cmpl(value_cid_reg, Immediate(kImmutableArrayCid)); | |
| 1588 __ j(GREATER, &no_fixed_length, Assembler::kNearJump); | |
| 1589 __ cmpl(value_cid_reg, Immediate(kArrayCid)); | |
| 1590 __ j(LESS, &no_fixed_length, Assembler::kNearJump); | |
| 1591 __ pushl(value_cid_reg); | |
| 1592 __ movl(value_cid_reg, | |
| 1593 FieldAddress(value_reg, Array::length_offset())); | |
| 1594 __ cmpl(field_length_operand, value_cid_reg); | |
| 1595 __ popl(value_cid_reg); | |
| 1596 __ jmp(&length_compared, Assembler::kNearJump); | |
| 1597 __ Bind(&no_fixed_length); | |
| 1598 __ jmp(fail); | |
| 1599 __ Bind(&length_compared); | |
| 1600 } | |
| 1601 __ j(NOT_EQUAL, fail); | |
| 1602 } | |
| 1603 __ Bind(&skip_length_check); | |
| 1604 __ cmpl(value_cid_reg, field_nullability_operand); | 1525 __ cmpl(value_cid_reg, field_nullability_operand); |
| 1605 } else if (value_cid == kNullCid) { | 1526 } else if (value_cid == kNullCid) { |
| 1606 // Value in graph known to be null. | 1527 // Value in graph known to be null. |
| 1607 // Compare with null. | 1528 // Compare with null. |
| 1608 __ cmpl(field_nullability_operand, Immediate(value_cid)); | 1529 __ cmpl(field_nullability_operand, Immediate(value_cid)); |
| 1609 } else { | 1530 } else { |
| 1610 // Value in graph known to be non-null. | 1531 // Value in graph known to be non-null. |
| 1611 Label skip_length_check; | |
| 1612 // Compare class id with guard field class id. | 1532 // Compare class id with guard field class id. |
| 1613 __ cmpl(field_cid_operand, Immediate(value_cid)); | 1533 __ cmpl(field_cid_operand, Immediate(value_cid)); |
| 1614 // If not equal, skip over length check. | |
| 1615 __ j(NOT_EQUAL, &skip_length_check); | |
| 1616 // Insert length check. | |
| 1617 if (field_has_length) { | |
| 1618 ASSERT(value_cid_reg != kNoRegister); | |
| 1619 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | |
| 1620 __ cmpl(FieldAddress(value_reg, Array::length_offset()), | |
| 1621 Immediate(Smi::RawValue(field_length))); | |
| 1622 } else if (RawObject::IsTypedDataClassId(value_cid)) { | |
| 1623 __ cmpl(FieldAddress(value_reg, TypedData::length_offset()), | |
| 1624 Immediate(Smi::RawValue(field_length))); | |
| 1625 } else if (field_cid != kIllegalCid) { | |
| 1626 ASSERT(field_cid != value_cid); | |
| 1627 ASSERT(field_length >= 0); | |
| 1628 // Field has a known class id and length. At compile time it is | |
| 1629 // known that the value's class id is not a fixed length list. | |
| 1630 __ jmp(fail); | |
| 1631 } else { | |
| 1632 ASSERT(field_cid == kIllegalCid); | |
| 1633 ASSERT(field_length == Field::kUnknownFixedLength); | |
| 1634 // Following jump cannot not occur, fall through. | |
| 1635 } | |
| 1636 __ j(NOT_EQUAL, fail); | |
| 1637 } | |
| 1638 // Not identical, possibly null. | |
| 1639 __ Bind(&skip_length_check); | |
| 1640 } | 1534 } |
| 1641 // Jump when class id guard and list length guard are okay. | 1535 // Jump when class id guard and list length guard are okay. |
|
Cutch
2014/05/28 14:13:31
remove list length from comment
Vyacheslav Egorov (Google)
2014/05/29 17:36:51
Done.
| |
| 1642 __ j(EQUAL, &ok); | 1536 __ j(EQUAL, &ok); |
| 1643 | 1537 |
| 1644 // Check if guard field is uninitialized. | 1538 // At this point the field guard is being initialized for the first time. |
| 1645 __ cmpl(field_cid_operand, Immediate(kIllegalCid)); | 1539 if (!field().needs_length_check()) { |
|
Florian Schneider
2014/05/28 14:57:36
Maybe add a comment that the GuardFieldLength is e
Vyacheslav Egorov (Google)
2014/05/29 17:36:51
Done.
| |
| 1646 // Jump to failure path when guard field has been initialized and | 1540 // Check if guard field is uninitialized. |
| 1647 // the field and value class ids do not not match. | 1541 __ cmpl(field_cid_operand, Immediate(kIllegalCid)); |
| 1648 __ j(NOT_EQUAL, fail); | 1542 // Jump to failure path when guard field has been initialized and |
| 1543 // the field and value class ids do not not match. | |
| 1544 __ j(NOT_EQUAL, fail); | |
| 1649 | 1545 |
| 1650 // At this point the field guard is being initialized for the first time. | 1546 if (value_cid == kDynamicCid) { |
| 1651 if (value_cid == kDynamicCid) { | 1547 // Do not know value's class id. |
| 1652 // Do not know value's class id. | 1548 __ movl(field_cid_operand, value_cid_reg); |
| 1653 __ movl(field_cid_operand, value_cid_reg); | 1549 __ movl(field_nullability_operand, value_cid_reg); |
| 1654 __ movl(field_nullability_operand, value_cid_reg); | 1550 } else { |
| 1655 if (field_has_length) { | 1551 ASSERT(field_reg != kNoRegister); |
| 1656 Label check_array, length_set, no_fixed_length; | 1552 __ movl(field_cid_operand, Immediate(value_cid)); |
| 1657 __ cmpl(value_cid_reg, Immediate(kNullCid)); | 1553 __ movl(field_nullability_operand, Immediate(value_cid)); |
| 1658 __ j(EQUAL, &no_fixed_length, Assembler::kNearJump); | |
| 1659 // Check for typed data array. | |
| 1660 __ cmpl(value_cid_reg, Immediate(kTypedDataInt32x4ArrayCid)); | |
| 1661 // Not a typed array or a regular array. | |
| 1662 __ j(GREATER, &no_fixed_length, Assembler::kNearJump); | |
| 1663 __ cmpl(value_cid_reg, Immediate(kTypedDataInt8ArrayCid)); | |
| 1664 // Could still be a regular array. | |
| 1665 __ j(LESS, &check_array, Assembler::kNearJump); | |
| 1666 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1667 __ movl(value_cid_reg, | |
| 1668 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1669 __ movl(field_length_operand, value_cid_reg); | |
| 1670 // Updated field length typed data array. | |
| 1671 __ jmp(&length_set, Assembler::kNearJump); | |
| 1672 // Check for regular array. | |
| 1673 __ Bind(&check_array); | |
| 1674 __ cmpl(value_cid_reg, Immediate(kImmutableArrayCid)); | |
| 1675 __ j(GREATER, &no_fixed_length, Assembler::kNearJump); | |
| 1676 __ cmpl(value_cid_reg, Immediate(kArrayCid)); | |
| 1677 __ j(LESS, &no_fixed_length, Assembler::kNearJump); | |
| 1678 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1679 __ movl(value_cid_reg, | |
| 1680 FieldAddress(value_reg, Array::length_offset())); | |
| 1681 __ movl(field_length_operand, value_cid_reg); | |
| 1682 // Updated field length from regular array. | |
| 1683 __ jmp(&length_set, Assembler::kNearJump); | |
| 1684 __ Bind(&no_fixed_length); | |
| 1685 __ movl(field_length_operand, | |
| 1686 Immediate(Smi::RawValue(Field::kNoFixedLength))); | |
| 1687 __ Bind(&length_set); | |
| 1688 } | 1554 } |
| 1689 } else { | 1555 |
| 1690 ASSERT(field_reg != kNoRegister); | 1556 if (deopt == NULL) { |
| 1691 __ movl(field_cid_operand, Immediate(value_cid)); | 1557 ASSERT(!compiler->is_optimizing()); |
| 1692 __ movl(field_nullability_operand, Immediate(value_cid)); | 1558 __ jmp(&ok); |
| 1693 if (field_has_length) { | |
| 1694 ASSERT(value_cid_reg != kNoRegister); | |
| 1695 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | |
| 1696 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1697 __ movl(value_cid_reg, | |
| 1698 FieldAddress(value_reg, Array::length_offset())); | |
| 1699 __ movl(field_length_operand, value_cid_reg); | |
| 1700 } else if (RawObject::IsTypedDataClassId(value_cid)) { | |
| 1701 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1702 __ movl(value_cid_reg, | |
| 1703 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1704 __ movl(field_length_operand, value_cid_reg); | |
| 1705 } else { | |
| 1706 __ movl(field_length_operand, | |
| 1707 Immediate(Smi::RawValue(Field::kNoFixedLength))); | |
| 1708 } | |
| 1709 } | 1559 } |
| 1710 } | 1560 } |
| 1711 | 1561 |
| 1712 if (deopt == NULL) { | 1562 if (deopt == NULL) { |
| 1713 ASSERT(!compiler->is_optimizing()); | 1563 ASSERT(!compiler->is_optimizing()); |
| 1714 __ jmp(&ok); | |
| 1715 __ Bind(fail); | 1564 __ Bind(fail); |
| 1716 | 1565 |
| 1717 __ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()), | 1566 __ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()), |
| 1718 Immediate(kDynamicCid)); | 1567 Immediate(kDynamicCid)); |
| 1719 __ j(EQUAL, &ok); | 1568 __ j(EQUAL, &ok); |
| 1720 | 1569 |
| 1721 __ pushl(field_reg); | 1570 __ pushl(field_reg); |
| 1722 __ pushl(value_reg); | 1571 __ pushl(value_reg); |
| 1723 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); | 1572 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); |
| 1724 __ Drop(2); // Drop the field and the value. | 1573 __ Drop(2); // Drop the field and the value. |
| 1725 } | 1574 } |
| 1726 } else { | 1575 } else { |
| 1727 ASSERT(compiler->is_optimizing()); | 1576 ASSERT(compiler->is_optimizing()); |
| 1728 ASSERT(deopt != NULL); | 1577 ASSERT(deopt != NULL); |
| 1578 ASSERT(fail == deopt); | |
| 1579 | |
| 1729 // Field guard class has been initialized and is known. | 1580 // Field guard class has been initialized and is known. |
| 1730 if (field_reg != kNoRegister) { | |
| 1731 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); | |
| 1732 } | |
| 1733 | |
| 1734 if (value_cid == kDynamicCid) { | 1581 if (value_cid == kDynamicCid) { |
| 1735 // Value's class id is not known. | 1582 // Value's class id is not known. |
| 1736 __ testl(value_reg, Immediate(kSmiTagMask)); | 1583 __ testl(value_reg, Immediate(kSmiTagMask)); |
| 1737 | 1584 |
| 1738 if (field_cid != kSmiCid) { | 1585 if (field_cid != kSmiCid) { |
| 1739 __ j(ZERO, fail); | 1586 __ j(ZERO, fail); |
| 1740 __ LoadClassId(value_cid_reg, value_reg); | 1587 __ LoadClassId(value_cid_reg, value_reg); |
| 1741 __ cmpl(value_cid_reg, Immediate(field_cid)); | 1588 __ cmpl(value_cid_reg, Immediate(field_cid)); |
| 1742 } | 1589 } |
| 1743 | 1590 |
| 1744 if (field_has_length) { | |
| 1745 // Jump when Value CID != Field guard CID | |
| 1746 __ j(NOT_EQUAL, fail); | |
| 1747 | |
| 1748 // Classes are same, perform guarded list length check. | |
| 1749 ASSERT(field_reg != kNoRegister); | |
| 1750 ASSERT(value_cid_reg != kNoRegister); | |
| 1751 FieldAddress field_length_operand( | |
| 1752 field_reg, Field::guarded_list_length_offset()); | |
| 1753 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1754 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1755 __ movl(value_cid_reg, | |
| 1756 FieldAddress(value_reg, Array::length_offset())); | |
| 1757 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1758 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1759 __ movl(value_cid_reg, | |
| 1760 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1761 } | |
| 1762 __ cmpl(value_cid_reg, field_length_operand); | |
| 1763 } | |
| 1764 | |
| 1765 if (field().is_nullable() && (field_cid != kNullCid)) { | 1591 if (field().is_nullable() && (field_cid != kNullCid)) { |
| 1766 __ j(EQUAL, &ok); | 1592 __ j(EQUAL, &ok); |
| 1767 const Immediate& raw_null = | 1593 const Immediate& raw_null = |
| 1768 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1594 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1769 __ cmpl(value_reg, raw_null); | 1595 __ cmpl(value_reg, raw_null); |
| 1770 } | 1596 } |
| 1771 __ j(NOT_EQUAL, fail); | 1597 __ j(NOT_EQUAL, fail); |
| 1772 } else { | 1598 } else { |
| 1773 // Both value's and field's class id is known. | 1599 // Both value's and field's class id is known. |
| 1774 if ((value_cid != field_cid) && (value_cid != nullability)) { | 1600 ASSERT((value_cid != field_cid) && (value_cid != nullability)); |
| 1775 __ jmp(fail); | 1601 __ jmp(fail); |
| 1776 } else if (field_has_length && (value_cid == field_cid)) { | |
| 1777 ASSERT(value_cid_reg != kNoRegister); | |
| 1778 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1779 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1780 __ movl(value_cid_reg, | |
| 1781 FieldAddress(value_reg, Array::length_offset())); | |
| 1782 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1783 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1784 __ movl(value_cid_reg, | |
| 1785 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1786 } | |
| 1787 __ cmpl(value_cid_reg, Immediate(Smi::RawValue(field_length))); | |
| 1788 __ j(NOT_EQUAL, fail); | |
| 1789 } else { | |
| 1790 UNREACHABLE(); | |
| 1791 } | |
| 1792 } | 1602 } |
| 1793 } | 1603 } |
| 1794 __ Bind(&ok); | 1604 __ Bind(&ok); |
| 1795 } | 1605 } |
| 1796 | 1606 |
| 1797 | 1607 |
| 1608 LocationSummary* GuardFieldLengthInstr::MakeLocationSummary(Isolate* isolate, | |
| 1609 bool opt) const { | |
| 1610 const intptr_t kNumInputs = 1; | |
| 1611 LocationSummary* summary = new(isolate) LocationSummary( | |
| 1612 isolate, kNumInputs, 0, LocationSummary::kNoCall); | |
| 1613 summary->set_in(0, Location::RequiresRegister()); | |
| 1614 | |
| 1615 if (!opt || (field().guarded_list_length() == Field::kUnknownFixedLength)) { | |
| 1616 // We need temporaries for field object, length offset and expected length. | |
| 1617 summary->AddTemp(Location::RequiresRegister()); | |
| 1618 summary->AddTemp(Location::RequiresRegister()); | |
| 1619 summary->AddTemp(Location::RequiresRegister()); | |
| 1620 } | |
| 1621 | |
| 1622 return summary; | |
| 1623 } | |
| 1624 | |
| 1625 | |
| 1626 void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 1627 if (field().guarded_list_length() == Field::kNoFixedLength) { | |
|
Florian Schneider
2014/05/28 14:57:36
ASSERT(!compiler->is_optimizing())?
In optimizing
Vyacheslav Egorov (Google)
2014/05/29 17:36:51
Done.
| |
| 1628 return; | |
| 1629 } | |
| 1630 | |
| 1631 Register value_reg = locs()->in(0).reg(); | |
| 1632 | |
| 1633 if (!compiler->is_optimizing() || | |
| 1634 (field().guarded_list_length() == Field::kUnknownFixedLength)) { | |
| 1635 Register field_reg = locs()->temp(0).reg(); | |
| 1636 Register offset_reg = locs()->temp(1).reg(); | |
| 1637 Register length_reg = locs()->temp(2).reg(); | |
| 1638 | |
| 1639 Label ok; | |
| 1640 | |
| 1641 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); | |
| 1642 | |
| 1643 __ movl(offset_reg, FieldAddress(field_reg, | |
| 1644 Field::guarded_list_length_in_object_offset_offset())); | |
| 1645 __ movl(length_reg, FieldAddress(field_reg, | |
| 1646 Field::guarded_list_length_offset())); | |
| 1647 | |
| 1648 __ cmpl(offset_reg, Immediate(0)); | |
|
Cutch
2014/05/28 14:13:31
move the compare / jmp above the load of length_re
Florian Schneider
2014/05/28 14:57:36
Maybe
__ cmpl(offset_reg, Immediate(kUnknownLeng
Vyacheslav Egorov (Google)
2014/05/29 17:36:51
I am doing some manual scheduling here. Keeping lo
Vyacheslav Egorov (Google)
2014/05/29 17:36:51
I could, but on MIPS I would have to load immediat
| |
| 1649 __ j(NEGATIVE, &ok); | |
| 1650 | |
| 1651 __ cmpl(length_reg, FieldAddress(value_reg, offset_reg, TIMES_1, 0)); | |
| 1652 __ j(EQUAL, &ok); | |
| 1653 | |
| 1654 __ pushl(field_reg); | |
| 1655 __ pushl(value_reg); | |
| 1656 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); | |
| 1657 __ Drop(2); // Drop the field and the value. | |
| 1658 | |
| 1659 __ Bind(&ok); | |
| 1660 } else { | |
| 1661 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField); | |
| 1662 | |
| 1663 ASSERT(compiler->is_optimizing()); | |
| 1664 ASSERT(field().guarded_list_length() >= 0); | |
| 1665 | |
|
Florian Schneider
2014/05/28 14:57:36
ASSERT(field().guarded_list_length_in_object_offse
Vyacheslav Egorov (Google)
2014/05/29 17:36:51
Done.
| |
| 1666 __ cmpl(FieldAddress(value_reg, | |
| 1667 field().guarded_list_length_in_object_offset()), | |
| 1668 Immediate(Smi::RawValue(field().guarded_list_length()))); | |
| 1669 __ j(NOT_EQUAL, deopt); | |
| 1670 } | |
| 1671 } | |
| 1672 | |
| 1673 | |
| 1798 class StoreInstanceFieldSlowPath : public SlowPathCode { | 1674 class StoreInstanceFieldSlowPath : public SlowPathCode { |
| 1799 public: | 1675 public: |
| 1800 StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction, | 1676 StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction, |
| 1801 const Class& cls) | 1677 const Class& cls) |
| 1802 : instruction_(instruction), cls_(cls) { } | 1678 : instruction_(instruction), cls_(cls) { } |
| 1803 | 1679 |
| 1804 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { | 1680 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1805 __ Comment("StoreInstanceFieldSlowPath"); | 1681 __ Comment("StoreInstanceFieldSlowPath"); |
| 1806 __ Bind(entry_label()); | 1682 __ Bind(entry_label()); |
| 1807 const Code& stub = | 1683 const Code& stub = |
| (...skipping 4575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6383 PcDescriptors::kOther, | 6259 PcDescriptors::kOther, |
| 6384 locs()); | 6260 locs()); |
| 6385 __ Drop(ArgumentCount()); // Discard arguments. | 6261 __ Drop(ArgumentCount()); // Discard arguments. |
| 6386 } | 6262 } |
| 6387 | 6263 |
| 6388 } // namespace dart | 6264 } // namespace dart |
| 6389 | 6265 |
| 6390 #undef __ | 6266 #undef __ |
| 6391 | 6267 |
| 6392 #endif // defined TARGET_ARCH_IA32 | 6268 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |