| 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 "lib/error.h" | 10 #include "lib/error.h" |
| 11 #include "vm/dart_entry.h" | 11 #include "vm/dart_entry.h" |
| 12 #include "vm/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
| 13 #include "vm/locations.h" | 13 #include "vm/locations.h" |
| 14 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
| 15 #include "vm/parser.h" | 15 #include "vm/parser.h" |
| 16 #include "vm/stack_frame.h" |
| 16 #include "vm/stub_code.h" | 17 #include "vm/stub_code.h" |
| 17 #include "vm/symbols.h" | 18 #include "vm/symbols.h" |
| 18 | 19 |
| 19 #define __ compiler->assembler()-> | 20 #define __ compiler->assembler()-> |
| 20 | 21 |
| 21 namespace dart { | 22 namespace dart { |
| 22 | 23 |
| 23 DECLARE_FLAG(int, optimization_counter_threshold); | 24 DECLARE_FLAG(int, optimization_counter_threshold); |
| 24 DECLARE_FLAG(bool, propagate_ic_data); | 25 DECLARE_FLAG(bool, propagate_ic_data); |
| 25 | 26 |
| (...skipping 1299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1325 break; | 1326 break; |
| 1326 case kFloat64ArrayCid: | 1327 case kFloat64ArrayCid: |
| 1327 __ movsd(element_address, locs()->in(2).fpu_reg()); | 1328 __ movsd(element_address, locs()->in(2).fpu_reg()); |
| 1328 break; | 1329 break; |
| 1329 default: | 1330 default: |
| 1330 UNREACHABLE(); | 1331 UNREACHABLE(); |
| 1331 } | 1332 } |
| 1332 } | 1333 } |
| 1333 | 1334 |
| 1334 | 1335 |
| 1336 LocationSummary* GuardFieldInstr::MakeLocationSummary() const { |
| 1337 const intptr_t kNumInputs = 1; |
| 1338 LocationSummary* summary = |
| 1339 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall); |
| 1340 summary->set_in(0, Location::RequiresRegister()); |
| 1341 if (value()->Type()->ToCid() == kDynamicCid) { |
| 1342 summary->AddTemp(Location::RequiresRegister()); |
| 1343 } |
| 1344 if (field().guarded_cid() == kIllegalCid) { |
| 1345 summary->AddTemp(Location::RequiresRegister()); |
| 1346 } |
| 1347 return summary; |
| 1348 } |
| 1349 |
| 1350 |
| 1351 static void PushCid(FlowGraphCompiler* compiler, const Immediate& imm) { |
| 1352 __ pushq(Immediate(Smi::RawValue(imm.value()))); |
| 1353 } |
| 1354 |
| 1355 |
| 1356 static void PushCid(FlowGraphCompiler* compiler, Register reg) { |
| 1357 __ SmiTag(reg); |
| 1358 __ pushq(reg); |
| 1359 } |
| 1360 |
| 1361 |
| 1362 template<typename ValueCidOperandType> |
| 1363 static void EmitCidGuardInit(FlowGraphCompiler* compiler, |
| 1364 ValueCidOperandType value_cid, |
| 1365 const Immediate& field_cid, |
| 1366 const Immediate& nullability, |
| 1367 Label* deopt, |
| 1368 Label* ok) { |
| 1369 // nothing to do. |
| 1370 } |
| 1371 |
| 1372 |
| 1373 template<typename ValueCidOperandType> |
| 1374 static void EmitCidGuardInit(FlowGraphCompiler* compiler, |
| 1375 ValueCidOperandType value_cid, |
| 1376 const FieldAddress& field_cid, |
| 1377 const FieldAddress& nullability, |
| 1378 Label* deopt, |
| 1379 Label* ok) { |
| 1380 // Check if field is initialized for the first time. |
| 1381 Label fail; |
| 1382 __ cmpq(field_cid, Immediate(kIllegalCid)); |
| 1383 __ j(NOT_EQUAL, (deopt != NULL) ? deopt : &fail); |
| 1384 __ movq(field_cid, value_cid); |
| 1385 __ movq(nullability, value_cid); |
| 1386 __ jmp(ok); |
| 1387 if (deopt == NULL) { |
| 1388 __ Bind(&fail); |
| 1389 } |
| 1390 } |
| 1391 |
| 1392 |
| 1393 static void CompareJump(FlowGraphCompiler* compiler, |
| 1394 Condition cond, |
| 1395 const Immediate& left, |
| 1396 const Immediate& right, |
| 1397 Label* target) { |
| 1398 if ((left.value() == right.value()) && (cond == EQUAL)) { |
| 1399 __ jmp(target); |
| 1400 } else if ((left.value() != right.value()) && cond == NOT_EQUAL) { |
| 1401 __ jmp(target); |
| 1402 } |
| 1403 } |
| 1404 |
| 1405 |
| 1406 static void CompareJump(FlowGraphCompiler* compiler, |
| 1407 Condition cond, |
| 1408 Immediate left, |
| 1409 Register right, |
| 1410 Label* target) { |
| 1411 ASSERT((cond == EQUAL) || (cond == NOT_EQUAL)); |
| 1412 __ cmpq(right, left); |
| 1413 __ j(cond, target); |
| 1414 } |
| 1415 |
| 1416 |
| 1417 template<typename LeftT, typename RightT> |
| 1418 static void CompareJump(FlowGraphCompiler* compiler, |
| 1419 Condition cond, |
| 1420 LeftT left, |
| 1421 RightT right, |
| 1422 Label* target) { |
| 1423 __ cmpq(left, right); |
| 1424 __ j(cond, target); |
| 1425 } |
| 1426 |
| 1427 |
| 1428 template<typename ValueCidOperandType, |
| 1429 typename FieldCidOperandType, |
| 1430 typename FieldNullabilityOperandType> |
| 1431 static void EmitCidGuard(FlowGraphCompiler* compiler, |
| 1432 const Field& field, |
| 1433 ValueCidOperandType value_cid, |
| 1434 FieldCidOperandType field_cid, |
| 1435 FieldNullabilityOperandType nullability, |
| 1436 Label* deopt) { |
| 1437 Label ok, update; |
| 1438 CompareJump(compiler, EQUAL, field_cid, value_cid, &ok); |
| 1439 if ((deopt != NULL) && (field.guarded_cid() != kIllegalCid)) { |
| 1440 CompareJump(compiler, NOT_EQUAL, nullability, value_cid, deopt); |
| 1441 } else { |
| 1442 CompareJump(compiler, EQUAL, nullability, value_cid, &ok); |
| 1443 } |
| 1444 |
| 1445 EmitCidGuardInit(compiler, value_cid, field_cid, nullability, deopt, &ok); |
| 1446 |
| 1447 if (deopt == NULL) { |
| 1448 // Switch field's cid to dynamic and notify runtime. |
| 1449 CompareJump(compiler, EQUAL, field_cid, Immediate(kDynamicCid), &ok); |
| 1450 __ PushObject(field); |
| 1451 PushCid(compiler, value_cid); |
| 1452 __ CallRuntime(kUpdateFieldCidRuntimeEntry); |
| 1453 __ Drop(2); |
| 1454 } |
| 1455 |
| 1456 __ Bind(&ok); |
| 1457 } |
| 1458 |
| 1459 |
| 1460 template<typename FieldCidOperandType, typename FieldNullabilityOperandType> |
| 1461 static void EmitCidGuard(FlowGraphCompiler* compiler, |
| 1462 const Field& field, |
| 1463 intptr_t value_cid, |
| 1464 Register value_cid_reg, |
| 1465 FieldCidOperandType field_cid, |
| 1466 FieldNullabilityOperandType nullability, |
| 1467 Label* deopt) { |
| 1468 if (value_cid == kDynamicCid) { |
| 1469 EmitCidGuard(compiler, field, value_cid_reg, field_cid, nullability, deopt); |
| 1470 } else { |
| 1471 EmitCidGuard(compiler, |
| 1472 field, |
| 1473 Immediate(value_cid), |
| 1474 field_cid, |
| 1475 nullability, |
| 1476 deopt); |
| 1477 } |
| 1478 } |
| 1479 |
| 1480 |
| 1481 static void EmitFieldGuard(FlowGraphCompiler* compiler, |
| 1482 Register value_reg, |
| 1483 const Field& field, |
| 1484 intptr_t value_cid, |
| 1485 Register value_cid_reg, |
| 1486 intptr_t field_cid, |
| 1487 intptr_t nullability, |
| 1488 Register field_reg, |
| 1489 Label* deopt) { |
| 1490 if (value_cid == kDynamicCid) { |
| 1491 Label not_smi, cid_loaded; |
| 1492 __ testq(value_reg, Immediate(kSmiTagMask)); |
| 1493 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 1494 __ movq(value_cid_reg, Immediate(kSmiCid)); |
| 1495 __ jmp(&cid_loaded); |
| 1496 __ Bind(¬_smi); |
| 1497 __ LoadClassId(value_cid_reg, value_reg); |
| 1498 __ Bind(&cid_loaded); |
| 1499 } |
| 1500 |
| 1501 if (field_cid == kIllegalCid) { |
| 1502 __ LoadObject(field_reg, Field::ZoneHandle(field.raw())); |
| 1503 EmitCidGuard(compiler, |
| 1504 field, |
| 1505 value_cid, |
| 1506 value_cid_reg, |
| 1507 FieldAddress(field_reg, Field::guarded_cid_offset()), |
| 1508 FieldAddress(field_reg, Field::is_nullable_offset()), |
| 1509 deopt); |
| 1510 } else { |
| 1511 EmitCidGuard(compiler, |
| 1512 field, |
| 1513 value_cid, |
| 1514 value_cid_reg, |
| 1515 Immediate(field_cid), |
| 1516 Immediate(nullability), |
| 1517 deopt); |
| 1518 } |
| 1519 } |
| 1520 |
| 1521 |
| 1522 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1523 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1524 const intptr_t field_cid = field().guarded_cid(); |
| 1525 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; |
| 1526 |
| 1527 Register value_reg = locs()->in(0).reg(); |
| 1528 |
| 1529 Register value_cid_reg = (value_cid == kDynamicCid) ? |
| 1530 locs()->temp(0).reg() : kNoRegister; |
| 1531 |
| 1532 Label* deopt = compiler->is_optimizing() && CanDeoptimize() ? |
| 1533 compiler->AddDeoptStub(deopt_id(), kDeoptStoreInstanceField) : NULL; |
| 1534 |
| 1535 if ((deopt != NULL) && (field_cid != kIllegalCid)) { |
| 1536 if (value_cid != kDynamicCid) { |
| 1537 ASSERT(field_cid != value_cid); |
| 1538 __ jmp(deopt); |
| 1539 return; |
| 1540 } |
| 1541 |
| 1542 if (field_cid == kSmiCid) { |
| 1543 __ testq(value_reg, Immediate(kSmiTagMask)); |
| 1544 } else { |
| 1545 ASSERT(value_cid_reg != kNoRegister); |
| 1546 __ testq(value_reg, Immediate(kSmiTagMask)); |
| 1547 __ j(ZERO, deopt); |
| 1548 __ LoadClassId(value_cid_reg, value_reg); |
| 1549 __ cmpq(value_cid_reg, Immediate(field_cid)); |
| 1550 } |
| 1551 |
| 1552 if (field().is_nullable()) { |
| 1553 Label ok; |
| 1554 __ j(EQUAL, &ok); |
| 1555 const Immediate& raw_null = |
| 1556 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1557 __ cmpq(value_reg, raw_null); |
| 1558 __ j(NOT_EQUAL, deopt); |
| 1559 __ Bind(&ok); |
| 1560 } else { |
| 1561 __ j(NOT_EQUAL, deopt); |
| 1562 } |
| 1563 |
| 1564 return; |
| 1565 } |
| 1566 |
| 1567 Register field_reg = (field_cid == kIllegalCid) ? |
| 1568 locs()->temp(1).reg() : kNoRegister; |
| 1569 |
| 1570 EmitFieldGuard(compiler, |
| 1571 value_reg, |
| 1572 field(), |
| 1573 value_cid, value_cid_reg, |
| 1574 field_cid, nullability, field_reg, |
| 1575 deopt); |
| 1576 } |
| 1577 |
| 1578 |
| 1335 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { | 1579 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { |
| 1336 const intptr_t kNumInputs = 2; | 1580 const intptr_t kNumInputs = 2; |
| 1337 const intptr_t num_temps = 0; | 1581 const intptr_t num_temps = 0; |
| 1338 LocationSummary* summary = | 1582 LocationSummary* summary = |
| 1339 new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); | 1583 new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); |
| 1340 summary->set_in(0, Location::RequiresRegister()); | 1584 summary->set_in(0, Location::RequiresRegister()); |
| 1341 summary->set_in(1, ShouldEmitStoreBarrier() | 1585 summary->set_in(1, (ShouldEmitStoreBarrier() || should_emit_field_guard()) |
| 1342 ? Location::WritableRegister() | 1586 ? Location::WritableRegister() |
| 1343 : Location::RegisterOrConstant(value())); | 1587 : Location::RegisterOrConstant(value())); |
| 1588 |
| 1589 if (should_emit_field_guard()) { |
| 1590 summary->AddTemp(Location::RequiresRegister()); |
| 1591 summary->AddTemp(Location::RequiresRegister()); |
| 1592 } |
| 1593 |
| 1344 return summary; | 1594 return summary; |
| 1345 } | 1595 } |
| 1346 | 1596 |
| 1347 | 1597 |
| 1348 void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1598 void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1349 Register instance_reg = locs()->in(0).reg(); | 1599 Register instance_reg = locs()->in(0).reg(); |
| 1600 |
| 1601 |
| 1602 if (should_emit_field_guard()) { |
| 1603 ASSERT(!compiler->is_optimizing()); |
| 1604 Register value_reg = locs()->in(1).reg(); |
| 1605 Register value_cid_reg = locs()->temp(0).reg(); |
| 1606 Register field_reg = locs()->temp(1).reg(); |
| 1607 |
| 1608 __ pushq(instance_reg); |
| 1609 __ pushq(value_reg); |
| 1610 EmitFieldGuard(compiler, |
| 1611 value_reg, |
| 1612 field(), |
| 1613 kDynamicCid, |
| 1614 value_cid_reg, |
| 1615 kIllegalCid, |
| 1616 kIllegalCid, |
| 1617 field_reg, |
| 1618 NULL); |
| 1619 __ popq(value_reg); |
| 1620 __ popq(instance_reg); |
| 1621 } |
| 1622 |
| 1350 if (ShouldEmitStoreBarrier()) { | 1623 if (ShouldEmitStoreBarrier()) { |
| 1351 Register value_reg = locs()->in(1).reg(); | 1624 Register value_reg = locs()->in(1).reg(); |
| 1352 __ StoreIntoObject(instance_reg, | 1625 __ StoreIntoObject(instance_reg, |
| 1353 FieldAddress(instance_reg, field().Offset()), value_reg); | 1626 FieldAddress(instance_reg, field().Offset()), value_reg); |
| 1354 } else { | 1627 } else { |
| 1355 if (locs()->in(1).IsConstant()) { | 1628 if (locs()->in(1).IsConstant()) { |
| 1356 __ StoreObject(FieldAddress(instance_reg, field().Offset()), | 1629 __ StoreObject(FieldAddress(instance_reg, field().Offset()), |
| 1357 locs()->in(1).constant()); | 1630 locs()->in(1).constant()); |
| 1358 } else { | 1631 } else { |
| 1359 Register value_reg = locs()->in(1).reg(); | 1632 Register value_reg = locs()->in(1).reg(); |
| (...skipping 1313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2673 } | 2946 } |
| 2674 | 2947 |
| 2675 | 2948 |
| 2676 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2949 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2677 comparison()->EmitBranchCode(compiler, this); | 2950 comparison()->EmitBranchCode(compiler, this); |
| 2678 } | 2951 } |
| 2679 | 2952 |
| 2680 | 2953 |
| 2681 LocationSummary* CheckClassInstr::MakeLocationSummary() const { | 2954 LocationSummary* CheckClassInstr::MakeLocationSummary() const { |
| 2682 const intptr_t kNumInputs = 1; | 2955 const intptr_t kNumInputs = 1; |
| 2683 const intptr_t kNumTemps = 1; | 2956 const intptr_t kNumTemps = 0; |
| 2684 LocationSummary* summary = | 2957 LocationSummary* summary = |
| 2685 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2958 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2686 summary->set_in(0, Location::RequiresRegister()); | 2959 summary->set_in(0, Location::RequiresRegister()); |
| 2687 summary->set_temp(0, Location::RequiresRegister()); | 2960 if (!null_check()) { |
| 2961 summary->AddTemp(Location::RequiresRegister()); |
| 2962 } |
| 2688 return summary; | 2963 return summary; |
| 2689 } | 2964 } |
| 2690 | 2965 |
| 2691 | 2966 |
| 2692 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2967 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2968 if (null_check()) { |
| 2969 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 2970 kDeoptCheckClass); |
| 2971 const Immediate& raw_null = |
| 2972 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 2973 __ cmpq(locs()->in(0).reg(), raw_null); |
| 2974 __ j(EQUAL, deopt); |
| 2975 return; |
| 2976 } |
| 2977 |
| 2693 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || | 2978 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || |
| 2694 (unary_checks().NumberOfChecks() > 1)); | 2979 (unary_checks().NumberOfChecks() > 1)); |
| 2695 Register value = locs()->in(0).reg(); | 2980 Register value = locs()->in(0).reg(); |
| 2696 Register temp = locs()->temp(0).reg(); | 2981 Register temp = locs()->temp(0).reg(); |
| 2697 Label* deopt = compiler->AddDeoptStub(deopt_id(), | 2982 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 2698 kDeoptCheckClass); | 2983 kDeoptCheckClass); |
| 2699 Label is_ok; | 2984 Label is_ok; |
| 2700 intptr_t cix = 0; | 2985 intptr_t cix = 0; |
| 2701 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { | 2986 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { |
| 2702 __ testq(value, Immediate(kSmiTagMask)); | 2987 __ testq(value, Immediate(kSmiTagMask)); |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3158 PcDescriptors::kOther, | 3443 PcDescriptors::kOther, |
| 3159 locs()); | 3444 locs()); |
| 3160 __ Drop(2); // Discard type arguments and receiver. | 3445 __ Drop(2); // Discard type arguments and receiver. |
| 3161 } | 3446 } |
| 3162 | 3447 |
| 3163 } // namespace dart | 3448 } // namespace dart |
| 3164 | 3449 |
| 3165 #undef __ | 3450 #undef __ |
| 3166 | 3451 |
| 3167 #endif // defined TARGET_ARCH_X64 | 3452 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |