| 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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 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 1285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1296 case kTypedDataFloat64x2ArrayCid: | 1296 case kTypedDataFloat64x2ArrayCid: |
| 1297 case kTypedDataFloat32x4ArrayCid: | 1297 case kTypedDataFloat32x4ArrayCid: |
| 1298 __ movups(element_address, locs()->in(2).fpu_reg()); | 1298 __ movups(element_address, locs()->in(2).fpu_reg()); |
| 1299 break; | 1299 break; |
| 1300 default: | 1300 default: |
| 1301 UNREACHABLE(); | 1301 UNREACHABLE(); |
| 1302 } | 1302 } |
| 1303 } | 1303 } |
| 1304 | 1304 |
| 1305 | 1305 |
| 1306 LocationSummary* GuardFieldInstr::MakeLocationSummary(Isolate* isolate, | 1306 LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Isolate* isolate, |
| 1307 bool opt) const { | 1307 bool opt) const { |
| 1308 const intptr_t kNumInputs = 1; | 1308 const intptr_t kNumInputs = 1; |
| 1309 LocationSummary* summary = new(isolate) LocationSummary( | 1309 LocationSummary* summary = new(isolate) LocationSummary( |
| 1310 isolate, kNumInputs, 0, LocationSummary::kNoCall); | 1310 isolate, kNumInputs, 0, LocationSummary::kNoCall); |
| 1311 summary->set_in(0, Location::RequiresRegister()); | 1311 summary->set_in(0, Location::RequiresRegister()); |
| 1312 const bool field_has_length = field().needs_length_check(); | 1312 |
| 1313 const bool need_value_temp_reg = | 1313 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1314 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) && | 1314 const intptr_t field_cid = field().guarded_cid(); |
| 1315 (field().guarded_cid() != kSmiCid))); | 1315 |
| 1316 if (need_value_temp_reg) { | 1316 const bool emit_full_guard = !opt || (field_cid == kIllegalCid); |
| 1317 const bool needs_value_cid_temp_reg = |
| 1318 (value_cid == kDynamicCid) && (emit_full_guard || (field_cid != kSmiCid)); |
| 1319 const bool needs_field_temp_reg = emit_full_guard; |
| 1320 |
| 1321 if (needs_value_cid_temp_reg) { |
| 1317 summary->AddTemp(Location::RequiresRegister()); | 1322 summary->AddTemp(Location::RequiresRegister()); |
| 1318 } | 1323 } |
| 1319 const bool need_field_temp_reg = | 1324 |
| 1320 field_has_length || (field().guarded_cid() == kIllegalCid); | 1325 if (needs_field_temp_reg) { |
| 1321 if (need_field_temp_reg) { | |
| 1322 summary->AddTemp(Location::RequiresRegister()); | 1326 summary->AddTemp(Location::RequiresRegister()); |
| 1323 } | 1327 } |
| 1328 |
| 1324 return summary; | 1329 return summary; |
| 1325 } | 1330 } |
| 1326 | 1331 |
| 1327 | 1332 |
| 1328 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1333 void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1334 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1329 const intptr_t field_cid = field().guarded_cid(); | 1335 const intptr_t field_cid = field().guarded_cid(); |
| 1330 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; | 1336 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; |
| 1331 const intptr_t field_length = field().guarded_list_length(); | |
| 1332 const bool field_has_length = field().needs_length_check(); | |
| 1333 const bool needs_value_temp_reg = | |
| 1334 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) && | |
| 1335 (field().guarded_cid() != kSmiCid))); | |
| 1336 const bool needs_field_temp_reg = | |
| 1337 field_has_length || (field().guarded_cid() == kIllegalCid); | |
| 1338 if (field_has_length) { | |
| 1339 // Currently, we should only see final fields that remember length. | |
| 1340 ASSERT(field().is_final()); | |
| 1341 } | |
| 1342 | 1337 |
| 1343 if (field_cid == kDynamicCid) { | 1338 if (field_cid == kDynamicCid) { |
| 1344 ASSERT(!compiler->is_optimizing()); | 1339 ASSERT(!compiler->is_optimizing()); |
| 1345 return; // Nothing to emit. | 1340 return; // Nothing to emit. |
| 1346 } | 1341 } |
| 1347 | 1342 |
| 1348 const intptr_t value_cid = value()->Type()->ToCid(); | 1343 const bool emit_full_guard = |
| 1344 !compiler->is_optimizing() || (field_cid == kIllegalCid); |
| 1345 |
| 1346 const bool needs_value_cid_temp_reg = |
| 1347 (value_cid == kDynamicCid) && (emit_full_guard || (field_cid != kSmiCid)); |
| 1348 |
| 1349 const bool needs_field_temp_reg = emit_full_guard; |
| 1349 | 1350 |
| 1350 Register value_reg = locs()->in(0).reg(); | 1351 Register value_reg = locs()->in(0).reg(); |
| 1351 | 1352 |
| 1352 Register value_cid_reg = needs_value_temp_reg ? | 1353 Register value_cid_reg = needs_value_cid_temp_reg ? |
| 1353 locs()->temp(0).reg() : kNoRegister; | 1354 locs()->temp(0).reg() : kNoRegister; |
| 1354 | 1355 |
| 1355 Register field_reg = needs_field_temp_reg ? | 1356 Register field_reg = needs_field_temp_reg ? |
| 1356 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; | 1357 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; |
| 1357 | 1358 |
| 1358 Label ok, fail_label; | 1359 Label ok, fail_label; |
| 1359 | 1360 |
| 1360 Label* deopt = compiler->is_optimizing() ? | 1361 Label* deopt = compiler->is_optimizing() ? |
| 1361 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; | 1362 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; |
| 1362 | 1363 |
| 1363 Label* fail = (deopt != NULL) ? deopt : &fail_label; | 1364 Label* fail = (deopt != NULL) ? deopt : &fail_label; |
| 1364 | 1365 |
| 1365 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) { | 1366 if (emit_full_guard) { |
| 1366 if (!compiler->is_optimizing() && (field_reg == kNoRegister)) { | |
| 1367 // Currently we can't have different location summaries for optimized | |
| 1368 // and non-optimized code. So instead we manually pick up a register | |
| 1369 // that is known to be free because we know how non-optimizing compiler | |
| 1370 // allocates registers. | |
| 1371 field_reg = RBX; | |
| 1372 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg)); | |
| 1373 } | |
| 1374 | |
| 1375 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); | 1367 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); |
| 1376 | 1368 |
| 1377 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); | 1369 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); |
| 1378 FieldAddress field_nullability_operand( | 1370 FieldAddress field_nullability_operand( |
| 1379 field_reg, Field::is_nullable_offset()); | 1371 field_reg, Field::is_nullable_offset()); |
| 1380 FieldAddress field_length_operand( | |
| 1381 field_reg, Field::guarded_list_length_offset()); | |
| 1382 | 1372 |
| 1383 if (value_cid == kDynamicCid) { | 1373 if (value_cid == kDynamicCid) { |
| 1384 if (value_cid_reg == kNoRegister) { | |
| 1385 ASSERT(!compiler->is_optimizing()); | |
| 1386 value_cid_reg = RDX; | |
| 1387 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg)); | |
| 1388 } | |
| 1389 | |
| 1390 LoadValueCid(compiler, value_cid_reg, value_reg); | 1374 LoadValueCid(compiler, value_cid_reg, value_reg); |
| 1391 | 1375 |
| 1392 Label skip_length_check; | |
| 1393 __ cmpq(value_cid_reg, field_cid_operand); | 1376 __ cmpq(value_cid_reg, field_cid_operand); |
| 1394 __ j(NOT_EQUAL, &skip_length_check); | 1377 __ j(EQUAL, &ok); |
| 1395 if (field_has_length) { | |
| 1396 // Field guard may have remembered list length, check it. | |
| 1397 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1398 __ pushq(value_cid_reg); | |
| 1399 __ movq(value_cid_reg, | |
| 1400 FieldAddress(value_reg, Array::length_offset())); | |
| 1401 __ CompareImmediate( | |
| 1402 value_cid_reg, Immediate(Smi::RawValue(field_length)), PP); | |
| 1403 __ popq(value_cid_reg); | |
| 1404 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1405 __ pushq(value_cid_reg); | |
| 1406 __ movq(value_cid_reg, | |
| 1407 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1408 __ CompareImmediate( | |
| 1409 value_cid_reg, Immediate(Smi::RawValue(field_length)), PP); | |
| 1410 __ popq(value_cid_reg); | |
| 1411 } else { | |
| 1412 ASSERT(field_cid == kIllegalCid); | |
| 1413 ASSERT(field_length == Field::kUnknownFixedLength); | |
| 1414 // At compile time we do not know the type of the field nor its | |
| 1415 // length. At execution time we may have set the class id and | |
| 1416 // list length so we compare the guarded length with the | |
| 1417 // list length here, without this check the list length could change | |
| 1418 // without triggering a deoptimization. | |
| 1419 Label check_array, length_compared, no_fixed_length; | |
| 1420 // If length is negative the length guard is either disabled or | |
| 1421 // has not been initialized, either way it is safe to skip the | |
| 1422 // length check. | |
| 1423 __ CompareImmediate( | |
| 1424 field_length_operand, Immediate(Smi::RawValue(0)), PP); | |
| 1425 __ j(LESS, &skip_length_check); | |
| 1426 __ CompareImmediate(value_cid_reg, Immediate(kNullCid), PP); | |
| 1427 __ j(EQUAL, &no_fixed_length, Assembler::kNearJump); | |
| 1428 // Check for typed data array. | |
| 1429 __ CompareImmediate( | |
| 1430 value_cid_reg, Immediate(kTypedDataInt32x4ArrayCid), PP); | |
| 1431 // Not a typed array or a regular array. | |
| 1432 __ j(GREATER, &no_fixed_length, Assembler::kNearJump); | |
| 1433 __ CompareImmediate( | |
| 1434 value_cid_reg, Immediate(kTypedDataInt8ArrayCid), PP); | |
| 1435 // Could still be a regular array. | |
| 1436 __ j(LESS, &check_array, Assembler::kNearJump); | |
| 1437 __ pushq(value_cid_reg); | |
| 1438 __ movq(value_cid_reg, | |
| 1439 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1440 __ cmpq(field_length_operand, value_cid_reg); | |
| 1441 __ popq(value_cid_reg); | |
| 1442 __ jmp(&length_compared, Assembler::kNearJump); | |
| 1443 // Check for regular array. | |
| 1444 __ Bind(&check_array); | |
| 1445 __ CompareImmediate(value_cid_reg, Immediate(kImmutableArrayCid), PP); | |
| 1446 __ j(GREATER, &no_fixed_length, Assembler::kNearJump); | |
| 1447 __ CompareImmediate(value_cid_reg, Immediate(kArrayCid), PP); | |
| 1448 __ j(LESS, &no_fixed_length, Assembler::kNearJump); | |
| 1449 __ pushq(value_cid_reg); | |
| 1450 __ movq(value_cid_reg, | |
| 1451 FieldAddress(value_reg, Array::length_offset())); | |
| 1452 __ cmpq(field_length_operand, value_cid_reg); | |
| 1453 __ popq(value_cid_reg); | |
| 1454 __ jmp(&length_compared, Assembler::kNearJump); | |
| 1455 __ Bind(&no_fixed_length); | |
| 1456 __ jmp(fail); | |
| 1457 __ Bind(&length_compared); | |
| 1458 } | |
| 1459 __ j(NOT_EQUAL, fail); | |
| 1460 } | |
| 1461 __ Bind(&skip_length_check); | |
| 1462 __ cmpq(value_cid_reg, field_nullability_operand); | 1378 __ cmpq(value_cid_reg, field_nullability_operand); |
| 1463 } else if (value_cid == kNullCid) { | 1379 } else if (value_cid == kNullCid) { |
| 1464 __ CompareImmediate(field_nullability_operand, Immediate(value_cid), PP); | 1380 __ CompareImmediate(field_nullability_operand, Immediate(value_cid), PP); |
| 1465 } else { | 1381 } else { |
| 1466 Label skip_length_check; | |
| 1467 __ CompareImmediate(field_cid_operand, Immediate(value_cid), PP); | 1382 __ CompareImmediate(field_cid_operand, Immediate(value_cid), PP); |
| 1468 // If not equal, skip over length check. | |
| 1469 __ j(NOT_EQUAL, &skip_length_check); | |
| 1470 // Insert length check. | |
| 1471 if (field_has_length) { | |
| 1472 ASSERT(value_cid_reg != kNoRegister); | |
| 1473 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | |
| 1474 __ CompareImmediate(FieldAddress(value_reg, Array::length_offset()), | |
| 1475 Immediate(Smi::RawValue(field_length)), PP); | |
| 1476 } else if (RawObject::IsTypedDataClassId(value_cid)) { | |
| 1477 __ CompareImmediate( | |
| 1478 FieldAddress(value_reg, TypedData::length_offset()), | |
| 1479 Immediate(Smi::RawValue(field_length)), PP); | |
| 1480 } else if (field_cid != kIllegalCid) { | |
| 1481 ASSERT(field_cid != value_cid); | |
| 1482 ASSERT(field_length >= 0); | |
| 1483 // Field has a known class id and length. At compile time it is | |
| 1484 // known that the value's class id is not a fixed length list. | |
| 1485 __ jmp(fail); | |
| 1486 } else { | |
| 1487 ASSERT(field_cid == kIllegalCid); | |
| 1488 ASSERT(field_length == Field::kUnknownFixedLength); | |
| 1489 // Following jump cannot not occur, fall through. | |
| 1490 } | |
| 1491 __ j(NOT_EQUAL, fail); | |
| 1492 } | |
| 1493 // Not identical, possibly null. | |
| 1494 __ Bind(&skip_length_check); | |
| 1495 } | 1383 } |
| 1496 __ j(EQUAL, &ok); | 1384 __ j(EQUAL, &ok); |
| 1497 | 1385 |
| 1498 __ CompareImmediate(field_cid_operand, Immediate(kIllegalCid), PP); | 1386 // Check if the tracked state of the guarded field can be initialized |
| 1499 __ j(NOT_EQUAL, fail); | 1387 // inline. If the field needs length check we fall through to runtime |
| 1388 // which is responsible for computing offset of the length field |
| 1389 // based on the class id. |
| 1390 if (!field().needs_length_check()) { |
| 1391 // Uninitialized field can be handled inline. Check if the |
| 1392 // field is still unitialized. |
| 1393 __ CompareImmediate(field_cid_operand, Immediate(kIllegalCid), PP); |
| 1394 __ j(NOT_EQUAL, fail); |
| 1500 | 1395 |
| 1501 if (value_cid == kDynamicCid) { | 1396 if (value_cid == kDynamicCid) { |
| 1502 __ movq(field_cid_operand, value_cid_reg); | 1397 __ movq(field_cid_operand, value_cid_reg); |
| 1503 __ movq(field_nullability_operand, value_cid_reg); | 1398 __ movq(field_nullability_operand, value_cid_reg); |
| 1504 if (field_has_length) { | 1399 } else { |
| 1505 Label check_array, length_set, no_fixed_length; | 1400 ASSERT(field_reg != kNoRegister); |
| 1506 __ CompareImmediate(value_cid_reg, Immediate(kNullCid), PP); | 1401 __ LoadImmediate(field_cid_operand, Immediate(value_cid), PP); |
| 1507 __ j(EQUAL, &no_fixed_length, Assembler::kNearJump); | 1402 __ LoadImmediate(field_nullability_operand, Immediate(value_cid), PP); |
| 1508 // Check for typed data array. | |
| 1509 __ CompareImmediate(value_cid_reg, | |
| 1510 Immediate(kTypedDataInt32x4ArrayCid), PP); | |
| 1511 // Not a typed array or a regular array. | |
| 1512 __ j(GREATER, &no_fixed_length); | |
| 1513 __ CompareImmediate( | |
| 1514 value_cid_reg, Immediate(kTypedDataInt8ArrayCid), PP); | |
| 1515 // Could still be a regular array. | |
| 1516 __ j(LESS, &check_array, Assembler::kNearJump); | |
| 1517 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1518 __ movq(value_cid_reg, | |
| 1519 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1520 __ movq(field_length_operand, value_cid_reg); | |
| 1521 // Updated field length typed data array. | |
| 1522 __ jmp(&length_set); | |
| 1523 // Check for regular array. | |
| 1524 __ Bind(&check_array); | |
| 1525 __ CompareImmediate(value_cid_reg, Immediate(kImmutableArrayCid), PP); | |
| 1526 __ j(GREATER, &no_fixed_length, Assembler::kNearJump); | |
| 1527 __ CompareImmediate(value_cid_reg, Immediate(kArrayCid), PP); | |
| 1528 __ j(LESS, &no_fixed_length, Assembler::kNearJump); | |
| 1529 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1530 __ movq(value_cid_reg, | |
| 1531 FieldAddress(value_reg, Array::length_offset())); | |
| 1532 __ movq(field_length_operand, value_cid_reg); | |
| 1533 // Updated field length from regular array. | |
| 1534 __ jmp(&length_set, Assembler::kNearJump); | |
| 1535 __ Bind(&no_fixed_length); | |
| 1536 __ LoadImmediate(field_length_operand, | |
| 1537 Immediate(Smi::RawValue(Field::kNoFixedLength)), PP); | |
| 1538 __ Bind(&length_set); | |
| 1539 } | 1403 } |
| 1540 } else { | 1404 |
| 1541 ASSERT(field_reg != kNoRegister); | 1405 if (deopt == NULL) { |
| 1542 __ LoadImmediate(field_cid_operand, Immediate(value_cid), PP); | 1406 ASSERT(!compiler->is_optimizing()); |
| 1543 __ LoadImmediate(field_nullability_operand, Immediate(value_cid), PP); | 1407 __ jmp(&ok); |
| 1544 if (field_has_length) { | |
| 1545 ASSERT(value_cid_reg != kNoRegister); | |
| 1546 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | |
| 1547 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1548 __ movq(value_cid_reg, | |
| 1549 FieldAddress(value_reg, Array::length_offset())); | |
| 1550 __ movq(field_length_operand, value_cid_reg); | |
| 1551 } else if (RawObject::IsTypedDataClassId(value_cid)) { | |
| 1552 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1553 __ movq(value_cid_reg, | |
| 1554 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1555 __ movq(field_length_operand, value_cid_reg); | |
| 1556 } else { | |
| 1557 __ LoadImmediate(field_length_operand, | |
| 1558 Immediate(Smi::RawValue(Field::kNoFixedLength)), PP); | |
| 1559 } | |
| 1560 } | 1408 } |
| 1561 } | 1409 } |
| 1562 | 1410 |
| 1563 if (deopt == NULL) { | 1411 if (deopt == NULL) { |
| 1564 ASSERT(!compiler->is_optimizing()); | 1412 ASSERT(!compiler->is_optimizing()); |
| 1565 __ jmp(&ok); | |
| 1566 __ Bind(fail); | 1413 __ Bind(fail); |
| 1567 | 1414 |
| 1568 __ CompareImmediate(FieldAddress(field_reg, Field::guarded_cid_offset()), | 1415 __ CompareImmediate(FieldAddress(field_reg, Field::guarded_cid_offset()), |
| 1569 Immediate(kDynamicCid), PP); | 1416 Immediate(kDynamicCid), PP); |
| 1570 __ j(EQUAL, &ok); | 1417 __ j(EQUAL, &ok); |
| 1571 | 1418 |
| 1572 __ pushq(field_reg); | 1419 __ pushq(field_reg); |
| 1573 __ pushq(value_reg); | 1420 __ pushq(value_reg); |
| 1574 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); | 1421 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); |
| 1575 __ Drop(2); // Drop the field and the value. | 1422 __ Drop(2); // Drop the field and the value. |
| 1576 } | 1423 } |
| 1577 } else { | 1424 } else { |
| 1578 ASSERT(compiler->is_optimizing()); | 1425 ASSERT(compiler->is_optimizing()); |
| 1579 ASSERT(deopt != NULL); | 1426 ASSERT(deopt != NULL); |
| 1427 |
| 1580 // Field guard class has been initialized and is known. | 1428 // Field guard class has been initialized and is known. |
| 1581 if (field_reg != kNoRegister) { | |
| 1582 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); | |
| 1583 } | |
| 1584 | |
| 1585 if (value_cid == kDynamicCid) { | 1429 if (value_cid == kDynamicCid) { |
| 1586 // Field's guarded class id is fixed but value's class id is not known. | 1430 // Value's class id is not known. |
| 1587 __ testq(value_reg, Immediate(kSmiTagMask)); | 1431 __ testq(value_reg, Immediate(kSmiTagMask)); |
| 1588 | 1432 |
| 1589 if (field_cid != kSmiCid) { | 1433 if (field_cid != kSmiCid) { |
| 1590 __ j(ZERO, fail); | 1434 __ j(ZERO, fail); |
| 1591 __ LoadClassId(value_cid_reg, value_reg); | 1435 __ LoadClassId(value_cid_reg, value_reg); |
| 1592 __ CompareImmediate(value_cid_reg, Immediate(field_cid), PP); | 1436 __ CompareImmediate(value_cid_reg, Immediate(field_cid), PP); |
| 1593 } | 1437 } |
| 1594 | 1438 |
| 1595 if (field_has_length) { | |
| 1596 // Jump when Value CID != Field guard CID | |
| 1597 __ j(NOT_EQUAL, fail); | |
| 1598 | |
| 1599 // Classes are same, perform guarded list length check. | |
| 1600 ASSERT(field_reg != kNoRegister); | |
| 1601 ASSERT(value_cid_reg != kNoRegister); | |
| 1602 FieldAddress field_length_operand( | |
| 1603 field_reg, Field::guarded_list_length_offset()); | |
| 1604 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1605 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1606 __ movq(value_cid_reg, | |
| 1607 FieldAddress(value_reg, Array::length_offset())); | |
| 1608 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1609 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1610 __ movq(value_cid_reg, | |
| 1611 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1612 } | |
| 1613 __ cmpq(value_cid_reg, field_length_operand); | |
| 1614 } | |
| 1615 | |
| 1616 if (field().is_nullable() && (field_cid != kNullCid)) { | 1439 if (field().is_nullable() && (field_cid != kNullCid)) { |
| 1617 __ j(EQUAL, &ok); | 1440 __ j(EQUAL, &ok); |
| 1618 __ CompareObject(value_reg, Object::null_object(), PP); | 1441 __ CompareObject(value_reg, Object::null_object(), PP); |
| 1619 } | 1442 } |
| 1443 |
| 1620 __ j(NOT_EQUAL, fail); | 1444 __ j(NOT_EQUAL, fail); |
| 1621 } else { | 1445 } else { |
| 1622 // Both value's and field's class id is known. | 1446 // Both value's and field's class id is known. |
| 1623 if ((value_cid != field_cid) && (value_cid != nullability)) { | 1447 ASSERT((value_cid != field_cid) && (value_cid != nullability)); |
| 1624 __ jmp(fail); | 1448 __ jmp(fail); |
| 1625 } else if (field_has_length && (value_cid == field_cid)) { | |
| 1626 ASSERT(value_cid_reg != kNoRegister); | |
| 1627 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1628 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1629 __ movq(value_cid_reg, | |
| 1630 FieldAddress(value_reg, Array::length_offset())); | |
| 1631 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1632 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1633 __ movq(value_cid_reg, | |
| 1634 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1635 } | |
| 1636 __ CompareImmediate( | |
| 1637 value_cid_reg, Immediate(Smi::RawValue(field_length)), PP); | |
| 1638 __ j(NOT_EQUAL, fail); | |
| 1639 } else { | |
| 1640 UNREACHABLE(); | |
| 1641 } | |
| 1642 } | 1449 } |
| 1643 } | 1450 } |
| 1644 __ Bind(&ok); | 1451 __ Bind(&ok); |
| 1645 } | 1452 } |
| 1646 | 1453 |
| 1647 | 1454 |
| 1455 LocationSummary* GuardFieldLengthInstr::MakeLocationSummary(Isolate* isolate, |
| 1456 bool opt) const { |
| 1457 const intptr_t kNumInputs = 1; |
| 1458 LocationSummary* summary = new(isolate) LocationSummary( |
| 1459 isolate, kNumInputs, 0, LocationSummary::kNoCall); |
| 1460 summary->set_in(0, Location::RequiresRegister()); |
| 1461 |
| 1462 if (!opt || (field().guarded_list_length() == Field::kUnknownFixedLength)) { |
| 1463 // We need temporaries for field object, length offset and expected length. |
| 1464 summary->AddTemp(Location::RequiresRegister()); |
| 1465 summary->AddTemp(Location::RequiresRegister()); |
| 1466 summary->AddTemp(Location::RequiresRegister()); |
| 1467 } |
| 1468 |
| 1469 return summary; |
| 1470 } |
| 1471 |
| 1472 |
| 1473 void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1474 if (field().guarded_list_length() == Field::kNoFixedLength) { |
| 1475 ASSERT(!compiler->is_optimizing()); |
| 1476 return; // Nothing to emit. |
| 1477 } |
| 1478 |
| 1479 Register value_reg = locs()->in(0).reg(); |
| 1480 |
| 1481 if (!compiler->is_optimizing() || |
| 1482 (field().guarded_list_length() == Field::kUnknownFixedLength)) { |
| 1483 Register field_reg = locs()->temp(0).reg(); |
| 1484 Register offset_reg = locs()->temp(1).reg(); |
| 1485 Register length_reg = locs()->temp(2).reg(); |
| 1486 |
| 1487 Label ok; |
| 1488 |
| 1489 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP); |
| 1490 |
| 1491 __ movsxb(offset_reg, FieldAddress(field_reg, |
| 1492 Field::guarded_list_length_in_object_offset_offset())); |
| 1493 __ movq(length_reg, FieldAddress(field_reg, |
| 1494 Field::guarded_list_length_offset())); |
| 1495 |
| 1496 __ cmpq(offset_reg, Immediate(0)); |
| 1497 __ j(NEGATIVE, &ok); |
| 1498 |
| 1499 // Load the length from the value. GuardFieldClass already verified that |
| 1500 // value's class matches guarded class id of the field. |
| 1501 // offset_reg contains offset already corrected by -kHeapObjectTag that is |
| 1502 // why we use Address instead of FieldAddress. |
| 1503 __ cmpq(length_reg, Address(value_reg, offset_reg, TIMES_1, 0)); |
| 1504 __ j(EQUAL, &ok); |
| 1505 |
| 1506 __ pushq(field_reg); |
| 1507 __ pushq(value_reg); |
| 1508 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); |
| 1509 __ Drop(2); // Drop the field and the value. |
| 1510 |
| 1511 __ Bind(&ok); |
| 1512 } else { |
| 1513 Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField); |
| 1514 |
| 1515 ASSERT(compiler->is_optimizing()); |
| 1516 ASSERT(field().guarded_list_length() >= 0); |
| 1517 ASSERT(field().guarded_list_length_in_object_offset() != |
| 1518 Field::kUnknownLengthOffset); |
| 1519 |
| 1520 __ CompareImmediate( |
| 1521 FieldAddress(value_reg, |
| 1522 field().guarded_list_length_in_object_offset()), |
| 1523 Immediate(Smi::RawValue(field().guarded_list_length())), |
| 1524 PP); |
| 1525 __ j(NOT_EQUAL, deopt); |
| 1526 } |
| 1527 } |
| 1528 |
| 1529 |
| 1648 class StoreInstanceFieldSlowPath : public SlowPathCode { | 1530 class StoreInstanceFieldSlowPath : public SlowPathCode { |
| 1649 public: | 1531 public: |
| 1650 StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction, | 1532 StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction, |
| 1651 const Class& cls) | 1533 const Class& cls) |
| 1652 : instruction_(instruction), cls_(cls) { } | 1534 : instruction_(instruction), cls_(cls) { } |
| 1653 | 1535 |
| 1654 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { | 1536 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1655 __ Comment("StoreInstanceFieldSlowPath"); | 1537 __ Comment("StoreInstanceFieldSlowPath"); |
| 1656 __ Bind(entry_label()); | 1538 __ Bind(entry_label()); |
| 1657 const Code& stub = | 1539 const Code& stub = |
| (...skipping 4264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5922 PcDescriptors::kOther, | 5804 PcDescriptors::kOther, |
| 5923 locs()); | 5805 locs()); |
| 5924 __ Drop(ArgumentCount()); // Discard arguments. | 5806 __ Drop(ArgumentCount()); // Discard arguments. |
| 5925 } | 5807 } |
| 5926 | 5808 |
| 5927 } // namespace dart | 5809 } // namespace dart |
| 5928 | 5810 |
| 5929 #undef __ | 5811 #undef __ |
| 5930 | 5812 |
| 5931 #endif // defined TARGET_ARCH_X64 | 5813 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |