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 ***** */
44 #include "nsIXPConnect.h"
45 #include "mozilla/ModuleUtils.h"
46 #include "nsIServiceManager.h"
47 #include "nsIScriptGlobalObject.h"
48 #include "nsIObserver.h"
49 #include "nsIObserverService.h"
50 #include "nsICategoryManager.h"
51 #include "nsIJSRuntimeService.h"
52 #include "nsIThreadInternal.h"
53 #include "nsThreadUtils.h"
56 #include "nsReadableUtils.h"
59 /* XXX DOM dependency */
60 #include "nsIScriptContext.h"
61 #include "nsIJSContextStack.h"
63 /* XXX private JS headers. */
64 #include "jscompartment.h"
67 * defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
68 * script hook. This was a hack to avoid some js engine problems that should
69 * be fixed now (see Mozilla bug 77636).
71 #undef CAUTIOUS_SCRIPTHOOK
74 # define DEBUG_COUNT(name, count) \
75 { if ((count % 10) == 0) printf (name ": %i\n", count); }
76 # define DEBUG_CREATE(name, count) {count++; DEBUG_COUNT ("+++++ "name,count)}
77 # define DEBUG_DESTROY(name, count) {count--; DEBUG_COUNT ("----- "name,count)}
79 # define DEBUG_CREATE(name, count)
80 # define DEBUG_DESTROY(name, count)
83 #define ASSERT_VALID_CONTEXT { if (!mCx) return NS_ERROR_NOT_AVAILABLE; }
84 #define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; }
86 #define JSDSERVICE_CID \
87 { /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */ \
91 {0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \
95 { /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */ \
99 {0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \
102 #define JSDS_MAJOR_VERSION 1
103 #define JSDS_MINOR_VERSION 2
105 #define NS_CATMAN_CTRID "@mozilla.org/categorymanager;1"
106 #define NS_JSRT_CTRID "@mozilla.org/js/xpc/RuntimeService;1"
108 #define AUTOREG_CATEGORY "xpcom-autoregistration"
109 #define APPSTART_CATEGORY "app-startup"
110 #define JSD_AUTOREG_ENTRY "JSDebugger Startup Observer"
111 #define JSD_STARTUP_ENTRY "JSDebugger Startup Observer"
114 jsds_GCCallbackProc (JSContext
*cx
, JSGCStatus status
);
116 /*******************************************************************************
118 ******************************************************************************/
120 const char implementationString
[] = "Mozilla JavaScript Debugger Service";
122 const char jsdServiceCtrID
[] = "@mozilla.org/js/jsd/debugger-service;1";
123 const char jsdARObserverCtrID
[] = "@mozilla.org/js/jsd/app-start-observer;2";
124 const char jsdASObserverCtrID
[] = "service,@mozilla.org/js/jsd/app-start-observer;2";
127 PRUint32 gScriptCount
= 0;
128 PRUint32 gValueCount
= 0;
129 PRUint32 gPropertyCount
= 0;
130 PRUint32 gContextCount
= 0;
131 PRUint32 gFrameCount
= 0;
134 static jsdService
*gJsds
= 0;
135 static JSGCCallback gLastGCProc
= jsds_GCCallbackProc
;
136 static JSGCStatus gGCStatus
= JSGC_END
;
138 static struct DeadScript
{
142 } *gDeadScripts
= nsnull
;
152 static struct FilterRecord
{
154 jsdIFilter
*filterObject
;
156 nsCString urlPattern
;
157 PatternType patternType
;
160 } *gFilters
= nsnull
;
162 static struct LiveEphemeral
*gLiveValues
= nsnull
;
163 static struct LiveEphemeral
*gLiveProperties
= nsnull
;
164 static struct LiveEphemeral
*gLiveContexts
= nsnull
;
165 static struct LiveEphemeral
*gLiveStackFrames
= nsnull
;
167 /*******************************************************************************
168 * utility functions for ephemeral lists
169 *******************************************************************************/
170 already_AddRefed
<jsdIEphemeral
>
171 jsds_FindEphemeral (LiveEphemeral
**listHead
, void *key
)
176 LiveEphemeral
*lv_record
=
177 reinterpret_cast<LiveEphemeral
*>
178 (PR_NEXT_LINK(&(*listHead
)->links
));
181 if (lv_record
->key
== key
)
183 NS_IF_ADDREF(lv_record
->value
);
184 return lv_record
->value
;
186 lv_record
= reinterpret_cast<LiveEphemeral
*>
187 (PR_NEXT_LINK(&lv_record
->links
));
189 while (lv_record
!= *listHead
);
195 jsds_InvalidateAllEphemerals (LiveEphemeral
**listHead
)
197 LiveEphemeral
*lv_record
=
198 reinterpret_cast<LiveEphemeral
*>
199 (PR_NEXT_LINK(&(*listHead
)->links
));
202 LiveEphemeral
*next
=
203 reinterpret_cast<LiveEphemeral
*>
204 (PR_NEXT_LINK(&lv_record
->links
));
205 lv_record
->value
->Invalidate();
211 jsds_InsertEphemeral (LiveEphemeral
**listHead
, LiveEphemeral
*item
)
214 /* if the list exists, add to it */
215 PR_APPEND_LINK(&item
->links
, &(*listHead
)->links
);
217 /* otherwise create the list */
218 PR_INIT_CLIST(&item
->links
);
224 jsds_RemoveEphemeral (LiveEphemeral
**listHead
, LiveEphemeral
*item
)
226 LiveEphemeral
*next
= reinterpret_cast<LiveEphemeral
*>
227 (PR_NEXT_LINK(&item
->links
));
231 /* if the current item is also the next item, we're the only element,
232 * null out the list head */
233 NS_ASSERTION (*listHead
== item
,
234 "How could we not be the head of a one item list?");
237 else if (item
== *listHead
)
239 /* otherwise, if we're currently the list head, change it */
243 PR_REMOVE_AND_INIT_LINK(&item
->links
);
246 /*******************************************************************************
247 * utility functions for filters
248 *******************************************************************************/
250 jsds_FreeFilter (FilterRecord
*rec
)
252 NS_IF_RELEASE (rec
->filterObject
);
256 /* copies appropriate |filter| attributes into |rec|.
257 * False return indicates failure, the contents of |rec| will not be changed.
260 jsds_SyncFilter (FilterRecord
*rec
, jsdIFilter
*filter
)
262 NS_ASSERTION (rec
, "jsds_SyncFilter without rec");
263 NS_ASSERTION (filter
, "jsds_SyncFilter without filter");
265 JSObject
*glob_proper
= nsnull
;
266 nsCOMPtr
<nsISupports
> glob
;
267 nsresult rv
= filter
->GetGlobalObject(getter_AddRefs(glob
));
271 nsCOMPtr
<nsIScriptGlobalObject
> nsiglob
= do_QueryInterface(glob
);
273 glob_proper
= nsiglob
->GetGlobalJSObject();
277 rv
= filter
->GetStartLine(&startLine
);
282 rv
= filter
->GetStartLine(&endLine
);
286 nsCAutoString urlPattern
;
287 rv
= filter
->GetUrlPattern (urlPattern
);
291 PRUint32 len
= urlPattern
.Length();
293 if (urlPattern
[0] == '*') {
294 /* pattern starts with a *, shift all chars once to the left,
295 * including the trailing null. */
296 urlPattern
= Substring(urlPattern
, 1, len
);
298 if (urlPattern
[len
- 2] == '*') {
299 /* pattern is in the format "*foo*", overwrite the final * with
301 urlPattern
.Truncate(len
- 2);
302 rec
->patternType
= ptContains
;
304 /* pattern is in the format "*foo", just make a note of the
306 rec
->patternType
= ptEndsWith
;
308 } else if (urlPattern
[len
- 1] == '*') {
309 /* pattern is in the format "foo*", overwrite the final * with a
311 urlPattern
.Truncate(len
- 1);
312 rec
->patternType
= ptStartsWith
;
314 /* pattern is in the format "foo". */
315 rec
->patternType
= ptEquals
;
318 rec
->patternType
= ptIgnore
;
321 /* we got everything we need without failing, now copy it into rec. */
323 if (rec
->filterObject
!= filter
) {
324 NS_IF_RELEASE(rec
->filterObject
);
326 rec
->filterObject
= filter
;
329 rec
->glob
= glob_proper
;
331 rec
->startLine
= startLine
;
332 rec
->endLine
= endLine
;
334 rec
->urlPattern
= urlPattern
;
341 jsds_FindFilter (jsdIFilter
*filter
)
346 FilterRecord
*current
= gFilters
;
349 if (current
->filterObject
== filter
)
351 current
= reinterpret_cast<FilterRecord
*>
352 (PR_NEXT_LINK(¤t
->links
));
353 } while (current
!= gFilters
);
358 /* returns true if the hook should be executed. */
360 jsds_FilterHook (JSDContext
*jsdc
, JSDThreadState
*state
)
362 JSContext
*cx
= JSD_GetJSContext (jsdc
, state
);
363 void *glob
= static_cast<void *>(JS_GetGlobalObject (cx
));
366 NS_WARNING("No global in threadstate");
370 JSDStackFrameInfo
*frame
= JSD_GetStackFrame (jsdc
, state
);
373 NS_WARNING("No frame in threadstate");
377 JSDScript
*script
= JSD_GetScriptForStackFrame (jsdc
, state
, frame
);
381 jsuword pc
= JSD_GetPCForStackFrame (jsdc
, state
, frame
);
383 nsDependentCString
url(JSD_GetScriptFilename (jsdc
, script
));
385 NS_WARNING ("Script with no filename");
392 PRUint32 currentLine
= JSD_GetClosestLine (jsdc
, script
, pc
);
394 FilterRecord
*currentFilter
= gFilters
;
397 nsresult rv
= currentFilter
->filterObject
->GetFlags(&flags
);
398 NS_ASSERTION(NS_SUCCEEDED(rv
), "Error getting flags for filter");
399 if (flags
& jsdIFilter::FLAG_ENABLED
) {
400 /* if there is no glob, or the globs match */
401 if ((!currentFilter
->glob
|| currentFilter
->glob
== glob
) &&
402 /* and there is no start line, or the start line is before
403 * or equal to the current */
404 (!currentFilter
->startLine
||
405 currentFilter
->startLine
<= currentLine
) &&
406 /* and there is no end line, or the end line is after
407 * or equal to the current */
408 (!currentFilter
->endLine
||
409 currentFilter
->endLine
>= currentLine
)) {
410 /* then we're going to have to compare the url. */
411 if (currentFilter
->patternType
== ptIgnore
)
412 return !!(flags
& jsdIFilter::FLAG_PASS
);
416 nsCString urlPattern
= currentFilter
->urlPattern
;
417 PRUint32 patternLength
= urlPattern
.Length();
418 if (len
>= patternLength
) {
419 switch (currentFilter
->patternType
) {
421 if (urlPattern
.Equals(url
))
422 return !!(flags
& jsdIFilter::FLAG_PASS
);
425 if (urlPattern
.Equals(Substring(url
, 0, patternLength
)))
426 return !!(flags
& jsdIFilter::FLAG_PASS
);
429 if (urlPattern
.Equals(Substring(url
, len
- patternLength
)))
430 return !!(flags
& jsdIFilter::FLAG_PASS
);
434 nsACString::const_iterator start
, end
;
435 url
.BeginReading(start
);
437 if (FindInReadable(currentFilter
->urlPattern
, start
, end
))
438 return !!(flags
& jsdIFilter::FLAG_PASS
);
442 NS_ERROR("Invalid pattern type");
447 currentFilter
= reinterpret_cast<FilterRecord
*>
448 (PR_NEXT_LINK(¤tFilter
->links
));
449 } while (currentFilter
!= gFilters
);
455 /*******************************************************************************
457 *******************************************************************************/
460 jsds_NotifyPendingDeadScripts (JSContext
*cx
)
462 #ifdef CAUTIOUS_SCRIPTHOOK
463 JSRuntime
*rt
= JS_GetRuntime(cx
);
465 jsdService
*jsds
= gJsds
;
467 nsCOMPtr
<jsdIScriptHook
> hook
;
470 jsds
->GetScriptHook (getter_AddRefs(hook
));
474 DeadScript
*deadScripts
= gDeadScripts
;
475 gDeadScripts
= nsnull
;
476 while (deadScripts
) {
477 DeadScript
*ds
= deadScripts
;
478 /* get next deleted script */
479 deadScripts
= reinterpret_cast<DeadScript
*>
480 (PR_NEXT_LINK(&ds
->links
));
481 if (deadScripts
== ds
)
482 deadScripts
= nsnull
;
486 /* tell the user this script has been destroyed */
487 #ifdef CAUTIOUS_SCRIPTHOOK
490 hook
->OnScriptDestroyed (ds
->script
);
491 #ifdef CAUTIOUS_SCRIPTHOOK
496 /* take it out of the circular list */
497 PR_REMOVE_LINK(&ds
->links
);
499 /* addref came from the FromPtr call in jsds_ScriptHookProc */
500 NS_RELEASE(ds
->script
);
501 /* free the struct! */
506 jsds
->UnPause(nsnull
);
512 jsds_GCCallbackProc (JSContext
*cx
, JSGCStatus status
)
515 printf ("new gc status is %i\n", status
);
517 if (status
== JSGC_END
) {
518 /* just to guard against reentering. */
519 gGCStatus
= JSGC_BEGIN
;
521 jsds_NotifyPendingDeadScripts (cx
);
526 return gLastGCProc (cx
, status
);
532 jsds_ErrorHookProc (JSDContext
*jsdc
, JSContext
*cx
, const char *message
,
533 JSErrorReport
*report
, void *callerdata
)
535 static PRBool running
= PR_FALSE
;
537 nsCOMPtr
<jsdIErrorHook
> hook
;
538 gJsds
->GetErrorHook(getter_AddRefs(hook
));
540 return JSD_ERROR_REPORTER_PASS_ALONG
;
543 return JSD_ERROR_REPORTER_PASS_ALONG
;
547 nsCOMPtr
<jsdIValue
> val
;
548 if (JS_IsExceptionPending(cx
)) {
550 JS_GetPendingException(cx
, &jv
);
551 JSDValue
*jsdv
= JSD_NewValue (jsdc
, jv
);
552 val
= getter_AddRefs(jsdValue::FromPtr(jsdc
, jsdv
));
555 nsCAutoString fileName
;
562 fileName
.Assign(report
->filename
);
563 line
= report
->lineno
;
564 pos
= report
->tokenptr
- report
->linebuf
;
565 flags
= report
->flags
;
566 errnum
= report
->errorNumber
;
576 gJsds
->Pause(nsnull
);
577 hook
->OnError (nsDependentCString(message
), fileName
, line
, pos
, flags
, errnum
, val
, &rval
);
578 gJsds
->UnPause(nsnull
);
582 return JSD_ERROR_REPORTER_DEBUG
;
584 return JSD_ERROR_REPORTER_PASS_ALONG
;
588 jsds_CallHookProc (JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
,
589 uintN type
, void* callerdata
)
591 nsCOMPtr
<jsdICallHook
> hook
;
595 case JSD_HOOK_TOPLEVEL_START
:
596 case JSD_HOOK_TOPLEVEL_END
:
597 gJsds
->GetTopLevelHook(getter_AddRefs(hook
));
600 case JSD_HOOK_FUNCTION_CALL
:
601 case JSD_HOOK_FUNCTION_RETURN
:
602 gJsds
->GetFunctionHook(getter_AddRefs(hook
));
606 NS_ASSERTION (0, "Unknown hook type.");
612 if (!jsds_FilterHook (jsdc
, jsdthreadstate
))
615 JSDStackFrameInfo
*native_frame
= JSD_GetStackFrame (jsdc
, jsdthreadstate
);
616 nsCOMPtr
<jsdIStackFrame
> frame
=
617 getter_AddRefs(jsdStackFrame::FromPtr(jsdc
, jsdthreadstate
,
619 gJsds
->Pause(nsnull
);
620 hook
->OnCall(frame
, type
);
621 gJsds
->UnPause(nsnull
);
622 jsdStackFrame::InvalidateAll();
628 jsds_ExecutionHookProc (JSDContext
* jsdc
, JSDThreadState
* jsdthreadstate
,
629 uintN type
, void* callerdata
, jsval
* rval
)
631 nsCOMPtr
<jsdIExecutionHook
> hook(0);
632 PRUint32 hook_rv
= JSD_HOOK_RETURN_CONTINUE
;
633 nsCOMPtr
<jsdIValue
> js_rv
;
637 case JSD_HOOK_INTERRUPTED
:
638 gJsds
->GetInterruptHook(getter_AddRefs(hook
));
640 case JSD_HOOK_DEBUG_REQUESTED
:
641 gJsds
->GetDebugHook(getter_AddRefs(hook
));
643 case JSD_HOOK_DEBUGGER_KEYWORD
:
644 gJsds
->GetDebuggerHook(getter_AddRefs(hook
));
646 case JSD_HOOK_BREAKPOINT
:
648 /* we can't pause breakpoints the way we pause the other
649 * execution hooks (at least, not easily.) Instead we bail
650 * here if the service is paused. */
652 gJsds
->GetPauseDepth(&level
);
654 gJsds
->GetBreakpointHook(getter_AddRefs(hook
));
659 hook_rv
= JSD_HOOK_RETURN_CONTINUE_THROW
;
660 gJsds
->GetThrowHook(getter_AddRefs(hook
));
662 JSDValue
*jsdv
= JSD_GetException (jsdc
, jsdthreadstate
);
663 js_rv
= getter_AddRefs(jsdValue::FromPtr (jsdc
, jsdv
));
668 NS_ASSERTION (0, "Unknown hook type.");
674 if (!jsds_FilterHook (jsdc
, jsdthreadstate
))
675 return JSD_HOOK_RETURN_CONTINUE
;
677 JSDStackFrameInfo
*native_frame
= JSD_GetStackFrame (jsdc
, jsdthreadstate
);
678 nsCOMPtr
<jsdIStackFrame
> frame
=
679 getter_AddRefs(jsdStackFrame::FromPtr(jsdc
, jsdthreadstate
,
681 gJsds
->Pause(nsnull
);
682 jsdIValue
*inout_rv
= js_rv
;
683 NS_IF_ADDREF(inout_rv
);
684 hook
->OnExecute (frame
, type
, &inout_rv
, &hook_rv
);
686 NS_IF_RELEASE(inout_rv
);
687 gJsds
->UnPause(nsnull
);
688 jsdStackFrame::InvalidateAll();
690 if (hook_rv
== JSD_HOOK_RETURN_RET_WITH_VAL
||
691 hook_rv
== JSD_HOOK_RETURN_THROW_WITH_VAL
) {
695 if (NS_SUCCEEDED(js_rv
->GetJSDValue (&jsdv
)))
696 *rval
= JSD_GetValueWrappedJSVal(jsdc
, jsdv
);
704 jsds_ScriptHookProc (JSDContext
* jsdc
, JSDScript
* jsdscript
, JSBool creating
,
707 #ifdef CAUTIOUS_SCRIPTHOOK
708 JSContext
*cx
= JSD_GetDefaultJSContext(jsdc
);
709 JSRuntime
*rt
= JS_GetRuntime(cx
);
713 nsCOMPtr
<jsdIScriptHook
> hook
;
714 gJsds
->GetScriptHook(getter_AddRefs(hook
));
716 /* a script is being created */
718 /* nobody cares, just exit */
722 nsCOMPtr
<jsdIScript
> script
=
723 getter_AddRefs(jsdScript::FromPtr(jsdc
, jsdscript
));
724 #ifdef CAUTIOUS_SCRIPTHOOK
727 gJsds
->Pause(nsnull
);
728 hook
->OnScriptCreated (script
);
729 gJsds
->UnPause(nsnull
);
730 #ifdef CAUTIOUS_SCRIPTHOOK
734 /* a script is being destroyed. even if there is no registered hook
735 * we'll still need to invalidate the jsdIScript record, in order
736 * to remove the reference held in the JSDScript private data. */
737 nsCOMPtr
<jsdIScript
> jsdis
=
738 static_cast<jsdIScript
*>(JSD_GetScriptPrivate(jsdscript
));
744 if (gGCStatus
== JSGC_END
) {
745 nsCOMPtr
<jsdIScriptHook
> hook
;
746 gJsds
->GetScriptHook(getter_AddRefs(hook
));
750 /* if GC *isn't* running, we can tell the user about the script
752 #ifdef CAUTIOUS_SCRIPTHOOK
756 gJsds
->Pause(nsnull
);
757 hook
->OnScriptDestroyed (jsdis
);
758 gJsds
->UnPause(nsnull
);
759 #ifdef CAUTIOUS_SCRIPTHOOK
763 /* if a GC *is* running, we've got to wait until it's done before
764 * we can execute any JS, so we queue the notification in a PRCList
765 * until GC tells us it's done. See jsds_GCCallbackProc(). */
766 DeadScript
*ds
= PR_NEW(DeadScript
);
768 return; /* NS_ERROR_OUT_OF_MEMORY */
772 NS_ADDREF(ds
->script
);
774 /* if the queue exists, add to it */
775 PR_APPEND_LINK(&ds
->links
, &gDeadScripts
->links
);
777 /* otherwise create the queue */
778 PR_INIT_CLIST(&ds
->links
);
785 /*******************************************************************************
786 * reflected jsd data structures
787 *******************************************************************************/
791 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral);
794 jsdContext::GetJSDContext(JSDContext **_rval)
802 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject
, jsdIObject
)
805 jsdObject::GetJSDContext(JSDContext
**_rval
)
812 jsdObject::GetJSDObject(JSDObject
**_rval
)
819 jsdObject::GetCreatorURL(nsACString
&_rval
)
821 _rval
.Assign(JSD_GetObjectNewURL(mCx
, mObject
));
826 jsdObject::GetCreatorLine(PRUint32
*_rval
)
828 *_rval
= JSD_GetObjectNewLineNumber(mCx
, mObject
);
833 jsdObject::GetConstructorURL(nsACString
&_rval
)
835 _rval
.Assign(JSD_GetObjectConstructorURL(mCx
, mObject
));
840 jsdObject::GetConstructorLine(PRUint32
*_rval
)
842 *_rval
= JSD_GetObjectConstructorLineNumber(mCx
, mObject
);
847 jsdObject::GetValue(jsdIValue
**_rval
)
849 JSDValue
*jsdv
= JSD_GetValueForObject (mCx
, mObject
);
851 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
856 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty
, jsdIProperty
, jsdIEphemeral
)
858 jsdProperty::jsdProperty (JSDContext
*aCx
, JSDProperty
*aProperty
) :
859 mCx(aCx
), mProperty(aProperty
)
861 DEBUG_CREATE ("jsdProperty", gPropertyCount
);
862 mValid
= (aCx
&& aProperty
);
863 mLiveListEntry
.value
= this;
864 jsds_InsertEphemeral (&gLiveProperties
, &mLiveListEntry
);
867 jsdProperty::~jsdProperty ()
869 DEBUG_DESTROY ("jsdProperty", gPropertyCount
);
875 jsdProperty::Invalidate()
877 ASSERT_VALID_EPHEMERAL
;
879 jsds_RemoveEphemeral (&gLiveProperties
, &mLiveListEntry
);
880 JSD_DropProperty (mCx
, mProperty
);
885 jsdProperty::InvalidateAll()
888 jsds_InvalidateAllEphemerals (&gLiveProperties
);
892 jsdProperty::GetJSDContext(JSDContext
**_rval
)
899 jsdProperty::GetJSDProperty(JSDProperty
**_rval
)
906 jsdProperty::GetIsValid(PRBool
*_rval
)
913 jsdProperty::GetAlias(jsdIValue
**_rval
)
915 JSDValue
*jsdv
= JSD_GetPropertyValue (mCx
, mProperty
);
917 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
922 jsdProperty::GetFlags(PRUint32
*_rval
)
924 *_rval
= JSD_GetPropertyFlags (mCx
, mProperty
);
929 jsdProperty::GetName(jsdIValue
**_rval
)
931 JSDValue
*jsdv
= JSD_GetPropertyName (mCx
, mProperty
);
933 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
938 jsdProperty::GetValue(jsdIValue
**_rval
)
940 JSDValue
*jsdv
= JSD_GetPropertyValue (mCx
, mProperty
);
942 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
947 jsdProperty::GetVarArgSlot(PRUint32
*_rval
)
949 *_rval
= JSD_GetPropertyVarArgSlot (mCx
, mProperty
);
954 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript
, jsdIScript
, jsdIEphemeral
)
956 jsdScript::jsdScript (JSDContext
*aCx
, JSDScript
*aScript
) : mValid(PR_FALSE
),
967 DEBUG_CREATE ("jsdScript", gScriptCount
);
970 /* copy the script's information now, so we have it later, when it
972 JSD_LockScriptSubsystem(mCx
);
973 mFileName
= new nsCString(JSD_GetScriptFilename(mCx
, mScript
));
975 new nsCString(JSD_GetScriptFunctionName(mCx
, mScript
));
976 mBaseLineNumber
= JSD_GetScriptBaseLineNumber(mCx
, mScript
);
977 mLineExtent
= JSD_GetScriptLineExtent(mCx
, mScript
);
978 mFirstPC
= JSD_GetClosestPC(mCx
, mScript
, 0);
979 JSD_UnlockScriptSubsystem(mCx
);
985 jsdScript::~jsdScript ()
987 DEBUG_DESTROY ("jsdScript", gScriptCount
);
991 delete mFunctionName
;
996 /* Invalidate() needs to be called to release an owning reference to
997 * ourselves, so if we got here without being invalidated, something
998 * has gone wrong with our ref count. */
999 NS_ASSERTION (!mValid
, "Script destroyed without being invalidated.");
1003 * This method populates a line <-> pc map for a pretty printed version of this
1004 * script. It does this by decompiling, and then recompiling the script. The
1005 * resulting script is scanned for the line map, and then left as GC fodder.
1008 jsdScript::CreatePPLineMap()
1010 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
1011 JSAutoRequest
ar(cx
);
1012 JSObject
*obj
= JS_NewObject(cx
, NULL
, NULL
, NULL
);
1013 JSFunction
*fun
= JSD_GetJSFunction (mCx
, mScript
);
1016 PRBool scriptOwner
= PR_FALSE
;
1019 uintN nargs
= JS_GetFunctionArgumentCount(cx
, fun
);
1022 JSString
*jsstr
= JS_DecompileFunctionBody (cx
, fun
, 4);
1026 const char *argnames
[] = {"arg1", "arg2", "arg3", "arg4",
1027 "arg5", "arg6", "arg7", "arg8",
1028 "arg9", "arg10", "arg11", "arg12" };
1029 fun
= JS_CompileUCFunction (cx
, obj
, "ppfun", nargs
, argnames
,
1030 JS_GetStringChars(jsstr
),
1031 JS_GetStringLength(jsstr
),
1032 "x-jsd:ppbuffer?type=function", 3);
1033 if (!fun
|| !(script
= JS_GetFunctionScript(cx
, fun
)))
1037 JSString
*jsstr
= JS_DecompileScript (cx
, JSD_GetJSScript(mCx
, mScript
),
1042 script
= JS_CompileUCScript (cx
, obj
,
1043 JS_GetStringChars(jsstr
),
1044 JS_GetStringLength(jsstr
),
1045 "x-jsd:ppbuffer?type=script", 1);
1048 scriptOwner
= PR_TRUE
;
1052 PRUint32 scriptExtent
= JS_GetScriptLineExtent (cx
, script
);
1053 jsbytecode
* firstPC
= JS_LineNumberToPC (cx
, script
, 0);
1054 /* allocate worst case size of map (number of lines in script + 1
1055 * for our 0 record), we'll shrink it with a realloc later. */
1056 PCMapEntry
*lineMap
=
1057 static_cast<PCMapEntry
*>
1058 (PR_Malloc((scriptExtent
+ 1) * sizeof (PCMapEntry
)));
1059 PRUint32 lineMapSize
= 0;
1062 for (PRUint32 line
= baseLine
; line
< scriptExtent
+ baseLine
; ++line
) {
1063 jsbytecode
* pc
= JS_LineNumberToPC (cx
, script
, line
);
1064 if (line
== JS_PCToLineNumber (cx
, script
, pc
)) {
1065 lineMap
[lineMapSize
].line
= line
;
1066 lineMap
[lineMapSize
].pc
= pc
- firstPC
;
1070 if (scriptExtent
!= lineMapSize
) {
1072 static_cast<PCMapEntry
*>
1073 (PR_Realloc(mPPLineMap
= lineMap
,
1074 lineMapSize
* sizeof(PCMapEntry
)));
1076 PR_Free(mPPLineMap
);
1083 JS_DestroyScript (cx
, script
);
1085 mPCMapSize
= lineMapSize
;
1086 return mPPLineMap
= lineMap
;
1090 jsdScript::PPPcToLine (PRUint32 aPC
)
1092 if (!mPPLineMap
&& !CreatePPLineMap())
1095 for (i
= 1; i
< mPCMapSize
; ++i
) {
1096 if (mPPLineMap
[i
].pc
> aPC
)
1097 return mPPLineMap
[i
- 1].line
;
1100 return mPPLineMap
[mPCMapSize
- 1].line
;
1104 jsdScript::PPLineToPc (PRUint32 aLine
)
1106 if (!mPPLineMap
&& !CreatePPLineMap())
1109 for (i
= 1; i
< mPCMapSize
; ++i
) {
1110 if (mPPLineMap
[i
].line
> aLine
)
1111 return mPPLineMap
[i
- 1].pc
;
1114 return mPPLineMap
[mPCMapSize
- 1].pc
;
1118 jsdScript::GetJSDContext(JSDContext
**_rval
)
1120 ASSERT_VALID_EPHEMERAL
;
1126 jsdScript::GetJSDScript(JSDScript
**_rval
)
1128 ASSERT_VALID_EPHEMERAL
;
1134 jsdScript::GetVersion (PRInt32
*_rval
)
1136 ASSERT_VALID_EPHEMERAL
;
1137 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
1138 JSScript
*script
= JSD_GetJSScript(mCx
, mScript
);
1139 *_rval
= static_cast<PRInt32
>(JS_GetScriptVersion(cx
, script
));
1144 jsdScript::GetTag(PRUint32
*_rval
)
1147 mTag
= ++jsdScript::LastTag
;
1154 jsdScript::Invalidate()
1156 ASSERT_VALID_EPHEMERAL
;
1159 /* release the addref we do in FromPtr */
1160 jsdIScript
*script
= static_cast<jsdIScript
*>
1161 (JSD_GetScriptPrivate(mScript
));
1162 NS_ASSERTION (script
== this, "That's not my script!");
1164 JSD_SetScriptPrivate(mScript
, NULL
);
1169 jsdScript::InvalidateAll ()
1172 if (NS_FAILED(gJsds
->GetJSDContext (&cx
)))
1176 JSDScript
*iter
= NULL
;
1178 JSD_LockScriptSubsystem(cx
);
1179 while((script
= JSD_IterateScripts(cx
, &iter
)) != NULL
) {
1180 nsCOMPtr
<jsdIScript
> jsdis
=
1181 static_cast<jsdIScript
*>(JSD_GetScriptPrivate(script
));
1183 jsdis
->Invalidate();
1185 JSD_UnlockScriptSubsystem(cx
);
1189 jsdScript::GetIsValid(PRBool
*_rval
)
1196 jsdScript::SetFlags(PRUint32 flags
)
1198 ASSERT_VALID_EPHEMERAL
;
1199 JSD_SetScriptFlags(mCx
, mScript
, flags
);
1204 jsdScript::GetFlags(PRUint32
*_rval
)
1206 ASSERT_VALID_EPHEMERAL
;
1207 *_rval
= JSD_GetScriptFlags(mCx
, mScript
);
1212 jsdScript::GetFileName(nsACString
&_rval
)
1214 _rval
.Assign(*mFileName
);
1219 jsdScript::GetFunctionName(nsACString
&_rval
)
1221 _rval
.Assign(*mFunctionName
);
1226 jsdScript::GetParameterNames(PRUint32
* count
, PRUnichar
*** paramNames
)
1228 ASSERT_VALID_EPHEMERAL
;
1229 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
1231 NS_WARNING("No default context !?");
1232 return NS_ERROR_FAILURE
;
1234 JSFunction
*fun
= JSD_GetJSFunction (mCx
, mScript
);
1236 JSAutoRequest
ar(cx
);
1240 !JS_FunctionHasLocalNames(cx
, fun
) ||
1241 (nargs
= JS_GetFunctionArgumentCount(cx
, fun
)) == 0) {
1243 *paramNames
= nsnull
;
1248 static_cast<PRUnichar
**>(NS_Alloc(nargs
* sizeof(PRUnichar
*)));
1250 return NS_ERROR_OUT_OF_MEMORY
;
1253 jsuword
*names
= JS_GetFunctionLocalNameArray(cx
, fun
, &mark
);
1256 return NS_ERROR_OUT_OF_MEMORY
;
1259 nsresult rv
= NS_OK
;
1260 for (uintN i
= 0; i
< nargs
; ++i
) {
1261 JSAtom
*atom
= JS_LocalNameToAtom(names
[i
]);
1265 JSString
*str
= JS_AtomKey(atom
);
1266 ret
[i
] = NS_strndup(reinterpret_cast<PRUnichar
*>(JS_GetStringChars(str
)),
1267 JS_GetStringLength(str
));
1269 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i
, ret
);
1270 rv
= NS_ERROR_OUT_OF_MEMORY
;
1275 JS_ReleaseFunctionLocalNameArray(cx
, mark
);
1284 jsdScript::GetFunctionObject(jsdIValue
**_rval
)
1286 JSFunction
*fun
= JSD_GetJSFunction(mCx
, mScript
);
1288 return NS_ERROR_NOT_AVAILABLE
;
1290 JSObject
*obj
= JS_GetFunctionObject(fun
);
1292 return NS_ERROR_FAILURE
;
1295 if (NS_FAILED(gJsds
->GetJSDContext (&cx
)))
1296 return NS_ERROR_NOT_INITIALIZED
;
1298 JSDValue
*jsdv
= JSD_NewValue(cx
, OBJECT_TO_JSVAL(obj
));
1300 return NS_ERROR_OUT_OF_MEMORY
;
1302 *_rval
= jsdValue::FromPtr(cx
, jsdv
);
1304 JSD_DropValue(cx
, jsdv
);
1305 return NS_ERROR_OUT_OF_MEMORY
;
1312 jsdScript::GetFunctionSource(nsAString
& aFunctionSource
)
1314 ASSERT_VALID_EPHEMERAL
;
1315 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
1317 NS_WARNING("No default context !?");
1318 return NS_ERROR_FAILURE
;
1320 JSFunction
*fun
= JSD_GetJSFunction (mCx
, mScript
);
1322 JSAutoRequest
ar(cx
);
1326 JSAutoEnterCompartment ac
;
1327 if (!ac
.enter(cx
, JS_GetFunctionObject(fun
)))
1328 return NS_ERROR_FAILURE
;
1329 jsstr
= JS_DecompileFunction (cx
, fun
, 4);
1331 JSScript
*script
= JSD_GetJSScript (mCx
, mScript
);
1332 js::SwitchToCompartment
sc(cx
, script
->compartment
);
1333 jsstr
= JS_DecompileScript (cx
, script
, "ppscript", 4);
1336 return NS_ERROR_FAILURE
;
1340 reinterpret_cast<PRUnichar
*>(JS_GetStringChars(jsstr
)),
1341 JS_GetStringLength(jsstr
));
1346 jsdScript::GetBaseLineNumber(PRUint32
*_rval
)
1348 *_rval
= mBaseLineNumber
;
1353 jsdScript::GetLineExtent(PRUint32
*_rval
)
1355 *_rval
= mLineExtent
;
1360 jsdScript::GetCallCount(PRUint32
*_rval
)
1362 ASSERT_VALID_EPHEMERAL
;
1363 *_rval
= JSD_GetScriptCallCount (mCx
, mScript
);
1368 jsdScript::GetMaxRecurseDepth(PRUint32
*_rval
)
1370 ASSERT_VALID_EPHEMERAL
;
1371 *_rval
= JSD_GetScriptMaxRecurseDepth (mCx
, mScript
);
1376 jsdScript::GetMinExecutionTime(double *_rval
)
1378 ASSERT_VALID_EPHEMERAL
;
1379 *_rval
= JSD_GetScriptMinExecutionTime (mCx
, mScript
);
1384 jsdScript::GetMaxExecutionTime(double *_rval
)
1386 ASSERT_VALID_EPHEMERAL
;
1387 *_rval
= JSD_GetScriptMaxExecutionTime (mCx
, mScript
);
1392 jsdScript::GetTotalExecutionTime(double *_rval
)
1394 ASSERT_VALID_EPHEMERAL
;
1395 *_rval
= JSD_GetScriptTotalExecutionTime (mCx
, mScript
);
1400 jsdScript::GetMinOwnExecutionTime(double *_rval
)
1402 ASSERT_VALID_EPHEMERAL
;
1403 *_rval
= JSD_GetScriptMinOwnExecutionTime (mCx
, mScript
);
1408 jsdScript::GetMaxOwnExecutionTime(double *_rval
)
1410 ASSERT_VALID_EPHEMERAL
;
1411 *_rval
= JSD_GetScriptMaxOwnExecutionTime (mCx
, mScript
);
1416 jsdScript::GetTotalOwnExecutionTime(double *_rval
)
1418 ASSERT_VALID_EPHEMERAL
;
1419 *_rval
= JSD_GetScriptTotalOwnExecutionTime (mCx
, mScript
);
1424 jsdScript::ClearProfileData()
1426 ASSERT_VALID_EPHEMERAL
;
1427 JSD_ClearScriptProfileData(mCx
, mScript
);
1432 jsdScript::PcToLine(PRUint32 aPC
, PRUint32 aPcmap
, PRUint32
*_rval
)
1434 ASSERT_VALID_EPHEMERAL
;
1435 if (aPcmap
== PCMAP_SOURCETEXT
) {
1436 *_rval
= JSD_GetClosestLine (mCx
, mScript
, mFirstPC
+ aPC
);
1437 } else if (aPcmap
== PCMAP_PRETTYPRINT
) {
1438 *_rval
= PPPcToLine(aPC
);
1440 return NS_ERROR_INVALID_ARG
;
1447 jsdScript::LineToPc(PRUint32 aLine
, PRUint32 aPcmap
, PRUint32
*_rval
)
1449 ASSERT_VALID_EPHEMERAL
;
1450 if (aPcmap
== PCMAP_SOURCETEXT
) {
1451 jsuword pc
= JSD_GetClosestPC (mCx
, mScript
, aLine
);
1452 *_rval
= pc
- mFirstPC
;
1453 } else if (aPcmap
== PCMAP_PRETTYPRINT
) {
1454 *_rval
= PPLineToPc(aLine
);
1456 return NS_ERROR_INVALID_ARG
;
1463 jsdScript::IsLineExecutable(PRUint32 aLine
, PRUint32 aPcmap
, PRBool
*_rval
)
1465 ASSERT_VALID_EPHEMERAL
;
1466 if (aPcmap
== PCMAP_SOURCETEXT
) {
1467 jsuword pc
= JSD_GetClosestPC (mCx
, mScript
, aLine
);
1468 *_rval
= (aLine
== JSD_GetClosestLine (mCx
, mScript
, pc
));
1469 } else if (aPcmap
== PCMAP_PRETTYPRINT
) {
1470 if (!mPPLineMap
&& !CreatePPLineMap())
1471 return NS_ERROR_OUT_OF_MEMORY
;
1473 for (PRUint32 i
= 0; i
< mPCMapSize
; ++i
) {
1474 if (mPPLineMap
[i
].line
>= aLine
) {
1475 *_rval
= (mPPLineMap
[i
].line
== aLine
);
1480 return NS_ERROR_INVALID_ARG
;
1487 jsdScript::SetBreakpoint(PRUint32 aPC
)
1489 ASSERT_VALID_EPHEMERAL
;
1490 jsuword pc
= mFirstPC
+ aPC
;
1491 JSD_SetExecutionHook (mCx
, mScript
, pc
, jsds_ExecutionHookProc
, NULL
);
1496 jsdScript::ClearBreakpoint(PRUint32 aPC
)
1498 ASSERT_VALID_EPHEMERAL
;
1499 jsuword pc
= mFirstPC
+ aPC
;
1500 JSD_ClearExecutionHook (mCx
, mScript
, pc
);
1505 jsdScript::ClearAllBreakpoints()
1507 ASSERT_VALID_EPHEMERAL
;
1508 JSD_LockScriptSubsystem(mCx
);
1509 JSD_ClearAllExecutionHooksForScript (mCx
, mScript
);
1510 JSD_UnlockScriptSubsystem(mCx
);
1515 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext
, jsdIContext
, jsdIEphemeral
)
1518 jsdContext::FromPtr (JSDContext
*aJSDCx
, JSContext
*aJSCx
)
1520 if (!aJSDCx
|| !aJSCx
)
1523 nsCOMPtr
<jsdIContext
> jsdicx
;
1524 nsCOMPtr
<jsdIEphemeral
> eph
=
1525 jsds_FindEphemeral (&gLiveContexts
, static_cast<void *>(aJSCx
));
1528 jsdicx
= do_QueryInterface(eph
);
1532 nsCOMPtr
<nsISupports
> iscx
;
1533 if (JS_GetOptions(aJSCx
) & JSOPTION_PRIVATE_IS_NSISUPPORTS
)
1534 iscx
= static_cast<nsISupports
*>(JS_GetContextPrivate(aJSCx
));
1535 jsdicx
= new jsdContext (aJSDCx
, aJSCx
, iscx
);
1538 jsdIContext
*ctx
= nsnull
;
1543 jsdContext::jsdContext (JSDContext
*aJSDCx
, JSContext
*aJSCx
,
1544 nsISupports
*aISCx
) : mValid(PR_TRUE
), mTag(0),
1546 mJSCx(aJSCx
), mISCx(aISCx
)
1548 DEBUG_CREATE ("jsdContext", gContextCount
);
1549 mLiveListEntry
.value
= this;
1550 mLiveListEntry
.key
= static_cast<void *>(aJSCx
);
1551 jsds_InsertEphemeral (&gLiveContexts
, &mLiveListEntry
);
1554 jsdContext::~jsdContext()
1556 DEBUG_DESTROY ("jsdContext", gContextCount
);
1559 /* call Invalidate() to take ourselves out of the live list */
1565 jsdContext::GetIsValid(PRBool
*_rval
)
1572 jsdContext::Invalidate()
1574 ASSERT_VALID_EPHEMERAL
;
1576 jsds_RemoveEphemeral (&gLiveContexts
, &mLiveListEntry
);
1581 jsdContext::InvalidateAll()
1584 jsds_InvalidateAllEphemerals (&gLiveContexts
);
1588 jsdContext::GetJSContext(JSContext
**_rval
)
1590 ASSERT_VALID_EPHEMERAL
;
1596 jsdContext::GetOptions(PRUint32
*_rval
)
1598 ASSERT_VALID_EPHEMERAL
;
1599 *_rval
= JS_GetOptions(mJSCx
);
1604 jsdContext::SetOptions(PRUint32 options
)
1606 ASSERT_VALID_EPHEMERAL
;
1607 PRUint32 lastOptions
= JS_GetOptions(mJSCx
);
1609 /* don't let users change this option, they'd just be shooting themselves
1611 if ((options
^ lastOptions
) & JSOPTION_PRIVATE_IS_NSISUPPORTS
)
1612 return NS_ERROR_ILLEGAL_VALUE
;
1614 JS_SetOptions(mJSCx
, options
);
1619 jsdContext::GetPrivateData(nsISupports
**_rval
)
1621 ASSERT_VALID_EPHEMERAL
;
1622 PRUint32 options
= JS_GetOptions(mJSCx
);
1623 if (options
& JSOPTION_PRIVATE_IS_NSISUPPORTS
)
1625 *_rval
= static_cast<nsISupports
*>(JS_GetContextPrivate(mJSCx
));
1626 NS_IF_ADDREF(*_rval
);
1637 jsdContext::GetWrappedContext(nsISupports
**_rval
)
1639 ASSERT_VALID_EPHEMERAL
;
1640 NS_IF_ADDREF(*_rval
= mISCx
);
1645 jsdContext::GetTag(PRUint32
*_rval
)
1647 ASSERT_VALID_EPHEMERAL
;
1649 mTag
= ++jsdContext::LastTag
;
1656 jsdContext::GetVersion (PRInt32
*_rval
)
1658 ASSERT_VALID_EPHEMERAL
;
1659 *_rval
= static_cast<PRInt32
>(JS_GetVersion(mJSCx
));
1664 jsdContext::SetVersion (PRInt32 id
)
1666 ASSERT_VALID_EPHEMERAL
;
1667 JSVersion ver
= static_cast<JSVersion
>(id
);
1668 JS_SetVersion(mJSCx
, ver
);
1673 jsdContext::GetGlobalObject (jsdIValue
**_rval
)
1675 ASSERT_VALID_EPHEMERAL
;
1676 JSObject
*glob
= JS_GetGlobalObject(mJSCx
);
1677 JSDValue
*jsdv
= JSD_NewValue (mJSDCx
, OBJECT_TO_JSVAL(glob
));
1679 return NS_ERROR_FAILURE
;
1680 *_rval
= jsdValue::FromPtr (mJSDCx
, jsdv
);
1682 return NS_ERROR_FAILURE
;
1687 jsdContext::GetScriptsEnabled (PRBool
*_rval
)
1689 ASSERT_VALID_EPHEMERAL
;
1695 nsCOMPtr
<nsIScriptContext
> context
= do_QueryInterface(mISCx
);
1697 return NS_ERROR_NO_INTERFACE
;
1699 *_rval
= context
->GetScriptsEnabled();
1705 jsdContext::SetScriptsEnabled (PRBool _rval
)
1707 ASSERT_VALID_EPHEMERAL
;
1711 return NS_ERROR_NO_INTERFACE
;
1714 nsCOMPtr
<nsIScriptContext
> context
= do_QueryInterface(mISCx
);
1716 return NS_ERROR_NO_INTERFACE
;
1718 context
->SetScriptsEnabled(_rval
, PR_TRUE
);
1724 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame
, jsdIStackFrame
, jsdIEphemeral
)
1726 jsdStackFrame::jsdStackFrame (JSDContext
*aCx
, JSDThreadState
*aThreadState
,
1727 JSDStackFrameInfo
*aStackFrameInfo
) :
1728 mCx(aCx
), mThreadState(aThreadState
), mStackFrameInfo(aStackFrameInfo
)
1730 DEBUG_CREATE ("jsdStackFrame", gFrameCount
);
1731 mValid
= (aCx
&& aThreadState
&& aStackFrameInfo
);
1733 mLiveListEntry
.key
= aStackFrameInfo
;
1734 mLiveListEntry
.value
= this;
1735 jsds_InsertEphemeral (&gLiveStackFrames
, &mLiveListEntry
);
1739 jsdStackFrame::~jsdStackFrame()
1741 DEBUG_DESTROY ("jsdStackFrame", gFrameCount
);
1744 /* call Invalidate() to take ourselves out of the live list */
1750 jsdStackFrame::FromPtr (JSDContext
*aCx
, JSDThreadState
*aThreadState
,
1751 JSDStackFrameInfo
*aStackFrameInfo
)
1753 if (!aStackFrameInfo
)
1757 nsCOMPtr
<jsdIStackFrame
> frame
;
1759 nsCOMPtr
<jsdIEphemeral
> eph
=
1760 jsds_FindEphemeral (&gLiveStackFrames
,
1761 reinterpret_cast<void *>(aStackFrameInfo
));
1765 frame
= do_QueryInterface(eph
);
1770 rv
= new jsdStackFrame (aCx
, aThreadState
, aStackFrameInfo
);
1778 jsdStackFrame::Invalidate()
1780 ASSERT_VALID_EPHEMERAL
;
1782 jsds_RemoveEphemeral (&gLiveStackFrames
, &mLiveListEntry
);
1787 jsdStackFrame::InvalidateAll()
1789 if (gLiveStackFrames
)
1790 jsds_InvalidateAllEphemerals (&gLiveStackFrames
);
1794 jsdStackFrame::GetJSDContext(JSDContext
**_rval
)
1796 ASSERT_VALID_EPHEMERAL
;
1802 jsdStackFrame::GetJSDThreadState(JSDThreadState
**_rval
)
1804 ASSERT_VALID_EPHEMERAL
;
1805 *_rval
= mThreadState
;
1810 jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo
**_rval
)
1812 ASSERT_VALID_EPHEMERAL
;
1813 *_rval
= mStackFrameInfo
;
1818 jsdStackFrame::GetIsValid(PRBool
*_rval
)
1825 jsdStackFrame::GetCallingFrame(jsdIStackFrame
**_rval
)
1827 ASSERT_VALID_EPHEMERAL
;
1828 JSDStackFrameInfo
*sfi
= JSD_GetCallingStackFrame (mCx
, mThreadState
,
1830 *_rval
= jsdStackFrame::FromPtr (mCx
, mThreadState
, sfi
);
1835 jsdStackFrame::GetExecutionContext(jsdIContext
**_rval
)
1837 ASSERT_VALID_EPHEMERAL
;
1838 JSContext
*cx
= JSD_GetJSContext (mCx
, mThreadState
);
1839 *_rval
= jsdContext::FromPtr (mCx
, cx
);
1844 jsdStackFrame::GetFunctionName(nsACString
&_rval
)
1846 ASSERT_VALID_EPHEMERAL
;
1847 _rval
.Assign(JSD_GetNameForStackFrame(mCx
, mThreadState
, mStackFrameInfo
));
1852 jsdStackFrame::GetIsDebugger(PRBool
*_rval
)
1854 ASSERT_VALID_EPHEMERAL
;
1855 *_rval
= JSD_IsStackFrameDebugger (mCx
, mThreadState
, mStackFrameInfo
);
1860 jsdStackFrame::GetIsConstructing(PRBool
*_rval
)
1862 ASSERT_VALID_EPHEMERAL
;
1863 *_rval
= JSD_IsStackFrameConstructing (mCx
, mThreadState
, mStackFrameInfo
);
1868 jsdStackFrame::GetScript(jsdIScript
**_rval
)
1870 ASSERT_VALID_EPHEMERAL
;
1871 JSDScript
*script
= JSD_GetScriptForStackFrame (mCx
, mThreadState
,
1873 *_rval
= jsdScript::FromPtr (mCx
, script
);
1878 jsdStackFrame::GetPc(PRUint32
*_rval
)
1880 ASSERT_VALID_EPHEMERAL
;
1881 JSDScript
*script
= JSD_GetScriptForStackFrame (mCx
, mThreadState
,
1884 return NS_ERROR_FAILURE
;
1885 jsuword pcbase
= JSD_GetClosestPC(mCx
, script
, 0);
1887 jsuword pc
= JSD_GetPCForStackFrame (mCx
, mThreadState
, mStackFrameInfo
);
1889 *_rval
= pc
- pcbase
;
1896 jsdStackFrame::GetLine(PRUint32
*_rval
)
1898 ASSERT_VALID_EPHEMERAL
;
1899 JSDScript
*script
= JSD_GetScriptForStackFrame (mCx
, mThreadState
,
1902 jsuword pc
= JSD_GetPCForStackFrame (mCx
, mThreadState
, mStackFrameInfo
);
1903 *_rval
= JSD_GetClosestLine (mCx
, script
, pc
);
1905 return NS_ERROR_FAILURE
;
1911 jsdStackFrame::GetCallee(jsdIValue
**_rval
)
1913 ASSERT_VALID_EPHEMERAL
;
1914 JSDValue
*jsdv
= JSD_GetCallObjectForStackFrame (mCx
, mThreadState
,
1917 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
1922 jsdStackFrame::GetScope(jsdIValue
**_rval
)
1924 ASSERT_VALID_EPHEMERAL
;
1925 JSDValue
*jsdv
= JSD_GetScopeChainForStackFrame (mCx
, mThreadState
,
1928 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
1933 jsdStackFrame::GetThisValue(jsdIValue
**_rval
)
1935 ASSERT_VALID_EPHEMERAL
;
1936 JSDValue
*jsdv
= JSD_GetThisForStackFrame (mCx
, mThreadState
,
1939 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
1945 jsdStackFrame::Eval (const nsAString
&bytes
, const nsACString
&fileName
,
1946 PRUint32 line
, jsdIValue
**result
, PRBool
*_rval
)
1948 ASSERT_VALID_EPHEMERAL
;
1950 if (bytes
.IsEmpty())
1951 return NS_ERROR_INVALID_ARG
;
1953 // get pointer to buffer contained in |bytes|
1954 nsAString::const_iterator h
;
1955 bytes
.BeginReading(h
);
1956 const jschar
*char_bytes
= reinterpret_cast<const jschar
*>(h
.get());
1958 JSExceptionState
*estate
= 0;
1961 JSContext
*cx
= JSD_GetJSContext (mCx
, mThreadState
);
1963 JSAutoRequest
ar(cx
);
1965 estate
= JS_SaveExceptionState (cx
);
1966 JS_ClearPendingException (cx
);
1969 nsCOMPtr
<nsIJSContextStack
> stack
= do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
);
1970 if (NS_SUCCEEDED(rv
))
1971 rv
= stack
->Push(cx
);
1972 if (NS_FAILED(rv
)) {
1973 JS_RestoreExceptionState (cx
, estate
);
1977 *_rval
= JSD_AttemptUCScriptInStackFrame (mCx
, mThreadState
,
1979 char_bytes
, bytes
.Length(),
1980 PromiseFlatCString(fileName
).get(),
1983 if (JS_IsExceptionPending(cx
))
1984 JS_GetPendingException (cx
, &jv
);
1989 JS_RestoreExceptionState (cx
, estate
);
1992 JSContext
* poppedCX
;
1993 rv
= stack
->Pop(&poppedCX
);
1994 NS_ASSERTION(NS_SUCCEEDED(rv
) && poppedCX
== cx
, "bad pop");
1996 (void) stack
->Pop(nsnull
);
1999 JSDValue
*jsdv
= JSD_NewValue (mCx
, jv
);
2001 return NS_ERROR_FAILURE
;
2002 *result
= jsdValue::FromPtr (mCx
, jsdv
);
2004 return NS_ERROR_FAILURE
;
2010 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue
, jsdIValue
, jsdIEphemeral
)
2012 jsdValue::FromPtr (JSDContext
*aCx
, JSDValue
*aValue
)
2014 /* value will be dropped by te jsdValue destructor. */
2019 jsdIValue
*rv
= new jsdValue (aCx
, aValue
);
2024 jsdValue::jsdValue (JSDContext
*aCx
, JSDValue
*aValue
) : mValid(PR_TRUE
),
2028 DEBUG_CREATE ("jsdValue", gValueCount
);
2029 mLiveListEntry
.value
= this;
2030 jsds_InsertEphemeral (&gLiveValues
, &mLiveListEntry
);
2033 jsdValue::~jsdValue()
2035 DEBUG_DESTROY ("jsdValue", gValueCount
);
2037 /* call Invalidate() to take ourselves out of the live list */
2042 jsdValue::GetIsValid(PRBool
*_rval
)
2049 jsdValue::Invalidate()
2051 ASSERT_VALID_EPHEMERAL
;
2053 jsds_RemoveEphemeral (&gLiveValues
, &mLiveListEntry
);
2054 JSD_DropValue (mCx
, mValue
);
2059 jsdValue::InvalidateAll()
2062 jsds_InvalidateAllEphemerals (&gLiveValues
);
2066 jsdValue::GetJSDContext(JSDContext
**_rval
)
2068 ASSERT_VALID_EPHEMERAL
;
2074 jsdValue::GetJSDValue (JSDValue
**_rval
)
2076 ASSERT_VALID_EPHEMERAL
;
2082 jsdValue::GetIsNative (PRBool
*_rval
)
2084 ASSERT_VALID_EPHEMERAL
;
2085 *_rval
= JSD_IsValueNative (mCx
, mValue
);
2090 jsdValue::GetIsNumber (PRBool
*_rval
)
2092 ASSERT_VALID_EPHEMERAL
;
2093 *_rval
= JSD_IsValueNumber (mCx
, mValue
);
2098 jsdValue::GetIsPrimitive (PRBool
*_rval
)
2100 ASSERT_VALID_EPHEMERAL
;
2101 *_rval
= JSD_IsValuePrimitive (mCx
, mValue
);
2106 jsdValue::GetJsType (PRUint32
*_rval
)
2108 ASSERT_VALID_EPHEMERAL
;
2111 val
= JSD_GetValueWrappedJSVal (mCx
, mValue
);
2113 if (JSVAL_IS_NULL(val
))
2115 else if (JSVAL_IS_BOOLEAN(val
))
2116 *_rval
= TYPE_BOOLEAN
;
2117 else if (JSVAL_IS_DOUBLE(val
))
2118 *_rval
= TYPE_DOUBLE
;
2119 else if (JSVAL_IS_INT(val
))
2121 else if (JSVAL_IS_STRING(val
))
2122 *_rval
= TYPE_STRING
;
2123 else if (JSVAL_IS_VOID(val
))
2125 else if (JSD_IsValueFunction (mCx
, mValue
))
2126 *_rval
= TYPE_FUNCTION
;
2127 else if (JSVAL_IS_OBJECT(val
))
2128 *_rval
= TYPE_OBJECT
;
2130 NS_ASSERTION (0, "Value has no discernible type.");
2136 jsdValue::GetJsPrototype (jsdIValue
**_rval
)
2138 ASSERT_VALID_EPHEMERAL
;
2139 JSDValue
*jsdv
= JSD_GetValuePrototype (mCx
, mValue
);
2140 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2145 jsdValue::GetJsParent (jsdIValue
**_rval
)
2147 ASSERT_VALID_EPHEMERAL
;
2148 JSDValue
*jsdv
= JSD_GetValueParent (mCx
, mValue
);
2149 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2154 jsdValue::GetJsClassName(nsACString
&_rval
)
2156 ASSERT_VALID_EPHEMERAL
;
2157 _rval
.Assign(JSD_GetValueClassName(mCx
, mValue
));
2163 jsdValue::GetJsConstructor (jsdIValue
**_rval
)
2165 ASSERT_VALID_EPHEMERAL
;
2166 JSDValue
*jsdv
= JSD_GetValueConstructor (mCx
, mValue
);
2167 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2172 jsdValue::GetJsFunctionName(nsACString
&_rval
)
2174 ASSERT_VALID_EPHEMERAL
;
2175 _rval
.Assign(JSD_GetValueFunctionName(mCx
, mValue
));
2180 jsdValue::GetBooleanValue(PRBool
*_rval
)
2182 ASSERT_VALID_EPHEMERAL
;
2183 *_rval
= JSD_GetValueBoolean (mCx
, mValue
);
2188 jsdValue::GetDoubleValue(double *_rval
)
2190 ASSERT_VALID_EPHEMERAL
;
2191 *_rval
= JSD_GetValueDouble (mCx
, mValue
);
2196 jsdValue::GetIntValue(PRInt32
*_rval
)
2198 ASSERT_VALID_EPHEMERAL
;
2199 *_rval
= JSD_GetValueInt (mCx
, mValue
);
2204 jsdValue::GetObjectValue(jsdIObject
**_rval
)
2206 ASSERT_VALID_EPHEMERAL
;
2208 obj
= JSD_GetObjectForValue (mCx
, mValue
);
2209 *_rval
= jsdObject::FromPtr (mCx
, obj
);
2211 return NS_ERROR_FAILURE
;
2216 jsdValue::GetStringValue(nsACString
&_rval
)
2218 ASSERT_VALID_EPHEMERAL
;
2219 JSString
*jstr_val
= JSD_GetValueString(mCx
, mValue
);
2221 nsDependentString
chars(
2222 reinterpret_cast<PRUnichar
*>(JS_GetStringChars(jstr_val
)),
2223 JS_GetStringLength(jstr_val
));
2224 CopyUTF16toUTF8(chars
, _rval
);
2232 jsdValue::GetPropertyCount (PRInt32
*_rval
)
2234 ASSERT_VALID_EPHEMERAL
;
2235 if (JSD_IsValueObject(mCx
, mValue
))
2236 *_rval
= JSD_GetCountOfProperties (mCx
, mValue
);
2243 jsdValue::GetProperties (jsdIProperty
***propArray
, PRUint32
*length
)
2245 ASSERT_VALID_EPHEMERAL
;
2246 *propArray
= nsnull
;
2250 PRUint32 prop_count
= JSD_IsValueObject(mCx
, mValue
)
2251 ? JSD_GetCountOfProperties (mCx
, mValue
)
2253 NS_ENSURE_TRUE(prop_count
, NS_OK
);
2255 jsdIProperty
**pa_temp
=
2256 static_cast<jsdIProperty
**>
2257 (nsMemory::Alloc(sizeof (jsdIProperty
*) *
2259 NS_ENSURE_TRUE(pa_temp
, NS_ERROR_OUT_OF_MEMORY
);
2262 JSDProperty
*iter
= NULL
;
2264 while ((prop
= JSD_IterateProperties (mCx
, mValue
, &iter
))) {
2265 pa_temp
[i
] = jsdProperty::FromPtr (mCx
, prop
);
2269 NS_ASSERTION (prop_count
== i
, "property count mismatch");
2271 /* if caller doesn't care about length, don't bother telling them */
2272 *propArray
= pa_temp
;
2274 *length
= prop_count
;
2280 jsdValue::GetProperty (const nsACString
&name
, jsdIProperty
**_rval
)
2282 ASSERT_VALID_EPHEMERAL
;
2283 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2285 JSAutoRequest
ar(cx
);
2287 /* not rooting this */
2288 JSString
*jstr_name
= JS_NewStringCopyZ(cx
, PromiseFlatCString(name
).get());
2290 return NS_ERROR_OUT_OF_MEMORY
;
2292 JSDProperty
*prop
= JSD_GetValueProperty (mCx
, mValue
, jstr_name
);
2294 *_rval
= jsdProperty::FromPtr (mCx
, prop
);
2301 ASSERT_VALID_EPHEMERAL
;
2302 JSD_RefreshValue (mCx
, mValue
);
2307 jsdValue::GetWrappedValue()
2309 ASSERT_VALID_EPHEMERAL
;
2311 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID(), &rv
);
2315 nsAXPCNativeCallContext
*cc
= nsnull
;
2316 rv
= xpc
->GetCurrentNativeCallContext(&cc
);
2321 rv
= cc
->GetRetValPtr(&result
);
2328 rv
= cc
->GetJSContext(&cx
);
2331 *result
= JSD_GetValueWrappedJSVal (mCx
, mValue
);
2332 if (!JS_WrapValue(cx
, result
))
2333 return NS_ERROR_FAILURE
;
2334 cc
->SetReturnValueWasSet(PR_TRUE
);
2341 jsdValue::GetScript(jsdIScript
**_rval
)
2343 ASSERT_VALID_EPHEMERAL
;
2344 JSDScript
*script
= JSD_GetScriptForValue(mCx
, mValue
);
2345 *_rval
= jsdScript::FromPtr(mCx
, script
);
2349 /******************************************************************************
2350 * debugger service implementation
2351 ******************************************************************************/
2352 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdService
, jsdIDebuggerService
)
2355 jsdService::GetJSDContext(JSDContext
**_rval
)
2362 jsdService::GetFlags (PRUint32
*_rval
)
2364 ASSERT_VALID_CONTEXT
;
2365 *_rval
= JSD_GetContextFlags (mCx
);
2370 jsdService::SetFlags (PRUint32 flags
)
2372 ASSERT_VALID_CONTEXT
;
2373 JSD_SetContextFlags (mCx
, flags
);
2378 jsdService::GetImplementationString(nsACString
&aImplementationString
)
2380 aImplementationString
.AssignLiteral(implementationString
);
2385 jsdService::GetImplementationMajor(PRUint32
*_rval
)
2387 *_rval
= JSDS_MAJOR_VERSION
;
2392 jsdService::GetImplementationMinor(PRUint32
*_rval
)
2394 *_rval
= JSDS_MINOR_VERSION
;
2399 jsdService::GetIsOn (PRBool
*_rval
)
2406 jsdService::On (void)
2408 return NS_ERROR_NOT_IMPLEMENTED
;
2412 jsdService::AsyncOn (jsdIActivationCallback
*activationCallback
)
2416 /* get JS things from the CallContext */
2417 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID(), &rv
);
2418 if (NS_FAILED(rv
)) return rv
;
2420 nsAXPCNativeCallContext
*cc
= nsnull
;
2421 rv
= xpc
->GetCurrentNativeCallContext(&cc
);
2422 if (NS_FAILED(rv
)) return rv
;
2425 rv
= cc
->GetJSContext (&cx
);
2426 if (NS_FAILED(rv
)) return rv
;
2428 mActivationCallback
= activationCallback
;
2430 return xpc
->SetDebugModeWhenPossible(PR_TRUE
);
2434 jsdService::RecompileForDebugMode (JSRuntime
*rt
, JSBool mode
) {
2435 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
2438 JSContext
*iter
= NULL
;
2440 jsword currentThreadId
= reinterpret_cast<jsword
>(js_CurrentThreadId());
2442 while ((cx
= JS_ContextIterator (rt
, &iter
))) {
2443 if (JS_GetContextThread(cx
) == currentThreadId
) {
2444 JS_SetDebugMode(cx
, mode
);
2452 jsdService::ActivateDebugger (JSRuntime
*rt
)
2455 return (rt
== mRuntime
) ? NS_OK
: NS_ERROR_ALREADY_INITIALIZED
;
2458 RecompileForDebugMode(rt
, JS_TRUE
);
2460 if (gLastGCProc
== jsds_GCCallbackProc
)
2461 /* condition indicates that the callback proc has not been set yet */
2462 gLastGCProc
= JS_SetGCCallbackRT (rt
, jsds_GCCallbackProc
);
2464 mCx
= JSD_DebuggerOnForUser (rt
, NULL
, NULL
);
2466 return NS_ERROR_FAILURE
;
2468 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2469 JSObject
*glob
= JS_GetGlobalObject (cx
);
2471 /* init xpconnect on the debugger's context in case xpconnect tries to
2472 * use it for stuff. */
2474 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID(), &rv
);
2478 xpc
->InitClasses (cx
, glob
);
2480 /* If any of these mFooHook objects are installed, do the required JSD
2481 * hookup now. See also, jsdService::SetFooHook().
2484 JSD_SetErrorReporter (mCx
, jsds_ErrorHookProc
, NULL
);
2486 JSD_SetThrowHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2487 /* can't ignore script callbacks, as we need to |Release| the wrapper
2488 * stored in private data when a script is deleted. */
2490 JSD_SetInterruptHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2492 JSD_SetDebuggerHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2494 JSD_SetDebugBreakHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2496 JSD_SetTopLevelHook (mCx
, jsds_CallHookProc
, NULL
);
2498 JSD_ClearTopLevelHook (mCx
);
2500 JSD_SetFunctionHook (mCx
, jsds_CallHookProc
, NULL
);
2502 JSD_ClearFunctionHook (mCx
);
2506 printf ("+++ JavaScript debugging hooks installed.\n");
2509 if (mActivationCallback
)
2510 return mActivationCallback
->OnDebuggerActivated();
2516 jsdService::Off (void)
2521 if (!mCx
|| !mRuntime
)
2522 return NS_ERROR_NOT_INITIALIZED
;
2525 if (gGCStatus
!= JSGC_END
)
2526 return NS_ERROR_NOT_AVAILABLE
;
2528 JSContext
*cx
= JSD_GetDefaultJSContext(mCx
);
2529 jsds_NotifyPendingDeadScripts(cx
);
2533 if (gLastGCProc != jsds_GCCallbackProc)
2534 JS_SetGCCallbackRT (mRuntime, gLastGCProc);
2537 jsdContext::InvalidateAll();
2538 jsdScript::InvalidateAll();
2539 jsdValue::InvalidateAll();
2540 jsdProperty::InvalidateAll();
2541 ClearAllBreakpoints();
2543 JSD_SetErrorReporter (mCx
, NULL
, NULL
);
2544 JSD_SetScriptHook (mCx
, NULL
, NULL
);
2545 JSD_ClearThrowHook (mCx
);
2546 JSD_ClearInterruptHook (mCx
);
2547 JSD_ClearDebuggerHook (mCx
);
2548 JSD_ClearDebugBreakHook (mCx
);
2549 JSD_ClearTopLevelHook (mCx
);
2550 JSD_ClearFunctionHook (mCx
);
2552 JSD_DebuggerOff (mCx
);
2559 printf ("+++ JavaScript debugging hooks removed.\n");
2563 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID(), &rv
);
2567 xpc
->SetDebugModeWhenPossible(PR_FALSE
);
2573 jsdService::GetPauseDepth(PRUint32
*_rval
)
2575 NS_ENSURE_ARG_POINTER(_rval
);
2576 *_rval
= mPauseLevel
;
2581 jsdService::Pause(PRUint32
*_rval
)
2584 return NS_ERROR_NOT_INITIALIZED
;
2586 if (++mPauseLevel
== 1) {
2587 JSD_SetErrorReporter (mCx
, NULL
, NULL
);
2588 JSD_ClearThrowHook (mCx
);
2589 JSD_ClearInterruptHook (mCx
);
2590 JSD_ClearDebuggerHook (mCx
);
2591 JSD_ClearDebugBreakHook (mCx
);
2592 JSD_ClearTopLevelHook (mCx
);
2593 JSD_ClearFunctionHook (mCx
);
2594 JSD_DebuggerPause (mCx
);
2598 *_rval
= mPauseLevel
;
2604 jsdService::UnPause(PRUint32
*_rval
)
2607 return NS_ERROR_NOT_INITIALIZED
;
2609 if (mPauseLevel
== 0)
2610 return NS_ERROR_NOT_AVAILABLE
;
2612 /* check mOn before we muck with this stuff, it's possible the debugger
2613 * was turned off while we were paused.
2615 if (--mPauseLevel
== 0 && mOn
) {
2616 JSD_DebuggerUnpause (mCx
);
2618 JSD_SetErrorReporter (mCx
, jsds_ErrorHookProc
, NULL
);
2620 JSD_SetThrowHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2622 JSD_SetInterruptHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2624 JSD_SetDebuggerHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2626 JSD_SetDebugBreakHook (mCx
, jsds_ExecutionHookProc
, NULL
);
2628 JSD_SetTopLevelHook (mCx
, jsds_CallHookProc
, NULL
);
2630 JSD_ClearTopLevelHook (mCx
);
2632 JSD_SetFunctionHook (mCx
, jsds_CallHookProc
, NULL
);
2634 JSD_ClearFunctionHook (mCx
);
2638 *_rval
= mPauseLevel
;
2644 jsdService::EnumerateContexts (jsdIContextEnumerator
*enumerator
)
2646 ASSERT_VALID_CONTEXT
;
2651 JSContext
*iter
= NULL
;
2654 while ((cx
= JS_ContextIterator (mRuntime
, &iter
)))
2656 nsCOMPtr
<jsdIContext
> jsdicx
=
2657 getter_AddRefs(jsdContext::FromPtr(mCx
, cx
));
2660 if (NS_FAILED(enumerator
->EnumerateContext(jsdicx
)))
2669 jsdService::EnumerateScripts (jsdIScriptEnumerator
*enumerator
)
2671 ASSERT_VALID_CONTEXT
;
2674 JSDScript
*iter
= NULL
;
2675 nsresult rv
= NS_OK
;
2677 JSD_LockScriptSubsystem(mCx
);
2678 while((script
= JSD_IterateScripts(mCx
, &iter
))) {
2679 nsCOMPtr
<jsdIScript
> jsdis
=
2680 getter_AddRefs(jsdScript::FromPtr(mCx
, script
));
2681 rv
= enumerator
->EnumerateScript (jsdis
);
2685 JSD_UnlockScriptSubsystem(mCx
);
2691 jsdService::GC (void)
2693 ASSERT_VALID_CONTEXT
;
2694 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2700 jsdService::DumpHeap(const nsACString
&fileName
)
2702 ASSERT_VALID_CONTEXT
;
2704 return NS_ERROR_NOT_IMPLEMENTED
;
2706 nsresult rv
= NS_OK
;
2707 FILE *file
= !fileName
.IsEmpty() ? fopen(PromiseFlatCString(fileName
).get(), "w") : stdout
;
2709 rv
= NS_ERROR_FAILURE
;
2711 JSContext
*cx
= JSD_GetDefaultJSContext (mCx
);
2712 if (!JS_DumpHeap(cx
, file
, NULL
, 0, NULL
, (size_t)-1, NULL
))
2713 rv
= NS_ERROR_FAILURE
;
2722 jsdService::ClearProfileData ()
2724 ASSERT_VALID_CONTEXT
;
2725 JSD_ClearAllProfileData (mCx
);
2730 jsdService::InsertFilter (jsdIFilter
*filter
, jsdIFilter
*after
)
2732 NS_ENSURE_ARG_POINTER (filter
);
2733 if (jsds_FindFilter (filter
))
2734 return NS_ERROR_INVALID_ARG
;
2736 FilterRecord
*rec
= PR_NEWZAP (FilterRecord
);
2738 return NS_ERROR_OUT_OF_MEMORY
;
2740 if (!jsds_SyncFilter (rec
, filter
)) {
2742 return NS_ERROR_FAILURE
;
2747 /* insert at head of list */
2748 PR_INSERT_LINK(&rec
->links
, &gFilters
->links
);
2751 /* insert somewhere in the list */
2752 FilterRecord
*afterRecord
= jsds_FindFilter (after
);
2754 jsds_FreeFilter(rec
);
2755 return NS_ERROR_INVALID_ARG
;
2757 PR_INSERT_AFTER(&rec
->links
, &afterRecord
->links
);
2761 /* user asked to insert into the middle of an empty list, bail. */
2762 jsds_FreeFilter(rec
);
2763 return NS_ERROR_NOT_INITIALIZED
;
2765 PR_INIT_CLIST(&rec
->links
);
2773 jsdService::AppendFilter (jsdIFilter
*filter
)
2775 NS_ENSURE_ARG_POINTER (filter
);
2776 if (jsds_FindFilter (filter
))
2777 return NS_ERROR_INVALID_ARG
;
2778 FilterRecord
*rec
= PR_NEWZAP (FilterRecord
);
2780 if (!jsds_SyncFilter (rec
, filter
)) {
2782 return NS_ERROR_FAILURE
;
2786 PR_INSERT_BEFORE(&rec
->links
, &gFilters
->links
);
2788 PR_INIT_CLIST(&rec
->links
);
2796 jsdService::RemoveFilter (jsdIFilter
*filter
)
2798 NS_ENSURE_ARG_POINTER(filter
);
2799 FilterRecord
*rec
= jsds_FindFilter (filter
);
2801 return NS_ERROR_INVALID_ARG
;
2803 if (gFilters
== rec
) {
2804 gFilters
= reinterpret_cast<FilterRecord
*>
2805 (PR_NEXT_LINK(&rec
->links
));
2806 /* If we're the only filter left, null out the list head. */
2807 if (gFilters
== rec
)
2812 PR_REMOVE_LINK(&rec
->links
);
2813 jsds_FreeFilter (rec
);
2819 jsdService::SwapFilters (jsdIFilter
*filter_a
, jsdIFilter
*filter_b
)
2821 NS_ENSURE_ARG_POINTER(filter_a
);
2822 NS_ENSURE_ARG_POINTER(filter_b
);
2824 FilterRecord
*rec_a
= jsds_FindFilter (filter_a
);
2826 return NS_ERROR_INVALID_ARG
;
2828 if (filter_a
== filter_b
) {
2829 /* just a refresh */
2830 if (!jsds_SyncFilter (rec_a
, filter_a
))
2831 return NS_ERROR_FAILURE
;
2835 FilterRecord
*rec_b
= jsds_FindFilter (filter_b
);
2837 /* filter_b is not in the list, replace filter_a with filter_b. */
2838 if (!jsds_SyncFilter (rec_a
, filter_b
))
2839 return NS_ERROR_FAILURE
;
2841 /* both filters are in the list, swap. */
2842 if (!jsds_SyncFilter (rec_a
, filter_b
))
2843 return NS_ERROR_FAILURE
;
2844 if (!jsds_SyncFilter (rec_b
, filter_a
))
2845 return NS_ERROR_FAILURE
;
2852 jsdService::EnumerateFilters (jsdIFilterEnumerator
*enumerator
)
2857 FilterRecord
*current
= gFilters
;
2859 jsds_SyncFilter (current
, current
->filterObject
);
2860 /* SyncFilter failure would be bad, but what would we do about it? */
2862 nsresult rv
= enumerator
->EnumerateFilter (current
->filterObject
);
2866 current
= reinterpret_cast<FilterRecord
*>
2867 (PR_NEXT_LINK (¤t
->links
));
2868 } while (current
!= gFilters
);
2874 jsdService::RefreshFilters ()
2876 return EnumerateFilters(nsnull
);
2880 jsdService::ClearFilters ()
2885 FilterRecord
*current
= reinterpret_cast<FilterRecord
*>
2886 (PR_NEXT_LINK (&gFilters
->links
));
2888 FilterRecord
*next
= reinterpret_cast<FilterRecord
*>
2889 (PR_NEXT_LINK (¤t
->links
));
2890 PR_REMOVE_AND_INIT_LINK(¤t
->links
);
2891 jsds_FreeFilter(current
);
2893 } while (current
!= gFilters
);
2895 jsds_FreeFilter(current
);
2902 jsdService::ClearAllBreakpoints (void)
2904 ASSERT_VALID_CONTEXT
;
2906 JSD_LockScriptSubsystem(mCx
);
2907 JSD_ClearAllExecutionHooks (mCx
);
2908 JSD_UnlockScriptSubsystem(mCx
);
2913 jsdService::WrapValue(jsdIValue
**_rval
)
2915 ASSERT_VALID_CONTEXT
;
2918 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService (nsIXPConnect::GetCID(), &rv
);
2922 nsAXPCNativeCallContext
*cc
= nsnull
;
2923 rv
= xpc
->GetCurrentNativeCallContext (&cc
);
2928 rv
= cc
->GetArgc (&argc
);
2932 return NS_ERROR_INVALID_ARG
;
2935 rv
= cc
->GetArgvPtr (&argv
);
2939 return WrapJSValue(argv
[0], _rval
);
2943 jsdService::WrapJSValue(const jsval
&value
, jsdIValue
** _rval
)
2945 JSDValue
*jsdv
= JSD_NewValue(mCx
, value
);
2947 return NS_ERROR_FAILURE
;
2949 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
2955 jsdService::EnterNestedEventLoop (jsdINestCallback
*callback
, PRUint32
*_rval
)
2957 // Nesting event queues is a thing of the past. Now, we just spin the
2958 // current event loop.
2961 nsCOMPtr
<nsIJSContextStack
>
2962 stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv
));
2965 PRUint32 nestLevel
= ++mNestedLoopLevel
;
2967 nsCOMPtr
<nsIThread
> thread
= do_GetCurrentThread();
2969 if (NS_SUCCEEDED(stack
->Push(nsnull
))) {
2972 rv
= callback
->OnNest();
2976 while (NS_SUCCEEDED(rv
) && mNestedLoopLevel
>= nestLevel
) {
2977 if (!NS_ProcessNextEvent(thread
))
2978 rv
= NS_ERROR_UNEXPECTED
;
2983 NS_ASSERTION(cx
== nsnull
, "JSContextStack mismatch");
2986 rv
= NS_ERROR_FAILURE
;
2988 NS_ASSERTION (mNestedLoopLevel
<= nestLevel
,
2989 "nested event didn't unwind properly");
2990 if (mNestedLoopLevel
== nestLevel
)
2993 *_rval
= mNestedLoopLevel
;
2998 jsdService::ExitNestedEventLoop (PRUint32
*_rval
)
3000 if (mNestedLoopLevel
> 0)
3003 return NS_ERROR_FAILURE
;
3005 *_rval
= mNestedLoopLevel
;
3009 /* hook attribute get/set functions */
3012 jsdService::SetErrorHook (jsdIErrorHook
*aHook
)
3016 /* if the debugger isn't initialized, that's all we can do for now. The
3017 * ActivateDebugger() method will do the rest when the coast is clear.
3019 if (!mCx
|| mPauseLevel
)
3023 JSD_SetErrorReporter (mCx
, jsds_ErrorHookProc
, NULL
);
3025 JSD_SetErrorReporter (mCx
, NULL
, NULL
);
3031 jsdService::GetErrorHook (jsdIErrorHook
**aHook
)
3033 *aHook
= mErrorHook
;
3034 NS_IF_ADDREF(*aHook
);
3040 jsdService::SetBreakpointHook (jsdIExecutionHook
*aHook
)
3042 mBreakpointHook
= aHook
;
3047 jsdService::GetBreakpointHook (jsdIExecutionHook
**aHook
)
3049 *aHook
= mBreakpointHook
;
3050 NS_IF_ADDREF(*aHook
);
3056 jsdService::SetDebugHook (jsdIExecutionHook
*aHook
)
3060 /* if the debugger isn't initialized, that's all we can do for now. The
3061 * ActivateDebugger() method will do the rest when the coast is clear.
3063 if (!mCx
|| mPauseLevel
)
3067 JSD_SetDebugBreakHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3069 JSD_ClearDebugBreakHook (mCx
);
3075 jsdService::GetDebugHook (jsdIExecutionHook
**aHook
)
3077 *aHook
= mDebugHook
;
3078 NS_IF_ADDREF(*aHook
);
3084 jsdService::SetDebuggerHook (jsdIExecutionHook
*aHook
)
3086 mDebuggerHook
= aHook
;
3088 /* if the debugger isn't initialized, that's all we can do for now. The
3089 * ActivateDebugger() method will do the rest when the coast is clear.
3091 if (!mCx
|| mPauseLevel
)
3095 JSD_SetDebuggerHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3097 JSD_ClearDebuggerHook (mCx
);
3103 jsdService::GetDebuggerHook (jsdIExecutionHook
**aHook
)
3105 *aHook
= mDebuggerHook
;
3106 NS_IF_ADDREF(*aHook
);
3112 jsdService::SetInterruptHook (jsdIExecutionHook
*aHook
)
3114 mInterruptHook
= aHook
;
3116 /* if the debugger isn't initialized, that's all we can do for now. The
3117 * ActivateDebugger() method will do the rest when the coast is clear.
3119 if (!mCx
|| mPauseLevel
)
3123 JSD_SetInterruptHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3125 JSD_ClearInterruptHook (mCx
);
3131 jsdService::GetInterruptHook (jsdIExecutionHook
**aHook
)
3133 *aHook
= mInterruptHook
;
3134 NS_IF_ADDREF(*aHook
);
3140 jsdService::SetScriptHook (jsdIScriptHook
*aHook
)
3142 mScriptHook
= aHook
;
3144 /* if the debugger isn't initialized, that's all we can do for now. The
3145 * ActivateDebugger() method will do the rest when the coast is clear.
3147 if (!mCx
|| mPauseLevel
)
3151 JSD_SetScriptHook (mCx
, jsds_ScriptHookProc
, NULL
);
3152 /* we can't unset it if !aHook, because we still need to see script
3153 * deletes in order to Release the jsdIScripts held in JSDScript
3159 jsdService::GetScriptHook (jsdIScriptHook
**aHook
)
3161 *aHook
= mScriptHook
;
3162 NS_IF_ADDREF(*aHook
);
3168 jsdService::SetThrowHook (jsdIExecutionHook
*aHook
)
3172 /* if the debugger isn't initialized, that's all we can do for now. The
3173 * ActivateDebugger() method will do the rest when the coast is clear.
3175 if (!mCx
|| mPauseLevel
)
3179 JSD_SetThrowHook (mCx
, jsds_ExecutionHookProc
, NULL
);
3181 JSD_ClearThrowHook (mCx
);
3187 jsdService::GetThrowHook (jsdIExecutionHook
**aHook
)
3189 *aHook
= mThrowHook
;
3190 NS_IF_ADDREF(*aHook
);
3196 jsdService::SetTopLevelHook (jsdICallHook
*aHook
)
3198 mTopLevelHook
= aHook
;
3200 /* if the debugger isn't initialized, that's all we can do for now. The
3201 * ActivateDebugger() method will do the rest when the coast is clear.
3203 if (!mCx
|| mPauseLevel
)
3207 JSD_SetTopLevelHook (mCx
, jsds_CallHookProc
, NULL
);
3209 JSD_ClearTopLevelHook (mCx
);
3215 jsdService::GetTopLevelHook (jsdICallHook
**aHook
)
3217 *aHook
= mTopLevelHook
;
3218 NS_IF_ADDREF(*aHook
);
3224 jsdService::SetFunctionHook (jsdICallHook
*aHook
)
3226 mFunctionHook
= aHook
;
3228 /* if the debugger isn't initialized, that's all we can do for now. The
3229 * ActivateDebugger() method will do the rest when the coast is clear.
3231 if (!mCx
|| mPauseLevel
)
3235 JSD_SetFunctionHook (mCx
, jsds_CallHookProc
, NULL
);
3237 JSD_ClearFunctionHook (mCx
);
3243 jsdService::GetFunctionHook (jsdICallHook
**aHook
)
3245 *aHook
= mFunctionHook
;
3246 NS_IF_ADDREF(*aHook
);
3252 jsdService::~jsdService()
3255 mErrorHook
= nsnull
;
3256 mBreakpointHook
= nsnull
;
3257 mDebugHook
= nsnull
;
3258 mDebuggerHook
= nsnull
;
3259 mInterruptHook
= nsnull
;
3260 mScriptHook
= nsnull
;
3261 mThrowHook
= nsnull
;
3262 mTopLevelHook
= nsnull
;
3263 mFunctionHook
= nsnull
;
3264 gGCStatus
= JSGC_END
;
3270 jsdService::GetService ()
3273 gJsds
= new jsdService();
3275 NS_IF_ADDREF(gJsds
);
3279 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService
, jsdService::GetService
)
3281 /* app-start observer. turns on the debugger at app-start. this is inserted
3282 * and/or removed from the app-start category by the jsdService::initAtStartup
3285 class jsdASObserver
: public nsIObserver
3294 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver
, nsIObserver
)
3297 jsdASObserver::Observe (nsISupports
*aSubject
, const char *aTopic
,
3298 const PRUnichar
*aData
)
3302 // Hmm. Why is the app-startup observer called multiple times?
3303 //NS_ASSERTION(!gJsds, "app startup observer called twice");
3304 nsCOMPtr
<jsdIDebuggerService
> jsds
= do_GetService(jsdServiceCtrID
, &rv
);
3309 rv
= jsds
->GetIsOn(&on
);
3310 if (NS_FAILED(rv
) || on
)
3313 nsCOMPtr
<nsIJSRuntimeService
> rts
= do_GetService(NS_JSRT_CTRID
, &rv
);
3318 rts
->GetRuntime (&rt
);
3322 rv
= jsds
->ActivateDebugger(rt
);
3329 NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver
)
3330 NS_DEFINE_NAMED_CID(JSDSERVICE_CID
);
3331 NS_DEFINE_NAMED_CID(JSDASO_CID
);
3333 static const mozilla::Module::CIDEntry kJSDCIDs
[] = {
3334 { &kJSDSERVICE_CID
, false, NULL
, jsdServiceConstructor
},
3335 { &kJSDASO_CID
, false, NULL
, jsdASObserverConstructor
},
3339 static const mozilla::Module::ContractIDEntry kJSDContracts
[] = {
3340 { jsdServiceCtrID
, &kJSDSERVICE_CID
},
3341 { jsdARObserverCtrID
, &kJSDASO_CID
},
3345 static const mozilla::Module kJSDModule
= {
3346 mozilla::Module::kVersion
,
3351 NSMODULE_DEFN(JavaScript_Debugger
) = &kJSDModule
;
3353 /********************************************************************************
3354 ********************************************************************************
3360 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState
, jsdIThreadState
);
3363 jsdThreadState::GetJSDContext(JSDContext
**_rval
)
3370 jsdThreadState::GetJSDThreadState(JSDThreadState
**_rval
)
3372 *_rval
= mThreadState
;
3377 jsdThreadState::GetFrameCount (PRUint32
*_rval
)
3379 *_rval
= JSD_GetCountOfStackFrames (mCx
, mThreadState
);
3384 jsdThreadState::GetTopFrame (jsdIStackFrame
**_rval
)
3386 JSDStackFrameInfo
*sfi
= JSD_GetStackFrame (mCx
, mThreadState
);
3388 *_rval
= jsdStackFrame::FromPtr (mCx
, mThreadState
, sfi
);
3393 jsdThreadState::GetPendingException(jsdIValue
**_rval
)
3395 JSDValue
*jsdv
= JSD_GetException (mCx
, mThreadState
);
3397 *_rval
= jsdValue::FromPtr (mCx
, jsdv
);
3402 jsdThreadState::SetPendingException(jsdIValue
*aException
)
3406 nsresult rv
= aException
->GetJSDValue (&jsdv
);
3408 return NS_ERROR_FAILURE
;
3410 if (!JSD_SetException (mCx
, mThreadState
, jsdv
))
3411 return NS_ERROR_FAILURE
;