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
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.
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
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;
59 void* _jsd_global_lock = NULL;
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);
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
80 _validateUserCallbacks(JSD_UserCallbacks* callbacks)
83 (callbacks->size && callbacks->size <= sizeof(JSD_UserCallbacks));
87 _newJSDContext(JSRuntime* jsrt,
88 JSD_UserCallbacks* callbacks,
92 JSDContext* jsdc = NULL;
93 JSCrossCompartmentCall *call = NULL;
98 if( ! _validateUserCallbacks(callbacks) )
101 jsdc = (JSDContext*) calloc(1, sizeof(JSDContext));
103 goto label_newJSDContext_failure;
105 if( ! JSD_INIT_LOCKS(jsdc) )
106 goto label_newJSDContext_failure;
108 JS_INIT_CLIST(&jsdc->links);
113 memcpy(&jsdc->userCallbacks, callbacks, callbacks->size);
117 #ifdef JSD_HAS_DANGEROUS_THREAD
118 jsdc->dangerousThread = _dangerousThread;
121 JS_INIT_CLIST(&jsdc->threadsStates);
122 JS_INIT_CLIST(&jsdc->sources);
123 JS_INIT_CLIST(&jsdc->removedSources);
125 jsdc->sourceAlterCount = 1;
127 if( ! jsd_CreateAtomTable(jsdc) )
128 goto label_newJSDContext_failure;
130 if( ! jsd_InitObjectManager(jsdc) )
131 goto label_newJSDContext_failure;
133 if( ! jsd_InitScriptManager(jsdc) )
134 goto label_newJSDContext_failure;
136 jsdc->dumbContext = JS_NewContext(jsdc->jsrt, 256);
137 if( ! jsdc->dumbContext )
138 goto label_newJSDContext_failure;
140 JS_BeginRequest(jsdc->dumbContext);
142 jsdc->glob = JS_NewCompartmentAndGlobalObject(jsdc->dumbContext, &global_class, NULL);
145 goto label_newJSDContext_failure;
147 call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
149 goto label_newJSDContext_failure;
151 if( ! JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob) )
152 goto label_newJSDContext_failure;
155 JS_LeaveCrossCompartmentCall(call);
157 JS_EndRequest(jsdc->dumbContext);
160 jsdc->inited = JS_TRUE;
163 JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
168 label_newJSDContext_failure:
170 jsd_DestroyObjectManager(jsdc);
171 jsd_DestroyAtomTable(jsdc);
172 JS_EndRequest(jsdc->dumbContext);
179 _destroyJSDContext(JSDContext* jsdc)
181 JSD_ASSERT_VALID_CONTEXT(jsdc);
184 JS_REMOVE_LINK(&jsdc->links);
187 jsd_DestroyObjectManager(jsdc);
188 jsd_DestroyAtomTable(jsdc);
190 jsdc->inited = JS_FALSE;
193 * We should free jsdc here, but we let it leak in case there are any
194 * asynchronous hooks calling into the system using it as a handle
196 * XXX we also leak the locks
198 JS_DestroyContext(jsdc->dumbContext);
199 jsdc->dumbContext = NULL;
202 /***************************************************************************/
205 jsd_DebuggerOnForUser(JSRuntime* jsrt,
206 JSD_UserCallbacks* callbacks,
211 JSContext* iter = NULL;
213 jsdc = _newJSDContext(jsrt, callbacks, user, scopeobj);
218 * Set hooks here. The new/destroy script hooks are on even when
219 * the debugger is paused. The destroy hook so we'll clean up
220 * internal data structures when scripts are destroyed, and the
221 * newscript hook for backwards compatibility for now. We'd like
222 * to stop doing that.
224 JS_SetNewScriptHookProc(jsdc->jsrt, jsd_NewScriptHookProc, jsdc);
225 JS_SetDestroyScriptHookProc(jsdc->jsrt, jsd_DestroyScriptHookProc, jsdc);
226 jsd_DebuggerUnpause(jsdc);
228 LWDBG_SetNewScriptHookProc(jsd_NewScriptHookProc, jsdc);
230 if( jsdc->userCallbacks.setContext )
231 jsdc->userCallbacks.setContext(jsdc, jsdc->user);
239 JS_ASSERT(_validateUserCallbacks(&_callbacks));
240 return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user, NULL);
244 jsd_DebuggerOff(JSDContext* jsdc)
246 jsd_DebuggerPause(jsdc, JS_TRUE);
247 /* clear hooks here */
248 JS_SetNewScriptHookProc(jsdc->jsrt, NULL, NULL);
249 JS_SetDestroyScriptHookProc(jsdc->jsrt, NULL, NULL);
251 LWDBG_SetNewScriptHookProc(NULL,NULL);
255 JSD_LockScriptSubsystem(jsdc);
256 jsd_DestroyScriptManager(jsdc);
257 JSD_UnlockScriptSubsystem(jsdc);
258 jsd_DestroyAllSources(jsdc);
260 _destroyJSDContext(jsdc);
262 if( jsdc->userCallbacks.setContext )
263 jsdc->userCallbacks.setContext(NULL, jsdc->user);
267 jsd_DebuggerPause(JSDContext* jsdc, JSBool forceAllHooksOff)
269 JS_SetDebuggerHandler(jsdc->jsrt, NULL, NULL);
270 if (forceAllHooksOff || !(jsdc->flags & JSD_COLLECT_PROFILE_DATA)) {
271 JS_SetExecuteHook(jsdc->jsrt, NULL, NULL);
272 JS_SetCallHook(jsdc->jsrt, NULL, NULL);
274 JS_SetThrowHook(jsdc->jsrt, NULL, NULL);
275 JS_SetDebugErrorHook(jsdc->jsrt, NULL, NULL);
279 jsd_DebuggerUnpause(JSDContext* jsdc)
281 JS_SetDebuggerHandler(jsdc->jsrt, jsd_DebuggerHandler, jsdc);
282 JS_SetExecuteHook(jsdc->jsrt, jsd_TopLevelCallHook, jsdc);
283 JS_SetCallHook(jsdc->jsrt, jsd_FunctionCallHook, jsdc);
284 JS_SetThrowHook(jsdc->jsrt, jsd_ThrowHandler, jsdc);
285 JS_SetDebugErrorHook(jsdc->jsrt, jsd_DebugErrorHook, jsdc);
289 jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user)
294 #ifdef JSD_HAS_DANGEROUS_THREAD
295 _dangerousThread = JSD_CURRENT_THREAD();
299 memcpy(&_callbacks, callbacks, sizeof(JSD_UserCallbacks));
301 memset(&_callbacks, 0 , sizeof(JSD_UserCallbacks));
305 jsd_SetContextPrivate(JSDContext* jsdc, void *data)
307 void *rval = jsdc->data;
313 jsd_GetContextPrivate(JSDContext* jsdc)
319 jsd_ClearAllProfileData(JSDContext* jsdc)
323 JSD_LOCK_SCRIPTS(jsdc);
324 current = (JSDScript *)jsdc->scripts.next;
325 while (current != (JSDScript *)&jsdc->scripts)
327 jsd_ClearScriptProfileData(jsdc, current);
328 current = (JSDScript *)current->links.next;
331 JSD_UNLOCK_SCRIPTS(jsdc);
335 jsd_JSDContextForJSContext(JSContext* context)
338 JSDContext* jsdc = NULL;
339 JSRuntime* runtime = JS_GetRuntime(context);
342 for( iter = (JSDContext*)_jsd_context_list.next;
343 iter != (JSDContext*)&_jsd_context_list;
344 iter = (JSDContext*)iter->links.next )
346 if( runtime == iter->jsrt )
357 jsd_DebugErrorHook(JSContext *cx, const char *message,
358 JSErrorReport *report, void *closure)
360 JSDContext* jsdc = (JSDContext*) closure;
361 JSD_ErrorReporter errorReporter;
362 void* errorReporterData;
369 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
372 /* local in case hook gets cleared on another thread */
374 errorReporter = jsdc->errorReporter;
375 errorReporterData = jsdc->errorReporterData;
381 switch(errorReporter(jsdc, cx, message, report, errorReporterData))
383 case JSD_ERROR_REPORTER_PASS_ALONG:
385 case JSD_ERROR_REPORTER_RETURN:
387 case JSD_ERROR_REPORTER_DEBUG:
390 JSD_ExecutionHookProc hook;
393 /* local in case hook gets cleared on another thread */
395 hook = jsdc->debugBreakHook;
396 hookData = jsdc->debugBreakHookData;
399 jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUG_REQUESTED,
400 hook, hookData, &rval);
401 /* XXX Should make this dependent on ExecutionHook retval */
404 case JSD_ERROR_REPORTER_CLEAR_RETURN:
405 if(report && JSREPORT_IS_EXCEPTION(report->flags))
406 JS_ClearPendingException(cx);
416 jsd_SetErrorReporter(JSDContext* jsdc,
417 JSD_ErrorReporter reporter,
421 jsdc->errorReporter = reporter;
422 jsdc->errorReporterData = callerdata;
428 jsd_GetErrorReporter(JSDContext* jsdc,
429 JSD_ErrorReporter* reporter,
434 *reporter = jsdc->errorReporter;
436 *callerdata = jsdc->errorReporterData;