| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/code_generator.h" | 8 #include "vm/code_generator.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/ic_data.h" | 10 #include "vm/ic_data.h" |
| (...skipping 1446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1457 __ popl(EAX); | 1457 __ popl(EAX); |
| 1458 __ popl(EAX); | 1458 __ popl(EAX); |
| 1459 __ popl(EAX); // Get result into EAX. | 1459 __ popl(EAX); // Get result into EAX. |
| 1460 | 1460 |
| 1461 // Remove the stub frame as we are about to return. | 1461 // Remove the stub frame as we are about to return. |
| 1462 __ LeaveFrame(); | 1462 __ LeaveFrame(); |
| 1463 __ ret(); | 1463 __ ret(); |
| 1464 } | 1464 } |
| 1465 | 1465 |
| 1466 | 1466 |
| 1467 // Use inline cache data array to invoke the target or continue in inline | 1467 |
| 1468 // cache miss handler. Stub for 1-argument check (receiver class). | 1468 // Generate inline cache check for 'num_args'. |
| 1469 // ECX: Inline cache data array | 1469 // ECX: Inline cache data array. |
| 1470 // EDX: Arguments array | 1470 // EDX: Arguments array. |
| 1471 // TOS(0): return address | 1471 // TOS(0): return address |
| 1472 void StubCode::GenerateInlineCacheStub(Assembler* assembler) { | 1472 // Control flow: |
| 1473 Label ic_miss, is_smi, test_class; | 1473 // - If receiver is null -> jump to IC miss. |
| 1474 // - If receiver is Smi -> load Smi class. |
| 1475 // - If receiver is not-Smi -> load receiver's class. |
| 1476 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1477 // - Match found -> jump to target. |
| 1478 // - Match not found -> jump to IC miss. |
| 1479 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, |
| 1480 intptr_t num_args) { |
| 1481 ASSERT(num_args > 0); |
| 1474 // Get receiver. | 1482 // Get receiver. |
| 1475 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); | 1483 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); |
| 1476 __ movl(EAX, Address(ESP, EAX, TIMES_2, 0)); | 1484 __ movl(EAX, Address(ESP, EAX, TIMES_2, 0)); |
| 1477 | 1485 |
| 1478 __ CompareObject(EAX, Instance::ZoneHandle(Instance::null())); | 1486 Label get_class, ic_miss; |
| 1479 __ j(EQUAL, &ic_miss, Assembler::kNearJump); // Null receiver -> IC miss. | 1487 __ call(&get_class); |
| 1480 | |
| 1481 // Test if Smi -> load Smi class for comparison. | |
| 1482 __ testl(EAX, Immediate(kSmiTagMask)); | |
| 1483 __ j(ZERO, &is_smi, Assembler::kNearJump); | |
| 1484 __ movl(EAX, FieldAddress(EAX, Object::class_offset())); | |
| 1485 __ jmp(&test_class); | |
| 1486 __ Bind(&is_smi); | |
| 1487 const Class& smi_class = | |
| 1488 Class::ZoneHandle(Isolate::Current()->object_store()->smi_class()); | |
| 1489 __ LoadObject(EAX, smi_class); | |
| 1490 | |
| 1491 __ Bind(&test_class); | |
| 1492 // EAX: receiver's class | 1488 // EAX: receiver's class |
| 1493 // ECX: IC data array. | 1489 // ECX: IC data array. |
| 1494 | 1490 |
| 1495 #if defined(DEBUG) | 1491 #if defined(DEBUG) |
| 1496 { Label ok; | 1492 { Label ok; |
| 1497 // Check that the IC data array has NumberOfArgumentsChecked() == 1. | 1493 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. |
| 1498 __ movl(EBX, FieldAddress(ECX, | 1494 __ movl(EBX, FieldAddress(ECX, |
| 1499 Array::data_offset() + ICData::kNumArgsCheckedIndex * kWordSize)); | 1495 Array::data_offset() + ICData::kNumArgsCheckedIndex * kWordSize)); |
| 1500 const Immediate value = Immediate(reinterpret_cast<int32_t>(Smi::New(1))); | 1496 const Immediate value = |
| 1497 Immediate(reinterpret_cast<int32_t>(Smi::New(num_args))); |
| 1501 __ cmpl(EBX, value); | 1498 __ cmpl(EBX, value); |
| 1502 __ j(EQUAL, &ok, Assembler::kNearJump); | 1499 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1503 __ Stop("Incorrect stub for IC data"); | 1500 __ Stop("Incorrect stub for IC data"); |
| 1504 __ Bind(&ok); | 1501 __ Bind(&ok); |
| 1505 } | 1502 } |
| 1506 #endif // DEBUG | 1503 #endif // DEBUG |
| 1507 | 1504 |
| 1505 // Loop that checks if there is an IC data match. |
| 1506 // EAX: receiver's class. |
| 1507 // ECX: IC data array (preserved). |
| 1508 __ leal(EBX, FieldAddress(ECX, |
| 1509 Array::data_offset() + ICData::kChecksStartIndex * kWordSize)); |
| 1510 // EBX: pointing to a class to check against (into IC data array). |
| 1508 const Immediate raw_null = | 1511 const Immediate raw_null = |
| 1509 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1512 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1510 __ leal(EBX, FieldAddress(ECX, | 1513 Label loop, found; |
| 1511 Array::data_offset() + ICData::kChecksStartIndex * kWordSize)); | 1514 if (num_args == 1) { |
| 1512 Label loop, found, call_target_function; | 1515 __ Bind(&loop); |
| 1513 __ Bind(&loop); | 1516 __ movl(EDI, Address(EBX, 0)); // Get class to check. |
| 1514 __ movl(EDI, Address(EBX, 0)); // Get class to check. | 1517 __ cmpl(EAX, EDI); // Match? |
| 1515 __ cmpl(EAX, EDI); // Match? | 1518 __ j(EQUAL, &found, Assembler::kNearJump); |
| 1516 __ j(EQUAL, &found, Assembler::kNearJump); | 1519 __ addl(EBX, Immediate(kWordSize * 2)); // Next element (class + target). |
| 1517 __ addl(EBX, Immediate(kWordSize * 2)); // next element (class + target). | 1520 __ cmpl(EDI, raw_null); // Done? |
| 1518 __ cmpl(EDI, raw_null); // Done? | 1521 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 1519 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); | 1522 } else if (num_args == 2) { |
| 1523 Label no_match; |
| 1524 __ Bind(&loop); |
| 1525 __ movl(EDI, Address(EBX, 0)); // Get class from IC data to check. |
| 1526 // Get receiver. |
| 1527 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); |
| 1528 __ movl(EAX, Address(ESP, EAX, TIMES_2, 0)); |
| 1529 __ call(&get_class); |
| 1530 __ cmpl(EAX, EDI); // Match? |
| 1531 __ j(NOT_EQUAL, &no_match, Assembler::kNearJump); |
| 1532 // Check second. |
| 1533 __ movl(EDI, Address(EBX, kWordSize)); // Get class from IC data to check. |
| 1534 // Get next argument. |
| 1535 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); |
| 1536 __ movl(EAX, Address(ESP, EAX, TIMES_2, -kWordSize)); |
| 1537 __ call(&get_class); |
| 1538 __ cmpl(EAX, EDI); // Match? |
| 1539 __ j(EQUAL, &found, Assembler::kNearJump); |
| 1540 __ Bind(&no_match); |
| 1541 __ addl(EBX, Immediate(kWordSize * 1 + (num_args))); // Next element. |
| 1542 __ cmpl(EDI, raw_null); // Done? |
| 1543 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 1544 } |
| 1520 | 1545 |
| 1521 __ Bind(&ic_miss); | 1546 __ Bind(&ic_miss); |
| 1522 | 1547 // Get receiver, again. |
| 1523 // Get receiver. | |
| 1524 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); | 1548 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); |
| 1525 __ movl(EAX, Address(ESP, EAX, TIMES_2, 0)); | 1549 __ leal(EAX, Address(ESP, EAX, TIMES_2, 0)); |
| 1526 __ EnterFrame(0); | 1550 __ EnterFrame(0); |
| 1527 // Setup space for return value on stack by pushing smi 0. | 1551 // Setup space for return value on stack by pushing smi 0. |
| 1528 __ pushl(EDX); // Preserve arguments array. | 1552 __ pushl(EDX); // Preserve arguments array. |
| 1529 __ pushl(ECX); // Preserve IC data array | 1553 __ pushl(ECX); // Preserve IC data array |
| 1530 __ pushl(Immediate(0)); | 1554 __ pushl(Immediate(0)); // Space for result (target code object). |
| 1531 __ pushl(EAX); // Push receiver. | 1555 __ movl(EDX, FieldAddress(EDX, Array::data_offset())); |
| 1532 __ CallRuntimeFromStub(kInlineCacheMissHandlerRuntimeEntry); | 1556 // Push call arguments. |
| 1533 __ popl(EAX); // Remove receiver pushed earlier. | 1557 for (intptr_t i = 0; i < num_args; i++) { |
| 1534 __ popl(EAX); // Pop returned code object into EAX. | 1558 __ movl(EDX, Address(EAX, -kWordSize * i)); |
| 1559 __ pushl(EDX); |
| 1560 } |
| 1561 if (num_args == 1) { |
| 1562 __ CallRuntimeFromStub(kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1563 } else if (num_args == 2) { |
| 1564 __ CallRuntimeFromStub(kInlineCacheMissHandlerTwoArgsRuntimeEntry); |
| 1565 } else { |
| 1566 UNIMPLEMENTED(); |
| 1567 } |
| 1568 // Remove call arguments pushed earlier. |
| 1569 for (intptr_t i = 0; i < num_args; i++) { |
| 1570 __ popl(EAX); |
| 1571 } |
| 1572 __ popl(EAX); // Pop returned code object into EAX (null if not found). |
| 1535 __ popl(ECX); // Restore IC data array. | 1573 __ popl(ECX); // Restore IC data array. |
| 1536 __ popl(EDX); // Restore arguments array. | 1574 __ popl(EDX); // Restore arguments array. |
| 1537 __ LeaveFrame(); | 1575 __ LeaveFrame(); |
| 1576 Label call_target_function; |
| 1538 __ cmpl(EAX, raw_null); | 1577 __ cmpl(EAX, raw_null); |
| 1539 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); | 1578 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); |
| 1540 // NoSuchMethod or closure. | 1579 // NoSuchMethod or closure. |
| 1541 __ jmp(&StubCode::MegamorphicLookupLabel()); | 1580 __ jmp(&StubCode::MegamorphicLookupLabel()); |
| 1542 | 1581 |
| 1543 __ Bind(&found); | 1582 __ Bind(&found); |
| 1544 __ movl(EAX, Address(EBX, kWordSize)); // Target function. | 1583 // EBX: Pointer to an IC data check group (classes + target) |
| 1584 __ movl(EAX, Address(EBX, kWordSize * num_args)); // Target function. |
| 1545 | 1585 |
| 1546 __ Bind(&call_target_function); | 1586 __ Bind(&call_target_function); |
| 1547 // EAX: Target function. | 1587 // EAX: Target function. |
| 1548 __ movl(EAX, FieldAddress(EAX, Function::code_offset())); | 1588 __ movl(EAX, FieldAddress(EAX, Function::code_offset())); |
| 1549 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); | 1589 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); |
| 1550 __ addl(EAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); | 1590 __ addl(EAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| 1551 __ jmp(EAX); | 1591 __ jmp(EAX); |
| 1592 |
| 1593 __ Bind(&get_class); |
| 1594 Label not_smi; |
| 1595 // Test if Smi -> load Smi class for comparison. |
| 1596 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1597 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 1598 const Class& smi_class = |
| 1599 Class::ZoneHandle(Isolate::Current()->object_store()->smi_class()); |
| 1600 __ LoadObject(EAX, smi_class); |
| 1601 __ ret(); |
| 1602 |
| 1603 __ Bind(¬_smi); |
| 1604 __ movl(EAX, FieldAddress(EAX, Object::class_offset())); |
| 1605 __ ret(); |
| 1552 } | 1606 } |
| 1553 | 1607 |
| 1554 | 1608 |
| 1609 // Use inline cache data array to invoke the target or continue in inline |
| 1610 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1611 // ECX: Inline cache data array |
| 1612 // EDX: Arguments array |
| 1613 // TOS(0): return address |
| 1614 // Inline cache data array structure: |
| 1615 // 0: function-name |
| 1616 // 1: N, number of arguments checked. |
| 1617 // 2 .. (length - 1): group of checks, each check containing: |
| 1618 // - N classes. |
| 1619 // - 1 target function. |
| 1620 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1621 return GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1622 } |
| 1623 |
| 1624 |
| 1625 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1626 return GenerateNArgsCheckInlineCacheStub(assembler, 2); |
| 1627 } |
| 1628 |
| 1555 // ECX: Function object. | 1629 // ECX: Function object. |
| 1556 // EDX: Arguments array. | 1630 // EDX: Arguments array. |
| 1557 // TOS(0): return address (Dart code). | 1631 // TOS(0): return address (Dart code). |
| 1558 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { | 1632 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { |
| 1559 __ EnterFrame(0); | 1633 __ EnterFrame(0); |
| 1560 __ pushl(EDX); | 1634 __ pushl(EDX); |
| 1561 __ pushl(ECX); | 1635 __ pushl(ECX); |
| 1562 __ CallRuntimeFromStub(kBreakpointStaticHandlerRuntimeEntry); | 1636 __ CallRuntimeFromStub(kBreakpointStaticHandlerRuntimeEntry); |
| 1563 __ popl(ECX); | 1637 __ popl(ECX); |
| 1564 __ popl(EDX); | 1638 __ popl(EDX); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1578 // TOS(0): return address (Dart code). | 1652 // TOS(0): return address (Dart code). |
| 1579 void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) { | 1653 void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) { |
| 1580 __ EnterFrame(0); | 1654 __ EnterFrame(0); |
| 1581 __ pushl(ECX); | 1655 __ pushl(ECX); |
| 1582 __ pushl(EDX); | 1656 __ pushl(EDX); |
| 1583 __ CallRuntimeFromStub(kBreakpointDynamicHandlerRuntimeEntry); | 1657 __ CallRuntimeFromStub(kBreakpointDynamicHandlerRuntimeEntry); |
| 1584 __ popl(EDX); | 1658 __ popl(EDX); |
| 1585 __ popl(ECX); | 1659 __ popl(ECX); |
| 1586 __ LeaveFrame(); | 1660 __ LeaveFrame(); |
| 1587 // Now call the dynamic function. | 1661 // Now call the dynamic function. |
| 1588 __ jmp(&StubCode::InlineCacheLabel()); | 1662 __ jmp(&StubCode::OneArgCheckInlineCacheLabel()); |
| 1589 } | 1663 } |
| 1590 | 1664 |
| 1591 } // namespace dart | 1665 } // namespace dart |
| 1592 | 1666 |
| 1593 #endif // defined TARGET_ARCH_IA32 | 1667 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |