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_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 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 1449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1460 case kTypedDataInt32x4ArrayCid: | 1460 case kTypedDataInt32x4ArrayCid: |
| 1461 case kTypedDataFloat32x4ArrayCid: | 1461 case kTypedDataFloat32x4ArrayCid: |
| 1462 UNIMPLEMENTED(); | 1462 UNIMPLEMENTED(); |
| 1463 break; | 1463 break; |
| 1464 default: | 1464 default: |
| 1465 UNREACHABLE(); | 1465 UNREACHABLE(); |
| 1466 } | 1466 } |
| 1467 } | 1467 } |
| 1468 | 1468 |
| 1469 | 1469 |
| 1470 LocationSummary* GuardFieldInstr::MakeLocationSummary(Isolate* isolate, | 1470 LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Isolate* isolate, |
| 1471 bool opt) const { | 1471 bool opt) const { |
| 1472 const intptr_t kNumInputs = 1; | 1472 const intptr_t kNumInputs = 1; |
| 1473 LocationSummary* summary = new(isolate) LocationSummary( | 1473 LocationSummary* summary = new(isolate) LocationSummary( |
| 1474 isolate, kNumInputs, 0, LocationSummary::kNoCall); | 1474 isolate, kNumInputs, 0, LocationSummary::kNoCall); |
| 1475 summary->set_in(0, Location::RequiresRegister()); | 1475 summary->set_in(0, Location::RequiresRegister()); |
| 1476 const bool field_has_length = field().needs_length_check(); | 1476 |
| 1477 const bool need_value_temp_reg = | 1477 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1478 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) && | 1478 const intptr_t field_cid = field().guarded_cid(); |
| 1479 (field().guarded_cid() != kSmiCid))); | 1479 |
| 1480 if (need_value_temp_reg) { | 1480 const bool emit_full_guard = !opt || (field_cid == kIllegalCid); |
| 1481 const bool needs_value_cid_temp_reg = | |
| 1482 (value_cid == kDynamicCid) && (emit_full_guard || (field_cid != kSmiCid)); | |
| 1483 const bool needs_field_temp_reg = emit_full_guard; | |
| 1484 | |
| 1485 if (needs_value_cid_temp_reg) { | |
| 1481 summary->AddTemp(Location::RequiresRegister()); | 1486 summary->AddTemp(Location::RequiresRegister()); |
| 1482 } | 1487 } |
| 1483 const bool need_field_temp_reg = | 1488 |
| 1484 field_has_length || (field().guarded_cid() == kIllegalCid); | 1489 if (needs_field_temp_reg) { |
| 1485 if (need_field_temp_reg) { | |
| 1486 summary->AddTemp(Location::RequiresRegister()); | 1490 summary->AddTemp(Location::RequiresRegister()); |
| 1487 } | 1491 } |
| 1492 | |
| 1488 return summary; | 1493 return summary; |
| 1489 } | 1494 } |
| 1490 | 1495 |
| 1491 | 1496 |
| 1492 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1497 void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1493 __ TraceSimMsg("GuardFieldInstr"); | 1498 __ TraceSimMsg("GuardFieldClassInstr"); |
| 1499 | |
| 1500 const intptr_t value_cid = value()->Type()->ToCid(); | |
| 1494 const intptr_t field_cid = field().guarded_cid(); | 1501 const intptr_t field_cid = field().guarded_cid(); |
| 1495 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; | 1502 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; |
| 1496 const intptr_t field_length = field().guarded_list_length(); | |
| 1497 const bool field_has_length = field().needs_length_check(); | |
| 1498 const bool needs_value_temp_reg = | |
| 1499 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) && | |
| 1500 (field().guarded_cid() != kSmiCid))); | |
| 1501 const bool needs_field_temp_reg = | |
| 1502 field_has_length || (field().guarded_cid() == kIllegalCid); | |
| 1503 if (field_has_length) { | |
| 1504 // Currently, we should only see final fields that remember length. | |
| 1505 ASSERT(field().is_final()); | |
| 1506 } | |
| 1507 | 1503 |
| 1508 if (field_cid == kDynamicCid) { | 1504 if (field_cid == kDynamicCid) { |
| 1509 ASSERT(!compiler->is_optimizing()); | 1505 ASSERT(!compiler->is_optimizing()); |
| 1510 return; // Nothing to emit. | 1506 return; // Nothing to emit. |
| 1511 } | 1507 } |
| 1512 | 1508 |
| 1513 const intptr_t value_cid = value()->Type()->ToCid(); | 1509 const bool emit_full_guard = |
| 1510 !compiler->is_optimizing() || (field_cid == kIllegalCid); | |
| 1511 | |
| 1512 const bool needs_value_cid_temp_reg = | |
| 1513 (value_cid == kDynamicCid) && (emit_full_guard || (field_cid != kSmiCid)); | |
| 1514 | |
| 1515 const bool needs_field_temp_reg = emit_full_guard; | |
| 1514 | 1516 |
| 1515 Register value_reg = locs()->in(0).reg(); | 1517 Register value_reg = locs()->in(0).reg(); |
|
zra
2014/05/29 18:20:34
const Register here and below.
Vyacheslav Egorov (Google)
2014/06/02 10:48:37
Done.
| |
| 1516 | 1518 |
| 1517 Register value_cid_reg = needs_value_temp_reg ? | 1519 Register value_cid_reg = needs_value_cid_temp_reg ? |
| 1518 locs()->temp(0).reg() : kNoRegister; | 1520 locs()->temp(0).reg() : kNoRegister; |
| 1519 | 1521 |
| 1520 Register field_reg = needs_field_temp_reg ? | 1522 Register field_reg = needs_field_temp_reg ? |
| 1521 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; | 1523 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; |
| 1522 | 1524 |
| 1523 Label ok, fail_label; | 1525 Label ok, fail_label; |
| 1524 | 1526 |
| 1525 Label* deopt = compiler->is_optimizing() ? | 1527 Label* deopt = compiler->is_optimizing() ? |
| 1526 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; | 1528 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; |
| 1527 | 1529 |
| 1528 Label* fail = (deopt != NULL) ? deopt : &fail_label; | 1530 Label* fail = (deopt != NULL) ? deopt : &fail_label; |
| 1529 | 1531 |
| 1530 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) { | 1532 if (emit_full_guard) { |
| 1531 if (!compiler->is_optimizing() && (field_reg == kNoRegister)) { | |
| 1532 // Currently we can't have different location summaries for optimized | |
| 1533 // and non-optimized code. So instead we manually pick up a register | |
| 1534 // that is known to be free because we know how non-optimizing compiler | |
| 1535 // allocates registers. | |
| 1536 field_reg = A0; | |
| 1537 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg)); | |
| 1538 } | |
| 1539 | |
| 1540 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); | 1533 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); |
| 1541 | 1534 |
| 1542 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); | 1535 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); |
| 1543 FieldAddress field_nullability_operand( | 1536 FieldAddress field_nullability_operand( |
| 1544 field_reg, Field::is_nullable_offset()); | 1537 field_reg, Field::is_nullable_offset()); |
| 1545 FieldAddress field_length_operand( | |
| 1546 field_reg, Field::guarded_list_length_offset()); | |
| 1547 | 1538 |
| 1548 if (value_cid == kDynamicCid) { | 1539 if (value_cid == kDynamicCid) { |
| 1549 if (value_cid_reg == kNoRegister) { | |
| 1550 ASSERT(!compiler->is_optimizing()); | |
| 1551 value_cid_reg = A1; | |
| 1552 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg)); | |
| 1553 } | |
| 1554 | |
| 1555 LoadValueCid(compiler, value_cid_reg, value_reg); | 1540 LoadValueCid(compiler, value_cid_reg, value_reg); |
| 1556 | 1541 |
| 1557 Label skip_length_check; | |
| 1558 | |
| 1559 __ lw(CMPRES1, field_cid_operand); | 1542 __ lw(CMPRES1, field_cid_operand); |
| 1560 __ bne(value_cid_reg, CMPRES1, &skip_length_check); | 1543 __ beq(value_cid_reg, CMPRES1, &ok); |
| 1561 if (field_has_length) { | |
| 1562 // Field guard may have remembered list length, check it. | |
| 1563 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1564 __ lw(TMP, FieldAddress(value_reg, Array::length_offset())); | |
| 1565 __ LoadImmediate(CMPRES1, Smi::RawValue(field_length)); | |
| 1566 __ subu(CMPRES1, TMP, CMPRES1); | |
| 1567 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1568 __ lw(TMP, FieldAddress(value_reg, TypedData::length_offset())); | |
| 1569 __ LoadImmediate(CMPRES1, Smi::RawValue(field_length)); | |
| 1570 __ subu(CMPRES1, TMP, CMPRES1); | |
| 1571 } else { | |
| 1572 ASSERT(field_cid == kIllegalCid); | |
| 1573 ASSERT(field_length == Field::kUnknownFixedLength); | |
| 1574 // At compile time we do not know the type of the field nor its | |
| 1575 // length. At execution time we may have set the class id and | |
| 1576 // list length so we compare the guarded length with the | |
| 1577 // list length here, without this check the list length could change | |
| 1578 // without triggering a deoptimization. | |
| 1579 Label check_array, length_compared, no_fixed_length; | |
| 1580 // If length is negative the length guard is either disabled or | |
| 1581 // has not been initialized, either way it is safe to skip the | |
| 1582 // length check. | |
| 1583 __ lw(CMPRES1, field_length_operand); | |
| 1584 __ BranchSignedLess(CMPRES1, 0, &skip_length_check); | |
| 1585 __ BranchEqual(value_cid_reg, kNullCid, &no_fixed_length); | |
| 1586 // Check for typed data array. | |
| 1587 __ BranchSignedGreater(value_cid_reg, kTypedDataInt32x4ArrayCid, | |
| 1588 &no_fixed_length); | |
| 1589 __ BranchSignedLess(value_cid_reg, kTypedDataInt8ArrayCid, | |
| 1590 &check_array); | |
| 1591 __ lw(TMP, FieldAddress(value_reg, TypedData::length_offset())); | |
| 1592 __ lw(CMPRES1, field_length_operand); | |
| 1593 __ subu(CMPRES1, TMP, CMPRES1); | |
| 1594 __ b(&length_compared); | |
| 1595 // Check for regular array. | |
| 1596 __ Bind(&check_array); | |
| 1597 __ BranchSignedGreater(value_cid_reg, kImmutableArrayCid, | |
| 1598 &no_fixed_length); | |
| 1599 __ BranchSignedLess(value_cid_reg, kArrayCid, &no_fixed_length); | |
| 1600 __ lw(TMP, FieldAddress(value_reg, Array::length_offset())); | |
| 1601 __ lw(CMPRES1, field_length_operand); | |
| 1602 __ subu(CMPRES1, TMP, CMPRES1); | |
| 1603 __ b(&length_compared); | |
| 1604 __ Bind(&no_fixed_length); | |
| 1605 __ b(fail); | |
| 1606 __ Bind(&length_compared); | |
| 1607 } | |
| 1608 __ bne(CMPRES1, ZR, fail); | |
| 1609 } | |
| 1610 __ Bind(&skip_length_check); | |
| 1611 __ lw(TMP, field_nullability_operand); | 1544 __ lw(TMP, field_nullability_operand); |
| 1612 __ subu(CMPRES1, value_cid_reg, TMP); | 1545 __ subu(CMPRES1, value_cid_reg, TMP); |
| 1613 } else if (value_cid == kNullCid) { | 1546 } else if (value_cid == kNullCid) { |
| 1614 __ lw(TMP, field_nullability_operand); | 1547 __ lw(TMP, field_nullability_operand); |
| 1615 __ LoadImmediate(CMPRES1, value_cid); | 1548 __ LoadImmediate(CMPRES1, value_cid); |
| 1616 __ subu(CMPRES1, TMP, CMPRES1); | 1549 __ subu(CMPRES1, TMP, CMPRES1); |
| 1617 } else { | 1550 } else { |
| 1618 Label skip_length_check; | |
| 1619 __ lw(TMP, field_cid_operand); | 1551 __ lw(TMP, field_cid_operand); |
| 1620 __ LoadImmediate(CMPRES1, value_cid); | 1552 __ LoadImmediate(CMPRES1, value_cid); |
| 1621 __ subu(CMPRES1, TMP, CMPRES1); | 1553 __ subu(CMPRES1, TMP, CMPRES1); |
| 1622 __ bne(CMPRES1, ZR, &skip_length_check); | |
| 1623 // Insert length check. | |
| 1624 if (field_has_length) { | |
| 1625 ASSERT(value_cid_reg != kNoRegister); | |
| 1626 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | |
| 1627 __ lw(TMP, FieldAddress(value_reg, Array::length_offset())); | |
| 1628 __ LoadImmediate(CMPRES1, Smi::RawValue(field_length)); | |
| 1629 __ subu(CMPRES1, TMP, CMPRES1); | |
| 1630 } else if (RawObject::IsTypedDataClassId(value_cid)) { | |
| 1631 __ lw(TMP, FieldAddress(value_reg, TypedData::length_offset())); | |
| 1632 __ LoadImmediate(CMPRES1, Smi::RawValue(field_length)); | |
| 1633 __ subu(CMPRES1, TMP, CMPRES1); | |
| 1634 } else if (field_cid != kIllegalCid) { | |
| 1635 ASSERT(field_cid != value_cid); | |
| 1636 ASSERT(field_length >= 0); | |
| 1637 // Field has a known class id and length. At compile time it is | |
| 1638 // known that the value's class id is not a fixed length list. | |
| 1639 __ b(fail); | |
| 1640 } else { | |
| 1641 ASSERT(field_cid == kIllegalCid); | |
| 1642 ASSERT(field_length == Field::kUnknownFixedLength); | |
| 1643 // Following jump cannot not occur, fall through. | |
| 1644 } | |
| 1645 __ bne(CMPRES1, ZR, fail); | |
| 1646 } | |
| 1647 __ Bind(&skip_length_check); | |
| 1648 } | 1554 } |
| 1649 __ beq(CMPRES1, ZR, &ok); | 1555 __ beq(CMPRES1, ZR, &ok); |
| 1650 | 1556 |
| 1651 __ lw(CMPRES1, field_cid_operand); | 1557 // Check if the tracked state of the guarded field can be initialized |
| 1652 __ BranchNotEqual(CMPRES1, kIllegalCid, fail); | 1558 // inline. If the field needs length check we fall through to runtime |
| 1559 // which is responsible for computing offset of the length field | |
| 1560 // based on the class id. | |
| 1561 // Length guard will be emitted separately when needed via GuardFieldLength | |
| 1562 // instruction after GuardFieldClass. | |
| 1563 if (!field().needs_length_check()) { | |
| 1564 // Uninitialized field can be handled inline. Check if the | |
| 1565 // field is still unitialized. | |
| 1566 __ lw(CMPRES1, field_cid_operand); | |
| 1567 __ BranchNotEqual(CMPRES1, kIllegalCid, fail); | |
| 1653 | 1568 |
| 1654 if (value_cid == kDynamicCid) { | 1569 if (value_cid == kDynamicCid) { |
| 1655 __ sw(value_cid_reg, field_cid_operand); | 1570 __ sw(value_cid_reg, field_cid_operand); |
| 1656 __ sw(value_cid_reg, field_nullability_operand); | 1571 __ sw(value_cid_reg, field_nullability_operand); |
| 1657 if (field_has_length) { | 1572 } else { |
| 1658 Label check_array, length_set, no_fixed_length; | 1573 __ LoadImmediate(TMP, value_cid); |
| 1659 __ BranchEqual(value_cid_reg, kNullCid, &no_fixed_length); | 1574 __ sw(TMP, field_cid_operand); |
| 1660 // Check for typed data array. | 1575 __ sw(TMP, field_nullability_operand); |
| 1661 __ BranchSignedGreater(value_cid_reg, kTypedDataInt32x4ArrayCid, | |
| 1662 &no_fixed_length); | |
| 1663 __ BranchSignedLess(value_cid_reg, kTypedDataInt8ArrayCid, | |
| 1664 &check_array); | |
| 1665 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1666 __ lw(value_cid_reg, | |
| 1667 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1668 __ sw(value_cid_reg, field_length_operand); | |
| 1669 // Updated field length typed data array. | |
| 1670 __ b(&length_set); | |
| 1671 // Check for regular array. | |
| 1672 __ Bind(&check_array); | |
| 1673 __ BranchSignedGreater(value_cid_reg, kImmutableArrayCid, | |
| 1674 &no_fixed_length); | |
| 1675 __ BranchSignedLess(value_cid_reg, kArrayCid, &no_fixed_length); | |
| 1676 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1677 __ lw(value_cid_reg, | |
| 1678 FieldAddress(value_reg, Array::length_offset())); | |
| 1679 __ sw(value_cid_reg, field_length_operand); | |
| 1680 // Updated field length from regular array. | |
| 1681 __ b(&length_set); | |
| 1682 __ Bind(&no_fixed_length); | |
| 1683 __ LoadImmediate(TMP, Smi::RawValue(Field::kNoFixedLength)); | |
| 1684 __ sw(TMP, field_length_operand); | |
| 1685 __ Bind(&length_set); | |
| 1686 } | 1576 } |
| 1687 } else { | 1577 |
| 1688 ASSERT(field_reg != kNoRegister); | 1578 if (deopt == NULL) { |
| 1689 __ LoadImmediate(TMP, value_cid); | 1579 ASSERT(!compiler->is_optimizing()); |
| 1690 __ sw(TMP, field_cid_operand); | 1580 __ b(&ok); |
| 1691 __ sw(TMP, field_nullability_operand); | |
| 1692 if (field_has_length) { | |
| 1693 ASSERT(value_cid_reg != kNoRegister); | |
| 1694 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | |
| 1695 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1696 __ lw(value_cid_reg, | |
| 1697 FieldAddress(value_reg, Array::length_offset())); | |
| 1698 __ sw(value_cid_reg, field_length_operand); | |
| 1699 } else if (RawObject::IsTypedDataClassId(value_cid)) { | |
| 1700 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1701 __ lw(value_cid_reg, | |
| 1702 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1703 __ sw(value_cid_reg, field_length_operand); | |
| 1704 } else { | |
| 1705 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1706 __ LoadImmediate(value_cid_reg, Smi::RawValue(Field::kNoFixedLength)); | |
| 1707 __ sw(value_cid_reg, field_length_operand); | |
| 1708 } | |
| 1709 } | 1581 } |
| 1710 } | 1582 } |
| 1711 | 1583 |
| 1712 if (deopt == NULL) { | 1584 if (deopt == NULL) { |
| 1713 ASSERT(!compiler->is_optimizing()); | 1585 ASSERT(!compiler->is_optimizing()); |
| 1714 __ b(&ok); | |
| 1715 __ Bind(fail); | 1586 __ Bind(fail); |
| 1716 | 1587 |
| 1717 __ lw(CMPRES1, FieldAddress(field_reg, Field::guarded_cid_offset())); | 1588 __ lw(CMPRES1, FieldAddress(field_reg, Field::guarded_cid_offset())); |
| 1718 __ BranchEqual(CMPRES1, kDynamicCid, &ok); | 1589 __ BranchEqual(CMPRES1, kDynamicCid, &ok); |
| 1719 | 1590 |
| 1720 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1591 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1721 __ sw(field_reg, Address(SP, 1 * kWordSize)); | 1592 __ sw(field_reg, Address(SP, 1 * kWordSize)); |
| 1722 __ sw(value_reg, Address(SP, 0 * kWordSize)); | 1593 __ sw(value_reg, Address(SP, 0 * kWordSize)); |
| 1723 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); | 1594 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); |
| 1724 __ Drop(2); // Drop the field and the value. | 1595 __ Drop(2); // Drop the field and the value. |
| 1725 } | 1596 } |
| 1726 } else { | 1597 } else { |
| 1727 ASSERT(compiler->is_optimizing()); | 1598 ASSERT(compiler->is_optimizing()); |
| 1728 ASSERT(deopt != NULL); | 1599 ASSERT(deopt != NULL); |
| 1600 | |
| 1729 // Field guard class has been initialized and is known. | 1601 // Field guard class has been initialized and is known. |
| 1730 if (field_reg != kNoRegister) { | |
| 1731 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); | |
| 1732 } | |
| 1733 if (value_cid == kDynamicCid) { | 1602 if (value_cid == kDynamicCid) { |
| 1734 // Field's guarded class id is fixed by value's class id is not known. | 1603 // Value's class id is not known. |
| 1735 __ andi(CMPRES1, value_reg, Immediate(kSmiTagMask)); | 1604 __ andi(CMPRES1, value_reg, Immediate(kSmiTagMask)); |
| 1736 | 1605 |
| 1737 if (field_cid != kSmiCid) { | 1606 if (field_cid != kSmiCid) { |
| 1738 __ beq(CMPRES1, ZR, fail); | 1607 __ beq(CMPRES1, ZR, fail); |
| 1739 __ LoadClassId(value_cid_reg, value_reg); | 1608 __ LoadClassId(value_cid_reg, value_reg); |
| 1740 __ LoadImmediate(TMP, field_cid); | 1609 __ LoadImmediate(TMP, field_cid); |
| 1741 __ subu(CMPRES1, value_cid_reg, TMP); | 1610 __ subu(CMPRES1, value_cid_reg, TMP); |
| 1742 } | 1611 } |
| 1743 | 1612 |
| 1744 if (field_has_length) { | |
| 1745 // Jump when Value CID != Field guard CID | |
| 1746 __ bne(CMPRES1, ZR, fail); | |
| 1747 // Classes are same, perform guarded list length check. | |
| 1748 ASSERT(field_reg != kNoRegister); | |
| 1749 ASSERT(value_cid_reg != kNoRegister); | |
| 1750 FieldAddress field_length_operand( | |
| 1751 field_reg, Field::guarded_list_length_offset()); | |
| 1752 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1753 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1754 __ lw(value_cid_reg, | |
| 1755 FieldAddress(value_reg, Array::length_offset())); | |
| 1756 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1757 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1758 __ lw(value_cid_reg, | |
| 1759 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1760 } | |
| 1761 __ lw(TMP, field_length_operand); | |
| 1762 __ subu(CMPRES1, value_cid_reg, TMP); | |
| 1763 } | |
| 1764 | |
| 1765 if (field().is_nullable() && (field_cid != kNullCid)) { | 1613 if (field().is_nullable() && (field_cid != kNullCid)) { |
| 1766 __ beq(CMPRES1, ZR, &ok); | 1614 __ beq(CMPRES1, ZR, &ok); |
| 1767 __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null())); | 1615 if (field_cid != kSmiCid) { |
| 1768 __ subu(CMPRES1, value_reg, TMP); | 1616 __ LoadImmediate(TMP, kNullCid); |
| 1617 __ subu(CMPRES1, value_cid_reg, TMP); | |
| 1618 } else { | |
| 1619 __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null())); | |
| 1620 __ subu(CMPRES1, value_reg, TMP); | |
| 1621 } | |
| 1769 } | 1622 } |
| 1770 | 1623 |
| 1771 __ bne(CMPRES1, ZR, fail); | 1624 __ bne(CMPRES1, ZR, fail); |
| 1772 } else { | 1625 } else { |
| 1773 // Both value's and field's class id is known. | 1626 // Both value's and field's class id is known. |
| 1774 if ((value_cid != field_cid) && (value_cid != nullability)) { | 1627 ASSERT((value_cid != field_cid) && (value_cid != nullability)); |
| 1775 __ b(fail); | 1628 __ b(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 __ lw(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 __ lw(value_cid_reg, | |
| 1785 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1786 } | |
| 1787 __ LoadImmediate(TMP, Smi::RawValue(field_length)); | |
| 1788 __ subu(CMPRES1, value_cid_reg, TMP); | |
| 1789 __ bne(CMPRES1, ZR, fail); | |
| 1790 } else { | |
| 1791 UNREACHABLE(); | |
| 1792 } | |
| 1793 } | 1629 } |
| 1794 } | 1630 } |
| 1795 __ Bind(&ok); | 1631 __ Bind(&ok); |
| 1796 } | 1632 } |
| 1797 | 1633 |
| 1798 | 1634 |
| 1635 LocationSummary* GuardFieldLengthInstr::MakeLocationSummary(Isolate* isolate, | |
| 1636 bool opt) const { | |
| 1637 const intptr_t kNumInputs = 1; | |
| 1638 LocationSummary* summary = new(isolate) LocationSummary( | |
| 1639 isolate, kNumInputs, 0, LocationSummary::kNoCall); | |
| 1640 summary->set_in(0, Location::RequiresRegister()); | |
| 1641 | |
| 1642 if (!opt || (field().guarded_list_length() == Field::kUnknownFixedLength)) { | |
| 1643 // We need temporary for field object. | |
| 1644 summary->AddTemp(Location::RequiresRegister()); | |
| 1645 } | |
| 1646 | |
| 1647 return summary; | |
| 1648 } | |
| 1649 | |
| 1650 | |
| 1651 void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 1652 if (field().guarded_list_length() == Field::kNoFixedLength) { | |
| 1653 ASSERT(!compiler->is_optimizing()); | |
| 1654 return; // Nothing to emit. | |
| 1655 } | |
| 1656 | |
| 1657 Register value_reg = locs()->in(0).reg(); | |
| 1658 | |
| 1659 if (!compiler->is_optimizing() || | |
| 1660 (field().guarded_list_length() == Field::kUnknownFixedLength)) { | |
| 1661 Register field_reg = locs()->temp(0).reg(); | |
| 1662 | |
| 1663 Label ok; | |
| 1664 | |
| 1665 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); | |
| 1666 | |
| 1667 __ lb(CMPRES1, FieldAddress(field_reg, | |
| 1668 Field::guarded_list_length_in_object_offset_offset())); | |
| 1669 __ lw(CMPRES2, FieldAddress(field_reg, | |
|
zra
2014/05/29 18:20:34
You can move this load to the branch delay slot of
Vyacheslav Egorov (Google)
2014/06/02 10:48:37
I just moved it to right after the branch. There i
| |
| 1670 Field::guarded_list_length_offset())); | |
| 1671 | |
| 1672 __ blez(CMPRES1, &ok); | |
| 1673 | |
| 1674 // Load the length from the value. GuardFieldClass already verified that | |
| 1675 // value's class matches guarded class id of the field. | |
| 1676 // CMPRES1 contains offset already corrected by -kHeapObjectTag that is | |
| 1677 // why we can use Address instead of FieldAddress. | |
| 1678 __ addu(TMP, value_reg, CMPRES1); | |
| 1679 __ lw(TMP, Address(TMP)); | |
| 1680 | |
| 1681 __ beq(CMPRES2, TMP, &ok); | |
| 1682 | |
| 1683 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | |
| 1684 __ sw(field_reg, Address(SP, 1 * kWordSize)); | |
| 1685 __ sw(value_reg, Address(SP, 0 * kWordSize)); | |
| 1686 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); | |
| 1687 __ Drop(2); // Drop the field and the value. | |
| 1688 | |
| 1689 __ Bind(&ok); | |
| 1690 } else { | |
| 1691 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField); | |
| 1692 | |
| 1693 ASSERT(compiler->is_optimizing()); | |
| 1694 ASSERT(field().guarded_list_length() >= 0); | |
| 1695 ASSERT(field().guarded_list_length_in_object_offset() != | |
| 1696 Field::kUnknownLengthOffset); | |
| 1697 | |
| 1698 __ lw(CMPRES1, | |
| 1699 FieldAddress(value_reg, | |
| 1700 field().guarded_list_length_in_object_offset())); | |
| 1701 __ LoadImmediate(TMP, Smi::RawValue(field().guarded_list_length())); | |
| 1702 __ bne(CMPRES1, TMP, deopt); | |
| 1703 } | |
| 1704 } | |
| 1705 | |
| 1706 | |
| 1799 class StoreInstanceFieldSlowPath : public SlowPathCode { | 1707 class StoreInstanceFieldSlowPath : public SlowPathCode { |
| 1800 public: | 1708 public: |
| 1801 StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction, | 1709 StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction, |
| 1802 const Class& cls) | 1710 const Class& cls) |
| 1803 : instruction_(instruction), cls_(cls) { } | 1711 : instruction_(instruction), cls_(cls) { } |
| 1804 | 1712 |
| 1805 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { | 1713 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1806 __ Comment("StoreInstanceFieldSlowPath"); | 1714 __ Comment("StoreInstanceFieldSlowPath"); |
| 1807 __ Bind(entry_label()); | 1715 __ Bind(entry_label()); |
| 1808 const Code& stub = | 1716 const Code& stub = |
| (...skipping 2948 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4757 compiler->GenerateCall(token_pos(), | 4665 compiler->GenerateCall(token_pos(), |
| 4758 &label, | 4666 &label, |
| 4759 PcDescriptors::kOther, | 4667 PcDescriptors::kOther, |
| 4760 locs()); | 4668 locs()); |
| 4761 __ Drop(ArgumentCount()); // Discard arguments. | 4669 __ Drop(ArgumentCount()); // Discard arguments. |
| 4762 } | 4670 } |
| 4763 | 4671 |
| 4764 } // namespace dart | 4672 } // namespace dart |
| 4765 | 4673 |
| 4766 #endif // defined TARGET_ARCH_MIPS | 4674 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |