Fix regexp match pair end-index == -1 assumption. (r=dmandelin, a=blocker b=605754)
[mozilla-central.git] / js / jsd / jsd_high.c
blobfab896bf77ff5f2de331ab3c9810dc4cc4f96653
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,
90 JSObject* scopeobj)
92 JSDContext* jsdc = NULL;
93 JSCrossCompartmentCall *call = NULL;
95 if( ! jsrt )
96 return NULL;
98 if( ! _validateUserCallbacks(callbacks) )
99 return NULL;
101 jsdc = (JSDContext*) calloc(1, sizeof(JSDContext));
102 if( ! jsdc )
103 goto label_newJSDContext_failure;
105 if( ! JSD_INIT_LOCKS(jsdc) )
106 goto label_newJSDContext_failure;
108 JS_INIT_CLIST(&jsdc->links);
110 jsdc->jsrt = jsrt;
112 if( callbacks )
113 memcpy(&jsdc->userCallbacks, callbacks, callbacks->size);
115 jsdc->user = user;
117 #ifdef JSD_HAS_DANGEROUS_THREAD
118 jsdc->dangerousThread = _dangerousThread;
119 #endif
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);
144 if( ! jsdc->glob )
145 goto label_newJSDContext_failure;
147 call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
148 if( ! call )
149 goto label_newJSDContext_failure;
151 if( ! JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob) )
152 goto label_newJSDContext_failure;
154 if( call )
155 JS_LeaveCrossCompartmentCall(call);
157 JS_EndRequest(jsdc->dumbContext);
159 jsdc->data = NULL;
160 jsdc->inited = JS_TRUE;
162 JSD_LOCK();
163 JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
164 JSD_UNLOCK();
166 return jsdc;
168 label_newJSDContext_failure:
169 if( jsdc ) {
170 jsd_DestroyObjectManager(jsdc);
171 jsd_DestroyAtomTable(jsdc);
172 JS_EndRequest(jsdc->dumbContext);
173 free(jsdc);
175 return NULL;
178 static void
179 _destroyJSDContext(JSDContext* jsdc)
181 JSD_ASSERT_VALID_CONTEXT(jsdc);
183 JSD_LOCK();
184 JS_REMOVE_LINK(&jsdc->links);
185 JSD_UNLOCK();
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 /***************************************************************************/
204 JSDContext*
205 jsd_DebuggerOnForUser(JSRuntime* jsrt,
206 JSD_UserCallbacks* callbacks,
207 void* user,
208 JSObject* scopeobj)
210 JSDContext* jsdc;
211 JSContext* iter = NULL;
213 jsdc = _newJSDContext(jsrt, callbacks, user, scopeobj);
214 if( ! jsdc )
215 return NULL;
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);
227 #ifdef LIVEWIRE
228 LWDBG_SetNewScriptHookProc(jsd_NewScriptHookProc, jsdc);
229 #endif
230 if( jsdc->userCallbacks.setContext )
231 jsdc->userCallbacks.setContext(jsdc, jsdc->user);
232 return jsdc;
235 JSDContext*
236 jsd_DebuggerOn(void)
238 JS_ASSERT(_jsrt);
239 JS_ASSERT(_validateUserCallbacks(&_callbacks));
240 return jsd_DebuggerOnForUser(_jsrt, &_callbacks, _user, NULL);
243 void
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);
250 #ifdef LIVEWIRE
251 LWDBG_SetNewScriptHookProc(NULL,NULL);
252 #endif
254 /* clean up */
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);
266 void
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);
278 void
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);
288 void
289 jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user)
291 _jsrt = jsrt;
292 _user = user;
294 #ifdef JSD_HAS_DANGEROUS_THREAD
295 _dangerousThread = JSD_CURRENT_THREAD();
296 #endif
298 if( callbacks )
299 memcpy(&_callbacks, callbacks, sizeof(JSD_UserCallbacks));
300 else
301 memset(&_callbacks, 0 , sizeof(JSD_UserCallbacks));
304 void*
305 jsd_SetContextPrivate(JSDContext* jsdc, void *data)
307 void *rval = jsdc->data;
308 jsdc->data = data;
309 return data;
312 void*
313 jsd_GetContextPrivate(JSDContext* jsdc)
315 return jsdc->data;
318 void
319 jsd_ClearAllProfileData(JSDContext* jsdc)
321 JSDScript *current;
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);
334 JSDContext*
335 jsd_JSDContextForJSContext(JSContext* context)
337 JSDContext* iter;
338 JSDContext* jsdc = NULL;
339 JSRuntime* runtime = JS_GetRuntime(context);
341 JSD_LOCK();
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 )
348 jsdc = iter;
349 break;
352 JSD_UNLOCK();
353 return jsdc;
356 static JSBool
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;
364 if( ! jsdc )
366 JS_ASSERT(0);
367 return JS_TRUE;
369 if( JSD_IS_DANGEROUS_THREAD(jsdc) )
370 return JS_TRUE;
372 /* local in case hook gets cleared on another thread */
373 JSD_LOCK();
374 errorReporter = jsdc->errorReporter;
375 errorReporterData = jsdc->errorReporterData;
376 JSD_UNLOCK();
378 if(!errorReporter)
379 return JS_TRUE;
381 switch(errorReporter(jsdc, cx, message, report, errorReporterData))
383 case JSD_ERROR_REPORTER_PASS_ALONG:
384 return JS_TRUE;
385 case JSD_ERROR_REPORTER_RETURN:
386 return JS_FALSE;
387 case JSD_ERROR_REPORTER_DEBUG:
389 jsval rval;
390 JSD_ExecutionHookProc hook;
391 void* hookData;
393 /* local in case hook gets cleared on another thread */
394 JSD_LOCK();
395 hook = jsdc->debugBreakHook;
396 hookData = jsdc->debugBreakHookData;
397 JSD_UNLOCK();
399 jsd_CallExecutionHook(jsdc, cx, JSD_HOOK_DEBUG_REQUESTED,
400 hook, hookData, &rval);
401 /* XXX Should make this dependent on ExecutionHook retval */
402 return JS_TRUE;
404 case JSD_ERROR_REPORTER_CLEAR_RETURN:
405 if(report && JSREPORT_IS_EXCEPTION(report->flags))
406 JS_ClearPendingException(cx);
407 return JS_FALSE;
408 default:
409 JS_ASSERT(0);
410 break;
412 return JS_TRUE;
415 JSBool
416 jsd_SetErrorReporter(JSDContext* jsdc,
417 JSD_ErrorReporter reporter,
418 void* callerdata)
420 JSD_LOCK();
421 jsdc->errorReporter = reporter;
422 jsdc->errorReporterData = callerdata;
423 JSD_UNLOCK();
424 return JS_TRUE;
427 JSBool
428 jsd_GetErrorReporter(JSDContext* jsdc,
429 JSD_ErrorReporter* reporter,
430 void** callerdata)
432 JSD_LOCK();
433 if( reporter )
434 *reporter = jsdc->errorReporter;
435 if( callerdata )
436 *callerdata = jsdc->errorReporterData;
437 JSD_UNLOCK();
438 return JS_TRUE;