Ticket #2973: 2973.diff

File 2973.diff, 55.1 KB (added by trompetin17, 9 years ago)
  • source/ps/GameSetup/Config.cpp

     
    130130    CFG_GET_VAL("jsdebugger.enable", g_JSDebuggerEnabled);
    131131    CFG_GET_VAL("profiler2.script.enable", g_ScriptProfilingEnabled);
    132132
    133     if (g_JSDebuggerEnabled)
    134         LOGERROR(L"JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)");
     133    //if (g_JSDebuggerEnabled)
     134    //  LOGERROR(L"JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)");
    135135    // Script Debugging and profiling does not make sense together because of the hooks
    136136    // that reduce performance a lot - and it wasn't tested if it even works together.
    137137    if (g_JSDebuggerEnabled && g_ScriptProfilingEnabled)
  • source/ps/GameSetup/GameSetup.cpp

     
    727727
    728728
    729729    // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    730     //TIMER_BEGIN(L"shutdown DebuggingServer (if active)");
    731     //delete g_DebuggingServer;
    732     //TIMER_END(L"shutdown DebuggingServer (if active)");
     730    TIMER_BEGIN(L"shutdown DebuggingServer (if active)");
     731    delete g_DebuggingServer;
     732    TIMER_END(L"shutdown DebuggingServer (if active)");
    733733
    734734    delete &g_L10n;
    735735
     
    957957
    958958    // before scripting
    959959    // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    960     //if (g_JSDebuggerEnabled)
    961     //  g_DebuggingServer = new CDebuggingServer();
     960    if (g_JSDebuggerEnabled)
     961        g_DebuggingServer = new CDebuggingServer();
    962962
    963963    // Optionally start profiler HTTP output automatically
    964964    // (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 /*
    2120
     21
    2222#include "DebuggingServer.h"
    2323#include "ThreadDebugger.h"
    2424#include "ps/CLogger.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

     
    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#include "AutoRooters.h"
    2525
     
    416416    }
    417417   
    418418    // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    419     /*
     419   
    420420    if (g_JSDebuggerEnabled && g_DebuggingServer != NULL)
    421421    {
    422422        if(!JS_SetDebugMode(GetContext(), true))
    423423            LOGERROR(L"Failed to set Spidermonkey to debug mode!");
     424       
     425        if(!JS_SetDebugModeForAllCompartments(GetContext(), true))
     426            LOGERROR(L"Failed to set Spidermonkey to debug mode!");
    424427        else
    425428            g_DebuggingServer->RegisterScriptinterface(debugName, this);
    426     } */
     429    }
    427430
    428431    m_CxPrivate.pScriptInterface = this;
    429432    JS_SetContextPrivate(m->m_cx, (void*)&m_CxPrivate);
     
    439442   
    440443    // Unregister from the Debugger class
    441444    // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    442     //if (g_JSDebuggerEnabled && g_DebuggingServer != NULL)
    443     //  g_DebuggingServer->UnRegisterScriptinterface(this);
     445    if (g_JSDebuggerEnabled && g_DebuggingServer != NULL)
     446        g_DebuggingServer->UnRegisterScriptinterface(this);
    444447}
    445448
    446449void 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  /*
    2120
     21
    2222#include "ThreadDebugger.h"
    2323#include "lib/utf8.h"
    2424#include "ps/CLogger.h"
     
    2626#include <map>
    2727#include <queue>
    2828
     29//Operators
     30bool operator==(JS::FrameDescription& a, JS::FrameDescription& b)
     31{
     32    return a.fun == b.fun;
     33}
     34
     35bool operator!=(JS::FrameDescription& a, JS::FrameDescription& b)
     36{
     37    return a.fun != b.fun;
     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;
     
    95106}
    96107
    97108CMutex CallHookMutex;
    98 static void* CallHook_(JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* UNUSED(ok), void* closure)
     109static void* CallHook_(JSContext* cx, JSAbstractFramePtr fp, bool UNUSED(isConstruncting), JSBool before, JSBool* UNUSED(ok), void* closure)
    99110{
    100111    CScopeLock lock(CallHookMutex);
    101112    CThreadDebugger* pThreadDebugger = (CThreadDebugger*) closure;
     
    102113    if (before)
    103114    {
    104115        JSScript* script;
    105         script = JS_GetFrameScript(cx, fp);
     116        script = fp.script();
    106117        const char* fileName = JS_GetScriptFilename(cx, script);
     118
    107119        uint lineno = JS_GetScriptBaseLineNumber(cx, script);
    108         JSFunction* fun = JS_GetFrameFunction(cx, fp);
     120       
     121        JSFunction* fun = fp.maybeFun();
    109122        pThreadDebugger->ExecuteHook(cx, fileName, lineno, script, fun, closure);
    110123    }
    111124   
     
    149162    // and spidermonkey throws errors if it detects a pointer on the stack.
    150163    // We only use the pointer for comparing it with the current stack pointer and we don't try to access it, so it
    151164    // shouldn't be a problem.
    152     JSStackFrame** m_pLastBreakFrame;
     165    JS::FrameDescription** m_pLastBreakFrame;
    153166    uint m_ObjectReferenceID;
    154167
    155168    /// shared between multiple mongoose threads and one scriptinterface thread
     
    174187    : m_NextDbgCmd(DBG_CMD_NONE)
    175188    , m_pScriptInterface(NULL)
    176189    , m_pDebuggingServer(NULL)
    177     , m_pLastBreakFrame(new JSStackFrame*)
     190, m_pLastBreakFrame(new JS::FrameDescription*)
    178191    , m_IsInBreak(false)
    179192{ }
    180193
     
    293306    // Remove all the hooks because they store a pointer to this object
    294307    JS_SetExecuteHook(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);
    295308    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);
     309    JS_SetNewScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);
     310    JS_SetDestroyScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);
    298311}
    299312
    300313void CThreadDebugger::ReturnActiveBreakPoints(jsbytecode* pBytecode)
     
    333346    m->m_pDebuggingServer = pDebuggingServer;
    334347    JS_SetExecuteHook(m->m_pScriptInterface->GetJSRuntime(), CallHook_, (void*)this);
    335348    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);
     349    JS_SetNewScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), NewScriptHook_, (void*)this);
     350    JS_SetDestroyScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), DestroyScriptHook_, (void*)this);
    338351    JS_SetThrowHook(m->m_pScriptInterface->GetJSRuntime(), ThrowHandler_, (void*)this);
    339352   
    340353    if (m->m_pDebuggingServer->GetSettingSimultaneousThreadBreak())
     
    352365    //          a higher line number.
    353366    // 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)
    354367    uint line = JS_PCToLineNumber(cx, script, pc);
    355     JSStackFrame* iter = NULL;
    356     JSStackFrame* pStackFrame;
    357     pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    358368    uint lastBreakLine = GetLastBreakLine() ;
     369    JS::StackDescription* description = JS::DescribeStack(cx, NULL);
     370    JS::FrameDescription* pStackFrame = description->frames;
     371    JSTrapStatus result = JSTRAP_CONTINUE;
     372
    359373    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;
     374    if ((**m->m_pLastBreakFrame == *pStackFrame && lastBreakLine != line) ||
     375        (**m->m_pLastBreakFrame != *pStackFrame && !CurrentFrameIsChildOf(description, *m->m_pLastBreakFrame)))
     376        result = BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);
     377
     378    JS::FreeStackDescription(cx, description);
     379    return result;
    365380}
    366381
    367382JSTrapStatus CThreadDebugger::StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void* UNUSED(closure))
     
    369384    // We break when we are on the same stack frame but not on the same line
    370385    // or when we are on another stack frame.
    371386    uint line = JS_PCToLineNumber(cx, script, pc);
    372     JSStackFrame* iter = NULL;
    373     JSStackFrame* pStackFrame;
    374     pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     387    JS::StackDescription* description = JS::DescribeStack(cx, NULL);
     388    JS::FrameDescription* pStackFrame = description->frames;
    375389    uint lastBreakLine = GetLastBreakLine();
     390    JSTrapStatus result = JSTRAP_CONTINUE;
    376391   
    377392    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;
     393    if ((**m->m_pLastBreakFrame == *pStackFrame && lastBreakLine != line) || **m->m_pLastBreakFrame != *pStackFrame)
     394        result = BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);
     395   
     396    JS::FreeStackDescription(cx, description);
     397    return result;
    382398}
    383399
    384400JSTrapStatus CThreadDebugger::StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void* UNUSED(closure))
     
    385401{
    386402    // We break when we are in a different Frame and m_pLastBreakFrame is not a parent of the current frame
    387403    // (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))
     404   
     405    JS::StackDescription* description = JS::DescribeStack(cx, NULL);
     406    JS::FrameDescription* pStackFrame = description->frames;
     407    JSTrapStatus result = JSTRAP_CONTINUE;
     408   
     409    if (*pStackFrame != **m->m_pLastBreakFrame && !CurrentFrameIsChildOf(description, *m->m_pLastBreakFrame))
    392410    {
    393411        jsval val = JSVAL_VOID;
    394         return BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);
     412        result = BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);
    395413    }
    396     else
    397         return JSTRAP_CONTINUE;
     414   
     415    JS::FreeStackDescription(cx, description);
     416    return result;
    398417}
    399418
    400 bool CThreadDebugger::CurrentFrameIsChildOf(JSStackFrame* pParentFrame)
     419bool CThreadDebugger::CurrentFrameIsChildOf(JS::StackDescription* description, JS::FrameDescription* frame)
    401420{
    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)
     421    for (int i = 0; i < (int)description->nframes; i++) {
     422        JS::FrameDescription* nextframe = (description->frames + i);
     423       
     424        if (*nextframe == *frame)
     425        {
    409426            return true;
    410         fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     427        }
    411428    }
    412429    return false;
    413430}
     
    489506        }
    490507        else if (nextDbgCmd == DBG_CMD_SINGLESTEP || nextDbgCmd == DBG_CMD_STEPINTO || nextDbgCmd == DBG_CMD_STEPOUT)
    491508        {
    492             JSStackFrame* iter = NULL;
    493             *m->m_pLastBreakFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     509            JS::StackDescription* description = JS::DescribeStack(m->m_pScriptInterface->GetContext(), NULL);
     510            *m->m_pLastBreakFrame = description->frames;
     511            //JS::FreeStackDescription(m->m_pScriptInterface->GetContext(), description);
    494512           
    495513            if (!JS_SetSingleStepMode(cx, script, true))
    496514                LOGERROR(L"JS_SetSingleStepMode returned false!"); // TODO: When can this happen?
     
    524542            }
    525543            break;
    526544        }
    527         else 
     545        else
    528546            debug_warn("Invalid DBGCMD found in CThreadDebugger::BreakHandler!");
    529547    }
    530548    ClearTrapsToRemove();
     
    545563void CThreadDebugger::NewScriptHook(JSContext* cx, const char* filename, unsigned lineno, JSScript* script, JSFunction* UNUSED(fun), void* UNUSED(callerdata))
    546564{
    547565    uint scriptExtent = JS_GetScriptLineExtent (cx, script);
     566
     567    if (filename == NULL)
     568        filename = "<No FileName>";
     569
    548570    std::string stringFileName(filename);
    549571    if (stringFileName.empty())
    550572        return;
     
    588610
    589611void CThreadDebugger::DestroyScriptHook(JSContext* cx, JSScript* script)
    590612{
     613    if (cx == NULL)
     614    {
     615        cx = m->m_pScriptInterface->GetContext();
     616    }
    591617    uint scriptExtent = JS_GetScriptLineExtent (cx, script);
    592618    uint baseLine = JS_GetScriptBaseLineNumber(cx, script);
    593619   
     
    649675    ENSURE(GetIsInBreak());
    650676   
    651677    CScopeLock lock(m->m_Mutex);
    652    
    653     JSStackFrame *fp;
    654     JSStackFrame *iter = 0;
    655     jsint counter = 0;
    656    
     678
    657679    JSObject* jsArray;
    658680    jsArray = JS_NewArrayObject(m->m_pScriptInterface->GetContext(), 0, 0);
    659681    JSString* functionID;
    660 
    661     fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    662 
    663     while (fp)
    664     {
    665         JSFunction* fun = 0;
    666         fun = JS_GetFrameFunction(m->m_pScriptInterface->GetContext(), fp);
    667         if (NULL == fun)
     682   
     683    JS::StackDescription* description = JS::DescribeStack(m->m_pScriptInterface->GetContext(), NULL);
     684   
     685    for (int i = 0; i < (int)description->nframes; i++) {
     686        JS::FrameDescription* frame = (description->frames + i);
     687       
     688        if (frame->fun == NULL)
    668689            functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "null");
    669690        else
    670691        {
    671             functionID = JS_GetFunctionId(fun);
    672             if (NULL == functionID)
     692            functionID = JS_GetFunctionId(frame->fun);
     693            if (functionID == NULL)
     694                functionID = JS_GetFunctionDisplayId(frame->fun);
     695               
     696            if (functionID == NULL)
    673697                functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "anonymous");
     698           
     699
    674700        }
    675 
    676         JSBool ret = JS_DefineElement(m->m_pScriptInterface->GetContext(), jsArray, counter, STRING_TO_JSVAL(functionID), NULL, NULL, 0);
     701        JSBool ret = JS_DefineElement(m->m_pScriptInterface->GetContext(), jsArray, i, STRING_TO_JSVAL(functionID), NULL, NULL, 0);
    677702        ENSURE(ret);
    678         fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    679         counter++;
    680703    }
    681704   
     705    JS::FreeStackDescription(m->m_pScriptInterface->GetContext(), description);
     706   
     707    JS::RootedValue rv(m->m_pScriptInterface->GetContext(),OBJECT_TO_JSVAL(jsArray));
     708    JS::MutableHandleValue mhv(&rv);
     709   
    682710    m->m_Callstack.clear();
    683     m->m_Callstack = m->m_pScriptInterface->StringifyJSON(OBJECT_TO_JSVAL(jsArray), false).c_str();
     711    m->m_Callstack = m->m_pScriptInterface->StringifyJSON(mhv, false).c_str();
    684712}
    685713
    686714void CThreadDebugger::GetStackFrameData(std::stringstream& response, uint nestingLevel, STACK_INFO stackInfoKind)
     
    721749    ENSURE(GetIsInBreak());
    722750   
    723751    CScopeLock lock(m->m_Mutex);
    724     JSStackFrame *iter = 0;
    725     uint counter = 0;
    726     jsval val;
    727752   
    728753    if (stackInfo == STACK_INFO_GLOBALOBJECT)
    729754    {
    730         JSObject* obj;
    731         obj = JS_GetGlobalForScopeChain(m->m_pScriptInterface->GetContext());
    732         m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(OBJECT_TO_JSVAL(obj), false);
     755        //Get global function
     756        JSObject* global;
     757        global = JS_GetGlobalForScopeChain(m->m_pScriptInterface->GetContext());
     758        m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(OBJECT_TO_JSVAL(global), false);
    733759    }
    734760    else
    735761    {
    736         JSStackFrame *fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
    737         while (fp)
     762        JS::StackDescription* description = JS::DescribeStack(m->m_pScriptInterface->GetContext(), NULL);
     763        JS::FrameDescription* frame = (description->frames + nestingLevel);
     764       
     765        JSBrokenFrameIterator bFrame(m->m_pScriptInterface->GetContext());
     766        for (uint i = 0; i < nestingLevel; i++) {
     767            bFrame = ++bFrame;
     768        }
     769        JSAbstractFramePtr aFrame = (JSAbstractFramePtr)bFrame.abstractFramePtr();
     770        JSObject* callobject = aFrame.callObject(m->m_pScriptInterface->GetContext()); //need the call to build evaluateInStackFrame
     771       
     772        const char* fileName = JS_GetScriptFilename(m->m_pScriptInterface->GetContext(), frame->script);
     773
     774        if (stackInfo == STACK_INFO_LOCALS)
    738775        {
    739             if (counter == nestingLevel)
     776            bool bbt = m->m_pDebuggingServer->GetBreakRequestedByThread();
     777            bool bbu = m->m_pDebuggingServer->GetBreakRequestedByUser();
     778           
     779            m->m_pDebuggingServer->SetBreakRequestedByThread(false);
     780            m->m_pDebuggingServer->SetBreakRequestedByUser(false);
     781           
     782            if (JS_FunctionHasLocalNames(m->m_pScriptInterface->GetContext(),frame->fun))
    740783            {
    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);
     784                void* lArray;
     785                uintptr_t* aNames = JS_GetFunctionLocalNameArray(m->m_pScriptInterface->GetContext(), frame->fun, &lArray);
     786               
     787                JSObject* locals = JS_NewObject(m->m_pScriptInterface->GetContext(), NULL, NULL, NULL);
     788
     789                uintptr_t last = 0xCDCDCDCDCDCDCDCD;
     790                while (*aNames != last) {
     791                    JSAtom* atom = JS_LocalNameToAtom(*aNames);
     792                    JSString* jsName = JS_AtomKey(atom);
     793                    const char * lName = JS_EncodeString(m->m_pScriptInterface->GetContext(), jsName);
     794                   
     795                    JS::RootedValue rLocal(m->m_pScriptInterface->GetContext());
     796                    JS::MutableHandleValue vLocal(&rLocal);
     797                   
     798                    aFrame.evaluateInStackFrame(m->m_pScriptInterface->GetContext(), lName, strlen(lName), fileName, frame->lineno, vLocal);
     799                   
     800
     801                    JS_DefineProperty(m->m_pScriptInterface->GetContext(), locals, lName , vLocal, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
     802                   
     803                    ++aNames;
    747804                }
    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                 }
     805               
     806                JS_ReleaseFunctionLocalNameArray(m->m_pScriptInterface->GetContext(), lArray);
     807                m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(JS::ObjectValue(*locals), false);
     808
    755809            }
    756            
    757             counter++;
    758             fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     810            m->m_pDebuggingServer->SetBreakRequestedByThread(bbt);
     811            m->m_pDebuggingServer->SetBreakRequestedByUser(bbu);
     812
    759813        }
     814        else if (stackInfo == STACK_INFO_THIS)
     815        {
     816            JS::RootedValue jThis(m->m_pScriptInterface->GetContext());
     817            JS::MutableHandleValue mjThis(&jThis);
     818            aFrame.getThisValue(m->m_pScriptInterface->GetContext(), mjThis);
     819            m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(mjThis, false);
     820        }
     821       
     822        JS::FreeStackDescription(m->m_pScriptInterface->GetContext(), description);
    760823    }
     824   
     825   
     826   
     827//  JSStackFrame *iter = 0;
     828//  uint counter = 0;
     829//  jsval val;
     830// 
     831//  if (stackInfo == STACK_INFO_GLOBALOBJECT)
     832//  {
     833//      JSObject* obj;
     834//      obj = JS_GetGlobalForScopeChain(m->m_pScriptInterface->GetContext());
     835//      m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(OBJECT_TO_JSVAL(obj), false);
     836//  }
     837//  else
     838//  {
     839//      JSStackFrame *fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     840//      while (fp)
     841//      {
     842//          if (counter == nestingLevel)
     843//          {
     844//              if (stackInfo == STACK_INFO_LOCALS)
     845//              {
     846//                  JSObject* obj;
     847//                  obj = JS_GetFrameCallObject(m->m_pScriptInterface->GetContext(), fp);
     848//                  //obj = JS_GetFrameScopeChain(m->m_pScriptInterface->GetContext(), fp);
     849//                  m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(OBJECT_TO_JSVAL(obj), false);
     850//              }
     851//              else if (stackInfo == STACK_INFO_THIS)
     852//              {
     853//                  if (JS_GetFrameThis(m->m_pScriptInterface->GetContext(), fp, &val))
     854//                      m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(val, false);
     855//                  else
     856//                      m->m_StackFrameData[stackInfo][nestingLevel] = "";
     857//              }
     858//          }
     859//         
     860//          counter++;
     861//          fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);
     862//      }
     863//  }
    761864}
    762 */
    763865
     866
    764867/*
    765868 * TODO: This is very hacky and ugly and should be improved.
    766869 * It replaces cyclic references with a notification that cyclic references are not supported.
     
    774877 *    the rest of the game and because this part of code should be replaced anyway in the future.
    775878 */
    776879 
    777  /*
     880
    778881namespace CyclicRefWorkaround
    779882{
    780883    std::set<JSObject*> g_ProcessedObjects;
     
    785888   
    786889    struct Stringifier
    787890    {
    788         static JSBool callback(const jschar* buf, uint32 len, void* data)
     891        static JSBool callback(const jschar* buf, Uint32 len, void* data)
    789892        {
    790893            utf16string str(buf, buf+len);
    791894            std::wstring strw(str.begin(), str.end());
     
    797900
    798901        std::stringstream stream;
    799902    };
    800    
    801     JSBool replacer(JSContext* cx, uintN UNUSED(argc), jsval* vp)
     903
     904    JSBool replacer(JSContext *cx, unsigned UNUSED(argc), JS::Value *vp)
    802905    {
    803906        jsval value = JS_ARGV(cx, vp)[1];
    804907        jsval key = JS_ARGV(cx, vp)[0];
     
    807910        else
    808911            g_countSameKeys = 0;
    809912       
    810         if (JSVAL_IS_OBJECT(value))
     913        if (value.isObject())
    811914        {   
    812915            // Work around a spidermonkey bug that causes replacer to be called twice with the same key:
    813916            // https://bugzilla.mozilla.org/show_bug.cgi?id=636079
     
    851954        jsval execString;
    852955        if (JS_GetPendingException(m->m_pScriptInterface->GetContext(), &exec))
    853956        {
    854             if (JSVAL_IS_OBJECT(exec))
     957            if (exec.isObject())
    855958            {
    856959                JS_GetProperty(m->m_pScriptInterface->GetContext(), JSVAL_TO_OBJECT(exec), "message", &execString);
    857960           
     
    9361039    CScopeLock lock(m->m_Mutex);
    9371040    return m->m_ID;
    9381041}
    939 */
     1042
  • source/scriptinterface/ThreadDebugger.h

     
    1717 
    1818 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)
    1919
    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();
     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();
    159159//  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::auto_ptr<ThreadDebugger_impl> m;
    183 //};
    184 //
    185 //#endif // INCLUDED_THREADDEBUGGER
     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* frame);
     178    void ReturnActiveBreakPoints(jsbytecode* pBytecode);
     179    void SaveStackFrameData(STACK_INFO stackInfo, uint nestingLevel);
     180    std::string StringifyCyclicJSON(jsval obj, bool indent);
     181
     182    std::auto_ptr<ThreadDebugger_impl> m;
     183};
     184
     185#endif // INCLUDED_THREADDEBUGGER