Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Side by Side Diff: runtime/vm/intermediate_language_arm.cc

Issue 22915008: Tests for GuardField length check along with bug fixes (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/guard_field_test.cc ('k') | runtime/vm/intermediate_language_ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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_ARM. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM.
6 #if defined(TARGET_ARCH_ARM) 6 #if defined(TARGET_ARCH_ARM)
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 1425 matching lines...) Expand 10 before | Expand all | Expand 10 after
1436 } 1436 }
1437 } 1437 }
1438 1438
1439 1439
1440 LocationSummary* GuardFieldInstr::MakeLocationSummary() const { 1440 LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
1441 const intptr_t kNumInputs = 1; 1441 const intptr_t kNumInputs = 1;
1442 LocationSummary* summary = 1442 LocationSummary* summary =
1443 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall); 1443 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
1444 summary->set_in(0, Location::RequiresRegister()); 1444 summary->set_in(0, Location::RequiresRegister());
1445 const bool field_has_length = field().needs_length_check(); 1445 const bool field_has_length = field().needs_length_check();
1446 const bool need_value_temp_reg = 1446 summary->AddTemp(Location::RequiresRegister());
1447 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) && 1447 summary->AddTemp(Location::RequiresRegister());
1448 (field().guarded_cid() != kSmiCid)));
1449 if (need_value_temp_reg) {
1450 summary->AddTemp(Location::RequiresRegister());
1451 summary->AddTemp(Location::RequiresRegister());
1452 }
1453 const bool need_field_temp_reg = 1448 const bool need_field_temp_reg =
1454 field_has_length || (field().guarded_cid() == kIllegalCid); 1449 field_has_length || (field().guarded_cid() == kIllegalCid);
1455 if (need_field_temp_reg) { 1450 if (need_field_temp_reg) {
1456 summary->AddTemp(Location::RequiresRegister()); 1451 summary->AddTemp(Location::RequiresRegister());
1457 } 1452 }
1458 return summary; 1453 return summary;
1459 } 1454 }
1460 1455
1461 1456
1462 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 1457 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
1463 const intptr_t field_cid = field().guarded_cid(); 1458 const intptr_t field_cid = field().guarded_cid();
1464 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; 1459 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
1465 const intptr_t field_length = field().guarded_list_length(); 1460 const intptr_t field_length = field().guarded_list_length();
1466 const bool field_has_length = field().needs_length_check(); 1461 const bool field_has_length = field().needs_length_check();
1467 const bool needs_value_temp_reg =
1468 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
1469 (field().guarded_cid() != kSmiCid)));
1470 const bool needs_field_temp_reg = 1462 const bool needs_field_temp_reg =
1471 field_has_length || (field().guarded_cid() == kIllegalCid); 1463 field_has_length || (field().guarded_cid() == kIllegalCid);
1472 if (field_has_length) { 1464 if (field_has_length) {
1473 // Currently, we should only see final fields that remember length. 1465 // Currently, we should only see final fields that remember length.
1474 ASSERT(field().is_final()); 1466 ASSERT(field().is_final());
1475 } 1467 }
1476 1468
1477 if (field_cid == kDynamicCid) { 1469 if (field_cid == kDynamicCid) {
1478 ASSERT(!compiler->is_optimizing()); 1470 ASSERT(!compiler->is_optimizing());
1479 return; // Nothing to emit. 1471 return; // Nothing to emit.
1480 } 1472 }
1481 1473
1482 const intptr_t value_cid = value()->Type()->ToCid(); 1474 const intptr_t value_cid = value()->Type()->ToCid();
1483 1475
1484 Register value_reg = locs()->in(0).reg(); 1476 Register value_reg = locs()->in(0).reg();
1485 1477
1486 Register value_cid_reg = needs_value_temp_reg ? 1478 Register value_cid_reg = locs()->temp(0).reg();
1487 locs()->temp(0).reg() : kNoRegister; 1479
1488 Register temp_reg = needs_value_temp_reg ? 1480 Register temp_reg = locs()->temp(1).reg();
1489 locs()->temp(1).reg() : kNoRegister;
1490 1481
1491 Register field_reg = needs_field_temp_reg ? 1482 Register field_reg = needs_field_temp_reg ?
1492 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; 1483 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
1493 1484
1494 Label ok, fail_label; 1485 Label ok, fail_label;
1495 1486
1496 Label* deopt = compiler->is_optimizing() ? 1487 Label* deopt = compiler->is_optimizing() ?
1497 compiler->AddDeoptStub(deopt_id(), kDeoptGuardField) : NULL; 1488 compiler->AddDeoptStub(deopt_id(), kDeoptGuardField) : NULL;
1498 1489
1499 Label* fail = (deopt != NULL) ? deopt : &fail_label; 1490 Label* fail = (deopt != NULL) ? deopt : &fail_label;
(...skipping 11 matching lines...) Expand all
1511 } 1502 }
1512 1503
1513 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); 1504 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
1514 1505
1515 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); 1506 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
1516 FieldAddress field_nullability_operand( 1507 FieldAddress field_nullability_operand(
1517 field_reg, Field::is_nullable_offset()); 1508 field_reg, Field::is_nullable_offset());
1518 FieldAddress field_length_operand( 1509 FieldAddress field_length_operand(
1519 field_reg, Field::guarded_list_length_offset()); 1510 field_reg, Field::guarded_list_length_offset());
1520 1511
1521 if (value_cid_reg == kNoRegister) { 1512 ASSERT(value_cid_reg != kNoRegister);
1522 ASSERT(!compiler->is_optimizing()); 1513 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1523 value_cid_reg = R3;
1524 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1525 }
1526 1514
1527 if (value_cid == kDynamicCid) { 1515 if (value_cid == kDynamicCid) {
1528 LoadValueCid(compiler, value_cid_reg, value_reg); 1516 LoadValueCid(compiler, value_cid_reg, value_reg);
1529 Label skip_length_check; 1517 Label skip_length_check;
1530 __ ldr(IP, field_cid_operand); 1518 __ ldr(IP, field_cid_operand);
1531 __ cmp(value_cid_reg, ShifterOperand(IP)); 1519 __ cmp(value_cid_reg, ShifterOperand(IP));
1532 __ b(&skip_length_check, NE); 1520 __ b(&skip_length_check, NE);
1533 if (field_has_length) { 1521 if (field_has_length) {
1534 ASSERT(temp_reg != kNoRegister); 1522 ASSERT(temp_reg != kNoRegister);
1535 // Field guard may have remembered list length, check it. 1523 // Field guard may have remembered list length, check it.
1536 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { 1524 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1537 __ ldr(temp_reg, 1525 __ ldr(temp_reg,
1538 FieldAddress(value_reg, Array::length_offset())); 1526 FieldAddress(value_reg, Array::length_offset()));
1539 __ CompareImmediate(temp_reg, field_length); 1527 __ CompareImmediate(temp_reg, Smi::RawValue(field_length));
1540 } else if (RawObject::IsTypedDataClassId(field_cid)) { 1528 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1541 __ ldr(temp_reg, 1529 __ ldr(temp_reg,
1542 FieldAddress(value_reg, TypedData::length_offset())); 1530 FieldAddress(value_reg, TypedData::length_offset()));
1543 __ CompareImmediate(temp_reg, field_length); 1531 __ CompareImmediate(temp_reg, Smi::RawValue(field_length));
1544 } else { 1532 } else {
1545 ASSERT(field_cid == kIllegalCid); 1533 ASSERT(field_cid == kIllegalCid);
1534 ASSERT(field_length == Field::kUnknownFixedLength);
1535 // At compile time we do not know the type of the field nor its
1536 // length. At execution time we may have set the class id and
1537 // list length so we compare the guarded length with the
1538 // list length here, without this check the list length could change
1539 // without triggering a deoptimization.
1540 Label check_array, length_compared, no_fixed_length;
1541 __ CompareImmediate(value_cid_reg, kNullCid);
1542 __ b(&no_fixed_length, EQ);
1543 // Check for typed data array.
1544 __ CompareImmediate(value_cid_reg, kTypedDataFloat32x4ArrayCid);
1545 __ b(&no_fixed_length, GT);
1546 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid);
1547 // Could still be a regular array.
1548 __ b(&check_array, LT);
1549 __ ldr(temp_reg,
1550 FieldAddress(value_reg, TypedData::length_offset()));
1551 __ ldr(IP, field_length_operand);
1552 __ cmp(temp_reg, ShifterOperand(IP));
1553 __ b(&length_compared);
1554 // Check for regular array.
1555 __ Bind(&check_array);
1556 __ CompareImmediate(value_cid_reg, kImmutableArrayCid);
1557 __ b(&no_fixed_length, GT);
1558 __ CompareImmediate(value_cid_reg, kArrayCid);
1559 __ b(&no_fixed_length, LT);
1560 __ ldr(temp_reg,
1561 FieldAddress(value_reg, Array::length_offset()));
1562 __ ldr(IP, field_length_operand);
1563 __ cmp(temp_reg, ShifterOperand(IP));
1564 __ b(&length_compared);
1565 __ Bind(&no_fixed_length);
1566 __ b(fail);
1567 __ Bind(&length_compared);
1546 // Following branch cannot not occur, fall through. 1568 // Following branch cannot not occur, fall through.
1547 } 1569 }
1548 __ b(fail, NE); 1570 __ b(fail, NE);
1549 } 1571 }
1550 __ Bind(&skip_length_check); 1572 __ Bind(&skip_length_check);
1551 __ ldr(IP, field_nullability_operand); 1573 __ ldr(IP, field_nullability_operand);
1552 __ cmp(value_cid_reg, ShifterOperand(IP)); 1574 __ cmp(value_cid_reg, ShifterOperand(IP));
1553 } else if (value_cid == kNullCid) { 1575 } else if (value_cid == kNullCid) {
1554 __ ldr(value_cid_reg, field_nullability_operand); 1576 __ ldr(value_cid_reg, field_nullability_operand);
1555 __ CompareImmediate(value_cid_reg, value_cid); 1577 __ CompareImmediate(value_cid_reg, value_cid);
1556 } else { 1578 } else {
1557 Label skip_length_check; 1579 Label skip_length_check;
1558 __ ldr(value_cid_reg, field_cid_operand); 1580 __ ldr(value_cid_reg, field_cid_operand);
1559 __ CompareImmediate(value_cid_reg, value_cid); 1581 __ CompareImmediate(value_cid_reg, value_cid);
1560 __ b(&skip_length_check, NE); 1582 __ b(&skip_length_check, NE);
1561 if (field_has_length) { 1583 if (field_has_length) {
1562 ASSERT(value_cid_reg != kNoRegister); 1584 ASSERT(value_cid_reg != kNoRegister);
1563 ASSERT(temp_reg != kNoRegister); 1585 ASSERT(temp_reg != kNoRegister);
1564 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { 1586 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
1565 __ ldr(temp_reg, 1587 __ ldr(temp_reg,
1566 FieldAddress(value_reg, Array::length_offset())); 1588 FieldAddress(value_reg, Array::length_offset()));
1567 __ CompareImmediate(temp_reg, field_length); 1589 __ CompareImmediate(temp_reg, Smi::RawValue(field_length));
1568 } else if (RawObject::IsTypedDataClassId(field_cid)) { 1590 } else if (RawObject::IsTypedDataClassId(value_cid)) {
1569 __ ldr(temp_reg, 1591 __ ldr(temp_reg,
1570 FieldAddress(value_reg, TypedData::length_offset())); 1592 FieldAddress(value_reg, TypedData::length_offset()));
1571 __ CompareImmediate(temp_reg, field_length); 1593 __ CompareImmediate(temp_reg, Smi::RawValue(field_length));
1594 } else if (field_cid != kIllegalCid) {
1595 ASSERT(field_cid != value_cid);
1596 ASSERT(field_length >= 0);
1597 // Field has a known class id and length. At compile time it is
1598 // known that the value's class id is not a fixed length list.
1599 __ b(fail);
1572 } else { 1600 } else {
1573 ASSERT(field_cid == kIllegalCid); 1601 ASSERT(field_cid == kIllegalCid);
1602 ASSERT(field_length == Field::kUnknownFixedLength);
1574 // Following jump cannot not occur, fall through. 1603 // Following jump cannot not occur, fall through.
1575 } 1604 }
1605 __ b(fail, NE);
1576 } 1606 }
1577 // Not identical, possibly null. 1607 // Not identical, possibly null.
1578 __ Bind(&skip_length_check); 1608 __ Bind(&skip_length_check);
1579 } 1609 }
1580 __ b(&ok, EQ); 1610 __ b(&ok, EQ);
1581 1611
1582 __ ldr(IP, field_cid_operand); 1612 __ ldr(IP, field_cid_operand);
1583 __ CompareImmediate(IP, kIllegalCid); 1613 __ CompareImmediate(IP, kIllegalCid);
1584 __ b(fail, NE); 1614 __ b(fail, NE);
1585 1615
1586 if (value_cid == kDynamicCid) { 1616 if (value_cid == kDynamicCid) {
1587 __ str(value_cid_reg, field_cid_operand); 1617 __ str(value_cid_reg, field_cid_operand);
1588 __ str(value_cid_reg, field_nullability_operand); 1618 __ str(value_cid_reg, field_nullability_operand);
1589 if (field_has_length) { 1619 if (field_has_length) {
1590 Label check_array, local_exit, local_fail; 1620 Label check_array, length_set, no_fixed_length;
1591 __ CompareImmediate(value_cid_reg, kNullCid); 1621 __ CompareImmediate(value_cid_reg, kNullCid);
1592 __ b(&local_fail, EQ); 1622 __ b(&no_fixed_length, EQ);
1593 // Check for typed data array. 1623 // Check for typed data array.
1594 __ CompareImmediate(value_cid_reg, kTypedDataFloat32x4ArrayCid); 1624 __ CompareImmediate(value_cid_reg, kTypedDataFloat32x4ArrayCid);
1595 __ b(&local_fail, GT); 1625 __ b(&no_fixed_length, GT);
1596 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid); 1626 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid);
1597 __ b(&check_array, LT); // Could still be a regular array. 1627 // Could still be a regular array.
1628 __ b(&check_array, LT);
1598 // Destroy value_cid_reg (safe because we are finished with it). 1629 // Destroy value_cid_reg (safe because we are finished with it).
1599 __ ldr(value_cid_reg, 1630 __ ldr(value_cid_reg,
1600 FieldAddress(value_reg, TypedData::length_offset())); 1631 FieldAddress(value_reg, TypedData::length_offset()));
1601 __ str(value_cid_reg, field_length_operand); 1632 __ str(value_cid_reg, field_length_operand);
1602 __ b(&local_exit); // Updated field length typed data array. 1633 __ b(&length_set); // Updated field length typed data array.
1603 // Check for regular array. 1634 // Check for regular array.
1604 __ Bind(&check_array); 1635 __ Bind(&check_array);
1605 __ CompareImmediate(value_cid_reg, kImmutableArrayCid); 1636 __ CompareImmediate(value_cid_reg, kImmutableArrayCid);
1606 __ b(&local_fail, GT); 1637 __ b(&no_fixed_length, GT);
1607 __ CompareImmediate(value_cid_reg, kArrayCid); 1638 __ CompareImmediate(value_cid_reg, kArrayCid);
1608 __ b(&local_fail, LT); 1639 __ b(&no_fixed_length, LT);
1609 // Destroy value_cid_reg (safe because we are finished with it). 1640 // Destroy value_cid_reg (safe because we are finished with it).
1610 __ ldr(value_cid_reg, 1641 __ ldr(value_cid_reg,
1611 FieldAddress(value_reg, Array::length_offset())); 1642 FieldAddress(value_reg, Array::length_offset()));
1612 __ str(value_cid_reg, field_length_operand); 1643 __ str(value_cid_reg, field_length_operand);
1613 __ b(&local_exit); // Updated field length from regular array. 1644 // Updated field length from regular array.
1614 1645 __ b(&length_set);
1615 __ Bind(&local_fail); 1646 __ Bind(&no_fixed_length);
1616 __ LoadImmediate(IP, Field::kNoFixedLength); 1647 __ LoadImmediate(IP, Smi::RawValue(Field::kNoFixedLength));
1617 __ str(IP, field_length_operand); 1648 __ str(IP, field_length_operand);
1618 1649 __ Bind(&length_set);
1619 __ Bind(&local_exit);
1620 } 1650 }
1621 } else { 1651 } else {
1622 __ LoadImmediate(IP, value_cid); 1652 __ LoadImmediate(IP, value_cid);
1623 __ str(IP, field_cid_operand); 1653 __ str(IP, field_cid_operand);
1624 __ str(IP, field_nullability_operand); 1654 __ str(IP, field_nullability_operand);
1625 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { 1655 if (field_has_length) {
1626 // Destroy value_cid_reg (safe because we are finished with it). 1656 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
1627 __ ldr(value_cid_reg, 1657 // Destroy value_cid_reg (safe because we are finished with it).
1628 FieldAddress(value_reg, Array::length_offset())); 1658 __ ldr(value_cid_reg,
1629 __ str(value_cid_reg, field_length_operand); 1659 FieldAddress(value_reg, Array::length_offset()));
1630 } else if (RawObject::IsTypedDataClassId(value_cid)) { 1660 __ str(value_cid_reg, field_length_operand);
1631 // Destroy value_cid_reg (safe because we are finished with it). 1661 } else if (RawObject::IsTypedDataClassId(value_cid)) {
1632 __ ldr(value_cid_reg, 1662 // Destroy value_cid_reg (safe because we are finished with it).
1633 FieldAddress(value_reg, TypedData::length_offset())); 1663 __ ldr(value_cid_reg,
1634 __ str(value_cid_reg, field_length_operand); 1664 FieldAddress(value_reg, TypedData::length_offset()));
1635 } else { 1665 __ str(value_cid_reg, field_length_operand);
1636 __ LoadImmediate(IP, Field::kNoFixedLength); 1666 } else {
1637 __ str(IP, field_length_operand); 1667 __ LoadImmediate(IP, Smi::RawValue(Field::kNoFixedLength));
1668 __ str(IP, field_length_operand);
1669 }
1638 } 1670 }
1639 } 1671 }
1640
1641 if (!ok_is_fall_through) { 1672 if (!ok_is_fall_through) {
1642 __ b(&ok); 1673 __ b(&ok);
1643 } 1674 }
1644 } else { 1675 } else {
1645 if (field_reg != kNoRegister) { 1676 if (field_reg != kNoRegister) {
1646 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); 1677 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
1647 } 1678 }
1648 if (value_cid == kDynamicCid) { 1679 if (value_cid == kDynamicCid) {
1649 // Field's guarded class id is fixed by value's class id is not known. 1680 // Field's guarded class id is fixed by value's class id is not known.
1650 __ tst(value_reg, ShifterOperand(kSmiTagMask)); 1681 __ tst(value_reg, ShifterOperand(kSmiTagMask));
(...skipping 2985 matching lines...) Expand 10 before | Expand all | Expand 10 after
4636 compiler->GenerateCall(token_pos(), 4667 compiler->GenerateCall(token_pos(),
4637 &label, 4668 &label,
4638 PcDescriptors::kOther, 4669 PcDescriptors::kOther,
4639 locs()); 4670 locs());
4640 __ Drop(2); // Discard type arguments and receiver. 4671 __ Drop(2); // Discard type arguments and receiver.
4641 } 4672 }
4642 4673
4643 } // namespace dart 4674 } // namespace dart
4644 4675
4645 #endif // defined TARGET_ARCH_ARM 4676 #endif // defined TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « runtime/vm/guard_field_test.cc ('k') | runtime/vm/intermediate_language_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698