Ticket #2973: 2973_continuation1.patch

File 2973_continuation1.patch, 61.0 KB (added by Bernard, 8 years ago)

Hi, I fixed the gc roots. The game builds completely now but the ThrowHook doesn't seem to get called. I think this is due to the spidermonkey library. I would like to submit the patch for your review. Cheers!

  • source/ps/GameSetup/Config.cpp

     
    109109    CFG_GET_VAL("jsdebugger.enable", g_JSDebuggerEnabled);
    110110    CFG_GET_VAL("profiler2.script.enable", g_ScriptProfilingEnabled);
    111111
    112     if (g_JSDebuggerEnabled)
    113         LOGERROR("JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)");
     112    //if (g_JSDebuggerEnabled)
     113    //  LOGERROR("JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)");
    114114    // Script Debugging and profiling does not make sense together because of the hooks
    115115    // that reduce performance a lot - and it wasn't tested if it even works together.
    116116    if (g_JSDebuggerEnabled && g_ScriptProfilingEnabled)
  • source/ps/GameSetup/GameSetup.cpp

     
    734734
    735735
    736736    // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    737     //TIMER_BEGIN(L"shutdown DebuggingServer (if active)");
    738     //delete g_DebuggingServer;
    739     //TIMER_END(L"shutdown DebuggingServer (if active)");
     737    TIMER_BEGIN(L"shutdown DebuggingServer (if active)");
     738    delete g_DebuggingServer;
     739    TIMER_END(L"shutdown DebuggingServer (if active)");
    740740
    741741    delete &g_L10n;
    742742
     
    963963
    964964    // before scripting
    965965    // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    966     //if (g_JSDebuggerEnabled)
    967     //  g_DebuggingServer = new CDebuggingServer();
     966    if (g_JSDebuggerEnabled)
     967        g_DebuggingServer = new CDebuggingServer();
    968968
    969969    // Optionally start profiler HTTP output automatically
    970970    // (By default it's only enabled by a hotkey, for security/performance)
  • source/scriptinterface/DebuggingServer.cpp

     
    1717 
    1818// JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    1919#include "precompiled.h" // needs to be here for Windows builds
    20 /*
     20
    2121
    2222#include "DebuggingServer.h"
    2323#include "ThreadDebugger.h"
     
    174174    return m_SettingSimultaneousThreadBreak;
    175175}
    176176
    177 
    178177static Status AddFileResponse(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
    179178{
    180179    std::vector<std::string>& templates = *(std::vector<std::string>*)cbData;
     
    252251        {
    253252            EnumVfsJSFiles(stream);
    254253        }
     254        else if (uri == "/GetFile")
     255        {
     256            std::string filename;
     257            if (!GetWebArgs(conn, request_info, "filename", filename))
     258                return handled;
     259            GetFile(filename, stream);
     260        }
     261        else if (uri == "/ToggleBreakpoint")
     262        {
     263            std::string filename;
     264            uint line;
     265            if (!GetWebArgs(conn, request_info, "filename", filename) ||
     266                !GetWebArgs(conn, request_info, "line", line))
     267            {
     268                return handled;
     269            }
     270            ToggleBreakPoint(filename, line);
     271        }
    255272        else if (uri == "/GetAllCallstacks")
    256273        {
    257274            GetAllCallstacks(stream);
     
    262279            if (!GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID))
    263280                return handled;
    264281            // TODO: handle the return value
    265             SetNextDbgCmd(threadDebuggerID, DBG_CMD_CONTINUE); 
     282            SetNextDbgCmd(threadDebuggerID, DBG_CMD_CONTINUE);
    266283        }
    267284        else if (uri == "/Break")
    268285        {
    269286            SetBreakRequestedByUser(true);
    270287        }
    271         else if (uri == "/SetSettingSimultaneousThreadBreak")
    272         {
    273             std::string strEnabled;
    274             bool bEnabled = false;
    275             if (!GetWebArgs(conn, request_info, "enabled", strEnabled))
    276                 return handled;
    277             // TODO: handle the return value
    278             if (strEnabled == "true")
    279                 bEnabled = true;
    280             else if (strEnabled == "false")
    281                 bEnabled = false;
    282             else
    283                 return handled; // TODO: return an error state
    284             SetSettingSimultaneousThreadBreak(bEnabled);
    285         }
    286         else if (uri == "/GetSettingSimultaneousThreadBreak")
    287         {
    288             stream << "{ \"Enabled\" : " << (GetSettingSimultaneousThreadBreak() ? "true" : "false") << " } ";
    289         }
    290         else if (uri == "/SetSettingBreakOnException")
    291         {
    292             std::string strEnabled;
    293             bool bEnabled = false;
    294             if (!GetWebArgs(conn, request_info, "enabled", strEnabled))
    295                 return handled;
    296             // TODO: handle the return value
    297             if (strEnabled == "true")
    298                 bEnabled = true;
    299             else if (strEnabled == "false")
    300                 bEnabled = false;
    301             else
    302                 return handled; // TODO: return an error state
    303             SetSettingBreakOnException(bEnabled);
    304         }
    305         else if (uri == "/GetSettingBreakOnException")
    306         {
    307             stream << "{ \"Enabled\" : " << (GetSettingBreakOnException() ? "true" : "false") << " } ";
    308         }
    309288        else if (uri == "/Step")
    310289        {
    311290            uint threadDebuggerID;
     
    334313        {
    335314            uint nestingLevel;
    336315            uint threadDebuggerID;
    337             if (!GetWebArgs(conn, request_info, "nestingLevel", nestingLevel) || 
     316            if (!GetWebArgs(conn, request_info, "nestingLevel", nestingLevel) ||
    338317                !GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID))
    339318            {
    340319                return handled;
     
    345324        {
    346325            uint nestingLevel;
    347326            uint threadDebuggerID;
    348             if (!GetWebArgs(conn, request_info, "nestingLevel", nestingLevel) || 
     327            if (!GetWebArgs(conn, request_info, "nestingLevel", nestingLevel) ||
    349328                !GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID))
    350329            {
    351330                return handled;
     
    352331            }
    353332            GetStackFrameData(stream, nestingLevel, threadDebuggerID, STACK_INFO_THIS);
    354333        }
     334        else if (uri == "/SetSettingSimultaneousThreadBreak")
     335        {
     336            std::string strEnabled;
     337            bool bEnabled = false;
     338            if (!GetWebArgs(conn, request_info, "enabled", strEnabled))
     339                return handled;
     340            // TODO: handle the return value
     341            if (strEnabled == "true")
     342                bEnabled = true;
     343            else if (strEnabled == "false")
     344                bEnabled = false;
     345            else
     346                return handled; // TODO: return an error state
     347            SetSettingSimultaneousThreadBreak(bEnabled);
     348        }
     349        else if (uri == "/GetSettingSimultaneousThreadBreak")
     350        {
     351            stream << "{ \"Enabled\" : " << (GetSettingSimultaneousThreadBreak() ? "true" : "false") << " } ";
     352        }
     353        else if (uri == "/SetSettingBreakOnException")
     354        {
     355            std::string strEnabled;
     356            bool bEnabled = false;
     357            if (!GetWebArgs(conn, request_info, "enabled", strEnabled))
     358                return handled;
     359            // TODO: handle the return value
     360            if (strEnabled == "true")
     361                bEnabled = true;
     362            else if (strEnabled == "false")
     363                bEnabled = false;
     364            else
     365                return handled; // TODO: return an error state
     366            SetSettingBreakOnException(bEnabled);
     367        }
     368        else if (uri == "/GetSettingBreakOnException")
     369        {
     370            //stream << "{ \"Enabled\" : " << (GetSettingBreakOnException() ? "true" : "false") << " } ";
     371        }
    355372        else if (uri == "/GetCurrentGlobalObject")
    356373        {
    357374            uint threadDebuggerID;
     
    361378            }
    362379            GetStackFrameData(stream, 0, threadDebuggerID, STACK_INFO_GLOBALOBJECT);
    363380        }
    364         else if (uri == "/ToggleBreakpoint")
    365         {
    366             std::string filename;
    367             uint line;
    368             if (!GetWebArgs(conn, request_info, "filename", filename) ||
    369                 !GetWebArgs(conn, request_info, "line", line))
    370             {
    371                 return handled;
    372             }
    373             ToggleBreakPoint(filename, line);
    374         }
    375         else if (uri == "/GetFile")
    376         {
    377             std::string filename;
    378             if (!GetWebArgs(conn, request_info, "filename", filename))
    379                 return handled;
    380             GetFile(filename, stream);
    381         }
    382381        else
    383382        {
    384383            mg_printf(conn, "%s", header404);
     
    568567    ENSURE(m_BreakPointsLockID == breakPointsLockID);
    569568    SDL_SemPost(m_BreakPointsSem);
    570569}
    571 */
    572  No newline at end of file
  • source/scriptinterface/DebuggingServer.h

     
    11/* Copyright (C) 2013 Wildfire Games.
    2  * This file is part of 0 A.D.
    3  *
    4  * 0 A.D. is free software: you can redistribute it and/or modify
    5  * it under the terms of the GNU General Public License as published by
    6  * the Free Software Foundation, either version 2 of the License, or
    7  * (at your option) any later version.
    8  *
    9  * 0 A.D. is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
    16  */
     2* This file is part of 0 A.D.
     3*
     4* 0 A.D. is free software: you can redistribute it and/or modify
     5* it under the terms of the GNU General Public License as published by
     6* the Free Software Foundation, either version 2 of the License, or
     7* (at your option) any later version.
     8*
     9* 0 A.D. is distributed in the hope that it will be useful,
     10* but WITHOUT ANY WARRANTY; without even the implied warranty of
     11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12* GNU General Public License for more details.
     13*
     14* You should have received a copy of the GNU General Public License
     15* along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
     16*/
    1717
    1818// JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    1919
    20 //#ifndef INCLUDED_DEBUGGINGSERVER
    21 //#define INCLUDED_DEBUGGINGSERVER
    22 //
    23 //#include "third_party/mongoose/mongoose.h"
    24 //#include "ScriptInterface.h"
    25 //
    26 //#include "lib/external_libraries/libsdl.h"
    27 //
    28 //class CBreakPoint;
    29 //class CThreadDebugger;
    30 //
    31 //enum DBGCMD { DBG_CMD_NONE=0, DBG_CMD_CONTINUE, DBG_CMD_SINGLESTEP, DBG_CMD_STEPINTO, DBG_CMD_STEPOUT };
    32 //enum STACK_INFO { STACK_INFO_LOCALS=0, STACK_INFO_THIS, STACK_INFO_GLOBALOBJECT };
    33 //
    34 //class CDebuggingServer
    35 //{
    36 //public:
    37 //  CDebuggingServer();
    38 //  ~CDebuggingServer();
    39 // 
    40 //  /** @brief Register a new ScriptInerface for debugging the scripts it executes
    41 //   *
    42 //   * @param name A name for the ScriptInterface (will be sent to the debugging client an probably displayed to the user)
    43 //   * @param pScriptInterface A pointer to the ScriptInterface. This pointer must stay valid until UnRegisterScriptInterface ist called!
    44 //   */
    45 //  void RegisterScriptinterface(std::string name, ScriptInterface* pScriptInterface);
    46 // 
    47 //  /** @brief Unregister a ScriptInerface that was previously registered using RegisterScriptinterface.
    48 //   *
    49 //   * @param pScriptInterface A pointer to the ScriptInterface
    50 //   */
    51 //  void UnRegisterScriptinterface(ScriptInterface* pScriptInterface);
    52 //
    53 // 
    54 //  // Mongoose callback when request comes from a client
    55 //  void* MgDebuggingServerCallback(mg_event event, struct mg_connection *conn, const struct mg_request_info *request_info);   
    56 // 
    57 //  /** @brief Aquire exclusive read and write access to the list of breakpoints.
    58 //   *
    59 //   * @param breakPoints A pointer to the list storing all breakpoints.
    60 //   *
    61 //   * @return  A number you need to pass to ReleaseBreakPointAccess().
    62 //   *
    63 //   * Make sure to call ReleaseBreakPointAccess after you don't need access any longer.
    64 //   * Using this function you get exclusive access and other threads won't be able to access the breakpoints until you call ReleaseBreakPointAccess!
    65 //   */
    66 //  double AquireBreakPointAccess(std::list<CBreakPoint>** breakPoints);
    67 // 
    68 //  /** @brief See AquireBreakPointAccess(). You must not access the pointer returend by AquireBreakPointAccess() any longer after you call this function.
    69 //   * 
    70 //   * @param breakPointsLockID The number you got when aquiring the access. It's used to make sure that this function never gets
    71 //   *          used by the wrong thread.       
    72 //   */
    73 //  void ReleaseBreakPointAccess(double breakPointsLockID);
    74 // 
    75 // 
    76 //  /// Called from multiple Mongoose threads and multiple ScriptInterface threads
    77 //  bool GetBreakRequestedByThread();
    78 //  bool GetBreakRequestedByUser();
    79 //  // Should other threads be stopped as soon as possible after a breakpoint is triggered in a thread
    80 //  bool GetSettingSimultaneousThreadBreak();
    81 //  // Should the debugger break on any JS-Exception? If set to false, it will only break when the exceptions text is "Breakpoint".
    82 //  bool GetSettingBreakOnException();
    83 //  void SetBreakRequestedByThread(bool Enabled);
    84 //  void SetBreakRequestedByUser(bool Enabled);
    85 // 
    86 //private:
    87 //  static const char* header400;
    88 //
    89 //  /// Webserver helper function (can be called by multiple mongooser threads)
    90 //  bool GetWebArgs(struct mg_connection *conn, const struct mg_request_info* request_info, std::string argName, uint& arg);
    91 //  bool GetWebArgs(struct mg_connection *conn, const struct mg_request_info* request_info, std::string argName, std::string& arg);
    92 // 
    93 //  /// Functions that are made available via http (can be called by multiple mongoose threads)
    94 //  void GetThreadDebuggerStatus(std::stringstream& response);
    95 //  void ToggleBreakPoint(std::string filename, uint line);
    96 //  void GetAllCallstacks(std::stringstream& response);
    97 //  void GetStackFrameData(std::stringstream& response, uint nestingLevel, uint threadDebuggerID, STACK_INFO stackInfoKind);
    98 //  bool SetNextDbgCmd(uint threadDebuggerID, DBGCMD dbgCmd);
    99 //  void SetSettingSimultaneousThreadBreak(bool Enabled);
    100 //  void SetSettingBreakOnException(bool Enabled);
    101 // 
    102 //  /** @brief Returns a list of the full vfs paths to all files with the extension .js found in the vfs root
    103 //   *
    104 //   *  @param response This will contain the list as JSON array.
    105 //   */
    106 //  void EnumVfsJSFiles(std::stringstream& response);
    107 // 
    108 //  /** @brief Get the content of a .js file loaded into vfs
    109 //   *
    110 //   * @param filename A full vfs path (as returned by EnumVfsJSFiles).
    111 //   * @param response This will contain the contents of the requested file.
    112 //   */
    113 //  void GetFile(std::string filename, std::stringstream& response);
    114 // 
    115 //  /// Shared between multiple mongoose threads
    116 // 
    117 //
    118 //  bool m_SettingSimultaneousThreadBreak;
    119 //  bool m_SettingBreakOnException;
    120 // 
    121 //  /// Shared between multiple scriptinterface threads
    122 //  uint m_LastThreadDebuggerID;
    123 // 
    124 //  /// Shared between multiple scriptinerface threads and multiple mongoose threads
    125 //  std::list<CThreadDebugger*> m_ThreadDebuggers;
    126 // 
    127 //  // The CThreadDebuggers will check this value and break the thread if it's true.
    128 //  // This only works for JS code, so C++ code will not break until it executes JS-code again.
    129 //  bool m_BreakRequestedByThread;
    130 //  bool m_BreakRequestedByUser;
    131 // 
    132 //  // The breakpoint is uniquely identified using filename an line-number.
    133 //  // Since the filename is the whole vfs path it should really be unique.
    134 //  std::list<CBreakPoint> m_BreakPoints;
    135 // 
    136 //  /// Used for controlling access to m_BreakPoints
    137 //  SDL_sem* m_BreakPointsSem;
    138 //  double m_BreakPointsLockID;
    139 // 
    140 //  /// Mutexes used to ensure thread-safety. Currently we just use one Mutex (m_Mutex) and if we detect possible sources
    141 //  /// of deadlocks, we use the second mutex for some members to avoid it.
    142 //  CMutex m_Mutex;
    143 //  CMutex m_Mutex1;
    144 // 
    145 //  /// Not important for this class' thread-safety
    146 //  void EnableHTTP();
    147 //  mg_context* m_MgContext;
    148 //};
    149 //
    150 //extern CDebuggingServer* g_DebuggingServer;
    151 //
    152 //
    153 //#endif // INCLUDED_DEBUGGINGSERVER
     20#ifndef INCLUDED_DEBUGGINGSERVER
     21#define INCLUDED_DEBUGGINGSERVER
     22
     23#include "third_party/mongoose/mongoose.h"
     24#include "ScriptInterface.h"
     25
     26#include "lib/external_libraries/libsdl.h"
     27
     28class CBreakPoint;
     29class CThreadDebugger;
     30
     31enum DBGCMD { DBG_CMD_NONE = 0, DBG_CMD_CONTINUE, DBG_CMD_SINGLESTEP, DBG_CMD_STEPINTO, DBG_CMD_STEPOUT };
     32enum STACK_INFO { STACK_INFO_LOCALS = 0, STACK_INFO_THIS, STACK_INFO_GLOBALOBJECT };
     33
     34class CDebuggingServer
     35{
     36public:
     37    CDebuggingServer();
     38    ~CDebuggingServer();
     39
     40    /** @brief Register a new ScriptInerface for debugging the scripts it executes
     41    *
     42    * @param name A name for the ScriptInterface (will be sent to the debugging client an probably displayed to the user)
     43    * @param pScriptInterface A pointer to the ScriptInterface. This pointer must stay valid until UnRegisterScriptInterface ist called!
     44    */
     45    void RegisterScriptinterface(std::string name, ScriptInterface* pScriptInterface);
     46
     47    /** @brief Unregister a ScriptInerface that was previously registered using RegisterScriptinterface.
     48    *
     49    * @param pScriptInterface A pointer to the ScriptInterface
     50    */
     51    void UnRegisterScriptinterface(ScriptInterface* pScriptInterface);
     52
     53
     54    // Mongoose callback when request comes from a client
     55    void* MgDebuggingServerCallback(mg_event event, struct mg_connection *conn, const struct mg_request_info *request_info);
     56
     57    /** @brief Aquire exclusive read and write access to the list of breakpoints.
     58    *
     59    * @param breakPoints A pointer to the list storing all breakpoints.
     60    *
     61    * @return  A number you need to pass to ReleaseBreakPointAccess().
     62    *
     63    * Make sure to call ReleaseBreakPointAccess after you don't need access any longer.
     64    * Using this function you get exclusive access and other threads won't be able to access the breakpoints until you call ReleaseBreakPointAccess!
     65    */
     66    double AquireBreakPointAccess(std::list<CBreakPoint>** breakPoints);
     67
     68    /** @brief See AquireBreakPointAccess(). You must not access the pointer returend by AquireBreakPointAccess() any longer after you call this function.
     69    *
     70    * @param breakPointsLockID The number you got when aquiring the access. It's used to make sure that this function never gets
     71    *          used by the wrong thread.
     72    */
     73    void ReleaseBreakPointAccess(double breakPointsLockID);
     74
     75
     76    /// Called from multiple Mongoose threads and multiple ScriptInterface threads
     77    bool GetBreakRequestedByThread();
     78    bool GetBreakRequestedByUser();
     79    // Should other threads be stopped as soon as possible after a breakpoint is triggered in a thread
     80    bool GetSettingSimultaneousThreadBreak();
     81    // Should the debugger break on any JS-Exception? If set to false, it will only break when the exceptions text is "Breakpoint".
     82    bool GetSettingBreakOnException();
     83    void SetBreakRequestedByThread(bool Enabled);
     84    void SetBreakRequestedByUser(bool Enabled);
     85
     86private:
     87    static const char* header400;
     88
     89    /// Webserver helper function (can be called by multiple mongooser threads)
     90    bool GetWebArgs(struct mg_connection *conn, const struct mg_request_info* request_info, std::string argName, uint& arg);
     91    bool GetWebArgs(struct mg_connection *conn, const struct mg_request_info* request_info, std::string argName, std::string& arg);
     92
     93    /// Functions that are made available via http (can be called by multiple mongoose threads)
     94    void GetThreadDebuggerStatus(std::stringstream& response);
     95    void ToggleBreakPoint(std::string filename, uint line);
     96    void GetAllCallstacks(std::stringstream& response);
     97    void GetStackFrameData(std::stringstream& response, uint nestingLevel, uint threadDebuggerID, STACK_INFO stackInfoKind);
     98    bool SetNextDbgCmd(uint threadDebuggerID, DBGCMD dbgCmd);
     99    void SetSettingSimultaneousThreadBreak(bool Enabled);
     100    void SetSettingBreakOnException(bool Enabled);
     101
     102    /** @brief Returns a list of the full vfs paths to all files with the extension .js found in the vfs root
     103    *
     104    *  @param response This will contain the list as JSON array.
     105    */
     106    void EnumVfsJSFiles(std::stringstream& response);
     107
     108    /** @brief Get the content of a .js file loaded into vfs
     109    *
     110    * @param filename A full vfs path (as returned by EnumVfsJSFiles).
     111    * @param response This will contain the contents of the requested file.
     112    */
     113    void GetFile(std::string filename, std::stringstream& response);
     114
     115    /// Shared between multiple mongoose threads
     116
     117
     118    bool m_SettingSimultaneousThreadBreak;
     119    bool m_SettingBreakOnException;
     120
     121    /// Shared between multiple scriptinterface threads
     122    uint m_LastThreadDebuggerID;
     123
     124    /// Shared between multiple scriptinerface threads and multiple mongoose threads
     125    std::list<CThreadDebugger*> m_ThreadDebuggers;
     126
     127    // The CThreadDebuggers will check this value and break the thread if it's true.
     128    // This only works for JS code, so C++ code will not break until it executes JS-code again.
     129    bool m_BreakRequestedByThread;
     130    bool m_BreakRequestedByUser;
     131
     132    // The breakpoint is uniquely identified using filename an line-number.
     133    // Since the filename is the whole vfs path it should really be unique.
     134    std::list<CBreakPoint> m_BreakPoints;
     135
     136    /// Used for controlling access to m_BreakPoints
     137    SDL_sem* m_BreakPointsSem;
     138    double m_BreakPointsLockID;
     139
     140    /// Mutexes used to ensure thread-safety. Currently we just use one Mutex (m_Mutex) and if we detect possible sources
     141    /// of deadlocks, we use the second mutex for some members to avoid it.
     142    CMutex m_Mutex;
     143    CMutex m_Mutex1;
     144
     145    /// Not important for this class' thread-safety
     146    void EnableHTTP();
     147    mg_context* m_MgContext;
     148};
     149
     150extern CDebuggingServer* g_DebuggingServer;
     151
     152
     153#endif // INCLUDED_DEBUGGINGSERVER
  • source/scriptinterface/ScriptInterface.cpp

     
    1919
    2020#include "ScriptInterface.h"
    2121#include "ScriptRuntime.h"
    22 // #include "DebuggingServer.h" // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
     22#include "DebuggingServer.h" // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    2323#include "ScriptStats.h"
    2424
    2525#include "lib/debug.h"
     
    403403    }
    404404   
    405405    // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    406     /*
     406   
    407407    if (g_JSDebuggerEnabled && g_DebuggingServer != NULL)
    408408    {
    409         if(!JS_SetDebugMode(GetContext(), true))
     409        if(!JS_SetDebugModeForAllCompartments(GetContext(), true))
    410410            LOGERROR("Failed to set Spidermonkey to debug mode!");
    411411        else
    412412            g_DebuggingServer->RegisterScriptinterface(debugName, this);
    413     } */
     413    }
    414414
    415415    m_CxPrivate.pScriptInterface = this;
    416416    JS_SetContextPrivate(m->m_cx, (void*)&m_CxPrivate);
     
    426426   
    427427    // Unregister from the Debugger class
    428428    // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    429     //if (g_JSDebuggerEnabled && g_DebuggingServer != NULL)
    430     //  g_DebuggingServer->UnRegisterScriptinterface(this);
     429    if (g_JSDebuggerEnabled && g_DebuggingServer != NULL)
     430        g_DebuggingServer->UnRegisterScriptinterface(this);
    431431}
    432432
    433433void ScriptInterface::ShutDown()
  • source/scriptinterface/ThreadDebugger.cpp

     
    1717 
    1818 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    1919#include "precompiled.h" // needs to be here for Windows builds
    20  /*
     20 
    2121
    2222#include "ThreadDebugger.h"
    2323#include "lib/utf8.h"
     
    2626#include <map>
    2727#include <queue>
    2828
     29//Operators
     30bool operator==(JS::FrameDescription& a, JS::FrameDescription& b)
     31{
     32    return a.funDisplayName() == b.funDisplayName();
     33}
     34
     35bool operator!=(JS::FrameDescription& a, JS::FrameDescription& b)
     36{
     37    return a.funDisplayName() != b.funDisplayName();
     38}
    2939// Hooks
    3040
    3141CMutex ThrowHandlerMutex;
     
    3747}
    3848
    3949CMutex TrapHandlerMutex;
    40 static JSTrapStatus TrapHandler_(JSContext* cx, JSScript* script, jsbytecode* pc, jsval* rval, jsval closure) 
     50static JSTrapStatus TrapHandler_(JSContext* cx, JSScript* script, jsbytecode* pc, jsval* rval, jsval closure)
    4151{
    4252    CScopeLock lock(TrapHandlerMutex);
    4353    CThreadDebugger* pThreadDebugger = (CThreadDebugger*) JSVAL_TO_PRIVATE(closure);
     
    7181}
    7282
    7383CMutex DestroyScriptHookMutex;
    74 void DestroyScriptHook_(JSContext* cx, JSScript* script, void* callerdata)
     84void DestroyScriptHook_(JSFreeOp* UNUSED(fop), JSScript* script, void* callerdata)
    7585{
    7686    CScopeLock lock(DestroyScriptHookMutex);
    7787    CThreadDebugger* pThreadDebugger = (CThreadDebugger*) callerdata;
    78     return pThreadDebugger->DestroyScriptHook(cx, script);
     88
     89    return pThreadDebugger->DestroyScriptHook(NULL, script);
    7990}
    8091
    8192CMutex StepOutHandlerMutex;
     
    94105    return pThreadDebugger->CheckForBreakRequestHandler(cx, script, pc, rval, NULL);
    95106}
    96107
     108
    97109CMutex CallHookMutex;
    98 static void* CallHook_(JSContext* cx, JSStackFrame* fp, bool before, bool* UNUSED(ok), void* closure)
     110//static void* CallHook_(JSContext* cx, JSAbstractFramePtr* fp, bool isConstructing, bool before, bool* UNUSED(ok), void* closure)
     111static void* CallHook_(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, bool before, bool *ok, void *closure)
    99112{
    100113    CScopeLock lock(CallHookMutex);
    101114    CThreadDebugger* pThreadDebugger = (CThreadDebugger*) closure;
     
    102115    if (before)
    103116    {
    104117        JSScript* script;
    105         script = JS_GetFrameScript(cx, fp);
    106         const char* fileName = JS_GetScriptFilename(cx, script);
     118        script = frame.script();
     119        const char* fileName = JS_GetScriptFilename(script);
     120
    107121        uint lineno = JS_GetScriptBaseLineNumber(cx, script);
    108         JSFunction* fun = JS_GetFrameFunction(cx, fp);
     122       
     123        JSFunction* fun = frame.maybeFun();
    109124        pThreadDebugger->ExecuteHook(cx, fileName, lineno, script, fun, closure);
    110125    }
    111126   
     
    149164    // and spidermonkey throws errors if it detects a pointer on the stack.
    150165    // We only use the pointer for comparing it with the current stack pointer and we don't try to access it, so it
    151166    // shouldn't be a problem.
    152     JSStackFrame** m_pLastBreakFrame;
     167    JS::FrameDescription** m_pLastBreakFrame;
    153168    uint m_ObjectReferenceID;
    154169
    155170    /// shared between multiple mongoose threads and one scriptinterface thread
     
    174189    : m_NextDbgCmd(DBG_CMD_NONE)
    175190    , m_pScriptInterface(NULL)
    176191    , m_pDebuggingServer(NULL)
    177     , m_pLastBreakFrame(new JSStackFrame*)
     192, m_pLastBreakFrame(new JS::FrameDescription*)
    178193    , m_IsInBreak(false)
    179194{ }
    180195
     
    273288    ENSURE(script != NULL && pc != NULL);
    274289    activeBreakPoint->m_ActualLine = JS_PCToLineNumber(m->m_pScriptInterface->GetContext(), script, pc);
    275290   
    276     JS_SetTrap(m->m_pScriptInterface->GetContext(), script, pc, TrapHandler_, PRIVATE_TO_JSVAL(this));
     291    JS::Rooted<JSScript*> hscript(m->m_pScriptInterface->GetContext(), script);
     292    JS::Rooted<jsval> hjsval(m->m_pScriptInterface->GetContext(), PRIVATE_TO_JSVAL((JSObject*)this));
     293    JS_SetTrap(m->m_pScriptInterface->GetContext(), hscript, pc, TrapHandler_, hjsval);
    277294}
    278295
    279296
     
    293310    // Remove all the hooks because they store a pointer to this object
    294311    JS_SetExecuteHook(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);
    295312    JS_SetCallHook(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);
    296     JS_SetNewScriptHook(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);
    297     JS_SetDestroyScriptHook(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);
     313    JS_SetNewScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);
     314    JS_SetDestroyScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);
    298315}
    299316
    300317void CThreadDebugger::ReturnActiveBreakPoints(jsbytecode* pBytecode)
     
    331348    m->m_Name = name;
    332349    m->m_pScriptInterface = pScriptInterface;
    333350    m->m_pDebuggingServer = pDebuggingServer;
     351    //JSInterpreterHook
    334352    JS_SetExecuteHook(m->m_pScriptInterface->GetJSRuntime(), CallHook_, (void*)this);
    335353    JS_SetCallHook(m->m_pScriptInterface->GetJSRuntime(), CallHook_, (void*)this);
    336     JS_SetNewScriptHook(m->m_pScriptInterface->GetJSRuntime(), NewScriptHook_, (void*)this);
    337     JS_SetDestroyScriptHook(m->m_pScriptInterface->GetJSRuntime(), DestroyScriptHook_, (void*)this);
     354    JS_SetNewScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), NewScriptHook_, (void*)this);
     355    JS_SetDestroyScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), DestroyScriptHook_, (void*)this);
    338356    JS_SetThrowHook(m->m_pScriptInterface->GetJSRuntime(), ThrowHandler_, (void*)this);
    339357   
    340358    if (m->m_pDebuggingServer->GetSettingSimultaneousThreadBreak())
     
    352370    //          a higher line number.
    353371    // 2. We are in a different Frame and m_pLastBreakFrame is not a parent of the current frame (because we stepped out of the function)
    354372    uint line = JS_PCToLineNumber(cx, script, pc);
    355     JSStackFrame* iter = NULL;
    356     JSStackFrame* pStackFrame;
    357     pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    358373    uint lastBreakLine = GetLastBreakLine() ;
     374    JS::StackDescription* description = JS::DescribeStack(cx, NULL);
     375    JS::FrameDescription* pStackFrame = description->frames;
     376    JSTrapStatus result = JSTRAP_CONTINUE;
     377
    359378    jsval val = JSVAL_VOID;
    360     if ((*m->m_pLastBreakFrame == pStackFrame && lastBreakLine != line) ||
    361         (*m->m_pLastBreakFrame != pStackFrame && !CurrentFrameIsChildOf(*m->m_pLastBreakFrame)))
    362         return BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);
    363     else
    364         return JSTRAP_CONTINUE;
     379    if ((**m->m_pLastBreakFrame == *pStackFrame && lastBreakLine != line) ||
     380        (**m->m_pLastBreakFrame != *pStackFrame && !CurrentFrameIsChildOf(description, *m->m_pLastBreakFrame)))
     381        result = BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);
     382
     383    JS::FreeStackDescription(cx, description);
     384    return result;
    365385}
    366386
    367387JSTrapStatus CThreadDebugger::StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void* UNUSED(closure))
     
    369389    // We break when we are on the same stack frame but not on the same line
    370390    // or when we are on another stack frame.
    371391    uint line = JS_PCToLineNumber(cx, script, pc);
    372     JSStackFrame* iter = NULL;
    373     JSStackFrame* pStackFrame;
    374     pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     392    JS::StackDescription* description = JS::DescribeStack(cx, NULL);
     393    JS::FrameDescription* pStackFrame = description->frames;
    375394    uint lastBreakLine = GetLastBreakLine();
     395    JSTrapStatus result = JSTRAP_CONTINUE;
    376396   
    377397    jsval val = JSVAL_VOID;
    378     if ((*m->m_pLastBreakFrame == pStackFrame && lastBreakLine != line) || *m->m_pLastBreakFrame != pStackFrame)
    379         return BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);
    380     else
    381         return JSTRAP_CONTINUE;
     398    if ((**m->m_pLastBreakFrame == *pStackFrame && lastBreakLine != line) || **m->m_pLastBreakFrame != *pStackFrame)
     399        result = BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);
     400   
     401    JS::FreeStackDescription(cx, description);
     402    return result;
    382403}
    383404
    384405JSTrapStatus CThreadDebugger::StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void* UNUSED(closure))
     
    385406{
    386407    // We break when we are in a different Frame and m_pLastBreakFrame is not a parent of the current frame
    387408    // (because we stepped out of the function)
    388     JSStackFrame* iter = NULL;
    389     JSStackFrame* pStackFrame;
    390     pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    391     if (pStackFrame != *m->m_pLastBreakFrame && !CurrentFrameIsChildOf(*m->m_pLastBreakFrame))
     409   
     410    JS::StackDescription* description = JS::DescribeStack(cx, NULL);
     411    JS::FrameDescription* pStackFrame = description->frames;
     412    JSTrapStatus result = JSTRAP_CONTINUE;
     413   
     414    if (*pStackFrame != **m->m_pLastBreakFrame && !CurrentFrameIsChildOf(description, *m->m_pLastBreakFrame))
    392415    {
    393416        jsval val = JSVAL_VOID;
    394         return BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);
     417        result = BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);
    395418    }
    396     else
    397         return JSTRAP_CONTINUE;
     419   
     420    JS::FreeStackDescription(cx, description);
     421    return result;
    398422}
    399423
    400 bool CThreadDebugger::CurrentFrameIsChildOf(JSStackFrame* pParentFrame)
     424bool CThreadDebugger::CurrentFrameIsChildOf(JS::StackDescription* description, JS::FrameDescription* frame)
    401425{
    402     JSStackFrame* iter = NULL;
    403     JSStackFrame* fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    404     // Get the first parent Frame
    405     fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    406     while (fp)
    407     {
    408         if (fp == pParentFrame)
     426    for (int i = 0; i < (int)description->nframes; i++) {
     427        JS::FrameDescription* nextframe = (description->frames + i);
     428       
     429        if (*nextframe == *frame)
     430        {
    409431            return true;
    410         fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     432        }
    411433    }
    412434    return false;
    413435}
     
    429451
    430452JSTrapStatus CThreadDebugger::ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
    431453{
    432     jsval jsexception;
     454    jsval ujsexception;
     455    JS::Rooted<jsval> jsexception(m->m_pScriptInterface->GetContext(), ujsexception);
    433456    JS_GetPendingException(cx, &jsexception);
    434457    if (JSVAL_IS_STRING(jsexception))
    435458    {
     
    448471JSTrapStatus CThreadDebugger::BreakHandler(JSContext* cx, JSScript* script, jsbytecode* pc, jsval* UNUSED(rval), jsval UNUSED(closure), BREAK_SRC breakSrc)
    449472{
    450473    uint line = JS_PCToLineNumber(cx, script, pc);
    451     std::string filename(JS_GetScriptFilename(cx, script));
     474    std::string filename(JS_GetScriptFilename(script));
    452475
    453476    SetIsInBreak(true);
    454477    SaveCallstack();
     
    459482    if (breakSrc == BREAK_SRC_INTERRUP)
    460483    {
    461484        JS_ClearInterrupt(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);
    462         JS_SetSingleStepMode(cx, script, false);
     485        JS::Rooted<JSScript*> hscript(cx, script);
     486        JS_SetSingleStepMode(cx, hscript, false);
    463487    }
    464488   
    465489    if (m->m_pDebuggingServer->GetSettingSimultaneousThreadBreak())
     
    489513        }
    490514        else if (nextDbgCmd == DBG_CMD_SINGLESTEP || nextDbgCmd == DBG_CMD_STEPINTO || nextDbgCmd == DBG_CMD_STEPOUT)
    491515        {
    492             JSStackFrame* iter = NULL;
    493             *m->m_pLastBreakFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    494            
    495             if (!JS_SetSingleStepMode(cx, script, true))
     516            JS::StackDescription* description = JS::DescribeStack(m->m_pScriptInterface->GetContext(), NULL);
     517            *m->m_pLastBreakFrame = description->frames;
     518            //JS::FreeStackDescription(m->m_pScriptInterface->GetContext(), description);
     519
     520            JS::Rooted<JSScript*> hscript(cx, script);
     521            if (!JS_SetSingleStepMode(cx, hscript, true))
    496522                LOGERROR("JS_SetSingleStepMode returned false!"); // TODO: When can this happen?
    497523            else
    498524            {
     
    515541        }
    516542        else if (nextDbgCmd == DBG_CMD_CONTINUE)
    517543        {
    518             if (!JS_SetSingleStepMode(cx, script, true))
     544            JS::Rooted<JSScript*> hscript(cx, script);
     545            if (!JS_SetSingleStepMode(cx, hscript, true))
    519546                LOGERROR("JS_SetSingleStepMode returned false!"); // TODO: When can this happen?
    520547            else
    521548            {
     
    524551            }
    525552            break;
    526553        }
    527         else 
     554        else
    528555            debug_warn("Invalid DBGCMD found in CThreadDebugger::BreakHandler!");
    529556    }
    530557    ClearTrapsToRemove();
     
    545572void CThreadDebugger::NewScriptHook(JSContext* cx, const char* filename, unsigned lineno, JSScript* script, JSFunction* UNUSED(fun), void* UNUSED(callerdata))
    546573{
    547574    uint scriptExtent = JS_GetScriptLineExtent (cx, script);
     575
     576    if (filename == NULL)
     577        filename = "<No FileName>";
     578
    548579    std::string stringFileName(filename);
    549580    if (stringFileName.empty())
    550581        return;
     
    588619
    589620void CThreadDebugger::DestroyScriptHook(JSContext* cx, JSScript* script)
    590621{
     622    if (cx == NULL)
     623    {
     624        cx = m->m_pScriptInterface->GetContext();
     625    }
    591626    uint scriptExtent = JS_GetScriptLineExtent (cx, script);
    592627    uint baseLine = JS_GetScriptBaseLineNumber(cx, script);
    593628   
    594629    char* pStr = NULL;
    595     pStr = (char*)JS_GetScriptFilename(cx, script);
     630    pStr = (char*)JS_GetScriptFilename(script);
    596631    if (pStr != NULL)
    597632    {
    598633        std::string fileName(pStr);
     
    650685   
    651686    CScopeLock lock(m->m_Mutex);
    652687   
    653     JSStackFrame *fp;
    654     JSStackFrame *iter = 0;
    655     jsint counter = 0;
     688    //JSStackFrame *fp;
     689    //JSStackFrame *iter = 0;
     690    //jsint counter = 0;
    656691   
    657     JSObject* jsArray;
    658     jsArray = JS_NewArrayObject(m->m_pScriptInterface->GetContext(), 0, 0);
    659     JSString* functionID;
     692    //jsArray = JS_NewArrayObject(m->m_pScriptInterface->GetContext(), 0, 0);
     693    //JSString* functionID;
    660694
    661     fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     695    //fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    662696
    663     while (fp)
    664     {
    665         JSFunction* fun = 0;
    666         fun = JS_GetFrameFunction(m->m_pScriptInterface->GetContext(), fp);
    667         if (NULL == fun)
    668             functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "null");
    669         else
    670         {
    671             functionID = JS_GetFunctionId(fun);
    672             if (NULL == functionID)
    673                 functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "anonymous");
    674         }
    675697
    676         bool ret = JS_DefineElement(m->m_pScriptInterface->GetContext(), jsArray, counter, STRING_TO_JSVAL(functionID), NULL, NULL, 0);
    677         ENSURE(ret);
    678         fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    679         counter++;
     698    JS::StackDescription* description = JS::DescribeStack(m->m_pScriptInterface->GetContext(), NULL);
     699    int limit = (int)description->nframes;
     700    JS::Rooted<JSObject*> hobj1(m->m_pScriptInterface->GetContext(), 0);
     701    JS::Rooted<JSObject*> hobj2(m->m_pScriptInterface->GetContext(), 0);
     702    JSObject* jsArray = JS_NewObject(m->m_pScriptInterface->GetContext(), NULL, hobj1, hobj2);
     703    m->m_Callstack.clear();
     704    for (int i = 0; i < (int)description->nframes; i++) {
     705        JS::FrameDescription* frame = (description->frames + i);
     706        //JSFunction* fun = 0;
     707        //fun = JS_GetFrameFunction(m->m_pScriptInterface->GetContext(), fp);
     708        //if (NULL == frame->funDisplayName())
     709        //  functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "null");
     710        //else
     711        //{
     712        //  functionID = JS_GetFunctionId(fun);
     713        //  if (NULL == functionID)
     714        //      functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "anonymous");
     715        //}
     716
     717        //bool ret = JS_DefineElement(m->m_pScriptInterface->GetContext(), jsArray, counter, STRING_TO_JSVAL(functionID), NULL, NULL, 0);
     718        //ENSURE(ret);
     719
     720        jsArray = JSVAL_TO_OBJECT(STRING_TO_JSVAL(JS_FORGET_STRING_FLATNESS(frame->funDisplayName())));
     721        JS::Rooted<jsval> hjsval(m->m_pScriptInterface->GetContext(), OBJECT_TO_JSVAL(jsArray));
     722        m->m_Callstack.append(m->m_pScriptInterface->StringifyJSON(&hjsval, false).c_str());
     723        //fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     724        //counter++;
    680725    }
    681726   
    682     m->m_Callstack.clear();
    683     m->m_Callstack = m->m_pScriptInterface->StringifyJSON(OBJECT_TO_JSVAL(jsArray), false).c_str();
    684727}
    685728
    686729void CThreadDebugger::GetStackFrameData(std::stringstream& response, uint nestingLevel, STACK_INFO stackInfoKind)
     
    719762void CThreadDebugger::SaveStackFrameData(STACK_INFO stackInfo, uint nestingLevel)
    720763{
    721764    ENSURE(GetIsInBreak());
    722    
     765
    723766    CScopeLock lock(m->m_Mutex);
    724     JSStackFrame *iter = 0;
     767    //JSStackFrame *iter = 0;
    725768    uint counter = 0;
    726769    jsval val;
    727    
     770
    728771    if (stackInfo == STACK_INFO_GLOBALOBJECT)
    729772    {
    730773        JSObject* obj;
    731         obj = JS_GetGlobalForScopeChain(m->m_pScriptInterface->GetContext());
     774        obj = JS::CurrentGlobalOrNull(m->m_pScriptInterface->GetContext());
    732775        m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(OBJECT_TO_JSVAL(obj), false);
    733776    }
    734777    else
    735778    {
    736         JSStackFrame *fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    737         while (fp)
     779        JS::StackDescription* description = JS::DescribeStack(m->m_pScriptInterface->GetContext(), NULL);
     780        JS::FrameDescription* frame = (description->frames + nestingLevel);
     781
     782        JSBrokenFrameIterator bFrame(m->m_pScriptInterface->GetContext());
     783        for (uint i = 0; i < nestingLevel; i++) {
     784            bFrame = ++bFrame;
     785        }
     786        JSAbstractFramePtr aFrame = (JSAbstractFramePtr)bFrame.abstractFramePtr();
     787        JSObject* callobject = aFrame.callObject(m->m_pScriptInterface->GetContext()); //need the call to build evaluateInStackFrame
     788
     789        const char* fileName = frame->filename();
     790
     791        //JSStackFrame *fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     792        //while (fp)
     793        //{
     794        while (counter != nestingLevel)
    738795        {
    739             if (counter == nestingLevel)
    740             {
    741                 if (stackInfo == STACK_INFO_LOCALS)
    742                 {
    743                     JSObject* obj;
    744                     obj = JS_GetFrameCallObject(m->m_pScriptInterface->GetContext(), fp);
    745                     //obj = JS_GetFrameScopeChain(m->m_pScriptInterface->GetContext(), fp);
    746                     m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(OBJECT_TO_JSVAL(obj), false);
    747                 }
    748                 else if (stackInfo == STACK_INFO_THIS)
    749                 {
    750                     if (JS_GetFrameThis(m->m_pScriptInterface->GetContext(), fp, &val))
    751                         m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(val, false);
    752                     else
    753                         m->m_StackFrameData[stackInfo][nestingLevel] = "";
    754                 }
    755             }
    756            
    757796            counter++;
    758             fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     797            //fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    759798        }
     799
     800        if (stackInfo == STACK_INFO_LOCALS)
     801        {
     802
     803            JS::RootedValue rLocal(m->m_pScriptInterface->GetContext());
     804            JS::MutableHandleValue vLocal(&rLocal);
     805            const char* lName = JS_EncodeString(m->m_pScriptInterface->GetContext(), JS_FORGET_STRING_FLATNESS(frame->funDisplayName()));
     806            aFrame.evaluateInStackFrame(m->m_pScriptInterface->GetContext(), lName, strlen(lName), fileName, frame->lineno(), vLocal);
     807        }
     808        else if (stackInfo == STACK_INFO_THIS)
     809        {
     810            m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(val, false);
     811        }
     812        else
     813        {
     814            m->m_StackFrameData[stackInfo][nestingLevel] = "";
     815        }
    760816    }
    761817}
    762 */
    763818
     819
    764820/*
    765821 * TODO: This is very hacky and ugly and should be improved.
    766822 * It replaces cyclic references with a notification that cyclic references are not supported.
     
    774830 *    the rest of the game and because this part of code should be replaced anyway in the future.
    775831 */
    776832 
    777  /*
     833 
    778834namespace CyclicRefWorkaround
    779835{
    780836    std::set<JSObject*> g_ProcessedObjects;
     
    785841   
    786842    struct Stringifier
    787843    {
    788         static bool callback(const jschar* buf, uint32 len, void* data)
     844        static bool callback(const jschar* buf, u32 len, void* data)
    789845        {
    790846            utf16string str(buf, buf+len);
    791847            std::wstring strw(str.begin(), str.end());
     
    798854        std::stringstream stream;
    799855    };
    800856   
    801     bool replacer(JSContext* cx, uintN UNUSED(argc), jsval* vp)
     857    bool replacer(JSContext* cx, uint UNUSED(argc), jsval* vp)
    802858    {
    803         jsval value = JS_ARGV(cx, vp)[1];
    804         jsval key = JS_ARGV(cx, vp)[0];
     859        jsval value = js_CallArgs_h(cx, vp)[1];
     860        jsval key = js_CallArgs_h(cx, vp)[0];
    805861        if (g_LastKey == key)
    806862            g_countSameKeys++;
    807863        else
    808864            g_countSameKeys = 0;
    809865       
    810         if (JSVAL_IS_OBJECT(value))
     866        if (value.isObject())
    811867        {   
    812868            // Work around a spidermonkey bug that causes replacer to be called twice with the same key:
    813869            // https://bugzilla.mozilla.org/show_bug.cgi?id=636079
     
    821877            {
    822878                g_RecursionDetectedInPrevReplacer = true;
    823879                jsval ret = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "Debugger: object removed from output because of cyclic reference."));
    824                 JS_SET_RVAL(cx, vp, ret);
     880                JS::CallReceiverFromVp(&ret);
    825881                g_LastKey = key;
    826882                g_LastValue = value;
    827883                return true;
     
    830886        g_LastKey = key;
    831887        g_LastValue = value;
    832888        g_RecursionDetectedInPrevReplacer = false;
    833         JS_SET_RVAL(cx, vp, JS_ARGV(cx, vp)[1]);
     889        JS::CallReceiverFromVp(js_CallArgs_h(cx, &vp)[1]);
    834890        return true;
    835891    }
    836892}
     
    842898    CyclicRefWorkaround::g_LastKey = JSVAL_VOID;
    843899   
    844900    JSObject* pGlob = JSVAL_TO_OBJECT(m->m_pScriptInterface->GetGlobalObject());
    845     JSFunction* fun = JS_DefineFunction(m->m_pScriptInterface->GetContext(), pGlob, "replacer", CyclicRefWorkaround::replacer, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
     901    JS::Rooted<JSObject*> hpGlob(m->m_pScriptInterface->GetContext(), pGlob);
     902    JSFunction* fun = JS_DefineFunction(m->m_pScriptInterface->GetContext(), hpGlob, "replacer", CyclicRefWorkaround::replacer, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
    846903    JSObject* replacer = JS_GetFunctionObject(fun);
    847     if (!JS_Stringify(m->m_pScriptInterface->GetContext(), &obj, replacer, indent ? INT_TO_JSVAL(2) : JSVAL_VOID, &CyclicRefWorkaround::Stringifier::callback, &str))
     904    JS::Rooted<jsval> hobj(m->m_pScriptInterface->GetContext(), obj);
     905    JS::Rooted<JSObject*> hreplacer(m->m_pScriptInterface->GetContext(), replacer);
     906    JS::Rooted<jsval> hindent(m->m_pScriptInterface->GetContext(), indent ? INT_TO_JSVAL(2) : JSVAL_VOID);
     907    if (!JS_Stringify(m->m_pScriptInterface->GetContext(), &hobj, hreplacer, hindent, &CyclicRefWorkaround::Stringifier::callback, &str))
    848908    {
    849909        LOGERROR("StringifyJSON failed");
    850         jsval exec;
    851         jsval execString;
     910        jsval uexec=OBJECT_TO_JSVAL(0);
     911        jsval uexecString=OBJECT_TO_JSVAL(0);
     912
     913        JS::Rooted<jsval> exec(m->m_pScriptInterface->GetContext(), uexec);
     914        JS::Rooted<jsval> execString(m->m_pScriptInterface->GetContext(), uexecString);
     915
    852916        if (JS_GetPendingException(m->m_pScriptInterface->GetContext(), &exec))
    853917        {
    854             if (JSVAL_IS_OBJECT(exec))
     918            if (exec.isObject())
    855919            {
    856                 JS_GetProperty(m->m_pScriptInterface->GetContext(), JSVAL_TO_OBJECT(exec), "message", &execString);
     920                JS::Rooted<JSObject*> hexec(m->m_pScriptInterface->GetContext(), JSVAL_TO_OBJECT(exec));
     921                JS_GetProperty(m->m_pScriptInterface->GetContext(), hexec, "message", &execString);
    857922           
    858923                if (JSVAL_IS_STRING(execString))
    859924                {
     
    9361001    CScopeLock lock(m->m_Mutex);
    9371002    return m->m_ID;
    9381003}
    939 */
     1004
  • source/scriptinterface/ThreadDebugger.h

     
    11/* Copyright (C) 2013 Wildfire Games.
    2  * This file is part of 0 A.D.
    3  *
    4  * 0 A.D. is free software: you can redistribute it and/or modify
    5  * it under the terms of the GNU General Public License as published by
    6  * the Free Software Foundation, either version 2 of the License, or
    7  * (at your option) any later version.
    8  *
    9  * 0 A.D. is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
    16  */
    17  
    18  // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
     2* This file is part of 0 A.D.
     3*
     4* 0 A.D. is free software: you can redistribute it and/or modify
     5* it under the terms of the GNU General Public License as published by
     6* the Free Software Foundation, either version 2 of the License, or
     7* (at your option) any later version.
     8*
     9* 0 A.D. is distributed in the hope that it will be useful,
     10* but WITHOUT ANY WARRANTY; without even the implied warranty of
     11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12* GNU General Public License for more details.
     13*
     14* You should have received a copy of the GNU General Public License
     15* along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
     16*/
    1917
    20 //#ifndef INCLUDED_THREADDEBUGGER
    21 //#define INCLUDED_THREADDEBUGGER
    22 //
    23 //#include "DebuggingServer.h"
    24 //#include "ScriptInterface.h"
    25 //#include "scriptinterface/ScriptExtraHeaders.h"
    26 //
    27 //// These Breakpoint classes are not implemented threadsafe. The class using the Breakpoints is responsible to make sure that
    28 //// only one thread accesses the Breakpoint at a time
    29 //class CBreakPoint
    30 //{
    31 //public:
    32 //  CBreakPoint() : m_UserLine(0) { }
    33 // 
    34 //  uint m_UserLine;
    35 //  std::string m_Filename;
    36 //};
    37 //
    38 //// Only use this with one ScriptInterface/CThreadDebugger!
    39 //class CActiveBreakPoint : public CBreakPoint
    40 //{
    41 //public:
    42 //  CActiveBreakPoint()
    43 //      : m_ActualLine(m_UserLine)
    44 //      , m_Script(NULL)
    45 //      , m_Pc(NULL)
    46 //      , m_ToRemove(false)
    47 //  { }
    48 //
    49 //  CActiveBreakPoint(CBreakPoint breakPoint)
    50 //      : CBreakPoint(breakPoint) // using default copy constructor
    51 //      , m_ActualLine(m_UserLine)
    52 //      , m_Script(NULL)
    53 //      , m_Pc(NULL)
    54 //      , m_ToRemove(false)
    55 //  { }
    56 // 
    57 //  uint m_ActualLine;
    58 //  JSScript* m_Script;
    59 //  jsbytecode* m_Pc;
    60 //  bool m_ToRemove;
    61 //};
    62 //
    63 //enum BREAK_SRC { BREAK_SRC_TRAP, BREAK_SRC_INTERRUP, BREAK_SRC_EXCEPTION };
    64 //
    65 //struct ThreadDebugger_impl;
    66 //
    67 //class CThreadDebugger
    68 //{
    69 //public:
    70 //  CThreadDebugger();
    71 //  ~CThreadDebugger();
    72 //
    73 //  /** @brief Initialize the object (required before using the object!).
    74 //   *
    75 //   * @param   id A unique identifier greater than 0 for the object inside its CDebuggingServer object.
    76 //   * @param   name A name that will be can be displayed by the UI to identify the thread.
    77 //   * @param   pScriptInterface Pointer to a scriptinterface. All Hooks, breakpoint traps etc. will be registered in this
    78 //   *          scriptinterface and will be called by the thread this scriptinterface is running in.
    79 //   * @param   pDebuggingServer Pointer to the DebuggingServer object this Object should belong to.
    80 //   *
    81 //   * @return  Return value.
    82 //   */
    83 //  void Initialize(uint id, std::string name, ScriptInterface* pScriptInterface, CDebuggingServer* pDebuggingServer);
    84 // 
    85 // 
    86 //  // A bunch of hooks used to get information from spidermonkey.
    87 //  // These hooks are used internally only but have to be public because they need to be accessible from the global hook functions.
    88 //  // Spidermonkey requires function pointers as hooks, which only works if the functions are global or static (not part of an object).
    89 //  // These global functions in ThreadDebugger.cpp are just wrappers for the following member functions.
    90 // 
    91 //  /** Simply calls BreakHandler with BREAK_SRC_TRAP */
    92 //  JSTrapStatus TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure);
    93 //  /** Hook to capture exceptions and breakpoints in code (throw "Breakpoint";) */
    94 //  JSTrapStatus ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval);
    95 //  /** All other hooks call this one if the execution should be paused. It puts the program in a wait-loop and
    96 //   *  waits for weak-up events (continue, step etc.). */
    97 //  JSTrapStatus BreakHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure, BREAK_SRC breakSrc);
    98 //  JSTrapStatus StepHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
    99 //  JSTrapStatus StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
    100 //  JSTrapStatus StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
    101 //  /** This is an interrup-hook that can be called multiple times per line of code and is used to break into the execution
    102 //    * without previously setting a breakpoint and to break other threads when one thread triggers a breakpoint */
    103 //  JSTrapStatus CheckForBreakRequestHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
    104 //  /** The callback function which gets executed for each new script that gets loaded and each function inside a script.
    105 //   *   We use it for "Execute-Hooks" and "Call-Hooks" in terms of Spidermonkey.
    106 //   *   This hook actually sets the traps (Breakpoints) "on the fly" that have been defined by the user previously.
    107 //   */
    108 //  void ExecuteHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata);
    109 //  /** This hook is used to update the mapping between filename plus line-numbers and jsbytecode pointers */
    110 //  void NewScriptHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata);
    111 //  /** This hook makes sure that invalid mappings between filename plus line-number and jsbytecode points get deleted */
    112 //  void DestroyScriptHook(JSContext *cx, JSScript *script);
    113 // 
    114 //
    115 //  void ClearTrap(CActiveBreakPoint* activeBreakPoint);
    116 // 
    117 //  /** @brief Checks if a mapping for the specified filename and line number exists in this CThreadDebugger's context
    118 //   */
    119 //  bool CheckIfMappingPresent(std::string filename, uint line);
    120 // 
    121 //  /** @brief Checks if a mapping exists for each breakpoint in the list of breakpoints that aren't set yet.
    122 //   *         If there is a mapping, it removes the breakpoint from the list of unset breakpoints (from CDebuggingServer),
    123 //   *         adds it to the list of active breakpoints (CThreadDebugger) and sets a trap.
    124 //   *         Threading: m_Mutex is locked in this call
    125 //   */
    126 //  void SetAllNewTraps();
    127 // 
    128 //  /** @brief Sets a new trap and stores the information in the CActiveBreakPoint pointer
    129 //   *         Make sure that a mapping exists before calling this function
    130 //   *         Threading: Locking m_Mutex is required by the callee
    131 //   */
    132 //  void SetNewTrap(CActiveBreakPoint* activeBreakPoint, std::string filename, uint line);
    133 //
    134 //  /** @brief Toggle a breakpoint if it's active in this threadDebugger object.
    135 //   *         Threading: Locking m_Mutex is required by the callee
    136 //   *
    137 //   * @param   filename full vfs path to the script filename
    138 //   * @param   userLine linenumber where the USER set the breakpoint (UserLine)
    139 //   *
    140 //   * @return  true if the breakpoint's state was changed
    141 //   */
    142 //  bool ToggleBreakPoint(std::string filename, uint userLine);
    143 // 
    144 // 
    145 //  void GetCallstack(std::stringstream& response);
    146 //  void GetStackFrameData(std::stringstream& response, uint nestingLevel, STACK_INFO stackInfoKind);
    147 // 
    148 //  /** @brief Compares the object's associated scriptinterface with the pointer passed as parameter.
    149 //   * @return true if equal
    150 //   */
    151 //  bool CompareScriptInterfacePtr(ScriptInterface* pScriptInterface) const;
    152 // 
    153 //  // Getter/Setters for members that need to be threadsafe
    154 //  std::string GetBreakFileName();
    155 //  bool GetIsInBreak();
    156 //  uint GetLastBreakLine();
    157 //  std::string GetName();
    158 //  uint GetID();
    159 //  void ContinueExecution();
    160 //  void SetNextDbgCmd(DBGCMD dbgCmd);
    161 //  DBGCMD GetNextDbgCmd();
    162 //  // The callee is responsible for locking m_Mutex
    163 //  void AddStackInfoRequest(STACK_INFO requestType, uint nestingLevel, SDL_sem* semaphore);
    164 // 
    165 // 
    166 //private:
    167 //  // Getters/Setters for members that need to be threadsafe
    168 //  void SetBreakFileName(std::string breakFileName);
    169 //  void SetLastBreakLine(uint breakLine);
    170 //  void SetIsInBreak(bool isInBreak);
    171 // 
    172 //  // Other threadsafe functions
    173 //  void SaveCallstack();
    174 // 
    175 //  /// Used only in the scriptinterface's thread.
    176 //  void ClearTrapsToRemove();
    177 //  bool CurrentFrameIsChildOf(JSStackFrame* pParentFrame);
    178 //  void ReturnActiveBreakPoints(jsbytecode* pBytecode);
    179 //  void SaveStackFrameData(STACK_INFO stackInfo, uint nestingLevel);
    180 //  std::string StringifyCyclicJSON(jsval obj, bool indent);
    181 //
    182 //  std::unique_ptr<ThreadDebugger_impl> m;
    183 //};
    184 //
    185 //#endif // INCLUDED_THREADDEBUGGER
     18// JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
     19
     20#ifndef INCLUDED_THREADDEBUGGER
     21#define INCLUDED_THREADDEBUGGER
     22
     23#include "DebuggingServer.h"
     24#include "ScriptInterface.h"
     25#include "scriptinterface/ScriptExtraHeaders.h"
     26
     27// These Breakpoint classes are not implemented threadsafe. The class using the Breakpoints is responsible to make sure that
     28// only one thread accesses the Breakpoint at a time
     29class CBreakPoint
     30{
     31public:
     32    CBreakPoint() : m_UserLine(0) { }
     33
     34    uint m_UserLine;
     35    std::string m_Filename;
     36};
     37
     38// Only use this with one ScriptInterface/CThreadDebugger!
     39class CActiveBreakPoint : public CBreakPoint
     40{
     41public:
     42    CActiveBreakPoint()
     43        : m_ActualLine(m_UserLine)
     44        , m_Script(NULL)
     45        , m_Pc(NULL)
     46        , m_ToRemove(false)
     47    { }
     48
     49    CActiveBreakPoint(CBreakPoint breakPoint)
     50        : CBreakPoint(breakPoint) // using default copy constructor
     51        , m_ActualLine(m_UserLine)
     52        , m_Script(NULL)
     53        , m_Pc(NULL)
     54        , m_ToRemove(false)
     55    { }
     56
     57    uint m_ActualLine;
     58    JSScript* m_Script;
     59    jsbytecode* m_Pc;
     60    bool m_ToRemove;
     61};
     62
     63enum BREAK_SRC { BREAK_SRC_TRAP, BREAK_SRC_INTERRUP, BREAK_SRC_EXCEPTION };
     64
     65struct ThreadDebugger_impl;
     66
     67class CThreadDebugger
     68{
     69public:
     70    CThreadDebugger();
     71    ~CThreadDebugger();
     72
     73    /** @brief Initialize the object (required before using the object!).
     74    *
     75    * @param    id A unique identifier greater than 0 for the object inside its CDebuggingServer object.
     76    * @param    name A name that will be can be displayed by the UI to identify the thread.
     77    * @param    pScriptInterface Pointer to a scriptinterface. All Hooks, breakpoint traps etc. will be registered in this
     78    *          scriptinterface and will be called by the thread this scriptinterface is running in.
     79    * @param    pDebuggingServer Pointer to the DebuggingServer object this Object should belong to.
     80    *
     81    * @return   Return value.
     82    */
     83    void Initialize(uint id, std::string name, ScriptInterface* pScriptInterface, CDebuggingServer* pDebuggingServer);
     84
     85
     86    // A bunch of hooks used to get information from spidermonkey.
     87    // These hooks are used internally only but have to be public because they need to be accessible from the global hook functions.
     88    // Spidermonkey requires function pointers as hooks, which only works if the functions are global or static (not part of an object).
     89    // These global functions in ThreadDebugger.cpp are just wrappers for the following member functions.
     90
     91    /** Simply calls BreakHandler with BREAK_SRC_TRAP */
     92    JSTrapStatus TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure);
     93    /** Hook to capture exceptions and breakpoints in code (throw "Breakpoint";) */
     94    JSTrapStatus ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval);
     95    /** All other hooks call this one if the execution should be paused. It puts the program in a wait-loop and
     96    *  waits for weak-up events (continue, step etc.). */
     97    JSTrapStatus BreakHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure, BREAK_SRC breakSrc);
     98    JSTrapStatus StepHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
     99    JSTrapStatus StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
     100    JSTrapStatus StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
     101    /** This is an interrup-hook that can be called multiple times per line of code and is used to break into the execution
     102    * without previously setting a breakpoint and to break other threads when one thread triggers a breakpoint */
     103    JSTrapStatus CheckForBreakRequestHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
     104    /** The callback function which gets executed for each new script that gets loaded and each function inside a script.
     105    *   We use it for "Execute-Hooks" and "Call-Hooks" in terms of Spidermonkey.
     106    *   This hook actually sets the traps (Breakpoints) "on the fly" that have been defined by the user previously.
     107    */
     108    void ExecuteHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata);
     109    /** This hook is used to update the mapping between filename plus line-numbers and jsbytecode pointers */
     110    void NewScriptHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata);
     111    /** This hook makes sure that invalid mappings between filename plus line-number and jsbytecode points get deleted */
     112    void DestroyScriptHook(JSContext *cx, JSScript *script);
     113
     114
     115    void ClearTrap(CActiveBreakPoint* activeBreakPoint);
     116
     117    /** @brief Checks if a mapping for the specified filename and line number exists in this CThreadDebugger's context
     118    */
     119    bool CheckIfMappingPresent(std::string filename, uint line);
     120
     121    /** @brief Checks if a mapping exists for each breakpoint in the list of breakpoints that aren't set yet.
     122    *         If there is a mapping, it removes the breakpoint from the list of unset breakpoints (from CDebuggingServer),
     123    *         adds it to the list of active breakpoints (CThreadDebugger) and sets a trap.
     124    *         Threading: m_Mutex is locked in this call
     125    */
     126    void SetAllNewTraps();
     127
     128    /** @brief Sets a new trap and stores the information in the CActiveBreakPoint pointer
     129    *         Make sure that a mapping exists before calling this function
     130    *         Threading: Locking m_Mutex is required by the callee
     131    */
     132    void SetNewTrap(CActiveBreakPoint* activeBreakPoint, std::string filename, uint line);
     133
     134    /** @brief Toggle a breakpoint if it's active in this threadDebugger object.
     135    *         Threading: Locking m_Mutex is required by the callee
     136    *
     137    * @param    filename full vfs path to the script filename
     138    * @param    userLine linenumber where the USER set the breakpoint (UserLine)
     139    *
     140    * @return   true if the breakpoint's state was changed
     141    */
     142    bool ToggleBreakPoint(std::string filename, uint userLine);
     143
     144
     145    void GetCallstack(std::stringstream& response);
     146    void GetStackFrameData(std::stringstream& response, uint nestingLevel, STACK_INFO stackInfoKind);
     147
     148    /** @brief Compares the object's associated scriptinterface with the pointer passed as parameter.
     149    * @return true if equal
     150    */
     151    bool CompareScriptInterfacePtr(ScriptInterface* pScriptInterface) const;
     152
     153    // Getter/Setters for members that need to be threadsafe
     154    std::string GetBreakFileName();
     155    bool GetIsInBreak();
     156    uint GetLastBreakLine();
     157    std::string GetName();
     158    uint GetID();
     159    void ContinueExecution();
     160    void SetNextDbgCmd(DBGCMD dbgCmd);
     161    DBGCMD GetNextDbgCmd();
     162    // The callee is responsible for locking m_Mutex
     163    void AddStackInfoRequest(STACK_INFO requestType, uint nestingLevel, SDL_sem* semaphore);
     164
     165
     166private:
     167    // Getters/Setters for members that need to be threadsafe
     168    void SetBreakFileName(std::string breakFileName);
     169    void SetLastBreakLine(uint breakLine);
     170    void SetIsInBreak(bool isInBreak);
     171
     172    // Other threadsafe functions
     173    void SaveCallstack();
     174
     175    /// Used only in the scriptinterface's thread.
     176    void ClearTrapsToRemove();
     177    bool CurrentFrameIsChildOf(JS::StackDescription* description, JS::FrameDescription* pStackFrame);
     178    void ReturnActiveBreakPoints(jsbytecode* pBytecode);
     179    void SaveStackFrameData(STACK_INFO stackInfo, uint nestingLevel);
     180    std::string StringifyCyclicJSON(jsval obj, bool indent);
     181
     182    std::unique_ptr<ThreadDebugger_impl> m;
     183};
     184
     185#endif // INCLUDED_THREADDEBUGGER