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
;