Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 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 1340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1351 if (value_is_smi == NULL) { | 1351 if (value_is_smi == NULL) { |
| 1352 __ b(&done, EQ); | 1352 __ b(&done, EQ); |
| 1353 } else { | 1353 } else { |
| 1354 __ b(value_is_smi, EQ); | 1354 __ b(value_is_smi, EQ); |
| 1355 } | 1355 } |
| 1356 __ LoadClassId(value_cid_reg, value_reg, PP); | 1356 __ LoadClassId(value_cid_reg, value_reg, PP); |
| 1357 __ Bind(&done); | 1357 __ Bind(&done); |
| 1358 } | 1358 } |
| 1359 | 1359 |
| 1360 | 1360 |
| 1361 LocationSummary* GuardFieldInstr::MakeLocationSummary(Isolate* isolate, | 1361 LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Isolate* isolate, |
| 1362 bool opt) const { | 1362 bool opt) const { |
| 1363 const intptr_t kNumInputs = 1; | 1363 const intptr_t kNumInputs = 1; |
| 1364 LocationSummary* summary = new(isolate) LocationSummary( | 1364 LocationSummary* summary = new(isolate) LocationSummary( |
| 1365 isolate, kNumInputs, 0, LocationSummary::kNoCall); | 1365 isolate, kNumInputs, 0, LocationSummary::kNoCall); |
| 1366 summary->set_in(0, Location::RequiresRegister()); | 1366 summary->set_in(0, Location::RequiresRegister()); |
| 1367 const bool field_has_length = field().needs_length_check(); | 1367 |
| 1368 summary->AddTemp(Location::RequiresRegister()); | 1368 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1369 summary->AddTemp(Location::RequiresRegister()); | 1369 const intptr_t field_cid = field().guarded_cid(); |
| 1370 const bool need_field_temp_reg = | 1370 |
| 1371 field_has_length || (field().guarded_cid() == kIllegalCid); | 1371 const bool emit_full_guard = |
| 1372 if (need_field_temp_reg) { | 1372 !opt || (field_cid == kIllegalCid); |
| 1373 | |
| 1374 const bool needs_value_cid_temp_reg = emit_full_guard || | |
| 1375 ((value_cid == kDynamicCid) && (field_cid != kSmiCid)); | |
| 1376 | |
| 1377 const bool needs_field_temp_reg = emit_full_guard; | |
| 1378 | |
| 1379 if (needs_value_cid_temp_reg) { | |
| 1373 summary->AddTemp(Location::RequiresRegister()); | 1380 summary->AddTemp(Location::RequiresRegister()); |
| 1374 } | 1381 } |
| 1382 | |
| 1383 if (needs_field_temp_reg) { | |
| 1384 summary->AddTemp(Location::RequiresRegister()); | |
| 1385 } | |
| 1386 | |
| 1375 return summary; | 1387 return summary; |
| 1376 } | 1388 } |
| 1377 | 1389 |
| 1378 | 1390 |
| 1379 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1391 void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1392 const intptr_t value_cid = value()->Type()->ToCid(); | |
| 1380 const intptr_t field_cid = field().guarded_cid(); | 1393 const intptr_t field_cid = field().guarded_cid(); |
| 1381 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; | 1394 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; |
| 1382 const intptr_t field_length = field().guarded_list_length(); | |
| 1383 const bool field_has_length = field().needs_length_check(); | |
| 1384 const bool needs_field_temp_reg = | |
| 1385 field_has_length || (field().guarded_cid() == kIllegalCid); | |
| 1386 if (field_has_length) { | |
| 1387 // Currently, we should only see final fields that remember length. | |
| 1388 ASSERT(field().is_final()); | |
| 1389 } | |
| 1390 | 1395 |
| 1391 if (field_cid == kDynamicCid) { | 1396 if (field_cid == kDynamicCid) { |
| 1392 ASSERT(!compiler->is_optimizing()); | 1397 ASSERT(!compiler->is_optimizing()); |
| 1393 return; // Nothing to emit. | 1398 return; // Nothing to emit. |
| 1394 } | 1399 } |
| 1395 | 1400 |
| 1396 const intptr_t value_cid = value()->Type()->ToCid(); | 1401 const bool emit_full_guard = |
| 1402 !compiler->is_optimizing() || (field_cid == kIllegalCid); | |
| 1403 | |
| 1404 const bool needs_value_cid_temp_reg = emit_full_guard || | |
| 1405 ((value_cid == kDynamicCid) && (field_cid != kSmiCid)); | |
| 1406 | |
| 1407 const bool needs_field_temp_reg = emit_full_guard; | |
| 1397 | 1408 |
| 1398 const Register value_reg = locs()->in(0).reg(); | 1409 const Register value_reg = locs()->in(0).reg(); |
| 1399 | 1410 |
| 1400 const Register value_cid_reg = locs()->temp(0).reg(); | 1411 const Register value_cid_reg = needs_value_cid_temp_reg ? |
| 1412 locs()->temp(0).reg() : kNoRegister; | |
| 1401 | 1413 |
| 1402 const Register temp_reg = locs()->temp(1).reg(); | 1414 const Register field_reg = needs_field_temp_reg ? |
| 1403 | |
| 1404 Register field_reg = needs_field_temp_reg ? | |
| 1405 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; | 1415 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; |
| 1406 | 1416 |
| 1407 Label ok, fail_label; | 1417 Label ok, fail_label; |
| 1408 | 1418 |
| 1409 Label* deopt = compiler->is_optimizing() ? | 1419 Label* deopt = compiler->is_optimizing() ? |
| 1410 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; | 1420 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; |
| 1411 | 1421 |
| 1412 Label* fail = (deopt != NULL) ? deopt : &fail_label; | 1422 Label* fail = (deopt != NULL) ? deopt : &fail_label; |
| 1413 | 1423 |
| 1414 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) { | 1424 if (emit_full_guard) { |
| 1415 if (!compiler->is_optimizing() && (field_reg == kNoRegister)) { | |
| 1416 // Currently we can't have different location summaries for optimized | |
| 1417 // and non-optimized code. So instead we manually pick up a register | |
| 1418 // that is known to be free because we know how non-optimizing compiler | |
| 1419 // allocates registers. | |
| 1420 field_reg = R2; | |
| 1421 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg)); | |
| 1422 } | |
| 1423 | |
| 1424 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); | 1425 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); |
| 1425 | 1426 |
| 1426 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); | 1427 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); |
| 1427 FieldAddress field_nullability_operand( | 1428 FieldAddress field_nullability_operand( |
| 1428 field_reg, Field::is_nullable_offset()); | 1429 field_reg, Field::is_nullable_offset()); |
| 1429 FieldAddress field_length_operand( | |
| 1430 field_reg, Field::guarded_list_length_offset()); | |
| 1431 | |
| 1432 ASSERT(value_cid_reg != kNoRegister); | |
| 1433 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg)); | |
| 1434 | 1430 |
| 1435 if (value_cid == kDynamicCid) { | 1431 if (value_cid == kDynamicCid) { |
| 1436 LoadValueCid(compiler, value_cid_reg, value_reg); | 1432 LoadValueCid(compiler, value_cid_reg, value_reg); |
| 1437 Label skip_length_check; | 1433 Label skip_length_check; |
| 1438 __ ldr(TMP, field_cid_operand); | 1434 __ ldr(TMP, field_cid_operand); |
| 1439 __ CompareRegisters(value_cid_reg, TMP); | 1435 __ CompareRegisters(value_cid_reg, TMP); |
| 1440 __ b(&skip_length_check, NE); | 1436 __ b(&ok, EQ); |
| 1441 if (field_has_length) { | |
| 1442 ASSERT(temp_reg != kNoRegister); | |
| 1443 // Field guard may have remembered list length, check it. | |
| 1444 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1445 __ LoadFieldFromOffset( | |
| 1446 temp_reg, value_reg, Array::length_offset(), PP); | |
| 1447 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); | |
| 1448 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1449 __ LoadFieldFromOffset( | |
| 1450 temp_reg, value_reg, TypedData::length_offset(), PP); | |
| 1451 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); | |
| 1452 } else { | |
| 1453 ASSERT(field_cid == kIllegalCid); | |
| 1454 ASSERT(field_length == Field::kUnknownFixedLength); | |
| 1455 // At compile time we do not know the type of the field nor its | |
| 1456 // length. At execution time we may have set the class id and | |
| 1457 // list length so we compare the guarded length with the | |
| 1458 // list length here, without this check the list length could change | |
| 1459 // without triggering a deoptimization. | |
| 1460 Label check_array, length_compared, no_fixed_length; | |
| 1461 // If length is negative the length guard is either disabled or | |
| 1462 // has not been initialized, either way it is safe to skip the | |
| 1463 // length check. | |
| 1464 __ ldr(TMP, field_length_operand); | |
| 1465 __ CompareImmediate(TMP, 0, PP); | |
| 1466 __ b(&skip_length_check, LT); | |
| 1467 __ CompareImmediate(value_cid_reg, kNullCid, PP); | |
| 1468 __ b(&no_fixed_length, EQ); | |
| 1469 // Check for typed data array. | |
| 1470 __ CompareImmediate(value_cid_reg, kTypedDataInt32x4ArrayCid, PP); | |
| 1471 __ b(&no_fixed_length, GT); | |
| 1472 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid, PP); | |
| 1473 // Could still be a regular array. | |
| 1474 __ b(&check_array, LT); | |
| 1475 __ LoadFieldFromOffset( | |
| 1476 temp_reg, value_reg, TypedData::length_offset(), PP); | |
| 1477 __ ldr(TMP, field_length_operand); | |
| 1478 __ CompareRegisters(temp_reg, TMP); | |
| 1479 __ b(&length_compared); | |
| 1480 // Check for regular array. | |
| 1481 __ Bind(&check_array); | |
| 1482 __ CompareImmediate(value_cid_reg, kImmutableArrayCid, PP); | |
| 1483 __ b(&no_fixed_length, GT); | |
| 1484 __ CompareImmediate(value_cid_reg, kArrayCid, PP); | |
| 1485 __ b(&no_fixed_length, LT); | |
| 1486 __ LoadFieldFromOffset( | |
| 1487 temp_reg, value_reg, Array::length_offset(), PP); | |
| 1488 __ ldr(TMP, field_length_operand); | |
| 1489 __ CompareRegisters(temp_reg, TMP); | |
| 1490 __ b(&length_compared); | |
| 1491 __ Bind(&no_fixed_length); | |
| 1492 __ b(fail); | |
| 1493 __ Bind(&length_compared); | |
| 1494 // Following branch cannot not occur, fall through. | |
| 1495 } | |
| 1496 __ b(fail, NE); | |
| 1497 } | |
| 1498 __ Bind(&skip_length_check); | |
| 1499 __ ldr(TMP, field_nullability_operand); | 1437 __ ldr(TMP, field_nullability_operand); |
| 1500 __ CompareRegisters(value_cid_reg, TMP); | 1438 __ CompareRegisters(value_cid_reg, TMP); |
| 1501 } else if (value_cid == kNullCid) { | 1439 } else if (value_cid == kNullCid) { |
| 1502 __ ldr(value_cid_reg, field_nullability_operand); | 1440 __ ldr(value_cid_reg, field_nullability_operand); |
| 1503 __ CompareImmediate(value_cid_reg, value_cid, PP); | 1441 __ CompareImmediate(value_cid_reg, value_cid, PP); |
| 1504 } else { | 1442 } else { |
| 1505 Label skip_length_check; | 1443 Label skip_length_check; |
| 1506 __ ldr(value_cid_reg, field_cid_operand); | 1444 __ ldr(value_cid_reg, field_cid_operand); |
| 1507 __ CompareImmediate(value_cid_reg, value_cid, PP); | 1445 __ CompareImmediate(value_cid_reg, value_cid, PP); |
| 1508 __ b(&skip_length_check, NE); | |
| 1509 if (field_has_length) { | |
| 1510 ASSERT(value_cid_reg != kNoRegister); | |
| 1511 ASSERT(temp_reg != kNoRegister); | |
| 1512 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | |
| 1513 __ LoadFieldFromOffset( | |
| 1514 temp_reg, value_reg, Array::length_offset(), PP); | |
| 1515 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); | |
| 1516 } else if (RawObject::IsTypedDataClassId(value_cid)) { | |
| 1517 __ LoadFieldFromOffset( | |
| 1518 temp_reg, value_reg, TypedData::length_offset(), PP); | |
| 1519 __ CompareImmediate(temp_reg, Smi::RawValue(field_length), PP); | |
| 1520 } else if (field_cid != kIllegalCid) { | |
| 1521 ASSERT(field_cid != value_cid); | |
| 1522 ASSERT(field_length >= 0); | |
| 1523 // Field has a known class id and length. At compile time it is | |
| 1524 // known that the value's class id is not a fixed length list. | |
| 1525 __ b(fail); | |
| 1526 } else { | |
| 1527 ASSERT(field_cid == kIllegalCid); | |
| 1528 ASSERT(field_length == Field::kUnknownFixedLength); | |
| 1529 // Following jump cannot not occur, fall through. | |
| 1530 } | |
| 1531 __ b(fail, NE); | |
| 1532 } | |
| 1533 // Not identical, possibly null. | |
| 1534 __ Bind(&skip_length_check); | |
| 1535 } | 1446 } |
| 1536 __ b(&ok, EQ); | 1447 __ b(&ok, EQ); |
| 1537 | 1448 |
| 1538 __ ldr(TMP, field_cid_operand); | 1449 // Check if the tracked state of the guarded field can be initialized |
| 1539 __ CompareImmediate(TMP, kIllegalCid, PP); | 1450 // inline. If the field needs length check we fall through to runtime |
| 1540 __ b(fail, NE); | 1451 // which is responsible for computing offset of the length field |
| 1452 // based on the class id. | |
| 1453 // Length guard will be emitted separately when needed via GuardFieldLength | |
| 1454 // instruction after GuardFieldClass. | |
| 1455 if (!field().needs_length_check()) { | |
| 1456 // Uninitialized field can be handled inline. Check if the | |
| 1457 // field is still unitialized. | |
| 1458 __ ldr(TMP, field_cid_operand); | |
|
Florian Schneider
2014/06/02 11:37:01
General suggestion for ARM/ARM64/MIPS code (You do
Vyacheslav Egorov (Google)
2014/06/02 12:09:47
I second this. The stuff we are writing now is ver
| |
| 1459 __ CompareImmediate(TMP, kIllegalCid, PP); | |
| 1460 __ b(fail, NE); | |
| 1541 | 1461 |
| 1542 if (value_cid == kDynamicCid) { | 1462 if (value_cid == kDynamicCid) { |
| 1543 __ str(value_cid_reg, field_cid_operand); | 1463 __ str(value_cid_reg, field_cid_operand); |
| 1544 __ str(value_cid_reg, field_nullability_operand); | 1464 __ str(value_cid_reg, field_nullability_operand); |
| 1545 if (field_has_length) { | 1465 } else { |
| 1546 Label check_array, length_set, no_fixed_length; | 1466 __ LoadImmediate(TMP, value_cid, PP); |
| 1547 __ CompareImmediate(value_cid_reg, kNullCid, PP); | 1467 __ str(TMP, field_cid_operand); |
| 1548 __ b(&no_fixed_length, EQ); | 1468 __ str(TMP, field_nullability_operand); |
| 1549 // Check for typed data array. | |
| 1550 __ CompareImmediate(value_cid_reg, kTypedDataInt32x4ArrayCid, PP); | |
| 1551 __ b(&no_fixed_length, GT); | |
| 1552 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid, PP); | |
| 1553 // Could still be a regular array. | |
| 1554 __ b(&check_array, LT); | |
| 1555 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1556 __ LoadFieldFromOffset( | |
| 1557 value_cid_reg, value_reg, TypedData::length_offset(), PP); | |
| 1558 __ str(value_cid_reg, field_length_operand); | |
| 1559 __ b(&length_set); // Updated field length typed data array. | |
| 1560 // Check for regular array. | |
| 1561 __ Bind(&check_array); | |
| 1562 __ CompareImmediate(value_cid_reg, kImmutableArrayCid, PP); | |
| 1563 __ b(&no_fixed_length, GT); | |
| 1564 __ CompareImmediate(value_cid_reg, kArrayCid, PP); | |
| 1565 __ b(&no_fixed_length, LT); | |
| 1566 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1567 __ LoadFieldFromOffset( | |
| 1568 value_cid_reg, value_reg, Array::length_offset(), PP); | |
| 1569 __ str(value_cid_reg, field_length_operand); | |
| 1570 // Updated field length from regular array. | |
| 1571 __ b(&length_set); | |
| 1572 __ Bind(&no_fixed_length); | |
| 1573 __ LoadImmediate(TMP, Smi::RawValue(Field::kNoFixedLength), PP); | |
| 1574 __ str(TMP, field_length_operand); | |
| 1575 __ Bind(&length_set); | |
| 1576 } | 1469 } |
| 1577 } else { | 1470 |
| 1578 __ LoadImmediate(TMP, value_cid, PP); | 1471 if (deopt == NULL) { |
| 1579 __ str(TMP, field_cid_operand); | 1472 ASSERT(!compiler->is_optimizing()); |
| 1580 __ str(TMP, field_nullability_operand); | 1473 __ b(&ok); |
| 1581 if (field_has_length) { | |
| 1582 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | |
| 1583 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1584 __ LoadFieldFromOffset( | |
| 1585 value_cid_reg, value_reg, Array::length_offset(), PP); | |
| 1586 __ str(value_cid_reg, field_length_operand); | |
| 1587 } else if (RawObject::IsTypedDataClassId(value_cid)) { | |
| 1588 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1589 __ LoadFieldFromOffset( | |
| 1590 value_cid_reg, value_reg, TypedData::length_offset(), PP); | |
| 1591 __ str(value_cid_reg, field_length_operand); | |
| 1592 } else { | |
| 1593 __ LoadImmediate(TMP, Smi::RawValue(Field::kNoFixedLength), PP); | |
| 1594 __ str(TMP, field_length_operand); | |
| 1595 } | |
| 1596 } | 1474 } |
| 1597 } | 1475 } |
| 1598 | 1476 |
| 1599 if (deopt == NULL) { | 1477 if (deopt == NULL) { |
| 1600 ASSERT(!compiler->is_optimizing()); | 1478 ASSERT(!compiler->is_optimizing()); |
| 1601 __ b(&ok); | |
| 1602 __ Bind(fail); | 1479 __ Bind(fail); |
| 1603 | 1480 |
| 1604 __ LoadFieldFromOffset(TMP, field_reg, Field::guarded_cid_offset(), PP); | 1481 __ LoadFieldFromOffset(TMP, field_reg, Field::guarded_cid_offset(), PP); |
| 1605 __ CompareImmediate(TMP, kDynamicCid, PP); | 1482 __ CompareImmediate(TMP, kDynamicCid, PP); |
| 1606 __ b(&ok, EQ); | 1483 __ b(&ok, EQ); |
| 1607 | 1484 |
| 1608 __ Push(field_reg); | 1485 __ Push(field_reg); |
| 1609 __ Push(value_reg); | 1486 __ Push(value_reg); |
| 1610 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); | 1487 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); |
| 1611 __ Drop(2); // Drop the field and the value. | 1488 __ Drop(2); // Drop the field and the value. |
| 1612 } | 1489 } |
| 1613 } else { | 1490 } else { |
| 1614 ASSERT(compiler->is_optimizing()); | 1491 ASSERT(compiler->is_optimizing()); |
| 1615 ASSERT(deopt != NULL); | 1492 ASSERT(deopt != NULL); |
| 1493 | |
| 1616 // Field guard class has been initialized and is known. | 1494 // Field guard class has been initialized and is known. |
| 1617 if (field_reg != kNoRegister) { | |
| 1618 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); | |
| 1619 } | |
| 1620 if (value_cid == kDynamicCid) { | 1495 if (value_cid == kDynamicCid) { |
| 1621 // Field's guarded class id is fixed by value's class id is not known. | 1496 // Value's class id is not known. |
| 1622 __ tsti(value_reg, kSmiTagMask); | 1497 __ tsti(value_reg, kSmiTagMask); |
| 1623 | 1498 |
| 1624 if (field_cid != kSmiCid) { | 1499 if (field_cid != kSmiCid) { |
| 1625 __ b(fail, EQ); | 1500 __ b(fail, EQ); |
| 1626 __ LoadClassId(value_cid_reg, value_reg, PP); | 1501 __ LoadClassId(value_cid_reg, value_reg, PP); |
| 1627 __ CompareImmediate(value_cid_reg, field_cid, PP); | 1502 __ CompareImmediate(value_cid_reg, field_cid, PP); |
| 1628 } | 1503 } |
| 1629 | 1504 |
| 1630 if (field_has_length) { | |
| 1631 __ b(fail, NE); | |
| 1632 // Classes are same, perform guarded list length check. | |
| 1633 ASSERT(field_reg != kNoRegister); | |
| 1634 ASSERT(value_cid_reg != kNoRegister); | |
| 1635 FieldAddress field_length_operand( | |
| 1636 field_reg, Field::guarded_list_length_offset()); | |
| 1637 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1638 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1639 __ LoadFieldFromOffset( | |
| 1640 value_cid_reg, value_reg, Array::length_offset(), PP); | |
| 1641 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1642 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1643 __ LoadFieldFromOffset( | |
| 1644 value_cid_reg, value_reg, TypedData::length_offset(), PP); | |
| 1645 } | |
| 1646 __ ldr(TMP, field_length_operand); | |
| 1647 __ CompareRegisters(value_cid_reg, TMP); | |
| 1648 } | |
| 1649 | |
| 1650 if (field().is_nullable() && (field_cid != kNullCid)) { | 1505 if (field().is_nullable() && (field_cid != kNullCid)) { |
| 1651 __ b(&ok, EQ); | 1506 __ b(&ok, EQ); |
| 1652 __ CompareObject(value_reg, Object::null_object(), PP); | 1507 __ CompareObject(value_reg, Object::null_object(), PP); |
| 1653 } | 1508 } |
| 1509 | |
| 1654 __ b(fail, NE); | 1510 __ b(fail, NE); |
| 1655 } else { | 1511 } else { |
| 1656 // Both value's and field's class id is known. | 1512 // Both value's and field's class id is known. |
| 1657 if ((value_cid != field_cid) && (value_cid != nullability)) { | 1513 ASSERT((value_cid != field_cid) && (value_cid != nullability)); |
| 1658 __ b(fail); | 1514 __ b(fail); |
| 1659 } else if (field_has_length && (value_cid == field_cid)) { | |
| 1660 ASSERT(value_cid_reg != kNoRegister); | |
| 1661 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1662 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1663 __ LoadFieldFromOffset( | |
| 1664 value_cid_reg, value_reg, Array::length_offset(), PP); | |
| 1665 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1666 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1667 __ LoadFieldFromOffset( | |
| 1668 value_cid_reg, value_reg, TypedData::length_offset(), PP); | |
| 1669 } | |
| 1670 __ CompareImmediate(value_cid_reg, field_length, PP); | |
| 1671 __ b(fail, NE); | |
| 1672 } else { | |
| 1673 UNREACHABLE(); | |
| 1674 } | |
| 1675 } | 1515 } |
| 1676 } | 1516 } |
| 1677 __ Bind(&ok); | 1517 __ Bind(&ok); |
| 1678 } | 1518 } |
| 1679 | 1519 |
| 1680 | 1520 |
| 1521 LocationSummary* GuardFieldLengthInstr::MakeLocationSummary(Isolate* isolate, | |
| 1522 bool opt) const { | |
| 1523 const intptr_t kNumInputs = 1; | |
| 1524 LocationSummary* summary = new(isolate) LocationSummary( | |
| 1525 isolate, kNumInputs, 0, LocationSummary::kNoCall); | |
| 1526 summary->set_in(0, Location::RequiresRegister()); | |
| 1527 | |
| 1528 if (!opt || (field().guarded_list_length() == Field::kUnknownFixedLength)) { | |
| 1529 // We need temporaries for field object, length offset and expected length. | |
| 1530 summary->AddTemp(Location::RequiresRegister()); | |
| 1531 summary->AddTemp(Location::RequiresRegister()); | |
| 1532 summary->AddTemp(Location::RequiresRegister()); | |
| 1533 } | |
| 1534 | |
| 1535 return summary; | |
| 1536 } | |
| 1537 | |
| 1538 | |
| 1539 void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 1540 if (field().guarded_list_length() == Field::kNoFixedLength) { | |
| 1541 ASSERT(!compiler->is_optimizing()); | |
| 1542 return; // Nothing to emit. | |
| 1543 } | |
| 1544 | |
| 1545 Label* deopt = compiler->is_optimizing() ? | |
| 1546 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; | |
| 1547 | |
| 1548 const Register value_reg = locs()->in(0).reg(); | |
| 1549 | |
| 1550 if (!compiler->is_optimizing() || | |
| 1551 (field().guarded_list_length() == Field::kUnknownFixedLength)) { | |
| 1552 const Register field_reg = locs()->temp(0).reg(); | |
| 1553 const Register offset_reg = locs()->temp(1).reg(); | |
| 1554 const Register length_reg = locs()->temp(2).reg(); | |
| 1555 | |
| 1556 Label ok; | |
| 1557 | |
| 1558 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); | |
| 1559 | |
| 1560 __ ldrsb(offset_reg, FieldAddress(field_reg, | |
| 1561 Field::guarded_list_length_in_object_offset_offset())); | |
| 1562 __ ldr(length_reg, FieldAddress(field_reg, | |
| 1563 Field::guarded_list_length_offset())); | |
| 1564 | |
| 1565 __ tst(offset_reg, Operand(offset_reg)); | |
| 1566 __ b(&ok, MI); | |
| 1567 | |
| 1568 // Load the length from the value. GuardFieldClass already verified that | |
| 1569 // value's class matches guarded class id of the field. | |
| 1570 // offset_reg contains offset already corrected by -kHeapObjectTag that is | |
| 1571 // why we use Address instead of FieldAddress. | |
| 1572 __ ldr(TMP, Address(value_reg, offset_reg)); | |
| 1573 __ CompareRegisters(length_reg, TMP); | |
| 1574 | |
| 1575 if (deopt == NULL) { | |
| 1576 __ b(&ok, EQ); | |
| 1577 | |
| 1578 __ Push(field_reg); | |
| 1579 __ Push(value_reg); | |
| 1580 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); | |
| 1581 __ Drop(2); // Drop the field and the value. | |
| 1582 } else { | |
| 1583 __ b(deopt, NE); | |
| 1584 } | |
| 1585 | |
| 1586 __ Bind(&ok); | |
| 1587 } else { | |
| 1588 ASSERT(compiler->is_optimizing()); | |
| 1589 ASSERT(field().guarded_list_length() >= 0); | |
| 1590 ASSERT(field().guarded_list_length_in_object_offset() != | |
| 1591 Field::kUnknownLengthOffset); | |
| 1592 | |
| 1593 __ ldr(TMP, FieldAddress(value_reg, | |
| 1594 field().guarded_list_length_in_object_offset())); | |
| 1595 __ CompareImmediate(TMP, Smi::RawValue(field().guarded_list_length()), PP); | |
| 1596 __ b(deopt, NE); | |
| 1597 } | |
| 1598 } | |
| 1599 | |
| 1600 | |
| 1681 class StoreInstanceFieldSlowPath : public SlowPathCode { | 1601 class StoreInstanceFieldSlowPath : public SlowPathCode { |
| 1682 public: | 1602 public: |
| 1683 StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction, | 1603 StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction, |
| 1684 const Class& cls) | 1604 const Class& cls) |
| 1685 : instruction_(instruction), cls_(cls) { } | 1605 : instruction_(instruction), cls_(cls) { } |
| 1686 | 1606 |
| 1687 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { | 1607 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1688 __ Comment("StoreInstanceFieldSlowPath"); | 1608 __ Comment("StoreInstanceFieldSlowPath"); |
| 1689 __ Bind(entry_label()); | 1609 __ Bind(entry_label()); |
| 1690 | 1610 |
| (...skipping 3710 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5401 compiler->GenerateCall(token_pos(), | 5321 compiler->GenerateCall(token_pos(), |
| 5402 &label, | 5322 &label, |
| 5403 PcDescriptors::kOther, | 5323 PcDescriptors::kOther, |
| 5404 locs()); | 5324 locs()); |
| 5405 __ Drop(ArgumentCount()); // Discard arguments. | 5325 __ Drop(ArgumentCount()); // Discard arguments. |
| 5406 } | 5326 } |
| 5407 | 5327 |
| 5408 } // namespace dart | 5328 } // namespace dart |
| 5409 | 5329 |
| 5410 #endif // defined TARGET_ARCH_ARM64 | 5330 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |