OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 670 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
681 | 681 |
682 // Notify debugger if a real break point is triggered or if performing single | 682 // Notify debugger if a real break point is triggered or if performing single |
683 // stepping with no more steps to perform. Otherwise do another step. | 683 // stepping with no more steps to perform. Otherwise do another step. |
684 if (!break_points_hit->IsUndefined() || | 684 if (!break_points_hit->IsUndefined() || |
685 (thread_local_.last_step_action_ != StepNone && | 685 (thread_local_.last_step_action_ != StepNone && |
686 thread_local_.step_count_ == 0)) { | 686 thread_local_.step_count_ == 0)) { |
687 // Clear all current stepping setup. | 687 // Clear all current stepping setup. |
688 ClearStepping(); | 688 ClearStepping(); |
689 | 689 |
690 // Notify the debug event listeners. | 690 // Notify the debug event listeners. |
691 Debugger::OnDebugBreak(break_points_hit); | 691 Debugger::OnDebugBreak(break_points_hit, false); |
692 } else if (thread_local_.last_step_action_ != StepNone) { | 692 } else if (thread_local_.last_step_action_ != StepNone) { |
693 // Hold on to last step action as it is cleared by the call to | 693 // Hold on to last step action as it is cleared by the call to |
694 // ClearStepping. | 694 // ClearStepping. |
695 StepAction step_action = thread_local_.last_step_action_; | 695 StepAction step_action = thread_local_.last_step_action_; |
696 int step_count = thread_local_.step_count_; | 696 int step_count = thread_local_.step_count_; |
697 | 697 |
698 // Clear all current stepping setup. | 698 // Clear all current stepping setup. |
699 ClearStepping(); | 699 ClearStepping(); |
700 | 700 |
701 // Set up for the remaining steps. | 701 // Set up for the remaining steps. |
(...skipping 799 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1501 if (!caught_exception) { | 1501 if (!caught_exception) { |
1502 event_data = MakeExceptionEvent(exec_state, exception, uncaught, | 1502 event_data = MakeExceptionEvent(exec_state, exception, uncaught, |
1503 &caught_exception); | 1503 &caught_exception); |
1504 } | 1504 } |
1505 // Bail out and don't call debugger if exception. | 1505 // Bail out and don't call debugger if exception. |
1506 if (caught_exception) { | 1506 if (caught_exception) { |
1507 return; | 1507 return; |
1508 } | 1508 } |
1509 | 1509 |
1510 // Process debug event | 1510 // Process debug event |
1511 ProcessDebugEvent(v8::Exception, event_data); | 1511 ProcessDebugEvent(v8::Exception, event_data, false); |
1512 // Return to continue execution from where the exception was thrown. | 1512 // Return to continue execution from where the exception was thrown. |
1513 } | 1513 } |
1514 | 1514 |
1515 | 1515 |
1516 void Debugger::OnDebugBreak(Handle<Object> break_points_hit) { | 1516 void Debugger::OnDebugBreak(Handle<Object> break_points_hit, |
| 1517 bool auto_continue) { |
1517 HandleScope scope; | 1518 HandleScope scope; |
1518 | 1519 |
1519 // Debugger has already been entered by caller. | 1520 // Debugger has already been entered by caller. |
1520 ASSERT(Top::context() == *Debug::debug_context()); | 1521 ASSERT(Top::context() == *Debug::debug_context()); |
1521 | 1522 |
1522 // Bail out if there is no listener for this event | 1523 // Bail out if there is no listener for this event |
1523 if (!Debugger::EventActive(v8::Break)) return; | 1524 if (!Debugger::EventActive(v8::Break)) return; |
1524 | 1525 |
1525 // Debugger must be entered in advance. | 1526 // Debugger must be entered in advance. |
1526 ASSERT(Top::context() == *Debug::debug_context()); | 1527 ASSERT(Top::context() == *Debug::debug_context()); |
1527 | 1528 |
1528 // Create the event data object. | 1529 // Create the event data object. |
1529 bool caught_exception = false; | 1530 bool caught_exception = false; |
1530 Handle<Object> exec_state = MakeExecutionState(&caught_exception); | 1531 Handle<Object> exec_state = MakeExecutionState(&caught_exception); |
1531 Handle<Object> event_data; | 1532 Handle<Object> event_data; |
1532 if (!caught_exception) { | 1533 if (!caught_exception) { |
1533 event_data = MakeBreakEvent(exec_state, break_points_hit, | 1534 event_data = MakeBreakEvent(exec_state, break_points_hit, |
1534 &caught_exception); | 1535 &caught_exception); |
1535 } | 1536 } |
1536 // Bail out and don't call debugger if exception. | 1537 // Bail out and don't call debugger if exception. |
1537 if (caught_exception) { | 1538 if (caught_exception) { |
1538 return; | 1539 return; |
1539 } | 1540 } |
1540 | 1541 |
1541 // Process debug event | 1542 // Process debug event |
1542 ProcessDebugEvent(v8::Break, event_data); | 1543 ProcessDebugEvent(v8::Break, event_data, auto_continue); |
1543 } | 1544 } |
1544 | 1545 |
1545 | 1546 |
1546 void Debugger::OnBeforeCompile(Handle<Script> script) { | 1547 void Debugger::OnBeforeCompile(Handle<Script> script) { |
1547 HandleScope scope; | 1548 HandleScope scope; |
1548 | 1549 |
1549 // Bail out based on state or if there is no listener for this event | 1550 // Bail out based on state or if there is no listener for this event |
1550 if (Debug::InDebugger()) return; | 1551 if (Debug::InDebugger()) return; |
1551 if (compiling_natives()) return; | 1552 if (compiling_natives()) return; |
1552 if (!EventActive(v8::BeforeCompile)) return; | 1553 if (!EventActive(v8::BeforeCompile)) return; |
1553 | 1554 |
1554 // Enter the debugger. | 1555 // Enter the debugger. |
1555 EnterDebugger debugger; | 1556 EnterDebugger debugger; |
1556 if (debugger.FailedToEnter()) return; | 1557 if (debugger.FailedToEnter()) return; |
1557 | 1558 |
1558 // Create the event data object. | 1559 // Create the event data object. |
1559 bool caught_exception = false; | 1560 bool caught_exception = false; |
1560 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception); | 1561 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception); |
1561 // Bail out and don't call debugger if exception. | 1562 // Bail out and don't call debugger if exception. |
1562 if (caught_exception) { | 1563 if (caught_exception) { |
1563 return; | 1564 return; |
1564 } | 1565 } |
1565 | 1566 |
1566 // Process debug event | 1567 // Process debug event |
1567 ProcessDebugEvent(v8::BeforeCompile, event_data); | 1568 ProcessDebugEvent(v8::BeforeCompile, event_data, false); |
1568 } | 1569 } |
1569 | 1570 |
1570 | 1571 |
1571 // Handle debugger actions when a new script is compiled. | 1572 // Handle debugger actions when a new script is compiled. |
1572 void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) { | 1573 void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) { |
1573 HandleScope scope; | 1574 HandleScope scope; |
1574 | 1575 |
1575 // No compile events while compiling natives. | 1576 // No compile events while compiling natives. |
1576 if (compiling_natives()) return; | 1577 if (compiling_natives()) return; |
1577 | 1578 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1618 | 1619 |
1619 // Create the compile state object. | 1620 // Create the compile state object. |
1620 Handle<Object> event_data = MakeCompileEvent(script, | 1621 Handle<Object> event_data = MakeCompileEvent(script, |
1621 false, | 1622 false, |
1622 &caught_exception); | 1623 &caught_exception); |
1623 // Bail out and don't call debugger if exception. | 1624 // Bail out and don't call debugger if exception. |
1624 if (caught_exception) { | 1625 if (caught_exception) { |
1625 return; | 1626 return; |
1626 } | 1627 } |
1627 // Process debug event | 1628 // Process debug event |
1628 ProcessDebugEvent(v8::AfterCompile, event_data); | 1629 ProcessDebugEvent(v8::AfterCompile, event_data, false); |
1629 } | 1630 } |
1630 | 1631 |
1631 | 1632 |
1632 void Debugger::OnNewFunction(Handle<JSFunction> function) { | 1633 void Debugger::OnNewFunction(Handle<JSFunction> function) { |
1633 return; | 1634 return; |
1634 HandleScope scope; | 1635 HandleScope scope; |
1635 | 1636 |
1636 // Bail out based on state or if there is no listener for this event | 1637 // Bail out based on state or if there is no listener for this event |
1637 if (Debug::InDebugger()) return; | 1638 if (Debug::InDebugger()) return; |
1638 if (compiling_natives()) return; | 1639 if (compiling_natives()) return; |
1639 if (!Debugger::EventActive(v8::NewFunction)) return; | 1640 if (!Debugger::EventActive(v8::NewFunction)) return; |
1640 | 1641 |
1641 // Enter the debugger. | 1642 // Enter the debugger. |
1642 EnterDebugger debugger; | 1643 EnterDebugger debugger; |
1643 if (debugger.FailedToEnter()) return; | 1644 if (debugger.FailedToEnter()) return; |
1644 | 1645 |
1645 // Create the event object. | 1646 // Create the event object. |
1646 bool caught_exception = false; | 1647 bool caught_exception = false; |
1647 Handle<Object> event_data = MakeNewFunctionEvent(function, &caught_exception); | 1648 Handle<Object> event_data = MakeNewFunctionEvent(function, &caught_exception); |
1648 // Bail out and don't call debugger if exception. | 1649 // Bail out and don't call debugger if exception. |
1649 if (caught_exception) { | 1650 if (caught_exception) { |
1650 return; | 1651 return; |
1651 } | 1652 } |
1652 // Process debug event. | 1653 // Process debug event. |
1653 ProcessDebugEvent(v8::NewFunction, event_data); | 1654 ProcessDebugEvent(v8::NewFunction, event_data, false); |
1654 } | 1655 } |
1655 | 1656 |
1656 | 1657 |
1657 void Debugger::ProcessDebugEvent(v8::DebugEvent event, | 1658 void Debugger::ProcessDebugEvent(v8::DebugEvent event, |
1658 Handle<Object> event_data) { | 1659 Handle<Object> event_data, |
| 1660 bool auto_continue) { |
1659 HandleScope scope; | 1661 HandleScope scope; |
1660 | 1662 |
1661 // Create the execution state. | 1663 // Create the execution state. |
1662 bool caught_exception = false; | 1664 bool caught_exception = false; |
1663 Handle<Object> exec_state = MakeExecutionState(&caught_exception); | 1665 Handle<Object> exec_state = MakeExecutionState(&caught_exception); |
1664 if (caught_exception) { | 1666 if (caught_exception) { |
1665 return; | 1667 return; |
1666 } | 1668 } |
1667 // First notify the builtin debugger. | 1669 // First notify the builtin debugger. |
1668 if (message_thread_ != NULL) { | 1670 if (message_thread_ != NULL) { |
1669 message_thread_->DebugEvent(event, exec_state, event_data); | 1671 message_thread_->DebugEvent(event, exec_state, event_data, auto_continue); |
1670 } | 1672 } |
1671 // Notify registered debug event listener. This can be either a C or a | 1673 // Notify registered debug event listener. This can be either a C or a |
1672 // JavaScript function. | 1674 // JavaScript function. |
1673 if (!event_listener_.is_null()) { | 1675 if (!event_listener_.is_null()) { |
1674 if (event_listener_->IsProxy()) { | 1676 if (event_listener_->IsProxy()) { |
1675 // C debug event listener. | 1677 // C debug event listener. |
1676 Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_)); | 1678 Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_)); |
1677 v8::DebugEventCallback callback = | 1679 v8::DebugEventCallback callback = |
1678 FUNCTION_CAST<v8::DebugEventCallback>(callback_obj->proxy()); | 1680 FUNCTION_CAST<v8::DebugEventCallback>(callback_obj->proxy()); |
1679 callback(event, | 1681 callback(event, |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1766 | 1768 |
1767 void Debugger::ProcessCommand(Vector<const uint16_t> command) { | 1769 void Debugger::ProcessCommand(Vector<const uint16_t> command) { |
1768 if (message_thread_ != NULL) { | 1770 if (message_thread_ != NULL) { |
1769 message_thread_->ProcessCommand( | 1771 message_thread_->ProcessCommand( |
1770 Vector<uint16_t>(const_cast<uint16_t *>(command.start()), | 1772 Vector<uint16_t>(const_cast<uint16_t *>(command.start()), |
1771 command.length())); | 1773 command.length())); |
1772 } | 1774 } |
1773 } | 1775 } |
1774 | 1776 |
1775 | 1777 |
| 1778 bool Debugger::HasCommands() { |
| 1779 if (message_thread_ != NULL) { |
| 1780 return message_thread_->HasCommands(); |
| 1781 } else { |
| 1782 return false; |
| 1783 } |
| 1784 } |
| 1785 |
| 1786 |
1776 void Debugger::ProcessHostDispatch(void* dispatch) { | 1787 void Debugger::ProcessHostDispatch(void* dispatch) { |
1777 if (message_thread_ != NULL) { | 1788 if (message_thread_ != NULL) { |
1778 message_thread_->ProcessHostDispatch(dispatch); | 1789 message_thread_->ProcessHostDispatch(dispatch); |
1779 } | 1790 } |
1780 } | 1791 } |
1781 | 1792 |
1782 | 1793 |
1783 void Debugger::UpdateActiveDebugger() { | 1794 void Debugger::UpdateActiveDebugger() { |
1784 set_debugger_active((message_thread_ != NULL && | 1795 set_debugger_active((message_thread_ != NULL && |
1785 message_handler_ != NULL) || | 1796 message_handler_ != NULL) || |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1897 Debugger::SendMessage(message); | 1908 Debugger::SendMessage(message); |
1898 } | 1909 } |
1899 } | 1910 } |
1900 } | 1911 } |
1901 | 1912 |
1902 | 1913 |
1903 // This method is called by the V8 thread whenever a debug event occurs in | 1914 // This method is called by the V8 thread whenever a debug event occurs in |
1904 // the VM. | 1915 // the VM. |
1905 void DebugMessageThread::DebugEvent(v8::DebugEvent event, | 1916 void DebugMessageThread::DebugEvent(v8::DebugEvent event, |
1906 Handle<Object> exec_state, | 1917 Handle<Object> exec_state, |
1907 Handle<Object> event_data) { | 1918 Handle<Object> event_data, |
| 1919 bool auto_continue) { |
1908 HandleScope scope; | 1920 HandleScope scope; |
1909 | 1921 |
1910 if (!Debug::Load()) return; | 1922 if (!Debug::Load()) return; |
1911 | 1923 |
1912 // Process the individual events. | 1924 // Process the individual events. |
1913 bool interactive = false; | 1925 bool interactive = false; |
1914 switch (event) { | 1926 switch (event) { |
1915 case v8::Break: | 1927 case v8::Break: |
1916 interactive = true; // Break event is always interactive | 1928 interactive = true; // Break event is always interactive |
1917 break; | 1929 break; |
(...skipping 22 matching lines...) Expand all Loading... |
1940 v8::Function::Cast(*api_exec_state->Get(fun_name)); | 1952 v8::Function::Cast(*api_exec_state->Get(fun_name)); |
1941 v8::TryCatch try_catch; | 1953 v8::TryCatch try_catch; |
1942 v8::Local<v8::Object> cmd_processor = | 1954 v8::Local<v8::Object> cmd_processor = |
1943 v8::Object::Cast(*fun->Call(api_exec_state, 0, NULL)); | 1955 v8::Object::Cast(*fun->Call(api_exec_state, 0, NULL)); |
1944 if (try_catch.HasCaught()) { | 1956 if (try_catch.HasCaught()) { |
1945 PrintLn(try_catch.Exception()); | 1957 PrintLn(try_catch.Exception()); |
1946 return; | 1958 return; |
1947 } | 1959 } |
1948 | 1960 |
1949 // Notify the debugger that a debug event has occurred. | 1961 // Notify the debugger that a debug event has occurred. |
1950 bool success = SetEventJSONFromEvent(event_data); | 1962 if (!auto_continue) { |
1951 if (!success) { | 1963 bool success = SetEventJSONFromEvent(event_data); |
1952 // If failed to notify debugger just continue running. | 1964 if (!success) { |
1953 return; | 1965 // If failed to notify debugger just continue running. |
| 1966 return; |
| 1967 } |
1954 } | 1968 } |
1955 | 1969 |
1956 // Wait for requests from the debugger. | 1970 // Process requests from the debugger. |
1957 host_running_ = false; | 1971 host_running_ = false; |
1958 while (true) { | 1972 while (true) { |
| 1973 // Wait for new command in the queue. |
1959 command_received_->Wait(); | 1974 command_received_->Wait(); |
| 1975 |
| 1976 // The debug command interrupt flag might have been set when the command was |
| 1977 // added. |
| 1978 StackGuard::Continue(DEBUGCOMMAND); |
| 1979 |
| 1980 // Get the command from the queue. |
| 1981 Vector<uint16_t> command = command_queue_.Get(); |
1960 Logger::DebugTag("Got request from command queue, in interactive loop."); | 1982 Logger::DebugTag("Got request from command queue, in interactive loop."); |
1961 Vector<uint16_t> command = command_queue_.Get(); | |
1962 ASSERT(!host_running_); | 1983 ASSERT(!host_running_); |
1963 if (!Debugger::debugger_active()) { | 1984 if (!Debugger::debugger_active()) { |
1964 host_running_ = true; | 1985 host_running_ = true; |
1965 return; | 1986 return; |
1966 } | 1987 } |
1967 | 1988 |
1968 // Check if the command is a host dispatch. | 1989 // Check if the command is a host dispatch. |
1969 if (command[0] == 0) { | 1990 if (command[0] == 0) { |
1970 if (Debugger::host_dispatch_handler_) { | 1991 if (Debugger::host_dispatch_handler_) { |
1971 int32_t dispatch = (command[1] << 16) | command[2]; | 1992 int32_t dispatch = (command[1] << 16) | command[2]; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2024 Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val), | 2045 Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val), |
2025 response->Length()); | 2046 response->Length()); |
2026 | 2047 |
2027 // Set host_running_ correctly for nested debugger evaluations. | 2048 // Set host_running_ correctly for nested debugger evaluations. |
2028 host_running_ = running; | 2049 host_running_ = running; |
2029 | 2050 |
2030 // Return the result. | 2051 // Return the result. |
2031 SendMessage(str); | 2052 SendMessage(str); |
2032 | 2053 |
2033 // Return from debug event processing is VM should be running. | 2054 // Return from debug event processing is VM should be running. |
2034 if (running) { | 2055 if (running || (auto_continue && !HasCommands())) { |
2035 return; | 2056 return; |
2036 } | 2057 } |
2037 } | 2058 } |
2038 } | 2059 } |
2039 | 2060 |
2040 | 2061 |
2041 // Puts a command coming from the public API on the queue. Creates | 2062 // Puts a command coming from the public API on the queue. Creates |
2042 // a copy of the command string managed by the debugger. Up to this | 2063 // a copy of the command string managed by the debugger. Up to this |
2043 // point, the command data was managed by the API client. Called | 2064 // point, the command data was managed by the API client. Called |
2044 // by the API client thread. This is where the API client hands off | 2065 // by the API client thread. This is where the API client hands off |
2045 // processing of the command to the DebugMessageThread thread. | 2066 // processing of the command to the DebugMessageThread thread. |
2046 // The new copy of the command is destroyed in HandleCommand(). | 2067 // The new copy of the command is destroyed in HandleCommand(). |
2047 void DebugMessageThread::ProcessCommand(Vector<uint16_t> command) { | 2068 void DebugMessageThread::ProcessCommand(Vector<uint16_t> command) { |
2048 Vector<uint16_t> command_copy = command.Clone(); | 2069 Vector<uint16_t> command_copy = command.Clone(); |
2049 Logger::DebugTag("Put command on command_queue."); | 2070 Logger::DebugTag("Put command on command_queue."); |
2050 command_queue_.Put(command_copy); | 2071 command_queue_.Put(command_copy); |
2051 command_received_->Signal(); | 2072 command_received_->Signal(); |
| 2073 |
| 2074 if (!Debug::InDebugger()) { |
| 2075 StackGuard::DebugCommand(); |
| 2076 } |
2052 } | 2077 } |
2053 | 2078 |
2054 | 2079 |
2055 // Puts a host dispatch comming from the public API on the queue. | 2080 // Puts a host dispatch comming from the public API on the queue. |
2056 void DebugMessageThread::ProcessHostDispatch(void* dispatch) { | 2081 void DebugMessageThread::ProcessHostDispatch(void* dispatch) { |
2057 uint16_t hack[3]; | 2082 uint16_t hack[3]; |
2058 hack[0] = 0; | 2083 hack[0] = 0; |
2059 hack[1] = reinterpret_cast<uint32_t>(dispatch) >> 16; | 2084 hack[1] = reinterpret_cast<uint32_t>(dispatch) >> 16; |
2060 hack[2] = reinterpret_cast<uint32_t>(dispatch) & 0xFFFF; | 2085 hack[2] = reinterpret_cast<uint32_t>(dispatch) & 0xFFFF; |
2061 Logger::DebugTag("Put dispatch on command_queue."); | 2086 Logger::DebugTag("Put dispatch on command_queue."); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2143 } | 2168 } |
2144 | 2169 |
2145 | 2170 |
2146 void LockingMessageQueue::Clear() { | 2171 void LockingMessageQueue::Clear() { |
2147 ScopedLock sl(lock_); | 2172 ScopedLock sl(lock_); |
2148 queue_.Clear(); | 2173 queue_.Clear(); |
2149 } | 2174 } |
2150 | 2175 |
2151 | 2176 |
2152 } } // namespace v8::internal | 2177 } } // namespace v8::internal |
OLD | NEW |