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
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.
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 ***** */
45 #include "nsIXPConnect.h"
46 #include "nsIGenericFactory.h"
47 #include "nsIServiceManager.h"
48 #include "nsIScriptGlobalObject.h"
49 #include "nsIObserver.h"
50 #include "nsIObserverService.h"
51 #include "nsICategoryManager.h"
52 #include "nsIJSRuntimeService.h"
53 #include "nsIThreadInternal.h"
54 #include "nsThreadUtils.h"
57 #include "nsReadableUtils.h"
60 /* XXX DOM dependency */
61 #include "nsIScriptContext.h"
62 #include "nsIJSContextStack.h"
65 * defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
66 * script hook. This was a hack to avoid some js engine problems that should
67 * be fixed now (see Mozilla bug 77636).
69 #undef CAUTIOUS_SCRIPTHOOK
72 # define DEBUG_COUNT(name, count) \
73 { if ((count % 10) == 0) printf (name ": %i\n", count); }
74 # define DEBUG_CREATE(name, count) {count++; DEBUG_COUNT ("+++++ "name,count)}
75 # define DEBUG_DESTROY(name, count) {count--; DEBUG_COUNT ("----- "name,count)}
77 # define DEBUG_CREATE(name, count)
78 # define DEBUG_DESTROY(name, count)
81 #define ASSERT_VALID_CONTEXT { if (!mCx) return NS_ERROR_NOT_AVAILABLE; }
82 #define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; }
84 #define JSDSERVICE_CID \
85 { /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */ \
89 {0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \
93 { /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */ \
97 {0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \
100 #define JSDS_MAJOR_VERSION 1
101 #define JSDS_MINOR_VERSION 2
103 #define NS_CATMAN_CTRID "@mozilla.org/categorymanager;1"
104 #define NS_JSRT_CTRID "@mozilla.org/js/xpc/RuntimeService;1"
106 #define AUTOREG_CATEGORY "xpcom-autoregistration"
107 #define APPSTART_CATEGORY "app-startup"
108 #define JSD_AUTOREG_ENTRY "JSDebugger Startup Observer"
109 #define JSD_STARTUP_ENTRY "JSDebugger Startup Observer"
112 jsds_GCCallbackProc (JSContext
*cx
, JSGCStatus status
);
114 /*******************************************************************************
116 ******************************************************************************/
118 const char implementationString
[] = "Mozilla JavaScript Debugger Service";
120 const char jsdServiceCtrID
[] = "@mozilla.org/js/jsd/debugger-service;1";
121 const char jsdARObserverCtrID
[] = "@mozilla.org/js/jsd/app-start-observer;2";
122 const char jsdASObserverCtrID
[] = "service,@mozilla.org/js/jsd/app-start-observer;2";
125 PRUint32 gScriptCount
= 0;
126 PRUint32 gValueCount
= 0;
127 PRUint32 gPropertyCount
= 0;
128 PRUint32 gContextCount
= 0;
129 PRUint32 gFrameCount
= 0;
132 static jsdService
*gJsds
= 0;
133 static JSGCCallback gLastGCProc
= jsds_GCCallbackProc
;
134 static JSGCStatus gGCStatus
= JSGC_END
;
136 static struct DeadScript
{
140 } *gDeadScripts
= nsnull
;
150 static struct FilterRecord
{
152 jsdIFilter
*filterObject
;
154 nsCString urlPattern
;
155 PatternType patternType
;
158 } *gFilters
= nsnull
;
160 static struct LiveEphemeral
*gLiveValues
= nsnull
;
161 static struct LiveEphemeral
*gLiveProperties
= nsnull
;
162 static struct LiveEphemeral
*gLiveContexts
= nsnull
;
163 static struct LiveEphemeral
*gLiveStackFrames
= nsnull
;
165 /*******************************************************************************
166 * utility functions for ephemeral lists
167 *******************************************************************************/
168 already_AddRefed
<jsdIEphemeral
>
169 jsds_FindEphemeral (LiveEphemeral
**listHead
, void *key
)
174 LiveEphemeral
*lv_record
=
175 reinterpret_cast<LiveEphemeral
*>
176 (PR_NEXT_LINK(&(*listHead
)->links
));
179 if (lv_record
->key
== key
)
181 NS_IF_ADDREF(lv_record
->value
);
182 return lv_record
->value
;
184 lv_record
= reinterpret_cast<LiveEphemeral
*>
185 (PR_NEXT_LINK(&lv_record
->links
));
187 while (lv_record
!= *listHead
);
193 jsds_InvalidateAllEphemerals (LiveEphemeral
**listHead
)
195 LiveEphemeral
*lv_record
=
196 reinterpret_cast<LiveEphemeral
*>
197 (PR_NEXT_LINK(&(*listHead
)->links
));
200 LiveEphemeral
*next
=
201 reinterpret_cast<LiveEphemeral
*>
202 (PR_NEXT_LINK(&lv_record
->links
));
203 lv_record
->value
->Invalidate();
209 jsds_InsertEphemeral (LiveEphemeral
**listHead
, LiveEphemeral
*item
)
212 /* if the list exists, add to it */
213 PR_APPEND_LINK(&item
->links
, &(*listHead
)->links
);
215 /* otherwise create the list */
216 PR_INIT_CLIST(&item
->links
);
222 jsds_RemoveEphemeral (LiveEphemeral
**listHead
, LiveEphemeral
*item
)
224 LiveEphemeral
*next
= reinterpret_cast<LiveEphemeral
*>
225 (PR_NEXT_LINK(&item
->links
));
229 /* if the current item is also the next item, we're the only element,
230 * null out the list head */
231 NS_ASSERTION (*listHead
== item
,
232 "How could we not be the head of a one item list?");
235 else if (item
== *listHead
)
237 /* otherwise, if we're currently the list head, change it */
241 PR_REMOVE_AND_INIT_LINK(&item
->links
);
244 /*******************************************************************************
245 * utility functions for filters
246 *******************************************************************************/
248 jsds_FreeFilter (FilterRecord
*filter
)
250 NS_IF_RELEASE (filter
->filterObject
);
254 /* copies appropriate |filter| attributes into |rec|.
255 * False return indicates failure, the contents of |rec| will not be changed.
258 jsds_SyncFilter (FilterRecord
*rec
, jsdIFilter
*filter
)
260 NS_ASSERTION (rec
, "jsds_SyncFilter without rec");
261 NS_ASSERTION (filter
, "jsds_SyncFilter without filter");
263 JSObject
*glob_proper
= nsnull
;
264 nsCOMPtr
<nsISupports
> glob
;
265 nsresult rv
= filter
->GetGlobalObject(getter_AddRefs(glob
));
269 nsCOMPtr
<nsIScriptGlobalObject
> nsiglob
= do_QueryInterface(glob
);
271 glob_proper
= nsiglob
->GetGlobalJSObject();
275 rv
= filter
->GetStartLine(&startLine
);
280 rv
= filter
->GetStartLine(&endLine
);
284 nsCAutoString urlPattern
;
285 rv
= filter
->GetUrlPattern (urlPattern
);
289 PRUint32 len
= urlPattern
.Length();
291 if (urlPattern
[0] == '*') {
292 /* pattern starts with a *, shift all chars once to the left,
293 * including the trailing null. */
294 urlPattern
= Substring(urlPattern
, 1, len
);
296 if (urlPattern
[len
- 2] == '*') {
297 /* pattern is in the format "*foo*", overwrite the final * with
299 urlPattern
.Truncate(len
- 2);
300 rec
->patternType
= ptContains
;
302 /* pattern is in the format "*foo", just make a note of the
304 rec
->patternType
= ptEndsWith
;
306 } else if (urlPattern
[len
- 1] == '*') {
307 /* pattern is in the format "foo*", overwrite the final * with a
309 urlPattern
.Truncate(len
- 1);
310 rec
->patternType
= ptStartsWith
;
312 /* pattern is in the format "foo". */
313 rec
->patternType
= ptEquals
;
316 rec
->patternType
= ptIgnore
;
319 /* we got everything we need without failing, now copy it into rec. */
321 if (rec
->filterObject
!= filter
) {
322 NS_IF_RELEASE(rec
->filterObject
);
324 rec
->filterObject
= filter
;
327 rec
->glob
= glob_proper
;
329 rec
->startLine
= startLine
;
330 rec
->endLine
= endLine
;
332 rec
->urlPattern
= urlPattern
;
339 jsds_FindFilter (jsdIFilter
*filter
)
344 FilterRecord
*current
= gFilters
;
347 if (current
->filterObject
== filter
)
349 current
= reinterpret_cast<FilterRecord
*>
350 (PR_NEXT_LINK(¤t
->links
));
351 } while (current
!= gFilters
);
356 /* returns true if the hook should be executed. */
358 jsds_FilterHook (JSDContext
*jsdc
, JSDThreadState
*state
)
360 JSContext
*cx
= JSD_GetJSContext (jsdc
, state
);
361 void *glob
= static_cast<void *>(JS_GetGlobalObject (cx
));
364 NS_WARNING("No global in threadstate");
368 JSDStackFrameInfo
*frame
= JSD_GetStackFrame (jsdc
, state
);
371 NS_WARNING("No frame in threadstate");
375 JSDScript
*script
= JSD_GetScriptForStackFrame (jsdc
, state
, frame
);
379 jsuint pc
= JSD_GetPCForStackFrame (jsdc
, state
, frame
);
381 nsDependentCString
url(JSD_GetScriptFilename (jsdc
, script
));
383 NS_WARNING ("Script with no filename");
390 PRUint32 currentLine
= JSD_GetClosestLine (jsdc
, script
, pc
);
392 FilterRecord
*currentFilter
= gFilters
;
395 nsresult rv
= currentFilter
->filterObject
->GetFlags(&flags
);
396 NS_ASSERTION(NS_SUCCEEDED(rv
), "Error getting flags for filter");
397 if (flags
& jsdIFilter::FLAG_ENABLED
) {
398 /* if there is no glob, or the globs match */
399 if ((!currentFilter
->glob
|| currentFilter
->glob
== glob
) &&
400 /* and there is no start line, or the start line is before
401 * or equal to the current */
402 (!currentFilter
->startLine
||
403 currentFilter
->startLine
<= currentLine
) &&
404 /* and there is no end line, or the end line is after
405 * or equal to the current */
406 (!currentFilter
->endLine
||
407 currentFilter
->endLine
>= currentLine
)) {
408 /* then we're going to have to compare the url. */
409 if (currentFilter
->patternType
== ptIgnore
)
410 return !!(flags
& jsdIFilter::FLAG_PASS
);
414 nsCString urlPattern
= currentFilter
->urlPattern
;
415 PRUint32 patternLength
= urlPattern
.Length();
416 if (len
>= patternLength
) {
417 switch (currentFilter
->patternType
) {
419 if (urlPattern
.Equals(url
))
420 return !!(flags
& jsdIFilter::FLAG_PASS
);
423 if (urlPattern
.Equals(Substring(url
, 0, patternLength
)))
424 return !!(flags
& jsdIFilter::FLAG_PASS
);
427 if (urlPattern
.Equals(Substring(url
, len
- patternLength
)))
428 return !!(flags
& jsdIFilter::FLAG_PASS
);
432 nsACString::const_iterator start
, end
;
433 url
.BeginReading(start
);
435 if (FindInReadable(currentFilter
->urlPattern
, start
, end
))
436 return !!(flags
& jsdIFilter::FLAG_PASS
);
440 NS_ASSERTION(0, "Invalid pattern type");
445 currentFilter
= reinterpret_cast<FilterRecord
*>
446 (PR_NEXT_LINK(¤tFilter
->links
));
447 } while (currentFilter
!= gFilters
);
453 /*******************************************************************************
455 *******************************************************************************/
458 jsds_NotifyPendingDeadScripts (JSContext
*cx
)
460 #ifdef CAUTIOUS_SCRIPTHOOK
461 JSRuntime
*rt
= JS_GetRuntime(cx
);
463 jsdService
*jsds
= gJsds
;
465 nsCOMPtr
<jsdIScriptHook
> hook
;
468 jsds
->GetScriptHook (getter_AddRefs(hook
));
472 DeadScript
*deadScripts
= gDeadScripts
;
473 gDeadScripts
= nsnull
;
474 while (deadScripts
) {
475 DeadScript
*ds
= deadScripts
;
476 /* get next deleted script */
477 deadScripts
= reinterpret_cast<DeadScript
*>
478 (PR_NEXT_LINK(&ds
->links
));
479 if (deadScripts
== ds
)
480 deadScripts
= nsnull
;
484 /* tell the user this script has been destroyed */
485 #ifdef CAUTIOUS_SCRIPTHOOK
488 hook
->OnScriptDestroyed (ds
->script
);
489 #ifdef CAUTIOUS_SCRIPTHOOK
494 /* take it out of the circular list */
495 PR_REMOVE_LINK(&ds
->links
);
497 /* addref came from the FromPtr call in jsds_ScriptHookProc */
498 NS_RELEASE(ds
->script
);
499 /* free the struct! */
504 jsds
->UnPause(nsnull
);
510 jsds_GCCallbackProc (JSContext
*cx
, JSGCStatus status
)
513 printf ("new gc status is %i\n", status
);
515 if (status
== JSGC_END
) {
516 /* just to guard against reentering. */
517 gGCStatus
= JSGC_BEGIN
;
519 jsds_NotifyPendingDeadScripts (cx
);
524 return gLastGCProc (cx
, status
);
530 jsds_ErrorHookProc (JSDContext
*jsdc
, JSContext
*cx
, const char *message
,
531 JSErrorReport
*report
, void *callerdata
)
533 static PRBool running
= PR_FALSE
;
535 nsCOMPtr
<jsdIErrorHook
> hook
;
536 gJsds
->GetErrorHook(getter_AddRefs(hook
));
538 return JSD_ERROR_REPORTER_PASS_ALONG
;
541 return JSD_ERROR_REPORTER_PASS_ALONG
;
545 nsCOMPtr
<jsdIValue
> val
;
546 if (JS_IsExceptionPending(cx
)) {
548 JS_GetPendingException(cx
, &jv
);
549 JSDValue
*jsdv
= JSD_NewValue (jsdc
, jv
);
550 val
= getter_AddRefs(jsdValue::FromPtr(jsdc
, jsdv
));
553 nsCAutoString fileName
;
560 fileName
.Assign(report
->filename
);
561 line
= report
->lineno
;
562 pos
= report
->tokenptr
- report
->linebuf
;
563 flags
= report
->flags
;
564 errnum
= report
->errorNumber
;
574 gJsds
->Pause(nsnull
);
575 hook
->OnError (nsDependentCString(message
), fileName
, line
, pos
, flags
, errnum
, val
, &rval
);
576 gJsds
->UnPause(nsnull
);
580 return JSD_ERROR_REPORTER_DEBUG
;
582 return JSD_ERROR_REPORTER_PASS_ALONG
;
586 jsds_CallHookProc (JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
,
587 uintN type
, void* callerdata
)
589 nsCOMPtr
<jsdICallHook
> hook
;
593 case JSD_HOOK_TOPLEVEL_START
:
594 case JSD_HOOK_TOPLEVEL_END
:
595 gJsds
->GetTopLevelHook(getter_AddRefs(hook
));
598 case JSD_HOOK_FUNCTION_CALL
:
599 case JSD_HOOK_FUNCTION_RETURN
:
600 gJsds
->GetFunctionHook(getter_AddRefs(hook
));
604 NS_ASSERTION (0, "Unknown hook type.");
610 if (!jsds_FilterHook (jsdc
, jsdthreadstate
))
613 JSDStackFrameInfo
*native_frame
= JSD_GetStackFrame (jsdc
, jsdthreadstate
);
614 nsCOMPtr
<jsdIStackFrame
> frame
=
615 getter_AddRefs(jsdStackFrame::FromPtr(jsdc
, jsdthreadstate
,
617 gJsds
->Pause(nsnull
);
618 hook
->OnCall(frame
, type
);
619 gJsds
->UnPause(nsnull
);
620 jsdStackFrame::InvalidateAll();
626 jsds_ExecutionHookProc (JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
,
627 uintN type
, void* callerdata
, jsval
* rval
)
629 nsCOMPtr
<jsdIExecutionHook
> hook(0);
630 PRUint32 hook_rv
= JSD_HOOK_RETURN_CONTINUE
;
631 nsCOMPtr
<jsdIValue
> js_rv
;
635 case JSD_HOOK_INTERRUPTED
:
636 gJsds
->GetInterruptHook(getter_AddRefs(hook
));
638 case JSD_HOOK_DEBUG_REQUESTED
:
639 gJsds
->GetDebugHook(getter_AddRefs(hook
));
641 case JSD_HOOK_DEBUGGER_KEYWORD
:
642 gJsds
->GetDebuggerHook(getter_AddRefs(hook
));
644 case JSD_HOOK_BREAKPOINT
:
646 /* we can't pause breakpoints the way we pause the other
647 * execution hooks (at least, not easily.) Instead we bail
648 * here if the service is paused. */
650 gJsds
->GetPauseDepth(&level
);
652 gJsds
->GetBreakpointHook(getter_AddRefs(hook
));
657 hook_rv
= JSD_HOOK_RETURN_CONTINUE_THROW
;
658 gJsds
->GetThrowHook(getter_AddRefs(hook
));
660 JSDValue
*jsdv
= JSD_GetException (jsdc
, jsdthreadstate
);
661 js_rv
= getter_AddRefs(jsdValue::FromPtr (jsdc
, jsdv
));
666 NS_ASSERTION (0, "Unknown hook type.");
672 if (!jsds_FilterHook (jsdc
, jsdthreadstate
))
673 return JSD_HOOK_RETURN_CONTINUE
;
675 JSDStackFrameInfo
*native_frame
= JSD_GetStackFrame (jsdc
, jsdthreadstate
);
676 nsCOMPtr
<jsdIStackFrame
> frame
=
677 getter_AddRefs(jsdStackFrame::FromPtr(jsdc
, jsdthreadstate
,
679 gJsds
->Pause(nsnull
);
680 jsdIValue
*inout_rv
= js_rv
;
681 NS_IF_ADDREF(inout_rv
);
682 hook
->OnExecute (frame
, type
, &inout_rv
, &hook_rv
);
684 NS_IF_RELEASE(inout_rv
);
685 gJsds
->UnPause(nsnull
);
686 jsdStackFrame::InvalidateAll();
688 if (hook_rv
== JSD_HOOK_RETURN_RET_WITH_VAL
||
689 hook_rv
== JSD_HOOK_RETURN_THROW_WITH_VAL
) {
693 if (NS_SUCCEEDED(js_rv
->GetJSDValue (&jsdv
)))
694 *rval
= JSD_GetValueWrappedJSVal(jsdc
, jsdv
);
702 jsds_ScriptHookProc (JSDContext
* jsdc
, JSDScript
* jsdscript
, JSBool creating
,
705 #ifdef CAUTIOUS_SCRIPTHOOK
706 JSContext
*cx
= JSD_GetDefaultJSContext(jsdc
);
707 JSRuntime
*rt
= JS_GetRuntime(cx
);
711 nsCOMPtr
<jsdIScriptHook
> hook
;
712 gJsds
->GetScriptHook(getter_AddRefs(hook
));
714 /* a script is being created */
716 /* nobody cares, just exit */
720 nsCOMPtr
<jsdIScript
> script
=
721 getter_AddRefs(jsdScript::FromPtr(jsdc
, jsdscript
));
722 #ifdef CAUTIOUS_SCRIPTHOOK
725 gJsds
->Pause(nsnull
);
726 hook
->OnScriptCreated (script
);
727 gJsds
->UnPause(nsnull
);
728 #ifdef CAUTIOUS_SCRIPTHOOK
732 /* a script is being destroyed. even if there is no registered hook
733 * we'll still need to invalidate the jsdIScript record, in order
734 * to remove the reference held in the JSDScript private data. */
735 nsCOMPtr
<jsdIScript
> jsdis
=
736 static_cast<jsdIScript
*>(JSD_GetScriptPrivate(jsdscript
));
742 if (gGCStatus
== JSGC_END
) {
743 nsCOMPtr
<jsdIScriptHook
> hook
;
744 gJsds
->GetScriptHook(getter_AddRefs(hook
));
748 /* if GC *isn't* running, we can tell the user about the script
750 #ifdef CAUTIOUS_SCRIPTHOOK
754 gJsds
->Pause(nsnull
);
755 hook
->OnScriptDestroyed (jsdis
);
756 gJsds
->UnPause(nsnull
);
757 #ifdef CAUTIOUS_SCRIPTHOOK
761 /* if a GC *is* running, we've got to wait until it's done before
762 * we can execute any JS, so we queue the notification in a PRCList
763 * until GC tells us it's done. See jsds_GCCallbackProc(). */
764 DeadScript
*ds
= PR_NEW(DeadScript
);
766 return; /* NS_ERROR_OUT_OF_MEMORY */
770 NS_ADDREF(ds
->script
);
772 /* if the queue exists, add to it */
773 PR_APPEND_LINK(&ds
->links
, &gDeadScripts
->links
);
775 /* otherwise create the queue */
776 PR_INIT_CLIST(&ds
->links
);
783 /*******************************************************************************
784 * reflected jsd data structures
785 *******************************************************************************/
789 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral);
792 jsdContext::GetJSDContext(JSDContext **_rval)
800 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject
, jsdIObject
)
803 jsdObject::GetJSDContext(JSDContext
**_rval
)
810 jsdObject::GetJSDObject(JSDObject
**_rval
)
817 jsdObject::GetCreatorURL(nsACString
&_rval
)
819 _rval
.Assign(JSD_GetObjectNewURL(mCx
, mObject
));
824 jsdObject::GetCreatorLine(PRUint32
*_rval
)
826 *_rval
= JSD_GetObjectNewLineNumber(mCx
, mObject
);
831 jsdObject::GetConstructorURL(nsACString
&_rval
)
833 _rval
.Assign(JSD_GetObjectConstructorURL(mCx
, mObject
));
838 jsdObject::GetConstructorLine(PRUint32
*_rval
)
840 *_rval
= JSD_GetObjectConstructorLineNumber(mCx
, mObject
);
845 jsdObject::GetValue(jsdIValue
**_rval
)
847 JSDValue
*jsdv
= JSD_GetValueForObject (mCx
, mObject
);
849 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
854 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty
, jsdIProperty
, jsdIEphemeral
)
856 jsdProperty::jsdProperty (JSDContext
*aCx
, JSDProperty
*aProperty
) :
857 mCx(aCx
), mProperty(aProperty
)
859 DEBUG_CREATE ("jsdProperty", gPropertyCount
);
860 mValid
= (aCx
&& aProperty
);
861 mLiveListEntry
.value
= this;
862 jsds_InsertEphemeral (&gLiveProperties
, &mLiveListEntry
);
865 jsdProperty::~jsdProperty ()
867 DEBUG_DESTROY ("jsdProperty", gPropertyCount
);
873 jsdProperty::Invalidate()
875 ASSERT_VALID_EPHEMERAL
;
877 jsds_RemoveEphemeral (&gLiveProperties
, &mLiveListEntry
);
878 JSD_DropProperty (mCx
, mProperty
);
883 jsdProperty::InvalidateAll()
886 jsds_InvalidateAllEphemerals (&gLiveProperties
);
890 jsdProperty::GetJSDContext(JSDContext
**_rval
)
897 jsdProperty::GetJSDProperty(JSDProperty
**_rval
)
904 jsdProperty::GetIsValid(PRBool
*_rval
)
911 jsdProperty::GetAlias(jsdIValue
**_rval
)
913 JSDValue
*jsdv
= JSD_GetPropertyValue (mCx
, mProperty
);
915 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
920 jsdProperty::GetFlags(PRUint32
*_rval
)
922 *_rval
= JSD_GetPropertyFlags (mCx
, mProperty
);
927 jsdProperty::GetName(jsdIValue
**_rval
)
929 JSDValue
*jsdv
= JSD_GetPropertyName (mCx
, mProperty
);
931 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
936 jsdProperty::GetValue(jsdIValue
**_rval
)
938 JSDValue
*jsdv
= JSD_GetPropertyValue (mCx
, mProperty
);
940 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
945 jsdProperty::GetVarArgSlot(PRUint32
*_rval
)
947 *_rval
= JSD_GetPropertyVarArgSlot (mCx
, mProperty
);
952 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript
, jsdIScript
, jsdIEphemeral
)
954 jsdScript::jsdScript (JSDContext
*aCx
, JSDScript
*aScript
) : mValid(PR_FALSE
),
965 DEBUG_CREATE ("jsdScript", gScriptCount
);
968 /* copy the script's information now, so we have it later, when it
970 JSD_LockScriptSubsystem(mCx
);
971 mFileName
= new nsCString(JSD_GetScriptFilename(mCx
, mScript
));
973 new nsCString(JSD_GetScriptFunctionName(mCx
, mScript
));
974 mBaseLineNumber
= JSD_GetScriptBaseLineNumber(mCx
, mScript
);
975 mLineExtent
= JSD_GetScriptLineExtent(mCx
, mScript
);
976 mFirstPC
= JSD_GetClosestPC(mCx
, mScript
, 0);
977 JSD_UnlockScriptSubsystem(mCx
);
983 jsdScript::~jsdScript ()
985 DEBUG_DESTROY ("jsdScript", gScriptCount
);
989 delete mFunctionName
;
994 /* Invalidate() needs to be called to release an owning reference to
995 * ourselves, so if we got here without being invalidated, something
996 * has gone wrong with our ref count. */
997 NS_ASSERTION (!mValid
, "Script destroyed without being invalidated.");
1001 * This method populates a line <-> pc map for a pretty printed version of this
1002 * script. It does this by decompiling, and then recompiling the script. The
1003 * resulting script is scanned for the line map, and then left as GC fodder.
1006 jsdScript::CreatePPLineMap()
1008 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
1009 JSAutoRequest
ar(cx
);
1010 JSObject
*obj
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
1011 JSFunction
*fun
= JSD_GetJSFunction (mCx
, mScript
);
1014 PRBool scriptOwner
= PR_FALSE
;
1017 if (fun
->nargs
> 12)
1019 JSString
*jsstr
= JS_DecompileFunctionBody (cx
, fun
, 4);
1023 const char *argnames
[] = {"arg1", "arg2", "arg3", "arg4",
1024 "arg5", "arg6", "arg7", "arg8",
1025 "arg9", "arg10", "arg11", "arg12" };
1026 fun
= JS_CompileUCFunction (cx
, obj
, "ppfun", fun
->nargs
, argnames
,
1027 JS_GetStringChars(jsstr
),
1028 JS_GetStringLength(jsstr
),
1029 "x-jsd:ppbuffer?type=function", 3);
1030 if (!fun
|| !(script
= JS_GetFunctionScript(cx
, fun
)))
1034 JSString
*jsstr
= JS_DecompileScript (cx
, JSD_GetJSScript(mCx
, mScript
),
1039 script
= JS_CompileUCScript (cx
, obj
,
1040 JS_GetStringChars(jsstr
),
1041 JS_GetStringLength(jsstr
),
1042 "x-jsd:ppbuffer?type=script", 1);
1045 scriptOwner
= PR_TRUE
;
1049 PRUint32 scriptExtent
= JS_GetScriptLineExtent (cx
, script
);
1050 jsbytecode
* firstPC
= JS_LineNumberToPC (cx
, script
, 0);
1051 /* allocate worst case size of map (number of lines in script + 1
1052 * for our 0 record), we'll shrink it with a realloc later. */
1053 PCMapEntry
*lineMap
=
1054 static_cast<PCMapEntry
*>
1055 (PR_Malloc((scriptExtent
+ 1) * sizeof (PCMapEntry
)));
1056 PRUint32 lineMapSize
= 0;
1059 for (PRUint32 line
= baseLine
; line
< scriptExtent
+ baseLine
; ++line
) {
1060 jsbytecode
* pc
= JS_LineNumberToPC (cx
, script
, line
);
1061 if (line
== JS_PCToLineNumber (cx
, script
, pc
)) {
1062 lineMap
[lineMapSize
].line
= line
;
1063 lineMap
[lineMapSize
].pc
= pc
- firstPC
;
1067 if (scriptExtent
!= lineMapSize
) {
1069 static_cast<PCMapEntry
*>
1070 (PR_Realloc(mPPLineMap
= lineMap
,
1071 lineMapSize
* sizeof(PCMapEntry
)));
1073 PR_Free(mPPLineMap
);
1080 JS_DestroyScript (cx
, script
);
1082 mPCMapSize
= lineMapSize
;
1083 return mPPLineMap
= lineMap
;
1087 jsdScript::PPPcToLine (PRUint32 aPC
)
1089 if (!mPPLineMap
&& !CreatePPLineMap())
1092 for (i
= 1; i
< mPCMapSize
; ++i
) {
1093 if (mPPLineMap
[i
].pc
> aPC
)
1094 return mPPLineMap
[i
- 1].line
;
1097 return mPPLineMap
[mPCMapSize
- 1].line
;
1101 jsdScript::PPLineToPc (PRUint32 aLine
)
1103 if (!mPPLineMap
&& !CreatePPLineMap())
1106 for (i
= 1; i
< mPCMapSize
; ++i
) {
1107 if (mPPLineMap
[i
].line
> aLine
)
1108 return mPPLineMap
[i
- 1].pc
;
1111 return mPPLineMap
[mPCMapSize
- 1].pc
;
1115 jsdScript::GetJSDContext(JSDContext
**_rval
)
1117 ASSERT_VALID_EPHEMERAL
;
1123 jsdScript::GetJSDScript(JSDScript
**_rval
)
1125 ASSERT_VALID_EPHEMERAL
;
1131 jsdScript::GetVersion (PRInt32
*_rval
)
1133 ASSERT_VALID_EPHEMERAL
;
1134 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
1135 JSScript
*script
= JSD_GetJSScript(mCx
, mScript
);
1136 *_rval
= static_cast<PRInt32
>(JS_GetScriptVersion(cx
, script
));
1141 jsdScript::GetTag(PRUint32
*_rval
)
1144 mTag
= ++jsdScript::LastTag
;
1151 jsdScript::Invalidate()
1153 ASSERT_VALID_EPHEMERAL
;
1156 /* release the addref we do in FromPtr */
1157 jsdIScript
*script
= static_cast<jsdIScript
*>
1158 (JSD_GetScriptPrivate(mScript
));
1159 NS_ASSERTION (script
== this, "That's not my script!");
1161 JSD_SetScriptPrivate(mScript
, NULL
);
1166 jsdScript::InvalidateAll ()
1169 if (NS_FAILED(gJsds
->GetJSDContext (&cx
)))
1173 JSDScript
*iter
= NULL
;
1175 JSD_LockScriptSubsystem(cx
);
1176 while((script
= JSD_IterateScripts(cx
, &iter
)) != NULL
) {
1177 nsCOMPtr
<jsdIScript
> jsdis
=
1178 static_cast<jsdIScript
*>(JSD_GetScriptPrivate(script
));
1180 jsdis
->Invalidate();
1182 JSD_UnlockScriptSubsystem(cx
);
1186 jsdScript::GetIsValid(PRBool
*_rval
)
1193 jsdScript::SetFlags(PRUint32 flags
)
1195 ASSERT_VALID_EPHEMERAL
;
1196 JSD_SetScriptFlags(mCx
, mScript
, flags
);
1201 jsdScript::GetFlags(PRUint32
*_rval
)
1203 ASSERT_VALID_EPHEMERAL
;
1204 *_rval
= JSD_GetScriptFlags(mCx
, mScript
);
1209 jsdScript::GetFileName(nsACString
&_rval
)
1211 _rval
.Assign(*mFileName
);
1216 jsdScript::GetFunctionName(nsACString
&_rval
)
1218 _rval
.Assign(*mFunctionName
);
1223 jsdScript::GetFunctionObject(jsdIValue
**_rval
)
1225 JSFunction
*fun
= JSD_GetJSFunction(mCx
, mScript
);
1227 return NS_ERROR_NOT_AVAILABLE
;
1229 JSObject
*obj
= JS_GetFunctionObject(fun
);
1231 return NS_ERROR_FAILURE
;
1234 if (NS_FAILED(gJsds
->GetJSDContext (&cx
)))
1235 return NS_ERROR_NOT_INITIALIZED
;
1237 JSDValue
*jsdv
= JSD_NewValue(cx
, OBJECT_TO_JSVAL(obj
));
1239 return NS_ERROR_OUT_OF_MEMORY
;
1241 *_rval
= jsdValue::FromPtr(cx
, jsdv
);
1243 JSD_DropValue(cx
, jsdv
);
1244 return NS_ERROR_OUT_OF_MEMORY
;
1251 jsdScript::GetFunctionSource(nsAString
& aFunctionSource
)
1253 ASSERT_VALID_EPHEMERAL
;
1254 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
1256 NS_WARNING("No default context !?");
1257 return NS_ERROR_FAILURE
;
1259 JSFunction
*fun
= JSD_GetJSFunction (mCx
, mScript
);
1261 JSAutoRequest
ar(cx
);
1265 jsstr
= JS_DecompileFunction (cx
, fun
, 4);
1267 JSScript
*script
= JSD_GetJSScript (mCx
, mScript
);
1268 jsstr
= JS_DecompileScript (cx
, script
, "ppscript", 4);
1271 return NS_ERROR_FAILURE
;
1275 reinterpret_cast<PRUnichar
*>(JS_GetStringChars(jsstr
)),
1276 JS_GetStringLength(jsstr
));
1281 jsdScript::GetBaseLineNumber(PRUint32
*_rval
)
1283 *_rval
= mBaseLineNumber
;
1288 jsdScript::GetLineExtent(PRUint32
*_rval
)
1290 *_rval
= mLineExtent
;
1295 jsdScript::GetCallCount(PRUint32
*_rval
)
1297 ASSERT_VALID_EPHEMERAL
;
1298 *_rval
= JSD_GetScriptCallCount (mCx
, mScript
);
1303 jsdScript::GetMaxRecurseDepth(PRUint32
*_rval
)
1305 ASSERT_VALID_EPHEMERAL
;
1306 *_rval
= JSD_GetScriptMaxRecurseDepth (mCx
, mScript
);
1311 jsdScript::GetMinExecutionTime(double *_rval
)
1313 ASSERT_VALID_EPHEMERAL
;
1314 *_rval
= JSD_GetScriptMinExecutionTime (mCx
, mScript
);
1319 jsdScript::GetMaxExecutionTime(double *_rval
)
1321 ASSERT_VALID_EPHEMERAL
;
1322 *_rval
= JSD_GetScriptMaxExecutionTime (mCx
, mScript
);
1327 jsdScript::GetTotalExecutionTime(double *_rval
)
1329 ASSERT_VALID_EPHEMERAL
;
1330 *_rval
= JSD_GetScriptTotalExecutionTime (mCx
, mScript
);
1335 jsdScript::GetMinOwnExecutionTime(double *_rval
)
1337 ASSERT_VALID_EPHEMERAL
;
1338 *_rval
= JSD_GetScriptMinOwnExecutionTime (mCx
, mScript
);
1343 jsdScript::GetMaxOwnExecutionTime(double *_rval
)
1345 ASSERT_VALID_EPHEMERAL
;
1346 *_rval
= JSD_GetScriptMaxOwnExecutionTime (mCx
, mScript
);
1351 jsdScript::GetTotalOwnExecutionTime(double *_rval
)
1353 ASSERT_VALID_EPHEMERAL
;
1354 *_rval
= JSD_GetScriptTotalOwnExecutionTime (mCx
, mScript
);
1359 jsdScript::ClearProfileData()
1361 ASSERT_VALID_EPHEMERAL
;
1362 JSD_ClearScriptProfileData(mCx
, mScript
);
1367 jsdScript::PcToLine(PRUint32 aPC
, PRUint32 aPcmap
, PRUint32
*_rval
)
1369 ASSERT_VALID_EPHEMERAL
;
1370 if (aPcmap
== PCMAP_SOURCETEXT
) {
1371 *_rval
= JSD_GetClosestLine (mCx
, mScript
, mFirstPC
+ aPC
);
1372 } else if (aPcmap
== PCMAP_PRETTYPRINT
) {
1373 *_rval
= PPPcToLine(aPC
);
1375 return NS_ERROR_INVALID_ARG
;
1382 jsdScript::LineToPc(PRUint32 aLine
, PRUint32 aPcmap
, PRUint32
*_rval
)
1384 ASSERT_VALID_EPHEMERAL
;
1385 if (aPcmap
== PCMAP_SOURCETEXT
) {
1386 jsuword pc
= JSD_GetClosestPC (mCx
, mScript
, aLine
);
1387 *_rval
= pc
- mFirstPC
;
1388 } else if (aPcmap
== PCMAP_PRETTYPRINT
) {
1389 *_rval
= PPLineToPc(aLine
);
1391 return NS_ERROR_INVALID_ARG
;
1398 jsdScript::IsLineExecutable(PRUint32 aLine
, PRUint32 aPcmap
, PRBool
*_rval
)
1400 ASSERT_VALID_EPHEMERAL
;
1401 if (aPcmap
== PCMAP_SOURCETEXT
) {
1402 jsuword pc
= JSD_GetClosestPC (mCx
, mScript
, aLine
);
1403 *_rval
= (aLine
== JSD_GetClosestLine (mCx
, mScript
, pc
));
1404 } else if (aPcmap
== PCMAP_PRETTYPRINT
) {
1405 if (!mPPLineMap
&& !CreatePPLineMap())
1406 return NS_ERROR_OUT_OF_MEMORY
;
1408 for (PRUint32 i
= 0; i
< mPCMapSize
; ++i
) {
1409 if (mPPLineMap
[i
].line
>= aLine
) {
1410 *_rval
= (mPPLineMap
[i
].line
== aLine
);
1415 return NS_ERROR_INVALID_ARG
;
1422 jsdScript::SetBreakpoint(PRUint32 aPC
)
1424 ASSERT_VALID_EPHEMERAL
;
1425 jsuword pc
= mFirstPC
+ aPC
;
1426 JSD_SetExecutionHook (mCx
, mScript
, pc
, jsds_ExecutionHookProc
,
1427 reinterpret_cast<void *>(PRIVATE_TO_JSVAL(NULL
)));
1432 jsdScript::ClearBreakpoint(PRUint32 aPC
)
1434 ASSERT_VALID_EPHEMERAL
;
1435 jsuword pc
= mFirstPC
+ aPC
;
1436 JSD_ClearExecutionHook (mCx
, mScript
, pc
);
1441 jsdScript::ClearAllBreakpoints()
1443 ASSERT_VALID_EPHEMERAL
;
1444 JSD_LockScriptSubsystem(mCx
);
1445 JSD_ClearAllExecutionHooksForScript (mCx
, mScript
);
1446 JSD_UnlockScriptSubsystem(mCx
);
1451 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext
, jsdIContext
, jsdIEphemeral
)
1454 jsdContext::FromPtr (JSDContext
*aJSDCx
, JSContext
*aJSCx
)
1456 if (!aJSDCx
|| !aJSCx
)
1459 nsCOMPtr
<jsdIContext
> jsdicx
;
1460 nsCOMPtr
<jsdIEphemeral
> eph
=
1461 jsds_FindEphemeral (&gLiveContexts
, static_cast<void *>(aJSCx
));
1464 jsdicx
= do_QueryInterface(eph
);
1468 nsCOMPtr
<nsISupports
> iscx
;
1469 if (JS_GetOptions(aJSCx
) & JSOPTION_PRIVATE_IS_NSISUPPORTS
)
1470 iscx
= static_cast<nsISupports
*>(JS_GetContextPrivate(aJSCx
));
1471 jsdicx
= new jsdContext (aJSDCx
, aJSCx
, iscx
);
1474 jsdIContext
*ctx
= nsnull
;
1479 jsdContext::jsdContext (JSDContext
*aJSDCx
, JSContext
*aJSCx
,
1480 nsISupports
*aISCx
) : mValid(PR_TRUE
), mTag(0),
1482 mJSCx(aJSCx
), mISCx(aISCx
)
1484 DEBUG_CREATE ("jsdContext", gContextCount
);
1485 mLiveListEntry
.value
= this;
1486 mLiveListEntry
.key
= static_cast<void *>(aJSCx
);
1487 jsds_InsertEphemeral (&gLiveContexts
, &mLiveListEntry
);
1490 jsdContext::~jsdContext()
1492 DEBUG_DESTROY ("jsdContext", gContextCount
);
1495 /* call Invalidate() to take ourselves out of the live list */
1501 jsdContext::GetIsValid(PRBool
*_rval
)
1508 jsdContext::Invalidate()
1510 ASSERT_VALID_EPHEMERAL
;
1512 jsds_RemoveEphemeral (&gLiveContexts
, &mLiveListEntry
);
1517 jsdContext::InvalidateAll()
1520 jsds_InvalidateAllEphemerals (&gLiveContexts
);
1524 jsdContext::GetJSContext(JSContext
**_rval
)
1526 ASSERT_VALID_EPHEMERAL
;
1532 jsdContext::GetOptions(PRUint32
*_rval
)
1534 ASSERT_VALID_EPHEMERAL
;
1535 *_rval
= JS_GetOptions(mJSCx
);
1540 jsdContext::SetOptions(PRUint32 options
)
1542 ASSERT_VALID_EPHEMERAL
;
1543 PRUint32 lastOptions
= JS_GetOptions(mJSCx
);
1545 /* don't let users change this option, they'd just be shooting themselves
1547 if ((options
^ lastOptions
) & JSOPTION_PRIVATE_IS_NSISUPPORTS
)
1548 return NS_ERROR_ILLEGAL_VALUE
;
1550 JS_SetOptions(mJSCx
, options
);
1555 jsdContext::GetPrivateData(nsISupports
**_rval
)
1557 ASSERT_VALID_EPHEMERAL
;
1558 PRUint32 options
= JS_GetOptions(mJSCx
);
1559 if (options
& JSOPTION_PRIVATE_IS_NSISUPPORTS
)
1561 *_rval
= static_cast<nsISupports
*>(JS_GetContextPrivate(mJSCx
));
1562 NS_IF_ADDREF(*_rval
);
1573 jsdContext::GetWrappedContext(nsISupports
**_rval
)
1575 ASSERT_VALID_EPHEMERAL
;
1576 NS_IF_ADDREF(*_rval
= mISCx
);
1581 jsdContext::GetTag(PRUint32
*_rval
)
1583 ASSERT_VALID_EPHEMERAL
;
1585 mTag
= ++jsdContext::LastTag
;
1592 jsdContext::GetVersion (PRInt32
*_rval
)
1594 ASSERT_VALID_EPHEMERAL
;
1595 *_rval
= static_cast<PRInt32
>(JS_GetVersion(mJSCx
));
1600 jsdContext::SetVersion (PRInt32 id
)
1602 ASSERT_VALID_EPHEMERAL
;
1603 JSVersion ver
= static_cast<JSVersion
>(id
);
1604 JS_SetVersion(mJSCx
, ver
);
1609 jsdContext::GetGlobalObject (jsdIValue
**_rval
)
1611 ASSERT_VALID_EPHEMERAL
;
1612 JSObject
*glob
= JS_GetGlobalObject(mJSCx
);
1613 JSDValue
*jsdv
= JSD_NewValue (mJSDCx
, OBJECT_TO_JSVAL(glob
));
1615 return NS_ERROR_FAILURE
;
1616 *_rval
= jsdValue::FromPtr (mJSDCx
, jsdv
);
1618 return NS_ERROR_FAILURE
;
1623 jsdContext::GetScriptsEnabled (PRBool
*_rval
)
1625 ASSERT_VALID_EPHEMERAL
;
1631 nsCOMPtr
<nsIScriptContext
> context
= do_QueryInterface(mISCx
);
1633 return NS_ERROR_NO_INTERFACE
;
1635 *_rval
= context
->GetScriptsEnabled();
1641 jsdContext::SetScriptsEnabled (PRBool _rval
)
1643 ASSERT_VALID_EPHEMERAL
;
1647 return NS_ERROR_NO_INTERFACE
;
1650 nsCOMPtr
<nsIScriptContext
> context
= do_QueryInterface(mISCx
);
1652 return NS_ERROR_NO_INTERFACE
;
1654 context
->SetScriptsEnabled(_rval
, PR_TRUE
);
1660 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame
, jsdIStackFrame
, jsdIEphemeral
)
1662 jsdStackFrame::jsdStackFrame (JSDContext
*aCx
, JSDThreadState
*aThreadState
,
1663 JSDStackFrameInfo
*aStackFrameInfo
) :
1664 mCx(aCx
), mThreadState(aThreadState
), mStackFrameInfo(aStackFrameInfo
)
1666 DEBUG_CREATE ("jsdStackFrame", gFrameCount
);
1667 mValid
= (aCx
&& aThreadState
&& aStackFrameInfo
);
1669 mLiveListEntry
.key
= aStackFrameInfo
;
1670 mLiveListEntry
.value
= this;
1671 jsds_InsertEphemeral (&gLiveStackFrames
, &mLiveListEntry
);
1675 jsdStackFrame::~jsdStackFrame()
1677 DEBUG_DESTROY ("jsdStackFrame", gFrameCount
);
1680 /* call Invalidate() to take ourselves out of the live list */
1686 jsdStackFrame::FromPtr (JSDContext
*aCx
, JSDThreadState
*aThreadState
,
1687 JSDStackFrameInfo
*aStackFrameInfo
)
1689 if (!aStackFrameInfo
)
1693 nsCOMPtr
<jsdIStackFrame
> frame
;
1695 nsCOMPtr
<jsdIEphemeral
> eph
=
1696 jsds_FindEphemeral (&gLiveStackFrames
,
1697 reinterpret_cast<void *>(aStackFrameInfo
));
1701 frame
= do_QueryInterface(eph
);
1706 rv
= new jsdStackFrame (aCx
, aThreadState
, aStackFrameInfo
);
1714 jsdStackFrame::Invalidate()
1716 ASSERT_VALID_EPHEMERAL
;
1718 jsds_RemoveEphemeral (&gLiveStackFrames
, &mLiveListEntry
);
1723 jsdStackFrame::InvalidateAll()
1725 if (gLiveStackFrames
)
1726 jsds_InvalidateAllEphemerals (&gLiveStackFrames
);
1730 jsdStackFrame::GetJSDContext(JSDContext
**_rval
)
1732 ASSERT_VALID_EPHEMERAL
;
1738 jsdStackFrame::GetJSDThreadState(JSDThreadState
**_rval
)
1740 ASSERT_VALID_EPHEMERAL
;
1741 *_rval
= mThreadState
;
1746 jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo
**_rval
)
1748 ASSERT_VALID_EPHEMERAL
;
1749 *_rval
= mStackFrameInfo
;
1754 jsdStackFrame::GetIsValid(PRBool
*_rval
)
1761 jsdStackFrame::GetCallingFrame(jsdIStackFrame
**_rval
)
1763 ASSERT_VALID_EPHEMERAL
;
1764 JSDStackFrameInfo
*sfi
= JSD_GetCallingStackFrame (mCx
, mThreadState
,
1766 *_rval
= jsdStackFrame::FromPtr (mCx
, mThreadState
, sfi
);
1771 jsdStackFrame::GetExecutionContext(jsdIContext
**_rval
)
1773 ASSERT_VALID_EPHEMERAL
;
1774 JSContext
*cx
= JSD_GetJSContext (mCx
, mThreadState
);
1775 *_rval
= jsdContext::FromPtr (mCx
, cx
);
1780 jsdStackFrame::GetFunctionName(nsACString
&_rval
)
1782 ASSERT_VALID_EPHEMERAL
;
1783 _rval
.Assign(JSD_GetNameForStackFrame(mCx
, mThreadState
, mStackFrameInfo
));
1788 jsdStackFrame::GetIsNative(PRBool
*_rval
)
1790 ASSERT_VALID_EPHEMERAL
;
1791 *_rval
= JSD_IsStackFrameNative (mCx
, mThreadState
, mStackFrameInfo
);
1796 jsdStackFrame::GetIsDebugger(PRBool
*_rval
)
1798 ASSERT_VALID_EPHEMERAL
;
1799 *_rval
= JSD_IsStackFrameDebugger (mCx
, mThreadState
, mStackFrameInfo
);
1804 jsdStackFrame::GetIsConstructing(PRBool
*_rval
)
1806 ASSERT_VALID_EPHEMERAL
;
1807 *_rval
= JSD_IsStackFrameConstructing (mCx
, mThreadState
, mStackFrameInfo
);
1812 jsdStackFrame::GetScript(jsdIScript
**_rval
)
1814 ASSERT_VALID_EPHEMERAL
;
1815 JSDScript
*script
= JSD_GetScriptForStackFrame (mCx
, mThreadState
,
1817 *_rval
= jsdScript::FromPtr (mCx
, script
);
1822 jsdStackFrame::GetPc(PRUint32
*_rval
)
1824 ASSERT_VALID_EPHEMERAL
;
1825 JSDScript
*script
= JSD_GetScriptForStackFrame (mCx
, mThreadState
,
1828 return NS_ERROR_FAILURE
;
1829 jsuword pcbase
= JSD_GetClosestPC(mCx
, script
, 0);
1831 jsuword pc
= JSD_GetPCForStackFrame (mCx
, mThreadState
, mStackFrameInfo
);
1833 *_rval
= pc
- pcbase
;
1840 jsdStackFrame::GetLine(PRUint32
*_rval
)
1842 ASSERT_VALID_EPHEMERAL
;
1843 JSDScript
*script
= JSD_GetScriptForStackFrame (mCx
, mThreadState
,
1846 jsuword pc
= JSD_GetPCForStackFrame (mCx
, mThreadState
, mStackFrameInfo
);
1847 *_rval
= JSD_GetClosestLine (mCx
, script
, pc
);
1849 if (!JSD_IsStackFrameNative(mCx
, mThreadState
, mStackFrameInfo
))
1850 return NS_ERROR_FAILURE
;
1857 jsdStackFrame::GetCallee(jsdIValue
**_rval
)
1859 ASSERT_VALID_EPHEMERAL
;
1860 JSDValue
*jsdv
= JSD_GetCallObjectForStackFrame (mCx
, mThreadState
,
1863 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
1868 jsdStackFrame::GetScope(jsdIValue
**_rval
)
1870 ASSERT_VALID_EPHEMERAL
;
1871 JSDValue
*jsdv
= JSD_GetScopeChainForStackFrame (mCx
, mThreadState
,
1874 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
1879 jsdStackFrame::GetThisValue(jsdIValue
**_rval
)
1881 ASSERT_VALID_EPHEMERAL
;
1882 JSDValue
*jsdv
= JSD_GetThisForStackFrame (mCx
, mThreadState
,
1885 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
1891 jsdStackFrame::Eval (const nsAString
&bytes
, const nsACString
&fileName
,
1892 PRUint32 line
, jsdIValue
**result
, PRBool
*_rval
)
1894 ASSERT_VALID_EPHEMERAL
;
1896 if (bytes
.IsEmpty())
1897 return NS_ERROR_INVALID_ARG
;
1899 // get pointer to buffer contained in |bytes|
1900 nsAString::const_iterator h
;
1901 bytes
.BeginReading(h
);
1902 const jschar
*char_bytes
= reinterpret_cast<const jschar
*>(h
.get());
1904 JSExceptionState
*estate
= 0;
1907 JSContext
*cx
= JSD_GetJSContext (mCx
, mThreadState
);
1909 JSAutoRequest
ar(cx
);
1911 estate
= JS_SaveExceptionState (cx
);
1912 JS_ClearPendingException (cx
);
1914 *_rval
= JSD_AttemptUCScriptInStackFrame (mCx
, mThreadState
,
1916 char_bytes
, bytes
.Length(),
1917 PromiseFlatCString(fileName
).get(),
1920 if (JS_IsExceptionPending(cx
))
1921 JS_GetPendingException (cx
, &jv
);
1926 JS_RestoreExceptionState (cx
, estate
);
1928 JSDValue
*jsdv
= JSD_NewValue (mCx
, jv
);
1930 return NS_ERROR_FAILURE
;
1931 *result
= jsdValue::FromPtr (mCx
, jsdv
);
1933 return NS_ERROR_FAILURE
;
1939 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue
, jsdIValue
, jsdIEphemeral
)
1941 jsdValue::FromPtr (JSDContext
*aCx
, JSDValue
*aValue
)
1943 /* value will be dropped by te jsdValue destructor. */
1948 jsdIValue
*rv
= new jsdValue (aCx
, aValue
);
1953 jsdValue::jsdValue (JSDContext
*aCx
, JSDValue
*aValue
) : mValid(PR_TRUE
),
1957 DEBUG_CREATE ("jsdValue", gValueCount
);
1958 mLiveListEntry
.value
= this;
1959 jsds_InsertEphemeral (&gLiveValues
, &mLiveListEntry
);
1962 jsdValue::~jsdValue()
1964 DEBUG_DESTROY ("jsdValue", gValueCount
);
1966 /* call Invalidate() to take ourselves out of the live list */
1971 jsdValue::GetIsValid(PRBool
*_rval
)
1978 jsdValue::Invalidate()
1980 ASSERT_VALID_EPHEMERAL
;
1982 jsds_RemoveEphemeral (&gLiveValues
, &mLiveListEntry
);
1983 JSD_DropValue (mCx
, mValue
);
1988 jsdValue::InvalidateAll()
1991 jsds_InvalidateAllEphemerals (&gLiveValues
);
1995 jsdValue::GetJSDContext(JSDContext
**_rval
)
1997 ASSERT_VALID_EPHEMERAL
;
2003 jsdValue::GetJSDValue (JSDValue
**_rval
)
2005 ASSERT_VALID_EPHEMERAL
;
2011 jsdValue::GetIsNative (PRBool
*_rval
)
2013 ASSERT_VALID_EPHEMERAL
;
2014 *_rval
= JSD_IsValueNative (mCx
, mValue
);
2019 jsdValue::GetIsNumber (PRBool
*_rval
)
2021 ASSERT_VALID_EPHEMERAL
;
2022 *_rval
= JSD_IsValueNumber (mCx
, mValue
);
2027 jsdValue::GetIsPrimitive (PRBool
*_rval
)
2029 ASSERT_VALID_EPHEMERAL
;
2030 *_rval
= JSD_IsValuePrimitive (mCx
, mValue
);
2035 jsdValue::GetJsType (PRUint32
*_rval
)
2037 ASSERT_VALID_EPHEMERAL
;
2040 val
= JSD_GetValueWrappedJSVal (mCx
, mValue
);
2042 if (JSVAL_IS_NULL(val
))
2044 else if (JSVAL_IS_BOOLEAN(val
))
2045 *_rval
= TYPE_BOOLEAN
;
2046 else if (JSVAL_IS_DOUBLE(val
))
2047 *_rval
= TYPE_DOUBLE
;
2048 else if (JSVAL_IS_INT(val
))
2050 else if (JSVAL_IS_STRING(val
))
2051 *_rval
= TYPE_STRING
;
2052 else if (JSVAL_IS_VOID(val
))
2054 else if (JSD_IsValueFunction (mCx
, mValue
))
2055 *_rval
= TYPE_FUNCTION
;
2056 else if (JSVAL_IS_OBJECT(val
))
2057 *_rval
= TYPE_OBJECT
;
2059 NS_ASSERTION (0, "Value has no discernible type.");
2065 jsdValue::GetJsPrototype (jsdIValue
**_rval
)
2067 ASSERT_VALID_EPHEMERAL
;
2068 JSDValue
*jsdv
= JSD_GetValuePrototype (mCx
, mValue
);
2069 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2074 jsdValue::GetJsParent (jsdIValue
**_rval
)
2076 ASSERT_VALID_EPHEMERAL
;
2077 JSDValue
*jsdv
= JSD_GetValueParent (mCx
, mValue
);
2078 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2083 jsdValue::GetJsClassName(nsACString
&_rval
)
2085 ASSERT_VALID_EPHEMERAL
;
2086 _rval
.Assign(JSD_GetValueClassName(mCx
, mValue
));
2092 jsdValue::GetJsConstructor (jsdIValue
**_rval
)
2094 ASSERT_VALID_EPHEMERAL
;
2095 JSDValue
*jsdv
= JSD_GetValueConstructor (mCx
, mValue
);
2096 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2101 jsdValue::GetJsFunctionName(nsACString
&_rval
)
2103 ASSERT_VALID_EPHEMERAL
;
2104 _rval
.Assign(JSD_GetValueFunctionName(mCx
, mValue
));
2109 jsdValue::GetBooleanValue(PRBool
*_rval
)
2111 ASSERT_VALID_EPHEMERAL
;
2112 *_rval
= JSD_GetValueBoolean (mCx
, mValue
);
2117 jsdValue::GetDoubleValue(double *_rval
)
2119 ASSERT_VALID_EPHEMERAL
;
2120 double *dp
= JSD_GetValueDouble (mCx
, mValue
);
2122 return NS_ERROR_FAILURE
;
2128 jsdValue::GetIntValue(PRInt32
*_rval
)
2130 ASSERT_VALID_EPHEMERAL
;
2131 *_rval
= JSD_GetValueInt (mCx
, mValue
);
2136 jsdValue::GetObjectValue(jsdIObject
**_rval
)
2138 ASSERT_VALID_EPHEMERAL
;
2140 obj
= JSD_GetObjectForValue (mCx
, mValue
);
2141 *_rval
= jsdObject::FromPtr (mCx
, obj
);
2143 return NS_ERROR_FAILURE
;
2148 jsdValue::GetStringValue(nsACString
&_rval
)
2150 ASSERT_VALID_EPHEMERAL
;
2151 JSString
*jstr_val
= JSD_GetValueString(mCx
, mValue
);
2153 nsDependentString
chars(
2154 reinterpret_cast<PRUnichar
*>(JS_GetStringChars(jstr_val
)),
2155 JS_GetStringLength(jstr_val
));
2156 CopyUTF16toUTF8(chars
, _rval
);
2164 jsdValue::GetPropertyCount (PRInt32
*_rval
)
2166 ASSERT_VALID_EPHEMERAL
;
2167 if (JSD_IsValueObject(mCx
, mValue
))
2168 *_rval
= JSD_GetCountOfProperties (mCx
, mValue
);
2175 jsdValue::GetProperties (jsdIProperty
***propArray
, PRUint32
*length
)
2177 ASSERT_VALID_EPHEMERAL
;
2178 *propArray
= nsnull
;
2182 PRUint32 prop_count
= JSD_IsValueObject(mCx
, mValue
)
2183 ? JSD_GetCountOfProperties (mCx
, mValue
)
2185 NS_ENSURE_TRUE(prop_count
, NS_OK
);
2187 jsdIProperty
**pa_temp
=
2188 static_cast<jsdIProperty
**>
2189 (nsMemory::Alloc(sizeof (jsdIProperty
*) *
2191 NS_ENSURE_TRUE(pa_temp
, NS_ERROR_OUT_OF_MEMORY
);
2194 JSDProperty
*iter
= NULL
;
2196 while ((prop
= JSD_IterateProperties (mCx
, mValue
, &iter
))) {
2197 pa_temp
[i
] = jsdProperty::FromPtr (mCx
, prop
);
2201 NS_ASSERTION (prop_count
== i
, "property count mismatch");
2203 /* if caller doesn't care about length, don't bother telling them */
2204 *propArray
= pa_temp
;
2206 *length
= prop_count
;
2212 jsdValue::GetProperty (const nsACString
&name
, jsdIProperty
**_rval
)
2214 ASSERT_VALID_EPHEMERAL
;
2215 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2217 JSAutoRequest
ar(cx
);
2219 /* not rooting this */
2220 JSString
*jstr_name
= JS_NewStringCopyZ(cx
, PromiseFlatCString(name
).get());
2222 return NS_ERROR_OUT_OF_MEMORY
;
2224 JSDProperty
*prop
= JSD_GetValueProperty (mCx
, mValue
, jstr_name
);
2226 *_rval
= jsdProperty::FromPtr (mCx
, prop
);
2233 ASSERT_VALID_EPHEMERAL
;
2234 JSD_RefreshValue (mCx
, mValue
);
2239 jsdValue::GetWrappedValue()
2241 ASSERT_VALID_EPHEMERAL
;
2243 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID(), &rv
);
2247 nsAXPCNativeCallContext
*cc
= nsnull
;
2248 rv
= xpc
->GetCurrentNativeCallContext(&cc
);
2253 rv
= cc
->GetRetValPtr(&result
);
2259 *result
= JSD_GetValueWrappedJSVal (mCx
, mValue
);
2260 cc
->SetReturnValueWasSet(PR_TRUE
);
2266 /******************************************************************************
2267 * debugger service implementation
2268 ******************************************************************************/
2269 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdService
, jsdIDebuggerService
)
2272 jsdService::GetJSDContext(JSDContext
**_rval
)
2279 jsdService::GetInitAtStartup (PRBool
*_rval
)
2282 nsCOMPtr
<nsICategoryManager
>
2283 categoryManager(do_GetService(NS_CATMAN_CTRID
, &rv
));
2287 NS_WARNING("couldn't get category manager");
2291 if (mInitAtStartup
== triUnknown
) {
2292 nsXPIDLCString notused
;
2293 nsresult autoreg_rv
, appstart_rv
;
2295 autoreg_rv
= categoryManager
->GetCategoryEntry(AUTOREG_CATEGORY
,
2297 getter_Copies(notused
));
2298 appstart_rv
= categoryManager
->GetCategoryEntry(APPSTART_CATEGORY
,
2300 getter_Copies(notused
));
2301 if (autoreg_rv
!= appstart_rv
) {
2302 /* we have an inconsistent state in the registry, attempt to fix.
2303 * we need to make mInitAtStartup disagree with the state passed
2304 * to SetInitAtStartup to make it actually do something.
2306 mInitAtStartup
= triYes
;
2307 rv
= SetInitAtStartup (PR_FALSE
);
2310 NS_WARNING("SetInitAtStartup failed");
2313 } else if (autoreg_rv
== NS_ERROR_NOT_AVAILABLE
) {
2314 mInitAtStartup
= triNo
;
2315 } else if (NS_SUCCEEDED(autoreg_rv
)) {
2316 mInitAtStartup
= triYes
;
2318 NS_WARN_IF_FALSE(NS_SUCCEEDED(autoreg_rv
),
2319 "couldn't get autoreg category");
2320 NS_WARN_IF_FALSE(NS_SUCCEEDED(appstart_rv
),
2321 "couldn't get appstart category");
2327 *_rval
= (mInitAtStartup
== triYes
);
2333 * The initAtStartup property controls whether or not we register the
2334 * app start observer (jsdASObserver.) We register for both
2335 * "xpcom-autoregistration" and "app-startup" notifications if |state| is true.
2336 * the autoreg message is sent just before registration occurs (before
2337 * "app-startup".) We care about autoreg because it may load javascript
2338 * components. autoreg does *not* fire if components haven't changed since the
2339 * last autoreg, so we watch "app-startup" as a fallback.
2342 jsdService::SetInitAtStartup (PRBool state
)
2346 if (mInitAtStartup
== triUnknown
) {
2347 /* side effect sets mInitAtStartup */
2348 rv
= GetInitAtStartup(nsnull
);
2353 if (state
&& mInitAtStartup
== triYes
||
2354 !state
&& mInitAtStartup
== triNo
) {
2355 /* already in the requested state */
2359 nsCOMPtr
<nsICategoryManager
>
2360 categoryManager(do_GetService(NS_CATMAN_CTRID
, &rv
));
2365 rv
= categoryManager
->AddCategoryEntry(AUTOREG_CATEGORY
,
2368 PR_TRUE
, PR_TRUE
, nsnull
);
2371 rv
= categoryManager
->AddCategoryEntry(APPSTART_CATEGORY
,
2374 PR_TRUE
, PR_TRUE
, nsnull
);
2377 mInitAtStartup
= triYes
;
2379 rv
= categoryManager
->DeleteCategoryEntry(AUTOREG_CATEGORY
,
2380 JSD_AUTOREG_ENTRY
, PR_TRUE
);
2383 rv
= categoryManager
->DeleteCategoryEntry(APPSTART_CATEGORY
,
2384 JSD_STARTUP_ENTRY
, PR_TRUE
);
2387 mInitAtStartup
= triNo
;
2394 jsdService::GetFlags (PRUint32
*_rval
)
2396 ASSERT_VALID_CONTEXT
;
2397 *_rval
= JSD_GetContextFlags (mCx
);
2402 jsdService::SetFlags (PRUint32 flags
)
2404 ASSERT_VALID_CONTEXT
;
2405 JSD_SetContextFlags (mCx
, flags
);
2410 jsdService::GetImplementationString(nsACString
&aImplementationString
)
2412 aImplementationString
.AssignLiteral(implementationString
);
2417 jsdService::GetImplementationMajor(PRUint32
*_rval
)
2419 *_rval
= JSDS_MAJOR_VERSION
;
2424 jsdService::GetImplementationMinor(PRUint32
*_rval
)
2426 *_rval
= JSDS_MINOR_VERSION
;
2431 jsdService::GetIsOn (PRBool
*_rval
)
2438 jsdService::On (void)
2442 /* get JS things from the CallContext */
2443 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID(), &rv
);
2444 if (NS_FAILED(rv
)) return rv
;
2446 nsAXPCNativeCallContext
*cc
= nsnull
;
2447 rv
= xpc
->GetCurrentNativeCallContext(&cc
);
2448 if (NS_FAILED(rv
)) return rv
;
2451 rv
= cc
->GetJSContext (&cx
);
2452 if (NS_FAILED(rv
)) return rv
;
2454 return OnForRuntime(JS_GetRuntime (cx
));
2459 jsdService::OnForRuntime (JSRuntime
*rt
)
2462 return (rt
== mRuntime
) ? NS_OK
: NS_ERROR_ALREADY_INITIALIZED
;
2466 if (gLastGCProc
== jsds_GCCallbackProc
)
2467 /* condition indicates that the callback proc has not been set yet */
2468 gLastGCProc
= JS_SetGCCallbackRT (rt
, jsds_GCCallbackProc
);
2470 mCx
= JSD_DebuggerOnForUser (rt
, NULL
, NULL
);
2472 return NS_ERROR_FAILURE
;
2474 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2475 JSObject
*glob
= JS_GetGlobalObject (cx
);
2477 /* init xpconnect on the debugger's context in case xpconnect tries to
2478 * use it for stuff. */
2480 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID(), &rv
);
2484 xpc
->InitClasses (cx
, glob
);
2486 /* If any of these mFooHook objects are installed, do the required JSD
2487 * hookup now. See also, jsdService::SetFooHook().
2490 JSD_SetErrorReporter (mCx
, jsds_ErrorHookProc
, NULL
);
2492 JSD_SetThrowHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2493 /* can't ignore script callbacks, as we need to |Release| the wrapper
2494 * stored in private data when a script is deleted. */
2496 JSD_SetInterruptHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2498 JSD_SetDebuggerHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2500 JSD_SetDebugBreakHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2502 JSD_SetTopLevelHook (mCx
, jsds_CallHookProc
, NULL
);
2504 JSD_ClearTopLevelHook (mCx
);
2506 JSD_SetFunctionHook (mCx
, jsds_CallHookProc
, NULL
);
2508 JSD_ClearFunctionHook (mCx
);
2512 printf ("+++ JavaScript debugging hooks installed.\n");
2518 jsdService::Off (void)
2523 if (!mCx
|| !mRuntime
)
2524 return NS_ERROR_NOT_INITIALIZED
;
2527 if (gGCStatus
!= JSGC_END
)
2528 return NS_ERROR_NOT_AVAILABLE
;
2530 JSContext
*cx
= JSD_GetDefaultJSContext(mCx
);
2531 jsds_NotifyPendingDeadScripts(cx
);
2535 if (gLastGCProc != jsds_GCCallbackProc)
2536 JS_SetGCCallbackRT (mRuntime, gLastGCProc);
2539 jsdContext::InvalidateAll();
2540 jsdScript::InvalidateAll();
2541 jsdValue::InvalidateAll();
2542 jsdProperty::InvalidateAll();
2543 ClearAllBreakpoints();
2545 JSD_SetErrorReporter (mCx
, NULL
, NULL
);
2546 JSD_SetScriptHook (mCx
, NULL
, NULL
);
2547 JSD_ClearThrowHook (mCx
);
2548 JSD_ClearInterruptHook (mCx
);
2549 JSD_ClearDebuggerHook (mCx
);
2550 JSD_ClearDebugBreakHook (mCx
);
2551 JSD_ClearTopLevelHook (mCx
);
2552 JSD_ClearFunctionHook (mCx
);
2554 JSD_DebuggerOff (mCx
);
2561 printf ("+++ JavaScript debugging hooks removed.\n");
2568 jsdService::GetPauseDepth(PRUint32
*_rval
)
2570 NS_ENSURE_ARG_POINTER(_rval
);
2571 *_rval
= mPauseLevel
;
2576 jsdService::Pause(PRUint32
*_rval
)
2579 return NS_ERROR_NOT_INITIALIZED
;
2581 if (++mPauseLevel
== 1) {
2582 JSD_SetErrorReporter (mCx
, NULL
, NULL
);
2583 JSD_ClearThrowHook (mCx
);
2584 JSD_ClearInterruptHook (mCx
);
2585 JSD_ClearDebuggerHook (mCx
);
2586 JSD_ClearDebugBreakHook (mCx
);
2587 JSD_ClearTopLevelHook (mCx
);
2588 JSD_ClearFunctionHook (mCx
);
2592 *_rval
= mPauseLevel
;
2598 jsdService::UnPause(PRUint32
*_rval
)
2601 return NS_ERROR_NOT_INITIALIZED
;
2603 if (mPauseLevel
== 0)
2604 return NS_ERROR_NOT_AVAILABLE
;
2606 /* check mOn before we muck with this stuff, it's possible the debugger
2607 * was turned off while we were paused.
2609 if (--mPauseLevel
== 0 && mOn
) {
2611 JSD_SetErrorReporter (mCx
, jsds_ErrorHookProc
, NULL
);
2613 JSD_SetThrowHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2615 JSD_SetInterruptHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2617 JSD_SetDebuggerHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2619 JSD_SetDebugBreakHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2621 JSD_SetTopLevelHook (mCx
, jsds_CallHookProc
, NULL
);
2623 JSD_ClearTopLevelHook (mCx
);
2625 JSD_SetFunctionHook (mCx
, jsds_CallHookProc
, NULL
);
2627 JSD_ClearFunctionHook (mCx
);
2631 *_rval
= mPauseLevel
;
2637 jsdService::EnumerateContexts (jsdIContextEnumerator
*enumerator
)
2639 ASSERT_VALID_CONTEXT
;
2644 JSContext
*iter
= NULL
;
2647 while ((cx
= JS_ContextIterator (mRuntime
, &iter
)))
2649 nsCOMPtr
<jsdIContext
> jsdicx
=
2650 getter_AddRefs(jsdContext::FromPtr(mCx
, cx
));
2653 if (NS_FAILED(enumerator
->EnumerateContext(jsdicx
)))
2662 jsdService::EnumerateScripts (jsdIScriptEnumerator
*enumerator
)
2664 ASSERT_VALID_CONTEXT
;
2667 JSDScript
*iter
= NULL
;
2668 nsresult rv
= NS_OK
;
2670 JSD_LockScriptSubsystem(mCx
);
2671 while((script
= JSD_IterateScripts(mCx
, &iter
))) {
2672 nsCOMPtr
<jsdIScript
> jsdis
=
2673 getter_AddRefs(jsdScript::FromPtr(mCx
, script
));
2674 rv
= enumerator
->EnumerateScript (jsdis
);
2678 JSD_UnlockScriptSubsystem(mCx
);
2684 jsdService::GC (void)
2686 ASSERT_VALID_CONTEXT
;
2687 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2693 jsdService::DumpHeap(const nsACString
&fileName
)
2695 ASSERT_VALID_CONTEXT
;
2697 return NS_ERROR_NOT_IMPLEMENTED
;
2699 nsresult rv
= NS_OK
;
2700 FILE *file
= !fileName
.IsEmpty() ? fopen(PromiseFlatCString(fileName
).get(), "w") : stdout
;
2702 rv
= NS_ERROR_FAILURE
;
2704 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2705 if (!JS_DumpHeap(cx
, file
, NULL
, 0, NULL
, (size_t)-1, NULL
))
2706 rv
= NS_ERROR_FAILURE
;
2715 jsdService::ClearProfileData ()
2717 ASSERT_VALID_CONTEXT
;
2718 JSD_ClearAllProfileData (mCx
);
2723 jsdService::InsertFilter (jsdIFilter
*filter
, jsdIFilter
*after
)
2725 NS_ENSURE_ARG_POINTER (filter
);
2726 if (jsds_FindFilter (filter
))
2727 return NS_ERROR_INVALID_ARG
;
2729 FilterRecord
*rec
= PR_NEWZAP (FilterRecord
);
2731 return NS_ERROR_OUT_OF_MEMORY
;
2733 if (!jsds_SyncFilter (rec
, filter
)) {
2735 return NS_ERROR_FAILURE
;
2740 /* insert at head of list */
2741 PR_INSERT_LINK(&rec
->links
, &gFilters
->links
);
2744 /* insert somewhere in the list */
2745 FilterRecord
*afterRecord
= jsds_FindFilter (after
);
2747 jsds_FreeFilter(rec
);
2748 return NS_ERROR_INVALID_ARG
;
2750 PR_INSERT_AFTER(&rec
->links
, &afterRecord
->links
);
2754 /* user asked to insert into the middle of an empty list, bail. */
2755 jsds_FreeFilter(rec
);
2756 return NS_ERROR_NOT_INITIALIZED
;
2758 PR_INIT_CLIST(&rec
->links
);
2766 jsdService::AppendFilter (jsdIFilter
*filter
)
2768 NS_ENSURE_ARG_POINTER (filter
);
2769 if (jsds_FindFilter (filter
))
2770 return NS_ERROR_INVALID_ARG
;
2771 FilterRecord
*rec
= PR_NEWZAP (FilterRecord
);
2773 if (!jsds_SyncFilter (rec
, filter
)) {
2775 return NS_ERROR_FAILURE
;
2779 PR_INSERT_BEFORE(&rec
->links
, &gFilters
->links
);
2781 PR_INIT_CLIST(&rec
->links
);
2789 jsdService::RemoveFilter (jsdIFilter
*filter
)
2791 NS_ENSURE_ARG_POINTER(filter
);
2792 FilterRecord
*rec
= jsds_FindFilter (filter
);
2794 return NS_ERROR_INVALID_ARG
;
2796 if (gFilters
== rec
) {
2797 gFilters
= reinterpret_cast<FilterRecord
*>
2798 (PR_NEXT_LINK(&rec
->links
));
2799 /* If we're the only filter left, null out the list head. */
2800 if (gFilters
== rec
)
2805 PR_REMOVE_LINK(&rec
->links
);
2806 jsds_FreeFilter (rec
);
2812 jsdService::SwapFilters (jsdIFilter
*filter_a
, jsdIFilter
*filter_b
)
2814 NS_ENSURE_ARG_POINTER(filter_a
);
2815 NS_ENSURE_ARG_POINTER(filter_b
);
2817 FilterRecord
*rec_a
= jsds_FindFilter (filter_a
);
2819 return NS_ERROR_INVALID_ARG
;
2821 if (filter_a
== filter_b
) {
2822 /* just a refresh */
2823 if (!jsds_SyncFilter (rec_a
, filter_a
))
2824 return NS_ERROR_FAILURE
;
2828 FilterRecord
*rec_b
= jsds_FindFilter (filter_b
);
2830 /* filter_b is not in the list, replace filter_a with filter_b. */
2831 if (!jsds_SyncFilter (rec_a
, filter_b
))
2832 return NS_ERROR_FAILURE
;
2834 /* both filters are in the list, swap. */
2835 if (!jsds_SyncFilter (rec_a
, filter_b
))
2836 return NS_ERROR_FAILURE
;
2837 if (!jsds_SyncFilter (rec_b
, filter_a
))
2838 return NS_ERROR_FAILURE
;
2845 jsdService::EnumerateFilters (jsdIFilterEnumerator
*enumerator
)
2850 FilterRecord
*current
= gFilters
;
2852 jsds_SyncFilter (current
, current
->filterObject
);
2853 /* SyncFilter failure would be bad, but what would we do about it? */
2855 nsresult rv
= enumerator
->EnumerateFilter (current
->filterObject
);
2859 current
= reinterpret_cast<FilterRecord
*>
2860 (PR_NEXT_LINK (¤t
->links
));
2861 } while (current
!= gFilters
);
2867 jsdService::RefreshFilters ()
2869 return EnumerateFilters(nsnull
);
2873 jsdService::ClearFilters ()
2878 FilterRecord
*current
= reinterpret_cast<FilterRecord
*>
2879 (PR_NEXT_LINK (&gFilters
->links
));
2881 FilterRecord
*next
= reinterpret_cast<FilterRecord
*>
2882 (PR_NEXT_LINK (¤t
->links
));
2883 PR_REMOVE_AND_INIT_LINK(¤t
->links
);
2884 jsds_FreeFilter(current
);
2886 } while (current
!= gFilters
);
2888 jsds_FreeFilter(current
);
2895 jsdService::ClearAllBreakpoints (void)
2897 ASSERT_VALID_CONTEXT
;
2899 JSD_LockScriptSubsystem(mCx
);
2900 JSD_ClearAllExecutionHooks (mCx
);
2901 JSD_UnlockScriptSubsystem(mCx
);
2906 jsdService::WrapValue(jsdIValue
**_rval
)
2908 ASSERT_VALID_CONTEXT
;
2911 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService (nsIXPConnect::GetCID(), &rv
);
2915 nsAXPCNativeCallContext
*cc
= nsnull
;
2916 rv
= xpc
->GetCurrentNativeCallContext (&cc
);
2921 rv
= cc
->GetArgc (&argc
);
2925 return NS_ERROR_INVALID_ARG
;
2928 rv
= cc
->GetArgvPtr (&argv
);
2932 JSDValue
*jsdv
= JSD_NewValue (mCx
, argv
[0]);
2934 return NS_ERROR_FAILURE
;
2936 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2942 jsdService::EnterNestedEventLoop (jsdINestCallback
*callback
, PRUint32
*_rval
)
2944 // Nesting event queues is a thing of the past. Now, we just spin the
2945 // current event loop.
2948 nsCOMPtr
<nsIJSContextStack
>
2949 stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
));
2952 PRUint32 nestLevel
= ++mNestedLoopLevel
;
2954 nsCOMPtr
<nsIThread
> thread
= do_GetCurrentThread();
2956 if (NS_SUCCEEDED(stack
->Push(nsnull
))) {
2959 rv
= callback
->OnNest();
2963 while (NS_SUCCEEDED(rv
) && mNestedLoopLevel
>= nestLevel
) {
2964 if (!NS_ProcessNextEvent(thread
))
2965 rv
= NS_ERROR_UNEXPECTED
;
2970 NS_ASSERTION(cx
== nsnull
, "JSContextStack mismatch");
2973 rv
= NS_ERROR_FAILURE
;
2975 NS_ASSERTION (mNestedLoopLevel
<= nestLevel
,
2976 "nested event didn't unwind properly");
2977 if (mNestedLoopLevel
== nestLevel
)
2980 *_rval
= mNestedLoopLevel
;
2985 jsdService::ExitNestedEventLoop (PRUint32
*_rval
)
2987 if (mNestedLoopLevel
> 0)
2990 return NS_ERROR_FAILURE
;
2992 *_rval
= mNestedLoopLevel
;
2996 /* hook attribute get/set functions */
2999 jsdService::SetErrorHook (jsdIErrorHook
*aHook
)
3003 /* if the debugger isn't initialized, that's all we can do for now. The
3004 * OnForRuntime() method will do the rest when the coast is clear.
3006 if (!mCx
|| mPauseLevel
)
3010 JSD_SetErrorReporter (mCx
, jsds_ErrorHookProc
, NULL
);
3012 JSD_SetErrorReporter (mCx
, NULL
, NULL
);
3018 jsdService::GetErrorHook (jsdIErrorHook
**aHook
)
3020 *aHook
= mErrorHook
;
3021 NS_IF_ADDREF(*aHook
);
3027 jsdService::SetBreakpointHook (jsdIExecutionHook
*aHook
)
3029 mBreakpointHook
= aHook
;
3034 jsdService::GetBreakpointHook (jsdIExecutionHook
**aHook
)
3036 *aHook
= mBreakpointHook
;
3037 NS_IF_ADDREF(*aHook
);
3043 jsdService::SetDebugHook (jsdIExecutionHook
*aHook
)
3047 /* if the debugger isn't initialized, that's all we can do for now. The
3048 * OnForRuntime() method will do the rest when the coast is clear.
3050 if (!mCx
|| mPauseLevel
)
3054 JSD_SetDebugBreakHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3056 JSD_ClearDebugBreakHook (mCx
);
3062 jsdService::GetDebugHook (jsdIExecutionHook
**aHook
)
3064 *aHook
= mDebugHook
;
3065 NS_IF_ADDREF(*aHook
);
3071 jsdService::SetDebuggerHook (jsdIExecutionHook
*aHook
)
3073 mDebuggerHook
= aHook
;
3075 /* if the debugger isn't initialized, that's all we can do for now. The
3076 * OnForRuntime() method will do the rest when the coast is clear.
3078 if (!mCx
|| mPauseLevel
)
3082 JSD_SetDebuggerHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3084 JSD_ClearDebuggerHook (mCx
);
3090 jsdService::GetDebuggerHook (jsdIExecutionHook
**aHook
)
3092 *aHook
= mDebuggerHook
;
3093 NS_IF_ADDREF(*aHook
);
3099 jsdService::SetInterruptHook (jsdIExecutionHook
*aHook
)
3101 mInterruptHook
= aHook
;
3103 /* if the debugger isn't initialized, that's all we can do for now. The
3104 * OnForRuntime() method will do the rest when the coast is clear.
3106 if (!mCx
|| mPauseLevel
)
3110 JSD_SetInterruptHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3112 JSD_ClearInterruptHook (mCx
);
3118 jsdService::GetInterruptHook (jsdIExecutionHook
**aHook
)
3120 *aHook
= mInterruptHook
;
3121 NS_IF_ADDREF(*aHook
);
3127 jsdService::SetScriptHook (jsdIScriptHook
*aHook
)
3129 mScriptHook
= aHook
;
3131 /* if the debugger isn't initialized, that's all we can do for now. The
3132 * OnForRuntime() method will do the rest when the coast is clear.
3134 if (!mCx
|| mPauseLevel
)
3138 JSD_SetScriptHook (mCx
, jsds_ScriptHookProc
, NULL
);
3139 /* we can't unset it if !aHook, because we still need to see script
3140 * deletes in order to Release the jsdIScripts held in JSDScript
3146 jsdService::GetScriptHook (jsdIScriptHook
**aHook
)
3148 *aHook
= mScriptHook
;
3149 NS_IF_ADDREF(*aHook
);
3155 jsdService::SetThrowHook (jsdIExecutionHook
*aHook
)
3159 /* if the debugger isn't initialized, that's all we can do for now. The
3160 * OnForRuntime() method will do the rest when the coast is clear.
3162 if (!mCx
|| mPauseLevel
)
3166 JSD_SetThrowHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3168 JSD_ClearThrowHook (mCx
);
3174 jsdService::GetThrowHook (jsdIExecutionHook
**aHook
)
3176 *aHook
= mThrowHook
;
3177 NS_IF_ADDREF(*aHook
);
3183 jsdService::SetTopLevelHook (jsdICallHook
*aHook
)
3185 mTopLevelHook
= aHook
;
3187 /* if the debugger isn't initialized, that's all we can do for now. The
3188 * OnForRuntime() method will do the rest when the coast is clear.
3190 if (!mCx
|| mPauseLevel
)
3194 JSD_SetTopLevelHook (mCx
, jsds_CallHookProc
, NULL
);
3196 JSD_ClearTopLevelHook (mCx
);
3202 jsdService::GetTopLevelHook (jsdICallHook
**aHook
)
3204 *aHook
= mTopLevelHook
;
3205 NS_IF_ADDREF(*aHook
);
3211 jsdService::SetFunctionHook (jsdICallHook
*aHook
)
3213 mFunctionHook
= aHook
;
3215 /* if the debugger isn't initialized, that's all we can do for now. The
3216 * OnForRuntime() method will do the rest when the coast is clear.
3218 if (!mCx
|| mPauseLevel
)
3222 JSD_SetFunctionHook (mCx
, jsds_CallHookProc
, NULL
);
3224 JSD_ClearFunctionHook (mCx
);
3230 jsdService::GetFunctionHook (jsdICallHook
**aHook
)
3232 *aHook
= mFunctionHook
;
3233 NS_IF_ADDREF(*aHook
);
3239 jsdService::~jsdService()
3242 mErrorHook
= nsnull
;
3243 mBreakpointHook
= nsnull
;
3244 mDebugHook
= nsnull
;
3245 mDebuggerHook
= nsnull
;
3246 mInterruptHook
= nsnull
;
3247 mScriptHook
= nsnull
;
3248 mThrowHook
= nsnull
;
3249 mTopLevelHook
= nsnull
;
3250 mFunctionHook
= nsnull
;
3251 gGCStatus
= JSGC_END
;
3257 jsdService::GetService ()
3260 gJsds
= new jsdService();
3262 NS_IF_ADDREF(gJsds
);
3266 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService
, jsdService::GetService
)
3268 /* app-start observer. turns on the debugger at app-start. this is inserted
3269 * and/or removed from the app-start category by the jsdService::initAtStartup
3272 class jsdASObserver
: public nsIObserver
3281 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver
, nsIObserver
)
3284 jsdASObserver::Observe (nsISupports
*aSubject
, const char *aTopic
,
3285 const PRUnichar
*aData
)
3289 // Hmm. Why is the app-startup observer called multiple times?
3290 //NS_ASSERTION(!gJsds, "app startup observer called twice");
3291 nsCOMPtr
<jsdIDebuggerService
> jsds
= do_GetService(jsdServiceCtrID
, &rv
);
3296 rv
= jsds
->GetIsOn(&on
);
3297 if (NS_FAILED(rv
) || on
)
3300 nsCOMPtr
<nsIJSRuntimeService
> rts
= do_GetService(NS_JSRT_CTRID
, &rv
);
3305 rts
->GetRuntime (&rt
);
3309 rv
= jsds
->OnForRuntime(rt
);
3313 return jsds
->SetFlags(JSD_DISABLE_OBJECT_TRACE
);
3316 NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver
)
3318 static const nsModuleComponentInfo components
[] = {
3319 {"JSDService", JSDSERVICE_CID
, jsdServiceCtrID
, jsdServiceConstructor
},
3320 {"JSDASObserver", JSDASO_CID
, jsdARObserverCtrID
, jsdASObserverConstructor
}
3323 NS_IMPL_NSGETMODULE(JavaScript_Debugger
, components
)
3325 /********************************************************************************
3326 ********************************************************************************
3332 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState
, jsdIThreadState
);
3335 jsdThreadState::GetJSDContext(JSDContext
**_rval
)
3342 jsdThreadState::GetJSDThreadState(JSDThreadState
**_rval
)
3344 *_rval
= mThreadState
;
3349 jsdThreadState::GetFrameCount (PRUint32
*_rval
)
3351 *_rval
= JSD_GetCountOfStackFrames (mCx
, mThreadState
);
3356 jsdThreadState::GetTopFrame (jsdIStackFrame
**_rval
)
3358 JSDStackFrameInfo
*sfi
= JSD_GetStackFrame (mCx
, mThreadState
);
3360 *_rval
= jsdStackFrame::FromPtr (mCx
, mThreadState
, sfi
);
3365 jsdThreadState::GetPendingException(jsdIValue
**_rval
)
3367 JSDValue
*jsdv
= JSD_GetException (mCx
, mThreadState
);
3369 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
3374 jsdThreadState::SetPendingException(jsdIValue
*aException
)
3378 nsresult rv
= aException
->GetJSDValue (&jsdv
);
3380 return NS_ERROR_FAILURE
;
3382 if (!JSD_SetException (mCx
, mThreadState
, jsdv
))
3383 return NS_ERROR_FAILURE
;