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 1502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1513 ASSERT(cpu_registers_copy != NULL); | 1513 ASSERT(cpu_registers_copy != NULL); |
1514 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) { | 1514 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) { |
1515 cpu_registers_copy[i] = | 1515 cpu_registers_copy[i] = |
1516 *reinterpret_cast<intptr_t*>(saved_registers_address); | 1516 *reinterpret_cast<intptr_t*>(saved_registers_address); |
1517 saved_registers_address += kWordSize; | 1517 saved_registers_address += kWordSize; |
1518 } | 1518 } |
1519 *cpu_registers = cpu_registers_copy; | 1519 *cpu_registers = cpu_registers_copy; |
1520 } | 1520 } |
1521 | 1521 |
1522 | 1522 |
1523 // Copy optimized frame. The first incoming argument is stored at the | |
1524 // last entry in the copied frame buffer. | |
1525 static void CopyFrame(const Code& optimized_code, | |
1526 const StackFrame& frame, | |
1527 intptr_t** frame_start, | |
1528 intptr_t* frame_size) { | |
1529 const Function& function = Function::Handle(optimized_code.function()); | |
1530 // Do not copy incoming arguments if there are optional arguments (they | |
1531 // are copied into local space at method entry). | |
1532 const intptr_t num_args = | |
1533 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); | |
1534 // The fixed size section of the (fake) Dart frame called via a stub by the | |
1535 // optimized function contains FP, PP (ARM and MIPS only), PC-marker and | |
1536 // return-address. This section is copied as well, so that its contained | |
1537 // values can be updated before returning to the deoptimized function. | |
1538 const intptr_t frame_copy_size = | |
1539 + kDartFrameFixedSize // For saved values below sp. | |
1540 + ((frame.fp() - frame.sp()) / kWordSize) // For frame size incl. sp. | |
1541 + 1 // For fp. | |
1542 + kParamEndSlotFromFp // For saved values above fp. | |
1543 + num_args; // For arguments. | |
1544 intptr_t* frame_copy = new intptr_t[frame_copy_size]; | |
1545 ASSERT(frame_copy != NULL); | |
1546 intptr_t* start = reinterpret_cast<intptr_t*>( | |
1547 frame.sp() - (kDartFrameFixedSize * kWordSize)); | |
1548 for (intptr_t i = 0; i < frame_copy_size; i++) { | |
1549 frame_copy[i] = *(start + i); | |
1550 } | |
1551 *frame_start = frame_copy; | |
1552 *frame_size = frame_copy_size; | |
1553 } | |
1554 | |
1555 | |
1556 // Copies saved registers and caller's frame into temporary buffers. | 1523 // Copies saved registers and caller's frame into temporary buffers. |
1557 // Returns the stack size of unoptimized frame. | 1524 // Returns the stack size of unoptimized frame. |
1558 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, | 1525 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
1559 1, uword saved_registers_address) { | 1526 1, uword saved_registers_address) { |
1560 Isolate* isolate = Isolate::Current(); | 1527 Isolate* isolate = Isolate::Current(); |
1561 StackZone zone(isolate); | 1528 StackZone zone(isolate); |
1562 HANDLESCOPE(isolate); | 1529 HANDLESCOPE(isolate); |
1563 | 1530 |
1564 // All registers have been saved below last-fp as if they were locals. | 1531 // All registers have been saved below last-fp as if they were locals. |
1565 const uword last_fp = saved_registers_address | 1532 const uword last_fp = saved_registers_address |
1566 + (kNumberOfCpuRegisters * kWordSize) | 1533 + (kNumberOfCpuRegisters * kWordSize) |
1567 + (kNumberOfFpuRegisters * kFpuRegisterSize) | 1534 + (kNumberOfFpuRegisters * kFpuRegisterSize) |
1568 - ((kFirstLocalSlotFromFp + 1) * kWordSize); | 1535 - ((kFirstLocalSlotFromFp + 1) * kWordSize); |
1569 | 1536 |
1570 // Get optimized code and frame that need to be deoptimized. | 1537 // Get optimized code and frame that need to be deoptimized. |
1571 DartFrameIterator iterator(last_fp); | 1538 DartFrameIterator iterator(last_fp); |
1572 StackFrame* caller_frame = iterator.NextFrame(); | 1539 StackFrame* caller_frame = iterator.NextFrame(); |
1573 ASSERT(caller_frame != NULL); | 1540 ASSERT(caller_frame != NULL); |
1574 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | 1541 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
1575 ASSERT(optimized_code.is_optimized()); | 1542 ASSERT(optimized_code.is_optimized()); |
1576 | 1543 |
1577 intptr_t deopt_reason = kDeoptUnknown; | 1544 // Copy the saved registers from the stack. |
1578 const DeoptInfo& deopt_info = DeoptInfo::Handle( | 1545 fpu_register_t* fpu_registers; |
1579 optimized_code.GetDeoptInfoAtPc(caller_frame->pc(), &deopt_reason)); | 1546 intptr_t* cpu_registers; |
1580 ASSERT(!deopt_info.IsNull()); | 1547 CopySavedRegisters(saved_registers_address, &fpu_registers, &cpu_registers); |
1581 | 1548 |
1582 // Create the DeoptContext for this deoptimization. Store in isolate. | 1549 // Create the DeoptContext. |
1583 const Function& function = Function::Handle(optimized_code.function()); | 1550 DeoptContext* deopt_context = |
1584 const intptr_t num_args = | 1551 new DeoptContext(caller_frame, optimized_code, |
1585 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); | 1552 DeoptContext::kDestIsOriginalFrame, |
1586 DeoptContext* deopt_context = new DeoptContext( | 1553 fpu_registers, cpu_registers); |
1587 Array::Handle(optimized_code.object_table()), | |
1588 num_args, | |
1589 static_cast<DeoptReasonId>(deopt_reason)); | |
1590 isolate->set_deopt_context(deopt_context); | 1554 isolate->set_deopt_context(deopt_context); |
1591 | 1555 |
1592 // Copy the saved registers and the source frame. | 1556 // Stack size (FP - SP) in bytes. |
1593 fpu_register_t* fpu_registers; | 1557 return deopt_context->DestStackAdjustment() * kWordSize; |
1594 intptr_t* cpu_registers; | |
1595 intptr_t* frame_start; | |
1596 intptr_t frame_size; | |
1597 CopySavedRegisters(saved_registers_address, &fpu_registers, &cpu_registers); | |
1598 CopyFrame(optimized_code, *caller_frame, &frame_start, &frame_size); | |
1599 deopt_context->SetSourceArgs(frame_start, frame_size, | |
1600 fpu_registers, cpu_registers, | |
1601 true); // true = source frame is a copy. | |
1602 | |
1603 if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) { | |
1604 OS::PrintErr( | |
1605 "Deoptimizing (reason %" Pd " '%s') at pc %#" Px " '%s' (count %d)\n", | |
1606 deopt_reason, | |
1607 DeoptReasonToText(deopt_reason), | |
1608 caller_frame->pc(), | |
1609 function.ToFullyQualifiedCString(), | |
1610 function.deoptimization_counter()); | |
1611 } | |
1612 | |
1613 // Compute the stack size of the unoptimized frame. For functions with | |
1614 // optional arguments the deoptimization info does not describe the | |
1615 // incoming arguments. | |
1616 const intptr_t unoptimized_stack_size = | |
1617 + deopt_info.FrameSize() | |
1618 - kDartFrameFixedSize | |
1619 - num_args | |
1620 - kParamEndSlotFromFp | |
1621 - 1; // For fp. | |
1622 return unoptimized_stack_size * kWordSize; // Stack size (FP - SP) in bytes. | |
1623 } | 1558 } |
1624 END_LEAF_RUNTIME_ENTRY | 1559 END_LEAF_RUNTIME_ENTRY |
1625 | 1560 |
1626 | 1561 |
1627 static void DeoptimizeWithDeoptInfo(DeoptContext* deopt_context, | |
1628 const Code& code, | |
1629 const DeoptInfo& deopt_info, | |
1630 const StackFrame& caller_frame) { | |
1631 const intptr_t len = deopt_info.TranslationLength(); | |
1632 GrowableArray<DeoptInstr*> deopt_instructions(len); | |
1633 const Array& deopt_table = Array::Handle(code.deopt_info_array()); | |
1634 ASSERT(!deopt_table.IsNull()); | |
1635 deopt_info.ToInstructions(deopt_table, &deopt_instructions); | |
1636 | |
1637 intptr_t* start = reinterpret_cast<intptr_t*>( | |
1638 caller_frame.sp() - (kDartFrameFixedSize * kWordSize)); | |
1639 const Function& function = Function::Handle(code.function()); | |
1640 const intptr_t num_args = | |
1641 function.HasOptionalParameters() ? 0 : function.num_fixed_parameters(); | |
1642 const intptr_t to_frame_size = | |
1643 + kDartFrameFixedSize // For saved values below sp. | |
1644 + (caller_frame.fp() - caller_frame.sp()) / kWordSize | |
1645 + 1 // For fp. | |
1646 + kParamEndSlotFromFp | |
1647 + num_args; | |
1648 | |
1649 deopt_context->SetDestArgs(start, to_frame_size); | |
1650 | |
1651 const intptr_t frame_size = deopt_info.FrameSize(); | |
1652 | |
1653 // All kMaterializeObject instructions are emitted before the instructions | |
1654 // that describe stack frames. Skip them and defer materialization of | |
1655 // objects until the frame is fully reconstructed and it is safe to perform | |
1656 // GC. | |
1657 // Arguments (class of the instance to allocate and field-value pairs) are | |
1658 // described as part of the expression stack for the bottom-most deoptimized | |
1659 // frame. They will be used during materialization and removed from the stack | |
1660 // right before control switches to the unoptimized code. | |
1661 const intptr_t num_materializations = len - frame_size; | |
1662 deopt_context->PrepareForDeferredMaterialization(num_materializations); | |
1663 for (intptr_t from_index = 0, to_index = kDartFrameFixedSize; | |
1664 from_index < num_materializations; | |
1665 from_index++) { | |
1666 const intptr_t field_count = | |
1667 DeoptInstr::GetFieldCount(deopt_instructions[from_index]); | |
1668 intptr_t* args = deopt_context->GetDestFrameAddressAt(to_index); | |
1669 DeferredObject* obj = new DeferredObject(field_count, args); | |
1670 deopt_context->SetDeferredObjectAt(from_index, obj); | |
1671 to_index += obj->ArgumentCount(); | |
1672 } | |
1673 | |
1674 // Populate stack frames. | |
1675 for (intptr_t to_index = frame_size - 1, from_index = len - 1; | |
1676 to_index >= 0; | |
1677 to_index--, from_index--) { | |
1678 intptr_t* to_addr = deopt_context->GetDestFrameAddressAt(to_index); | |
1679 deopt_instructions[from_index]->Execute(deopt_context, to_addr); | |
1680 } | |
1681 | |
1682 if (FLAG_trace_deoptimization_verbose) { | |
1683 for (intptr_t i = 0; i < frame_size; i++) { | |
1684 OS::PrintErr("*%" Pd ". [%" Px "] %#014" Px " [%s]\n", | |
1685 i, | |
1686 reinterpret_cast<uword>(&start[i]), | |
1687 start[i], | |
1688 deopt_instructions[i + (len - frame_size)]->ToCString()); | |
1689 } | |
1690 } | |
1691 } | |
1692 | |
1693 | |
1694 // The stack has been adjusted to fit all values for unoptimized frame. | 1562 // The stack has been adjusted to fit all values for unoptimized frame. |
1695 // Fill the unoptimized frame. | 1563 // Fill the unoptimized frame. |
1696 DEFINE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, 1, uword last_fp) { | 1564 DEFINE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, 1, uword last_fp) { |
1697 Isolate* isolate = Isolate::Current(); | 1565 Isolate* isolate = Isolate::Current(); |
1698 StackZone zone(isolate); | 1566 StackZone zone(isolate); |
1699 HANDLESCOPE(isolate); | 1567 HANDLESCOPE(isolate); |
1700 | 1568 |
| 1569 DeoptContext* deopt_context = isolate->deopt_context(); |
1701 DartFrameIterator iterator(last_fp); | 1570 DartFrameIterator iterator(last_fp); |
1702 StackFrame* caller_frame = iterator.NextFrame(); | 1571 StackFrame* caller_frame = iterator.NextFrame(); |
1703 ASSERT(caller_frame != NULL); | 1572 ASSERT(caller_frame != NULL); |
1704 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | |
1705 const Function& function = Function::Handle(optimized_code.function()); | |
1706 ASSERT(!function.IsNull()); | |
1707 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); | |
1708 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); | |
1709 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); | |
1710 | 1573 |
1711 intptr_t deopt_reason = kDeoptUnknown; | 1574 #if defined(DEBUG) |
1712 const DeoptInfo& deopt_info = DeoptInfo::Handle( | 1575 { |
1713 optimized_code.GetDeoptInfoAtPc(caller_frame->pc(), &deopt_reason)); | 1576 // The code from the deopt_context. |
1714 ASSERT(!deopt_info.IsNull()); | 1577 const Code& code = Code::Handle(deopt_context->code()); |
1715 | 1578 |
1716 DeoptContext* deopt_context = isolate->deopt_context(); | 1579 // The code from our frame. |
1717 DeoptimizeWithDeoptInfo(deopt_context, | 1580 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
1718 optimized_code, | 1581 const Function& function = Function::Handle(optimized_code.function()); |
1719 deopt_info, | 1582 ASSERT(!function.IsNull()); |
1720 *caller_frame); | 1583 |
| 1584 // The code will be the same as before. |
| 1585 ASSERT(code.raw() == optimized_code.raw()); |
| 1586 |
| 1587 // Some sanity checking of the optimized/unoptimized code. |
| 1588 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); |
| 1589 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); |
| 1590 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); |
| 1591 } |
| 1592 #endif |
| 1593 |
| 1594 // TODO(turnidge): Compute the start of the dest frame in the |
| 1595 // DeoptContext instead of passing it in here. |
| 1596 intptr_t* start = reinterpret_cast<intptr_t*>( |
| 1597 caller_frame->sp() - (kDartFrameFixedSize * kWordSize)); |
| 1598 deopt_context->set_dest_frame(start); |
| 1599 deopt_context->FillDestFrame(); |
1721 } | 1600 } |
1722 END_LEAF_RUNTIME_ENTRY | 1601 END_LEAF_RUNTIME_ENTRY |
1723 | 1602 |
1724 | 1603 |
1725 // This is the last step in the deoptimization, GC can occur. | 1604 // This is the last step in the deoptimization, GC can occur. |
1726 // Returns number of bytes to remove from the expression stack of the | 1605 // Returns number of bytes to remove from the expression stack of the |
1727 // bottom-most deoptimized frame. Those arguments were artificially injected | 1606 // bottom-most deoptimized frame. Those arguments were artificially injected |
1728 // under return address to keep them discoverable by GC that can occur during | 1607 // under return address to keep them discoverable by GC that can occur during |
1729 // materialization phase. | 1608 // materialization phase. |
1730 DEFINE_RUNTIME_ENTRY(DeoptimizeMaterialize, 0) { | 1609 DEFINE_RUNTIME_ENTRY(DeoptimizeMaterialize, 0) { |
1731 DeoptContext* deopt_context = isolate->deopt_context(); | 1610 DeoptContext* deopt_context = isolate->deopt_context(); |
1732 | |
1733 intptr_t deopt_arg_count = deopt_context->MaterializeDeferredObjects(); | 1611 intptr_t deopt_arg_count = deopt_context->MaterializeDeferredObjects(); |
1734 isolate->set_deopt_context(NULL); | 1612 isolate->set_deopt_context(NULL); |
1735 delete deopt_context; | 1613 delete deopt_context; |
1736 | 1614 |
1737 // Return value tells deoptimization stub to remove the given number of bytes | 1615 // Return value tells deoptimization stub to remove the given number of bytes |
1738 // from the stack. | 1616 // from the stack. |
1739 arguments.SetReturn(Smi::Handle(Smi::New(deopt_arg_count * kWordSize))); | 1617 arguments.SetReturn(Smi::Handle(Smi::New(deopt_arg_count * kWordSize))); |
1740 | |
1741 // Since this is the only step where GC can occur during deoptimization, | |
1742 // use it to report the source line where deoptimization occured. | |
1743 if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) { | |
1744 DartFrameIterator iterator; | |
1745 StackFrame* top_frame = iterator.NextFrame(); | |
1746 ASSERT(top_frame != NULL); | |
1747 const Code& code = Code::Handle(top_frame->LookupDartCode()); | |
1748 const Function& top_function = Function::Handle(code.function()); | |
1749 const Script& script = Script::Handle(top_function.script()); | |
1750 const intptr_t token_pos = code.GetTokenIndexOfPC(top_frame->pc()); | |
1751 intptr_t line, column; | |
1752 script.GetTokenLocation(token_pos, &line, &column); | |
1753 String& line_string = String::Handle(script.GetLine(line)); | |
1754 OS::PrintErr(" Function: %s\n", top_function.ToFullyQualifiedCString()); | |
1755 OS::PrintErr(" Line %" Pd ": '%s'\n", line, line_string.ToCString()); | |
1756 OS::PrintErr(" Deopt args: %" Pd "\n", deopt_arg_count); | |
1757 } | |
1758 } | 1618 } |
1759 | 1619 |
1760 | 1620 |
1761 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, | 1621 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, |
1762 BigintCompare, | 1622 BigintCompare, |
1763 2, | 1623 2, |
1764 RawBigint* left, | 1624 RawBigint* left, |
1765 RawBigint* right) { | 1625 RawBigint* right) { |
1766 Isolate* isolate = Isolate::Current(); | 1626 Isolate* isolate = Isolate::Current(); |
1767 StackZone zone(isolate); | 1627 StackZone zone(isolate); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1825 field.UpdateCid(cid); | 1685 field.UpdateCid(cid); |
1826 intptr_t list_length = Field::kNoFixedLength; | 1686 intptr_t list_length = Field::kNoFixedLength; |
1827 if ((field.guarded_cid() != kDynamicCid) && | 1687 if ((field.guarded_cid() != kDynamicCid) && |
1828 field.is_final() && RawObject::IsBuiltinListClassId(cid)) { | 1688 field.is_final() && RawObject::IsBuiltinListClassId(cid)) { |
1829 list_length = GetListLength(value); | 1689 list_length = GetListLength(value); |
1830 } | 1690 } |
1831 field.UpdateLength(list_length); | 1691 field.UpdateLength(list_length); |
1832 } | 1692 } |
1833 | 1693 |
1834 } // namespace dart | 1694 } // namespace dart |
OLD | NEW |