Fix regexp match pair end-index == -1 assumption. (r=dmandelin, a=blocker b=605754)
[mozilla-central.git] / js / jsd / jsd_xpc.cpp
blob27b3faf1cc9072c93c5b1a99af8fedb86fb512cf
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Robert Ginda, <rginda@netscape.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "jsdbgapi.h"
41 #include "jslock.h"
42 #include "jsd_xpc.h"
44 #include "nsIXPConnect.h"
45 #include "mozilla/ModuleUtils.h"
46 #include "nsIServiceManager.h"
47 #include "nsIScriptGlobalObject.h"
48 #include "nsIObserver.h"
49 #include "nsIObserverService.h"
50 #include "nsICategoryManager.h"
51 #include "nsIJSRuntimeService.h"
52 #include "nsIThreadInternal.h"
53 #include "nsThreadUtils.h"
54 #include "nsMemory.h"
55 #include "jsdebug.h"
56 #include "nsReadableUtils.h"
57 #include "nsCRT.h"
59 /* XXX DOM dependency */
60 #include "nsIScriptContext.h"
61 #include "nsIJSContextStack.h"
63 /* XXX private JS headers. */
64 #include "jscompartment.h"
67 * defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
68 * script hook. This was a hack to avoid some js engine problems that should
69 * be fixed now (see Mozilla bug 77636).
71 #undef CAUTIOUS_SCRIPTHOOK
73 #ifdef DEBUG_verbose
74 # define DEBUG_COUNT(name, count) \
75 { if ((count % 10) == 0) printf (name ": %i\n", count); }
76 # define DEBUG_CREATE(name, count) {count++; DEBUG_COUNT ("+++++ "name,count)}
77 # define DEBUG_DESTROY(name, count) {count--; DEBUG_COUNT ("----- "name,count)}
78 #else
79 # define DEBUG_CREATE(name, count)
80 # define DEBUG_DESTROY(name, count)
81 #endif
83 #define ASSERT_VALID_CONTEXT { if (!mCx) return NS_ERROR_NOT_AVAILABLE; }
84 #define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; }
86 #define JSDSERVICE_CID \
87 { /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */ \
88 0xf1299dc2, \
89 0x1dd1, \
90 0x11b2, \
91 {0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \
94 #define JSDASO_CID \
95 { /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */ \
96 0x2fd6b7f6, \
97 0xeb8c, \
98 0x4f32, \
99 {0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \
102 #define JSDS_MAJOR_VERSION 1
103 #define JSDS_MINOR_VERSION 2
105 #define NS_CATMAN_CTRID "@mozilla.org/categorymanager;1"
106 #define NS_JSRT_CTRID "@mozilla.org/js/xpc/RuntimeService;1"
108 #define AUTOREG_CATEGORY "xpcom-autoregistration"
109 #define APPSTART_CATEGORY "app-startup"
110 #define JSD_AUTOREG_ENTRY "JSDebugger Startup Observer"
111 #define JSD_STARTUP_ENTRY "JSDebugger Startup Observer"
113 static JSBool
114 jsds_GCCallbackProc (JSContext *cx, JSGCStatus status);
116 /*******************************************************************************
117 * global vars
118 ******************************************************************************/
120 const char implementationString[] = "Mozilla JavaScript Debugger Service";
122 const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
123 const char jsdARObserverCtrID[] = "@mozilla.org/js/jsd/app-start-observer;2";
124 const char jsdASObserverCtrID[] = "service,@mozilla.org/js/jsd/app-start-observer;2";
126 #ifdef DEBUG_verbose
127 PRUint32 gScriptCount = 0;
128 PRUint32 gValueCount = 0;
129 PRUint32 gPropertyCount = 0;
130 PRUint32 gContextCount = 0;
131 PRUint32 gFrameCount = 0;
132 #endif
134 static jsdService *gJsds = 0;
135 static JSGCCallback gLastGCProc = jsds_GCCallbackProc;
136 static JSGCStatus gGCStatus = JSGC_END;
138 static struct DeadScript {
139 PRCList links;
140 JSDContext *jsdc;
141 jsdIScript *script;
142 } *gDeadScripts = nsnull;
144 enum PatternType {
145 ptIgnore = 0U,
146 ptStartsWith = 1U,
147 ptEndsWith = 2U,
148 ptContains = 3U,
149 ptEquals = 4U
152 static struct FilterRecord {
153 PRCList links;
154 jsdIFilter *filterObject;
155 void *glob;
156 nsCString urlPattern;
157 PatternType patternType;
158 PRUint32 startLine;
159 PRUint32 endLine;
160 } *gFilters = nsnull;
162 static struct LiveEphemeral *gLiveValues = nsnull;
163 static struct LiveEphemeral *gLiveProperties = nsnull;
164 static struct LiveEphemeral *gLiveContexts = nsnull;
165 static struct LiveEphemeral *gLiveStackFrames = nsnull;
167 /*******************************************************************************
168 * utility functions for ephemeral lists
169 *******************************************************************************/
170 already_AddRefed<jsdIEphemeral>
171 jsds_FindEphemeral (LiveEphemeral **listHead, void *key)
173 if (!*listHead)
174 return nsnull;
176 LiveEphemeral *lv_record =
177 reinterpret_cast<LiveEphemeral *>
178 (PR_NEXT_LINK(&(*listHead)->links));
181 if (lv_record->key == key)
183 NS_IF_ADDREF(lv_record->value);
184 return lv_record->value;
186 lv_record = reinterpret_cast<LiveEphemeral *>
187 (PR_NEXT_LINK(&lv_record->links));
189 while (lv_record != *listHead);
191 return nsnull;
194 void
195 jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
197 LiveEphemeral *lv_record =
198 reinterpret_cast<LiveEphemeral *>
199 (PR_NEXT_LINK(&(*listHead)->links));
200 while (*listHead)
202 LiveEphemeral *next =
203 reinterpret_cast<LiveEphemeral *>
204 (PR_NEXT_LINK(&lv_record->links));
205 lv_record->value->Invalidate();
206 lv_record = next;
210 void
211 jsds_InsertEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
213 if (*listHead) {
214 /* if the list exists, add to it */
215 PR_APPEND_LINK(&item->links, &(*listHead)->links);
216 } else {
217 /* otherwise create the list */
218 PR_INIT_CLIST(&item->links);
219 *listHead = item;
223 void
224 jsds_RemoveEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
226 LiveEphemeral *next = reinterpret_cast<LiveEphemeral *>
227 (PR_NEXT_LINK(&item->links));
229 if (next == item)
231 /* if the current item is also the next item, we're the only element,
232 * null out the list head */
233 NS_ASSERTION (*listHead == item,
234 "How could we not be the head of a one item list?");
235 *listHead = nsnull;
237 else if (item == *listHead)
239 /* otherwise, if we're currently the list head, change it */
240 *listHead = next;
243 PR_REMOVE_AND_INIT_LINK(&item->links);
246 /*******************************************************************************
247 * utility functions for filters
248 *******************************************************************************/
249 void
250 jsds_FreeFilter (FilterRecord *rec)
252 NS_IF_RELEASE (rec->filterObject);
253 PR_Free (rec);
256 /* copies appropriate |filter| attributes into |rec|.
257 * False return indicates failure, the contents of |rec| will not be changed.
259 PRBool
260 jsds_SyncFilter (FilterRecord *rec, jsdIFilter *filter)
262 NS_ASSERTION (rec, "jsds_SyncFilter without rec");
263 NS_ASSERTION (filter, "jsds_SyncFilter without filter");
265 JSObject *glob_proper = nsnull;
266 nsCOMPtr<nsISupports> glob;
267 nsresult rv = filter->GetGlobalObject(getter_AddRefs(glob));
268 if (NS_FAILED(rv))
269 return PR_FALSE;
270 if (glob) {
271 nsCOMPtr<nsIScriptGlobalObject> nsiglob = do_QueryInterface(glob);
272 if (nsiglob)
273 glob_proper = nsiglob->GetGlobalJSObject();
276 PRUint32 startLine;
277 rv = filter->GetStartLine(&startLine);
278 if (NS_FAILED(rv))
279 return PR_FALSE;
281 PRUint32 endLine;
282 rv = filter->GetStartLine(&endLine);
283 if (NS_FAILED(rv))
284 return PR_FALSE;
286 nsCAutoString urlPattern;
287 rv = filter->GetUrlPattern (urlPattern);
288 if (NS_FAILED(rv))
289 return PR_FALSE;
291 PRUint32 len = urlPattern.Length();
292 if (len) {
293 if (urlPattern[0] == '*') {
294 /* pattern starts with a *, shift all chars once to the left,
295 * including the trailing null. */
296 urlPattern = Substring(urlPattern, 1, len);
298 if (urlPattern[len - 2] == '*') {
299 /* pattern is in the format "*foo*", overwrite the final * with
300 * a null. */
301 urlPattern.Truncate(len - 2);
302 rec->patternType = ptContains;
303 } else {
304 /* pattern is in the format "*foo", just make a note of the
305 * new length. */
306 rec->patternType = ptEndsWith;
308 } else if (urlPattern[len - 1] == '*') {
309 /* pattern is in the format "foo*", overwrite the final * with a
310 * null. */
311 urlPattern.Truncate(len - 1);
312 rec->patternType = ptStartsWith;
313 } else {
314 /* pattern is in the format "foo". */
315 rec->patternType = ptEquals;
317 } else {
318 rec->patternType = ptIgnore;
321 /* we got everything we need without failing, now copy it into rec. */
323 if (rec->filterObject != filter) {
324 NS_IF_RELEASE(rec->filterObject);
325 NS_ADDREF(filter);
326 rec->filterObject = filter;
329 rec->glob = glob_proper;
331 rec->startLine = startLine;
332 rec->endLine = endLine;
334 rec->urlPattern = urlPattern;
336 return PR_TRUE;
340 FilterRecord *
341 jsds_FindFilter (jsdIFilter *filter)
343 if (!gFilters)
344 return nsnull;
346 FilterRecord *current = gFilters;
348 do {
349 if (current->filterObject == filter)
350 return current;
351 current = reinterpret_cast<FilterRecord *>
352 (PR_NEXT_LINK(&current->links));
353 } while (current != gFilters);
355 return nsnull;
358 /* returns true if the hook should be executed. */
359 PRBool
360 jsds_FilterHook (JSDContext *jsdc, JSDThreadState *state)
362 JSContext *cx = JSD_GetJSContext (jsdc, state);
363 void *glob = static_cast<void *>(JS_GetGlobalObject (cx));
365 if (!glob) {
366 NS_WARNING("No global in threadstate");
367 return PR_FALSE;
370 JSDStackFrameInfo *frame = JSD_GetStackFrame (jsdc, state);
372 if (!frame) {
373 NS_WARNING("No frame in threadstate");
374 return PR_FALSE;
377 JSDScript *script = JSD_GetScriptForStackFrame (jsdc, state, frame);
378 if (!script)
379 return PR_TRUE;
381 jsuword pc = JSD_GetPCForStackFrame (jsdc, state, frame);
383 nsDependentCString url(JSD_GetScriptFilename (jsdc, script));
384 if (url.IsEmpty()) {
385 NS_WARNING ("Script with no filename");
386 return PR_FALSE;
389 if (!gFilters)
390 return PR_TRUE;
392 PRUint32 currentLine = JSD_GetClosestLine (jsdc, script, pc);
393 PRUint32 len = 0;
394 FilterRecord *currentFilter = gFilters;
395 do {
396 PRUint32 flags = 0;
397 nsresult rv = currentFilter->filterObject->GetFlags(&flags);
398 NS_ASSERTION(NS_SUCCEEDED(rv), "Error getting flags for filter");
399 if (flags & jsdIFilter::FLAG_ENABLED) {
400 /* if there is no glob, or the globs match */
401 if ((!currentFilter->glob || currentFilter->glob == glob) &&
402 /* and there is no start line, or the start line is before
403 * or equal to the current */
404 (!currentFilter->startLine ||
405 currentFilter->startLine <= currentLine) &&
406 /* and there is no end line, or the end line is after
407 * or equal to the current */
408 (!currentFilter->endLine ||
409 currentFilter->endLine >= currentLine)) {
410 /* then we're going to have to compare the url. */
411 if (currentFilter->patternType == ptIgnore)
412 return !!(flags & jsdIFilter::FLAG_PASS);
414 if (!len)
415 len = url.Length();
416 nsCString urlPattern = currentFilter->urlPattern;
417 PRUint32 patternLength = urlPattern.Length();
418 if (len >= patternLength) {
419 switch (currentFilter->patternType) {
420 case ptEquals:
421 if (urlPattern.Equals(url))
422 return !!(flags & jsdIFilter::FLAG_PASS);
423 break;
424 case ptStartsWith:
425 if (urlPattern.Equals(Substring(url, 0, patternLength)))
426 return !!(flags & jsdIFilter::FLAG_PASS);
427 break;
428 case ptEndsWith:
429 if (urlPattern.Equals(Substring(url, len - patternLength)))
430 return !!(flags & jsdIFilter::FLAG_PASS);
431 break;
432 case ptContains:
434 nsACString::const_iterator start, end;
435 url.BeginReading(start);
436 url.EndReading(end);
437 if (FindInReadable(currentFilter->urlPattern, start, end))
438 return !!(flags & jsdIFilter::FLAG_PASS);
440 break;
441 default:
442 NS_ERROR("Invalid pattern type");
447 currentFilter = reinterpret_cast<FilterRecord *>
448 (PR_NEXT_LINK(&currentFilter->links));
449 } while (currentFilter != gFilters);
451 return PR_TRUE;
455 /*******************************************************************************
456 * c callbacks
457 *******************************************************************************/
459 static void
460 jsds_NotifyPendingDeadScripts (JSContext *cx)
462 #ifdef CAUTIOUS_SCRIPTHOOK
463 JSRuntime *rt = JS_GetRuntime(cx);
464 #endif
465 jsdService *jsds = gJsds;
467 nsCOMPtr<jsdIScriptHook> hook;
468 if (jsds) {
469 NS_ADDREF(jsds);
470 jsds->GetScriptHook (getter_AddRefs(hook));
471 jsds->Pause(nsnull);
474 DeadScript *deadScripts = gDeadScripts;
475 gDeadScripts = nsnull;
476 while (deadScripts) {
477 DeadScript *ds = deadScripts;
478 /* get next deleted script */
479 deadScripts = reinterpret_cast<DeadScript *>
480 (PR_NEXT_LINK(&ds->links));
481 if (deadScripts == ds)
482 deadScripts = nsnull;
484 if (hook)
486 /* tell the user this script has been destroyed */
487 #ifdef CAUTIOUS_SCRIPTHOOK
488 JS_UNKEEP_ATOMS(rt);
489 #endif
490 hook->OnScriptDestroyed (ds->script);
491 #ifdef CAUTIOUS_SCRIPTHOOK
492 JS_KEEP_ATOMS(rt);
493 #endif
496 /* take it out of the circular list */
497 PR_REMOVE_LINK(&ds->links);
499 /* addref came from the FromPtr call in jsds_ScriptHookProc */
500 NS_RELEASE(ds->script);
501 /* free the struct! */
502 PR_Free(ds);
505 if (jsds) {
506 jsds->UnPause(nsnull);
507 NS_RELEASE(jsds);
511 static JSBool
512 jsds_GCCallbackProc (JSContext *cx, JSGCStatus status)
514 #ifdef DEBUG_verbose
515 printf ("new gc status is %i\n", status);
516 #endif
517 if (status == JSGC_END) {
518 /* just to guard against reentering. */
519 gGCStatus = JSGC_BEGIN;
520 while (gDeadScripts)
521 jsds_NotifyPendingDeadScripts (cx);
524 gGCStatus = status;
525 if (gLastGCProc)
526 return gLastGCProc (cx, status);
528 return JS_TRUE;
531 static uintN
532 jsds_ErrorHookProc (JSDContext *jsdc, JSContext *cx, const char *message,
533 JSErrorReport *report, void *callerdata)
535 static PRBool running = PR_FALSE;
537 nsCOMPtr<jsdIErrorHook> hook;
538 gJsds->GetErrorHook(getter_AddRefs(hook));
539 if (!hook)
540 return JSD_ERROR_REPORTER_PASS_ALONG;
542 if (running)
543 return JSD_ERROR_REPORTER_PASS_ALONG;
545 running = PR_TRUE;
547 nsCOMPtr<jsdIValue> val;
548 if (JS_IsExceptionPending(cx)) {
549 jsval jv;
550 JS_GetPendingException(cx, &jv);
551 JSDValue *jsdv = JSD_NewValue (jsdc, jv);
552 val = getter_AddRefs(jsdValue::FromPtr(jsdc, jsdv));
555 nsCAutoString fileName;
556 PRUint32 line;
557 PRUint32 pos;
558 PRUint32 flags;
559 PRUint32 errnum;
560 PRBool rval;
561 if (report) {
562 fileName.Assign(report->filename);
563 line = report->lineno;
564 pos = report->tokenptr - report->linebuf;
565 flags = report->flags;
566 errnum = report->errorNumber;
568 else
570 line = 0;
571 pos = 0;
572 flags = 0;
573 errnum = 0;
576 gJsds->Pause(nsnull);
577 hook->OnError (nsDependentCString(message), fileName, line, pos, flags, errnum, val, &rval);
578 gJsds->UnPause(nsnull);
580 running = PR_FALSE;
581 if (!rval)
582 return JSD_ERROR_REPORTER_DEBUG;
584 return JSD_ERROR_REPORTER_PASS_ALONG;
587 static JSBool
588 jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
589 uintN type, void* callerdata)
591 nsCOMPtr<jsdICallHook> hook;
593 switch (type)
595 case JSD_HOOK_TOPLEVEL_START:
596 case JSD_HOOK_TOPLEVEL_END:
597 gJsds->GetTopLevelHook(getter_AddRefs(hook));
598 break;
600 case JSD_HOOK_FUNCTION_CALL:
601 case JSD_HOOK_FUNCTION_RETURN:
602 gJsds->GetFunctionHook(getter_AddRefs(hook));
603 break;
605 default:
606 NS_ASSERTION (0, "Unknown hook type.");
609 if (!hook)
610 return JS_TRUE;
612 if (!jsds_FilterHook (jsdc, jsdthreadstate))
613 return JS_FALSE;
615 JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
616 nsCOMPtr<jsdIStackFrame> frame =
617 getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
618 native_frame));
619 gJsds->Pause(nsnull);
620 hook->OnCall(frame, type);
621 gJsds->UnPause(nsnull);
622 jsdStackFrame::InvalidateAll();
624 return JS_TRUE;
627 static PRUint32
628 jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
629 uintN type, void* callerdata, jsval* rval)
631 nsCOMPtr<jsdIExecutionHook> hook(0);
632 PRUint32 hook_rv = JSD_HOOK_RETURN_CONTINUE;
633 nsCOMPtr<jsdIValue> js_rv;
635 switch (type)
637 case JSD_HOOK_INTERRUPTED:
638 gJsds->GetInterruptHook(getter_AddRefs(hook));
639 break;
640 case JSD_HOOK_DEBUG_REQUESTED:
641 gJsds->GetDebugHook(getter_AddRefs(hook));
642 break;
643 case JSD_HOOK_DEBUGGER_KEYWORD:
644 gJsds->GetDebuggerHook(getter_AddRefs(hook));
645 break;
646 case JSD_HOOK_BREAKPOINT:
648 /* we can't pause breakpoints the way we pause the other
649 * execution hooks (at least, not easily.) Instead we bail
650 * here if the service is paused. */
651 PRUint32 level;
652 gJsds->GetPauseDepth(&level);
653 if (!level)
654 gJsds->GetBreakpointHook(getter_AddRefs(hook));
656 break;
657 case JSD_HOOK_THROW:
659 hook_rv = JSD_HOOK_RETURN_CONTINUE_THROW;
660 gJsds->GetThrowHook(getter_AddRefs(hook));
661 if (hook) {
662 JSDValue *jsdv = JSD_GetException (jsdc, jsdthreadstate);
663 js_rv = getter_AddRefs(jsdValue::FromPtr (jsdc, jsdv));
665 break;
667 default:
668 NS_ASSERTION (0, "Unknown hook type.");
671 if (!hook)
672 return hook_rv;
674 if (!jsds_FilterHook (jsdc, jsdthreadstate))
675 return JSD_HOOK_RETURN_CONTINUE;
677 JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
678 nsCOMPtr<jsdIStackFrame> frame =
679 getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
680 native_frame));
681 gJsds->Pause(nsnull);
682 jsdIValue *inout_rv = js_rv;
683 NS_IF_ADDREF(inout_rv);
684 hook->OnExecute (frame, type, &inout_rv, &hook_rv);
685 js_rv = inout_rv;
686 NS_IF_RELEASE(inout_rv);
687 gJsds->UnPause(nsnull);
688 jsdStackFrame::InvalidateAll();
690 if (hook_rv == JSD_HOOK_RETURN_RET_WITH_VAL ||
691 hook_rv == JSD_HOOK_RETURN_THROW_WITH_VAL) {
692 *rval = JSVAL_VOID;
693 if (js_rv) {
694 JSDValue *jsdv;
695 if (NS_SUCCEEDED(js_rv->GetJSDValue (&jsdv)))
696 *rval = JSD_GetValueWrappedJSVal(jsdc, jsdv);
700 return hook_rv;
703 static void
704 jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating,
705 void* callerdata)
707 #ifdef CAUTIOUS_SCRIPTHOOK
708 JSContext *cx = JSD_GetDefaultJSContext(jsdc);
709 JSRuntime *rt = JS_GetRuntime(cx);
710 #endif
712 if (creating) {
713 nsCOMPtr<jsdIScriptHook> hook;
714 gJsds->GetScriptHook(getter_AddRefs(hook));
716 /* a script is being created */
717 if (!hook) {
718 /* nobody cares, just exit */
719 return;
722 nsCOMPtr<jsdIScript> script =
723 getter_AddRefs(jsdScript::FromPtr(jsdc, jsdscript));
724 #ifdef CAUTIOUS_SCRIPTHOOK
725 JS_UNKEEP_ATOMS(rt);
726 #endif
727 gJsds->Pause(nsnull);
728 hook->OnScriptCreated (script);
729 gJsds->UnPause(nsnull);
730 #ifdef CAUTIOUS_SCRIPTHOOK
731 JS_KEEP_ATOMS(rt);
732 #endif
733 } else {
734 /* a script is being destroyed. even if there is no registered hook
735 * we'll still need to invalidate the jsdIScript record, in order
736 * to remove the reference held in the JSDScript private data. */
737 nsCOMPtr<jsdIScript> jsdis =
738 static_cast<jsdIScript *>(JSD_GetScriptPrivate(jsdscript));
739 if (!jsdis)
740 return;
742 jsdis->Invalidate();
744 if (gGCStatus == JSGC_END) {
745 nsCOMPtr<jsdIScriptHook> hook;
746 gJsds->GetScriptHook(getter_AddRefs(hook));
747 if (!hook)
748 return;
750 /* if GC *isn't* running, we can tell the user about the script
751 * delete now. */
752 #ifdef CAUTIOUS_SCRIPTHOOK
753 JS_UNKEEP_ATOMS(rt);
754 #endif
756 gJsds->Pause(nsnull);
757 hook->OnScriptDestroyed (jsdis);
758 gJsds->UnPause(nsnull);
759 #ifdef CAUTIOUS_SCRIPTHOOK
760 JS_KEEP_ATOMS(rt);
761 #endif
762 } else {
763 /* if a GC *is* running, we've got to wait until it's done before
764 * we can execute any JS, so we queue the notification in a PRCList
765 * until GC tells us it's done. See jsds_GCCallbackProc(). */
766 DeadScript *ds = PR_NEW(DeadScript);
767 if (!ds)
768 return; /* NS_ERROR_OUT_OF_MEMORY */
770 ds->jsdc = jsdc;
771 ds->script = jsdis;
772 NS_ADDREF(ds->script);
773 if (gDeadScripts)
774 /* if the queue exists, add to it */
775 PR_APPEND_LINK(&ds->links, &gDeadScripts->links);
776 else {
777 /* otherwise create the queue */
778 PR_INIT_CLIST(&ds->links);
779 gDeadScripts = ds;
785 /*******************************************************************************
786 * reflected jsd data structures
787 *******************************************************************************/
789 /* Contexts */
791 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral);
793 NS_IMETHODIMP
794 jsdContext::GetJSDContext(JSDContext **_rval)
796 *_rval = mCx;
797 return NS_OK;
801 /* Objects */
802 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject, jsdIObject)
804 NS_IMETHODIMP
805 jsdObject::GetJSDContext(JSDContext **_rval)
807 *_rval = mCx;
808 return NS_OK;
811 NS_IMETHODIMP
812 jsdObject::GetJSDObject(JSDObject **_rval)
814 *_rval = mObject;
815 return NS_OK;
818 NS_IMETHODIMP
819 jsdObject::GetCreatorURL(nsACString &_rval)
821 _rval.Assign(JSD_GetObjectNewURL(mCx, mObject));
822 return NS_OK;
825 NS_IMETHODIMP
826 jsdObject::GetCreatorLine(PRUint32 *_rval)
828 *_rval = JSD_GetObjectNewLineNumber(mCx, mObject);
829 return NS_OK;
832 NS_IMETHODIMP
833 jsdObject::GetConstructorURL(nsACString &_rval)
835 _rval.Assign(JSD_GetObjectConstructorURL(mCx, mObject));
836 return NS_OK;
839 NS_IMETHODIMP
840 jsdObject::GetConstructorLine(PRUint32 *_rval)
842 *_rval = JSD_GetObjectConstructorLineNumber(mCx, mObject);
843 return NS_OK;
846 NS_IMETHODIMP
847 jsdObject::GetValue(jsdIValue **_rval)
849 JSDValue *jsdv = JSD_GetValueForObject (mCx, mObject);
851 *_rval = jsdValue::FromPtr (mCx, jsdv);
852 return NS_OK;
855 /* Properties */
856 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty, jsdIProperty, jsdIEphemeral)
858 jsdProperty::jsdProperty (JSDContext *aCx, JSDProperty *aProperty) :
859 mCx(aCx), mProperty(aProperty)
861 DEBUG_CREATE ("jsdProperty", gPropertyCount);
862 mValid = (aCx && aProperty);
863 mLiveListEntry.value = this;
864 jsds_InsertEphemeral (&gLiveProperties, &mLiveListEntry);
867 jsdProperty::~jsdProperty ()
869 DEBUG_DESTROY ("jsdProperty", gPropertyCount);
870 if (mValid)
871 Invalidate();
874 NS_IMETHODIMP
875 jsdProperty::Invalidate()
877 ASSERT_VALID_EPHEMERAL;
878 mValid = PR_FALSE;
879 jsds_RemoveEphemeral (&gLiveProperties, &mLiveListEntry);
880 JSD_DropProperty (mCx, mProperty);
881 return NS_OK;
884 void
885 jsdProperty::InvalidateAll()
887 if (gLiveProperties)
888 jsds_InvalidateAllEphemerals (&gLiveProperties);
891 NS_IMETHODIMP
892 jsdProperty::GetJSDContext(JSDContext **_rval)
894 *_rval = mCx;
895 return NS_OK;
898 NS_IMETHODIMP
899 jsdProperty::GetJSDProperty(JSDProperty **_rval)
901 *_rval = mProperty;
902 return NS_OK;
905 NS_IMETHODIMP
906 jsdProperty::GetIsValid(PRBool *_rval)
908 *_rval = mValid;
909 return NS_OK;
912 NS_IMETHODIMP
913 jsdProperty::GetAlias(jsdIValue **_rval)
915 JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
917 *_rval = jsdValue::FromPtr (mCx, jsdv);
918 return NS_OK;
921 NS_IMETHODIMP
922 jsdProperty::GetFlags(PRUint32 *_rval)
924 *_rval = JSD_GetPropertyFlags (mCx, mProperty);
925 return NS_OK;
928 NS_IMETHODIMP
929 jsdProperty::GetName(jsdIValue **_rval)
931 JSDValue *jsdv = JSD_GetPropertyName (mCx, mProperty);
933 *_rval = jsdValue::FromPtr (mCx, jsdv);
934 return NS_OK;
937 NS_IMETHODIMP
938 jsdProperty::GetValue(jsdIValue **_rval)
940 JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
942 *_rval = jsdValue::FromPtr (mCx, jsdv);
943 return NS_OK;
946 NS_IMETHODIMP
947 jsdProperty::GetVarArgSlot(PRUint32 *_rval)
949 *_rval = JSD_GetPropertyVarArgSlot (mCx, mProperty);
950 return NS_OK;
953 /* Scripts */
954 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
956 jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
957 mTag(0),
958 mCx(aCx),
959 mScript(aScript),
960 mFileName(0),
961 mFunctionName(0),
962 mBaseLineNumber(0),
963 mLineExtent(0),
964 mPPLineMap(0),
965 mFirstPC(0)
967 DEBUG_CREATE ("jsdScript", gScriptCount);
969 if (mScript) {
970 /* copy the script's information now, so we have it later, when it
971 * gets destroyed. */
972 JSD_LockScriptSubsystem(mCx);
973 mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
974 mFunctionName =
975 new nsCString(JSD_GetScriptFunctionName(mCx, mScript));
976 mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
977 mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
978 mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
979 JSD_UnlockScriptSubsystem(mCx);
981 mValid = PR_TRUE;
985 jsdScript::~jsdScript ()
987 DEBUG_DESTROY ("jsdScript", gScriptCount);
988 if (mFileName)
989 delete mFileName;
990 if (mFunctionName)
991 delete mFunctionName;
993 if (mPPLineMap)
994 PR_Free(mPPLineMap);
996 /* Invalidate() needs to be called to release an owning reference to
997 * ourselves, so if we got here without being invalidated, something
998 * has gone wrong with our ref count. */
999 NS_ASSERTION (!mValid, "Script destroyed without being invalidated.");
1003 * This method populates a line <-> pc map for a pretty printed version of this
1004 * script. It does this by decompiling, and then recompiling the script. The
1005 * resulting script is scanned for the line map, and then left as GC fodder.
1007 PCMapEntry *
1008 jsdScript::CreatePPLineMap()
1010 JSContext *cx = JSD_GetDefaultJSContext (mCx);
1011 JSAutoRequest ar(cx);
1012 JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
1013 JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
1014 JSScript *script;
1015 PRUint32 baseLine;
1016 PRBool scriptOwner = PR_FALSE;
1018 if (fun) {
1019 uintN nargs = JS_GetFunctionArgumentCount(cx, fun);
1020 if (nargs > 12)
1021 return nsnull;
1022 JSString *jsstr = JS_DecompileFunctionBody (cx, fun, 4);
1023 if (!jsstr)
1024 return nsnull;
1026 const char *argnames[] = {"arg1", "arg2", "arg3", "arg4",
1027 "arg5", "arg6", "arg7", "arg8",
1028 "arg9", "arg10", "arg11", "arg12" };
1029 fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames,
1030 JS_GetStringChars(jsstr),
1031 JS_GetStringLength(jsstr),
1032 "x-jsd:ppbuffer?type=function", 3);
1033 if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
1034 return nsnull;
1035 baseLine = 3;
1036 } else {
1037 JSString *jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript),
1038 "ppscript", 4);
1039 if (!jsstr)
1040 return nsnull;
1042 script = JS_CompileUCScript (cx, obj,
1043 JS_GetStringChars(jsstr),
1044 JS_GetStringLength(jsstr),
1045 "x-jsd:ppbuffer?type=script", 1);
1046 if (!script)
1047 return nsnull;
1048 scriptOwner = PR_TRUE;
1049 baseLine = 1;
1052 PRUint32 scriptExtent = JS_GetScriptLineExtent (cx, script);
1053 jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0);
1054 /* allocate worst case size of map (number of lines in script + 1
1055 * for our 0 record), we'll shrink it with a realloc later. */
1056 PCMapEntry *lineMap =
1057 static_cast<PCMapEntry *>
1058 (PR_Malloc((scriptExtent + 1) * sizeof (PCMapEntry)));
1059 PRUint32 lineMapSize = 0;
1061 if (lineMap) {
1062 for (PRUint32 line = baseLine; line < scriptExtent + baseLine; ++line) {
1063 jsbytecode* pc = JS_LineNumberToPC (cx, script, line);
1064 if (line == JS_PCToLineNumber (cx, script, pc)) {
1065 lineMap[lineMapSize].line = line;
1066 lineMap[lineMapSize].pc = pc - firstPC;
1067 ++lineMapSize;
1070 if (scriptExtent != lineMapSize) {
1071 lineMap =
1072 static_cast<PCMapEntry *>
1073 (PR_Realloc(mPPLineMap = lineMap,
1074 lineMapSize * sizeof(PCMapEntry)));
1075 if (!lineMap) {
1076 PR_Free(mPPLineMap);
1077 lineMapSize = 0;
1082 if (scriptOwner)
1083 JS_DestroyScript (cx, script);
1085 mPCMapSize = lineMapSize;
1086 return mPPLineMap = lineMap;
1089 PRUint32
1090 jsdScript::PPPcToLine (PRUint32 aPC)
1092 if (!mPPLineMap && !CreatePPLineMap())
1093 return 0;
1094 PRUint32 i;
1095 for (i = 1; i < mPCMapSize; ++i) {
1096 if (mPPLineMap[i].pc > aPC)
1097 return mPPLineMap[i - 1].line;
1100 return mPPLineMap[mPCMapSize - 1].line;
1103 PRUint32
1104 jsdScript::PPLineToPc (PRUint32 aLine)
1106 if (!mPPLineMap && !CreatePPLineMap())
1107 return 0;
1108 PRUint32 i;
1109 for (i = 1; i < mPCMapSize; ++i) {
1110 if (mPPLineMap[i].line > aLine)
1111 return mPPLineMap[i - 1].pc;
1114 return mPPLineMap[mPCMapSize - 1].pc;
1117 NS_IMETHODIMP
1118 jsdScript::GetJSDContext(JSDContext **_rval)
1120 ASSERT_VALID_EPHEMERAL;
1121 *_rval = mCx;
1122 return NS_OK;
1125 NS_IMETHODIMP
1126 jsdScript::GetJSDScript(JSDScript **_rval)
1128 ASSERT_VALID_EPHEMERAL;
1129 *_rval = mScript;
1130 return NS_OK;
1133 NS_IMETHODIMP
1134 jsdScript::GetVersion (PRInt32 *_rval)
1136 ASSERT_VALID_EPHEMERAL;
1137 JSContext *cx = JSD_GetDefaultJSContext (mCx);
1138 JSScript *script = JSD_GetJSScript(mCx, mScript);
1139 *_rval = static_cast<PRInt32>(JS_GetScriptVersion(cx, script));
1140 return NS_OK;
1143 NS_IMETHODIMP
1144 jsdScript::GetTag(PRUint32 *_rval)
1146 if (!mTag)
1147 mTag = ++jsdScript::LastTag;
1149 *_rval = mTag;
1150 return NS_OK;
1153 NS_IMETHODIMP
1154 jsdScript::Invalidate()
1156 ASSERT_VALID_EPHEMERAL;
1157 mValid = PR_FALSE;
1159 /* release the addref we do in FromPtr */
1160 jsdIScript *script = static_cast<jsdIScript *>
1161 (JSD_GetScriptPrivate(mScript));
1162 NS_ASSERTION (script == this, "That's not my script!");
1163 NS_RELEASE(script);
1164 JSD_SetScriptPrivate(mScript, NULL);
1165 return NS_OK;
1168 void
1169 jsdScript::InvalidateAll ()
1171 JSDContext *cx;
1172 if (NS_FAILED(gJsds->GetJSDContext (&cx)))
1173 return;
1175 JSDScript *script;
1176 JSDScript *iter = NULL;
1178 JSD_LockScriptSubsystem(cx);
1179 while((script = JSD_IterateScripts(cx, &iter)) != NULL) {
1180 nsCOMPtr<jsdIScript> jsdis =
1181 static_cast<jsdIScript *>(JSD_GetScriptPrivate(script));
1182 if (jsdis)
1183 jsdis->Invalidate();
1185 JSD_UnlockScriptSubsystem(cx);
1188 NS_IMETHODIMP
1189 jsdScript::GetIsValid(PRBool *_rval)
1191 *_rval = mValid;
1192 return NS_OK;
1195 NS_IMETHODIMP
1196 jsdScript::SetFlags(PRUint32 flags)
1198 ASSERT_VALID_EPHEMERAL;
1199 JSD_SetScriptFlags(mCx, mScript, flags);
1200 return NS_OK;
1203 NS_IMETHODIMP
1204 jsdScript::GetFlags(PRUint32 *_rval)
1206 ASSERT_VALID_EPHEMERAL;
1207 *_rval = JSD_GetScriptFlags(mCx, mScript);
1208 return NS_OK;
1211 NS_IMETHODIMP
1212 jsdScript::GetFileName(nsACString &_rval)
1214 _rval.Assign(*mFileName);
1215 return NS_OK;
1218 NS_IMETHODIMP
1219 jsdScript::GetFunctionName(nsACString &_rval)
1221 _rval.Assign(*mFunctionName);
1222 return NS_OK;
1225 NS_IMETHODIMP
1226 jsdScript::GetParameterNames(PRUint32* count, PRUnichar*** paramNames)
1228 ASSERT_VALID_EPHEMERAL;
1229 JSContext *cx = JSD_GetDefaultJSContext (mCx);
1230 if (!cx) {
1231 NS_WARNING("No default context !?");
1232 return NS_ERROR_FAILURE;
1234 JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
1236 JSAutoRequest ar(cx);
1238 uintN nargs;
1239 if (!fun ||
1240 !JS_FunctionHasLocalNames(cx, fun) ||
1241 (nargs = JS_GetFunctionArgumentCount(cx, fun)) == 0) {
1242 *count = 0;
1243 *paramNames = nsnull;
1244 return NS_OK;
1247 PRUnichar **ret =
1248 static_cast<PRUnichar**>(NS_Alloc(nargs * sizeof(PRUnichar*)));
1249 if (!ret)
1250 return NS_ERROR_OUT_OF_MEMORY;
1252 void *mark;
1253 jsuword *names = JS_GetFunctionLocalNameArray(cx, fun, &mark);
1254 if (!names) {
1255 NS_Free(ret);
1256 return NS_ERROR_OUT_OF_MEMORY;
1259 nsresult rv = NS_OK;
1260 for (uintN i = 0; i < nargs; ++i) {
1261 JSAtom *atom = JS_LocalNameToAtom(names[i]);
1262 if (!atom) {
1263 ret[i] = 0;
1264 } else {
1265 JSString *str = JS_AtomKey(atom);
1266 ret[i] = NS_strndup(reinterpret_cast<PRUnichar*>(JS_GetStringChars(str)),
1267 JS_GetStringLength(str));
1268 if (!ret[i]) {
1269 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
1270 rv = NS_ERROR_OUT_OF_MEMORY;
1271 break;
1275 JS_ReleaseFunctionLocalNameArray(cx, mark);
1276 if (NS_FAILED(rv))
1277 return rv;
1278 *count = nargs;
1279 *paramNames = ret;
1280 return NS_OK;
1283 NS_IMETHODIMP
1284 jsdScript::GetFunctionObject(jsdIValue **_rval)
1286 JSFunction *fun = JSD_GetJSFunction(mCx, mScript);
1287 if (!fun)
1288 return NS_ERROR_NOT_AVAILABLE;
1290 JSObject *obj = JS_GetFunctionObject(fun);
1291 if (!obj)
1292 return NS_ERROR_FAILURE;
1294 JSDContext *cx;
1295 if (NS_FAILED(gJsds->GetJSDContext (&cx)))
1296 return NS_ERROR_NOT_INITIALIZED;
1298 JSDValue *jsdv = JSD_NewValue(cx, OBJECT_TO_JSVAL(obj));
1299 if (!jsdv)
1300 return NS_ERROR_OUT_OF_MEMORY;
1302 *_rval = jsdValue::FromPtr(cx, jsdv);
1303 if (!*_rval) {
1304 JSD_DropValue(cx, jsdv);
1305 return NS_ERROR_OUT_OF_MEMORY;
1308 return NS_OK;
1311 NS_IMETHODIMP
1312 jsdScript::GetFunctionSource(nsAString & aFunctionSource)
1314 ASSERT_VALID_EPHEMERAL;
1315 JSContext *cx = JSD_GetDefaultJSContext (mCx);
1316 if (!cx) {
1317 NS_WARNING("No default context !?");
1318 return NS_ERROR_FAILURE;
1320 JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
1322 JSAutoRequest ar(cx);
1324 JSString *jsstr;
1325 if (fun) {
1326 JSAutoEnterCompartment ac;
1327 if (!ac.enter(cx, JS_GetFunctionObject(fun)))
1328 return NS_ERROR_FAILURE;
1329 jsstr = JS_DecompileFunction (cx, fun, 4);
1330 } else {
1331 JSScript *script = JSD_GetJSScript (mCx, mScript);
1332 js::SwitchToCompartment sc(cx, script->compartment);
1333 jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
1335 if (!jsstr)
1336 return NS_ERROR_FAILURE;
1338 aFunctionSource =
1339 nsDependentString(
1340 reinterpret_cast<PRUnichar*>(JS_GetStringChars(jsstr)),
1341 JS_GetStringLength(jsstr));
1342 return NS_OK;
1345 NS_IMETHODIMP
1346 jsdScript::GetBaseLineNumber(PRUint32 *_rval)
1348 *_rval = mBaseLineNumber;
1349 return NS_OK;
1352 NS_IMETHODIMP
1353 jsdScript::GetLineExtent(PRUint32 *_rval)
1355 *_rval = mLineExtent;
1356 return NS_OK;
1359 NS_IMETHODIMP
1360 jsdScript::GetCallCount(PRUint32 *_rval)
1362 ASSERT_VALID_EPHEMERAL;
1363 *_rval = JSD_GetScriptCallCount (mCx, mScript);
1364 return NS_OK;
1367 NS_IMETHODIMP
1368 jsdScript::GetMaxRecurseDepth(PRUint32 *_rval)
1370 ASSERT_VALID_EPHEMERAL;
1371 *_rval = JSD_GetScriptMaxRecurseDepth (mCx, mScript);
1372 return NS_OK;
1375 NS_IMETHODIMP
1376 jsdScript::GetMinExecutionTime(double *_rval)
1378 ASSERT_VALID_EPHEMERAL;
1379 *_rval = JSD_GetScriptMinExecutionTime (mCx, mScript);
1380 return NS_OK;
1383 NS_IMETHODIMP
1384 jsdScript::GetMaxExecutionTime(double *_rval)
1386 ASSERT_VALID_EPHEMERAL;
1387 *_rval = JSD_GetScriptMaxExecutionTime (mCx, mScript);
1388 return NS_OK;
1391 NS_IMETHODIMP
1392 jsdScript::GetTotalExecutionTime(double *_rval)
1394 ASSERT_VALID_EPHEMERAL;
1395 *_rval = JSD_GetScriptTotalExecutionTime (mCx, mScript);
1396 return NS_OK;
1399 NS_IMETHODIMP
1400 jsdScript::GetMinOwnExecutionTime(double *_rval)
1402 ASSERT_VALID_EPHEMERAL;
1403 *_rval = JSD_GetScriptMinOwnExecutionTime (mCx, mScript);
1404 return NS_OK;
1407 NS_IMETHODIMP
1408 jsdScript::GetMaxOwnExecutionTime(double *_rval)
1410 ASSERT_VALID_EPHEMERAL;
1411 *_rval = JSD_GetScriptMaxOwnExecutionTime (mCx, mScript);
1412 return NS_OK;
1415 NS_IMETHODIMP
1416 jsdScript::GetTotalOwnExecutionTime(double *_rval)
1418 ASSERT_VALID_EPHEMERAL;
1419 *_rval = JSD_GetScriptTotalOwnExecutionTime (mCx, mScript);
1420 return NS_OK;
1423 NS_IMETHODIMP
1424 jsdScript::ClearProfileData()
1426 ASSERT_VALID_EPHEMERAL;
1427 JSD_ClearScriptProfileData(mCx, mScript);
1428 return NS_OK;
1431 NS_IMETHODIMP
1432 jsdScript::PcToLine(PRUint32 aPC, PRUint32 aPcmap, PRUint32 *_rval)
1434 ASSERT_VALID_EPHEMERAL;
1435 if (aPcmap == PCMAP_SOURCETEXT) {
1436 *_rval = JSD_GetClosestLine (mCx, mScript, mFirstPC + aPC);
1437 } else if (aPcmap == PCMAP_PRETTYPRINT) {
1438 *_rval = PPPcToLine(aPC);
1439 } else {
1440 return NS_ERROR_INVALID_ARG;
1443 return NS_OK;
1446 NS_IMETHODIMP
1447 jsdScript::LineToPc(PRUint32 aLine, PRUint32 aPcmap, PRUint32 *_rval)
1449 ASSERT_VALID_EPHEMERAL;
1450 if (aPcmap == PCMAP_SOURCETEXT) {
1451 jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
1452 *_rval = pc - mFirstPC;
1453 } else if (aPcmap == PCMAP_PRETTYPRINT) {
1454 *_rval = PPLineToPc(aLine);
1455 } else {
1456 return NS_ERROR_INVALID_ARG;
1459 return NS_OK;
1462 NS_IMETHODIMP
1463 jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval)
1465 ASSERT_VALID_EPHEMERAL;
1466 if (aPcmap == PCMAP_SOURCETEXT) {
1467 jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
1468 *_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc));
1469 } else if (aPcmap == PCMAP_PRETTYPRINT) {
1470 if (!mPPLineMap && !CreatePPLineMap())
1471 return NS_ERROR_OUT_OF_MEMORY;
1472 *_rval = PR_FALSE;
1473 for (PRUint32 i = 0; i < mPCMapSize; ++i) {
1474 if (mPPLineMap[i].line >= aLine) {
1475 *_rval = (mPPLineMap[i].line == aLine);
1476 break;
1479 } else {
1480 return NS_ERROR_INVALID_ARG;
1483 return NS_OK;
1486 NS_IMETHODIMP
1487 jsdScript::SetBreakpoint(PRUint32 aPC)
1489 ASSERT_VALID_EPHEMERAL;
1490 jsuword pc = mFirstPC + aPC;
1491 JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, NULL);
1492 return NS_OK;
1495 NS_IMETHODIMP
1496 jsdScript::ClearBreakpoint(PRUint32 aPC)
1498 ASSERT_VALID_EPHEMERAL;
1499 jsuword pc = mFirstPC + aPC;
1500 JSD_ClearExecutionHook (mCx, mScript, pc);
1501 return NS_OK;
1504 NS_IMETHODIMP
1505 jsdScript::ClearAllBreakpoints()
1507 ASSERT_VALID_EPHEMERAL;
1508 JSD_LockScriptSubsystem(mCx);
1509 JSD_ClearAllExecutionHooksForScript (mCx, mScript);
1510 JSD_UnlockScriptSubsystem(mCx);
1511 return NS_OK;
1514 /* Contexts */
1515 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral)
1517 jsdIContext *
1518 jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx)
1520 if (!aJSDCx || !aJSCx)
1521 return nsnull;
1523 nsCOMPtr<jsdIContext> jsdicx;
1524 nsCOMPtr<jsdIEphemeral> eph =
1525 jsds_FindEphemeral (&gLiveContexts, static_cast<void *>(aJSCx));
1526 if (eph)
1528 jsdicx = do_QueryInterface(eph);
1530 else
1532 nsCOMPtr<nsISupports> iscx;
1533 if (JS_GetOptions(aJSCx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
1534 iscx = static_cast<nsISupports *>(JS_GetContextPrivate(aJSCx));
1535 jsdicx = new jsdContext (aJSDCx, aJSCx, iscx);
1538 jsdIContext *ctx = nsnull;
1539 jsdicx.swap(ctx);
1540 return ctx;
1543 jsdContext::jsdContext (JSDContext *aJSDCx, JSContext *aJSCx,
1544 nsISupports *aISCx) : mValid(PR_TRUE), mTag(0),
1545 mJSDCx(aJSDCx),
1546 mJSCx(aJSCx), mISCx(aISCx)
1548 DEBUG_CREATE ("jsdContext", gContextCount);
1549 mLiveListEntry.value = this;
1550 mLiveListEntry.key = static_cast<void *>(aJSCx);
1551 jsds_InsertEphemeral (&gLiveContexts, &mLiveListEntry);
1554 jsdContext::~jsdContext()
1556 DEBUG_DESTROY ("jsdContext", gContextCount);
1557 if (mValid)
1559 /* call Invalidate() to take ourselves out of the live list */
1560 Invalidate();
1564 NS_IMETHODIMP
1565 jsdContext::GetIsValid(PRBool *_rval)
1567 *_rval = mValid;
1568 return NS_OK;
1571 NS_IMETHODIMP
1572 jsdContext::Invalidate()
1574 ASSERT_VALID_EPHEMERAL;
1575 mValid = PR_FALSE;
1576 jsds_RemoveEphemeral (&gLiveContexts, &mLiveListEntry);
1577 return NS_OK;
1580 void
1581 jsdContext::InvalidateAll()
1583 if (gLiveContexts)
1584 jsds_InvalidateAllEphemerals (&gLiveContexts);
1587 NS_IMETHODIMP
1588 jsdContext::GetJSContext(JSContext **_rval)
1590 ASSERT_VALID_EPHEMERAL;
1591 *_rval = mJSCx;
1592 return NS_OK;
1595 NS_IMETHODIMP
1596 jsdContext::GetOptions(PRUint32 *_rval)
1598 ASSERT_VALID_EPHEMERAL;
1599 *_rval = JS_GetOptions(mJSCx);
1600 return NS_OK;
1603 NS_IMETHODIMP
1604 jsdContext::SetOptions(PRUint32 options)
1606 ASSERT_VALID_EPHEMERAL;
1607 PRUint32 lastOptions = JS_GetOptions(mJSCx);
1609 /* don't let users change this option, they'd just be shooting themselves
1610 * in the foot. */
1611 if ((options ^ lastOptions) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
1612 return NS_ERROR_ILLEGAL_VALUE;
1614 JS_SetOptions(mJSCx, options);
1615 return NS_OK;
1618 NS_IMETHODIMP
1619 jsdContext::GetPrivateData(nsISupports **_rval)
1621 ASSERT_VALID_EPHEMERAL;
1622 PRUint32 options = JS_GetOptions(mJSCx);
1623 if (options & JSOPTION_PRIVATE_IS_NSISUPPORTS)
1625 *_rval = static_cast<nsISupports*>(JS_GetContextPrivate(mJSCx));
1626 NS_IF_ADDREF(*_rval);
1628 else
1630 *_rval = nsnull;
1633 return NS_OK;
1636 NS_IMETHODIMP
1637 jsdContext::GetWrappedContext(nsISupports **_rval)
1639 ASSERT_VALID_EPHEMERAL;
1640 NS_IF_ADDREF(*_rval = mISCx);
1641 return NS_OK;
1644 NS_IMETHODIMP
1645 jsdContext::GetTag(PRUint32 *_rval)
1647 ASSERT_VALID_EPHEMERAL;
1648 if (!mTag)
1649 mTag = ++jsdContext::LastTag;
1651 *_rval = mTag;
1652 return NS_OK;
1655 NS_IMETHODIMP
1656 jsdContext::GetVersion (PRInt32 *_rval)
1658 ASSERT_VALID_EPHEMERAL;
1659 *_rval = static_cast<PRInt32>(JS_GetVersion(mJSCx));
1660 return NS_OK;
1663 NS_IMETHODIMP
1664 jsdContext::SetVersion (PRInt32 id)
1666 ASSERT_VALID_EPHEMERAL;
1667 JSVersion ver = static_cast<JSVersion>(id);
1668 JS_SetVersion(mJSCx, ver);
1669 return NS_OK;
1672 NS_IMETHODIMP
1673 jsdContext::GetGlobalObject (jsdIValue **_rval)
1675 ASSERT_VALID_EPHEMERAL;
1676 JSObject *glob = JS_GetGlobalObject(mJSCx);
1677 JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
1678 if (!jsdv)
1679 return NS_ERROR_FAILURE;
1680 *_rval = jsdValue::FromPtr (mJSDCx, jsdv);
1681 if (!*_rval)
1682 return NS_ERROR_FAILURE;
1683 return NS_OK;
1686 NS_IMETHODIMP
1687 jsdContext::GetScriptsEnabled (PRBool *_rval)
1689 ASSERT_VALID_EPHEMERAL;
1690 if (!mISCx) {
1691 *_rval = PR_TRUE;
1692 return NS_OK;
1695 nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
1696 if (!context)
1697 return NS_ERROR_NO_INTERFACE;
1699 *_rval = context->GetScriptsEnabled();
1701 return NS_OK;
1704 NS_IMETHODIMP
1705 jsdContext::SetScriptsEnabled (PRBool _rval)
1707 ASSERT_VALID_EPHEMERAL;
1708 if (!mISCx) {
1709 if (_rval)
1710 return NS_OK;
1711 return NS_ERROR_NO_INTERFACE;
1714 nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
1715 if (!context)
1716 return NS_ERROR_NO_INTERFACE;
1718 context->SetScriptsEnabled(_rval, PR_TRUE);
1720 return NS_OK;
1723 /* Stack Frames */
1724 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame, jsdIStackFrame, jsdIEphemeral)
1726 jsdStackFrame::jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState,
1727 JSDStackFrameInfo *aStackFrameInfo) :
1728 mCx(aCx), mThreadState(aThreadState), mStackFrameInfo(aStackFrameInfo)
1730 DEBUG_CREATE ("jsdStackFrame", gFrameCount);
1731 mValid = (aCx && aThreadState && aStackFrameInfo);
1732 if (mValid) {
1733 mLiveListEntry.key = aStackFrameInfo;
1734 mLiveListEntry.value = this;
1735 jsds_InsertEphemeral (&gLiveStackFrames, &mLiveListEntry);
1739 jsdStackFrame::~jsdStackFrame()
1741 DEBUG_DESTROY ("jsdStackFrame", gFrameCount);
1742 if (mValid)
1744 /* call Invalidate() to take ourselves out of the live list */
1745 Invalidate();
1749 jsdIStackFrame *
1750 jsdStackFrame::FromPtr (JSDContext *aCx, JSDThreadState *aThreadState,
1751 JSDStackFrameInfo *aStackFrameInfo)
1753 if (!aStackFrameInfo)
1754 return nsnull;
1756 jsdIStackFrame *rv;
1757 nsCOMPtr<jsdIStackFrame> frame;
1759 nsCOMPtr<jsdIEphemeral> eph =
1760 jsds_FindEphemeral (&gLiveStackFrames,
1761 reinterpret_cast<void *>(aStackFrameInfo));
1763 if (eph)
1765 frame = do_QueryInterface(eph);
1766 rv = frame;
1768 else
1770 rv = new jsdStackFrame (aCx, aThreadState, aStackFrameInfo);
1773 NS_IF_ADDREF(rv);
1774 return rv;
1777 NS_IMETHODIMP
1778 jsdStackFrame::Invalidate()
1780 ASSERT_VALID_EPHEMERAL;
1781 mValid = PR_FALSE;
1782 jsds_RemoveEphemeral (&gLiveStackFrames, &mLiveListEntry);
1783 return NS_OK;
1786 void
1787 jsdStackFrame::InvalidateAll()
1789 if (gLiveStackFrames)
1790 jsds_InvalidateAllEphemerals (&gLiveStackFrames);
1793 NS_IMETHODIMP
1794 jsdStackFrame::GetJSDContext(JSDContext **_rval)
1796 ASSERT_VALID_EPHEMERAL;
1797 *_rval = mCx;
1798 return NS_OK;
1801 NS_IMETHODIMP
1802 jsdStackFrame::GetJSDThreadState(JSDThreadState **_rval)
1804 ASSERT_VALID_EPHEMERAL;
1805 *_rval = mThreadState;
1806 return NS_OK;
1809 NS_IMETHODIMP
1810 jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo **_rval)
1812 ASSERT_VALID_EPHEMERAL;
1813 *_rval = mStackFrameInfo;
1814 return NS_OK;
1817 NS_IMETHODIMP
1818 jsdStackFrame::GetIsValid(PRBool *_rval)
1820 *_rval = mValid;
1821 return NS_OK;
1824 NS_IMETHODIMP
1825 jsdStackFrame::GetCallingFrame(jsdIStackFrame **_rval)
1827 ASSERT_VALID_EPHEMERAL;
1828 JSDStackFrameInfo *sfi = JSD_GetCallingStackFrame (mCx, mThreadState,
1829 mStackFrameInfo);
1830 *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
1831 return NS_OK;
1834 NS_IMETHODIMP
1835 jsdStackFrame::GetExecutionContext(jsdIContext **_rval)
1837 ASSERT_VALID_EPHEMERAL;
1838 JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
1839 *_rval = jsdContext::FromPtr (mCx, cx);
1840 return NS_OK;
1843 NS_IMETHODIMP
1844 jsdStackFrame::GetFunctionName(nsACString &_rval)
1846 ASSERT_VALID_EPHEMERAL;
1847 _rval.Assign(JSD_GetNameForStackFrame(mCx, mThreadState, mStackFrameInfo));
1848 return NS_OK;
1851 NS_IMETHODIMP
1852 jsdStackFrame::GetIsDebugger(PRBool *_rval)
1854 ASSERT_VALID_EPHEMERAL;
1855 *_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo);
1856 return NS_OK;
1859 NS_IMETHODIMP
1860 jsdStackFrame::GetIsConstructing(PRBool *_rval)
1862 ASSERT_VALID_EPHEMERAL;
1863 *_rval = JSD_IsStackFrameConstructing (mCx, mThreadState, mStackFrameInfo);
1864 return NS_OK;
1867 NS_IMETHODIMP
1868 jsdStackFrame::GetScript(jsdIScript **_rval)
1870 ASSERT_VALID_EPHEMERAL;
1871 JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1872 mStackFrameInfo);
1873 *_rval = jsdScript::FromPtr (mCx, script);
1874 return NS_OK;
1877 NS_IMETHODIMP
1878 jsdStackFrame::GetPc(PRUint32 *_rval)
1880 ASSERT_VALID_EPHEMERAL;
1881 JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1882 mStackFrameInfo);
1883 if (!script)
1884 return NS_ERROR_FAILURE;
1885 jsuword pcbase = JSD_GetClosestPC(mCx, script, 0);
1887 jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
1888 if (pc)
1889 *_rval = pc - pcbase;
1890 else
1891 *_rval = pcbase;
1892 return NS_OK;
1895 NS_IMETHODIMP
1896 jsdStackFrame::GetLine(PRUint32 *_rval)
1898 ASSERT_VALID_EPHEMERAL;
1899 JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1900 mStackFrameInfo);
1901 if (script) {
1902 jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
1903 *_rval = JSD_GetClosestLine (mCx, script, pc);
1904 } else {
1905 return NS_ERROR_FAILURE;
1907 return NS_OK;
1910 NS_IMETHODIMP
1911 jsdStackFrame::GetCallee(jsdIValue **_rval)
1913 ASSERT_VALID_EPHEMERAL;
1914 JSDValue *jsdv = JSD_GetCallObjectForStackFrame (mCx, mThreadState,
1915 mStackFrameInfo);
1917 *_rval = jsdValue::FromPtr (mCx, jsdv);
1918 return NS_OK;
1921 NS_IMETHODIMP
1922 jsdStackFrame::GetScope(jsdIValue **_rval)
1924 ASSERT_VALID_EPHEMERAL;
1925 JSDValue *jsdv = JSD_GetScopeChainForStackFrame (mCx, mThreadState,
1926 mStackFrameInfo);
1928 *_rval = jsdValue::FromPtr (mCx, jsdv);
1929 return NS_OK;
1932 NS_IMETHODIMP
1933 jsdStackFrame::GetThisValue(jsdIValue **_rval)
1935 ASSERT_VALID_EPHEMERAL;
1936 JSDValue *jsdv = JSD_GetThisForStackFrame (mCx, mThreadState,
1937 mStackFrameInfo);
1939 *_rval = jsdValue::FromPtr (mCx, jsdv);
1940 return NS_OK;
1944 NS_IMETHODIMP
1945 jsdStackFrame::Eval (const nsAString &bytes, const nsACString &fileName,
1946 PRUint32 line, jsdIValue **result, PRBool *_rval)
1948 ASSERT_VALID_EPHEMERAL;
1950 if (bytes.IsEmpty())
1951 return NS_ERROR_INVALID_ARG;
1953 // get pointer to buffer contained in |bytes|
1954 nsAString::const_iterator h;
1955 bytes.BeginReading(h);
1956 const jschar *char_bytes = reinterpret_cast<const jschar *>(h.get());
1958 JSExceptionState *estate = 0;
1959 jsval jv;
1961 JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
1963 JSAutoRequest ar(cx);
1965 estate = JS_SaveExceptionState (cx);
1966 JS_ClearPendingException (cx);
1968 nsresult rv;
1969 nsCOMPtr<nsIJSContextStack> stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
1970 if (NS_SUCCEEDED(rv))
1971 rv = stack->Push(cx);
1972 if (NS_FAILED(rv)) {
1973 JS_RestoreExceptionState (cx, estate);
1974 return rv;
1977 *_rval = JSD_AttemptUCScriptInStackFrame (mCx, mThreadState,
1978 mStackFrameInfo,
1979 char_bytes, bytes.Length(),
1980 PromiseFlatCString(fileName).get(),
1981 line, &jv);
1982 if (!*_rval) {
1983 if (JS_IsExceptionPending(cx))
1984 JS_GetPendingException (cx, &jv);
1985 else
1986 jv = JSVAL_NULL;
1989 JS_RestoreExceptionState (cx, estate);
1991 #ifdef DEBUG
1992 JSContext* poppedCX;
1993 rv = stack->Pop(&poppedCX);
1994 NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == cx, "bad pop");
1995 #else
1996 (void) stack->Pop(nsnull);
1997 #endif
1999 JSDValue *jsdv = JSD_NewValue (mCx, jv);
2000 if (!jsdv)
2001 return NS_ERROR_FAILURE;
2002 *result = jsdValue::FromPtr (mCx, jsdv);
2003 if (!*result)
2004 return NS_ERROR_FAILURE;
2006 return NS_OK;
2009 /* Values */
2010 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue, jsdIValue, jsdIEphemeral)
2011 jsdIValue *
2012 jsdValue::FromPtr (JSDContext *aCx, JSDValue *aValue)
2014 /* value will be dropped by te jsdValue destructor. */
2016 if (!aValue)
2017 return nsnull;
2019 jsdIValue *rv = new jsdValue (aCx, aValue);
2020 NS_IF_ADDREF(rv);
2021 return rv;
2024 jsdValue::jsdValue (JSDContext *aCx, JSDValue *aValue) : mValid(PR_TRUE),
2025 mCx(aCx),
2026 mValue(aValue)
2028 DEBUG_CREATE ("jsdValue", gValueCount);
2029 mLiveListEntry.value = this;
2030 jsds_InsertEphemeral (&gLiveValues, &mLiveListEntry);
2033 jsdValue::~jsdValue()
2035 DEBUG_DESTROY ("jsdValue", gValueCount);
2036 if (mValid)
2037 /* call Invalidate() to take ourselves out of the live list */
2038 Invalidate();
2041 NS_IMETHODIMP
2042 jsdValue::GetIsValid(PRBool *_rval)
2044 *_rval = mValid;
2045 return NS_OK;
2048 NS_IMETHODIMP
2049 jsdValue::Invalidate()
2051 ASSERT_VALID_EPHEMERAL;
2052 mValid = PR_FALSE;
2053 jsds_RemoveEphemeral (&gLiveValues, &mLiveListEntry);
2054 JSD_DropValue (mCx, mValue);
2055 return NS_OK;
2058 void
2059 jsdValue::InvalidateAll()
2061 if (gLiveValues)
2062 jsds_InvalidateAllEphemerals (&gLiveValues);
2065 NS_IMETHODIMP
2066 jsdValue::GetJSDContext(JSDContext **_rval)
2068 ASSERT_VALID_EPHEMERAL;
2069 *_rval = mCx;
2070 return NS_OK;
2073 NS_IMETHODIMP
2074 jsdValue::GetJSDValue (JSDValue **_rval)
2076 ASSERT_VALID_EPHEMERAL;
2077 *_rval = mValue;
2078 return NS_OK;
2081 NS_IMETHODIMP
2082 jsdValue::GetIsNative (PRBool *_rval)
2084 ASSERT_VALID_EPHEMERAL;
2085 *_rval = JSD_IsValueNative (mCx, mValue);
2086 return NS_OK;
2089 NS_IMETHODIMP
2090 jsdValue::GetIsNumber (PRBool *_rval)
2092 ASSERT_VALID_EPHEMERAL;
2093 *_rval = JSD_IsValueNumber (mCx, mValue);
2094 return NS_OK;
2097 NS_IMETHODIMP
2098 jsdValue::GetIsPrimitive (PRBool *_rval)
2100 ASSERT_VALID_EPHEMERAL;
2101 *_rval = JSD_IsValuePrimitive (mCx, mValue);
2102 return NS_OK;
2105 NS_IMETHODIMP
2106 jsdValue::GetJsType (PRUint32 *_rval)
2108 ASSERT_VALID_EPHEMERAL;
2109 jsval val;
2111 val = JSD_GetValueWrappedJSVal (mCx, mValue);
2113 if (JSVAL_IS_NULL(val))
2114 *_rval = TYPE_NULL;
2115 else if (JSVAL_IS_BOOLEAN(val))
2116 *_rval = TYPE_BOOLEAN;
2117 else if (JSVAL_IS_DOUBLE(val))
2118 *_rval = TYPE_DOUBLE;
2119 else if (JSVAL_IS_INT(val))
2120 *_rval = TYPE_INT;
2121 else if (JSVAL_IS_STRING(val))
2122 *_rval = TYPE_STRING;
2123 else if (JSVAL_IS_VOID(val))
2124 *_rval = TYPE_VOID;
2125 else if (JSD_IsValueFunction (mCx, mValue))
2126 *_rval = TYPE_FUNCTION;
2127 else if (JSVAL_IS_OBJECT(val))
2128 *_rval = TYPE_OBJECT;
2129 else
2130 NS_ASSERTION (0, "Value has no discernible type.");
2132 return NS_OK;
2135 NS_IMETHODIMP
2136 jsdValue::GetJsPrototype (jsdIValue **_rval)
2138 ASSERT_VALID_EPHEMERAL;
2139 JSDValue *jsdv = JSD_GetValuePrototype (mCx, mValue);
2140 *_rval = jsdValue::FromPtr (mCx, jsdv);
2141 return NS_OK;
2144 NS_IMETHODIMP
2145 jsdValue::GetJsParent (jsdIValue **_rval)
2147 ASSERT_VALID_EPHEMERAL;
2148 JSDValue *jsdv = JSD_GetValueParent (mCx, mValue);
2149 *_rval = jsdValue::FromPtr (mCx, jsdv);
2150 return NS_OK;
2153 NS_IMETHODIMP
2154 jsdValue::GetJsClassName(nsACString &_rval)
2156 ASSERT_VALID_EPHEMERAL;
2157 _rval.Assign(JSD_GetValueClassName(mCx, mValue));
2159 return NS_OK;
2162 NS_IMETHODIMP
2163 jsdValue::GetJsConstructor (jsdIValue **_rval)
2165 ASSERT_VALID_EPHEMERAL;
2166 JSDValue *jsdv = JSD_GetValueConstructor (mCx, mValue);
2167 *_rval = jsdValue::FromPtr (mCx, jsdv);
2168 return NS_OK;
2171 NS_IMETHODIMP
2172 jsdValue::GetJsFunctionName(nsACString &_rval)
2174 ASSERT_VALID_EPHEMERAL;
2175 _rval.Assign(JSD_GetValueFunctionName(mCx, mValue));
2176 return NS_OK;
2179 NS_IMETHODIMP
2180 jsdValue::GetBooleanValue(PRBool *_rval)
2182 ASSERT_VALID_EPHEMERAL;
2183 *_rval = JSD_GetValueBoolean (mCx, mValue);
2184 return NS_OK;
2187 NS_IMETHODIMP
2188 jsdValue::GetDoubleValue(double *_rval)
2190 ASSERT_VALID_EPHEMERAL;
2191 *_rval = JSD_GetValueDouble (mCx, mValue);
2192 return NS_OK;
2195 NS_IMETHODIMP
2196 jsdValue::GetIntValue(PRInt32 *_rval)
2198 ASSERT_VALID_EPHEMERAL;
2199 *_rval = JSD_GetValueInt (mCx, mValue);
2200 return NS_OK;
2203 NS_IMETHODIMP
2204 jsdValue::GetObjectValue(jsdIObject **_rval)
2206 ASSERT_VALID_EPHEMERAL;
2207 JSDObject *obj;
2208 obj = JSD_GetObjectForValue (mCx, mValue);
2209 *_rval = jsdObject::FromPtr (mCx, obj);
2210 if (!*_rval)
2211 return NS_ERROR_FAILURE;
2212 return NS_OK;
2215 NS_IMETHODIMP
2216 jsdValue::GetStringValue(nsACString &_rval)
2218 ASSERT_VALID_EPHEMERAL;
2219 JSString *jstr_val = JSD_GetValueString(mCx, mValue);
2220 if (jstr_val) {
2221 nsDependentString chars(
2222 reinterpret_cast<PRUnichar*>(JS_GetStringChars(jstr_val)),
2223 JS_GetStringLength(jstr_val));
2224 CopyUTF16toUTF8(chars, _rval);
2225 } else {
2226 _rval.Truncate();
2228 return NS_OK;
2231 NS_IMETHODIMP
2232 jsdValue::GetPropertyCount (PRInt32 *_rval)
2234 ASSERT_VALID_EPHEMERAL;
2235 if (JSD_IsValueObject(mCx, mValue))
2236 *_rval = JSD_GetCountOfProperties (mCx, mValue);
2237 else
2238 *_rval = -1;
2239 return NS_OK;
2242 NS_IMETHODIMP
2243 jsdValue::GetProperties (jsdIProperty ***propArray, PRUint32 *length)
2245 ASSERT_VALID_EPHEMERAL;
2246 *propArray = nsnull;
2247 if (length)
2248 *length = 0;
2250 PRUint32 prop_count = JSD_IsValueObject(mCx, mValue)
2251 ? JSD_GetCountOfProperties (mCx, mValue)
2252 : 0;
2253 NS_ENSURE_TRUE(prop_count, NS_OK);
2255 jsdIProperty **pa_temp =
2256 static_cast<jsdIProperty **>
2257 (nsMemory::Alloc(sizeof (jsdIProperty *) *
2258 prop_count));
2259 NS_ENSURE_TRUE(pa_temp, NS_ERROR_OUT_OF_MEMORY);
2261 PRUint32 i = 0;
2262 JSDProperty *iter = NULL;
2263 JSDProperty *prop;
2264 while ((prop = JSD_IterateProperties (mCx, mValue, &iter))) {
2265 pa_temp[i] = jsdProperty::FromPtr (mCx, prop);
2266 ++i;
2269 NS_ASSERTION (prop_count == i, "property count mismatch");
2271 /* if caller doesn't care about length, don't bother telling them */
2272 *propArray = pa_temp;
2273 if (length)
2274 *length = prop_count;
2276 return NS_OK;
2279 NS_IMETHODIMP
2280 jsdValue::GetProperty (const nsACString &name, jsdIProperty **_rval)
2282 ASSERT_VALID_EPHEMERAL;
2283 JSContext *cx = JSD_GetDefaultJSContext (mCx);
2285 JSAutoRequest ar(cx);
2287 /* not rooting this */
2288 JSString *jstr_name = JS_NewStringCopyZ(cx, PromiseFlatCString(name).get());
2289 if (!jstr_name)
2290 return NS_ERROR_OUT_OF_MEMORY;
2292 JSDProperty *prop = JSD_GetValueProperty (mCx, mValue, jstr_name);
2294 *_rval = jsdProperty::FromPtr (mCx, prop);
2295 return NS_OK;
2298 NS_IMETHODIMP
2299 jsdValue::Refresh()
2301 ASSERT_VALID_EPHEMERAL;
2302 JSD_RefreshValue (mCx, mValue);
2303 return NS_OK;
2306 NS_IMETHODIMP
2307 jsdValue::GetWrappedValue()
2309 ASSERT_VALID_EPHEMERAL;
2310 nsresult rv;
2311 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2312 if (NS_FAILED(rv))
2313 return rv;
2315 nsAXPCNativeCallContext *cc = nsnull;
2316 rv = xpc->GetCurrentNativeCallContext(&cc);
2317 if (NS_FAILED(rv))
2318 return rv;
2320 jsval *result;
2321 rv = cc->GetRetValPtr(&result);
2322 if (NS_FAILED(rv))
2323 return rv;
2325 if (result)
2327 JSContext *cx;
2328 rv = cc->GetJSContext(&cx);
2329 if (NS_FAILED(rv))
2330 return rv;
2331 *result = JSD_GetValueWrappedJSVal (mCx, mValue);
2332 if (!JS_WrapValue(cx, result))
2333 return NS_ERROR_FAILURE;
2334 cc->SetReturnValueWasSet(PR_TRUE);
2337 return NS_OK;
2340 NS_IMETHODIMP
2341 jsdValue::GetScript(jsdIScript **_rval)
2343 ASSERT_VALID_EPHEMERAL;
2344 JSDScript *script = JSD_GetScriptForValue(mCx, mValue);
2345 *_rval = jsdScript::FromPtr(mCx, script);
2346 return NS_OK;
2349 /******************************************************************************
2350 * debugger service implementation
2351 ******************************************************************************/
2352 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdService, jsdIDebuggerService)
2354 NS_IMETHODIMP
2355 jsdService::GetJSDContext(JSDContext **_rval)
2357 *_rval = mCx;
2358 return NS_OK;
2361 NS_IMETHODIMP
2362 jsdService::GetFlags (PRUint32 *_rval)
2364 ASSERT_VALID_CONTEXT;
2365 *_rval = JSD_GetContextFlags (mCx);
2366 return NS_OK;
2369 NS_IMETHODIMP
2370 jsdService::SetFlags (PRUint32 flags)
2372 ASSERT_VALID_CONTEXT;
2373 JSD_SetContextFlags (mCx, flags);
2374 return NS_OK;
2377 NS_IMETHODIMP
2378 jsdService::GetImplementationString(nsACString &aImplementationString)
2380 aImplementationString.AssignLiteral(implementationString);
2381 return NS_OK;
2384 NS_IMETHODIMP
2385 jsdService::GetImplementationMajor(PRUint32 *_rval)
2387 *_rval = JSDS_MAJOR_VERSION;
2388 return NS_OK;
2391 NS_IMETHODIMP
2392 jsdService::GetImplementationMinor(PRUint32 *_rval)
2394 *_rval = JSDS_MINOR_VERSION;
2395 return NS_OK;
2398 NS_IMETHODIMP
2399 jsdService::GetIsOn (PRBool *_rval)
2401 *_rval = mOn;
2402 return NS_OK;
2405 NS_IMETHODIMP
2406 jsdService::On (void)
2408 return NS_ERROR_NOT_IMPLEMENTED;
2411 NS_IMETHODIMP
2412 jsdService::AsyncOn (jsdIActivationCallback *activationCallback)
2414 nsresult rv;
2416 /* get JS things from the CallContext */
2417 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2418 if (NS_FAILED(rv)) return rv;
2420 nsAXPCNativeCallContext *cc = nsnull;
2421 rv = xpc->GetCurrentNativeCallContext(&cc);
2422 if (NS_FAILED(rv)) return rv;
2424 JSContext *cx;
2425 rv = cc->GetJSContext (&cx);
2426 if (NS_FAILED(rv)) return rv;
2428 mActivationCallback = activationCallback;
2430 return xpc->SetDebugModeWhenPossible(PR_TRUE);
2433 NS_IMETHODIMP
2434 jsdService::RecompileForDebugMode (JSRuntime *rt, JSBool mode) {
2435 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
2437 JSContext *cx;
2438 JSContext *iter = NULL;
2440 jsword currentThreadId = reinterpret_cast<jsword>(js_CurrentThreadId());
2442 while ((cx = JS_ContextIterator (rt, &iter))) {
2443 if (JS_GetContextThread(cx) == currentThreadId) {
2444 JS_SetDebugMode(cx, mode);
2448 return NS_OK;
2451 NS_IMETHODIMP
2452 jsdService::ActivateDebugger (JSRuntime *rt)
2454 if (mOn)
2455 return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED;
2457 mRuntime = rt;
2458 RecompileForDebugMode(rt, JS_TRUE);
2460 if (gLastGCProc == jsds_GCCallbackProc)
2461 /* condition indicates that the callback proc has not been set yet */
2462 gLastGCProc = JS_SetGCCallbackRT (rt, jsds_GCCallbackProc);
2464 mCx = JSD_DebuggerOnForUser (rt, NULL, NULL);
2465 if (!mCx)
2466 return NS_ERROR_FAILURE;
2468 JSContext *cx = JSD_GetDefaultJSContext (mCx);
2469 JSObject *glob = JS_GetGlobalObject (cx);
2471 /* init xpconnect on the debugger's context in case xpconnect tries to
2472 * use it for stuff. */
2473 nsresult rv;
2474 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2475 if (NS_FAILED(rv))
2476 return rv;
2478 xpc->InitClasses (cx, glob);
2480 /* If any of these mFooHook objects are installed, do the required JSD
2481 * hookup now. See also, jsdService::SetFooHook().
2483 if (mErrorHook)
2484 JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
2485 if (mThrowHook)
2486 JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
2487 /* can't ignore script callbacks, as we need to |Release| the wrapper
2488 * stored in private data when a script is deleted. */
2489 if (mInterruptHook)
2490 JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
2491 if (mDebuggerHook)
2492 JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
2493 if (mDebugHook)
2494 JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
2495 if (mTopLevelHook)
2496 JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
2497 else
2498 JSD_ClearTopLevelHook (mCx);
2499 if (mFunctionHook)
2500 JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
2501 else
2502 JSD_ClearFunctionHook (mCx);
2503 mOn = PR_TRUE;
2505 #ifdef DEBUG
2506 printf ("+++ JavaScript debugging hooks installed.\n");
2507 #endif
2509 if (mActivationCallback)
2510 return mActivationCallback->OnDebuggerActivated();
2512 return NS_OK;
2515 NS_IMETHODIMP
2516 jsdService::Off (void)
2518 if (!mOn)
2519 return NS_OK;
2521 if (!mCx || !mRuntime)
2522 return NS_ERROR_NOT_INITIALIZED;
2524 if (gDeadScripts) {
2525 if (gGCStatus != JSGC_END)
2526 return NS_ERROR_NOT_AVAILABLE;
2528 JSContext *cx = JSD_GetDefaultJSContext(mCx);
2529 jsds_NotifyPendingDeadScripts(cx);
2533 if (gLastGCProc != jsds_GCCallbackProc)
2534 JS_SetGCCallbackRT (mRuntime, gLastGCProc);
2537 jsdContext::InvalidateAll();
2538 jsdScript::InvalidateAll();
2539 jsdValue::InvalidateAll();
2540 jsdProperty::InvalidateAll();
2541 ClearAllBreakpoints();
2543 JSD_SetErrorReporter (mCx, NULL, NULL);
2544 JSD_SetScriptHook (mCx, NULL, NULL);
2545 JSD_ClearThrowHook (mCx);
2546 JSD_ClearInterruptHook (mCx);
2547 JSD_ClearDebuggerHook (mCx);
2548 JSD_ClearDebugBreakHook (mCx);
2549 JSD_ClearTopLevelHook (mCx);
2550 JSD_ClearFunctionHook (mCx);
2552 JSD_DebuggerOff (mCx);
2554 mCx = nsnull;
2555 mRuntime = nsnull;
2556 mOn = PR_FALSE;
2558 #ifdef DEBUG
2559 printf ("+++ JavaScript debugging hooks removed.\n");
2560 #endif
2562 nsresult rv;
2563 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2564 if (NS_FAILED(rv))
2565 return rv;
2567 xpc->SetDebugModeWhenPossible(PR_FALSE);
2569 return NS_OK;
2572 NS_IMETHODIMP
2573 jsdService::GetPauseDepth(PRUint32 *_rval)
2575 NS_ENSURE_ARG_POINTER(_rval);
2576 *_rval = mPauseLevel;
2577 return NS_OK;
2580 NS_IMETHODIMP
2581 jsdService::Pause(PRUint32 *_rval)
2583 if (!mCx)
2584 return NS_ERROR_NOT_INITIALIZED;
2586 if (++mPauseLevel == 1) {
2587 JSD_SetErrorReporter (mCx, NULL, NULL);
2588 JSD_ClearThrowHook (mCx);
2589 JSD_ClearInterruptHook (mCx);
2590 JSD_ClearDebuggerHook (mCx);
2591 JSD_ClearDebugBreakHook (mCx);
2592 JSD_ClearTopLevelHook (mCx);
2593 JSD_ClearFunctionHook (mCx);
2594 JSD_DebuggerPause (mCx);
2597 if (_rval)
2598 *_rval = mPauseLevel;
2600 return NS_OK;
2603 NS_IMETHODIMP
2604 jsdService::UnPause(PRUint32 *_rval)
2606 if (!mCx)
2607 return NS_ERROR_NOT_INITIALIZED;
2609 if (mPauseLevel == 0)
2610 return NS_ERROR_NOT_AVAILABLE;
2612 /* check mOn before we muck with this stuff, it's possible the debugger
2613 * was turned off while we were paused.
2615 if (--mPauseLevel == 0 && mOn) {
2616 JSD_DebuggerUnpause (mCx);
2617 if (mErrorHook)
2618 JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
2619 if (mThrowHook)
2620 JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
2621 if (mInterruptHook)
2622 JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
2623 if (mDebuggerHook)
2624 JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
2625 if (mDebugHook)
2626 JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
2627 if (mTopLevelHook)
2628 JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
2629 else
2630 JSD_ClearTopLevelHook (mCx);
2631 if (mFunctionHook)
2632 JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
2633 else
2634 JSD_ClearFunctionHook (mCx);
2637 if (_rval)
2638 *_rval = mPauseLevel;
2640 return NS_OK;
2643 NS_IMETHODIMP
2644 jsdService::EnumerateContexts (jsdIContextEnumerator *enumerator)
2646 ASSERT_VALID_CONTEXT;
2648 if (!enumerator)
2649 return NS_OK;
2651 JSContext *iter = NULL;
2652 JSContext *cx;
2654 while ((cx = JS_ContextIterator (mRuntime, &iter)))
2656 nsCOMPtr<jsdIContext> jsdicx =
2657 getter_AddRefs(jsdContext::FromPtr(mCx, cx));
2658 if (jsdicx)
2660 if (NS_FAILED(enumerator->EnumerateContext(jsdicx)))
2661 break;
2665 return NS_OK;
2668 NS_IMETHODIMP
2669 jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator)
2671 ASSERT_VALID_CONTEXT;
2673 JSDScript *script;
2674 JSDScript *iter = NULL;
2675 nsresult rv = NS_OK;
2677 JSD_LockScriptSubsystem(mCx);
2678 while((script = JSD_IterateScripts(mCx, &iter))) {
2679 nsCOMPtr<jsdIScript> jsdis =
2680 getter_AddRefs(jsdScript::FromPtr(mCx, script));
2681 rv = enumerator->EnumerateScript (jsdis);
2682 if (NS_FAILED(rv))
2683 break;
2685 JSD_UnlockScriptSubsystem(mCx);
2687 return rv;
2690 NS_IMETHODIMP
2691 jsdService::GC (void)
2693 ASSERT_VALID_CONTEXT;
2694 JSContext *cx = JSD_GetDefaultJSContext (mCx);
2695 JS_GC(cx);
2696 return NS_OK;
2699 NS_IMETHODIMP
2700 jsdService::DumpHeap(const nsACString &fileName)
2702 ASSERT_VALID_CONTEXT;
2703 #ifndef DEBUG
2704 return NS_ERROR_NOT_IMPLEMENTED;
2705 #else
2706 nsresult rv = NS_OK;
2707 FILE *file = !fileName.IsEmpty() ? fopen(PromiseFlatCString(fileName).get(), "w") : stdout;
2708 if (!file) {
2709 rv = NS_ERROR_FAILURE;
2710 } else {
2711 JSContext *cx = JSD_GetDefaultJSContext (mCx);
2712 if (!JS_DumpHeap(cx, file, NULL, 0, NULL, (size_t)-1, NULL))
2713 rv = NS_ERROR_FAILURE;
2714 if (file != stdout)
2715 fclose(file);
2717 return rv;
2718 #endif
2721 NS_IMETHODIMP
2722 jsdService::ClearProfileData ()
2724 ASSERT_VALID_CONTEXT;
2725 JSD_ClearAllProfileData (mCx);
2726 return NS_OK;
2729 NS_IMETHODIMP
2730 jsdService::InsertFilter (jsdIFilter *filter, jsdIFilter *after)
2732 NS_ENSURE_ARG_POINTER (filter);
2733 if (jsds_FindFilter (filter))
2734 return NS_ERROR_INVALID_ARG;
2736 FilterRecord *rec = PR_NEWZAP (FilterRecord);
2737 if (!rec)
2738 return NS_ERROR_OUT_OF_MEMORY;
2740 if (!jsds_SyncFilter (rec, filter)) {
2741 PR_Free (rec);
2742 return NS_ERROR_FAILURE;
2745 if (gFilters) {
2746 if (!after) {
2747 /* insert at head of list */
2748 PR_INSERT_LINK(&rec->links, &gFilters->links);
2749 gFilters = rec;
2750 } else {
2751 /* insert somewhere in the list */
2752 FilterRecord *afterRecord = jsds_FindFilter (after);
2753 if (!afterRecord) {
2754 jsds_FreeFilter(rec);
2755 return NS_ERROR_INVALID_ARG;
2757 PR_INSERT_AFTER(&rec->links, &afterRecord->links);
2759 } else {
2760 if (after) {
2761 /* user asked to insert into the middle of an empty list, bail. */
2762 jsds_FreeFilter(rec);
2763 return NS_ERROR_NOT_INITIALIZED;
2765 PR_INIT_CLIST(&rec->links);
2766 gFilters = rec;
2769 return NS_OK;
2772 NS_IMETHODIMP
2773 jsdService::AppendFilter (jsdIFilter *filter)
2775 NS_ENSURE_ARG_POINTER (filter);
2776 if (jsds_FindFilter (filter))
2777 return NS_ERROR_INVALID_ARG;
2778 FilterRecord *rec = PR_NEWZAP (FilterRecord);
2780 if (!jsds_SyncFilter (rec, filter)) {
2781 PR_Free (rec);
2782 return NS_ERROR_FAILURE;
2785 if (gFilters) {
2786 PR_INSERT_BEFORE(&rec->links, &gFilters->links);
2787 } else {
2788 PR_INIT_CLIST(&rec->links);
2789 gFilters = rec;
2792 return NS_OK;
2795 NS_IMETHODIMP
2796 jsdService::RemoveFilter (jsdIFilter *filter)
2798 NS_ENSURE_ARG_POINTER(filter);
2799 FilterRecord *rec = jsds_FindFilter (filter);
2800 if (!rec)
2801 return NS_ERROR_INVALID_ARG;
2803 if (gFilters == rec) {
2804 gFilters = reinterpret_cast<FilterRecord *>
2805 (PR_NEXT_LINK(&rec->links));
2806 /* If we're the only filter left, null out the list head. */
2807 if (gFilters == rec)
2808 gFilters = nsnull;
2812 PR_REMOVE_LINK(&rec->links);
2813 jsds_FreeFilter (rec);
2815 return NS_OK;
2818 NS_IMETHODIMP
2819 jsdService::SwapFilters (jsdIFilter *filter_a, jsdIFilter *filter_b)
2821 NS_ENSURE_ARG_POINTER(filter_a);
2822 NS_ENSURE_ARG_POINTER(filter_b);
2824 FilterRecord *rec_a = jsds_FindFilter (filter_a);
2825 if (!rec_a)
2826 return NS_ERROR_INVALID_ARG;
2828 if (filter_a == filter_b) {
2829 /* just a refresh */
2830 if (!jsds_SyncFilter (rec_a, filter_a))
2831 return NS_ERROR_FAILURE;
2832 return NS_OK;
2835 FilterRecord *rec_b = jsds_FindFilter (filter_b);
2836 if (!rec_b) {
2837 /* filter_b is not in the list, replace filter_a with filter_b. */
2838 if (!jsds_SyncFilter (rec_a, filter_b))
2839 return NS_ERROR_FAILURE;
2840 } else {
2841 /* both filters are in the list, swap. */
2842 if (!jsds_SyncFilter (rec_a, filter_b))
2843 return NS_ERROR_FAILURE;
2844 if (!jsds_SyncFilter (rec_b, filter_a))
2845 return NS_ERROR_FAILURE;
2848 return NS_OK;
2851 NS_IMETHODIMP
2852 jsdService::EnumerateFilters (jsdIFilterEnumerator *enumerator)
2854 if (!gFilters)
2855 return NS_OK;
2857 FilterRecord *current = gFilters;
2858 do {
2859 jsds_SyncFilter (current, current->filterObject);
2860 /* SyncFilter failure would be bad, but what would we do about it? */
2861 if (enumerator) {
2862 nsresult rv = enumerator->EnumerateFilter (current->filterObject);
2863 if (NS_FAILED(rv))
2864 return rv;
2866 current = reinterpret_cast<FilterRecord *>
2867 (PR_NEXT_LINK (&current->links));
2868 } while (current != gFilters);
2870 return NS_OK;
2873 NS_IMETHODIMP
2874 jsdService::RefreshFilters ()
2876 return EnumerateFilters(nsnull);
2879 NS_IMETHODIMP
2880 jsdService::ClearFilters ()
2882 if (!gFilters)
2883 return NS_OK;
2885 FilterRecord *current = reinterpret_cast<FilterRecord *>
2886 (PR_NEXT_LINK (&gFilters->links));
2887 do {
2888 FilterRecord *next = reinterpret_cast<FilterRecord *>
2889 (PR_NEXT_LINK (&current->links));
2890 PR_REMOVE_AND_INIT_LINK(&current->links);
2891 jsds_FreeFilter(current);
2892 current = next;
2893 } while (current != gFilters);
2895 jsds_FreeFilter(current);
2896 gFilters = nsnull;
2898 return NS_OK;
2901 NS_IMETHODIMP
2902 jsdService::ClearAllBreakpoints (void)
2904 ASSERT_VALID_CONTEXT;
2906 JSD_LockScriptSubsystem(mCx);
2907 JSD_ClearAllExecutionHooks (mCx);
2908 JSD_UnlockScriptSubsystem(mCx);
2909 return NS_OK;
2912 NS_IMETHODIMP
2913 jsdService::WrapValue(jsdIValue **_rval)
2915 ASSERT_VALID_CONTEXT;
2917 nsresult rv;
2918 nsCOMPtr<nsIXPConnect> xpc = do_GetService (nsIXPConnect::GetCID(), &rv);
2919 if (NS_FAILED(rv))
2920 return rv;
2922 nsAXPCNativeCallContext *cc = nsnull;
2923 rv = xpc->GetCurrentNativeCallContext (&cc);
2924 if (NS_FAILED(rv))
2925 return rv;
2927 PRUint32 argc;
2928 rv = cc->GetArgc (&argc);
2929 if (NS_FAILED(rv))
2930 return rv;
2931 if (argc < 1)
2932 return NS_ERROR_INVALID_ARG;
2934 jsval *argv;
2935 rv = cc->GetArgvPtr (&argv);
2936 if (NS_FAILED(rv))
2937 return rv;
2939 return WrapJSValue(argv[0], _rval);
2942 NS_IMETHODIMP
2943 jsdService::WrapJSValue(const jsval &value, jsdIValue** _rval)
2945 JSDValue *jsdv = JSD_NewValue(mCx, value);
2946 if (!jsdv)
2947 return NS_ERROR_FAILURE;
2949 *_rval = jsdValue::FromPtr (mCx, jsdv);
2950 return NS_OK;
2954 NS_IMETHODIMP
2955 jsdService::EnterNestedEventLoop (jsdINestCallback *callback, PRUint32 *_rval)
2957 // Nesting event queues is a thing of the past. Now, we just spin the
2958 // current event loop.
2960 nsresult rv;
2961 nsCOMPtr<nsIJSContextStack>
2962 stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
2963 if (NS_FAILED(rv))
2964 return rv;
2965 PRUint32 nestLevel = ++mNestedLoopLevel;
2967 nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
2969 if (NS_SUCCEEDED(stack->Push(nsnull))) {
2970 if (callback) {
2971 Pause(nsnull);
2972 rv = callback->OnNest();
2973 UnPause(nsnull);
2976 while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) {
2977 if (!NS_ProcessNextEvent(thread))
2978 rv = NS_ERROR_UNEXPECTED;
2981 JSContext* cx;
2982 stack->Pop(&cx);
2983 NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
2985 else
2986 rv = NS_ERROR_FAILURE;
2988 NS_ASSERTION (mNestedLoopLevel <= nestLevel,
2989 "nested event didn't unwind properly");
2990 if (mNestedLoopLevel == nestLevel)
2991 --mNestedLoopLevel;
2993 *_rval = mNestedLoopLevel;
2994 return rv;
2997 NS_IMETHODIMP
2998 jsdService::ExitNestedEventLoop (PRUint32 *_rval)
3000 if (mNestedLoopLevel > 0)
3001 --mNestedLoopLevel;
3002 else
3003 return NS_ERROR_FAILURE;
3005 *_rval = mNestedLoopLevel;
3006 return NS_OK;
3009 /* hook attribute get/set functions */
3011 NS_IMETHODIMP
3012 jsdService::SetErrorHook (jsdIErrorHook *aHook)
3014 mErrorHook = aHook;
3016 /* if the debugger isn't initialized, that's all we can do for now. The
3017 * ActivateDebugger() method will do the rest when the coast is clear.
3019 if (!mCx || mPauseLevel)
3020 return NS_OK;
3022 if (aHook)
3023 JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
3024 else
3025 JSD_SetErrorReporter (mCx, NULL, NULL);
3027 return NS_OK;
3030 NS_IMETHODIMP
3031 jsdService::GetErrorHook (jsdIErrorHook **aHook)
3033 *aHook = mErrorHook;
3034 NS_IF_ADDREF(*aHook);
3036 return NS_OK;
3039 NS_IMETHODIMP
3040 jsdService::SetBreakpointHook (jsdIExecutionHook *aHook)
3042 mBreakpointHook = aHook;
3043 return NS_OK;
3046 NS_IMETHODIMP
3047 jsdService::GetBreakpointHook (jsdIExecutionHook **aHook)
3049 *aHook = mBreakpointHook;
3050 NS_IF_ADDREF(*aHook);
3052 return NS_OK;
3055 NS_IMETHODIMP
3056 jsdService::SetDebugHook (jsdIExecutionHook *aHook)
3058 mDebugHook = aHook;
3060 /* if the debugger isn't initialized, that's all we can do for now. The
3061 * ActivateDebugger() method will do the rest when the coast is clear.
3063 if (!mCx || mPauseLevel)
3064 return NS_OK;
3066 if (aHook)
3067 JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
3068 else
3069 JSD_ClearDebugBreakHook (mCx);
3071 return NS_OK;
3074 NS_IMETHODIMP
3075 jsdService::GetDebugHook (jsdIExecutionHook **aHook)
3077 *aHook = mDebugHook;
3078 NS_IF_ADDREF(*aHook);
3080 return NS_OK;
3083 NS_IMETHODIMP
3084 jsdService::SetDebuggerHook (jsdIExecutionHook *aHook)
3086 mDebuggerHook = aHook;
3088 /* if the debugger isn't initialized, that's all we can do for now. The
3089 * ActivateDebugger() method will do the rest when the coast is clear.
3091 if (!mCx || mPauseLevel)
3092 return NS_OK;
3094 if (aHook)
3095 JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
3096 else
3097 JSD_ClearDebuggerHook (mCx);
3099 return NS_OK;
3102 NS_IMETHODIMP
3103 jsdService::GetDebuggerHook (jsdIExecutionHook **aHook)
3105 *aHook = mDebuggerHook;
3106 NS_IF_ADDREF(*aHook);
3108 return NS_OK;
3111 NS_IMETHODIMP
3112 jsdService::SetInterruptHook (jsdIExecutionHook *aHook)
3114 mInterruptHook = aHook;
3116 /* if the debugger isn't initialized, that's all we can do for now. The
3117 * ActivateDebugger() method will do the rest when the coast is clear.
3119 if (!mCx || mPauseLevel)
3120 return NS_OK;
3122 if (aHook)
3123 JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
3124 else
3125 JSD_ClearInterruptHook (mCx);
3127 return NS_OK;
3130 NS_IMETHODIMP
3131 jsdService::GetInterruptHook (jsdIExecutionHook **aHook)
3133 *aHook = mInterruptHook;
3134 NS_IF_ADDREF(*aHook);
3136 return NS_OK;
3139 NS_IMETHODIMP
3140 jsdService::SetScriptHook (jsdIScriptHook *aHook)
3142 mScriptHook = aHook;
3144 /* if the debugger isn't initialized, that's all we can do for now. The
3145 * ActivateDebugger() method will do the rest when the coast is clear.
3147 if (!mCx || mPauseLevel)
3148 return NS_OK;
3150 if (aHook)
3151 JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
3152 /* we can't unset it if !aHook, because we still need to see script
3153 * deletes in order to Release the jsdIScripts held in JSDScript
3154 * private data. */
3155 return NS_OK;
3158 NS_IMETHODIMP
3159 jsdService::GetScriptHook (jsdIScriptHook **aHook)
3161 *aHook = mScriptHook;
3162 NS_IF_ADDREF(*aHook);
3164 return NS_OK;
3167 NS_IMETHODIMP
3168 jsdService::SetThrowHook (jsdIExecutionHook *aHook)
3170 mThrowHook = aHook;
3172 /* if the debugger isn't initialized, that's all we can do for now. The
3173 * ActivateDebugger() method will do the rest when the coast is clear.
3175 if (!mCx || mPauseLevel)
3176 return NS_OK;
3178 if (aHook)
3179 JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
3180 else
3181 JSD_ClearThrowHook (mCx);
3183 return NS_OK;
3186 NS_IMETHODIMP
3187 jsdService::GetThrowHook (jsdIExecutionHook **aHook)
3189 *aHook = mThrowHook;
3190 NS_IF_ADDREF(*aHook);
3192 return NS_OK;
3195 NS_IMETHODIMP
3196 jsdService::SetTopLevelHook (jsdICallHook *aHook)
3198 mTopLevelHook = aHook;
3200 /* if the debugger isn't initialized, that's all we can do for now. The
3201 * ActivateDebugger() method will do the rest when the coast is clear.
3203 if (!mCx || mPauseLevel)
3204 return NS_OK;
3206 if (aHook)
3207 JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
3208 else
3209 JSD_ClearTopLevelHook (mCx);
3211 return NS_OK;
3214 NS_IMETHODIMP
3215 jsdService::GetTopLevelHook (jsdICallHook **aHook)
3217 *aHook = mTopLevelHook;
3218 NS_IF_ADDREF(*aHook);
3220 return NS_OK;
3223 NS_IMETHODIMP
3224 jsdService::SetFunctionHook (jsdICallHook *aHook)
3226 mFunctionHook = aHook;
3228 /* if the debugger isn't initialized, that's all we can do for now. The
3229 * ActivateDebugger() method will do the rest when the coast is clear.
3231 if (!mCx || mPauseLevel)
3232 return NS_OK;
3234 if (aHook)
3235 JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
3236 else
3237 JSD_ClearFunctionHook (mCx);
3239 return NS_OK;
3242 NS_IMETHODIMP
3243 jsdService::GetFunctionHook (jsdICallHook **aHook)
3245 *aHook = mFunctionHook;
3246 NS_IF_ADDREF(*aHook);
3248 return NS_OK;
3251 /* virtual */
3252 jsdService::~jsdService()
3254 ClearFilters();
3255 mErrorHook = nsnull;
3256 mBreakpointHook = nsnull;
3257 mDebugHook = nsnull;
3258 mDebuggerHook = nsnull;
3259 mInterruptHook = nsnull;
3260 mScriptHook = nsnull;
3261 mThrowHook = nsnull;
3262 mTopLevelHook = nsnull;
3263 mFunctionHook = nsnull;
3264 gGCStatus = JSGC_END;
3265 Off();
3266 gJsds = nsnull;
3269 jsdService *
3270 jsdService::GetService ()
3272 if (!gJsds)
3273 gJsds = new jsdService();
3275 NS_IF_ADDREF(gJsds);
3276 return gJsds;
3279 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService, jsdService::GetService)
3281 /* app-start observer. turns on the debugger at app-start. this is inserted
3282 * and/or removed from the app-start category by the jsdService::initAtStartup
3283 * property.
3285 class jsdASObserver : public nsIObserver
3287 public:
3288 NS_DECL_ISUPPORTS
3289 NS_DECL_NSIOBSERVER
3291 jsdASObserver () {}
3294 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver, nsIObserver)
3296 NS_IMETHODIMP
3297 jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic,
3298 const PRUnichar *aData)
3300 nsresult rv;
3302 // Hmm. Why is the app-startup observer called multiple times?
3303 //NS_ASSERTION(!gJsds, "app startup observer called twice");
3304 nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
3305 if (NS_FAILED(rv))
3306 return rv;
3308 PRBool on;
3309 rv = jsds->GetIsOn(&on);
3310 if (NS_FAILED(rv) || on)
3311 return rv;
3313 nsCOMPtr<nsIJSRuntimeService> rts = do_GetService(NS_JSRT_CTRID, &rv);
3314 if (NS_FAILED(rv))
3315 return rv;
3317 JSRuntime *rt;
3318 rts->GetRuntime (&rt);
3319 if (NS_FAILED(rv))
3320 return rv;
3322 rv = jsds->ActivateDebugger(rt);
3323 if (NS_FAILED(rv))
3324 return rv;
3326 return NS_OK;
3329 NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
3330 NS_DEFINE_NAMED_CID(JSDSERVICE_CID);
3331 NS_DEFINE_NAMED_CID(JSDASO_CID);
3333 static const mozilla::Module::CIDEntry kJSDCIDs[] = {
3334 { &kJSDSERVICE_CID, false, NULL, jsdServiceConstructor },
3335 { &kJSDASO_CID, false, NULL, jsdASObserverConstructor },
3336 { NULL }
3339 static const mozilla::Module::ContractIDEntry kJSDContracts[] = {
3340 { jsdServiceCtrID, &kJSDSERVICE_CID },
3341 { jsdARObserverCtrID, &kJSDASO_CID },
3342 { NULL }
3345 static const mozilla::Module kJSDModule = {
3346 mozilla::Module::kVersion,
3347 kJSDCIDs,
3348 kJSDContracts
3351 NSMODULE_DEFN(JavaScript_Debugger) = &kJSDModule;
3353 /********************************************************************************
3354 ********************************************************************************
3355 * graveyard
3358 #if 0
3359 /* Thread States */
3360 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState, jsdIThreadState);
3362 NS_IMETHODIMP
3363 jsdThreadState::GetJSDContext(JSDContext **_rval)
3365 *_rval = mCx;
3366 return NS_OK;
3369 NS_IMETHODIMP
3370 jsdThreadState::GetJSDThreadState(JSDThreadState **_rval)
3372 *_rval = mThreadState;
3373 return NS_OK;
3376 NS_IMETHODIMP
3377 jsdThreadState::GetFrameCount (PRUint32 *_rval)
3379 *_rval = JSD_GetCountOfStackFrames (mCx, mThreadState);
3380 return NS_OK;
3383 NS_IMETHODIMP
3384 jsdThreadState::GetTopFrame (jsdIStackFrame **_rval)
3386 JSDStackFrameInfo *sfi = JSD_GetStackFrame (mCx, mThreadState);
3388 *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
3389 return NS_OK;
3392 NS_IMETHODIMP
3393 jsdThreadState::GetPendingException(jsdIValue **_rval)
3395 JSDValue *jsdv = JSD_GetException (mCx, mThreadState);
3397 *_rval = jsdValue::FromPtr (mCx, jsdv);
3398 return NS_OK;
3401 NS_IMETHODIMP
3402 jsdThreadState::SetPendingException(jsdIValue *aException)
3404 JSDValue *jsdv;
3406 nsresult rv = aException->GetJSDValue (&jsdv);
3407 if (NS_FAILED(rv))
3408 return NS_ERROR_FAILURE;
3410 if (!JSD_SetException (mCx, mThreadState, jsdv))
3411 return NS_ERROR_FAILURE;
3413 return NS_OK;
3416 #endif