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; |
814 case FRAME_DROPPED_IN_DEBUG_SLOT_CALL: | 818 case FRAME_DROPPED_IN_DEBUG_SLOT_CALL: |
815 // Debug break slot stub does not return normally, instead it manually | 819 // Debug break slot stub does not return normally, instead it manually |
816 // cleans the stack and jumps. We should patch the jump address. | 820 // cleans the stack and jumps. We should patch the jump address. |
817 code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); | 821 code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); |
818 break; | 822 break; |
819 case FRAME_DROPPED_IN_DIRECT_CALL: | 823 case FRAME_DROPPED_IN_DIRECT_CALL: |
820 // Nothing to do, after_break_target is not used here. | 824 // Nothing to do, after_break_target is not used here. |
821 return true; | 825 return true; |
822 case FRAME_DROPPED_IN_RETURN_CALL: | 826 case FRAME_DROPPED_IN_RETURN_CALL: |
823 code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); | 827 code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); |
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1480 bool change = *above_frame_address != *pointer_address; | 1484 bool change = *above_frame_address != *pointer_address; |
1481 *above_frame_address = *pointer_address; | 1485 *above_frame_address = *pointer_address; |
1482 return change; | 1486 return change; |
1483 } | 1487 } |
1484 | 1488 |
1485 | 1489 |
1486 // Initializes an artificial stack frame. The data it contains is used for: | 1490 // Initializes an artificial stack frame. The data it contains is used for: |
1487 // a. successful work of frame dropper code which eventually gets control, | 1491 // a. successful work of frame dropper code which eventually gets control, |
1488 // b. being compatible with regular stack structure for various stack | 1492 // b. being compatible with regular stack structure for various stack |
1489 // iterators. | 1493 // 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. |
1490 // Frame structure (conforms InternalFrame structure): | 1498 // Frame structure (conforms InternalFrame structure): |
1491 // -- code | 1499 // -- code |
1492 // -- SMI maker | 1500 // -- SMI maker |
1493 // -- function (slot is called "context") | 1501 // -- function (slot is called "context") |
1494 // -- frame base | 1502 // -- frame base |
1495 static void SetUpFrameDropperFrame(StackFrame* bottom_js_frame, | 1503 static Object** SetUpFrameDropperFrame(StackFrame* bottom_js_frame, |
1496 Handle<Code> code) { | 1504 Handle<Code> code) { |
1497 DCHECK(bottom_js_frame->is_java_script()); | 1505 DCHECK(bottom_js_frame->is_java_script()); |
1498 | 1506 |
1499 Address fp = bottom_js_frame->fp(); | 1507 Address fp = bottom_js_frame->fp(); |
1500 | 1508 |
1501 // Move function pointer into "context" slot. | 1509 // Move function pointer into "context" slot. |
1502 Memory::Object_at(fp + StandardFrameConstants::kContextOffset) = | 1510 Memory::Object_at(fp + StandardFrameConstants::kContextOffset) = |
1503 Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset); | 1511 Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset); |
1504 | 1512 |
1505 Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code; | 1513 Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code; |
1506 Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) = | 1514 Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) = |
1507 Smi::FromInt(StackFrame::INTERNAL); | 1515 Smi::FromInt(StackFrame::INTERNAL); |
| 1516 |
| 1517 return reinterpret_cast<Object**>(&Memory::Object_at( |
| 1518 fp + StandardFrameConstants::kContextOffset)); |
1508 } | 1519 } |
1509 | 1520 |
1510 | 1521 |
1511 // Removes specified range of frames from stack. There may be 1 or more | 1522 // Removes specified range of frames from stack. There may be 1 or more |
1512 // frames in range. Anyway the bottom frame is restarted rather than dropped, | 1523 // frames in range. Anyway the bottom frame is restarted rather than dropped, |
1513 // and therefore has to be a JavaScript frame. | 1524 // and therefore has to be a JavaScript frame. |
1514 // Returns error message or NULL. | 1525 // Returns error message or NULL. |
1515 static const char* DropFrames(Vector<StackFrame*> frames, int top_frame_index, | 1526 static const char* DropFrames(Vector<StackFrame*> frames, |
| 1527 int top_frame_index, |
1516 int bottom_js_frame_index, | 1528 int bottom_js_frame_index, |
1517 LiveEdit::FrameDropMode* mode) { | 1529 LiveEdit::FrameDropMode* mode, |
| 1530 Object*** restarter_frame_function_pointer) { |
1518 if (!LiveEdit::kFrameDropperSupported) { | 1531 if (!LiveEdit::kFrameDropperSupported) { |
1519 return "Stack manipulations are not supported in this architecture."; | 1532 return "Stack manipulations are not supported in this architecture."; |
1520 } | 1533 } |
1521 | 1534 |
1522 StackFrame* pre_top_frame = frames[top_frame_index - 1]; | 1535 StackFrame* pre_top_frame = frames[top_frame_index - 1]; |
1523 StackFrame* top_frame = frames[top_frame_index]; | 1536 StackFrame* top_frame = frames[top_frame_index]; |
1524 StackFrame* bottom_js_frame = frames[bottom_js_frame_index]; | 1537 StackFrame* bottom_js_frame = frames[bottom_js_frame_index]; |
1525 | 1538 |
1526 DCHECK(bottom_js_frame->is_java_script()); | 1539 DCHECK(bottom_js_frame->is_java_script()); |
1527 | 1540 |
1528 // Check the nature of the top frame. | 1541 // Check the nature of the top frame. |
1529 Isolate* isolate = bottom_js_frame->isolate(); | 1542 Isolate* isolate = bottom_js_frame->isolate(); |
1530 Code* pre_top_frame_code = pre_top_frame->LookupCode(); | 1543 Code* pre_top_frame_code = pre_top_frame->LookupCode(); |
1531 bool frame_has_padding = true; | 1544 bool frame_has_padding = true; |
1532 if (pre_top_frame_code == | 1545 if (pre_top_frame_code->is_inline_cache_stub() && |
1533 isolate->builtins()->builtin(Builtins::kSlot_DebugBreak)) { | 1546 pre_top_frame_code->is_debug_stub()) { |
| 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)) { |
1534 // OK, we can drop debug break slot. | 1551 // OK, we can drop debug break slot. |
1535 *mode = LiveEdit::FRAME_DROPPED_IN_DEBUG_SLOT_CALL; | 1552 *mode = LiveEdit::FRAME_DROPPED_IN_DEBUG_SLOT_CALL; |
1536 } else if (pre_top_frame_code == | 1553 } else if (pre_top_frame_code == |
1537 isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit)) { | 1554 isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit)) { |
1538 // OK, we can drop our own code. | 1555 // OK, we can drop our own code. |
1539 pre_top_frame = frames[top_frame_index - 2]; | 1556 pre_top_frame = frames[top_frame_index - 2]; |
1540 top_frame = frames[top_frame_index - 1]; | 1557 top_frame = frames[top_frame_index - 1]; |
1541 *mode = LiveEdit::CURRENTLY_SET_MODE; | 1558 *mode = LiveEdit::CURRENTLY_SET_MODE; |
1542 frame_has_padding = false; | 1559 frame_has_padding = false; |
1543 } else if (pre_top_frame_code == | 1560 } else if (pre_top_frame_code == |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1617 // Committing now. After this point we should return only NULL value. | 1634 // Committing now. After this point we should return only NULL value. |
1618 | 1635 |
1619 FixTryCatchHandler(pre_top_frame, bottom_js_frame); | 1636 FixTryCatchHandler(pre_top_frame, bottom_js_frame); |
1620 // Make sure FixTryCatchHandler is idempotent. | 1637 // Make sure FixTryCatchHandler is idempotent. |
1621 DCHECK(!FixTryCatchHandler(pre_top_frame, bottom_js_frame)); | 1638 DCHECK(!FixTryCatchHandler(pre_top_frame, bottom_js_frame)); |
1622 | 1639 |
1623 Handle<Code> code = isolate->builtins()->FrameDropper_LiveEdit(); | 1640 Handle<Code> code = isolate->builtins()->FrameDropper_LiveEdit(); |
1624 *top_frame_pc_address = code->entry(); | 1641 *top_frame_pc_address = code->entry(); |
1625 pre_top_frame->SetCallerFp(bottom_js_frame->fp()); | 1642 pre_top_frame->SetCallerFp(bottom_js_frame->fp()); |
1626 | 1643 |
1627 SetUpFrameDropperFrame(bottom_js_frame, code); | 1644 *restarter_frame_function_pointer = |
| 1645 SetUpFrameDropperFrame(bottom_js_frame, code); |
| 1646 |
| 1647 DCHECK((**restarter_frame_function_pointer)->IsJSFunction()); |
1628 | 1648 |
1629 for (Address a = unused_stack_top; | 1649 for (Address a = unused_stack_top; |
1630 a < unused_stack_bottom; | 1650 a < unused_stack_bottom; |
1631 a += kPointerSize) { | 1651 a += kPointerSize) { |
1632 Memory::Object_at(a) = Smi::FromInt(0); | 1652 Memory::Object_at(a) = Smi::FromInt(0); |
1633 } | 1653 } |
1634 | 1654 |
1635 return NULL; | 1655 return NULL; |
1636 } | 1656 } |
1637 | 1657 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1732 // We are in check-only mode. | 1752 // We are in check-only mode. |
1733 return NULL; | 1753 return NULL; |
1734 } | 1754 } |
1735 | 1755 |
1736 if (!target_frame_found) { | 1756 if (!target_frame_found) { |
1737 // Nothing to drop. | 1757 // Nothing to drop. |
1738 return target.GetNotFoundMessage(); | 1758 return target.GetNotFoundMessage(); |
1739 } | 1759 } |
1740 | 1760 |
1741 LiveEdit::FrameDropMode drop_mode = LiveEdit::FRAMES_UNTOUCHED; | 1761 LiveEdit::FrameDropMode drop_mode = LiveEdit::FRAMES_UNTOUCHED; |
1742 const char* error_message = | 1762 Object** restarter_frame_function_pointer = NULL; |
1743 DropFrames(frames, top_frame_index, bottom_js_frame_index, &drop_mode); | 1763 const char* error_message = DropFrames(frames, top_frame_index, |
| 1764 bottom_js_frame_index, &drop_mode, |
| 1765 &restarter_frame_function_pointer); |
1744 | 1766 |
1745 if (error_message != NULL) { | 1767 if (error_message != NULL) { |
1746 return error_message; | 1768 return error_message; |
1747 } | 1769 } |
1748 | 1770 |
1749 // Adjust break_frame after some frames has been dropped. | 1771 // Adjust break_frame after some frames has been dropped. |
1750 StackFrame::Id new_id = StackFrame::NO_ID; | 1772 StackFrame::Id new_id = StackFrame::NO_ID; |
1751 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) { | 1773 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) { |
1752 if (frames[i]->type() == StackFrame::JAVA_SCRIPT) { | 1774 if (frames[i]->type() == StackFrame::JAVA_SCRIPT) { |
1753 new_id = frames[i]->id(); | 1775 new_id = frames[i]->id(); |
1754 break; | 1776 break; |
1755 } | 1777 } |
1756 } | 1778 } |
1757 debug->FramesHaveBeenDropped(new_id, drop_mode); | 1779 debug->FramesHaveBeenDropped( |
| 1780 new_id, drop_mode, restarter_frame_function_pointer); |
1758 return NULL; | 1781 return NULL; |
1759 } | 1782 } |
1760 | 1783 |
1761 | 1784 |
1762 // Fills result array with statuses of functions. Modifies the stack | 1785 // Fills result array with statuses of functions. Modifies the stack |
1763 // removing all listed function if possible and if do_drop is true. | 1786 // removing all listed function if possible and if do_drop is true. |
1764 static const char* DropActivationsInActiveThread( | 1787 static const char* DropActivationsInActiveThread( |
1765 Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) { | 1788 Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) { |
1766 MultipleFunctionTarget target(shared_info_array, result); | 1789 MultipleFunctionTarget target(shared_info_array, result); |
1767 Isolate* isolate = shared_info_array->GetIsolate(); | 1790 Isolate* isolate = shared_info_array->GetIsolate(); |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1978 isolate_->active_function_info_listener()->FunctionCode(code); | 2001 isolate_->active_function_info_listener()->FunctionCode(code); |
1979 } | 2002 } |
1980 | 2003 |
1981 | 2004 |
1982 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { | 2005 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { |
1983 return isolate->active_function_info_listener() != NULL; | 2006 return isolate->active_function_info_listener() != NULL; |
1984 } | 2007 } |
1985 | 2008 |
1986 } // namespace internal | 2009 } // namespace internal |
1987 } // namespace v8 | 2010 } // namespace v8 |
OLD | NEW |