Bug 827007: Implement Stop for UserMediaStreams; add NotifyRemoved for MediaStream...
[gecko.git] / js / jsd / jsd_high.cpp
blob3ed51fea88d99aa91f2b3cf7f7e3e7cd1efa5d98
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/. */
6 /*
7 * JavaScript Debugging support - 'High Level' functions
8 */
10 #include "jsd.h"
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;
24 #endif
26 #ifdef JSD_THREADSAFE
27 JSDStaticLock* _jsd_global_lock = NULL;
28 #endif
30 #ifdef DEBUG
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);
38 #endif
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
46 static JSBool
47 _validateUserCallbacks(JSD_UserCallbacks* callbacks)
49 return !callbacks ||
50 (callbacks->size && callbacks->size <= sizeof(JSD_UserCallbacks));
53 static JSDContext*
54 _newJSDContext(JSRuntime* jsrt,
55 JSD_UserCallbacks* callbacks,
56 void* user,
57 JSObject* scopeobj)
59 JSDContext* jsdc = NULL;
60 JSCompartment *oldCompartment = NULL;
61 JSBool ok;
63 if( ! jsrt )
64 return NULL;
66 if( ! _validateUserCallbacks(callbacks) )
67 return NULL;
69 jsdc = (JSDContext*) calloc(1, sizeof(JSDContext));
70 if( ! jsdc )
71 goto label_newJSDContext_failure;
73 if( ! JSD_INIT_LOCKS(jsdc) )
74 goto label_newJSDContext_failure;
76 JS_INIT_CLIST(&jsdc->links);
78 jsdc->jsrt = jsrt;
80 if( callbacks )
81 memcpy(&jsdc->userCallbacks, callbacks, callbacks->size);
83 jsdc->user = user;
85 #ifdef JSD_HAS_DANGEROUS_THREAD
86 jsdc->dangerousThread = _dangerousThread;
87 #endif
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);
113 if( ! jsdc->glob )
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);
124 if( ! ok )
125 goto label_newJSDContext_failure;
127 JS_EndRequest(jsdc->dumbContext);
129 jsdc->data = NULL;
130 jsdc->inited = JS_TRUE;
132 JSD_LOCK();
133 JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
134 JSD_UNLOCK();
136 return jsdc;
138 label_newJSDContext_failure:
139 if( jsdc ) {
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);
146 free(jsdc);
148 return NULL;
151 static void
152 _destroyJSDContext(JSDContext* jsdc)
154 JSD_ASSERT_VALID_CONTEXT(jsdc);
156 JSD_LOCK();
157 JS_REMOVE_LINK(&jsdc->links);
158 JSD_UNLOCK();
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 /***************************************************************************/
180 JSDContext*
181 jsd_DebuggerOnForUser(JSRuntime* jsrt,
182 JSD_UserCallbacks* callbacks,
183 void* user,
184 JSObject* scopeobj)
186 JSDContext* jsdc;
188 jsdc = _newJSDContext(jsrt, callbacks, user, scopeobj);
189 if( ! jsdc )
190 return NULL;
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);
202 #ifdef LIVEWIRE
203 LWDBG_SetNewScriptHookProc(jsd_NewScriptHookProc, jsdc);
204 #endif
205 if( jsdc->userCallbacks.setContext )
206 jsdc->userCallbacks.setContext(jsdc, jsdc->user);
207 return jsdc;
210 JSDContext*
211 jsd_DebuggerOn(void)
213 JS_ASSERT(_jsrt);
214 JS_ASSERT(_validateUserCallbacks(&_callbacks));
215 return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user, NULL);
218 void
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);
225 #ifdef LIVEWIRE
226 LWDBG_SetNewScriptHookProc(NULL,NULL);
227 #endif
229 /* clean up */
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);
241 void
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);
253 static JSBool
254 jsd_DebugErrorHook(JSContext *cx, const char *message,
255 JSErrorReport *report, void *closure);
257 void
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);
267 void
268 jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user)
270 _jsrt = jsrt;
271 _user = user;
273 #ifdef JSD_HAS_DANGEROUS_THREAD
274 _dangerousThread = JSD_CURRENT_THREAD();
275 #endif
277 if( callbacks )
278 memcpy(&_callbacks, callbacks, sizeof(JSD_UserCallbacks));
279 else
280 memset(&_callbacks, 0 , sizeof(JSD_UserCallbacks));
283 void*
284 jsd_SetContextPrivate(JSDContext* jsdc, void *data)
286 jsdc->data = data;
287 return data;
290 void*
291 jsd_GetContextPrivate(JSDContext* jsdc)
293 return jsdc->data;
296 void
297 jsd_ClearAllProfileData(JSDContext* jsdc)
299 JSDScript *current;
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);
312 JSDContext*
313 jsd_JSDContextForJSContext(JSContext* context)
315 JSDContext* iter;
316 JSDContext* jsdc = NULL;
317 JSRuntime* runtime = JS_GetRuntime(context);
319 JSD_LOCK();
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 )
326 jsdc = iter;
327 break;
330 JSD_UNLOCK();
331 return jsdc;
334 static JSBool
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;
342 if( ! jsdc )
344 JS_ASSERT(0);
345 return JS_TRUE;
347 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
348 return JS_TRUE;
350 /* local in case hook gets cleared on another thread */
351 JSD_LOCK();
352 errorReporter = jsdc->errorReporter;
353 errorReporterData = jsdc->errorReporterData;
354 JSD_UNLOCK();
356 if(!errorReporter)
357 return JS_TRUE;
359 switch(errorReporter(jsdc, cx, message, report, errorReporterData))
361 case JSD_ERROR_REPORTER_PASS_ALONG:
362 return JS_TRUE;
363 case JSD_ERROR_REPORTER_RETURN:
364 return JS_FALSE;
365 case JSD_ERROR_REPORTER_DEBUG:
367 jsval rval;
368 JSD_ExecutionHookProc hook;
369 void* hookData;
371 /* local in case hook gets cleared on another thread */
372 JSD_LOCK();
373 hook = jsdc->debugBreakHook;
374 hookData = jsdc->debugBreakHookData;
375 JSD_UNLOCK();
377 jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUG_REQUESTED,
378 hook, hookData, &rval);
379 /* XXX Should make this dependent on ExecutionHook retval */
380 return JS_TRUE;
382 case JSD_ERROR_REPORTER_CLEAR_RETURN:
383 if(report && JSREPORT_IS_EXCEPTION(report->flags))
384 JS_ClearPendingException(cx);
385 return JS_FALSE;
386 default:
387 JS_ASSERT(0);
388 break;
390 return JS_TRUE;
393 JSBool
394 jsd_SetErrorReporter(JSDContext* jsdc,
395 JSD_ErrorReporter reporter,
396 void* callerdata)
398 JSD_LOCK();
399 jsdc->errorReporter = reporter;
400 jsdc->errorReporterData = callerdata;
401 JSD_UNLOCK();
402 return JS_TRUE;
405 JSBool
406 jsd_GetErrorReporter(JSDContext* jsdc,
407 JSD_ErrorReporter* reporter,
408 void** callerdata)
410 JSD_LOCK();
411 if( reporter )
412 *reporter = jsdc->errorReporter;
413 if( callerdata )
414 *callerdata = jsdc->errorReporterData;
415 JSD_UNLOCK();
416 return JS_TRUE;