| 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/code_generator.h" | 5 #include "vm/code_generator.h" |
| 6 | 6 |
| 7 #include "vm/assembler.h" | 7 #include "vm/assembler.h" |
| 8 #include "vm/ast.h" | 8 #include "vm/ast.h" |
| 9 #include "vm/bigint_operations.h" | 9 #include "vm/bigint_operations.h" |
| 10 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
| (...skipping 1471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1482 | 1482 |
| 1483 // Copy optimized frame into the isolate buffer. | 1483 // Copy optimized frame into the isolate buffer. |
| 1484 // The first incoming argument is stored at the last entry in the | 1484 // The first incoming argument is stored at the last entry in the |
| 1485 // copied frame buffer. | 1485 // copied frame buffer. |
| 1486 static void CopyFrame(const Code& optimized_code, const StackFrame& frame) { | 1486 static void CopyFrame(const Code& optimized_code, const StackFrame& frame) { |
| 1487 const Function& function = Function::Handle(optimized_code.function()); | 1487 const Function& function = Function::Handle(optimized_code.function()); |
| 1488 // Do not copy incoming arguments if there are optional arguments (they | 1488 // Do not copy incoming arguments if there are optional arguments (they |
| 1489 // are copied into local space at method entry). | 1489 // are copied into local space at method entry). |
| 1490 const intptr_t num_args = | 1490 const intptr_t num_args = |
| 1491 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); | 1491 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); |
| 1492 // FP, PC-marker and return-address will be copied as well. | 1492 // The fixed size section of the (fake) Dart frame called via a stub by the |
| 1493 // optimized function contains FP, PP (ARM and MIPS only), PC-marker and |
| 1494 // return-address. This section is copied as well, so that its contained |
| 1495 // values can be updated before returning to the deoptimized function. |
| 1493 const intptr_t frame_copy_size = | 1496 const intptr_t frame_copy_size = |
| 1494 // Deoptimized function's return address: caller_frame->pc(). | 1497 + kDartFrameFixedSize // For saved values below sp. |
| 1495 - kSavedPcSlotFromSp | 1498 + ((frame.fp() - frame.sp()) / kWordSize) // For frame size incl. sp. |
| 1496 + ((frame.fp() - frame.sp()) / kWordSize) | |
| 1497 + 1 // For fp. | 1499 + 1 // For fp. |
| 1498 + kParamEndSlotFromFp | 1500 + kParamEndSlotFromFp // For saved values above fp. |
| 1499 + num_args; | 1501 + num_args; // For arguments. |
| 1500 intptr_t* frame_copy = new intptr_t[frame_copy_size]; | 1502 intptr_t* frame_copy = new intptr_t[frame_copy_size]; |
| 1501 ASSERT(frame_copy != NULL); | 1503 ASSERT(frame_copy != NULL); |
| 1502 // Include the return address of optimized code. | |
| 1503 intptr_t* start = reinterpret_cast<intptr_t*>( | 1504 intptr_t* start = reinterpret_cast<intptr_t*>( |
| 1504 frame.sp() + (kSavedPcSlotFromSp * kWordSize)); | 1505 frame.sp() - (kDartFrameFixedSize * kWordSize)); |
| 1505 for (intptr_t i = 0; i < frame_copy_size; i++) { | 1506 for (intptr_t i = 0; i < frame_copy_size; i++) { |
| 1506 frame_copy[i] = *(start + i); | 1507 frame_copy[i] = *(start + i); |
| 1507 } | 1508 } |
| 1508 Isolate::Current()->SetDeoptFrameCopy(frame_copy, frame_copy_size); | 1509 Isolate::Current()->SetDeoptFrameCopy(frame_copy, frame_copy_size); |
| 1509 } | 1510 } |
| 1510 | 1511 |
| 1511 | 1512 |
| 1512 // Copies saved registers and caller's frame into temporary buffers. | 1513 // Copies saved registers and caller's frame into temporary buffers. |
| 1513 // Returns the stack size of unoptimized frame. | 1514 // Returns the stack size of unoptimized frame. |
| 1514 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, | 1515 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
| 1515 uword saved_registers_address) { | 1516 uword saved_registers_address) { |
| 1516 Isolate* isolate = Isolate::Current(); | 1517 Isolate* isolate = Isolate::Current(); |
| 1517 StackZone zone(isolate); | 1518 StackZone zone(isolate); |
| 1518 HANDLESCOPE(isolate); | 1519 HANDLESCOPE(isolate); |
| 1519 | 1520 |
| 1520 // All registers have been saved below last-fp. | 1521 // All registers have been saved below last-fp as if they were locals. |
| 1521 // Note that the deopt stub is not allowed to save any other values (pc | 1522 const uword last_fp = saved_registers_address |
| 1522 // marker, pool pointer, alignment, etc...) below last-fp. | 1523 + (kNumberOfCpuRegisters * kWordSize) |
| 1523 const uword last_fp = saved_registers_address + | 1524 + (kNumberOfFpuRegisters * kFpuRegisterSize) |
| 1524 kNumberOfCpuRegisters * kWordSize + | 1525 - ((kFirstLocalSlotFromFp + 1) * kWordSize); |
| 1525 kNumberOfFpuRegisters * kFpuRegisterSize; | |
| 1526 CopySavedRegisters(saved_registers_address); | 1526 CopySavedRegisters(saved_registers_address); |
| 1527 | 1527 |
| 1528 // Get optimized code and frame that need to be deoptimized. | 1528 // Get optimized code and frame that need to be deoptimized. |
| 1529 DartFrameIterator iterator(last_fp); | 1529 DartFrameIterator iterator(last_fp); |
| 1530 StackFrame* caller_frame = iterator.NextFrame(); | 1530 StackFrame* caller_frame = iterator.NextFrame(); |
| 1531 ASSERT(caller_frame != NULL); | 1531 ASSERT(caller_frame != NULL); |
| 1532 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | 1532 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
| 1533 ASSERT(optimized_code.is_optimized()); | 1533 ASSERT(optimized_code.is_optimized()); |
| 1534 | 1534 |
| 1535 intptr_t deopt_reason = kDeoptUnknown; | 1535 intptr_t deopt_reason = kDeoptUnknown; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1548 function.ToFullyQualifiedCString(), | 1548 function.ToFullyQualifiedCString(), |
| 1549 function.deoptimization_counter()); | 1549 function.deoptimization_counter()); |
| 1550 } | 1550 } |
| 1551 | 1551 |
| 1552 // Compute the stack size of the unoptimized frame. For functions with | 1552 // Compute the stack size of the unoptimized frame. For functions with |
| 1553 // optional arguments the deoptimization info does not describe the | 1553 // optional arguments the deoptimization info does not describe the |
| 1554 // incoming arguments. | 1554 // incoming arguments. |
| 1555 const Function& function = Function::Handle(optimized_code.function()); | 1555 const Function& function = Function::Handle(optimized_code.function()); |
| 1556 const intptr_t num_args = | 1556 const intptr_t num_args = |
| 1557 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); | 1557 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); |
| 1558 intptr_t unoptimized_stack_size = | 1558 const intptr_t unoptimized_stack_size = |
| 1559 + deopt_info.FrameSize() | 1559 + deopt_info.FrameSize() |
| 1560 - kDartFrameFixedSize |
| 1560 - num_args | 1561 - num_args |
| 1561 - kParamEndSlotFromFp | 1562 - kParamEndSlotFromFp |
| 1562 - 1; // For fp. | 1563 - 1; // For fp. |
| 1563 return unoptimized_stack_size * kWordSize; | 1564 return unoptimized_stack_size * kWordSize; // Stack size (FP - SP) in bytes. |
| 1564 } | 1565 } |
| 1565 END_LEAF_RUNTIME_ENTRY | 1566 END_LEAF_RUNTIME_ENTRY |
| 1566 | 1567 |
| 1567 | 1568 |
| 1568 static intptr_t DeoptimizeWithDeoptInfo(const Code& code, | 1569 static void DeoptimizeWithDeoptInfo(const Code& code, |
| 1569 const DeoptInfo& deopt_info, | 1570 const DeoptInfo& deopt_info, |
| 1570 const StackFrame& caller_frame, | 1571 const StackFrame& caller_frame, |
| 1571 intptr_t deopt_reason) { | 1572 intptr_t deopt_reason) { |
| 1572 const intptr_t len = deopt_info.TranslationLength(); | 1573 const intptr_t len = deopt_info.TranslationLength(); |
| 1573 GrowableArray<DeoptInstr*> deopt_instructions(len); | 1574 GrowableArray<DeoptInstr*> deopt_instructions(len); |
| 1574 const Array& deopt_table = Array::Handle(code.deopt_info_array()); | 1575 const Array& deopt_table = Array::Handle(code.deopt_info_array()); |
| 1575 ASSERT(!deopt_table.IsNull()); | 1576 ASSERT(!deopt_table.IsNull()); |
| 1576 deopt_info.ToInstructions(deopt_table, &deopt_instructions); | 1577 deopt_info.ToInstructions(deopt_table, &deopt_instructions); |
| 1577 | 1578 |
| 1578 intptr_t* start = reinterpret_cast<intptr_t*>( | 1579 intptr_t* start = reinterpret_cast<intptr_t*>( |
| 1579 caller_frame.sp() + (kSavedPcSlotFromSp * kWordSize)); | 1580 caller_frame.sp() - (kDartFrameFixedSize * kWordSize)); |
| 1580 const Function& function = Function::Handle(code.function()); | 1581 const Function& function = Function::Handle(code.function()); |
| 1581 const intptr_t num_args = | 1582 const intptr_t num_args = |
| 1582 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); | 1583 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); |
| 1583 const intptr_t to_frame_size = | 1584 const intptr_t to_frame_size = |
| 1584 - kSavedPcSlotFromSp // Deoptimized function's return address. | 1585 + kDartFrameFixedSize // For saved values below sp. |
| 1585 + (caller_frame.fp() - caller_frame.sp()) / kWordSize | 1586 + (caller_frame.fp() - caller_frame.sp()) / kWordSize |
| 1586 + 1 // For fp. | 1587 + 1 // For fp. |
| 1587 + kParamEndSlotFromFp | 1588 + kParamEndSlotFromFp |
| 1588 + num_args; | 1589 + num_args; |
| 1589 DeoptimizationContext deopt_context(start, | 1590 DeoptimizationContext deopt_context(start, |
| 1590 to_frame_size, | 1591 to_frame_size, |
| 1591 Array::Handle(code.object_table()), | 1592 Array::Handle(code.object_table()), |
| 1592 num_args, | 1593 num_args, |
| 1593 static_cast<DeoptReasonId>(deopt_reason)); | 1594 static_cast<DeoptReasonId>(deopt_reason)); |
| 1594 const intptr_t frame_size = deopt_info.FrameSize(); | 1595 const intptr_t frame_size = deopt_info.FrameSize(); |
| 1595 | 1596 |
| 1596 // All kMaterializeObject instructions are emitted before the instructions | 1597 // All kMaterializeObject instructions are emitted before the instructions |
| 1597 // that describe stack frames. Skip them and defer materialization of | 1598 // that describe stack frames. Skip them and defer materialization of |
| 1598 // objects until the frame is fully reconstructed and it is safe to perform | 1599 // objects until the frame is fully reconstructed and it is safe to perform |
| 1599 // GC. | 1600 // GC. |
| 1600 // Arguments (class of the instance to allocate and field-value pairs) are | 1601 // Arguments (class of the instance to allocate and field-value pairs) are |
| 1601 // described as part of the expression stack for the bottom-most deoptimized | 1602 // described as part of the expression stack for the bottom-most deoptimized |
| 1602 // frame. They will be used during materialization and removed from the stack | 1603 // frame. They will be used during materialization and removed from the stack |
| 1603 // right before control switches to the unoptimized code. | 1604 // right before control switches to the unoptimized code. |
| 1604 const intptr_t num_materializations = len - frame_size; | 1605 const intptr_t num_materializations = len - frame_size; |
| 1605 Isolate::Current()->PrepareForDeferredMaterialization(num_materializations); | 1606 Isolate::Current()->PrepareForDeferredMaterialization(num_materializations); |
| 1606 for (intptr_t from_index = 0, to_index = 1; | 1607 for (intptr_t from_index = 0, to_index = kDartFrameFixedSize; |
| 1607 from_index < num_materializations; | 1608 from_index < num_materializations; |
| 1608 from_index++) { | 1609 from_index++) { |
| 1609 const intptr_t field_count = | 1610 const intptr_t field_count = |
| 1610 DeoptInstr::GetFieldCount(deopt_instructions[from_index]); | 1611 DeoptInstr::GetFieldCount(deopt_instructions[from_index]); |
| 1611 intptr_t* args = deopt_context.GetToFrameAddressAt(to_index); | 1612 intptr_t* args = deopt_context.GetToFrameAddressAt(to_index); |
| 1612 DeferredObject* obj = new DeferredObject(field_count, args); | 1613 DeferredObject* obj = new DeferredObject(field_count, args); |
| 1613 Isolate::Current()->SetDeferredObjectAt(from_index, obj); | 1614 Isolate::Current()->SetDeferredObjectAt(from_index, obj); |
| 1614 to_index += obj->ArgumentCount(); | 1615 to_index += obj->ArgumentCount(); |
| 1615 } | 1616 } |
| 1616 | 1617 |
| 1617 // Populate stack frames. | 1618 // Populate stack frames. |
| 1618 for (intptr_t to_index = frame_size - 1, from_index = len - 1; | 1619 for (intptr_t to_index = frame_size - 1, from_index = len - 1; |
| 1619 to_index >= 0; | 1620 to_index >= 0; |
| 1620 to_index--, from_index--) { | 1621 to_index--, from_index--) { |
| 1621 intptr_t* to_addr = deopt_context.GetToFrameAddressAt(to_index); | 1622 intptr_t* to_addr = deopt_context.GetToFrameAddressAt(to_index); |
| 1622 deopt_instructions[from_index]->Execute(&deopt_context, to_addr); | 1623 deopt_instructions[from_index]->Execute(&deopt_context, to_addr); |
| 1623 } | 1624 } |
| 1624 | 1625 |
| 1625 if (FLAG_trace_deoptimization_verbose) { | 1626 if (FLAG_trace_deoptimization_verbose) { |
| 1626 for (intptr_t i = 0; i < frame_size; i++) { | 1627 for (intptr_t i = 0; i < frame_size; i++) { |
| 1627 OS::PrintErr("*%"Pd". [%"Px"] %#014"Px" [%s]\n", | 1628 OS::PrintErr("*%"Pd". [%"Px"] %#014"Px" [%s]\n", |
| 1628 i, | 1629 i, |
| 1629 reinterpret_cast<uword>(&start[i]), | 1630 reinterpret_cast<uword>(&start[i]), |
| 1630 start[i], | 1631 start[i], |
| 1631 deopt_instructions[i + (len - frame_size)]->ToCString()); | 1632 deopt_instructions[i + (len - frame_size)]->ToCString()); |
| 1632 } | 1633 } |
| 1633 } | 1634 } |
| 1634 return deopt_context.GetCallerFp(); | |
| 1635 } | 1635 } |
| 1636 | 1636 |
| 1637 | 1637 |
| 1638 // The stack has been adjusted to fit all values for unoptimized frame. | 1638 // The stack has been adjusted to fit all values for unoptimized frame. |
| 1639 // Fill the unoptimized frame. | 1639 // Fill the unoptimized frame. |
| 1640 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeFillFrame, uword last_fp) { | 1640 DEFINE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp) { |
| 1641 Isolate* isolate = Isolate::Current(); | 1641 Isolate* isolate = Isolate::Current(); |
| 1642 StackZone zone(isolate); | 1642 StackZone zone(isolate); |
| 1643 HANDLESCOPE(isolate); | 1643 HANDLESCOPE(isolate); |
| 1644 | 1644 |
| 1645 DartFrameIterator iterator(last_fp); | 1645 DartFrameIterator iterator(last_fp); |
| 1646 StackFrame* caller_frame = iterator.NextFrame(); | 1646 StackFrame* caller_frame = iterator.NextFrame(); |
| 1647 ASSERT(caller_frame != NULL); | 1647 ASSERT(caller_frame != NULL); |
| 1648 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | 1648 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
| 1649 const Function& function = Function::Handle(optimized_code.function()); | 1649 const Function& function = Function::Handle(optimized_code.function()); |
| 1650 ASSERT(!function.IsNull()); | 1650 ASSERT(!function.IsNull()); |
| 1651 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); | 1651 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); |
| 1652 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); | 1652 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); |
| 1653 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); | 1653 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); |
| 1654 | 1654 |
| 1655 intptr_t* frame_copy = isolate->deopt_frame_copy(); | 1655 intptr_t* frame_copy = isolate->deopt_frame_copy(); |
| 1656 intptr_t* cpu_registers_copy = isolate->deopt_cpu_registers_copy(); | 1656 intptr_t* cpu_registers_copy = isolate->deopt_cpu_registers_copy(); |
| 1657 fpu_register_t* fpu_registers_copy = isolate->deopt_fpu_registers_copy(); | 1657 fpu_register_t* fpu_registers_copy = isolate->deopt_fpu_registers_copy(); |
| 1658 | 1658 |
| 1659 intptr_t deopt_reason = kDeoptUnknown; | 1659 intptr_t deopt_reason = kDeoptUnknown; |
| 1660 const DeoptInfo& deopt_info = DeoptInfo::Handle( | 1660 const DeoptInfo& deopt_info = DeoptInfo::Handle( |
| 1661 optimized_code.GetDeoptInfoAtPc(caller_frame->pc(), &deopt_reason)); | 1661 optimized_code.GetDeoptInfoAtPc(caller_frame->pc(), &deopt_reason)); |
| 1662 ASSERT(!deopt_info.IsNull()); | 1662 ASSERT(!deopt_info.IsNull()); |
| 1663 | 1663 |
| 1664 const intptr_t caller_fp = DeoptimizeWithDeoptInfo(optimized_code, | 1664 DeoptimizeWithDeoptInfo(optimized_code, |
| 1665 deopt_info, | 1665 deopt_info, |
| 1666 *caller_frame, | 1666 *caller_frame, |
| 1667 deopt_reason); | 1667 deopt_reason); |
| 1668 | 1668 |
| 1669 isolate->SetDeoptFrameCopy(NULL, 0); | 1669 isolate->SetDeoptFrameCopy(NULL, 0); |
| 1670 isolate->set_deopt_cpu_registers_copy(NULL); | 1670 isolate->set_deopt_cpu_registers_copy(NULL); |
| 1671 isolate->set_deopt_fpu_registers_copy(NULL); | 1671 isolate->set_deopt_fpu_registers_copy(NULL); |
| 1672 delete[] frame_copy; | 1672 delete[] frame_copy; |
| 1673 delete[] cpu_registers_copy; | 1673 delete[] cpu_registers_copy; |
| 1674 delete[] fpu_registers_copy; | 1674 delete[] fpu_registers_copy; |
| 1675 | |
| 1676 return caller_fp; | |
| 1677 } | 1675 } |
| 1678 END_LEAF_RUNTIME_ENTRY | 1676 END_LEAF_RUNTIME_ENTRY |
| 1679 | 1677 |
| 1680 | 1678 |
| 1681 // This is the last step in the deoptimization, GC can occur. | 1679 // This is the last step in the deoptimization, GC can occur. |
| 1682 // Returns number of bytes to remove from the expression stack of the | 1680 // Returns number of bytes to remove from the expression stack of the |
| 1683 // bottom-most deoptimized frame. Those arguments were artificially injected | 1681 // bottom-most deoptimized frame. Those arguments were artificially injected |
| 1684 // under return address to keep them discoverable by GC that can occur during | 1682 // under return address to keep them discoverable by GC that can occur during |
| 1685 // materialization phase. | 1683 // materialization phase. |
| 1686 DEFINE_RUNTIME_ENTRY(DeoptimizeMaterialize, 0) { | 1684 DEFINE_RUNTIME_ENTRY(DeoptimizeMaterialize, 0) { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1759 // Arg1: Value that is being stored. | 1757 // Arg1: Value that is being stored. |
| 1760 DEFINE_RUNTIME_ENTRY(UpdateFieldCid, 2) { | 1758 DEFINE_RUNTIME_ENTRY(UpdateFieldCid, 2) { |
| 1761 ASSERT(arguments.ArgCount() == kUpdateFieldCidRuntimeEntry.argument_count()); | 1759 ASSERT(arguments.ArgCount() == kUpdateFieldCidRuntimeEntry.argument_count()); |
| 1762 const Field& field = Field::CheckedHandle(arguments.ArgAt(0)); | 1760 const Field& field = Field::CheckedHandle(arguments.ArgAt(0)); |
| 1763 const Object& value = Object::Handle(arguments.ArgAt(1)); | 1761 const Object& value = Object::Handle(arguments.ArgAt(1)); |
| 1764 | 1762 |
| 1765 field.UpdateCid(Class::Handle(value.clazz()).id()); | 1763 field.UpdateCid(Class::Handle(value.clazz()).id()); |
| 1766 } | 1764 } |
| 1767 | 1765 |
| 1768 } // namespace dart | 1766 } // namespace dart |
| OLD | NEW |