OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/debug/liveedit.h" | 5 #include "src/debug/liveedit.h" |
6 | 6 |
7 #include "src/ast/scopeinfo.h" | 7 #include "src/ast/scopeinfo.h" |
8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/compilation-cache.h" | 10 #include "src/compilation-cache.h" |
(...skipping 793 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
804 debug->thread_local_.frame_drop_mode_ = LiveEdit::FRAMES_UNTOUCHED; | 804 debug->thread_local_.frame_drop_mode_ = LiveEdit::FRAMES_UNTOUCHED; |
805 } | 805 } |
806 | 806 |
807 | 807 |
808 bool LiveEdit::SetAfterBreakTarget(Debug* debug) { | 808 bool LiveEdit::SetAfterBreakTarget(Debug* debug) { |
809 Code* code = NULL; | 809 Code* code = NULL; |
810 Isolate* isolate = debug->isolate_; | 810 Isolate* isolate = debug->isolate_; |
811 switch (debug->thread_local_.frame_drop_mode_) { | 811 switch (debug->thread_local_.frame_drop_mode_) { |
812 case FRAMES_UNTOUCHED: | 812 case FRAMES_UNTOUCHED: |
813 return false; | 813 return false; |
814 case FRAME_DROPPED_IN_IC_CALL: | |
815 // We must have been calling IC stub. Do not go there anymore. | |
816 code = isolate->builtins()->builtin(Builtins::kPlainReturn_LiveEdit); | |
817 break; | |
818 case FRAME_DROPPED_IN_DEBUG_SLOT_CALL: | 814 case FRAME_DROPPED_IN_DEBUG_SLOT_CALL: |
819 // Debug break slot stub does not return normally, instead it manually | 815 // Debug break slot stub does not return normally, instead it manually |
820 // cleans the stack and jumps. We should patch the jump address. | 816 // cleans the stack and jumps. We should patch the jump address. |
821 code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); | 817 code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); |
822 break; | 818 break; |
823 case FRAME_DROPPED_IN_DIRECT_CALL: | 819 case FRAME_DROPPED_IN_DIRECT_CALL: |
824 // Nothing to do, after_break_target is not used here. | 820 // Nothing to do, after_break_target is not used here. |
825 return true; | 821 return true; |
826 case FRAME_DROPPED_IN_RETURN_CALL: | 822 case FRAME_DROPPED_IN_RETURN_CALL: |
827 code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); | 823 code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); |
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1484 bool change = *above_frame_address != *pointer_address; | 1480 bool change = *above_frame_address != *pointer_address; |
1485 *above_frame_address = *pointer_address; | 1481 *above_frame_address = *pointer_address; |
1486 return change; | 1482 return change; |
1487 } | 1483 } |
1488 | 1484 |
1489 | 1485 |
1490 // Initializes an artificial stack frame. The data it contains is used for: | 1486 // Initializes an artificial stack frame. The data it contains is used for: |
1491 // a. successful work of frame dropper code which eventually gets control, | 1487 // a. successful work of frame dropper code which eventually gets control, |
1492 // b. being compatible with regular stack structure for various stack | 1488 // b. being compatible with regular stack structure for various stack |
1493 // iterators. | 1489 // iterators. |
1494 // Returns address of stack allocated pointer to restarted function, | |
1495 // the value that is called 'restarter_frame_function_pointer'. The value | |
1496 // at this address (possibly updated by GC) may be used later when preparing | |
1497 // 'step in' operation. | |
1498 // Frame structure (conforms InternalFrame structure): | 1490 // Frame structure (conforms InternalFrame structure): |
1499 // -- code | 1491 // -- code |
1500 // -- SMI maker | 1492 // -- SMI maker |
1501 // -- function (slot is called "context") | 1493 // -- function (slot is called "context") |
1502 // -- frame base | 1494 // -- frame base |
1503 static Object** SetUpFrameDropperFrame(StackFrame* bottom_js_frame, | 1495 static void SetUpFrameDropperFrame(StackFrame* bottom_js_frame, |
1504 Handle<Code> code) { | 1496 Handle<Code> code) { |
1505 DCHECK(bottom_js_frame->is_java_script()); | 1497 DCHECK(bottom_js_frame->is_java_script()); |
1506 | 1498 |
1507 Address fp = bottom_js_frame->fp(); | 1499 Address fp = bottom_js_frame->fp(); |
1508 | 1500 |
1509 // Move function pointer into "context" slot. | 1501 // Move function pointer into "context" slot. |
1510 Memory::Object_at(fp + StandardFrameConstants::kContextOffset) = | 1502 Memory::Object_at(fp + StandardFrameConstants::kContextOffset) = |
1511 Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset); | 1503 Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset); |
1512 | 1504 |
1513 Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code; | 1505 Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code; |
1514 Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) = | 1506 Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) = |
1515 Smi::FromInt(StackFrame::INTERNAL); | 1507 Smi::FromInt(StackFrame::INTERNAL); |
1516 | |
1517 return reinterpret_cast<Object**>(&Memory::Object_at( | |
1518 fp + StandardFrameConstants::kContextOffset)); | |
1519 } | 1508 } |
1520 | 1509 |
1521 | 1510 |
1522 // Removes specified range of frames from stack. There may be 1 or more | 1511 // Removes specified range of frames from stack. There may be 1 or more |
1523 // frames in range. Anyway the bottom frame is restarted rather than dropped, | 1512 // frames in range. Anyway the bottom frame is restarted rather than dropped, |
1524 // and therefore has to be a JavaScript frame. | 1513 // and therefore has to be a JavaScript frame. |
1525 // Returns error message or NULL. | 1514 // Returns error message or NULL. |
1526 static const char* DropFrames(Vector<StackFrame*> frames, | 1515 static const char* DropFrames(Vector<StackFrame*> frames, int top_frame_index, |
1527 int top_frame_index, | |
1528 int bottom_js_frame_index, | 1516 int bottom_js_frame_index, |
1529 LiveEdit::FrameDropMode* mode, | 1517 LiveEdit::FrameDropMode* mode) { |
1530 Object*** restarter_frame_function_pointer) { | |
1531 if (!LiveEdit::kFrameDropperSupported) { | 1518 if (!LiveEdit::kFrameDropperSupported) { |
1532 return "Stack manipulations are not supported in this architecture."; | 1519 return "Stack manipulations are not supported in this architecture."; |
1533 } | 1520 } |
1534 | 1521 |
1535 StackFrame* pre_top_frame = frames[top_frame_index - 1]; | 1522 StackFrame* pre_top_frame = frames[top_frame_index - 1]; |
1536 StackFrame* top_frame = frames[top_frame_index]; | 1523 StackFrame* top_frame = frames[top_frame_index]; |
1537 StackFrame* bottom_js_frame = frames[bottom_js_frame_index]; | 1524 StackFrame* bottom_js_frame = frames[bottom_js_frame_index]; |
1538 | 1525 |
1539 DCHECK(bottom_js_frame->is_java_script()); | 1526 DCHECK(bottom_js_frame->is_java_script()); |
1540 | 1527 |
1541 // Check the nature of the top frame. | 1528 // Check the nature of the top frame. |
1542 Isolate* isolate = bottom_js_frame->isolate(); | 1529 Isolate* isolate = bottom_js_frame->isolate(); |
1543 Code* pre_top_frame_code = pre_top_frame->LookupCode(); | 1530 Code* pre_top_frame_code = pre_top_frame->LookupCode(); |
1544 bool frame_has_padding = true; | 1531 bool frame_has_padding = true; |
1545 if (pre_top_frame_code->is_inline_cache_stub() && | 1532 if (pre_top_frame_code == |
1546 pre_top_frame_code->is_debug_stub()) { | 1533 isolate->builtins()->builtin(Builtins::kSlot_DebugBreak)) { |
1547 // OK, we can drop inline cache calls. | |
1548 *mode = LiveEdit::FRAME_DROPPED_IN_IC_CALL; | |
1549 } else if (pre_top_frame_code == | |
1550 isolate->builtins()->builtin(Builtins::kSlot_DebugBreak)) { | |
1551 // OK, we can drop debug break slot. | 1534 // OK, we can drop debug break slot. |
1552 *mode = LiveEdit::FRAME_DROPPED_IN_DEBUG_SLOT_CALL; | 1535 *mode = LiveEdit::FRAME_DROPPED_IN_DEBUG_SLOT_CALL; |
1553 } else if (pre_top_frame_code == | 1536 } else if (pre_top_frame_code == |
1554 isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit)) { | 1537 isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit)) { |
1555 // OK, we can drop our own code. | 1538 // OK, we can drop our own code. |
1556 pre_top_frame = frames[top_frame_index - 2]; | 1539 pre_top_frame = frames[top_frame_index - 2]; |
1557 top_frame = frames[top_frame_index - 1]; | 1540 top_frame = frames[top_frame_index - 1]; |
1558 *mode = LiveEdit::CURRENTLY_SET_MODE; | 1541 *mode = LiveEdit::CURRENTLY_SET_MODE; |
1559 frame_has_padding = false; | 1542 frame_has_padding = false; |
1560 } else if (pre_top_frame_code == | 1543 } else if (pre_top_frame_code == |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1634 // Committing now. After this point we should return only NULL value. | 1617 // Committing now. After this point we should return only NULL value. |
1635 | 1618 |
1636 FixTryCatchHandler(pre_top_frame, bottom_js_frame); | 1619 FixTryCatchHandler(pre_top_frame, bottom_js_frame); |
1637 // Make sure FixTryCatchHandler is idempotent. | 1620 // Make sure FixTryCatchHandler is idempotent. |
1638 DCHECK(!FixTryCatchHandler(pre_top_frame, bottom_js_frame)); | 1621 DCHECK(!FixTryCatchHandler(pre_top_frame, bottom_js_frame)); |
1639 | 1622 |
1640 Handle<Code> code = isolate->builtins()->FrameDropper_LiveEdit(); | 1623 Handle<Code> code = isolate->builtins()->FrameDropper_LiveEdit(); |
1641 *top_frame_pc_address = code->entry(); | 1624 *top_frame_pc_address = code->entry(); |
1642 pre_top_frame->SetCallerFp(bottom_js_frame->fp()); | 1625 pre_top_frame->SetCallerFp(bottom_js_frame->fp()); |
1643 | 1626 |
1644 *restarter_frame_function_pointer = | 1627 SetUpFrameDropperFrame(bottom_js_frame, code); |
1645 SetUpFrameDropperFrame(bottom_js_frame, code); | |
1646 | |
1647 DCHECK((**restarter_frame_function_pointer)->IsJSFunction()); | |
1648 | 1628 |
1649 for (Address a = unused_stack_top; | 1629 for (Address a = unused_stack_top; |
1650 a < unused_stack_bottom; | 1630 a < unused_stack_bottom; |
1651 a += kPointerSize) { | 1631 a += kPointerSize) { |
1652 Memory::Object_at(a) = Smi::FromInt(0); | 1632 Memory::Object_at(a) = Smi::FromInt(0); |
1653 } | 1633 } |
1654 | 1634 |
1655 return NULL; | 1635 return NULL; |
1656 } | 1636 } |
1657 | 1637 |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1798 // We are in check-only mode. | 1778 // We are in check-only mode. |
1799 return NULL; | 1779 return NULL; |
1800 } | 1780 } |
1801 | 1781 |
1802 if (!target_frame_found) { | 1782 if (!target_frame_found) { |
1803 // Nothing to drop. | 1783 // Nothing to drop. |
1804 return target.GetNotFoundMessage(); | 1784 return target.GetNotFoundMessage(); |
1805 } | 1785 } |
1806 | 1786 |
1807 LiveEdit::FrameDropMode drop_mode = LiveEdit::FRAMES_UNTOUCHED; | 1787 LiveEdit::FrameDropMode drop_mode = LiveEdit::FRAMES_UNTOUCHED; |
1808 Object** restarter_frame_function_pointer = NULL; | 1788 const char* error_message = |
1809 const char* error_message = DropFrames(frames, top_frame_index, | 1789 DropFrames(frames, top_frame_index, bottom_js_frame_index, &drop_mode); |
1810 bottom_js_frame_index, &drop_mode, | |
1811 &restarter_frame_function_pointer); | |
1812 | 1790 |
1813 if (error_message != NULL) { | 1791 if (error_message != NULL) { |
1814 return error_message; | 1792 return error_message; |
1815 } | 1793 } |
1816 | 1794 |
1817 // Adjust break_frame after some frames has been dropped. | 1795 // Adjust break_frame after some frames has been dropped. |
1818 StackFrame::Id new_id = StackFrame::NO_ID; | 1796 StackFrame::Id new_id = StackFrame::NO_ID; |
1819 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) { | 1797 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) { |
1820 if (frames[i]->type() == StackFrame::JAVA_SCRIPT) { | 1798 if (frames[i]->type() == StackFrame::JAVA_SCRIPT) { |
1821 new_id = frames[i]->id(); | 1799 new_id = frames[i]->id(); |
1822 break; | 1800 break; |
1823 } | 1801 } |
1824 } | 1802 } |
1825 debug->FramesHaveBeenDropped( | 1803 debug->FramesHaveBeenDropped(new_id, drop_mode); |
1826 new_id, drop_mode, restarter_frame_function_pointer); | |
1827 return NULL; | 1804 return NULL; |
1828 } | 1805 } |
1829 | 1806 |
1830 | 1807 |
1831 // Fills result array with statuses of functions. Modifies the stack | 1808 // Fills result array with statuses of functions. Modifies the stack |
1832 // removing all listed function if possible and if do_drop is true. | 1809 // removing all listed function if possible and if do_drop is true. |
1833 static const char* DropActivationsInActiveThread( | 1810 static const char* DropActivationsInActiveThread( |
1834 Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array, | 1811 Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array, |
1835 Handle<JSArray> result, bool do_drop) { | 1812 Handle<JSArray> result, bool do_drop) { |
1836 MultipleFunctionTarget target(old_shared_array, new_shared_array, result); | 1813 MultipleFunctionTarget target(old_shared_array, new_shared_array, result); |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2060 isolate_->active_function_info_listener()->FunctionCode(code); | 2037 isolate_->active_function_info_listener()->FunctionCode(code); |
2061 } | 2038 } |
2062 | 2039 |
2063 | 2040 |
2064 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { | 2041 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { |
2065 return isolate->active_function_info_listener() != NULL; | 2042 return isolate->active_function_info_listener() != NULL; |
2066 } | 2043 } |
2067 | 2044 |
2068 } // namespace internal | 2045 } // namespace internal |
2069 } // namespace v8 | 2046 } // namespace v8 |
OLD | NEW |