Ticket #2973: 2973.diff
File 2973.diff, 55.1 KB (added by , 9 years ago) |
---|
-
source/ps/GameSetup/Config.cpp
130 130 CFG_GET_VAL("jsdebugger.enable", g_JSDebuggerEnabled); 131 131 CFG_GET_VAL("profiler2.script.enable", g_ScriptProfilingEnabled); 132 132 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)"); 135 135 // Script Debugging and profiling does not make sense together because of the hooks 136 136 // that reduce performance a lot - and it wasn't tested if it even works together. 137 137 if (g_JSDebuggerEnabled && g_ScriptProfilingEnabled) -
source/ps/GameSetup/GameSetup.cpp
727 727 728 728 729 729 // 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)"); 733 733 734 734 delete &g_L10n; 735 735 … … 957 957 958 958 // before scripting 959 959 // 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(); 962 962 963 963 // Optionally start profiler HTTP output automatically 964 964 // (By default it's only enabled by a hotkey, for security/performance) -
source/scriptinterface/DebuggingServer.cpp
17 17 18 18 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 19 19 #include "precompiled.h" // needs to be here for Windows builds 20 /*21 20 21 22 22 #include "DebuggingServer.h" 23 23 #include "ThreadDebugger.h" 24 24 #include "ps/CLogger.h" … … 174 174 return m_SettingSimultaneousThreadBreak; 175 175 } 176 176 177 178 177 static Status AddFileResponse(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData) 179 178 { 180 179 std::vector<std::string>& templates = *(std::vector<std::string>*)cbData; … … 252 251 { 253 252 EnumVfsJSFiles(stream); 254 253 } 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 } 255 272 else if (uri == "/GetAllCallstacks") 256 273 { 257 274 GetAllCallstacks(stream); … … 262 279 if (!GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID)) 263 280 return handled; 264 281 // TODO: handle the return value 265 SetNextDbgCmd(threadDebuggerID, DBG_CMD_CONTINUE); 282 SetNextDbgCmd(threadDebuggerID, DBG_CMD_CONTINUE); 266 283 } 267 284 else if (uri == "/Break") 268 285 { 269 286 SetBreakRequestedByUser(true); 270 287 } 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 value278 if (strEnabled == "true")279 bEnabled = true;280 else if (strEnabled == "false")281 bEnabled = false;282 else283 return handled; // TODO: return an error state284 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 value297 if (strEnabled == "true")298 bEnabled = true;299 else if (strEnabled == "false")300 bEnabled = false;301 else302 return handled; // TODO: return an error state303 SetSettingBreakOnException(bEnabled);304 }305 else if (uri == "/GetSettingBreakOnException")306 {307 stream << "{ \"Enabled\" : " << (GetSettingBreakOnException() ? "true" : "false") << " } ";308 }309 288 else if (uri == "/Step") 310 289 { 311 290 uint threadDebuggerID; … … 334 313 { 335 314 uint nestingLevel; 336 315 uint threadDebuggerID; 337 if (!GetWebArgs(conn, request_info, "nestingLevel", nestingLevel) || 316 if (!GetWebArgs(conn, request_info, "nestingLevel", nestingLevel) || 338 317 !GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID)) 339 318 { 340 319 return handled; … … 345 324 { 346 325 uint nestingLevel; 347 326 uint threadDebuggerID; 348 if (!GetWebArgs(conn, request_info, "nestingLevel", nestingLevel) || 327 if (!GetWebArgs(conn, request_info, "nestingLevel", nestingLevel) || 349 328 !GetWebArgs(conn, request_info, "threadDebuggerID", threadDebuggerID)) 350 329 { 351 330 return handled; … … 352 331 } 353 332 GetStackFrameData(stream, nestingLevel, threadDebuggerID, STACK_INFO_THIS); 354 333 } 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 } 355 372 else if (uri == "/GetCurrentGlobalObject") 356 373 { 357 374 uint threadDebuggerID; … … 361 378 } 362 379 GetStackFrameData(stream, 0, threadDebuggerID, STACK_INFO_GLOBALOBJECT); 363 380 } 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 }382 381 else 383 382 { 384 383 mg_printf(conn, "%s", header404); … … 568 567 ENSURE(m_BreakPointsLockID == breakPointsLockID); 569 568 SDL_SemPost(m_BreakPointsSem); 570 569 } 571 */572 No newline at end of file -
source/scriptinterface/DebuggingServer.h
17 17 18 18 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 19 19 20 //#ifndef INCLUDED_DEBUGGINGSERVER21 //#define INCLUDED_DEBUGGINGSERVER22 // 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 CDebuggingServer35 //{36 //public:37 //CDebuggingServer();38 //~CDebuggingServer();39 //40 ///** @brief Register a new ScriptInerface for debugging the scripts it executes41 //*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 ScriptInterface50 //*/51 //void UnRegisterScriptinterface(ScriptInterface* pScriptInterface);52 // 53 //54 //// Mongoose callback when request comes from a client55 //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 gets71 //* used by the wrong thread.72 //*/73 //void ReleaseBreakPointAccess(double breakPointsLockID);74 //75 //76 ///// Called from multiple Mongoose threads and multiple ScriptInterface threads77 //bool GetBreakRequestedByThread();78 //bool GetBreakRequestedByUser();79 //// Should other threads be stopped as soon as possible after a breakpoint is triggered in a thread80 //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 root103 //*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 vfs109 //*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 threads116 //117 // 118 //bool m_SettingSimultaneousThreadBreak;119 //bool m_SettingBreakOnException;120 //121 ///// Shared between multiple scriptinterface threads122 //uint m_LastThreadDebuggerID;123 //124 ///// Shared between multiple scriptinerface threads and multiple mongoose threads125 //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_BreakPoints137 //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 sources141 ///// 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-safety146 //void EnableHTTP();147 //mg_context* m_MgContext;148 //};149 // 150 //extern CDebuggingServer* g_DebuggingServer;151 // 152 // 153 //#endif // INCLUDED_DEBUGGINGSERVER20 #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 -
source/scriptinterface/ScriptInterface.cpp
19 19 20 20 #include "ScriptInterface.h" 21 21 #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) 23 23 #include "ScriptStats.h" 24 24 #include "AutoRooters.h" 25 25 … … 416 416 } 417 417 418 418 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 419 /*419 420 420 if (g_JSDebuggerEnabled && g_DebuggingServer != NULL) 421 421 { 422 422 if(!JS_SetDebugMode(GetContext(), true)) 423 423 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!"); 424 427 else 425 428 g_DebuggingServer->RegisterScriptinterface(debugName, this); 426 } */429 } 427 430 428 431 m_CxPrivate.pScriptInterface = this; 429 432 JS_SetContextPrivate(m->m_cx, (void*)&m_CxPrivate); … … 439 442 440 443 // Unregister from the Debugger class 441 444 // 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); 444 447 } 445 448 446 449 void ScriptInterface::ShutDown() -
source/scriptinterface/ThreadDebugger.cpp
17 17 18 18 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 19 19 #include "precompiled.h" // needs to be here for Windows builds 20 /*21 20 21 22 22 #include "ThreadDebugger.h" 23 23 #include "lib/utf8.h" 24 24 #include "ps/CLogger.h" … … 26 26 #include <map> 27 27 #include <queue> 28 28 29 //Operators 30 bool operator==(JS::FrameDescription& a, JS::FrameDescription& b) 31 { 32 return a.fun == b.fun; 33 } 34 35 bool operator!=(JS::FrameDescription& a, JS::FrameDescription& b) 36 { 37 return a.fun != b.fun; 38 } 29 39 // Hooks 30 40 31 41 CMutex ThrowHandlerMutex; … … 37 47 } 38 48 39 49 CMutex TrapHandlerMutex; 40 static JSTrapStatus TrapHandler_(JSContext* cx, JSScript* script, jsbytecode* pc, jsval* rval, jsval closure) 50 static JSTrapStatus TrapHandler_(JSContext* cx, JSScript* script, jsbytecode* pc, jsval* rval, jsval closure) 41 51 { 42 52 CScopeLock lock(TrapHandlerMutex); 43 53 CThreadDebugger* pThreadDebugger = (CThreadDebugger*) JSVAL_TO_PRIVATE(closure); … … 71 81 } 72 82 73 83 CMutex DestroyScriptHookMutex; 74 void DestroyScriptHook_(JS Context* cx, JSScript* script, void* callerdata)84 void DestroyScriptHook_(JSFreeOp* UNUSED(fop), JSScript* script, void* callerdata) 75 85 { 76 86 CScopeLock lock(DestroyScriptHookMutex); 77 87 CThreadDebugger* pThreadDebugger = (CThreadDebugger*) callerdata; 78 return pThreadDebugger->DestroyScriptHook(cx, script); 88 89 return pThreadDebugger->DestroyScriptHook(NULL, script); 79 90 } 80 91 81 92 CMutex StepOutHandlerMutex; … … 95 106 } 96 107 97 108 CMutex CallHookMutex; 98 static void* CallHook_(JSContext* cx, JS StackFrame* fp, JSBool before, JSBool* UNUSED(ok), void* closure)109 static void* CallHook_(JSContext* cx, JSAbstractFramePtr fp, bool UNUSED(isConstruncting), JSBool before, JSBool* UNUSED(ok), void* closure) 99 110 { 100 111 CScopeLock lock(CallHookMutex); 101 112 CThreadDebugger* pThreadDebugger = (CThreadDebugger*) closure; … … 102 113 if (before) 103 114 { 104 115 JSScript* script; 105 script = JS_GetFrameScript(cx, fp);116 script = fp.script(); 106 117 const char* fileName = JS_GetScriptFilename(cx, script); 118 107 119 uint lineno = JS_GetScriptBaseLineNumber(cx, script); 108 JSFunction* fun = JS_GetFrameFunction(cx, fp); 120 121 JSFunction* fun = fp.maybeFun(); 109 122 pThreadDebugger->ExecuteHook(cx, fileName, lineno, script, fun, closure); 110 123 } 111 124 … … 149 162 // and spidermonkey throws errors if it detects a pointer on the stack. 150 163 // We only use the pointer for comparing it with the current stack pointer and we don't try to access it, so it 151 164 // shouldn't be a problem. 152 JS StackFrame** m_pLastBreakFrame;165 JS::FrameDescription** m_pLastBreakFrame; 153 166 uint m_ObjectReferenceID; 154 167 155 168 /// shared between multiple mongoose threads and one scriptinterface thread … … 174 187 : m_NextDbgCmd(DBG_CMD_NONE) 175 188 , m_pScriptInterface(NULL) 176 189 , m_pDebuggingServer(NULL) 177 , m_pLastBreakFrame(new JSStackFrame*)190 , m_pLastBreakFrame(new JS::FrameDescription*) 178 191 , m_IsInBreak(false) 179 192 { } 180 193 … … 293 306 // Remove all the hooks because they store a pointer to this object 294 307 JS_SetExecuteHook(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL); 295 308 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); 298 311 } 299 312 300 313 void CThreadDebugger::ReturnActiveBreakPoints(jsbytecode* pBytecode) … … 333 346 m->m_pDebuggingServer = pDebuggingServer; 334 347 JS_SetExecuteHook(m->m_pScriptInterface->GetJSRuntime(), CallHook_, (void*)this); 335 348 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); 338 351 JS_SetThrowHook(m->m_pScriptInterface->GetJSRuntime(), ThrowHandler_, (void*)this); 339 352 340 353 if (m->m_pDebuggingServer->GetSettingSimultaneousThreadBreak()) … … 352 365 // a higher line number. 353 366 // 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) 354 367 uint line = JS_PCToLineNumber(cx, script, pc); 355 JSStackFrame* iter = NULL;356 JSStackFrame* pStackFrame;357 pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);358 368 uint lastBreakLine = GetLastBreakLine() ; 369 JS::StackDescription* description = JS::DescribeStack(cx, NULL); 370 JS::FrameDescription* pStackFrame = description->frames; 371 JSTrapStatus result = JSTRAP_CONTINUE; 372 359 373 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; 365 380 } 366 381 367 382 JSTrapStatus CThreadDebugger::StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void* UNUSED(closure)) … … 369 384 // We break when we are on the same stack frame but not on the same line 370 385 // or when we are on another stack frame. 371 386 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; 375 389 uint lastBreakLine = GetLastBreakLine(); 390 JSTrapStatus result = JSTRAP_CONTINUE; 376 391 377 392 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; 382 398 } 383 399 384 400 JSTrapStatus CThreadDebugger::StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void* UNUSED(closure)) … … 385 401 { 386 402 // We break when we are in a different Frame and m_pLastBreakFrame is not a parent of the current frame 387 403 // (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)) 392 410 { 393 411 jsval val = JSVAL_VOID; 394 re turnBreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);412 result = BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP); 395 413 } 396 else 397 return JSTRAP_CONTINUE; 414 415 JS::FreeStackDescription(cx, description); 416 return result; 398 417 } 399 418 400 bool CThreadDebugger::CurrentFrameIsChildOf(JS StackFrame* pParentFrame)419 bool CThreadDebugger::CurrentFrameIsChildOf(JS::StackDescription* description, JS::FrameDescription* frame) 401 420 { 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 { 409 426 return true; 410 fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);427 } 411 428 } 412 429 return false; 413 430 } … … 489 506 } 490 507 else if (nextDbgCmd == DBG_CMD_SINGLESTEP || nextDbgCmd == DBG_CMD_STEPINTO || nextDbgCmd == DBG_CMD_STEPOUT) 491 508 { 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); 494 512 495 513 if (!JS_SetSingleStepMode(cx, script, true)) 496 514 LOGERROR(L"JS_SetSingleStepMode returned false!"); // TODO: When can this happen? … … 524 542 } 525 543 break; 526 544 } 527 else 545 else 528 546 debug_warn("Invalid DBGCMD found in CThreadDebugger::BreakHandler!"); 529 547 } 530 548 ClearTrapsToRemove(); … … 545 563 void CThreadDebugger::NewScriptHook(JSContext* cx, const char* filename, unsigned lineno, JSScript* script, JSFunction* UNUSED(fun), void* UNUSED(callerdata)) 546 564 { 547 565 uint scriptExtent = JS_GetScriptLineExtent (cx, script); 566 567 if (filename == NULL) 568 filename = "<No FileName>"; 569 548 570 std::string stringFileName(filename); 549 571 if (stringFileName.empty()) 550 572 return; … … 588 610 589 611 void CThreadDebugger::DestroyScriptHook(JSContext* cx, JSScript* script) 590 612 { 613 if (cx == NULL) 614 { 615 cx = m->m_pScriptInterface->GetContext(); 616 } 591 617 uint scriptExtent = JS_GetScriptLineExtent (cx, script); 592 618 uint baseLine = JS_GetScriptBaseLineNumber(cx, script); 593 619 … … 649 675 ENSURE(GetIsInBreak()); 650 676 651 677 CScopeLock lock(m->m_Mutex); 652 653 JSStackFrame *fp; 654 JSStackFrame *iter = 0; 655 jsint counter = 0; 656 678 657 679 JSObject* jsArray; 658 680 jsArray = JS_NewArrayObject(m->m_pScriptInterface->GetContext(), 0, 0); 659 681 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) 668 689 functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "null"); 669 690 else 670 691 { 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) 673 697 functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "anonymous"); 698 699 674 700 } 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); 677 702 ENSURE(ret); 678 fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);679 counter++;680 703 } 681 704 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 682 710 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(); 684 712 } 685 713 686 714 void CThreadDebugger::GetStackFrameData(std::stringstream& response, uint nestingLevel, STACK_INFO stackInfoKind) … … 721 749 ENSURE(GetIsInBreak()); 722 750 723 751 CScopeLock lock(m->m_Mutex); 724 JSStackFrame *iter = 0;725 uint counter = 0;726 jsval val;727 752 728 753 if (stackInfo == STACK_INFO_GLOBALOBJECT) 729 754 { 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); 733 759 } 734 760 else 735 761 { 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) 738 775 { 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)) 740 783 { 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; 747 804 } 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 755 809 } 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 759 813 } 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); 760 823 } 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 // } 761 864 } 762 */763 865 866 764 867 /* 765 868 * TODO: This is very hacky and ugly and should be improved. 766 869 * It replaces cyclic references with a notification that cyclic references are not supported. … … 774 877 * the rest of the game and because this part of code should be replaced anyway in the future. 775 878 */ 776 879 777 /* 880 778 881 namespace CyclicRefWorkaround 779 882 { 780 883 std::set<JSObject*> g_ProcessedObjects; … … 785 888 786 889 struct Stringifier 787 890 { 788 static JSBool callback(const jschar* buf, uint32 len, void* data)891 static JSBool callback(const jschar* buf, Uint32 len, void* data) 789 892 { 790 893 utf16string str(buf, buf+len); 791 894 std::wstring strw(str.begin(), str.end()); … … 797 900 798 901 std::stringstream stream; 799 902 }; 800 801 JSBool replacer(JSContext * cx, uintN UNUSED(argc), jsval*vp)903 904 JSBool replacer(JSContext *cx, unsigned UNUSED(argc), JS::Value *vp) 802 905 { 803 906 jsval value = JS_ARGV(cx, vp)[1]; 804 907 jsval key = JS_ARGV(cx, vp)[0]; … … 807 910 else 808 911 g_countSameKeys = 0; 809 912 810 if ( JSVAL_IS_OBJECT(value))913 if (value.isObject()) 811 914 { 812 915 // Work around a spidermonkey bug that causes replacer to be called twice with the same key: 813 916 // https://bugzilla.mozilla.org/show_bug.cgi?id=636079 … … 851 954 jsval execString; 852 955 if (JS_GetPendingException(m->m_pScriptInterface->GetContext(), &exec)) 853 956 { 854 if ( JSVAL_IS_OBJECT(exec))957 if (exec.isObject()) 855 958 { 856 959 JS_GetProperty(m->m_pScriptInterface->GetContext(), JSVAL_TO_OBJECT(exec), "message", &execString); 857 960 … … 936 1039 CScopeLock lock(m->m_Mutex); 937 1040 return m->m_ID; 938 1041 } 939 */ 1042 -
source/scriptinterface/ThreadDebugger.h
17 17 18 18 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 19 19 20 //#ifndef INCLUDED_THREADDEBUGGER21 //#define INCLUDED_THREADDEBUGGER22 // 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 that28 // //only one thread accesses the Breakpoint at a time29 //class CBreakPoint30 //{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 CBreakPoint40 //{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 constructor51 //, 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 CThreadDebugger68 //{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 this78 //* 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 execution102 //* 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 context118 //*/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 call125 //*/126 //void SetAllNewTraps();127 //128 ///** @brief Sets a new trap and stores the information in the CActiveBreakPoint pointer129 //* Make sure that a mapping exists before calling this function130 //* Threading: Locking m_Mutex is required by the callee131 //*/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 callee136 //*137 //* @param filename full vfs path to the script filename138 //* @param userLine linenumber where the USER set the breakpoint (UserLine)139 //*140 //* @return true if the breakpoint's state was changed141 //*/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 equal150 //*/151 //bool CompareScriptInterfacePtr(ScriptInterface* pScriptInterface) const;152 //153 //// Getter/Setters for members that need to be threadsafe154 //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 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 159 // void ContinueExecution(); 160 //void SetNextDbgCmd(DBGCMD dbgCmd);161 //DBGCMD GetNextDbgCmd();162 //// The callee is responsible for locking m_Mutex163 //void AddStackInfoRequest(STACK_INFO requestType, uint nestingLevel, SDL_sem* semaphore);164 //165 //166 //private:167 //// Getters/Setters for members that need to be threadsafe168 //void SetBreakFileName(std::string breakFileName);169 //void SetLastBreakLine(uint breakLine);170 //void SetIsInBreak(bool isInBreak);171 //172 //// Other threadsafe functions173 //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_THREADDEBUGGER160 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(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