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
;
155 PRUint32 patternLength
;
156 PatternType patternType
;
159 } *gFilters
= nsnull
;
161 static struct LiveEphemeral
*gLiveValues
= nsnull
;
162 static struct LiveEphemeral
*gLiveProperties
= nsnull
;
163 static struct LiveEphemeral
*gLiveContexts
= nsnull
;
164 static struct LiveEphemeral
*gLiveStackFrames
= nsnull
;
166 /*******************************************************************************
167 * utility functions for ephemeral lists
168 *******************************************************************************/
169 already_AddRefed
<jsdIEphemeral
>
170 jsds_FindEphemeral (LiveEphemeral
**listHead
, void *key
)
175 LiveEphemeral
*lv_record
=
176 reinterpret_cast<LiveEphemeral
*>
177 (PR_NEXT_LINK(&(*listHead
)->links
));
180 if (lv_record
->key
== key
)
182 NS_IF_ADDREF(lv_record
->value
);
183 return lv_record
->value
;
185 lv_record
= reinterpret_cast<LiveEphemeral
*>
186 (PR_NEXT_LINK(&lv_record
->links
));
188 while (lv_record
!= *listHead
);
194 jsds_InvalidateAllEphemerals (LiveEphemeral
**listHead
)
196 LiveEphemeral
*lv_record
=
197 reinterpret_cast<LiveEphemeral
*>
198 (PR_NEXT_LINK(&(*listHead
)->links
));
201 LiveEphemeral
*next
=
202 reinterpret_cast<LiveEphemeral
*>
203 (PR_NEXT_LINK(&lv_record
->links
));
204 lv_record
->value
->Invalidate();
210 jsds_InsertEphemeral (LiveEphemeral
**listHead
, LiveEphemeral
*item
)
213 /* if the list exists, add to it */
214 PR_APPEND_LINK(&item
->links
, &(*listHead
)->links
);
216 /* otherwise create the list */
217 PR_INIT_CLIST(&item
->links
);
223 jsds_RemoveEphemeral (LiveEphemeral
**listHead
, LiveEphemeral
*item
)
225 LiveEphemeral
*next
= reinterpret_cast<LiveEphemeral
*>
226 (PR_NEXT_LINK(&item
->links
));
230 /* if the current item is also the next item, we're the only element,
231 * null out the list head */
232 NS_ASSERTION (*listHead
== item
,
233 "How could we not be the head of a one item list?");
236 else if (item
== *listHead
)
238 /* otherwise, if we're currently the list head, change it */
242 PR_REMOVE_AND_INIT_LINK(&item
->links
);
245 /*******************************************************************************
246 * utility functions for filters
247 *******************************************************************************/
249 jsds_FreeFilter (FilterRecord
*filter
)
251 NS_IF_RELEASE (filter
->filterObject
);
252 if (filter
->urlPattern
)
253 nsMemory::Free(filter
->urlPattern
);
257 /* copies appropriate |filter| attributes into |rec|.
258 * False return indicates failure, the contents of |rec| will not be changed.
261 jsds_SyncFilter (FilterRecord
*rec
, jsdIFilter
*filter
)
263 NS_ASSERTION (rec
, "jsds_SyncFilter without rec");
264 NS_ASSERTION (filter
, "jsds_SyncFilter without filter");
266 JSObject
*glob_proper
= nsnull
;
267 nsCOMPtr
<nsISupports
> glob
;
268 nsresult rv
= filter
->GetGlobalObject(getter_AddRefs(glob
));
272 nsCOMPtr
<nsIScriptGlobalObject
> nsiglob
= do_QueryInterface(glob
);
274 glob_proper
= nsiglob
->GetGlobalJSObject();
278 rv
= filter
->GetStartLine(&startLine
);
283 rv
= filter
->GetStartLine(&endLine
);
288 rv
= filter
->GetUrlPattern (&urlPattern
);
293 PRUint32 len
= PL_strlen(urlPattern
);
294 if (urlPattern
[0] == '*') {
295 /* pattern starts with a *, shift all chars once to the left,
296 * including the trailing null. */
297 memmove (&urlPattern
[0], &urlPattern
[1], len
);
299 if (urlPattern
[len
- 2] == '*') {
300 /* pattern is in the format "*foo*", overwrite the final * with
302 urlPattern
[len
- 2] = '\0';
303 rec
->patternType
= ptContains
;
304 rec
->patternLength
= len
- 2;
306 /* pattern is in the format "*foo", just make a note of the
308 rec
->patternType
= ptEndsWith
;
309 rec
->patternLength
= len
- 1;
311 } else if (urlPattern
[len
- 1] == '*') {
312 /* pattern is in the format "foo*", overwrite the final * with a
314 urlPattern
[len
- 1] = '\0';
315 rec
->patternType
= ptStartsWith
;
316 rec
->patternLength
= len
- 1;
318 /* pattern is in the format "foo". */
319 rec
->patternType
= ptEquals
;
320 rec
->patternLength
= len
;
323 rec
->patternType
= ptIgnore
;
324 rec
->patternLength
= 0;
327 /* we got everything we need without failing, now copy it into rec. */
329 if (rec
->filterObject
!= filter
) {
330 NS_IF_RELEASE(rec
->filterObject
);
332 rec
->filterObject
= filter
;
335 rec
->glob
= glob_proper
;
337 rec
->startLine
= startLine
;
338 rec
->endLine
= endLine
;
341 nsMemory::Free (rec
->urlPattern
);
342 rec
->urlPattern
= urlPattern
;
349 jsds_FindFilter (jsdIFilter
*filter
)
354 FilterRecord
*current
= gFilters
;
357 if (current
->filterObject
== filter
)
359 current
= reinterpret_cast<FilterRecord
*>
360 (PR_NEXT_LINK(¤t
->links
));
361 } while (current
!= gFilters
);
366 /* returns true if the hook should be executed. */
368 jsds_FilterHook (JSDContext
*jsdc
, JSDThreadState
*state
)
370 JSContext
*cx
= JSD_GetJSContext (jsdc
, state
);
371 void *glob
= static_cast<void *>(JS_GetGlobalObject (cx
));
374 NS_WARNING("No global in threadstate");
378 JSDStackFrameInfo
*frame
= JSD_GetStackFrame (jsdc
, state
);
381 NS_WARNING("No frame in threadstate");
385 JSDScript
*script
= JSD_GetScriptForStackFrame (jsdc
, state
, frame
);
389 jsuint pc
= JSD_GetPCForStackFrame (jsdc
, state
, frame
);
391 const char *url
= JSD_GetScriptFilename (jsdc
, script
);
393 NS_WARNING ("Script with no filename");
400 PRUint32 currentLine
= JSD_GetClosestLine (jsdc
, script
, pc
);
402 FilterRecord
*currentFilter
= gFilters
;
405 nsresult rv
= currentFilter
->filterObject
->GetFlags(&flags
);
406 NS_ASSERTION(NS_SUCCEEDED(rv
), "Error getting flags for filter");
407 if (flags
& jsdIFilter::FLAG_ENABLED
) {
408 /* if there is no glob, or the globs match */
409 if ((!currentFilter
->glob
|| currentFilter
->glob
== glob
) &&
410 /* and there is no start line, or the start line is before
411 * or equal to the current */
412 (!currentFilter
->startLine
||
413 currentFilter
->startLine
<= currentLine
) &&
414 /* and there is no end line, or the end line is after
415 * or equal to the current */
416 (!currentFilter
->endLine
||
417 currentFilter
->endLine
>= currentLine
)) {
418 /* then we're going to have to compare the url. */
419 if (currentFilter
->patternType
== ptIgnore
)
420 return !!(flags
& jsdIFilter::FLAG_PASS
);
423 len
= PL_strlen(url
);
425 if (len
>= currentFilter
->patternLength
) {
426 switch (currentFilter
->patternType
) {
428 if (!PL_strcmp(currentFilter
->urlPattern
, url
))
429 return !!(flags
& jsdIFilter::FLAG_PASS
);
432 if (!PL_strncmp(currentFilter
->urlPattern
, url
,
433 currentFilter
->patternLength
))
434 return !!(flags
& jsdIFilter::FLAG_PASS
);
437 if (!PL_strcmp(currentFilter
->urlPattern
,
439 currentFilter
->patternLength
]))
440 return !!(flags
& jsdIFilter::FLAG_PASS
);
443 if (PL_strstr(url
, currentFilter
->urlPattern
))
444 return !!(flags
& jsdIFilter::FLAG_PASS
);
447 NS_ASSERTION(0, "Invalid pattern type");
452 currentFilter
= reinterpret_cast<FilterRecord
*>
453 (PR_NEXT_LINK(¤tFilter
->links
));
454 } while (currentFilter
!= gFilters
);
460 /*******************************************************************************
462 *******************************************************************************/
465 jsds_NotifyPendingDeadScripts (JSContext
*cx
)
467 #ifdef CAUTIOUS_SCRIPTHOOK
468 JSRuntime
*rt
= JS_GetRuntime(cx
);
470 jsdService
*jsds
= gJsds
;
472 nsCOMPtr
<jsdIScriptHook
> hook
;
475 jsds
->GetScriptHook (getter_AddRefs(hook
));
479 DeadScript
*deadScripts
= gDeadScripts
;
480 gDeadScripts
= nsnull
;
481 while (deadScripts
) {
482 DeadScript
*ds
= deadScripts
;
483 /* get next deleted script */
484 deadScripts
= reinterpret_cast<DeadScript
*>
485 (PR_NEXT_LINK(&ds
->links
));
486 if (deadScripts
== ds
)
487 deadScripts
= nsnull
;
491 /* tell the user this script has been destroyed */
492 #ifdef CAUTIOUS_SCRIPTHOOK
495 hook
->OnScriptDestroyed (ds
->script
);
496 #ifdef CAUTIOUS_SCRIPTHOOK
501 /* take it out of the circular list */
502 PR_REMOVE_LINK(&ds
->links
);
504 /* addref came from the FromPtr call in jsds_ScriptHookProc */
505 NS_RELEASE(ds
->script
);
506 /* free the struct! */
511 jsds
->UnPause(nsnull
);
517 jsds_GCCallbackProc (JSContext
*cx
, JSGCStatus status
)
520 printf ("new gc status is %i\n", status
);
522 if (status
== JSGC_END
) {
523 /* just to guard against reentering. */
524 gGCStatus
= JSGC_BEGIN
;
526 jsds_NotifyPendingDeadScripts (cx
);
531 return gLastGCProc (cx
, status
);
537 jsds_ErrorHookProc (JSDContext
*jsdc
, JSContext
*cx
, const char *message
,
538 JSErrorReport
*report
, void *callerdata
)
540 static PRBool running
= PR_FALSE
;
542 nsCOMPtr
<jsdIErrorHook
> hook
;
543 gJsds
->GetErrorHook(getter_AddRefs(hook
));
545 return JSD_ERROR_REPORTER_PASS_ALONG
;
548 return JSD_ERROR_REPORTER_PASS_ALONG
;
552 nsCOMPtr
<jsdIValue
> val
;
553 if (JS_IsExceptionPending(cx
)) {
555 JS_GetPendingException(cx
, &jv
);
556 JSDValue
*jsdv
= JSD_NewValue (jsdc
, jv
);
557 val
= getter_AddRefs(jsdValue::FromPtr(jsdc
, jsdv
));
560 const char *fileName
;
567 fileName
= report
->filename
;
568 line
= report
->lineno
;
569 pos
= report
->tokenptr
- report
->linebuf
;
570 flags
= report
->flags
;
571 errnum
= report
->errorNumber
;
582 gJsds
->Pause(nsnull
);
583 hook
->OnError (message
, fileName
, line
, pos
, flags
, errnum
, val
, &rval
);
584 gJsds
->UnPause(nsnull
);
588 return JSD_ERROR_REPORTER_DEBUG
;
590 return JSD_ERROR_REPORTER_PASS_ALONG
;
594 jsds_CallHookProc (JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
,
595 uintN type
, void* callerdata
)
597 nsCOMPtr
<jsdICallHook
> hook
;
601 case JSD_HOOK_TOPLEVEL_START
:
602 case JSD_HOOK_TOPLEVEL_END
:
603 gJsds
->GetTopLevelHook(getter_AddRefs(hook
));
606 case JSD_HOOK_FUNCTION_CALL
:
607 case JSD_HOOK_FUNCTION_RETURN
:
608 gJsds
->GetFunctionHook(getter_AddRefs(hook
));
612 NS_ASSERTION (0, "Unknown hook type.");
618 if (!jsds_FilterHook (jsdc
, jsdthreadstate
))
621 JSDStackFrameInfo
*native_frame
= JSD_GetStackFrame (jsdc
, jsdthreadstate
);
622 nsCOMPtr
<jsdIStackFrame
> frame
=
623 getter_AddRefs(jsdStackFrame::FromPtr(jsdc
, jsdthreadstate
,
625 gJsds
->Pause(nsnull
);
626 hook
->OnCall(frame
, type
);
627 gJsds
->UnPause(nsnull
);
628 jsdStackFrame::InvalidateAll();
634 jsds_ExecutionHookProc (JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
,
635 uintN type
, void* callerdata
, jsval
* rval
)
637 nsCOMPtr
<jsdIExecutionHook
> hook(0);
638 PRUint32 hook_rv
= JSD_HOOK_RETURN_CONTINUE
;
639 nsCOMPtr
<jsdIValue
> js_rv
;
643 case JSD_HOOK_INTERRUPTED
:
644 gJsds
->GetInterruptHook(getter_AddRefs(hook
));
646 case JSD_HOOK_DEBUG_REQUESTED
:
647 gJsds
->GetDebugHook(getter_AddRefs(hook
));
649 case JSD_HOOK_DEBUGGER_KEYWORD
:
650 gJsds
->GetDebuggerHook(getter_AddRefs(hook
));
652 case JSD_HOOK_BREAKPOINT
:
654 /* we can't pause breakpoints the way we pause the other
655 * execution hooks (at least, not easily.) Instead we bail
656 * here if the service is paused. */
658 gJsds
->GetPauseDepth(&level
);
660 gJsds
->GetBreakpointHook(getter_AddRefs(hook
));
665 hook_rv
= JSD_HOOK_RETURN_CONTINUE_THROW
;
666 gJsds
->GetThrowHook(getter_AddRefs(hook
));
668 JSDValue
*jsdv
= JSD_GetException (jsdc
, jsdthreadstate
);
669 js_rv
= getter_AddRefs(jsdValue::FromPtr (jsdc
, jsdv
));
674 NS_ASSERTION (0, "Unknown hook type.");
680 if (!jsds_FilterHook (jsdc
, jsdthreadstate
))
681 return JSD_HOOK_RETURN_CONTINUE
;
683 JSDStackFrameInfo
*native_frame
= JSD_GetStackFrame (jsdc
, jsdthreadstate
);
684 nsCOMPtr
<jsdIStackFrame
> frame
=
685 getter_AddRefs(jsdStackFrame::FromPtr(jsdc
, jsdthreadstate
,
687 gJsds
->Pause(nsnull
);
688 jsdIValue
*inout_rv
= js_rv
;
689 NS_IF_ADDREF(inout_rv
);
690 hook
->OnExecute (frame
, type
, &inout_rv
, &hook_rv
);
692 NS_IF_RELEASE(inout_rv
);
693 gJsds
->UnPause(nsnull
);
694 jsdStackFrame::InvalidateAll();
696 if (hook_rv
== JSD_HOOK_RETURN_RET_WITH_VAL
||
697 hook_rv
== JSD_HOOK_RETURN_THROW_WITH_VAL
) {
701 if (NS_SUCCEEDED(js_rv
->GetJSDValue (&jsdv
)))
702 *rval
= JSD_GetValueWrappedJSVal(jsdc
, jsdv
);
710 jsds_ScriptHookProc (JSDContext
* jsdc
, JSDScript
* jsdscript
, JSBool creating
,
713 #ifdef CAUTIOUS_SCRIPTHOOK
714 JSContext
*cx
= JSD_GetDefaultJSContext(jsdc
);
715 JSRuntime
*rt
= JS_GetRuntime(cx
);
718 nsCOMPtr
<jsdIScriptHook
> hook
;
719 gJsds
->GetScriptHook (getter_AddRefs(hook
));
722 /* a script is being created */
724 /* nobody cares, just exit */
728 nsCOMPtr
<jsdIScript
> script
=
729 getter_AddRefs(jsdScript::FromPtr(jsdc
, jsdscript
));
730 #ifdef CAUTIOUS_SCRIPTHOOK
733 gJsds
->Pause(nsnull
);
734 hook
->OnScriptCreated (script
);
735 gJsds
->UnPause(nsnull
);
736 #ifdef CAUTIOUS_SCRIPTHOOK
740 /* a script is being destroyed. even if there is no registered hook
741 * we'll still need to invalidate the jsdIScript record, in order
742 * to remove the reference held in the JSDScript private data. */
743 nsCOMPtr
<jsdIScript
> jsdis
=
744 static_cast<jsdIScript
*>(JSD_GetScriptPrivate(jsdscript
));
752 if (gGCStatus
== JSGC_END
) {
753 /* if GC *isn't* running, we can tell the user about the script
755 #ifdef CAUTIOUS_SCRIPTHOOK
759 gJsds
->Pause(nsnull
);
760 hook
->OnScriptDestroyed (jsdis
);
761 gJsds
->UnPause(nsnull
);
762 #ifdef CAUTIOUS_SCRIPTHOOK
766 /* if a GC *is* running, we've got to wait until it's done before
767 * we can execute any JS, so we queue the notification in a PRCList
768 * until GC tells us it's done. See jsds_GCCallbackProc(). */
769 DeadScript
*ds
= PR_NEW(DeadScript
);
771 return; /* NS_ERROR_OUT_OF_MEMORY */
775 NS_ADDREF(ds
->script
);
777 /* if the queue exists, add to it */
778 PR_APPEND_LINK(&ds
->links
, &gDeadScripts
->links
);
780 /* otherwise create the queue */
781 PR_INIT_CLIST(&ds
->links
);
788 /*******************************************************************************
789 * reflected jsd data structures
790 *******************************************************************************/
794 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral);
797 jsdContext::GetJSDContext(JSDContext **_rval)
805 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject
, jsdIObject
)
808 jsdObject::GetJSDContext(JSDContext
**_rval
)
815 jsdObject::GetJSDObject(JSDObject
**_rval
)
822 jsdObject::GetCreatorURL(char **_rval
)
824 const char *url
= JSD_GetObjectNewURL(mCx
, mObject
);
826 *_rval
= PL_strdup(url
);
828 return NS_ERROR_OUT_OF_MEMORY
;
836 jsdObject::GetCreatorLine(PRUint32
*_rval
)
838 *_rval
= JSD_GetObjectNewLineNumber(mCx
, mObject
);
843 jsdObject::GetConstructorURL(char **_rval
)
845 const char *url
= JSD_GetObjectConstructorURL(mCx
, mObject
);
847 *_rval
= PL_strdup(url
);
849 return NS_ERROR_OUT_OF_MEMORY
;
857 jsdObject::GetConstructorLine(PRUint32
*_rval
)
859 *_rval
= JSD_GetObjectConstructorLineNumber(mCx
, mObject
);
864 jsdObject::GetValue(jsdIValue
**_rval
)
866 JSDValue
*jsdv
= JSD_GetValueForObject (mCx
, mObject
);
868 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
873 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty
, jsdIProperty
, jsdIEphemeral
)
875 jsdProperty::jsdProperty (JSDContext
*aCx
, JSDProperty
*aProperty
) :
876 mCx(aCx
), mProperty(aProperty
)
878 DEBUG_CREATE ("jsdProperty", gPropertyCount
);
879 mValid
= (aCx
&& aProperty
);
880 mLiveListEntry
.value
= this;
881 jsds_InsertEphemeral (&gLiveProperties
, &mLiveListEntry
);
884 jsdProperty::~jsdProperty ()
886 DEBUG_DESTROY ("jsdProperty", gPropertyCount
);
892 jsdProperty::Invalidate()
894 ASSERT_VALID_EPHEMERAL
;
896 jsds_RemoveEphemeral (&gLiveProperties
, &mLiveListEntry
);
897 JSD_DropProperty (mCx
, mProperty
);
902 jsdProperty::InvalidateAll()
905 jsds_InvalidateAllEphemerals (&gLiveProperties
);
909 jsdProperty::GetJSDContext(JSDContext
**_rval
)
916 jsdProperty::GetJSDProperty(JSDProperty
**_rval
)
923 jsdProperty::GetIsValid(PRBool
*_rval
)
930 jsdProperty::GetAlias(jsdIValue
**_rval
)
932 JSDValue
*jsdv
= JSD_GetPropertyValue (mCx
, mProperty
);
934 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
939 jsdProperty::GetFlags(PRUint32
*_rval
)
941 *_rval
= JSD_GetPropertyFlags (mCx
, mProperty
);
946 jsdProperty::GetName(jsdIValue
**_rval
)
948 JSDValue
*jsdv
= JSD_GetPropertyName (mCx
, mProperty
);
950 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
955 jsdProperty::GetValue(jsdIValue
**_rval
)
957 JSDValue
*jsdv
= JSD_GetPropertyValue (mCx
, mProperty
);
959 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
964 jsdProperty::GetVarArgSlot(PRUint32
*_rval
)
966 *_rval
= JSD_GetPropertyVarArgSlot (mCx
, mProperty
);
971 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript
, jsdIScript
, jsdIEphemeral
)
973 jsdScript::jsdScript (JSDContext
*aCx
, JSDScript
*aScript
) : mValid(PR_FALSE
),
984 DEBUG_CREATE ("jsdScript", gScriptCount
);
987 /* copy the script's information now, so we have it later, when it
989 JSD_LockScriptSubsystem(mCx
);
990 mFileName
= new nsCString(JSD_GetScriptFilename(mCx
, mScript
));
992 new nsCString(JSD_GetScriptFunctionName(mCx
, mScript
));
993 mBaseLineNumber
= JSD_GetScriptBaseLineNumber(mCx
, mScript
);
994 mLineExtent
= JSD_GetScriptLineExtent(mCx
, mScript
);
995 mFirstPC
= JSD_GetClosestPC(mCx
, mScript
, 0);
996 JSD_UnlockScriptSubsystem(mCx
);
1002 jsdScript::~jsdScript ()
1004 DEBUG_DESTROY ("jsdScript", gScriptCount
);
1008 delete mFunctionName
;
1011 PR_Free(mPPLineMap
);
1013 /* Invalidate() needs to be called to release an owning reference to
1014 * ourselves, so if we got here without being invalidated, something
1015 * has gone wrong with our ref count. */
1016 NS_ASSERTION (!mValid
, "Script destroyed without being invalidated.");
1020 * This method populates a line <-> pc map for a pretty printed version of this
1021 * script. It does this by decompiling, and then recompiling the script. The
1022 * resulting script is scanned for the line map, and then left as GC fodder.
1025 jsdScript::CreatePPLineMap()
1027 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
1028 JSAutoRequest
ar(cx
);
1029 JSObject
*obj
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
1030 JSFunction
*fun
= JSD_GetJSFunction (mCx
, mScript
);
1033 PRBool scriptOwner
= PR_FALSE
;
1036 if (fun
->nargs
> 12)
1038 JSString
*jsstr
= JS_DecompileFunctionBody (cx
, fun
, 4);
1042 const char *argnames
[] = {"arg1", "arg2", "arg3", "arg4",
1043 "arg5", "arg6", "arg7", "arg8",
1044 "arg9", "arg10", "arg11", "arg12" };
1045 fun
= JS_CompileUCFunction (cx
, obj
, "ppfun", fun
->nargs
, argnames
,
1046 JS_GetStringChars(jsstr
),
1047 JS_GetStringLength(jsstr
),
1048 "x-jsd:ppbuffer?type=function", 3);
1049 if (!fun
|| !(script
= JS_GetFunctionScript(cx
, fun
)))
1053 JSString
*jsstr
= JS_DecompileScript (cx
, JSD_GetJSScript(mCx
, mScript
),
1058 script
= JS_CompileUCScript (cx
, obj
,
1059 JS_GetStringChars(jsstr
),
1060 JS_GetStringLength(jsstr
),
1061 "x-jsd:ppbuffer?type=script", 1);
1064 scriptOwner
= PR_TRUE
;
1068 PRUint32 scriptExtent
= JS_GetScriptLineExtent (cx
, script
);
1069 jsbytecode
* firstPC
= JS_LineNumberToPC (cx
, script
, 0);
1070 /* allocate worst case size of map (number of lines in script + 1
1071 * for our 0 record), we'll shrink it with a realloc later. */
1073 static_cast<PCMapEntry
*>
1074 (PR_Malloc((scriptExtent
+ 1) * sizeof (PCMapEntry
)));
1077 for (PRUint32 line
= baseLine
; line
< scriptExtent
+ baseLine
; ++line
) {
1078 jsbytecode
* pc
= JS_LineNumberToPC (cx
, script
, line
);
1079 if (line
== JS_PCToLineNumber (cx
, script
, pc
)) {
1080 mPPLineMap
[mPCMapSize
].line
= line
;
1081 mPPLineMap
[mPCMapSize
].pc
= pc
- firstPC
;
1085 if (scriptExtent
!= mPCMapSize
) {
1087 static_cast<PCMapEntry
*>
1088 (PR_Realloc(mPPLineMap
,
1089 mPCMapSize
* sizeof(PCMapEntry
)));
1094 JS_DestroyScript (cx
, script
);
1100 jsdScript::PPPcToLine (PRUint32 aPC
)
1102 if (!mPPLineMap
&& !CreatePPLineMap())
1105 for (i
= 1; i
< mPCMapSize
; ++i
) {
1106 if (mPPLineMap
[i
].pc
> aPC
)
1107 return mPPLineMap
[i
- 1].line
;
1110 return mPPLineMap
[mPCMapSize
- 1].line
;
1114 jsdScript::PPLineToPc (PRUint32 aLine
)
1116 if (!mPPLineMap
&& !CreatePPLineMap())
1119 for (i
= 1; i
< mPCMapSize
; ++i
) {
1120 if (mPPLineMap
[i
].line
> aLine
)
1121 return mPPLineMap
[i
- 1].pc
;
1124 return mPPLineMap
[mPCMapSize
- 1].pc
;
1128 jsdScript::GetJSDContext(JSDContext
**_rval
)
1130 ASSERT_VALID_EPHEMERAL
;
1136 jsdScript::GetJSDScript(JSDScript
**_rval
)
1138 ASSERT_VALID_EPHEMERAL
;
1144 jsdScript::GetVersion (PRInt32
*_rval
)
1146 ASSERT_VALID_EPHEMERAL
;
1147 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
1148 JSScript
*script
= JSD_GetJSScript(mCx
, mScript
);
1149 *_rval
= static_cast<PRInt32
>(JS_GetScriptVersion(cx
, script
));
1154 jsdScript::GetTag(PRUint32
*_rval
)
1157 mTag
= ++jsdScript::LastTag
;
1164 jsdScript::Invalidate()
1166 ASSERT_VALID_EPHEMERAL
;
1169 /* release the addref we do in FromPtr */
1170 jsdIScript
*script
= static_cast<jsdIScript
*>
1171 (JSD_GetScriptPrivate(mScript
));
1172 NS_ASSERTION (script
== this, "That's not my script!");
1174 JSD_SetScriptPrivate(mScript
, NULL
);
1179 jsdScript::InvalidateAll ()
1182 if (NS_FAILED(gJsds
->GetJSDContext (&cx
)))
1186 JSDScript
*iter
= NULL
;
1188 JSD_LockScriptSubsystem(cx
);
1189 while((script
= JSD_IterateScripts(cx
, &iter
)) != NULL
) {
1190 nsCOMPtr
<jsdIScript
> jsdis
=
1191 static_cast<jsdIScript
*>(JSD_GetScriptPrivate(script
));
1193 jsdis
->Invalidate();
1195 JSD_UnlockScriptSubsystem(cx
);
1199 jsdScript::GetIsValid(PRBool
*_rval
)
1206 jsdScript::SetFlags(PRUint32 flags
)
1208 ASSERT_VALID_EPHEMERAL
;
1209 JSD_SetScriptFlags(mCx
, mScript
, flags
);
1214 jsdScript::GetFlags(PRUint32
*_rval
)
1216 ASSERT_VALID_EPHEMERAL
;
1217 *_rval
= JSD_GetScriptFlags(mCx
, mScript
);
1222 jsdScript::GetFileName(char **_rval
)
1224 *_rval
= ToNewCString(*mFileName
);
1226 return NS_ERROR_OUT_OF_MEMORY
;
1231 jsdScript::GetFunctionName(char **_rval
)
1233 *_rval
= ToNewCString(*mFunctionName
);
1235 return NS_ERROR_OUT_OF_MEMORY
;
1240 jsdScript::GetFunctionObject(jsdIValue
**_rval
)
1242 JSFunction
*fun
= JSD_GetJSFunction(mCx
, mScript
);
1244 return NS_ERROR_NOT_AVAILABLE
;
1246 JSObject
*obj
= JS_GetFunctionObject(fun
);
1248 return NS_ERROR_FAILURE
;
1251 if (NS_FAILED(gJsds
->GetJSDContext (&cx
)))
1252 return NS_ERROR_NOT_INITIALIZED
;
1254 JSDValue
*jsdv
= JSD_NewValue(cx
, OBJECT_TO_JSVAL(obj
));
1256 return NS_ERROR_OUT_OF_MEMORY
;
1258 *_rval
= jsdValue::FromPtr(cx
, jsdv
);
1260 JSD_DropValue(cx
, jsdv
);
1261 return NS_ERROR_OUT_OF_MEMORY
;
1268 jsdScript::GetFunctionSource(nsAString
& aFunctionSource
)
1270 ASSERT_VALID_EPHEMERAL
;
1271 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
1273 NS_WARNING("No default context !?");
1274 return NS_ERROR_FAILURE
;
1276 JSFunction
*fun
= JSD_GetJSFunction (mCx
, mScript
);
1278 JSAutoRequest
ar(cx
);
1282 jsstr
= JS_DecompileFunction (cx
, fun
, 4);
1284 JSScript
*script
= JSD_GetJSScript (mCx
, mScript
);
1285 jsstr
= JS_DecompileScript (cx
, script
, "ppscript", 4);
1288 return NS_ERROR_FAILURE
;
1290 aFunctionSource
= reinterpret_cast<PRUnichar
*>(JS_GetStringChars(jsstr
));
1295 jsdScript::GetBaseLineNumber(PRUint32
*_rval
)
1297 *_rval
= mBaseLineNumber
;
1302 jsdScript::GetLineExtent(PRUint32
*_rval
)
1304 *_rval
= mLineExtent
;
1309 jsdScript::GetCallCount(PRUint32
*_rval
)
1311 ASSERT_VALID_EPHEMERAL
;
1312 *_rval
= JSD_GetScriptCallCount (mCx
, mScript
);
1317 jsdScript::GetMaxRecurseDepth(PRUint32
*_rval
)
1319 ASSERT_VALID_EPHEMERAL
;
1320 *_rval
= JSD_GetScriptMaxRecurseDepth (mCx
, mScript
);
1325 jsdScript::GetMinExecutionTime(double *_rval
)
1327 ASSERT_VALID_EPHEMERAL
;
1328 *_rval
= JSD_GetScriptMinExecutionTime (mCx
, mScript
);
1333 jsdScript::GetMaxExecutionTime(double *_rval
)
1335 ASSERT_VALID_EPHEMERAL
;
1336 *_rval
= JSD_GetScriptMaxExecutionTime (mCx
, mScript
);
1341 jsdScript::GetTotalExecutionTime(double *_rval
)
1343 ASSERT_VALID_EPHEMERAL
;
1344 *_rval
= JSD_GetScriptTotalExecutionTime (mCx
, mScript
);
1349 jsdScript::GetMinOwnExecutionTime(double *_rval
)
1351 ASSERT_VALID_EPHEMERAL
;
1352 *_rval
= JSD_GetScriptMinOwnExecutionTime (mCx
, mScript
);
1357 jsdScript::GetMaxOwnExecutionTime(double *_rval
)
1359 ASSERT_VALID_EPHEMERAL
;
1360 *_rval
= JSD_GetScriptMaxOwnExecutionTime (mCx
, mScript
);
1365 jsdScript::GetTotalOwnExecutionTime(double *_rval
)
1367 ASSERT_VALID_EPHEMERAL
;
1368 *_rval
= JSD_GetScriptTotalOwnExecutionTime (mCx
, mScript
);
1373 jsdScript::ClearProfileData()
1375 ASSERT_VALID_EPHEMERAL
;
1376 JSD_ClearScriptProfileData(mCx
, mScript
);
1381 jsdScript::PcToLine(PRUint32 aPC
, PRUint32 aPcmap
, PRUint32
*_rval
)
1383 ASSERT_VALID_EPHEMERAL
;
1384 if (aPcmap
== PCMAP_SOURCETEXT
) {
1385 *_rval
= JSD_GetClosestLine (mCx
, mScript
, mFirstPC
+ aPC
);
1386 } else if (aPcmap
== PCMAP_PRETTYPRINT
) {
1387 *_rval
= PPPcToLine(aPC
);
1389 return NS_ERROR_INVALID_ARG
;
1396 jsdScript::LineToPc(PRUint32 aLine
, PRUint32 aPcmap
, PRUint32
*_rval
)
1398 ASSERT_VALID_EPHEMERAL
;
1399 if (aPcmap
== PCMAP_SOURCETEXT
) {
1400 jsuword pc
= JSD_GetClosestPC (mCx
, mScript
, aLine
);
1401 *_rval
= pc
- mFirstPC
;
1402 } else if (aPcmap
== PCMAP_PRETTYPRINT
) {
1403 *_rval
= PPLineToPc(aLine
);
1405 return NS_ERROR_INVALID_ARG
;
1412 jsdScript::IsLineExecutable(PRUint32 aLine
, PRUint32 aPcmap
, PRBool
*_rval
)
1414 ASSERT_VALID_EPHEMERAL
;
1415 if (aPcmap
== PCMAP_SOURCETEXT
) {
1416 jsuword pc
= JSD_GetClosestPC (mCx
, mScript
, aLine
);
1417 *_rval
= (aLine
== JSD_GetClosestLine (mCx
, mScript
, pc
));
1418 } else if (aPcmap
== PCMAP_PRETTYPRINT
) {
1419 if (!mPPLineMap
&& !CreatePPLineMap())
1420 return NS_ERROR_FAILURE
;
1422 for (PRUint32 i
= 0; i
< mPCMapSize
; ++i
) {
1423 if (mPPLineMap
[i
].line
>= aLine
) {
1424 *_rval
= (mPPLineMap
[i
].line
== aLine
);
1429 return NS_ERROR_INVALID_ARG
;
1436 jsdScript::SetBreakpoint(PRUint32 aPC
)
1438 ASSERT_VALID_EPHEMERAL
;
1439 jsuword pc
= mFirstPC
+ aPC
;
1440 JSD_SetExecutionHook (mCx
, mScript
, pc
, jsds_ExecutionHookProc
,
1441 reinterpret_cast<void *>(PRIVATE_TO_JSVAL(NULL
)));
1446 jsdScript::ClearBreakpoint(PRUint32 aPC
)
1448 ASSERT_VALID_EPHEMERAL
;
1449 jsuword pc
= mFirstPC
+ aPC
;
1450 JSD_ClearExecutionHook (mCx
, mScript
, pc
);
1455 jsdScript::ClearAllBreakpoints()
1457 ASSERT_VALID_EPHEMERAL
;
1458 JSD_LockScriptSubsystem(mCx
);
1459 JSD_ClearAllExecutionHooksForScript (mCx
, mScript
);
1460 JSD_UnlockScriptSubsystem(mCx
);
1465 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext
, jsdIContext
, jsdIEphemeral
)
1468 jsdContext::FromPtr (JSDContext
*aJSDCx
, JSContext
*aJSCx
)
1470 if (!aJSDCx
|| !aJSCx
||
1471 !(JS_GetOptions(aJSCx
) & JSOPTION_PRIVATE_IS_NSISUPPORTS
))
1476 nsCOMPtr
<jsdIContext
> jsdicx
;
1477 nsCOMPtr
<jsdIEphemeral
> eph
=
1478 jsds_FindEphemeral (&gLiveContexts
, static_cast<void *>(aJSCx
));
1481 jsdicx
= do_QueryInterface(eph
);
1485 nsCOMPtr
<nsISupports
> iscx
=
1486 static_cast<nsISupports
*>(JS_GetContextPrivate(aJSCx
));
1490 jsdicx
= new jsdContext (aJSDCx
, aJSCx
, iscx
);
1493 jsdIContext
*rv
= jsdicx
;
1498 jsdContext::jsdContext (JSDContext
*aJSDCx
, JSContext
*aJSCx
,
1499 nsISupports
*aISCx
) : mValid(PR_TRUE
), mTag(0),
1501 mJSCx(aJSCx
), mISCx(aISCx
)
1503 DEBUG_CREATE ("jsdContext", gContextCount
);
1504 mLiveListEntry
.value
= this;
1505 mLiveListEntry
.key
= static_cast<void *>(aJSCx
);
1506 jsds_InsertEphemeral (&gLiveContexts
, &mLiveListEntry
);
1509 jsdContext::~jsdContext()
1511 DEBUG_DESTROY ("jsdContext", gContextCount
);
1514 /* call Invalidate() to take ourselves out of the live list */
1520 jsdContext::GetIsValid(PRBool
*_rval
)
1527 jsdContext::Invalidate()
1529 ASSERT_VALID_EPHEMERAL
;
1531 jsds_RemoveEphemeral (&gLiveContexts
, &mLiveListEntry
);
1536 jsdContext::InvalidateAll()
1539 jsds_InvalidateAllEphemerals (&gLiveContexts
);
1543 jsdContext::GetJSContext(JSContext
**_rval
)
1545 ASSERT_VALID_EPHEMERAL
;
1551 jsdContext::GetOptions(PRUint32
*_rval
)
1553 ASSERT_VALID_EPHEMERAL
;
1554 *_rval
= JS_GetOptions(mJSCx
);
1559 jsdContext::SetOptions(PRUint32 options
)
1561 ASSERT_VALID_EPHEMERAL
;
1562 PRUint32 lastOptions
= JS_GetOptions(mJSCx
);
1564 /* don't let users change this option, they'd just be shooting themselves
1566 if ((options
^ lastOptions
) & JSOPTION_PRIVATE_IS_NSISUPPORTS
)
1567 return NS_ERROR_ILLEGAL_VALUE
;
1569 JS_SetOptions(mJSCx
, options
);
1574 jsdContext::GetPrivateData(nsISupports
**_rval
)
1576 ASSERT_VALID_EPHEMERAL
;
1577 PRUint32 options
= JS_GetOptions(mJSCx
);
1578 if (options
& JSOPTION_PRIVATE_IS_NSISUPPORTS
)
1580 *_rval
= static_cast<nsISupports
*>(JS_GetContextPrivate(mJSCx
));
1581 NS_IF_ADDREF(*_rval
);
1592 jsdContext::GetWrappedContext(nsISupports
**_rval
)
1594 ASSERT_VALID_EPHEMERAL
;
1596 NS_IF_ADDREF(*_rval
);
1601 jsdContext::GetTag(PRUint32
*_rval
)
1603 ASSERT_VALID_EPHEMERAL
;
1605 mTag
= ++jsdContext::LastTag
;
1612 jsdContext::GetVersion (PRInt32
*_rval
)
1614 ASSERT_VALID_EPHEMERAL
;
1615 *_rval
= static_cast<PRInt32
>(JS_GetVersion(mJSCx
));
1620 jsdContext::SetVersion (PRInt32 id
)
1622 ASSERT_VALID_EPHEMERAL
;
1623 JSVersion ver
= static_cast<JSVersion
>(id
);
1624 JS_SetVersion(mJSCx
, ver
);
1629 jsdContext::GetGlobalObject (jsdIValue
**_rval
)
1631 ASSERT_VALID_EPHEMERAL
;
1632 JSObject
*glob
= JS_GetGlobalObject(mJSCx
);
1633 JSDValue
*jsdv
= JSD_NewValue (mJSDCx
, OBJECT_TO_JSVAL(glob
));
1635 return NS_ERROR_FAILURE
;
1636 *_rval
= jsdValue::FromPtr (mJSDCx
, jsdv
);
1638 return NS_ERROR_FAILURE
;
1643 jsdContext::GetScriptsEnabled (PRBool
*_rval
)
1645 ASSERT_VALID_EPHEMERAL
;
1646 nsCOMPtr
<nsIScriptContext
> context
= do_QueryInterface(mISCx
);
1648 return NS_ERROR_NO_INTERFACE
;
1650 *_rval
= context
->GetScriptsEnabled();
1656 jsdContext::SetScriptsEnabled (PRBool _rval
)
1658 ASSERT_VALID_EPHEMERAL
;
1659 nsCOMPtr
<nsIScriptContext
> context
= do_QueryInterface(mISCx
);
1661 return NS_ERROR_NO_INTERFACE
;
1663 context
->SetScriptsEnabled(_rval
, PR_TRUE
);
1669 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame
, jsdIStackFrame
, jsdIEphemeral
)
1671 jsdStackFrame::jsdStackFrame (JSDContext
*aCx
, JSDThreadState
*aThreadState
,
1672 JSDStackFrameInfo
*aStackFrameInfo
) :
1673 mCx(aCx
), mThreadState(aThreadState
), mStackFrameInfo(aStackFrameInfo
)
1675 DEBUG_CREATE ("jsdStackFrame", gFrameCount
);
1676 mValid
= (aCx
&& aThreadState
&& aStackFrameInfo
);
1678 mLiveListEntry
.key
= aStackFrameInfo
;
1679 mLiveListEntry
.value
= this;
1680 jsds_InsertEphemeral (&gLiveStackFrames
, &mLiveListEntry
);
1684 jsdStackFrame::~jsdStackFrame()
1686 DEBUG_DESTROY ("jsdStackFrame", gFrameCount
);
1689 /* call Invalidate() to take ourselves out of the live list */
1695 jsdStackFrame::FromPtr (JSDContext
*aCx
, JSDThreadState
*aThreadState
,
1696 JSDStackFrameInfo
*aStackFrameInfo
)
1698 if (!aStackFrameInfo
)
1702 nsCOMPtr
<jsdIStackFrame
> frame
;
1704 nsCOMPtr
<jsdIEphemeral
> eph
=
1705 jsds_FindEphemeral (&gLiveStackFrames
,
1706 reinterpret_cast<void *>(aStackFrameInfo
));
1710 frame
= do_QueryInterface(eph
);
1715 rv
= new jsdStackFrame (aCx
, aThreadState
, aStackFrameInfo
);
1723 jsdStackFrame::Invalidate()
1725 ASSERT_VALID_EPHEMERAL
;
1727 jsds_RemoveEphemeral (&gLiveStackFrames
, &mLiveListEntry
);
1732 jsdStackFrame::InvalidateAll()
1734 if (gLiveStackFrames
)
1735 jsds_InvalidateAllEphemerals (&gLiveStackFrames
);
1739 jsdStackFrame::GetJSDContext(JSDContext
**_rval
)
1741 ASSERT_VALID_EPHEMERAL
;
1747 jsdStackFrame::GetJSDThreadState(JSDThreadState
**_rval
)
1749 ASSERT_VALID_EPHEMERAL
;
1750 *_rval
= mThreadState
;
1755 jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo
**_rval
)
1757 ASSERT_VALID_EPHEMERAL
;
1758 *_rval
= mStackFrameInfo
;
1763 jsdStackFrame::GetIsValid(PRBool
*_rval
)
1770 jsdStackFrame::GetCallingFrame(jsdIStackFrame
**_rval
)
1772 ASSERT_VALID_EPHEMERAL
;
1773 JSDStackFrameInfo
*sfi
= JSD_GetCallingStackFrame (mCx
, mThreadState
,
1775 *_rval
= jsdStackFrame::FromPtr (mCx
, mThreadState
, sfi
);
1780 jsdStackFrame::GetExecutionContext(jsdIContext
**_rval
)
1782 ASSERT_VALID_EPHEMERAL
;
1783 JSContext
*cx
= JSD_GetJSContext (mCx
, mThreadState
);
1784 *_rval
= jsdContext::FromPtr (mCx
, cx
);
1789 jsdStackFrame::GetFunctionName(char **_rval
)
1791 ASSERT_VALID_EPHEMERAL
;
1792 const char *name
= JSD_GetNameForStackFrame(mCx
, mThreadState
,
1795 *_rval
= PL_strdup(name
);
1797 return NS_ERROR_OUT_OF_MEMORY
;
1799 /* top level scripts have no function name */
1807 jsdStackFrame::GetIsNative(PRBool
*_rval
)
1809 ASSERT_VALID_EPHEMERAL
;
1810 *_rval
= JSD_IsStackFrameNative (mCx
, mThreadState
, mStackFrameInfo
);
1815 jsdStackFrame::GetIsDebugger(PRBool
*_rval
)
1817 ASSERT_VALID_EPHEMERAL
;
1818 *_rval
= JSD_IsStackFrameDebugger (mCx
, mThreadState
, mStackFrameInfo
);
1823 jsdStackFrame::GetIsConstructing(PRBool
*_rval
)
1825 ASSERT_VALID_EPHEMERAL
;
1826 *_rval
= JSD_IsStackFrameConstructing (mCx
, mThreadState
, mStackFrameInfo
);
1831 jsdStackFrame::GetScript(jsdIScript
**_rval
)
1833 ASSERT_VALID_EPHEMERAL
;
1834 JSDScript
*script
= JSD_GetScriptForStackFrame (mCx
, mThreadState
,
1836 *_rval
= jsdScript::FromPtr (mCx
, script
);
1841 jsdStackFrame::GetPc(PRUint32
*_rval
)
1843 ASSERT_VALID_EPHEMERAL
;
1844 JSDScript
*script
= JSD_GetScriptForStackFrame (mCx
, mThreadState
,
1847 return NS_ERROR_FAILURE
;
1848 jsuword pcbase
= JSD_GetClosestPC(mCx
, script
, 0);
1850 jsuword pc
= JSD_GetPCForStackFrame (mCx
, mThreadState
, mStackFrameInfo
);
1852 *_rval
= pc
- pcbase
;
1859 jsdStackFrame::GetLine(PRUint32
*_rval
)
1861 ASSERT_VALID_EPHEMERAL
;
1862 JSDScript
*script
= JSD_GetScriptForStackFrame (mCx
, mThreadState
,
1865 jsuword pc
= JSD_GetPCForStackFrame (mCx
, mThreadState
, mStackFrameInfo
);
1866 *_rval
= JSD_GetClosestLine (mCx
, script
, pc
);
1868 if (!JSD_IsStackFrameNative(mCx
, mThreadState
, mStackFrameInfo
))
1869 return NS_ERROR_FAILURE
;
1876 jsdStackFrame::GetCallee(jsdIValue
**_rval
)
1878 ASSERT_VALID_EPHEMERAL
;
1879 JSDValue
*jsdv
= JSD_GetCallObjectForStackFrame (mCx
, mThreadState
,
1882 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
1887 jsdStackFrame::GetScope(jsdIValue
**_rval
)
1889 ASSERT_VALID_EPHEMERAL
;
1890 JSDValue
*jsdv
= JSD_GetScopeChainForStackFrame (mCx
, mThreadState
,
1893 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
1898 jsdStackFrame::GetThisValue(jsdIValue
**_rval
)
1900 ASSERT_VALID_EPHEMERAL
;
1901 JSDValue
*jsdv
= JSD_GetThisForStackFrame (mCx
, mThreadState
,
1904 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
1910 jsdStackFrame::Eval (const nsAString
&bytes
, const char *fileName
,
1911 PRUint32 line
, jsdIValue
**result
, PRBool
*_rval
)
1913 ASSERT_VALID_EPHEMERAL
;
1915 if (bytes
.IsEmpty())
1916 return NS_ERROR_INVALID_ARG
;
1918 // get pointer to buffer contained in |bytes|
1919 nsAString::const_iterator h
;
1920 bytes
.BeginReading(h
);
1921 const jschar
*char_bytes
= reinterpret_cast<const jschar
*>(h
.get());
1923 JSExceptionState
*estate
= 0;
1926 JSContext
*cx
= JSD_GetJSContext (mCx
, mThreadState
);
1928 JSAutoRequest
ar(cx
);
1930 estate
= JS_SaveExceptionState (cx
);
1931 JS_ClearPendingException (cx
);
1933 *_rval
= JSD_AttemptUCScriptInStackFrame (mCx
, mThreadState
,
1935 char_bytes
, bytes
.Length(),
1936 fileName
, line
, &jv
);
1938 if (JS_IsExceptionPending(cx
))
1939 JS_GetPendingException (cx
, &jv
);
1944 JS_RestoreExceptionState (cx
, estate
);
1946 JSDValue
*jsdv
= JSD_NewValue (mCx
, jv
);
1948 return NS_ERROR_FAILURE
;
1949 *result
= jsdValue::FromPtr (mCx
, jsdv
);
1951 return NS_ERROR_FAILURE
;
1957 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue
, jsdIValue
, jsdIEphemeral
)
1959 jsdValue::FromPtr (JSDContext
*aCx
, JSDValue
*aValue
)
1961 /* value will be dropped by te jsdValue destructor. */
1966 jsdIValue
*rv
= new jsdValue (aCx
, aValue
);
1971 jsdValue::jsdValue (JSDContext
*aCx
, JSDValue
*aValue
) : mValid(PR_TRUE
),
1975 DEBUG_CREATE ("jsdValue", gValueCount
);
1976 mLiveListEntry
.value
= this;
1977 jsds_InsertEphemeral (&gLiveValues
, &mLiveListEntry
);
1980 jsdValue::~jsdValue()
1982 DEBUG_DESTROY ("jsdValue", gValueCount
);
1984 /* call Invalidate() to take ourselves out of the live list */
1989 jsdValue::GetIsValid(PRBool
*_rval
)
1996 jsdValue::Invalidate()
1998 ASSERT_VALID_EPHEMERAL
;
2000 jsds_RemoveEphemeral (&gLiveValues
, &mLiveListEntry
);
2001 JSD_DropValue (mCx
, mValue
);
2006 jsdValue::InvalidateAll()
2009 jsds_InvalidateAllEphemerals (&gLiveValues
);
2013 jsdValue::GetJSDContext(JSDContext
**_rval
)
2015 ASSERT_VALID_EPHEMERAL
;
2021 jsdValue::GetJSDValue (JSDValue
**_rval
)
2023 ASSERT_VALID_EPHEMERAL
;
2029 jsdValue::GetIsNative (PRBool
*_rval
)
2031 ASSERT_VALID_EPHEMERAL
;
2032 *_rval
= JSD_IsValueNative (mCx
, mValue
);
2037 jsdValue::GetIsNumber (PRBool
*_rval
)
2039 ASSERT_VALID_EPHEMERAL
;
2040 *_rval
= JSD_IsValueNumber (mCx
, mValue
);
2045 jsdValue::GetIsPrimitive (PRBool
*_rval
)
2047 ASSERT_VALID_EPHEMERAL
;
2048 *_rval
= JSD_IsValuePrimitive (mCx
, mValue
);
2053 jsdValue::GetJsType (PRUint32
*_rval
)
2055 ASSERT_VALID_EPHEMERAL
;
2058 val
= JSD_GetValueWrappedJSVal (mCx
, mValue
);
2060 if (JSVAL_IS_NULL(val
))
2062 else if (JSVAL_IS_BOOLEAN(val
))
2063 *_rval
= TYPE_BOOLEAN
;
2064 else if (JSVAL_IS_DOUBLE(val
))
2065 *_rval
= TYPE_DOUBLE
;
2066 else if (JSVAL_IS_INT(val
))
2068 else if (JSVAL_IS_STRING(val
))
2069 *_rval
= TYPE_STRING
;
2070 else if (JSVAL_IS_VOID(val
))
2072 else if (JSD_IsValueFunction (mCx
, mValue
))
2073 *_rval
= TYPE_FUNCTION
;
2074 else if (JSVAL_IS_OBJECT(val
))
2075 *_rval
= TYPE_OBJECT
;
2077 NS_ASSERTION (0, "Value has no discernible type.");
2083 jsdValue::GetJsPrototype (jsdIValue
**_rval
)
2085 ASSERT_VALID_EPHEMERAL
;
2086 JSDValue
*jsdv
= JSD_GetValuePrototype (mCx
, mValue
);
2087 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2092 jsdValue::GetJsParent (jsdIValue
**_rval
)
2094 ASSERT_VALID_EPHEMERAL
;
2095 JSDValue
*jsdv
= JSD_GetValueParent (mCx
, mValue
);
2096 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2101 jsdValue::GetJsClassName(char **_rval
)
2103 ASSERT_VALID_EPHEMERAL
;
2104 const char *name
= JSD_GetValueClassName(mCx
, mValue
);
2106 *_rval
= PL_strdup(name
);
2108 return NS_ERROR_OUT_OF_MEMORY
;
2117 jsdValue::GetJsConstructor (jsdIValue
**_rval
)
2119 ASSERT_VALID_EPHEMERAL
;
2120 JSDValue
*jsdv
= JSD_GetValueConstructor (mCx
, mValue
);
2121 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2126 jsdValue::GetJsFunctionName(char **_rval
)
2128 ASSERT_VALID_EPHEMERAL
;
2129 const char *name
= JSD_GetValueFunctionName(mCx
, mValue
);
2131 *_rval
= PL_strdup(name
);
2133 return NS_ERROR_OUT_OF_MEMORY
;
2135 /* top level scripts have no function name */
2144 jsdValue::GetBooleanValue(PRBool
*_rval
)
2146 ASSERT_VALID_EPHEMERAL
;
2147 *_rval
= JSD_GetValueBoolean (mCx
, mValue
);
2152 jsdValue::GetDoubleValue(double *_rval
)
2154 ASSERT_VALID_EPHEMERAL
;
2155 double *dp
= JSD_GetValueDouble (mCx
, mValue
);
2157 return NS_ERROR_FAILURE
;
2163 jsdValue::GetIntValue(PRInt32
*_rval
)
2165 ASSERT_VALID_EPHEMERAL
;
2166 *_rval
= JSD_GetValueInt (mCx
, mValue
);
2171 jsdValue::GetObjectValue(jsdIObject
**_rval
)
2173 ASSERT_VALID_EPHEMERAL
;
2175 obj
= JSD_GetObjectForValue (mCx
, mValue
);
2176 *_rval
= jsdObject::FromPtr (mCx
, obj
);
2178 return NS_ERROR_FAILURE
;
2183 jsdValue::GetStringValue(char **_rval
)
2185 ASSERT_VALID_EPHEMERAL
;
2186 JSString
*jstr_val
= JSD_GetValueString(mCx
, mValue
);
2188 char *bytes
= JS_GetStringBytes(jstr_val
);
2189 *_rval
= PL_strdup(bytes
);
2191 return NS_ERROR_OUT_OF_MEMORY
;
2199 jsdValue::GetPropertyCount (PRInt32
*_rval
)
2201 ASSERT_VALID_EPHEMERAL
;
2202 if (JSD_IsValueObject(mCx
, mValue
))
2203 *_rval
= JSD_GetCountOfProperties (mCx
, mValue
);
2210 jsdValue::GetProperties (jsdIProperty
***propArray
, PRUint32
*length
)
2212 ASSERT_VALID_EPHEMERAL
;
2213 *propArray
= nsnull
;
2217 PRUint32 prop_count
= JSD_IsValueObject(mCx
, mValue
)
2218 ? JSD_GetCountOfProperties (mCx
, mValue
)
2220 NS_ENSURE_TRUE(prop_count
, NS_OK
);
2222 jsdIProperty
**pa_temp
=
2223 static_cast<jsdIProperty
**>
2224 (nsMemory::Alloc(sizeof (jsdIProperty
*) *
2226 NS_ENSURE_TRUE(pa_temp
, NS_ERROR_OUT_OF_MEMORY
);
2229 JSDProperty
*iter
= NULL
;
2231 while ((prop
= JSD_IterateProperties (mCx
, mValue
, &iter
))) {
2232 pa_temp
[i
] = jsdProperty::FromPtr (mCx
, prop
);
2236 NS_ASSERTION (prop_count
== i
, "property count mismatch");
2238 /* if caller doesn't care about length, don't bother telling them */
2239 *propArray
= pa_temp
;
2241 *length
= prop_count
;
2247 jsdValue::GetProperty (const char *name
, jsdIProperty
**_rval
)
2249 ASSERT_VALID_EPHEMERAL
;
2250 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2252 JSAutoRequest
ar(cx
);
2254 /* not rooting this */
2255 JSString
*jstr_name
= JS_NewStringCopyZ (cx
, name
);
2257 return NS_ERROR_OUT_OF_MEMORY
;
2259 JSDProperty
*prop
= JSD_GetValueProperty (mCx
, mValue
, jstr_name
);
2261 *_rval
= jsdProperty::FromPtr (mCx
, prop
);
2268 ASSERT_VALID_EPHEMERAL
;
2269 JSD_RefreshValue (mCx
, mValue
);
2274 jsdValue::GetWrappedValue()
2276 ASSERT_VALID_EPHEMERAL
;
2278 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID(), &rv
);
2282 nsAXPCNativeCallContext
*cc
= nsnull
;
2283 rv
= xpc
->GetCurrentNativeCallContext(&cc
);
2288 rv
= cc
->GetRetValPtr(&result
);
2294 *result
= JSD_GetValueWrappedJSVal (mCx
, mValue
);
2295 cc
->SetReturnValueWasSet(PR_TRUE
);
2301 /******************************************************************************
2302 * debugger service implementation
2303 ******************************************************************************/
2304 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdService
, jsdIDebuggerService
)
2307 jsdService::GetJSDContext(JSDContext
**_rval
)
2314 jsdService::GetInitAtStartup (PRBool
*_rval
)
2317 nsCOMPtr
<nsICategoryManager
>
2318 categoryManager(do_GetService(NS_CATMAN_CTRID
, &rv
));
2322 NS_WARNING("couldn't get category manager");
2326 if (mInitAtStartup
== triUnknown
) {
2327 nsXPIDLCString notused
;
2328 nsresult autoreg_rv
, appstart_rv
;
2330 autoreg_rv
= categoryManager
->GetCategoryEntry(AUTOREG_CATEGORY
,
2332 getter_Copies(notused
));
2333 appstart_rv
= categoryManager
->GetCategoryEntry(APPSTART_CATEGORY
,
2335 getter_Copies(notused
));
2336 if (autoreg_rv
!= appstart_rv
) {
2337 /* we have an inconsistent state in the registry, attempt to fix.
2338 * we need to make mInitAtStartup disagree with the state passed
2339 * to SetInitAtStartup to make it actually do something.
2341 mInitAtStartup
= triYes
;
2342 rv
= SetInitAtStartup (PR_FALSE
);
2345 NS_WARNING("SetInitAtStartup failed");
2348 } else if (autoreg_rv
== NS_ERROR_NOT_AVAILABLE
) {
2349 mInitAtStartup
= triNo
;
2350 } else if (NS_SUCCEEDED(autoreg_rv
)) {
2351 mInitAtStartup
= triYes
;
2353 NS_WARN_IF_FALSE(NS_SUCCEEDED(autoreg_rv
),
2354 "couldn't get autoreg category");
2355 NS_WARN_IF_FALSE(NS_SUCCEEDED(appstart_rv
),
2356 "couldn't get appstart category");
2362 *_rval
= (mInitAtStartup
== triYes
);
2368 * The initAtStartup property controls whether or not we register the
2369 * app start observer (jsdASObserver.) We register for both
2370 * "xpcom-autoregistration" and "app-startup" notifications if |state| is true.
2371 * the autoreg message is sent just before registration occurs (before
2372 * "app-startup".) We care about autoreg because it may load javascript
2373 * components. autoreg does *not* fire if components haven't changed since the
2374 * last autoreg, so we watch "app-startup" as a fallback.
2377 jsdService::SetInitAtStartup (PRBool state
)
2381 if (mInitAtStartup
== triUnknown
) {
2382 /* side effect sets mInitAtStartup */
2383 rv
= GetInitAtStartup(nsnull
);
2388 if (state
&& mInitAtStartup
== triYes
||
2389 !state
&& mInitAtStartup
== triNo
) {
2390 /* already in the requested state */
2394 nsCOMPtr
<nsICategoryManager
>
2395 categoryManager(do_GetService(NS_CATMAN_CTRID
, &rv
));
2400 rv
= categoryManager
->AddCategoryEntry(AUTOREG_CATEGORY
,
2403 PR_TRUE
, PR_TRUE
, nsnull
);
2406 rv
= categoryManager
->AddCategoryEntry(APPSTART_CATEGORY
,
2409 PR_TRUE
, PR_TRUE
, nsnull
);
2412 mInitAtStartup
= triYes
;
2414 rv
= categoryManager
->DeleteCategoryEntry(AUTOREG_CATEGORY
,
2415 JSD_AUTOREG_ENTRY
, PR_TRUE
);
2418 rv
= categoryManager
->DeleteCategoryEntry(APPSTART_CATEGORY
,
2419 JSD_STARTUP_ENTRY
, PR_TRUE
);
2422 mInitAtStartup
= triNo
;
2429 jsdService::GetFlags (PRUint32
*_rval
)
2431 ASSERT_VALID_CONTEXT
;
2432 *_rval
= JSD_GetContextFlags (mCx
);
2437 jsdService::SetFlags (PRUint32 flags
)
2439 ASSERT_VALID_CONTEXT
;
2440 JSD_SetContextFlags (mCx
, flags
);
2445 jsdService::GetImplementationString(char **_rval
)
2447 *_rval
= PL_strdup(implementationString
);
2449 return NS_ERROR_OUT_OF_MEMORY
;
2454 jsdService::GetImplementationMajor(PRUint32
*_rval
)
2456 *_rval
= JSDS_MAJOR_VERSION
;
2461 jsdService::GetImplementationMinor(PRUint32
*_rval
)
2463 *_rval
= JSDS_MINOR_VERSION
;
2468 jsdService::GetIsOn (PRBool
*_rval
)
2475 jsdService::On (void)
2479 /* get JS things from the CallContext */
2480 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID(), &rv
);
2481 if (NS_FAILED(rv
)) return rv
;
2483 nsAXPCNativeCallContext
*cc
= nsnull
;
2484 rv
= xpc
->GetCurrentNativeCallContext(&cc
);
2485 if (NS_FAILED(rv
)) return rv
;
2488 rv
= cc
->GetJSContext (&cx
);
2489 if (NS_FAILED(rv
)) return rv
;
2491 return OnForRuntime(JS_GetRuntime (cx
));
2496 jsdService::OnForRuntime (JSRuntime
*rt
)
2499 return (rt
== mRuntime
) ? NS_OK
: NS_ERROR_ALREADY_INITIALIZED
;
2503 if (gLastGCProc
== jsds_GCCallbackProc
)
2504 /* condition indicates that the callback proc has not been set yet */
2505 gLastGCProc
= JS_SetGCCallbackRT (rt
, jsds_GCCallbackProc
);
2507 mCx
= JSD_DebuggerOnForUser (rt
, NULL
, NULL
);
2509 return NS_ERROR_FAILURE
;
2511 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2512 JSObject
*glob
= JS_GetGlobalObject (cx
);
2514 /* init xpconnect on the debugger's context in case xpconnect tries to
2515 * use it for stuff. */
2517 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID(), &rv
);
2521 xpc
->InitClasses (cx
, glob
);
2523 /* If any of these mFooHook objects are installed, do the required JSD
2524 * hookup now. See also, jsdService::SetFooHook().
2527 JSD_SetErrorReporter (mCx
, jsds_ErrorHookProc
, NULL
);
2529 JSD_SetThrowHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2530 /* can't ignore script callbacks, as we need to |Release| the wrapper
2531 * stored in private data when a script is deleted. */
2533 JSD_SetInterruptHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2535 JSD_SetDebuggerHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2537 JSD_SetDebugBreakHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2539 JSD_SetTopLevelHook (mCx
, jsds_CallHookProc
, NULL
);
2541 JSD_ClearTopLevelHook (mCx
);
2543 JSD_SetFunctionHook (mCx
, jsds_CallHookProc
, NULL
);
2545 JSD_ClearFunctionHook (mCx
);
2549 printf ("+++ JavaScript debugging hooks installed.\n");
2555 jsdService::Off (void)
2560 if (!mCx
|| !mRuntime
)
2561 return NS_ERROR_NOT_INITIALIZED
;
2564 if (gGCStatus
!= JSGC_END
)
2565 return NS_ERROR_NOT_AVAILABLE
;
2567 JSContext
*cx
= JSD_GetDefaultJSContext(mCx
);
2568 jsds_NotifyPendingDeadScripts(cx
);
2572 if (gLastGCProc != jsds_GCCallbackProc)
2573 JS_SetGCCallbackRT (mRuntime, gLastGCProc);
2576 jsdContext::InvalidateAll();
2577 jsdScript::InvalidateAll();
2578 jsdValue::InvalidateAll();
2579 jsdProperty::InvalidateAll();
2580 ClearAllBreakpoints();
2582 JSD_SetErrorReporter (mCx
, NULL
, NULL
);
2583 JSD_SetScriptHook (mCx
, NULL
, NULL
);
2584 JSD_ClearThrowHook (mCx
);
2585 JSD_ClearInterruptHook (mCx
);
2586 JSD_ClearDebuggerHook (mCx
);
2587 JSD_ClearDebugBreakHook (mCx
);
2588 JSD_ClearTopLevelHook (mCx
);
2589 JSD_ClearFunctionHook (mCx
);
2591 JSD_DebuggerOff (mCx
);
2598 printf ("+++ JavaScript debugging hooks removed.\n");
2605 jsdService::GetPauseDepth(PRUint32
*_rval
)
2607 NS_ENSURE_ARG_POINTER(_rval
);
2608 *_rval
= mPauseLevel
;
2613 jsdService::Pause(PRUint32
*_rval
)
2616 return NS_ERROR_NOT_INITIALIZED
;
2618 if (++mPauseLevel
== 1) {
2619 JSD_SetErrorReporter (mCx
, NULL
, NULL
);
2620 JSD_ClearThrowHook (mCx
);
2621 JSD_ClearInterruptHook (mCx
);
2622 JSD_ClearDebuggerHook (mCx
);
2623 JSD_ClearDebugBreakHook (mCx
);
2624 JSD_ClearTopLevelHook (mCx
);
2625 JSD_ClearFunctionHook (mCx
);
2629 *_rval
= mPauseLevel
;
2635 jsdService::UnPause(PRUint32
*_rval
)
2638 return NS_ERROR_NOT_INITIALIZED
;
2640 if (mPauseLevel
== 0)
2641 return NS_ERROR_NOT_AVAILABLE
;
2643 /* check mOn before we muck with this stuff, it's possible the debugger
2644 * was turned off while we were paused.
2646 if (--mPauseLevel
== 0 && mOn
) {
2648 JSD_SetErrorReporter (mCx
, jsds_ErrorHookProc
, NULL
);
2650 JSD_SetThrowHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2652 JSD_SetInterruptHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2654 JSD_SetDebuggerHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2656 JSD_SetDebugBreakHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2658 JSD_SetTopLevelHook (mCx
, jsds_CallHookProc
, NULL
);
2660 JSD_ClearTopLevelHook (mCx
);
2662 JSD_SetFunctionHook (mCx
, jsds_CallHookProc
, NULL
);
2664 JSD_ClearFunctionHook (mCx
);
2668 *_rval
= mPauseLevel
;
2674 jsdService::EnumerateContexts (jsdIContextEnumerator
*enumerator
)
2676 ASSERT_VALID_CONTEXT
;
2681 JSContext
*iter
= NULL
;
2684 while ((cx
= JS_ContextIterator (mRuntime
, &iter
)))
2686 nsCOMPtr
<jsdIContext
> jsdicx
=
2687 getter_AddRefs(jsdContext::FromPtr(mCx
, cx
));
2690 if (NS_FAILED(enumerator
->EnumerateContext(jsdicx
)))
2699 jsdService::EnumerateScripts (jsdIScriptEnumerator
*enumerator
)
2701 ASSERT_VALID_CONTEXT
;
2704 JSDScript
*iter
= NULL
;
2705 nsresult rv
= NS_OK
;
2707 JSD_LockScriptSubsystem(mCx
);
2708 while((script
= JSD_IterateScripts(mCx
, &iter
))) {
2709 nsCOMPtr
<jsdIScript
> jsdis
=
2710 getter_AddRefs(jsdScript::FromPtr(mCx
, script
));
2711 rv
= enumerator
->EnumerateScript (jsdis
);
2715 JSD_UnlockScriptSubsystem(mCx
);
2721 jsdService::GC (void)
2723 ASSERT_VALID_CONTEXT
;
2724 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2730 jsdService::DumpHeap(const char* fileName
)
2732 ASSERT_VALID_CONTEXT
;
2734 return NS_ERROR_NOT_IMPLEMENTED
;
2736 nsresult rv
= NS_OK
;
2737 FILE *file
= fileName
? fopen(fileName
, "w") : stdout
;
2739 rv
= NS_ERROR_FAILURE
;
2741 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2742 if (!JS_DumpHeap(cx
, file
, NULL
, 0, NULL
, (size_t)-1, NULL
))
2743 rv
= NS_ERROR_FAILURE
;
2752 jsdService::ClearProfileData ()
2754 ASSERT_VALID_CONTEXT
;
2755 JSD_ClearAllProfileData (mCx
);
2760 jsdService::InsertFilter (jsdIFilter
*filter
, jsdIFilter
*after
)
2762 NS_ENSURE_ARG_POINTER (filter
);
2763 if (jsds_FindFilter (filter
))
2764 return NS_ERROR_INVALID_ARG
;
2766 FilterRecord
*rec
= PR_NEWZAP (FilterRecord
);
2768 return NS_ERROR_OUT_OF_MEMORY
;
2770 if (!jsds_SyncFilter (rec
, filter
)) {
2772 return NS_ERROR_FAILURE
;
2777 /* insert at head of list */
2778 PR_INSERT_LINK(&rec
->links
, &gFilters
->links
);
2781 /* insert somewhere in the list */
2782 FilterRecord
*afterRecord
= jsds_FindFilter (after
);
2784 jsds_FreeFilter(rec
);
2785 return NS_ERROR_INVALID_ARG
;
2787 PR_INSERT_AFTER(&rec
->links
, &afterRecord
->links
);
2791 /* user asked to insert into the middle of an empty list, bail. */
2792 jsds_FreeFilter(rec
);
2793 return NS_ERROR_NOT_INITIALIZED
;
2795 PR_INIT_CLIST(&rec
->links
);
2803 jsdService::AppendFilter (jsdIFilter
*filter
)
2805 NS_ENSURE_ARG_POINTER (filter
);
2806 if (jsds_FindFilter (filter
))
2807 return NS_ERROR_INVALID_ARG
;
2808 FilterRecord
*rec
= PR_NEWZAP (FilterRecord
);
2810 if (!jsds_SyncFilter (rec
, filter
)) {
2812 return NS_ERROR_FAILURE
;
2816 PR_INSERT_BEFORE(&rec
->links
, &gFilters
->links
);
2818 PR_INIT_CLIST(&rec
->links
);
2826 jsdService::RemoveFilter (jsdIFilter
*filter
)
2828 NS_ENSURE_ARG_POINTER(filter
);
2829 FilterRecord
*rec
= jsds_FindFilter (filter
);
2831 return NS_ERROR_INVALID_ARG
;
2833 if (gFilters
== rec
) {
2834 gFilters
= reinterpret_cast<FilterRecord
*>
2835 (PR_NEXT_LINK(&rec
->links
));
2836 /* If we're the only filter left, null out the list head. */
2837 if (gFilters
== rec
)
2842 PR_REMOVE_LINK(&rec
->links
);
2843 jsds_FreeFilter (rec
);
2849 jsdService::SwapFilters (jsdIFilter
*filter_a
, jsdIFilter
*filter_b
)
2851 NS_ENSURE_ARG_POINTER(filter_a
);
2852 NS_ENSURE_ARG_POINTER(filter_b
);
2854 FilterRecord
*rec_a
= jsds_FindFilter (filter_a
);
2856 return NS_ERROR_INVALID_ARG
;
2858 if (filter_a
== filter_b
) {
2859 /* just a refresh */
2860 if (!jsds_SyncFilter (rec_a
, filter_a
))
2861 return NS_ERROR_FAILURE
;
2865 FilterRecord
*rec_b
= jsds_FindFilter (filter_b
);
2867 /* filter_b is not in the list, replace filter_a with filter_b. */
2868 if (!jsds_SyncFilter (rec_a
, filter_b
))
2869 return NS_ERROR_FAILURE
;
2871 /* both filters are in the list, swap. */
2872 if (!jsds_SyncFilter (rec_a
, filter_b
))
2873 return NS_ERROR_FAILURE
;
2874 if (!jsds_SyncFilter (rec_b
, filter_a
))
2875 return NS_ERROR_FAILURE
;
2882 jsdService::EnumerateFilters (jsdIFilterEnumerator
*enumerator
)
2887 FilterRecord
*current
= gFilters
;
2889 jsds_SyncFilter (current
, current
->filterObject
);
2890 /* SyncFilter failure would be bad, but what would we do about it? */
2892 nsresult rv
= enumerator
->EnumerateFilter (current
->filterObject
);
2896 current
= reinterpret_cast<FilterRecord
*>
2897 (PR_NEXT_LINK (¤t
->links
));
2898 } while (current
!= gFilters
);
2904 jsdService::RefreshFilters ()
2906 return EnumerateFilters(nsnull
);
2910 jsdService::ClearFilters ()
2915 FilterRecord
*current
= reinterpret_cast<FilterRecord
*>
2916 (PR_NEXT_LINK (&gFilters
->links
));
2918 FilterRecord
*next
= reinterpret_cast<FilterRecord
*>
2919 (PR_NEXT_LINK (¤t
->links
));
2920 PR_REMOVE_AND_INIT_LINK(¤t
->links
);
2921 jsds_FreeFilter(current
);
2923 } while (current
!= gFilters
);
2925 jsds_FreeFilter(current
);
2932 jsdService::ClearAllBreakpoints (void)
2934 ASSERT_VALID_CONTEXT
;
2936 JSD_LockScriptSubsystem(mCx
);
2937 JSD_ClearAllExecutionHooks (mCx
);
2938 JSD_UnlockScriptSubsystem(mCx
);
2943 jsdService::WrapValue(jsdIValue
**_rval
)
2945 ASSERT_VALID_CONTEXT
;
2948 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService (nsIXPConnect::GetCID(), &rv
);
2952 nsAXPCNativeCallContext
*cc
= nsnull
;
2953 rv
= xpc
->GetCurrentNativeCallContext (&cc
);
2958 rv
= cc
->GetArgc (&argc
);
2962 return NS_ERROR_INVALID_ARG
;
2965 rv
= cc
->GetArgvPtr (&argv
);
2969 JSDValue
*jsdv
= JSD_NewValue (mCx
, argv
[0]);
2971 return NS_ERROR_FAILURE
;
2973 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2979 jsdService::EnterNestedEventLoop (jsdINestCallback
*callback
, PRUint32
*_rval
)
2981 // Nesting event queues is a thing of the past. Now, we just spin the
2982 // current event loop.
2985 nsCOMPtr
<nsIJSContextStack
>
2986 stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
));
2989 PRUint32 nestLevel
= ++mNestedLoopLevel
;
2991 nsCOMPtr
<nsIThread
> thread
= do_GetCurrentThread();
2993 if (NS_SUCCEEDED(stack
->Push(nsnull
))) {
2996 rv
= callback
->OnNest();
3000 while (NS_SUCCEEDED(rv
) && mNestedLoopLevel
>= nestLevel
) {
3001 if (!NS_ProcessNextEvent(thread
))
3002 rv
= NS_ERROR_UNEXPECTED
;
3007 NS_ASSERTION(cx
== nsnull
, "JSContextStack mismatch");
3010 rv
= NS_ERROR_FAILURE
;
3012 NS_ASSERTION (mNestedLoopLevel
<= nestLevel
,
3013 "nested event didn't unwind properly");
3014 if (mNestedLoopLevel
== nestLevel
)
3017 *_rval
= mNestedLoopLevel
;
3022 jsdService::ExitNestedEventLoop (PRUint32
*_rval
)
3024 if (mNestedLoopLevel
> 0)
3027 return NS_ERROR_FAILURE
;
3029 *_rval
= mNestedLoopLevel
;
3033 /* hook attribute get/set functions */
3036 jsdService::SetErrorHook (jsdIErrorHook
*aHook
)
3040 /* if the debugger isn't initialized, that's all we can do for now. The
3041 * OnForRuntime() method will do the rest when the coast is clear.
3043 if (!mCx
|| mPauseLevel
)
3047 JSD_SetErrorReporter (mCx
, jsds_ErrorHookProc
, NULL
);
3049 JSD_SetErrorReporter (mCx
, NULL
, NULL
);
3055 jsdService::GetErrorHook (jsdIErrorHook
**aHook
)
3057 *aHook
= mErrorHook
;
3058 NS_IF_ADDREF(*aHook
);
3064 jsdService::SetBreakpointHook (jsdIExecutionHook
*aHook
)
3066 mBreakpointHook
= aHook
;
3071 jsdService::GetBreakpointHook (jsdIExecutionHook
**aHook
)
3073 *aHook
= mBreakpointHook
;
3074 NS_IF_ADDREF(*aHook
);
3080 jsdService::SetDebugHook (jsdIExecutionHook
*aHook
)
3084 /* if the debugger isn't initialized, that's all we can do for now. The
3085 * OnForRuntime() method will do the rest when the coast is clear.
3087 if (!mCx
|| mPauseLevel
)
3091 JSD_SetDebugBreakHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3093 JSD_ClearDebugBreakHook (mCx
);
3099 jsdService::GetDebugHook (jsdIExecutionHook
**aHook
)
3101 *aHook
= mDebugHook
;
3102 NS_IF_ADDREF(*aHook
);
3108 jsdService::SetDebuggerHook (jsdIExecutionHook
*aHook
)
3110 mDebuggerHook
= aHook
;
3112 /* if the debugger isn't initialized, that's all we can do for now. The
3113 * OnForRuntime() method will do the rest when the coast is clear.
3115 if (!mCx
|| mPauseLevel
)
3119 JSD_SetDebuggerHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3121 JSD_ClearDebuggerHook (mCx
);
3127 jsdService::GetDebuggerHook (jsdIExecutionHook
**aHook
)
3129 *aHook
= mDebuggerHook
;
3130 NS_IF_ADDREF(*aHook
);
3136 jsdService::SetInterruptHook (jsdIExecutionHook
*aHook
)
3138 mInterruptHook
= aHook
;
3140 /* if the debugger isn't initialized, that's all we can do for now. The
3141 * OnForRuntime() method will do the rest when the coast is clear.
3143 if (!mCx
|| mPauseLevel
)
3147 JSD_SetInterruptHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3149 JSD_ClearInterruptHook (mCx
);
3155 jsdService::GetInterruptHook (jsdIExecutionHook
**aHook
)
3157 *aHook
= mInterruptHook
;
3158 NS_IF_ADDREF(*aHook
);
3164 jsdService::SetScriptHook (jsdIScriptHook
*aHook
)
3166 mScriptHook
= aHook
;
3168 /* if the debugger isn't initialized, that's all we can do for now. The
3169 * OnForRuntime() method will do the rest when the coast is clear.
3171 if (!mCx
|| mPauseLevel
)
3175 JSD_SetScriptHook (mCx
, jsds_ScriptHookProc
, NULL
);
3176 /* we can't unset it if !aHook, because we still need to see script
3177 * deletes in order to Release the jsdIScripts held in JSDScript
3183 jsdService::GetScriptHook (jsdIScriptHook
**aHook
)
3185 *aHook
= mScriptHook
;
3186 NS_IF_ADDREF(*aHook
);
3192 jsdService::SetThrowHook (jsdIExecutionHook
*aHook
)
3196 /* if the debugger isn't initialized, that's all we can do for now. The
3197 * OnForRuntime() method will do the rest when the coast is clear.
3199 if (!mCx
|| mPauseLevel
)
3203 JSD_SetThrowHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3205 JSD_ClearThrowHook (mCx
);
3211 jsdService::GetThrowHook (jsdIExecutionHook
**aHook
)
3213 *aHook
= mThrowHook
;
3214 NS_IF_ADDREF(*aHook
);
3220 jsdService::SetTopLevelHook (jsdICallHook
*aHook
)
3222 mTopLevelHook
= aHook
;
3224 /* if the debugger isn't initialized, that's all we can do for now. The
3225 * OnForRuntime() method will do the rest when the coast is clear.
3227 if (!mCx
|| mPauseLevel
)
3231 JSD_SetTopLevelHook (mCx
, jsds_CallHookProc
, NULL
);
3233 JSD_ClearTopLevelHook (mCx
);
3239 jsdService::GetTopLevelHook (jsdICallHook
**aHook
)
3241 *aHook
= mTopLevelHook
;
3242 NS_IF_ADDREF(*aHook
);
3248 jsdService::SetFunctionHook (jsdICallHook
*aHook
)
3250 mFunctionHook
= aHook
;
3252 /* if the debugger isn't initialized, that's all we can do for now. The
3253 * OnForRuntime() method will do the rest when the coast is clear.
3255 if (!mCx
|| mPauseLevel
)
3259 JSD_SetFunctionHook (mCx
, jsds_CallHookProc
, NULL
);
3261 JSD_ClearFunctionHook (mCx
);
3267 jsdService::GetFunctionHook (jsdICallHook
**aHook
)
3269 *aHook
= mFunctionHook
;
3270 NS_IF_ADDREF(*aHook
);
3276 jsdService::~jsdService()
3279 mErrorHook
= nsnull
;
3280 mBreakpointHook
= nsnull
;
3281 mDebugHook
= nsnull
;
3282 mDebuggerHook
= nsnull
;
3283 mInterruptHook
= nsnull
;
3284 mScriptHook
= nsnull
;
3285 mThrowHook
= nsnull
;
3286 mTopLevelHook
= nsnull
;
3287 mFunctionHook
= nsnull
;
3288 gGCStatus
= JSGC_END
;
3294 jsdService::GetService ()
3297 gJsds
= new jsdService();
3299 NS_IF_ADDREF(gJsds
);
3303 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService
, jsdService::GetService
)
3305 /* app-start observer. turns on the debugger at app-start. this is inserted
3306 * and/or removed from the app-start category by the jsdService::initAtStartup
3309 class jsdASObserver
: public nsIObserver
3318 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver
, nsIObserver
)
3321 jsdASObserver::Observe (nsISupports
*aSubject
, const char *aTopic
,
3322 const PRUnichar
*aData
)
3326 // Hmm. Why is the app-startup observer called multiple times?
3327 //NS_ASSERTION(!gJsds, "app startup observer called twice");
3328 nsCOMPtr
<jsdIDebuggerService
> jsds
= do_GetService(jsdServiceCtrID
, &rv
);
3333 rv
= jsds
->GetIsOn(&on
);
3334 if (NS_FAILED(rv
) || on
)
3337 nsCOMPtr
<nsIJSRuntimeService
> rts
= do_GetService(NS_JSRT_CTRID
, &rv
);
3342 rts
->GetRuntime (&rt
);
3346 rv
= jsds
->OnForRuntime(rt
);
3350 return jsds
->SetFlags(JSD_DISABLE_OBJECT_TRACE
);
3353 NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver
)
3355 static const nsModuleComponentInfo components
[] = {
3356 {"JSDService", JSDSERVICE_CID
, jsdServiceCtrID
, jsdServiceConstructor
},
3357 {"JSDASObserver", JSDASO_CID
, jsdARObserverCtrID
, jsdASObserverConstructor
}
3360 NS_IMPL_NSGETMODULE(JavaScript_Debugger
, components
)
3362 /********************************************************************************
3363 ********************************************************************************
3369 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState
, jsdIThreadState
);
3372 jsdThreadState::GetJSDContext(JSDContext
**_rval
)
3379 jsdThreadState::GetJSDThreadState(JSDThreadState
**_rval
)
3381 *_rval
= mThreadState
;
3386 jsdThreadState::GetFrameCount (PRUint32
*_rval
)
3388 *_rval
= JSD_GetCountOfStackFrames (mCx
, mThreadState
);
3393 jsdThreadState::GetTopFrame (jsdIStackFrame
**_rval
)
3395 JSDStackFrameInfo
*sfi
= JSD_GetStackFrame (mCx
, mThreadState
);
3397 *_rval
= jsdStackFrame::FromPtr (mCx
, mThreadState
, sfi
);
3402 jsdThreadState::GetPendingException(jsdIValue
**_rval
)
3404 JSDValue
*jsdv
= JSD_GetException (mCx
, mThreadState
);
3406 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
3411 jsdThreadState::SetPendingException(jsdIValue
*aException
)
3415 nsresult rv
= aException
->GetJSDValue (&jsdv
);
3417 return NS_ERROR_FAILURE
;
3419 if (!JSD_SetException (mCx
, mThreadState
, jsdv
))
3420 return NS_ERROR_FAILURE
;