| 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 |