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
,
91 JSDContext
* jsdc
= NULL
;
96 if( ! _validateUserCallbacks(callbacks
) )
99 jsdc
= (JSDContext
*) calloc(1, sizeof(JSDContext
));
101 goto label_newJSDContext_failure
;
103 if( ! JSD_INIT_LOCKS(jsdc
) )
104 goto label_newJSDContext_failure
;
106 JS_INIT_CLIST(&jsdc
->links
);
111 memcpy(&jsdc
->userCallbacks
, callbacks
, callbacks
->size
);
115 #ifdef JSD_HAS_DANGEROUS_THREAD
116 jsdc
->dangerousThread
= _dangerousThread
;
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
);
142 goto label_newJSDContext_failure
;
144 if( ! JS_InitStandardClasses(jsdc
->dumbContext
, jsdc
->glob
) )
145 goto label_newJSDContext_failure
;
147 JS_EndRequest(jsdc
->dumbContext
);
150 jsdc
->inited
= JS_TRUE
;
153 JS_INSERT_LINK(&jsdc
->links
, &_jsd_context_list
);
158 label_newJSDContext_failure
:
160 jsd_DestroyObjectManager(jsdc
);
161 jsd_DestroyAtomTable(jsdc
);
162 JS_EndRequest(jsdc
->dumbContext
);
169 _destroyJSDContext(JSDContext
* jsdc
)
171 JSD_ASSERT_VALID_CONTEXT(jsdc
);
174 JS_REMOVE_LINK(&jsdc
->links
);
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 /***************************************************************************/
195 jsd_DebuggerOnForUser(JSRuntime
* jsrt
,
196 JSD_UserCallbacks
* callbacks
,
200 JSContext
* iter
= NULL
;
202 jsdc
= _newJSDContext(jsrt
, callbacks
, user
);
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
);
217 LWDBG_SetNewScriptHookProc(jsd_NewScriptHookProc
, jsdc
);
219 if( jsdc
->userCallbacks
.setContext
)
220 jsdc
->userCallbacks
.setContext(jsdc
, jsdc
->user
);
228 JS_ASSERT(_validateUserCallbacks(&_callbacks
));
229 return jsd_DebuggerOnForUser(_jsrt
, &_callbacks
, _user
);
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
);
240 LWDBG_SetNewScriptHookProc(NULL
,NULL
);
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
);
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
);
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
);
278 jsd_SetUserCallbacks(JSRuntime
* jsrt
, JSD_UserCallbacks
* callbacks
, void* user
)
283 #ifdef JSD_HAS_DANGEROUS_THREAD
284 _dangerousThread
= JSD_CURRENT_THREAD();
288 memcpy(&_callbacks
, callbacks
, sizeof(JSD_UserCallbacks
));
290 memset(&_callbacks
, 0 , sizeof(JSD_UserCallbacks
));
294 jsd_SetContextPrivate(JSDContext
* jsdc
, void *data
)
296 void *rval
= jsdc
->data
;
302 jsd_GetContextPrivate(JSDContext
* jsdc
)
308 jsd_ClearAllProfileData(JSDContext
* jsdc
)
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
);
324 jsd_JSDContextForJSContext(JSContext
* context
)
327 JSDContext
* jsdc
= NULL
;
328 JSRuntime
* runtime
= JS_GetRuntime(context
);
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
)
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
;
358 if( JSD_IS_DANGEROUS_THREAD(jsdc
) )
361 /* local in case hook gets cleared on another thread */
363 errorReporter
= jsdc
->errorReporter
;
364 errorReporterData
= jsdc
->errorReporterData
;
370 switch(errorReporter(jsdc
, cx
, message
, report
, errorReporterData
))
372 case JSD_ERROR_REPORTER_PASS_ALONG
:
374 case JSD_ERROR_REPORTER_RETURN
:
376 case JSD_ERROR_REPORTER_DEBUG
:
379 JSD_ExecutionHookProc hook
;
382 /* local in case hook gets cleared on another thread */
384 hook
= jsdc
->debugBreakHook
;
385 hookData
= jsdc
->debugBreakHookData
;
388 jsd_CallExecutionHook(jsdc
, cx
, JSD_HOOK_DEBUG_REQUESTED
,
389 hook
, hookData
, &rval
);
390 /* XXX Should make this dependent on ExecutionHook retval */
393 case JSD_ERROR_REPORTER_CLEAR_RETURN
:
394 if(report
&& JSREPORT_IS_EXCEPTION(report
->flags
))
395 JS_ClearPendingException(cx
);
405 jsd_SetErrorReporter(JSDContext
* jsdc
,
406 JSD_ErrorReporter reporter
,
410 jsdc
->errorReporter
= reporter
;
411 jsdc
->errorReporterData
= callerdata
;
417 jsd_GetErrorReporter(JSDContext
* jsdc
,
418 JSD_ErrorReporter
* reporter
,
423 *reporter
= jsdc
->errorReporter
;
425 *callerdata
= jsdc
->errorReporterData
;