Ticket #2973: 2973_continuation1.patch
File 2973_continuation1.patch, 61.0 KB (added by , 8 years ago) |
---|
-
source/ps/GameSetup/Config.cpp
109 109 CFG_GET_VAL("jsdebugger.enable", g_JSDebuggerEnabled); 110 110 CFG_GET_VAL("profiler2.script.enable", g_ScriptProfilingEnabled); 111 111 112 if (g_JSDebuggerEnabled)113 LOGERROR("JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)");112 //if (g_JSDebuggerEnabled) 113 // LOGERROR("JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details)"); 114 114 // Script Debugging and profiling does not make sense together because of the hooks 115 115 // that reduce performance a lot - and it wasn't tested if it even works together. 116 116 if (g_JSDebuggerEnabled && g_ScriptProfilingEnabled) -
source/ps/GameSetup/GameSetup.cpp
734 734 735 735 736 736 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 737 //TIMER_BEGIN(L"shutdown DebuggingServer (if active)");738 //delete g_DebuggingServer;739 //TIMER_END(L"shutdown DebuggingServer (if active)");737 TIMER_BEGIN(L"shutdown DebuggingServer (if active)"); 738 delete g_DebuggingServer; 739 TIMER_END(L"shutdown DebuggingServer (if active)"); 740 740 741 741 delete &g_L10n; 742 742 … … 963 963 964 964 // before scripting 965 965 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 966 //if (g_JSDebuggerEnabled)967 //g_DebuggingServer = new CDebuggingServer();966 if (g_JSDebuggerEnabled) 967 g_DebuggingServer = new CDebuggingServer(); 968 968 969 969 // Optionally start profiler HTTP output automatically 970 970 // (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 /*20 21 21 22 22 #include "DebuggingServer.h" 23 23 #include "ThreadDebugger.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
1 1 /* Copyright (C) 2013 Wildfire Games. 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 2 * This file is part of 0 A.D. 3 * 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * 0 A.D. is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 */ 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 25 25 #include "lib/debug.h" … … 403 403 } 404 404 405 405 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 406 /*406 407 407 if (g_JSDebuggerEnabled && g_DebuggingServer != NULL) 408 408 { 409 if(!JS_SetDebugMode (GetContext(), true))409 if(!JS_SetDebugModeForAllCompartments(GetContext(), true)) 410 410 LOGERROR("Failed to set Spidermonkey to debug mode!"); 411 411 else 412 412 g_DebuggingServer->RegisterScriptinterface(debugName, this); 413 } */413 } 414 414 415 415 m_CxPrivate.pScriptInterface = this; 416 416 JS_SetContextPrivate(m->m_cx, (void*)&m_CxPrivate); … … 426 426 427 427 // Unregister from the Debugger class 428 428 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 429 //if (g_JSDebuggerEnabled && g_DebuggingServer != NULL)430 //g_DebuggingServer->UnRegisterScriptinterface(this);429 if (g_JSDebuggerEnabled && g_DebuggingServer != NULL) 430 g_DebuggingServer->UnRegisterScriptinterface(this); 431 431 } 432 432 433 433 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 /*20 21 21 22 22 #include "ThreadDebugger.h" 23 23 #include "lib/utf8.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.funDisplayName() == b.funDisplayName(); 33 } 34 35 bool operator!=(JS::FrameDescription& a, JS::FrameDescription& b) 36 { 37 return a.funDisplayName() != b.funDisplayName(); 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; … … 94 105 return pThreadDebugger->CheckForBreakRequestHandler(cx, script, pc, rval, NULL); 95 106 } 96 107 108 97 109 CMutex CallHookMutex; 98 static void* CallHook_(JSContext* cx, JSStackFrame* fp, bool before, bool* UNUSED(ok), void* closure) 110 //static void* CallHook_(JSContext* cx, JSAbstractFramePtr* fp, bool isConstructing, bool before, bool* UNUSED(ok), void* closure) 111 static void* CallHook_(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, bool before, bool *ok, void *closure) 99 112 { 100 113 CScopeLock lock(CallHookMutex); 101 114 CThreadDebugger* pThreadDebugger = (CThreadDebugger*) closure; … … 102 115 if (before) 103 116 { 104 117 JSScript* script; 105 script = JS_GetFrameScript(cx, fp); 106 const char* fileName = JS_GetScriptFilename(cx, script); 118 script = frame.script(); 119 const char* fileName = JS_GetScriptFilename(script); 120 107 121 uint lineno = JS_GetScriptBaseLineNumber(cx, script); 108 JSFunction* fun = JS_GetFrameFunction(cx, fp); 122 123 JSFunction* fun = frame.maybeFun(); 109 124 pThreadDebugger->ExecuteHook(cx, fileName, lineno, script, fun, closure); 110 125 } 111 126 … … 149 164 // and spidermonkey throws errors if it detects a pointer on the stack. 150 165 // We only use the pointer for comparing it with the current stack pointer and we don't try to access it, so it 151 166 // shouldn't be a problem. 152 JS StackFrame** m_pLastBreakFrame;167 JS::FrameDescription** m_pLastBreakFrame; 153 168 uint m_ObjectReferenceID; 154 169 155 170 /// shared between multiple mongoose threads and one scriptinterface thread … … 174 189 : m_NextDbgCmd(DBG_CMD_NONE) 175 190 , m_pScriptInterface(NULL) 176 191 , m_pDebuggingServer(NULL) 177 , m_pLastBreakFrame(new JSStackFrame*)192 , m_pLastBreakFrame(new JS::FrameDescription*) 178 193 , m_IsInBreak(false) 179 194 { } 180 195 … … 273 288 ENSURE(script != NULL && pc != NULL); 274 289 activeBreakPoint->m_ActualLine = JS_PCToLineNumber(m->m_pScriptInterface->GetContext(), script, pc); 275 290 276 JS_SetTrap(m->m_pScriptInterface->GetContext(), script, pc, TrapHandler_, PRIVATE_TO_JSVAL(this)); 291 JS::Rooted<JSScript*> hscript(m->m_pScriptInterface->GetContext(), script); 292 JS::Rooted<jsval> hjsval(m->m_pScriptInterface->GetContext(), PRIVATE_TO_JSVAL((JSObject*)this)); 293 JS_SetTrap(m->m_pScriptInterface->GetContext(), hscript, pc, TrapHandler_, hjsval); 277 294 } 278 295 279 296 … … 293 310 // Remove all the hooks because they store a pointer to this object 294 311 JS_SetExecuteHook(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL); 295 312 JS_SetCallHook(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL); 296 JS_SetNewScriptHook (m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);297 JS_SetDestroyScriptHook (m->m_pScriptInterface->GetJSRuntime(), NULL, NULL);313 JS_SetNewScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL); 314 JS_SetDestroyScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL); 298 315 } 299 316 300 317 void CThreadDebugger::ReturnActiveBreakPoints(jsbytecode* pBytecode) … … 331 348 m->m_Name = name; 332 349 m->m_pScriptInterface = pScriptInterface; 333 350 m->m_pDebuggingServer = pDebuggingServer; 351 //JSInterpreterHook 334 352 JS_SetExecuteHook(m->m_pScriptInterface->GetJSRuntime(), CallHook_, (void*)this); 335 353 JS_SetCallHook(m->m_pScriptInterface->GetJSRuntime(), CallHook_, (void*)this); 336 JS_SetNewScriptHook (m->m_pScriptInterface->GetJSRuntime(), NewScriptHook_, (void*)this);337 JS_SetDestroyScriptHook (m->m_pScriptInterface->GetJSRuntime(), DestroyScriptHook_, (void*)this);354 JS_SetNewScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), NewScriptHook_, (void*)this); 355 JS_SetDestroyScriptHookProc(m->m_pScriptInterface->GetJSRuntime(), DestroyScriptHook_, (void*)this); 338 356 JS_SetThrowHook(m->m_pScriptInterface->GetJSRuntime(), ThrowHandler_, (void*)this); 339 357 340 358 if (m->m_pDebuggingServer->GetSettingSimultaneousThreadBreak()) … … 352 370 // a higher line number. 353 371 // 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 372 uint line = JS_PCToLineNumber(cx, script, pc); 355 JSStackFrame* iter = NULL;356 JSStackFrame* pStackFrame;357 pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);358 373 uint lastBreakLine = GetLastBreakLine() ; 374 JS::StackDescription* description = JS::DescribeStack(cx, NULL); 375 JS::FrameDescription* pStackFrame = description->frames; 376 JSTrapStatus result = JSTRAP_CONTINUE; 377 359 378 jsval val = JSVAL_VOID; 360 if ((*m->m_pLastBreakFrame == pStackFrame && lastBreakLine != line) || 361 (*m->m_pLastBreakFrame != pStackFrame && !CurrentFrameIsChildOf(*m->m_pLastBreakFrame))) 362 return BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP); 363 else 364 return JSTRAP_CONTINUE; 379 if ((**m->m_pLastBreakFrame == *pStackFrame && lastBreakLine != line) || 380 (**m->m_pLastBreakFrame != *pStackFrame && !CurrentFrameIsChildOf(description, *m->m_pLastBreakFrame))) 381 result = BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP); 382 383 JS::FreeStackDescription(cx, description); 384 return result; 365 385 } 366 386 367 387 JSTrapStatus CThreadDebugger::StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void* UNUSED(closure)) … … 369 389 // We break when we are on the same stack frame but not on the same line 370 390 // or when we are on another stack frame. 371 391 uint line = JS_PCToLineNumber(cx, script, pc); 372 JSStackFrame* iter = NULL; 373 JSStackFrame* pStackFrame; 374 pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 392 JS::StackDescription* description = JS::DescribeStack(cx, NULL); 393 JS::FrameDescription* pStackFrame = description->frames; 375 394 uint lastBreakLine = GetLastBreakLine(); 395 JSTrapStatus result = JSTRAP_CONTINUE; 376 396 377 397 jsval val = JSVAL_VOID; 378 if ((*m->m_pLastBreakFrame == pStackFrame && lastBreakLine != line) || *m->m_pLastBreakFrame != pStackFrame) 379 return BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP); 380 else 381 return JSTRAP_CONTINUE; 398 if ((**m->m_pLastBreakFrame == *pStackFrame && lastBreakLine != line) || **m->m_pLastBreakFrame != *pStackFrame) 399 result = BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP); 400 401 JS::FreeStackDescription(cx, description); 402 return result; 382 403 } 383 404 384 405 JSTrapStatus CThreadDebugger::StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void* UNUSED(closure)) … … 385 406 { 386 407 // We break when we are in a different Frame and m_pLastBreakFrame is not a parent of the current frame 387 408 // (because we stepped out of the function) 388 JSStackFrame* iter = NULL; 389 JSStackFrame* pStackFrame; 390 pStackFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 391 if (pStackFrame != *m->m_pLastBreakFrame && !CurrentFrameIsChildOf(*m->m_pLastBreakFrame)) 409 410 JS::StackDescription* description = JS::DescribeStack(cx, NULL); 411 JS::FrameDescription* pStackFrame = description->frames; 412 JSTrapStatus result = JSTRAP_CONTINUE; 413 414 if (*pStackFrame != **m->m_pLastBreakFrame && !CurrentFrameIsChildOf(description, *m->m_pLastBreakFrame)) 392 415 { 393 416 jsval val = JSVAL_VOID; 394 re turnBreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP);417 result = BreakHandler(cx, script, pc, rval, val, BREAK_SRC_INTERRUP); 395 418 } 396 else 397 return JSTRAP_CONTINUE; 419 420 JS::FreeStackDescription(cx, description); 421 return result; 398 422 } 399 423 400 bool CThreadDebugger::CurrentFrameIsChildOf(JS StackFrame* pParentFrame)424 bool CThreadDebugger::CurrentFrameIsChildOf(JS::StackDescription* description, JS::FrameDescription* frame) 401 425 { 402 JSStackFrame* iter = NULL; 403 JSStackFrame* fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 404 // Get the first parent Frame 405 fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 406 while (fp) 407 { 408 if (fp == pParentFrame) 426 for (int i = 0; i < (int)description->nframes; i++) { 427 JS::FrameDescription* nextframe = (description->frames + i); 428 429 if (*nextframe == *frame) 430 { 409 431 return true; 410 fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);432 } 411 433 } 412 434 return false; 413 435 } … … 429 451 430 452 JSTrapStatus CThreadDebugger::ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval) 431 453 { 432 jsval jsexception; 454 jsval ujsexception; 455 JS::Rooted<jsval> jsexception(m->m_pScriptInterface->GetContext(), ujsexception); 433 456 JS_GetPendingException(cx, &jsexception); 434 457 if (JSVAL_IS_STRING(jsexception)) 435 458 { … … 448 471 JSTrapStatus CThreadDebugger::BreakHandler(JSContext* cx, JSScript* script, jsbytecode* pc, jsval* UNUSED(rval), jsval UNUSED(closure), BREAK_SRC breakSrc) 449 472 { 450 473 uint line = JS_PCToLineNumber(cx, script, pc); 451 std::string filename(JS_GetScriptFilename( cx,script));474 std::string filename(JS_GetScriptFilename(script)); 452 475 453 476 SetIsInBreak(true); 454 477 SaveCallstack(); … … 459 482 if (breakSrc == BREAK_SRC_INTERRUP) 460 483 { 461 484 JS_ClearInterrupt(m->m_pScriptInterface->GetJSRuntime(), NULL, NULL); 462 JS_SetSingleStepMode(cx, script, false); 485 JS::Rooted<JSScript*> hscript(cx, script); 486 JS_SetSingleStepMode(cx, hscript, false); 463 487 } 464 488 465 489 if (m->m_pDebuggingServer->GetSettingSimultaneousThreadBreak()) … … 489 513 } 490 514 else if (nextDbgCmd == DBG_CMD_SINGLESTEP || nextDbgCmd == DBG_CMD_STEPINTO || nextDbgCmd == DBG_CMD_STEPOUT) 491 515 { 492 JSStackFrame* iter = NULL; 493 *m->m_pLastBreakFrame = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 494 495 if (!JS_SetSingleStepMode(cx, script, true)) 516 JS::StackDescription* description = JS::DescribeStack(m->m_pScriptInterface->GetContext(), NULL); 517 *m->m_pLastBreakFrame = description->frames; 518 //JS::FreeStackDescription(m->m_pScriptInterface->GetContext(), description); 519 520 JS::Rooted<JSScript*> hscript(cx, script); 521 if (!JS_SetSingleStepMode(cx, hscript, true)) 496 522 LOGERROR("JS_SetSingleStepMode returned false!"); // TODO: When can this happen? 497 523 else 498 524 { … … 515 541 } 516 542 else if (nextDbgCmd == DBG_CMD_CONTINUE) 517 543 { 518 if (!JS_SetSingleStepMode(cx, script, true)) 544 JS::Rooted<JSScript*> hscript(cx, script); 545 if (!JS_SetSingleStepMode(cx, hscript, true)) 519 546 LOGERROR("JS_SetSingleStepMode returned false!"); // TODO: When can this happen? 520 547 else 521 548 { … … 524 551 } 525 552 break; 526 553 } 527 else 554 else 528 555 debug_warn("Invalid DBGCMD found in CThreadDebugger::BreakHandler!"); 529 556 } 530 557 ClearTrapsToRemove(); … … 545 572 void CThreadDebugger::NewScriptHook(JSContext* cx, const char* filename, unsigned lineno, JSScript* script, JSFunction* UNUSED(fun), void* UNUSED(callerdata)) 546 573 { 547 574 uint scriptExtent = JS_GetScriptLineExtent (cx, script); 575 576 if (filename == NULL) 577 filename = "<No FileName>"; 578 548 579 std::string stringFileName(filename); 549 580 if (stringFileName.empty()) 550 581 return; … … 588 619 589 620 void CThreadDebugger::DestroyScriptHook(JSContext* cx, JSScript* script) 590 621 { 622 if (cx == NULL) 623 { 624 cx = m->m_pScriptInterface->GetContext(); 625 } 591 626 uint scriptExtent = JS_GetScriptLineExtent (cx, script); 592 627 uint baseLine = JS_GetScriptBaseLineNumber(cx, script); 593 628 594 629 char* pStr = NULL; 595 pStr = (char*)JS_GetScriptFilename( cx,script);630 pStr = (char*)JS_GetScriptFilename(script); 596 631 if (pStr != NULL) 597 632 { 598 633 std::string fileName(pStr); … … 650 685 651 686 CScopeLock lock(m->m_Mutex); 652 687 653 JSStackFrame *fp;654 JSStackFrame *iter = 0;655 jsint counter = 0;688 //JSStackFrame *fp; 689 //JSStackFrame *iter = 0; 690 //jsint counter = 0; 656 691 657 JSObject* jsArray; 658 jsArray = JS_NewArrayObject(m->m_pScriptInterface->GetContext(), 0, 0); 659 JSString* functionID; 692 //jsArray = JS_NewArrayObject(m->m_pScriptInterface->GetContext(), 0, 0); 693 //JSString* functionID; 660 694 661 fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);695 //fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 662 696 663 while (fp)664 {665 JSFunction* fun = 0;666 fun = JS_GetFrameFunction(m->m_pScriptInterface->GetContext(), fp);667 if (NULL == fun)668 functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "null");669 else670 {671 functionID = JS_GetFunctionId(fun);672 if (NULL == functionID)673 functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "anonymous");674 }675 697 676 bool ret = JS_DefineElement(m->m_pScriptInterface->GetContext(), jsArray, counter, STRING_TO_JSVAL(functionID), NULL, NULL, 0); 677 ENSURE(ret); 678 fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 679 counter++; 698 JS::StackDescription* description = JS::DescribeStack(m->m_pScriptInterface->GetContext(), NULL); 699 int limit = (int)description->nframes; 700 JS::Rooted<JSObject*> hobj1(m->m_pScriptInterface->GetContext(), 0); 701 JS::Rooted<JSObject*> hobj2(m->m_pScriptInterface->GetContext(), 0); 702 JSObject* jsArray = JS_NewObject(m->m_pScriptInterface->GetContext(), NULL, hobj1, hobj2); 703 m->m_Callstack.clear(); 704 for (int i = 0; i < (int)description->nframes; i++) { 705 JS::FrameDescription* frame = (description->frames + i); 706 //JSFunction* fun = 0; 707 //fun = JS_GetFrameFunction(m->m_pScriptInterface->GetContext(), fp); 708 //if (NULL == frame->funDisplayName()) 709 // functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "null"); 710 //else 711 //{ 712 // functionID = JS_GetFunctionId(fun); 713 // if (NULL == functionID) 714 // functionID = JS_NewStringCopyZ(m->m_pScriptInterface->GetContext(), "anonymous"); 715 //} 716 717 //bool ret = JS_DefineElement(m->m_pScriptInterface->GetContext(), jsArray, counter, STRING_TO_JSVAL(functionID), NULL, NULL, 0); 718 //ENSURE(ret); 719 720 jsArray = JSVAL_TO_OBJECT(STRING_TO_JSVAL(JS_FORGET_STRING_FLATNESS(frame->funDisplayName()))); 721 JS::Rooted<jsval> hjsval(m->m_pScriptInterface->GetContext(), OBJECT_TO_JSVAL(jsArray)); 722 m->m_Callstack.append(m->m_pScriptInterface->StringifyJSON(&hjsval, false).c_str()); 723 //fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 724 //counter++; 680 725 } 681 726 682 m->m_Callstack.clear();683 m->m_Callstack = m->m_pScriptInterface->StringifyJSON(OBJECT_TO_JSVAL(jsArray), false).c_str();684 727 } 685 728 686 729 void CThreadDebugger::GetStackFrameData(std::stringstream& response, uint nestingLevel, STACK_INFO stackInfoKind) … … 719 762 void CThreadDebugger::SaveStackFrameData(STACK_INFO stackInfo, uint nestingLevel) 720 763 { 721 764 ENSURE(GetIsInBreak()); 722 765 723 766 CScopeLock lock(m->m_Mutex); 724 JSStackFrame *iter = 0;767 //JSStackFrame *iter = 0; 725 768 uint counter = 0; 726 769 jsval val; 727 770 728 771 if (stackInfo == STACK_INFO_GLOBALOBJECT) 729 772 { 730 773 JSObject* obj; 731 obj = JS _GetGlobalForScopeChain(m->m_pScriptInterface->GetContext());774 obj = JS::CurrentGlobalOrNull(m->m_pScriptInterface->GetContext()); 732 775 m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(OBJECT_TO_JSVAL(obj), false); 733 776 } 734 777 else 735 778 { 736 JSStackFrame *fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 737 while (fp) 779 JS::StackDescription* description = JS::DescribeStack(m->m_pScriptInterface->GetContext(), NULL); 780 JS::FrameDescription* frame = (description->frames + nestingLevel); 781 782 JSBrokenFrameIterator bFrame(m->m_pScriptInterface->GetContext()); 783 for (uint i = 0; i < nestingLevel; i++) { 784 bFrame = ++bFrame; 785 } 786 JSAbstractFramePtr aFrame = (JSAbstractFramePtr)bFrame.abstractFramePtr(); 787 JSObject* callobject = aFrame.callObject(m->m_pScriptInterface->GetContext()); //need the call to build evaluateInStackFrame 788 789 const char* fileName = frame->filename(); 790 791 //JSStackFrame *fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 792 //while (fp) 793 //{ 794 while (counter != nestingLevel) 738 795 { 739 if (counter == nestingLevel)740 {741 if (stackInfo == STACK_INFO_LOCALS)742 {743 JSObject* obj;744 obj = JS_GetFrameCallObject(m->m_pScriptInterface->GetContext(), fp);745 //obj = JS_GetFrameScopeChain(m->m_pScriptInterface->GetContext(), fp);746 m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(OBJECT_TO_JSVAL(obj), false);747 }748 else if (stackInfo == STACK_INFO_THIS)749 {750 if (JS_GetFrameThis(m->m_pScriptInterface->GetContext(), fp, &val))751 m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(val, false);752 else753 m->m_StackFrameData[stackInfo][nestingLevel] = "";754 }755 }756 757 796 counter++; 758 fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter);797 //fp = JS_FrameIterator(m->m_pScriptInterface->GetContext(), &iter); 759 798 } 799 800 if (stackInfo == STACK_INFO_LOCALS) 801 { 802 803 JS::RootedValue rLocal(m->m_pScriptInterface->GetContext()); 804 JS::MutableHandleValue vLocal(&rLocal); 805 const char* lName = JS_EncodeString(m->m_pScriptInterface->GetContext(), JS_FORGET_STRING_FLATNESS(frame->funDisplayName())); 806 aFrame.evaluateInStackFrame(m->m_pScriptInterface->GetContext(), lName, strlen(lName), fileName, frame->lineno(), vLocal); 807 } 808 else if (stackInfo == STACK_INFO_THIS) 809 { 810 m->m_StackFrameData[stackInfo][nestingLevel] = StringifyCyclicJSON(val, false); 811 } 812 else 813 { 814 m->m_StackFrameData[stackInfo][nestingLevel] = ""; 815 } 760 816 } 761 817 } 762 */763 818 819 764 820 /* 765 821 * TODO: This is very hacky and ugly and should be improved. 766 822 * It replaces cyclic references with a notification that cyclic references are not supported. … … 774 830 * the rest of the game and because this part of code should be replaced anyway in the future. 775 831 */ 776 832 777 /*833 778 834 namespace CyclicRefWorkaround 779 835 { 780 836 std::set<JSObject*> g_ProcessedObjects; … … 785 841 786 842 struct Stringifier 787 843 { 788 static bool callback(const jschar* buf, u int32 len, void* data)844 static bool callback(const jschar* buf, u32 len, void* data) 789 845 { 790 846 utf16string str(buf, buf+len); 791 847 std::wstring strw(str.begin(), str.end()); … … 798 854 std::stringstream stream; 799 855 }; 800 856 801 bool replacer(JSContext* cx, uint NUNUSED(argc), jsval* vp)857 bool replacer(JSContext* cx, uint UNUSED(argc), jsval* vp) 802 858 { 803 jsval value = JS_ARGV(cx, vp)[1];804 jsval key = JS_ARGV(cx, vp)[0];859 jsval value = js_CallArgs_h(cx, vp)[1]; 860 jsval key = js_CallArgs_h(cx, vp)[0]; 805 861 if (g_LastKey == key) 806 862 g_countSameKeys++; 807 863 else 808 864 g_countSameKeys = 0; 809 865 810 if ( JSVAL_IS_OBJECT(value))866 if (value.isObject()) 811 867 { 812 868 // Work around a spidermonkey bug that causes replacer to be called twice with the same key: 813 869 // https://bugzilla.mozilla.org/show_bug.cgi?id=636079 … … 821 877 { 822 878 g_RecursionDetectedInPrevReplacer = true; 823 879 jsval ret = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "Debugger: object removed from output because of cyclic reference.")); 824 JS _SET_RVAL(cx, vp,ret);880 JS::CallReceiverFromVp(&ret); 825 881 g_LastKey = key; 826 882 g_LastValue = value; 827 883 return true; … … 830 886 g_LastKey = key; 831 887 g_LastValue = value; 832 888 g_RecursionDetectedInPrevReplacer = false; 833 JS _SET_RVAL(cx, vp, JS_ARGV(cx,vp)[1]);889 JS::CallReceiverFromVp(js_CallArgs_h(cx, &vp)[1]); 834 890 return true; 835 891 } 836 892 } … … 842 898 CyclicRefWorkaround::g_LastKey = JSVAL_VOID; 843 899 844 900 JSObject* pGlob = JSVAL_TO_OBJECT(m->m_pScriptInterface->GetGlobalObject()); 845 JSFunction* fun = JS_DefineFunction(m->m_pScriptInterface->GetContext(), pGlob, "replacer", CyclicRefWorkaround::replacer, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); 901 JS::Rooted<JSObject*> hpGlob(m->m_pScriptInterface->GetContext(), pGlob); 902 JSFunction* fun = JS_DefineFunction(m->m_pScriptInterface->GetContext(), hpGlob, "replacer", CyclicRefWorkaround::replacer, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); 846 903 JSObject* replacer = JS_GetFunctionObject(fun); 847 if (!JS_Stringify(m->m_pScriptInterface->GetContext(), &obj, replacer, indent ? INT_TO_JSVAL(2) : JSVAL_VOID, &CyclicRefWorkaround::Stringifier::callback, &str)) 904 JS::Rooted<jsval> hobj(m->m_pScriptInterface->GetContext(), obj); 905 JS::Rooted<JSObject*> hreplacer(m->m_pScriptInterface->GetContext(), replacer); 906 JS::Rooted<jsval> hindent(m->m_pScriptInterface->GetContext(), indent ? INT_TO_JSVAL(2) : JSVAL_VOID); 907 if (!JS_Stringify(m->m_pScriptInterface->GetContext(), &hobj, hreplacer, hindent, &CyclicRefWorkaround::Stringifier::callback, &str)) 848 908 { 849 909 LOGERROR("StringifyJSON failed"); 850 jsval exec; 851 jsval execString; 910 jsval uexec=OBJECT_TO_JSVAL(0); 911 jsval uexecString=OBJECT_TO_JSVAL(0); 912 913 JS::Rooted<jsval> exec(m->m_pScriptInterface->GetContext(), uexec); 914 JS::Rooted<jsval> execString(m->m_pScriptInterface->GetContext(), uexecString); 915 852 916 if (JS_GetPendingException(m->m_pScriptInterface->GetContext(), &exec)) 853 917 { 854 if ( JSVAL_IS_OBJECT(exec))918 if (exec.isObject()) 855 919 { 856 JS_GetProperty(m->m_pScriptInterface->GetContext(), JSVAL_TO_OBJECT(exec), "message", &execString); 920 JS::Rooted<JSObject*> hexec(m->m_pScriptInterface->GetContext(), JSVAL_TO_OBJECT(exec)); 921 JS_GetProperty(m->m_pScriptInterface->GetContext(), hexec, "message", &execString); 857 922 858 923 if (JSVAL_IS_STRING(execString)) 859 924 { … … 936 1001 CScopeLock lock(m->m_Mutex); 937 1002 return m->m_ID; 938 1003 } 939 */ 1004 -
source/scriptinterface/ThreadDebugger.h
1 1 /* Copyright (C) 2013 Wildfire Games. 2 * This file is part of 0 A.D. 3 * 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * 0 A.D. is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 2 * This file is part of 0 A.D. 3 * 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * 0 A.D. is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 */ 19 17 20 //#ifndef INCLUDED_THREADDEBUGGER 21 //#define INCLUDED_THREADDEBUGGER 22 // 23 //#include "DebuggingServer.h" 24 //#include "ScriptInterface.h" 25 //#include "scriptinterface/ScriptExtraHeaders.h" 26 // 27 //// These Breakpoint classes are not implemented threadsafe. The class using the Breakpoints is responsible to make sure that 28 //// only one thread accesses the Breakpoint at a time 29 //class CBreakPoint 30 //{ 31 //public: 32 // CBreakPoint() : m_UserLine(0) { } 33 // 34 // uint m_UserLine; 35 // std::string m_Filename; 36 //}; 37 // 38 //// Only use this with one ScriptInterface/CThreadDebugger! 39 //class CActiveBreakPoint : public CBreakPoint 40 //{ 41 //public: 42 // CActiveBreakPoint() 43 // : m_ActualLine(m_UserLine) 44 // , m_Script(NULL) 45 // , m_Pc(NULL) 46 // , m_ToRemove(false) 47 // { } 48 // 49 // CActiveBreakPoint(CBreakPoint breakPoint) 50 // : CBreakPoint(breakPoint) // using default copy constructor 51 // , m_ActualLine(m_UserLine) 52 // , m_Script(NULL) 53 // , m_Pc(NULL) 54 // , m_ToRemove(false) 55 // { } 56 // 57 // uint m_ActualLine; 58 // JSScript* m_Script; 59 // jsbytecode* m_Pc; 60 // bool m_ToRemove; 61 //}; 62 // 63 //enum BREAK_SRC { BREAK_SRC_TRAP, BREAK_SRC_INTERRUP, BREAK_SRC_EXCEPTION }; 64 // 65 //struct ThreadDebugger_impl; 66 // 67 //class CThreadDebugger 68 //{ 69 //public: 70 // CThreadDebugger(); 71 // ~CThreadDebugger(); 72 // 73 // /** @brief Initialize the object (required before using the object!). 74 // * 75 // * @param id A unique identifier greater than 0 for the object inside its CDebuggingServer object. 76 // * @param name A name that will be can be displayed by the UI to identify the thread. 77 // * @param pScriptInterface Pointer to a scriptinterface. All Hooks, breakpoint traps etc. will be registered in this 78 // * scriptinterface and will be called by the thread this scriptinterface is running in. 79 // * @param pDebuggingServer Pointer to the DebuggingServer object this Object should belong to. 80 // * 81 // * @return Return value. 82 // */ 83 // void Initialize(uint id, std::string name, ScriptInterface* pScriptInterface, CDebuggingServer* pDebuggingServer); 84 // 85 // 86 // // A bunch of hooks used to get information from spidermonkey. 87 // // These hooks are used internally only but have to be public because they need to be accessible from the global hook functions. 88 // // Spidermonkey requires function pointers as hooks, which only works if the functions are global or static (not part of an object). 89 // // These global functions in ThreadDebugger.cpp are just wrappers for the following member functions. 90 // 91 // /** Simply calls BreakHandler with BREAK_SRC_TRAP */ 92 // JSTrapStatus TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure); 93 // /** Hook to capture exceptions and breakpoints in code (throw "Breakpoint";) */ 94 // JSTrapStatus ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval); 95 // /** All other hooks call this one if the execution should be paused. It puts the program in a wait-loop and 96 // * waits for weak-up events (continue, step etc.). */ 97 // JSTrapStatus BreakHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure, BREAK_SRC breakSrc); 98 // JSTrapStatus StepHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure); 99 // JSTrapStatus StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure); 100 // JSTrapStatus StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure); 101 // /** This is an interrup-hook that can be called multiple times per line of code and is used to break into the execution 102 // * without previously setting a breakpoint and to break other threads when one thread triggers a breakpoint */ 103 // JSTrapStatus CheckForBreakRequestHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure); 104 // /** The callback function which gets executed for each new script that gets loaded and each function inside a script. 105 // * We use it for "Execute-Hooks" and "Call-Hooks" in terms of Spidermonkey. 106 // * This hook actually sets the traps (Breakpoints) "on the fly" that have been defined by the user previously. 107 // */ 108 // void ExecuteHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata); 109 // /** This hook is used to update the mapping between filename plus line-numbers and jsbytecode pointers */ 110 // void NewScriptHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata); 111 // /** This hook makes sure that invalid mappings between filename plus line-number and jsbytecode points get deleted */ 112 // void DestroyScriptHook(JSContext *cx, JSScript *script); 113 // 114 // 115 // void ClearTrap(CActiveBreakPoint* activeBreakPoint); 116 // 117 // /** @brief Checks if a mapping for the specified filename and line number exists in this CThreadDebugger's context 118 // */ 119 // bool CheckIfMappingPresent(std::string filename, uint line); 120 // 121 // /** @brief Checks if a mapping exists for each breakpoint in the list of breakpoints that aren't set yet. 122 // * If there is a mapping, it removes the breakpoint from the list of unset breakpoints (from CDebuggingServer), 123 // * adds it to the list of active breakpoints (CThreadDebugger) and sets a trap. 124 // * Threading: m_Mutex is locked in this call 125 // */ 126 // void SetAllNewTraps(); 127 // 128 // /** @brief Sets a new trap and stores the information in the CActiveBreakPoint pointer 129 // * Make sure that a mapping exists before calling this function 130 // * Threading: Locking m_Mutex is required by the callee 131 // */ 132 // void SetNewTrap(CActiveBreakPoint* activeBreakPoint, std::string filename, uint line); 133 // 134 // /** @brief Toggle a breakpoint if it's active in this threadDebugger object. 135 // * Threading: Locking m_Mutex is required by the callee 136 // * 137 // * @param filename full vfs path to the script filename 138 // * @param userLine linenumber where the USER set the breakpoint (UserLine) 139 // * 140 // * @return true if the breakpoint's state was changed 141 // */ 142 // bool ToggleBreakPoint(std::string filename, uint userLine); 143 // 144 // 145 // void GetCallstack(std::stringstream& response); 146 // void GetStackFrameData(std::stringstream& response, uint nestingLevel, STACK_INFO stackInfoKind); 147 // 148 // /** @brief Compares the object's associated scriptinterface with the pointer passed as parameter. 149 // * @return true if equal 150 // */ 151 // bool CompareScriptInterfacePtr(ScriptInterface* pScriptInterface) const; 152 // 153 // // Getter/Setters for members that need to be threadsafe 154 // std::string GetBreakFileName(); 155 // bool GetIsInBreak(); 156 // uint GetLastBreakLine(); 157 // std::string GetName(); 158 // uint GetID(); 159 // void ContinueExecution(); 160 // void SetNextDbgCmd(DBGCMD dbgCmd); 161 // DBGCMD GetNextDbgCmd(); 162 // // The callee is responsible for locking m_Mutex 163 // void AddStackInfoRequest(STACK_INFO requestType, uint nestingLevel, SDL_sem* semaphore); 164 // 165 // 166 //private: 167 // // Getters/Setters for members that need to be threadsafe 168 // void SetBreakFileName(std::string breakFileName); 169 // void SetLastBreakLine(uint breakLine); 170 // void SetIsInBreak(bool isInBreak); 171 // 172 // // Other threadsafe functions 173 // void SaveCallstack(); 174 // 175 // /// Used only in the scriptinterface's thread. 176 // void ClearTrapsToRemove(); 177 // bool CurrentFrameIsChildOf(JSStackFrame* pParentFrame); 178 // void ReturnActiveBreakPoints(jsbytecode* pBytecode); 179 // void SaveStackFrameData(STACK_INFO stackInfo, uint nestingLevel); 180 // std::string StringifyCyclicJSON(jsval obj, bool indent); 181 // 182 // std::unique_ptr<ThreadDebugger_impl> m; 183 //}; 184 // 185 //#endif // INCLUDED_THREADDEBUGGER 18 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 19 20 #ifndef INCLUDED_THREADDEBUGGER 21 #define INCLUDED_THREADDEBUGGER 22 23 #include "DebuggingServer.h" 24 #include "ScriptInterface.h" 25 #include "scriptinterface/ScriptExtraHeaders.h" 26 27 // These Breakpoint classes are not implemented threadsafe. The class using the Breakpoints is responsible to make sure that 28 // only one thread accesses the Breakpoint at a time 29 class CBreakPoint 30 { 31 public: 32 CBreakPoint() : m_UserLine(0) { } 33 34 uint m_UserLine; 35 std::string m_Filename; 36 }; 37 38 // Only use this with one ScriptInterface/CThreadDebugger! 39 class CActiveBreakPoint : public CBreakPoint 40 { 41 public: 42 CActiveBreakPoint() 43 : m_ActualLine(m_UserLine) 44 , m_Script(NULL) 45 , m_Pc(NULL) 46 , m_ToRemove(false) 47 { } 48 49 CActiveBreakPoint(CBreakPoint breakPoint) 50 : CBreakPoint(breakPoint) // using default copy constructor 51 , m_ActualLine(m_UserLine) 52 , m_Script(NULL) 53 , m_Pc(NULL) 54 , m_ToRemove(false) 55 { } 56 57 uint m_ActualLine; 58 JSScript* m_Script; 59 jsbytecode* m_Pc; 60 bool m_ToRemove; 61 }; 62 63 enum BREAK_SRC { BREAK_SRC_TRAP, BREAK_SRC_INTERRUP, BREAK_SRC_EXCEPTION }; 64 65 struct ThreadDebugger_impl; 66 67 class CThreadDebugger 68 { 69 public: 70 CThreadDebugger(); 71 ~CThreadDebugger(); 72 73 /** @brief Initialize the object (required before using the object!). 74 * 75 * @param id A unique identifier greater than 0 for the object inside its CDebuggingServer object. 76 * @param name A name that will be can be displayed by the UI to identify the thread. 77 * @param pScriptInterface Pointer to a scriptinterface. All Hooks, breakpoint traps etc. will be registered in this 78 * scriptinterface and will be called by the thread this scriptinterface is running in. 79 * @param pDebuggingServer Pointer to the DebuggingServer object this Object should belong to. 80 * 81 * @return Return value. 82 */ 83 void Initialize(uint id, std::string name, ScriptInterface* pScriptInterface, CDebuggingServer* pDebuggingServer); 84 85 86 // A bunch of hooks used to get information from spidermonkey. 87 // These hooks are used internally only but have to be public because they need to be accessible from the global hook functions. 88 // Spidermonkey requires function pointers as hooks, which only works if the functions are global or static (not part of an object). 89 // These global functions in ThreadDebugger.cpp are just wrappers for the following member functions. 90 91 /** Simply calls BreakHandler with BREAK_SRC_TRAP */ 92 JSTrapStatus TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure); 93 /** Hook to capture exceptions and breakpoints in code (throw "Breakpoint";) */ 94 JSTrapStatus ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval); 95 /** All other hooks call this one if the execution should be paused. It puts the program in a wait-loop and 96 * waits for weak-up events (continue, step etc.). */ 97 JSTrapStatus BreakHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure, BREAK_SRC breakSrc); 98 JSTrapStatus StepHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure); 99 JSTrapStatus StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure); 100 JSTrapStatus StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure); 101 /** This is an interrup-hook that can be called multiple times per line of code and is used to break into the execution 102 * without previously setting a breakpoint and to break other threads when one thread triggers a breakpoint */ 103 JSTrapStatus CheckForBreakRequestHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure); 104 /** The callback function which gets executed for each new script that gets loaded and each function inside a script. 105 * We use it for "Execute-Hooks" and "Call-Hooks" in terms of Spidermonkey. 106 * This hook actually sets the traps (Breakpoints) "on the fly" that have been defined by the user previously. 107 */ 108 void ExecuteHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata); 109 /** This hook is used to update the mapping between filename plus line-numbers and jsbytecode pointers */ 110 void NewScriptHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata); 111 /** This hook makes sure that invalid mappings between filename plus line-number and jsbytecode points get deleted */ 112 void DestroyScriptHook(JSContext *cx, JSScript *script); 113 114 115 void ClearTrap(CActiveBreakPoint* activeBreakPoint); 116 117 /** @brief Checks if a mapping for the specified filename and line number exists in this CThreadDebugger's context 118 */ 119 bool CheckIfMappingPresent(std::string filename, uint line); 120 121 /** @brief Checks if a mapping exists for each breakpoint in the list of breakpoints that aren't set yet. 122 * If there is a mapping, it removes the breakpoint from the list of unset breakpoints (from CDebuggingServer), 123 * adds it to the list of active breakpoints (CThreadDebugger) and sets a trap. 124 * Threading: m_Mutex is locked in this call 125 */ 126 void SetAllNewTraps(); 127 128 /** @brief Sets a new trap and stores the information in the CActiveBreakPoint pointer 129 * Make sure that a mapping exists before calling this function 130 * Threading: Locking m_Mutex is required by the callee 131 */ 132 void SetNewTrap(CActiveBreakPoint* activeBreakPoint, std::string filename, uint line); 133 134 /** @brief Toggle a breakpoint if it's active in this threadDebugger object. 135 * Threading: Locking m_Mutex is required by the callee 136 * 137 * @param filename full vfs path to the script filename 138 * @param userLine linenumber where the USER set the breakpoint (UserLine) 139 * 140 * @return true if the breakpoint's state was changed 141 */ 142 bool ToggleBreakPoint(std::string filename, uint userLine); 143 144 145 void GetCallstack(std::stringstream& response); 146 void GetStackFrameData(std::stringstream& response, uint nestingLevel, STACK_INFO stackInfoKind); 147 148 /** @brief Compares the object's associated scriptinterface with the pointer passed as parameter. 149 * @return true if equal 150 */ 151 bool CompareScriptInterfacePtr(ScriptInterface* pScriptInterface) const; 152 153 // Getter/Setters for members that need to be threadsafe 154 std::string GetBreakFileName(); 155 bool GetIsInBreak(); 156 uint GetLastBreakLine(); 157 std::string GetName(); 158 uint GetID(); 159 void ContinueExecution(); 160 void SetNextDbgCmd(DBGCMD dbgCmd); 161 DBGCMD GetNextDbgCmd(); 162 // The callee is responsible for locking m_Mutex 163 void AddStackInfoRequest(STACK_INFO requestType, uint nestingLevel, SDL_sem* semaphore); 164 165 166 private: 167 // Getters/Setters for members that need to be threadsafe 168 void SetBreakFileName(std::string breakFileName); 169 void SetLastBreakLine(uint breakLine); 170 void SetIsInBreak(bool isInBreak); 171 172 // Other threadsafe functions 173 void SaveCallstack(); 174 175 /// Used only in the scriptinterface's thread. 176 void ClearTrapsToRemove(); 177 bool CurrentFrameIsChildOf(JS::StackDescription* description, JS::FrameDescription* pStackFrame); 178 void ReturnActiveBreakPoints(jsbytecode* pBytecode); 179 void SaveStackFrameData(STACK_INFO stackInfo, uint nestingLevel); 180 std::string StringifyCyclicJSON(jsval obj, bool indent); 181 182 std::unique_ptr<ThreadDebugger_impl> m; 183 }; 184 185 #endif // INCLUDED_THREADDEBUGGER