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/code_patcher.h" | 9 #include "vm/code_patcher.h" |
10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 if (!target_function.HasCode()) { | 667 if (!target_function.HasCode()) { |
668 const Error& error = | 668 const Error& error = |
669 Error::Handle(Compiler::CompileFunction(thread, target_function)); | 669 Error::Handle(Compiler::CompileFunction(thread, target_function)); |
670 if (!error.IsNull()) { | 670 if (!error.IsNull()) { |
671 Exceptions::PropagateError(error); | 671 Exceptions::PropagateError(error); |
672 } | 672 } |
673 } | 673 } |
674 const Code& target_code = Code::Handle(target_function.CurrentCode()); | 674 const Code& target_code = Code::Handle(target_function.CurrentCode()); |
675 // Before patching verify that we are not repeatedly patching to the same | 675 // Before patching verify that we are not repeatedly patching to the same |
676 // target. | 676 // target. |
677 ASSERT(target_code.raw() != | 677 ASSERT(target_code.EntryPoint() != |
678 CodePatcher::GetStaticCallTargetAt(caller_frame->pc(), caller_code)); | 678 CodePatcher::GetStaticCallTargetAt(caller_frame->pc(), caller_code)); |
679 CodePatcher::PatchStaticCallAt(caller_frame->pc(), | 679 const Instructions& instrs = |
680 caller_code, | 680 Instructions::Handle(caller_code.instructions()); |
681 target_code); | 681 { |
682 caller_code.SetStaticCallTargetCodeAt(caller_frame->pc(), target_code); | 682 WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size()); |
| 683 CodePatcher::PatchStaticCallAt(caller_frame->pc(), caller_code, |
| 684 target_code.EntryPoint()); |
| 685 caller_code.SetStaticCallTargetCodeAt(caller_frame->pc(), target_code); |
| 686 } |
683 if (FLAG_trace_patching) { | 687 if (FLAG_trace_patching) { |
684 OS::PrintErr("PatchStaticCall: patching caller pc %#" Px "" | 688 OS::PrintErr("PatchStaticCall: patching caller pc %#" Px "" |
685 " to '%s' new entry point %#" Px " (%s)\n", | 689 " to '%s' new entry point %#" Px " (%s)\n", |
686 caller_frame->pc(), | 690 caller_frame->pc(), |
687 target_function.ToFullyQualifiedCString(), | 691 target_function.ToFullyQualifiedCString(), |
688 target_code.EntryPoint(), | 692 target_code.EntryPoint(), |
689 target_code.is_optimized() ? "optimized" : "unoptimized"); | 693 target_code.is_optimized() ? "optimized" : "unoptimized"); |
690 } | 694 } |
691 arguments.SetReturn(target_code); | 695 arguments.SetReturn(target_code); |
692 } | 696 } |
693 | 697 |
694 | 698 |
695 // Result of an invoke may be an unhandled exception, in which case we | 699 // Result of an invoke may be an unhandled exception, in which case we |
696 // rethrow it. | 700 // rethrow it. |
697 static void CheckResultError(const Object& result) { | 701 static void CheckResultError(const Object& result) { |
698 if (result.IsError()) { | 702 if (result.IsError()) { |
699 Exceptions::PropagateError(Error::Cast(result)); | 703 Exceptions::PropagateError(Error::Cast(result)); |
700 } | 704 } |
701 } | 705 } |
702 | 706 |
703 | 707 |
704 // Gets called from debug stub when code reaches a breakpoint | 708 // Gets called from debug stub when code reaches a breakpoint |
705 // set on a runtime stub call. | 709 // set on a runtime stub call. |
706 DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) { | 710 DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) { |
707 DartFrameIterator iterator; | 711 DartFrameIterator iterator; |
708 StackFrame* caller_frame = iterator.NextFrame(); | 712 StackFrame* caller_frame = iterator.NextFrame(); |
709 ASSERT(caller_frame != NULL); | 713 ASSERT(caller_frame != NULL); |
710 const Code& orig_stub = Code::Handle( | 714 uword orig_stub = |
711 isolate->debugger()->GetPatchedStubAddress(caller_frame->pc())); | 715 isolate->debugger()->GetPatchedStubAddress(caller_frame->pc()); |
712 isolate->debugger()->SignalBpReached(); | 716 isolate->debugger()->SignalBpReached(); |
713 arguments.SetReturn(orig_stub); | 717 ASSERT((orig_stub & kSmiTagMask) == kSmiTag); |
| 718 arguments.SetReturn(Smi::Handle(reinterpret_cast<RawSmi*>(orig_stub))); |
714 } | 719 } |
715 | 720 |
716 | 721 |
717 DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) { | 722 DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) { |
718 isolate->debugger()->DebuggerStepCallback(); | 723 isolate->debugger()->DebuggerStepCallback(); |
719 } | 724 } |
720 | 725 |
721 | 726 |
722 // An instance call of the form o.f(...) could not be resolved. Check if | 727 // An instance call of the form o.f(...) could not be resolved. Check if |
723 // there is a getter with the same name. If so, invoke it. If the value is | 728 // there is a getter with the same name. If so, invoke it. If the value is |
(...skipping 704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1428 // The current code will not be changed in the case that the compiler | 1433 // The current code will not be changed in the case that the compiler |
1429 // bailed out during OSR compilation. | 1434 // bailed out during OSR compilation. |
1430 if (optimized_code.raw() != original_code.raw()) { | 1435 if (optimized_code.raw() != original_code.raw()) { |
1431 // The OSR code does not work for calling the function, so restore the | 1436 // The OSR code does not work for calling the function, so restore the |
1432 // unoptimized code. Patch the stack frame to return into the OSR | 1437 // unoptimized code. Patch the stack frame to return into the OSR |
1433 // code. | 1438 // code. |
1434 uword optimized_entry = | 1439 uword optimized_entry = |
1435 Instructions::Handle(optimized_code.instructions()).EntryPoint(); | 1440 Instructions::Handle(optimized_code.instructions()).EntryPoint(); |
1436 function.AttachCode(original_code); | 1441 function.AttachCode(original_code); |
1437 frame->set_pc(optimized_entry); | 1442 frame->set_pc(optimized_entry); |
1438 frame->set_pc_marker(optimized_code.raw()); | |
1439 } | 1443 } |
1440 } | 1444 } |
1441 } | 1445 } |
1442 | 1446 |
1443 | 1447 |
1444 DEFINE_RUNTIME_ENTRY(TraceICCall, 2) { | 1448 DEFINE_RUNTIME_ENTRY(TraceICCall, 2) { |
1445 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(0)); | 1449 const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(0)); |
1446 const Function& function = Function::CheckedHandle(arguments.ArgAt(1)); | 1450 const Function& function = Function::CheckedHandle(arguments.ArgAt(1)); |
1447 DartFrameIterator iterator; | 1451 DartFrameIterator iterator; |
1448 StackFrame* frame = iterator.NextFrame(); | 1452 StackFrame* frame = iterator.NextFrame(); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1516 isolate, Compiler::CompileFunction(thread, target_function)); | 1520 isolate, Compiler::CompileFunction(thread, target_function)); |
1517 if (!error.IsNull()) { | 1521 if (!error.IsNull()) { |
1518 Exceptions::PropagateError(error); | 1522 Exceptions::PropagateError(error); |
1519 } | 1523 } |
1520 } | 1524 } |
1521 ASSERT(target_function.HasCode()); | 1525 ASSERT(target_function.HasCode()); |
1522 ASSERT(target_function.raw() == target_code.function()); | 1526 ASSERT(target_function.raw() == target_code.function()); |
1523 | 1527 |
1524 const Code& current_target_code = Code::Handle( | 1528 const Code& current_target_code = Code::Handle( |
1525 isolate, target_function.CurrentCode()); | 1529 isolate, target_function.CurrentCode()); |
1526 CodePatcher::PatchStaticCallAt(frame->pc(), | 1530 const Instructions& instrs = Instructions::Handle( |
1527 caller_code, | 1531 isolate, caller_code.instructions()); |
1528 current_target_code); | 1532 { |
1529 caller_code.SetStaticCallTargetCodeAt(frame->pc(), current_target_code); | 1533 WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size()); |
| 1534 CodePatcher::PatchStaticCallAt(frame->pc(), caller_code, |
| 1535 current_target_code.EntryPoint()); |
| 1536 caller_code.SetStaticCallTargetCodeAt(frame->pc(), current_target_code); |
| 1537 } |
1530 if (FLAG_trace_patching) { | 1538 if (FLAG_trace_patching) { |
1531 OS::PrintErr("FixCallersTarget: caller %#" Px " " | 1539 OS::PrintErr("FixCallersTarget: caller %#" Px " " |
1532 "target '%s' %#" Px " -> %#" Px "\n", | 1540 "target '%s' %#" Px " -> %#" Px "\n", |
1533 frame->pc(), | 1541 frame->pc(), |
1534 target_function.ToFullyQualifiedCString(), | 1542 target_function.ToFullyQualifiedCString(), |
1535 target_code.EntryPoint(), | 1543 target_code.EntryPoint(), |
1536 current_target_code.EntryPoint()); | 1544 current_target_code.EntryPoint()); |
1537 } | 1545 } |
1538 arguments.SetReturn(current_target_code); | 1546 arguments.SetReturn(current_target_code); |
1539 } | 1547 } |
1540 | 1548 |
1541 | 1549 |
1542 // The caller tried to allocate an instance via an invalidated allocation | 1550 // The caller tried to allocate an instance via an invalidated allocation |
1543 // stub. | 1551 // stub. |
1544 DEFINE_RUNTIME_ENTRY(FixAllocationStubTarget, 0) { | 1552 DEFINE_RUNTIME_ENTRY(FixAllocationStubTarget, 0) { |
1545 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames); | 1553 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames); |
1546 StackFrame* frame = iterator.NextFrame(); | 1554 StackFrame* frame = iterator.NextFrame(); |
1547 ASSERT(frame != NULL); | 1555 ASSERT(frame != NULL); |
1548 while (frame->IsStubFrame() || frame->IsExitFrame()) { | 1556 while (frame->IsStubFrame() || frame->IsExitFrame()) { |
1549 frame = iterator.NextFrame(); | 1557 frame = iterator.NextFrame(); |
1550 ASSERT(frame != NULL); | 1558 ASSERT(frame != NULL); |
1551 } | 1559 } |
1552 if (frame->IsEntryFrame()) { | 1560 if (frame->IsEntryFrame()) { |
1553 // There must be a valid Dart frame. | 1561 // There must be a valid Dart frame. |
1554 UNREACHABLE(); | 1562 UNREACHABLE(); |
1555 } | 1563 } |
1556 ASSERT(frame->IsDartFrame()); | 1564 ASSERT(frame->IsDartFrame()); |
1557 const Code& caller_code = Code::Handle(isolate, frame->LookupDartCode()); | 1565 const Code& caller_code = Code::Handle(isolate, frame->LookupDartCode()); |
1558 ASSERT(!caller_code.IsNull()); | 1566 ASSERT(!caller_code.IsNull()); |
1559 const Code& stub = Code::Handle( | 1567 const uword target = |
1560 CodePatcher::GetStaticCallTargetAt(frame->pc(), caller_code)); | 1568 CodePatcher::GetStaticCallTargetAt(frame->pc(), caller_code); |
| 1569 const Code& stub = Code::Handle(isolate, Code::LookupCode(target)); |
1561 Class& alloc_class = Class::ZoneHandle(zone); | 1570 Class& alloc_class = Class::ZoneHandle(zone); |
1562 alloc_class ^= stub.owner(); | 1571 alloc_class ^= stub.owner(); |
1563 Code& alloc_stub = Code::Handle(isolate, alloc_class.allocation_stub()); | 1572 Code& alloc_stub = Code::Handle(isolate, alloc_class.allocation_stub()); |
1564 if (alloc_stub.IsNull()) { | 1573 if (alloc_stub.IsNull()) { |
1565 alloc_stub = StubCode::GetAllocationStubForClass(alloc_class); | 1574 alloc_stub = StubCode::GetAllocationStubForClass(alloc_class); |
1566 ASSERT(!CodePatcher::IsEntryPatched(alloc_stub)); | 1575 ASSERT(!CodePatcher::IsEntryPatched(alloc_stub)); |
1567 } | 1576 } |
1568 CodePatcher::PatchStaticCallAt(frame->pc(), | 1577 const Instructions& instrs = |
1569 caller_code, | 1578 Instructions::Handle(isolate, caller_code.instructions()); |
1570 alloc_stub); | 1579 { |
1571 caller_code.SetStubCallTargetCodeAt(frame->pc(), alloc_stub); | 1580 WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size()); |
| 1581 CodePatcher::PatchStaticCallAt(frame->pc(), |
| 1582 caller_code, |
| 1583 alloc_stub.EntryPoint()); |
| 1584 caller_code.SetStubCallTargetCodeAt(frame->pc(), alloc_stub); |
| 1585 } |
1572 if (FLAG_trace_patching) { | 1586 if (FLAG_trace_patching) { |
1573 OS::PrintErr("FixAllocationStubTarget: caller %#" Px " alloc-class %s " | 1587 OS::PrintErr("FixAllocationStubTarget: caller %#" Px " alloc-class %s " |
1574 " -> %#" Px "\n", | 1588 " -> %#" Px "\n", |
1575 frame->pc(), | 1589 frame->pc(), |
1576 alloc_class.ToCString(), | 1590 alloc_class.ToCString(), |
1577 alloc_stub.EntryPoint()); | 1591 alloc_stub.EntryPoint()); |
1578 } | 1592 } |
1579 arguments.SetReturn(alloc_stub); | 1593 arguments.SetReturn(alloc_stub); |
1580 } | 1594 } |
1581 | 1595 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1615 function.SwitchToUnoptimizedCode(); | 1629 function.SwitchToUnoptimizedCode(); |
1616 } | 1630 } |
1617 // Patch call site (lazy deoptimization is quite rare, patching it twice | 1631 // Patch call site (lazy deoptimization is quite rare, patching it twice |
1618 // is not a performance issue). | 1632 // is not a performance issue). |
1619 uword lazy_deopt_jump = optimized_code.GetLazyDeoptPc(); | 1633 uword lazy_deopt_jump = optimized_code.GetLazyDeoptPc(); |
1620 ASSERT(lazy_deopt_jump != 0); | 1634 ASSERT(lazy_deopt_jump != 0); |
1621 const Instructions& instrs = | 1635 const Instructions& instrs = |
1622 Instructions::Handle(zone, optimized_code.instructions()); | 1636 Instructions::Handle(zone, optimized_code.instructions()); |
1623 { | 1637 { |
1624 WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size()); | 1638 WritableInstructionsScope writable(instrs.EntryPoint(), instrs.size()); |
1625 CodePatcher::InsertDeoptimizationCallAt(pc, lazy_deopt_jump); | 1639 CodePatcher::InsertCallAt(pc, lazy_deopt_jump); |
1626 } | 1640 } |
1627 if (FLAG_trace_patching) { | 1641 if (FLAG_trace_patching) { |
1628 const String& name = String::Handle(function.name()); | 1642 const String& name = String::Handle(function.name()); |
1629 OS::PrintErr("InsertDeoptimizationCallAt: %" Px " to %" Px " for %s\n", pc, | 1643 OS::PrintErr("InsertCallAt: %" Px " to %" Px " for %s\n", pc, |
1630 lazy_deopt_jump, name.ToCString()); | 1644 lazy_deopt_jump, name.ToCString()); |
1631 } | 1645 } |
1632 // Mark code as dead (do not GC its embedded objects). | 1646 // Mark code as dead (do not GC its embedded objects). |
1633 optimized_code.set_is_alive(false); | 1647 optimized_code.set_is_alive(false); |
1634 } | 1648 } |
1635 | 1649 |
1636 | 1650 |
1637 // Currently checks only that all optimized frames have kDeoptIndex | 1651 // Currently checks only that all optimized frames have kDeoptIndex |
1638 // and unoptimized code has the kDeoptAfter. | 1652 // and unoptimized code has the kDeoptAfter. |
1639 void DeoptimizeFunctionsOnStack() { | 1653 void DeoptimizeFunctionsOnStack() { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1672 *reinterpret_cast<intptr_t*>(saved_registers_address); | 1686 *reinterpret_cast<intptr_t*>(saved_registers_address); |
1673 saved_registers_address += kWordSize; | 1687 saved_registers_address += kWordSize; |
1674 } | 1688 } |
1675 *cpu_registers = cpu_registers_copy; | 1689 *cpu_registers = cpu_registers_copy; |
1676 } | 1690 } |
1677 | 1691 |
1678 | 1692 |
1679 // Copies saved registers and caller's frame into temporary buffers. | 1693 // Copies saved registers and caller's frame into temporary buffers. |
1680 // Returns the stack size of unoptimized frame. | 1694 // Returns the stack size of unoptimized frame. |
1681 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, | 1695 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
1682 2, | 1696 1, uword saved_registers_address) { |
1683 uword saved_registers_address, | |
1684 uword is_lazy_deopt) { | |
1685 Thread* thread = Thread::Current(); | 1697 Thread* thread = Thread::Current(); |
1686 Isolate* isolate = thread->isolate(); | 1698 Isolate* isolate = thread->isolate(); |
1687 StackZone zone(thread); | 1699 StackZone zone(thread); |
1688 HANDLESCOPE(thread); | 1700 HANDLESCOPE(thread); |
1689 | 1701 |
1690 // All registers have been saved below last-fp as if they were locals. | 1702 // All registers have been saved below last-fp as if they were locals. |
1691 const uword last_fp = saved_registers_address | 1703 const uword last_fp = saved_registers_address |
1692 + (kNumberOfCpuRegisters * kWordSize) | 1704 + (kNumberOfCpuRegisters * kWordSize) |
1693 + (kNumberOfFpuRegisters * kFpuRegisterSize) | 1705 + (kNumberOfFpuRegisters * kFpuRegisterSize) |
1694 - ((kFirstLocalSlotFromFp + 1) * kWordSize); | 1706 - ((kFirstLocalSlotFromFp + 1) * kWordSize); |
1695 | 1707 |
1696 // Get optimized code and frame that need to be deoptimized. | 1708 // Get optimized code and frame that need to be deoptimized. |
1697 DartFrameIterator iterator(last_fp); | 1709 DartFrameIterator iterator(last_fp); |
1698 StackFrame* caller_frame = iterator.NextFrame(); | 1710 StackFrame* caller_frame = iterator.NextFrame(); |
1699 ASSERT(caller_frame != NULL); | 1711 ASSERT(caller_frame != NULL); |
1700 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | 1712 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
1701 ASSERT(optimized_code.is_optimized()); | 1713 ASSERT(optimized_code.is_optimized()); |
1702 | 1714 |
1703 // Copy the saved registers from the stack. | 1715 // Copy the saved registers from the stack. |
1704 fpu_register_t* fpu_registers; | 1716 fpu_register_t* fpu_registers; |
1705 intptr_t* cpu_registers; | 1717 intptr_t* cpu_registers; |
1706 CopySavedRegisters(saved_registers_address, &fpu_registers, &cpu_registers); | 1718 CopySavedRegisters(saved_registers_address, &fpu_registers, &cpu_registers); |
1707 | 1719 |
1708 // Create the DeoptContext. | 1720 // Create the DeoptContext. |
1709 DeoptContext* deopt_context = | 1721 DeoptContext* deopt_context = |
1710 new DeoptContext(caller_frame, | 1722 new DeoptContext(caller_frame, optimized_code, |
1711 optimized_code, | |
1712 DeoptContext::kDestIsOriginalFrame, | 1723 DeoptContext::kDestIsOriginalFrame, |
1713 fpu_registers, | 1724 fpu_registers, cpu_registers); |
1714 cpu_registers, | |
1715 is_lazy_deopt != 0); | |
1716 isolate->set_deopt_context(deopt_context); | 1725 isolate->set_deopt_context(deopt_context); |
1717 | 1726 |
1718 // Stack size (FP - SP) in bytes. | 1727 // Stack size (FP - SP) in bytes. |
1719 return deopt_context->DestStackAdjustment() * kWordSize; | 1728 return deopt_context->DestStackAdjustment() * kWordSize; |
1720 } | 1729 } |
1721 END_LEAF_RUNTIME_ENTRY | 1730 END_LEAF_RUNTIME_ENTRY |
1722 | 1731 |
1723 | 1732 |
1724 // The stack has been adjusted to fit all values for unoptimized frame. | 1733 // The stack has been adjusted to fit all values for unoptimized frame. |
1725 // Fill the unoptimized frame. | 1734 // Fill the unoptimized frame. |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1846 const intptr_t elm_size = old_data.ElementSizeInBytes(); | 1855 const intptr_t elm_size = old_data.ElementSizeInBytes(); |
1847 const TypedData& new_data = | 1856 const TypedData& new_data = |
1848 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); | 1857 TypedData::Handle(TypedData::New(cid, new_size, Heap::kOld)); |
1849 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); | 1858 TypedData::Copy(new_data, 0, old_data, 0, old_size * elm_size); |
1850 typed_data_cell.SetAt(0, new_data); | 1859 typed_data_cell.SetAt(0, new_data); |
1851 arguments.SetReturn(new_data); | 1860 arguments.SetReturn(new_data); |
1852 } | 1861 } |
1853 | 1862 |
1854 | 1863 |
1855 } // namespace dart | 1864 } // namespace dart |
OLD | NEW |