Bug 588735 - Mirror glass caption buttons for rtl windows. r=roc, a=blocking-betaN.
[mozilla-central.git] / js / jsd / jsd_high.c
blobb2e6fc00b3ca2830197140b9a96dd2df412e814c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * JavaScript Debugging support - 'High Level' functions
42 #include "jsd.h"
44 /***************************************************************************/
46 /* XXX not 'static' because of old Mac CodeWarrior bug */
47 JSCList _jsd_context_list = JS_INIT_STATIC_CLIST(&_jsd_context_list);
49 /* these are used to connect JSD_SetUserCallbacks() with JSD_DebuggerOn() */
50 static JSD_UserCallbacks _callbacks;
51 static void* _user = NULL;
52 static JSRuntime* _jsrt = NULL;
54 #ifdef JSD_HAS_DANGEROUS_THREAD
55 static void* _dangerousThread = NULL;
56 #endif
58 #ifdef JSD_THREADSAFE
59 void* _jsd_global_lock = NULL;
60 #endif
62 #ifdef DEBUG
63 void JSD_ASSERT_VALID_CONTEXT(JSDContext* jsdc)
65 JS_ASSERT(jsdc->inited);
66 JS_ASSERT(jsdc->jsrt);
67 JS_ASSERT(jsdc->dumbContext);
68 JS_ASSERT(jsdc->glob);
70 #endif
72 static JSClass global_class = {
73 "JSDGlobal", JSCLASS_GLOBAL_FLAGS,
74 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
75 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
76 JSCLASS_NO_OPTIONAL_MEMBERS
79 static JSBool
80 _validateUserCallbacks(JSD_UserCallbacks* callbacks)
82 return !callbacks ||
83 (callbacks->size && callbacks->size <= sizeof(JSD_UserCallbacks));
86 static JSDContext*
87 _newJSDContext(JSRuntime* jsrt,
88 JSD_UserCallbacks* callbacks,
89 void* user)
91 JSDContext* jsdc = NULL;
93 if( ! jsrt )
94 return NULL;
96 if( ! _validateUserCallbacks(callbacks) )
97 return NULL;
99 jsdc = (JSDContext*) calloc(1, sizeof(JSDContext));
100 if( ! jsdc )
101 goto label_newJSDContext_failure;
103 if( ! JSD_INIT_LOCKS(jsdc) )
104 goto label_newJSDContext_failure;
106 JS_INIT_CLIST(&jsdc->links);
108 jsdc->jsrt = jsrt;
110 if( callbacks )
111 memcpy(&jsdc->userCallbacks, callbacks, callbacks->size);
113 jsdc->user = user;
115 #ifdef JSD_HAS_DANGEROUS_THREAD
116 jsdc->dangerousThread = _dangerousThread;
117 #endif
119 JS_INIT_CLIST(&jsdc->threadsStates);
120 JS_INIT_CLIST(&jsdc->sources);
121 JS_INIT_CLIST(&jsdc->removedSources);
123 jsdc->sourceAlterCount = 1;
125 if( ! jsd_CreateAtomTable(jsdc) )
126 goto label_newJSDContext_failure;
128 if( ! jsd_InitObjectManager(jsdc) )
129 goto label_newJSDContext_failure;
131 if( ! jsd_InitScriptManager(jsdc) )
132 goto label_newJSDContext_failure;
134 jsdc->dumbContext = JS_NewContext(jsdc->jsrt, 256);
135 if( ! jsdc->dumbContext )
136 goto label_newJSDContext_failure;
138 JS_BeginRequest(jsdc->dumbContext);
140 jsdc->glob = JS_NewGlobalObject(jsdc->dumbContext, &global_class);
141 if( ! jsdc->glob )
142 goto label_newJSDContext_failure;
144 if( ! JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob) )
145 goto label_newJSDContext_failure;
147 JS_EndRequest(jsdc->dumbContext);
149 jsdc->data = NULL;
150 jsdc->inited = JS_TRUE;
152 JSD_LOCK();
153 JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
154 JSD_UNLOCK();
156 return jsdc;
158 label_newJSDContext_failure:
159 if( jsdc ) {
160 jsd_DestroyObjectManager(jsdc);
161 jsd_DestroyAtomTable(jsdc);
162 JS_EndRequest(jsdc->dumbContext);
163 free(jsdc);
165 return NULL;
168 static void
169 _destroyJSDContext(JSDContext* jsdc)
171 JSD_ASSERT_VALID_CONTEXT(jsdc);
173 JSD_LOCK();
174 JS_REMOVE_LINK(&jsdc->links);
175 JSD_UNLOCK();
177 jsd_DestroyObjectManager(jsdc);
178 jsd_DestroyAtomTable(jsdc);
180 jsdc->inited = JS_FALSE;
183 * We should free jsdc here, but we let it leak in case there are any
184 * asynchronous hooks calling into the system using it as a handle
186 * XXX we also leak the locks
188 JS_DestroyContext(jsdc->dumbContext);
189 jsdc->dumbContext = NULL;
192 /***************************************************************************/
194 JSDContext*
195 jsd_DebuggerOnForUser(JSRuntime* jsrt,
196 JSD_UserCallbacks* callbacks,
197 void* user)
199 JSDContext* jsdc;
200 JSContext* iter = NULL;
202 jsdc = _newJSDContext(jsrt, callbacks, user);
203 if( ! jsdc )
204 return NULL;
207 * Set hooks here. The new/destroy script hooks are on even when
208 * the debugger is paused. The destroy hook so we'll clean up
209 * internal data structures when scripts are destroyed, and the
210 * newscript hook for backwards compatibility for now. We'd like
211 * to stop doing that.
213 JS_SetNewScriptHookProc(jsdc->jsrt, jsd_NewScriptHookProc, jsdc);
214 JS_SetDestroyScriptHookProc(jsdc->jsrt, jsd_DestroyScriptHookProc, jsdc);
215 jsd_DebuggerUnpause(jsdc);
216 #ifdef LIVEWIRE
217 LWDBG_SetNewScriptHookProc(jsd_NewScriptHookProc, jsdc);
218 #endif
219 if( jsdc->userCallbacks.setContext )
220 jsdc->userCallbacks.setContext(jsdc, jsdc->user);
221 return jsdc;
224 JSDContext*
225 jsd_DebuggerOn(void)
227 JS_ASSERT(_jsrt);
228 JS_ASSERT(_validateUserCallbacks(&_callbacks));
229 return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user);
232 void
233 jsd_DebuggerOff(JSDContext* jsdc)
235 jsd_DebuggerPause(jsdc, JS_TRUE);
236 /* clear hooks here */
237 JS_SetNewScriptHookProc(jsdc->jsrt, NULL, NULL);
238 JS_SetDestroyScriptHookProc(jsdc->jsrt, NULL, NULL);
239 #ifdef LIVEWIRE
240 LWDBG_SetNewScriptHookProc(NULL,NULL);
241 #endif
243 /* clean up */
244 JSD_LockScriptSubsystem(jsdc);
245 jsd_DestroyScriptManager(jsdc);
246 JSD_UnlockScriptSubsystem(jsdc);
247 jsd_DestroyAllSources(jsdc);
249 _destroyJSDContext(jsdc);
251 if( jsdc->userCallbacks.setContext )
252 jsdc->userCallbacks.setContext(NULL, jsdc->user);
255 void
256 jsd_DebuggerPause(JSDContext* jsdc, JSBool forceAllHooksOff)
258 JS_SetDebuggerHandler(jsdc->jsrt, NULL, NULL);
259 if (forceAllHooksOff || !(jsdc->flags & JSD_COLLECT_PROFILE_DATA)) {
260 JS_SetExecuteHook(jsdc->jsrt, NULL, NULL);
261 JS_SetCallHook(jsdc->jsrt, NULL, NULL);
263 JS_SetThrowHook(jsdc->jsrt, NULL, NULL);
264 JS_SetDebugErrorHook(jsdc->jsrt, NULL, NULL);
267 void
268 jsd_DebuggerUnpause(JSDContext* jsdc)
270 JS_SetDebuggerHandler(jsdc->jsrt, jsd_DebuggerHandler, jsdc);
271 JS_SetExecuteHook(jsdc->jsrt, jsd_TopLevelCallHook, jsdc);
272 JS_SetCallHook(jsdc->jsrt, jsd_FunctionCallHook, jsdc);
273 JS_SetThrowHook(jsdc->jsrt, jsd_ThrowHandler, jsdc);
274 JS_SetDebugErrorHook(jsdc->jsrt, jsd_DebugErrorHook, jsdc);
277 void
278 jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user)
280 _jsrt = jsrt;
281 _user = user;
283 #ifdef JSD_HAS_DANGEROUS_THREAD
284 _dangerousThread = JSD_CURRENT_THREAD();
285 #endif
287 if( callbacks )
288 memcpy(&_callbacks, callbacks, sizeof(JSD_UserCallbacks));
289 else
290 memset(&_callbacks, 0 , sizeof(JSD_UserCallbacks));
293 void*
294 jsd_SetContextPrivate(JSDContext* jsdc, void *data)
296 void *rval = jsdc->data;
297 jsdc->data = data;
298 return data;
301 void*
302 jsd_GetContextPrivate(JSDContext* jsdc)
304 return jsdc->data;
307 void
308 jsd_ClearAllProfileData(JSDContext* jsdc)
310 JSDScript *current;
312 JSD_LOCK_SCRIPTS(jsdc);
313 current = (JSDScript *)jsdc->scripts.next;
314 while (current != (JSDScript *)&jsdc->scripts)
316 jsd_ClearScriptProfileData(jsdc, current);
317 current = (JSDScript *)current->links.next;
320 JSD_UNLOCK_SCRIPTS(jsdc);
323 JSDContext*
324 jsd_JSDContextForJSContext(JSContext* context)
326 JSDContext* iter;
327 JSDContext* jsdc = NULL;
328 JSRuntime* runtime = JS_GetRuntime(context);
330 JSD_LOCK();
331 for( iter = (JSDContext*)_jsd_context_list.next;
332 iter != (JSDContext*)&_jsd_context_list;
333 iter = (JSDContext*)iter->links.next )
335 if( runtime == iter->jsrt )
337 jsdc = iter;
338 break;
341 JSD_UNLOCK();
342 return jsdc;
345 static JSBool
346 jsd_DebugErrorHook(JSContext *cx, const char *message,
347 JSErrorReport *report, void *closure)
349 JSDContext* jsdc = (JSDContext*) closure;
350 JSD_ErrorReporter errorReporter;
351 void* errorReporterData;
353 if( ! jsdc )
355 JS_ASSERT(0);
356 return JS_TRUE;
358 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
359 return JS_TRUE;
361 /* local in case hook gets cleared on another thread */
362 JSD_LOCK();
363 errorReporter = jsdc->errorReporter;
364 errorReporterData = jsdc->errorReporterData;
365 JSD_UNLOCK();
367 if(!errorReporter)
368 return JS_TRUE;
370 switch(errorReporter(jsdc, cx, message, report, errorReporterData))
372 case JSD_ERROR_REPORTER_PASS_ALONG:
373 return JS_TRUE;
374 case JSD_ERROR_REPORTER_RETURN:
375 return JS_FALSE;
376 case JSD_ERROR_REPORTER_DEBUG:
378 jsval rval;
379 JSD_ExecutionHookProc hook;
380 void* hookData;
382 /* local in case hook gets cleared on another thread */
383 JSD_LOCK();
384 hook = jsdc->debugBreakHook;
385 hookData = jsdc->debugBreakHookData;
386 JSD_UNLOCK();
388 jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUG_REQUESTED,
389 hook, hookData, &rval);
390 /* XXX Should make this dependent on ExecutionHook retval */
391 return JS_TRUE;
393 case JSD_ERROR_REPORTER_CLEAR_RETURN:
394 if(report && JSREPORT_IS_EXCEPTION(report->flags))
395 JS_ClearPendingException(cx);
396 return JS_FALSE;
397 default:
398 JS_ASSERT(0);
399 break;
401 return JS_TRUE;
404 JSBool
405 jsd_SetErrorReporter(JSDContext* jsdc,
406 JSD_ErrorReporter reporter,
407 void* callerdata)
409 JSD_LOCK();
410 jsdc->errorReporter = reporter;
411 jsdc->errorReporterData = callerdata;
412 JSD_UNLOCK();
413 return JS_TRUE;
416 JSBool
417 jsd_GetErrorReporter(JSDContext* jsdc,
418 JSD_ErrorReporter* reporter,
419 void** callerdata)
421 JSD_LOCK();
422 if( reporter )
423 *reporter = jsdc->errorReporter;
424 if( callerdata )
425 *callerdata = jsdc->errorReporterData;
426 JSD_UNLOCK();
427 return JS_TRUE;