1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * JavaScript Debugging support - 'High Level' functions
12 /***************************************************************************/
14 /* XXX not 'static' because of old Mac CodeWarrior bug */
15 JSCList _jsd_context_list
= JS_INIT_STATIC_CLIST(&_jsd_context_list
);
17 /* these are used to connect JSD_SetUserCallbacks() with JSD_DebuggerOn() */
18 static JSD_UserCallbacks _callbacks
;
19 static void* _user
= NULL
;
20 static JSRuntime
* _jsrt
= NULL
;
22 #ifdef JSD_HAS_DANGEROUS_THREAD
23 static void* _dangerousThread
= NULL
;
27 JSDStaticLock
* _jsd_global_lock
= NULL
;
31 void JSD_ASSERT_VALID_CONTEXT(JSDContext
* jsdc
)
33 JS_ASSERT(jsdc
->inited
);
34 JS_ASSERT(jsdc
->jsrt
);
35 JS_ASSERT(jsdc
->dumbContext
);
36 JS_ASSERT(jsdc
->glob
);
40 static JSClass global_class
= {
41 "JSDGlobal", JSCLASS_GLOBAL_FLAGS
,
42 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_StrictPropertyStub
,
43 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
47 _validateUserCallbacks(JSD_UserCallbacks
* callbacks
)
50 (callbacks
->size
&& callbacks
->size
<= sizeof(JSD_UserCallbacks
));
54 _newJSDContext(JSRuntime
* jsrt
,
55 JSD_UserCallbacks
* callbacks
,
59 JSDContext
* jsdc
= NULL
;
60 JSCompartment
*oldCompartment
= NULL
;
66 if( ! _validateUserCallbacks(callbacks
) )
69 jsdc
= (JSDContext
*) calloc(1, sizeof(JSDContext
));
71 goto label_newJSDContext_failure
;
73 if( ! JSD_INIT_LOCKS(jsdc
) )
74 goto label_newJSDContext_failure
;
76 JS_INIT_CLIST(&jsdc
->links
);
81 memcpy(&jsdc
->userCallbacks
, callbacks
, callbacks
->size
);
85 #ifdef JSD_HAS_DANGEROUS_THREAD
86 jsdc
->dangerousThread
= _dangerousThread
;
89 JS_INIT_CLIST(&jsdc
->threadsStates
);
90 JS_INIT_CLIST(&jsdc
->sources
);
91 JS_INIT_CLIST(&jsdc
->removedSources
);
93 jsdc
->sourceAlterCount
= 1;
95 if( ! jsd_CreateAtomTable(jsdc
) )
96 goto label_newJSDContext_failure
;
98 if( ! jsd_InitObjectManager(jsdc
) )
99 goto label_newJSDContext_failure
;
101 if( ! jsd_InitScriptManager(jsdc
) )
102 goto label_newJSDContext_failure
;
104 jsdc
->dumbContext
= JS_NewContext(jsdc
->jsrt
, 256);
105 if( ! jsdc
->dumbContext
)
106 goto label_newJSDContext_failure
;
108 JS_BeginRequest(jsdc
->dumbContext
);
109 JS_SetOptions(jsdc
->dumbContext
, JS_GetOptions(jsdc
->dumbContext
));
111 jsdc
->glob
= JS_NewGlobalObject(jsdc
->dumbContext
, &global_class
, NULL
);
114 goto label_newJSDContext_failure
;
116 oldCompartment
= JS_EnterCompartment(jsdc
->dumbContext
, jsdc
->glob
);
118 if ( ! JS_AddNamedObjectRoot(jsdc
->dumbContext
, &jsdc
->glob
, "JSD context global") )
119 goto label_newJSDContext_failure
;
121 ok
= JS_InitStandardClasses(jsdc
->dumbContext
, jsdc
->glob
);
123 JS_LeaveCompartment(jsdc
->dumbContext
, oldCompartment
);
125 goto label_newJSDContext_failure
;
127 JS_EndRequest(jsdc
->dumbContext
);
130 jsdc
->inited
= JS_TRUE
;
133 JS_INSERT_LINK(&jsdc
->links
, &_jsd_context_list
);
138 label_newJSDContext_failure
:
140 if ( jsdc
->dumbContext
&& jsdc
->glob
)
141 JS_RemoveObjectRootRT(JS_GetRuntime(jsdc
->dumbContext
), &jsdc
->glob
);
142 jsd_DestroyObjectManager(jsdc
);
143 jsd_DestroyAtomTable(jsdc
);
144 if( jsdc
->dumbContext
)
145 JS_EndRequest(jsdc
->dumbContext
);
152 _destroyJSDContext(JSDContext
* jsdc
)
154 JSD_ASSERT_VALID_CONTEXT(jsdc
);
157 JS_REMOVE_LINK(&jsdc
->links
);
160 if ( jsdc
->dumbContext
&& jsdc
->glob
) {
161 JS_RemoveObjectRootRT(JS_GetRuntime(jsdc
->dumbContext
), &jsdc
->glob
);
163 jsd_DestroyObjectManager(jsdc
);
164 jsd_DestroyAtomTable(jsdc
);
166 jsdc
->inited
= JS_FALSE
;
169 * We should free jsdc here, but we let it leak in case there are any
170 * asynchronous hooks calling into the system using it as a handle
172 * XXX we also leak the locks
174 JS_DestroyContext(jsdc
->dumbContext
);
175 jsdc
->dumbContext
= NULL
;
178 /***************************************************************************/
181 jsd_DebuggerOnForUser(JSRuntime
* jsrt
,
182 JSD_UserCallbacks
* callbacks
,
188 jsdc
= _newJSDContext(jsrt
, callbacks
, user
, scopeobj
);
193 * Set hooks here. The new/destroy script hooks are on even when
194 * the debugger is paused. The destroy hook so we'll clean up
195 * internal data structures when scripts are destroyed, and the
196 * newscript hook for backwards compatibility for now. We'd like
197 * to stop doing that.
199 JS_SetNewScriptHookProc(jsdc
->jsrt
, jsd_NewScriptHookProc
, jsdc
);
200 JS_SetDestroyScriptHookProc(jsdc
->jsrt
, jsd_DestroyScriptHookProc
, jsdc
);
201 jsd_DebuggerUnpause(jsdc
);
203 LWDBG_SetNewScriptHookProc(jsd_NewScriptHookProc
, jsdc
);
205 if( jsdc
->userCallbacks
.setContext
)
206 jsdc
->userCallbacks
.setContext(jsdc
, jsdc
->user
);
214 JS_ASSERT(_validateUserCallbacks(&_callbacks
));
215 return jsd_DebuggerOnForUser(_jsrt
, &_callbacks
, _user
, NULL
);
219 jsd_DebuggerOff(JSDContext
* jsdc
)
221 jsd_DebuggerPause(jsdc
, JS_TRUE
);
222 /* clear hooks here */
223 JS_SetNewScriptHookProc(jsdc
->jsrt
, NULL
, NULL
);
224 JS_SetDestroyScriptHookProc(jsdc
->jsrt
, NULL
, NULL
);
226 LWDBG_SetNewScriptHookProc(NULL
,NULL
);
230 JSD_LockScriptSubsystem(jsdc
);
231 jsd_DestroyScriptManager(jsdc
);
232 JSD_UnlockScriptSubsystem(jsdc
);
233 jsd_DestroyAllSources(jsdc
);
235 _destroyJSDContext(jsdc
);
237 if( jsdc
->userCallbacks
.setContext
)
238 jsdc
->userCallbacks
.setContext(NULL
, jsdc
->user
);
242 jsd_DebuggerPause(JSDContext
* jsdc
, JSBool forceAllHooksOff
)
244 JS_SetDebuggerHandler(jsdc
->jsrt
, NULL
, NULL
);
245 if (forceAllHooksOff
|| !(jsdc
->flags
& JSD_COLLECT_PROFILE_DATA
)) {
246 JS_SetExecuteHook(jsdc
->jsrt
, NULL
, NULL
);
247 JS_SetCallHook(jsdc
->jsrt
, NULL
, NULL
);
249 JS_SetThrowHook(jsdc
->jsrt
, NULL
, NULL
);
250 JS_SetDebugErrorHook(jsdc
->jsrt
, NULL
, NULL
);
254 jsd_DebugErrorHook(JSContext
*cx
, const char *message
,
255 JSErrorReport
*report
, void *closure
);
258 jsd_DebuggerUnpause(JSDContext
* jsdc
)
260 JS_SetDebuggerHandler(jsdc
->jsrt
, jsd_DebuggerHandler
, jsdc
);
261 JS_SetExecuteHook(jsdc
->jsrt
, jsd_TopLevelCallHook
, jsdc
);
262 JS_SetCallHook(jsdc
->jsrt
, jsd_FunctionCallHook
, jsdc
);
263 JS_SetThrowHook(jsdc
->jsrt
, jsd_ThrowHandler
, jsdc
);
264 JS_SetDebugErrorHook(jsdc
->jsrt
, jsd_DebugErrorHook
, jsdc
);
268 jsd_SetUserCallbacks(JSRuntime
* jsrt
, JSD_UserCallbacks
* callbacks
, void* user
)
273 #ifdef JSD_HAS_DANGEROUS_THREAD
274 _dangerousThread
= JSD_CURRENT_THREAD();
278 memcpy(&_callbacks
, callbacks
, sizeof(JSD_UserCallbacks
));
280 memset(&_callbacks
, 0 , sizeof(JSD_UserCallbacks
));
284 jsd_SetContextPrivate(JSDContext
* jsdc
, void *data
)
291 jsd_GetContextPrivate(JSDContext
* jsdc
)
297 jsd_ClearAllProfileData(JSDContext
* jsdc
)
301 JSD_LOCK_SCRIPTS(jsdc
);
302 current
= (JSDScript
*)jsdc
->scripts
.next
;
303 while (current
!= (JSDScript
*)&jsdc
->scripts
)
305 jsd_ClearScriptProfileData(jsdc
, current
);
306 current
= (JSDScript
*)current
->links
.next
;
309 JSD_UNLOCK_SCRIPTS(jsdc
);
313 jsd_JSDContextForJSContext(JSContext
* context
)
316 JSDContext
* jsdc
= NULL
;
317 JSRuntime
* runtime
= JS_GetRuntime(context
);
320 for( iter
= (JSDContext
*)_jsd_context_list
.next
;
321 iter
!= (JSDContext
*)&_jsd_context_list
;
322 iter
= (JSDContext
*)iter
->links
.next
)
324 if( runtime
== iter
->jsrt
)
335 jsd_DebugErrorHook(JSContext
*cx
, const char *message
,
336 JSErrorReport
*report
, void *closure
)
338 JSDContext
* jsdc
= (JSDContext
*) closure
;
339 JSD_ErrorReporter errorReporter
;
340 void* errorReporterData
;
347 if( JSD_IS_DANGEROUS_THREAD(jsdc
) )
350 /* local in case hook gets cleared on another thread */
352 errorReporter
= jsdc
->errorReporter
;
353 errorReporterData
= jsdc
->errorReporterData
;
359 switch(errorReporter(jsdc
, cx
, message
, report
, errorReporterData
))
361 case JSD_ERROR_REPORTER_PASS_ALONG
:
363 case JSD_ERROR_REPORTER_RETURN
:
365 case JSD_ERROR_REPORTER_DEBUG
:
368 JSD_ExecutionHookProc hook
;
371 /* local in case hook gets cleared on another thread */
373 hook
= jsdc
->debugBreakHook
;
374 hookData
= jsdc
->debugBreakHookData
;
377 jsd_CallExecutionHook(jsdc
, cx
, JSD_HOOK_DEBUG_REQUESTED
,
378 hook
, hookData
, &rval
);
379 /* XXX Should make this dependent on ExecutionHook retval */
382 case JSD_ERROR_REPORTER_CLEAR_RETURN
:
383 if(report
&& JSREPORT_IS_EXCEPTION(report
->flags
))
384 JS_ClearPendingException(cx
);
394 jsd_SetErrorReporter(JSDContext
* jsdc
,
395 JSD_ErrorReporter reporter
,
399 jsdc
->errorReporter
= reporter
;
400 jsdc
->errorReporterData
= callerdata
;
406 jsd_GetErrorReporter(JSDContext
* jsdc
,
407 JSD_ErrorReporter
* reporter
,
412 *reporter
= jsdc
->errorReporter
;
414 *callerdata
= jsdc
->errorReporterData
;