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();
212 jsds_InsertEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
215 /* if the list exists, add to it */
216 PR_APPEND_LINK(&item->links, &(*listHead)->links);
218 /* otherwise create the list */
219 PR_INIT_CLIST(&item->links);
225 jsds_RemoveEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
227 LiveEphemeral *next = reinterpret_cast<LiveEphemeral *>
228 (PR_NEXT_LINK(&item->links));
232 /* if the current item is also the next item, we're the only element,
233 * null out the list head */
234 NS_ASSERTION (*listHead == item,
235 "How could we not be the head of a one item list?");
238 else if (item == *listHead)
240 /* otherwise, if we're currently the list head, change it */
244 PR_REMOVE_AND_INIT_LINK(&item->links);
247 /*******************************************************************************
248 * utility functions for filters
249 *******************************************************************************/
251 jsds_FreeFilter (FilterRecord *rec)
253 NS_IF_RELEASE (rec->filterObject);
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);
287 nsCAutoString urlPattern;
288 rv = filter->GetUrlPattern (urlPattern);
292 PRUint32 len = urlPattern.Length();
294 if (urlPattern[0] == '*') {
295 /* pattern starts with a *, shift all chars once to the left,
296 * including the trailing null. */
297 urlPattern = Substring(urlPattern, 1, len);
299 if (urlPattern[len - 2] == '*') {
300 /* pattern is in the format "*foo*", overwrite the final * with
302 urlPattern.Truncate(len - 2);
303 rec->patternType = ptContains;
305 /* pattern is in the format "*foo", just make a note of the
307 rec->patternType = ptEndsWith;
309 } else if (urlPattern[len - 1] == '*') {
310 /* pattern is in the format "foo*", overwrite the final * with a
312 urlPattern.Truncate(len - 1);
313 rec->patternType = ptStartsWith;
315 /* pattern is in the format "foo". */
316 rec->patternType = ptEquals;
319 rec->patternType = ptIgnore;
322 /* we got everything we need without failing, now copy it into rec. */
324 if (rec->filterObject != filter) {
325 NS_IF_RELEASE(rec->filterObject);
327 rec->filterObject = filter;
330 rec->glob = glob_proper;
332 rec->startLine = startLine;
333 rec->endLine = endLine;
335 rec->urlPattern = urlPattern;
342 jsds_FindFilter (jsdIFilter *filter)
347 FilterRecord *current = gFilters;
350 if (current->filterObject == filter)
352 current = reinterpret_cast<FilterRecord *>
353 (PR_NEXT_LINK(¤t->links));
354 } while (current != gFilters);
359 /* returns true if the hook should be executed. */
361 jsds_FilterHook (JSDContext *jsdc, JSDThreadState *state)
363 JSContext *cx = JSD_GetJSContext (jsdc, state);
364 void *glob = static_cast<void *>(JS_GetGlobalObject (cx));
367 NS_WARNING("No global in threadstate");
371 JSDStackFrameInfo *frame = JSD_GetStackFrame (jsdc, state);
374 NS_WARNING("No frame in threadstate");
378 JSDScript *script = JSD_GetScriptForStackFrame (jsdc, state, frame);
382 jsuword pc = JSD_GetPCForStackFrame (jsdc, state, frame);
384 nsDependentCString url(JSD_GetScriptFilename (jsdc, script));
386 NS_WARNING ("Script with no filename");
393 PRUint32 currentLine = JSD_GetClosestLine (jsdc, script, pc);
395 FilterRecord *currentFilter = gFilters;
398 nsresult rv = currentFilter->filterObject->GetFlags(&flags);
399 NS_ASSERTION(NS_SUCCEEDED(rv), "Error getting flags for filter");
400 if (flags & jsdIFilter::FLAG_ENABLED) {
401 /* if there is no glob, or the globs match */
402 if ((!currentFilter->glob || currentFilter->glob == glob) &&
403 /* and there is no start line, or the start line is before
404 * or equal to the current */
405 (!currentFilter->startLine ||
406 currentFilter->startLine <= currentLine) &&
407 /* and there is no end line, or the end line is after
408 * or equal to the current */
409 (!currentFilter->endLine ||
410 currentFilter->endLine >= currentLine)) {
411 /* then we're going to have to compare the url. */
412 if (currentFilter->patternType == ptIgnore)
413 return !!(flags & jsdIFilter::FLAG_PASS);
417 nsCString urlPattern = currentFilter->urlPattern;
418 PRUint32 patternLength = urlPattern.Length();
419 if (len >= patternLength) {
420 switch (currentFilter->patternType) {
422 if (urlPattern.Equals(url))
423 return !!(flags & jsdIFilter::FLAG_PASS);
426 if (urlPattern.Equals(Substring(url, 0, patternLength)))
427 return !!(flags & jsdIFilter::FLAG_PASS);
430 if (urlPattern.Equals(Substring(url, len - patternLength)))
431 return !!(flags & jsdIFilter::FLAG_PASS);
435 nsACString::const_iterator start, end;
436 url.BeginReading(start);
438 if (FindInReadable(currentFilter->urlPattern, start, end))
439 return !!(flags & jsdIFilter::FLAG_PASS);
443 NS_ERROR("Invalid pattern type");
448 currentFilter = reinterpret_cast<FilterRecord *>
449 (PR_NEXT_LINK(¤tFilter->links));
450 } while (currentFilter != gFilters);
456 /*******************************************************************************
458 *******************************************************************************/
461 jsds_NotifyPendingDeadScripts (JSContext *cx)
463 #ifdef CAUTIOUS_SCRIPTHOOK
464 JSRuntime *rt = JS_GetRuntime(cx);
466 jsdService *jsds = gJsds;
468 nsCOMPtr<jsdIScriptHook> hook;
471 jsds->GetScriptHook (getter_AddRefs(hook));
475 DeadScript *deadScripts = gDeadScripts;
476 gDeadScripts = nsnull;
477 while (deadScripts) {
478 DeadScript *ds = deadScripts;
479 /* get next deleted script */
480 deadScripts = reinterpret_cast<DeadScript *>
481 (PR_NEXT_LINK(&ds->links));
482 if (deadScripts == ds)
483 deadScripts = nsnull;
487 /* tell the user this script has been destroyed */
488 #ifdef CAUTIOUS_SCRIPTHOOK
491 hook->OnScriptDestroyed (ds->script);
492 #ifdef CAUTIOUS_SCRIPTHOOK
497 /* take it out of the circular list */
498 PR_REMOVE_LINK(&ds->links);
500 /* addref came from the FromPtr call in jsds_ScriptHookProc */
501 NS_RELEASE(ds->script);
502 /* free the struct! */
507 jsds->UnPause(nsnull);
513 jsds_GCCallbackProc (JSContext *cx, JSGCStatus status)
516 printf ("new gc status is %i\n", status);
518 if (status == JSGC_END) {
519 /* just to guard against reentering. */
520 gGCStatus = JSGC_BEGIN;
522 jsds_NotifyPendingDeadScripts (cx);
526 if (gLastGCProc && !gLastGCProc (cx, status)) {
528 * If gLastGCProc returns false, then the GC will abort without making
529 * another callback with status=JSGC_END, so set the status to JSGC_END
532 gGCStatus = JSGC_END;
540 jsds_ErrorHookProc (JSDContext *jsdc, JSContext *cx, const char *message,
541 JSErrorReport *report, void *callerdata)
543 static PRBool running = PR_FALSE;
545 nsCOMPtr<jsdIErrorHook> hook;
546 gJsds->GetErrorHook(getter_AddRefs(hook));
548 return JSD_ERROR_REPORTER_PASS_ALONG;
551 return JSD_ERROR_REPORTER_PASS_ALONG;
555 nsCOMPtr<jsdIValue> val;
556 if (JS_IsExceptionPending(cx)) {
558 JS_GetPendingException(cx, &jv);
559 JSDValue *jsdv = JSD_NewValue (jsdc, jv);
560 val = getter_AddRefs(jsdValue::FromPtr(jsdc, jsdv));
563 nsCAutoString fileName;
570 fileName.Assign(report->filename);
571 line = report->lineno;
572 pos = report->tokenptr - report->linebuf;
573 flags = report->flags;
574 errnum = report->errorNumber;
584 gJsds->Pause(nsnull);
585 hook->OnError (nsDependentCString(message), fileName, line, pos, flags, errnum, val, &rval);
586 gJsds->UnPause(nsnull);
590 return JSD_ERROR_REPORTER_DEBUG;
592 return JSD_ERROR_REPORTER_PASS_ALONG;
596 jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
597 uintN type, void* callerdata)
599 nsCOMPtr<jsdICallHook> hook;
603 case JSD_HOOK_TOPLEVEL_START:
604 case JSD_HOOK_TOPLEVEL_END:
605 gJsds->GetTopLevelHook(getter_AddRefs(hook));
608 case JSD_HOOK_FUNCTION_CALL:
609 case JSD_HOOK_FUNCTION_RETURN:
610 gJsds->GetFunctionHook(getter_AddRefs(hook));
614 NS_ASSERTION (0, "Unknown hook type.");
620 if (!jsds_FilterHook (jsdc, jsdthreadstate))
623 JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
624 nsCOMPtr<jsdIStackFrame> frame =
625 getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
627 gJsds->Pause(nsnull);
628 hook->OnCall(frame, type);
629 gJsds->UnPause(nsnull);
630 jsdStackFrame::InvalidateAll();
636 jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
637 uintN type, void* callerdata, jsval* rval)
639 nsCOMPtr<jsdIExecutionHook> hook(0);
640 PRUint32 hook_rv = JSD_HOOK_RETURN_CONTINUE;
641 nsCOMPtr<jsdIValue> js_rv;
645 case JSD_HOOK_INTERRUPTED:
646 gJsds->GetInterruptHook(getter_AddRefs(hook));
648 case JSD_HOOK_DEBUG_REQUESTED:
649 gJsds->GetDebugHook(getter_AddRefs(hook));
651 case JSD_HOOK_DEBUGGER_KEYWORD:
652 gJsds->GetDebuggerHook(getter_AddRefs(hook));
654 case JSD_HOOK_BREAKPOINT:
656 /* we can't pause breakpoints the way we pause the other
657 * execution hooks (at least, not easily.) Instead we bail
658 * here if the service is paused. */
660 gJsds->GetPauseDepth(&level);
662 gJsds->GetBreakpointHook(getter_AddRefs(hook));
667 hook_rv = JSD_HOOK_RETURN_CONTINUE_THROW;
668 gJsds->GetThrowHook(getter_AddRefs(hook));
670 JSDValue *jsdv = JSD_GetException (jsdc, jsdthreadstate);
671 js_rv = getter_AddRefs(jsdValue::FromPtr (jsdc, jsdv));
676 NS_ASSERTION (0, "Unknown hook type.");
682 if (!jsds_FilterHook (jsdc, jsdthreadstate))
683 return JSD_HOOK_RETURN_CONTINUE;
685 JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
686 nsCOMPtr<jsdIStackFrame> frame =
687 getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
689 gJsds->Pause(nsnull);
690 jsdIValue *inout_rv = js_rv;
691 NS_IF_ADDREF(inout_rv);
692 hook->OnExecute (frame, type, &inout_rv, &hook_rv);
694 NS_IF_RELEASE(inout_rv);
695 gJsds->UnPause(nsnull);
696 jsdStackFrame::InvalidateAll();
698 if (hook_rv == JSD_HOOK_RETURN_RET_WITH_VAL ||
699 hook_rv == JSD_HOOK_RETURN_THROW_WITH_VAL) {
703 if (NS_SUCCEEDED(js_rv->GetJSDValue (&jsdv)))
704 *rval = JSD_GetValueWrappedJSVal(jsdc, jsdv);
712 jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating,
715 #ifdef CAUTIOUS_SCRIPTHOOK
716 JSContext *cx = JSD_GetDefaultJSContext(jsdc);
717 JSRuntime *rt = JS_GetRuntime(cx);
721 nsCOMPtr<jsdIScriptHook> hook;
722 gJsds->GetScriptHook(getter_AddRefs(hook));
724 /* a script is being created */
726 /* nobody cares, just exit */
730 nsCOMPtr<jsdIScript> script =
731 getter_AddRefs(jsdScript::FromPtr(jsdc, jsdscript));
732 #ifdef CAUTIOUS_SCRIPTHOOK
735 gJsds->Pause(nsnull);
736 hook->OnScriptCreated (script);
737 gJsds->UnPause(nsnull);
738 #ifdef CAUTIOUS_SCRIPTHOOK
742 /* a script is being destroyed. even if there is no registered hook
743 * we'll still need to invalidate the jsdIScript record, in order
744 * to remove the reference held in the JSDScript private data. */
745 nsCOMPtr<jsdIScript> jsdis =
746 static_cast<jsdIScript *>(JSD_GetScriptPrivate(jsdscript));
752 if (gGCStatus == JSGC_END) {
753 nsCOMPtr<jsdIScriptHook> hook;
754 gJsds->GetScriptHook(getter_AddRefs(hook));
758 /* if GC *isn't* running, we can tell the user about the script
760 #ifdef CAUTIOUS_SCRIPTHOOK
764 gJsds->Pause(nsnull);
765 hook->OnScriptDestroyed (jsdis);
766 gJsds->UnPause(nsnull);
767 #ifdef CAUTIOUS_SCRIPTHOOK
771 /* if a GC *is* running, we've got to wait until it's done before
772 * we can execute any JS, so we queue the notification in a PRCList
773 * until GC tells us it's done. See jsds_GCCallbackProc(). */
774 DeadScript *ds = PR_NEW(DeadScript);
776 return; /* NS_ERROR_OUT_OF_MEMORY */
780 NS_ADDREF(ds->script);
782 /* if the queue exists, add to it */
783 PR_APPEND_LINK(&ds->links, &gDeadScripts->links);
785 /* otherwise create the queue */
786 PR_INIT_CLIST(&ds->links);
793 /*******************************************************************************
794 * reflected jsd data structures
795 *******************************************************************************/
799 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral);
802 jsdContext::GetJSDContext(JSDContext **_rval)
810 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject, jsdIObject)
813 jsdObject::GetJSDContext(JSDContext **_rval)
820 jsdObject::GetJSDObject(JSDObject **_rval)
827 jsdObject::GetCreatorURL(nsACString &_rval)
829 _rval.Assign(JSD_GetObjectNewURL(mCx, mObject));
834 jsdObject::GetCreatorLine(PRUint32 *_rval)
836 *_rval = JSD_GetObjectNewLineNumber(mCx, mObject);
841 jsdObject::GetConstructorURL(nsACString &_rval)
843 _rval.Assign(JSD_GetObjectConstructorURL(mCx, mObject));
848 jsdObject::GetConstructorLine(PRUint32 *_rval)
850 *_rval = JSD_GetObjectConstructorLineNumber(mCx, mObject);
855 jsdObject::GetValue(jsdIValue **_rval)
857 JSDValue *jsdv = JSD_GetValueForObject (mCx, mObject);
859 *_rval = jsdValue::FromPtr (mCx, jsdv);
864 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty, jsdIProperty, jsdIEphemeral)
866 jsdProperty::jsdProperty (JSDContext *aCx, JSDProperty *aProperty) :
867 mCx(aCx), mProperty(aProperty)
869 DEBUG_CREATE ("jsdProperty", gPropertyCount);
870 mValid = (aCx && aProperty);
871 mLiveListEntry.value = this;
872 jsds_InsertEphemeral (&gLiveProperties, &mLiveListEntry);
875 jsdProperty::~jsdProperty ()
877 DEBUG_DESTROY ("jsdProperty", gPropertyCount);
883 jsdProperty::Invalidate()
885 ASSERT_VALID_EPHEMERAL;
887 jsds_RemoveEphemeral (&gLiveProperties, &mLiveListEntry);
888 JSD_DropProperty (mCx, mProperty);
893 jsdProperty::InvalidateAll()
896 jsds_InvalidateAllEphemerals (&gLiveProperties);
900 jsdProperty::GetJSDContext(JSDContext **_rval)
907 jsdProperty::GetJSDProperty(JSDProperty **_rval)
914 jsdProperty::GetIsValid(PRBool *_rval)
921 jsdProperty::GetAlias(jsdIValue **_rval)
923 JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
925 *_rval = jsdValue::FromPtr (mCx, jsdv);
930 jsdProperty::GetFlags(PRUint32 *_rval)
932 *_rval = JSD_GetPropertyFlags (mCx, mProperty);
937 jsdProperty::GetName(jsdIValue **_rval)
939 JSDValue *jsdv = JSD_GetPropertyName (mCx, mProperty);
941 *_rval = jsdValue::FromPtr (mCx, jsdv);
946 jsdProperty::GetValue(jsdIValue **_rval)
948 JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
950 *_rval = jsdValue::FromPtr (mCx, jsdv);
955 jsdProperty::GetVarArgSlot(PRUint32 *_rval)
957 *_rval = JSD_GetPropertyVarArgSlot (mCx, mProperty);
962 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
965 AssignToJSString(nsACString *x, JSString *str)
971 size_t length = JS_GetStringEncodingLength(NULL, str);
972 if (length == size_t(-1))
973 return NS_ERROR_FAILURE;
974 x->SetLength(PRUint32(length));
975 if (x->Length() != PRUint32(length))
976 return NS_ERROR_OUT_OF_MEMORY;
977 JS_EncodeStringToBuffer(str, x->BeginWriting(), length);
981 jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
992 DEBUG_CREATE ("jsdScript", gScriptCount);
995 /* copy the script's information now, so we have it later, when it
997 JSD_LockScriptSubsystem(mCx);
998 mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
999 mFunctionName = new nsCString();
1000 if (mFunctionName) {
1001 JSString *str = JSD_GetScriptFunctionId(mCx, mScript);
1003 AssignToJSString(mFunctionName, str);
1005 mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
1006 mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
1007 mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
1008 JSD_UnlockScriptSubsystem(mCx);
1014 jsdScript::~jsdScript ()
1016 DEBUG_DESTROY ("jsdScript", gScriptCount);
1020 delete mFunctionName;
1023 PR_Free(mPPLineMap);
1025 /* Invalidate() needs to be called to release an owning reference to
1026 * ourselves, so if we got here without being invalidated, something
1027 * has gone wrong with our ref count. */
1028 NS_ASSERTION (!mValid, "Script destroyed without being invalidated.");
1032 * This method populates a line <-> pc map for a pretty printed version of this
1033 * script. It does this by decompiling, and then recompiling the script. The
1034 * resulting script is scanned for the line map, and then left as GC fodder.
1037 jsdScript::CreatePPLineMap()
1039 JSContext *cx = JSD_GetDefaultJSContext (mCx);
1040 JSAutoRequest ar(cx);
1041 JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
1042 JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
1043 JSScript *script; /* In JSD compartment */
1045 JSObject *scriptObj = NULL;
1048 const jschar *chars;
1054 JSAutoEnterCompartment ac;
1055 if (!ac.enter(cx, JS_GetFunctionObject(fun)))
1058 nargs = JS_GetFunctionArgumentCount(cx, fun);
1061 jsstr = JS_DecompileFunctionBody (cx, fun, 4);
1065 if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
1069 JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
1070 const char *argnames[] = {"arg1", "arg2", "arg3", "arg4",
1071 "arg5", "arg6", "arg7", "arg8",
1072 "arg9", "arg10", "arg11", "arg12" };
1073 fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
1074 length, "x-jsd:ppbuffer?type=function", 3);
1075 if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
1079 script = JSD_GetJSScript(mCx, mScript);
1083 JS::AutoEnterScriptCompartment ac;
1084 if (!ac.enter(cx, script))
1087 jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
1091 if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
1095 JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
1096 scriptObj = JS_CompileUCScript (cx, obj, chars, length, "x-jsd:ppbuffer?type=script", 1);
1099 script = JS_GetScriptFromObject(scriptObj);
1103 /* Make sure that a non-function script is rooted via scriptObj until the
1104 * end of script usage. */
1105 JS::Anchor<JSObject *> scriptAnchor(scriptObj);
1107 PRUint32 scriptExtent = JS_GetScriptLineExtent (cx, script);
1108 jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0);
1109 /* allocate worst case size of map (number of lines in script + 1
1110 * for our 0 record), we'll shrink it with a realloc later. */
1111 PCMapEntry *lineMap =
1112 static_cast<PCMapEntry *>
1113 (PR_Malloc((scriptExtent + 1) * sizeof (PCMapEntry)));
1114 PRUint32 lineMapSize = 0;
1117 for (PRUint32 line = baseLine; line < scriptExtent + baseLine; ++line) {
1118 jsbytecode* pc = JS_LineNumberToPC (cx, script, line);
1119 if (line == JS_PCToLineNumber (cx, script, pc)) {
1120 lineMap[lineMapSize].line = line;
1121 lineMap[lineMapSize].pc = pc - firstPC;
1125 if (scriptExtent != lineMapSize) {
1127 static_cast<PCMapEntry *>
1128 (PR_Realloc(mPPLineMap = lineMap,
1129 lineMapSize * sizeof(PCMapEntry)));
1131 PR_Free(mPPLineMap);
1137 mPCMapSize = lineMapSize;
1138 return mPPLineMap = lineMap;
1142 jsdScript::PPPcToLine (PRUint32 aPC)
1144 if (!mPPLineMap && !CreatePPLineMap())
1147 for (i = 1; i < mPCMapSize; ++i) {
1148 if (mPPLineMap[i].pc > aPC)
1149 return mPPLineMap[i - 1].line;
1152 return mPPLineMap[mPCMapSize - 1].line;
1156 jsdScript::PPLineToPc (PRUint32 aLine)
1158 if (!mPPLineMap && !CreatePPLineMap())
1161 for (i = 1; i < mPCMapSize; ++i) {
1162 if (mPPLineMap[i].line > aLine)
1163 return mPPLineMap[i - 1].pc;
1166 return mPPLineMap[mPCMapSize - 1].pc;
1170 jsdScript::GetJSDContext(JSDContext **_rval)
1172 ASSERT_VALID_EPHEMERAL;
1178 jsdScript::GetJSDScript(JSDScript **_rval)
1180 ASSERT_VALID_EPHEMERAL;
1186 jsdScript::GetVersion (PRInt32 *_rval)
1188 ASSERT_VALID_EPHEMERAL;
1189 JSContext *cx = JSD_GetDefaultJSContext (mCx);
1190 JSScript *script = JSD_GetJSScript(mCx, mScript);
1191 JS::AutoEnterScriptCompartment ac;
1192 if (!ac.enter(cx, script))
1193 return NS_ERROR_FAILURE;
1194 *_rval = static_cast<PRInt32>(JS_GetScriptVersion(cx, script));
1199 jsdScript::GetTag(PRUint32 *_rval)
1202 mTag = ++jsdScript::LastTag;
1209 jsdScript::Invalidate()
1211 ASSERT_VALID_EPHEMERAL;
1214 /* release the addref we do in FromPtr */
1215 jsdIScript *script = static_cast<jsdIScript *>
1216 (JSD_GetScriptPrivate(mScript));
1217 NS_ASSERTION (script == this, "That's not my script!");
1219 JSD_SetScriptPrivate(mScript, NULL);
1224 jsdScript::InvalidateAll ()
1227 if (NS_FAILED(gJsds->GetJSDContext (&cx)))
1231 JSDScript *iter = NULL;
1233 JSD_LockScriptSubsystem(cx);
1234 while((script = JSD_IterateScripts(cx, &iter)) != NULL) {
1235 nsCOMPtr<jsdIScript> jsdis =
1236 static_cast<jsdIScript *>(JSD_GetScriptPrivate(script));
1238 jsdis->Invalidate();
1240 JSD_UnlockScriptSubsystem(cx);
1244 jsdScript::GetIsValid(PRBool *_rval)
1251 jsdScript::SetFlags(PRUint32 flags)
1253 ASSERT_VALID_EPHEMERAL;
1254 JSD_SetScriptFlags(mCx, mScript, flags);
1259 jsdScript::GetFlags(PRUint32 *_rval)
1261 ASSERT_VALID_EPHEMERAL;
1262 *_rval = JSD_GetScriptFlags(mCx, mScript);
1267 jsdScript::GetFileName(nsACString &_rval)
1269 _rval.Assign(*mFileName);
1274 jsdScript::GetFunctionName(nsACString &_rval)
1276 _rval.Assign(*mFunctionName);
1281 jsdScript::GetParameterNames(PRUint32* count, PRUnichar*** paramNames)
1283 ASSERT_VALID_EPHEMERAL;
1284 JSContext *cx = JSD_GetDefaultJSContext (mCx);
1286 NS_WARNING("No default context !?");
1287 return NS_ERROR_FAILURE;
1289 JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
1292 *paramNames = nsnull;
1296 JSAutoRequest ar(cx);
1297 JSAutoEnterCompartment ac;
1298 if (!ac.enter(cx, JS_GetFunctionObject(fun)))
1299 return NS_ERROR_FAILURE;
1302 if (!JS_FunctionHasLocalNames(cx, fun) ||
1303 (nargs = JS_GetFunctionArgumentCount(cx, fun)) == 0) {
1305 *paramNames = nsnull;
1310 static_cast<PRUnichar**>(NS_Alloc(nargs * sizeof(PRUnichar*)));
1312 return NS_ERROR_OUT_OF_MEMORY;
1315 jsuword *names = JS_GetFunctionLocalNameArray(cx, fun, &mark);
1318 return NS_ERROR_OUT_OF_MEMORY;
1321 nsresult rv = NS_OK;
1322 for (uintN i = 0; i < nargs; ++i) {
1323 JSAtom *atom = JS_LocalNameToAtom(names[i]);
1327 JSString *str = JS_AtomKey(atom);
1328 ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str));
1330 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
1331 rv = NS_ERROR_OUT_OF_MEMORY;
1336 JS_ReleaseFunctionLocalNameArray(cx, mark);
1345 jsdScript::GetFunctionObject(jsdIValue **_rval)
1347 JSFunction *fun = JSD_GetJSFunction(mCx, mScript);
1349 return NS_ERROR_NOT_AVAILABLE;
1351 JSObject *obj = JS_GetFunctionObject(fun);
1353 return NS_ERROR_FAILURE;
1356 if (NS_FAILED(gJsds->GetJSDContext (&cx)))
1357 return NS_ERROR_NOT_INITIALIZED;
1359 JSDValue *jsdv = JSD_NewValue(cx, OBJECT_TO_JSVAL(obj));
1361 return NS_ERROR_OUT_OF_MEMORY;
1363 *_rval = jsdValue::FromPtr(cx, jsdv);
1365 JSD_DropValue(cx, jsdv);
1366 return NS_ERROR_OUT_OF_MEMORY;
1373 jsdScript::GetFunctionSource(nsAString & aFunctionSource)
1375 ASSERT_VALID_EPHEMERAL;
1376 JSContext *cx = JSD_GetDefaultJSContext (mCx);
1378 NS_WARNING("No default context !?");
1379 return NS_ERROR_FAILURE;
1381 JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
1383 JSAutoRequest ar(cx);
1386 JSAutoEnterCompartment ac;
1387 JS::AutoEnterScriptCompartment asc;
1389 if (!ac.enter(cx, JS_GetFunctionObject(fun)))
1390 return NS_ERROR_FAILURE;
1391 jsstr = JS_DecompileFunction (cx, fun, 4);
1393 JSScript *script = JSD_GetJSScript (mCx, mScript);
1394 if (!asc.enter(cx, script))
1395 return NS_ERROR_FAILURE;
1396 jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
1399 return NS_ERROR_FAILURE;
1402 const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length);
1404 return NS_ERROR_FAILURE;
1406 aFunctionSource = nsDependentString(chars, length);
1411 jsdScript::GetBaseLineNumber(PRUint32 *_rval)
1413 *_rval = mBaseLineNumber;
1418 jsdScript::GetLineExtent(PRUint32 *_rval)
1420 *_rval = mLineExtent;
1425 jsdScript::GetCallCount(PRUint32 *_rval)
1427 ASSERT_VALID_EPHEMERAL;
1428 *_rval = JSD_GetScriptCallCount (mCx, mScript);
1433 jsdScript::GetMaxRecurseDepth(PRUint32 *_rval)
1435 ASSERT_VALID_EPHEMERAL;
1436 *_rval = JSD_GetScriptMaxRecurseDepth (mCx, mScript);
1441 jsdScript::GetMinExecutionTime(double *_rval)
1443 ASSERT_VALID_EPHEMERAL;
1444 *_rval = JSD_GetScriptMinExecutionTime (mCx, mScript);
1449 jsdScript::GetMaxExecutionTime(double *_rval)
1451 ASSERT_VALID_EPHEMERAL;
1452 *_rval = JSD_GetScriptMaxExecutionTime (mCx, mScript);
1457 jsdScript::GetTotalExecutionTime(double *_rval)
1459 ASSERT_VALID_EPHEMERAL;
1460 *_rval = JSD_GetScriptTotalExecutionTime (mCx, mScript);
1465 jsdScript::GetMinOwnExecutionTime(double *_rval)
1467 ASSERT_VALID_EPHEMERAL;
1468 *_rval = JSD_GetScriptMinOwnExecutionTime (mCx, mScript);
1473 jsdScript::GetMaxOwnExecutionTime(double *_rval)
1475 ASSERT_VALID_EPHEMERAL;
1476 *_rval = JSD_GetScriptMaxOwnExecutionTime (mCx, mScript);
1481 jsdScript::GetTotalOwnExecutionTime(double *_rval)
1483 ASSERT_VALID_EPHEMERAL;
1484 *_rval = JSD_GetScriptTotalOwnExecutionTime (mCx, mScript);
1489 jsdScript::ClearProfileData()
1491 ASSERT_VALID_EPHEMERAL;
1492 JSD_ClearScriptProfileData(mCx, mScript);
1497 jsdScript::PcToLine(PRUint32 aPC, PRUint32 aPcmap, PRUint32 *_rval)
1499 ASSERT_VALID_EPHEMERAL;
1500 if (aPcmap == PCMAP_SOURCETEXT) {
1501 *_rval = JSD_GetClosestLine (mCx, mScript, mFirstPC + aPC);
1502 } else if (aPcmap == PCMAP_PRETTYPRINT) {
1503 *_rval = PPPcToLine(aPC);
1505 return NS_ERROR_INVALID_ARG;
1512 jsdScript::LineToPc(PRUint32 aLine, PRUint32 aPcmap, PRUint32 *_rval)
1514 ASSERT_VALID_EPHEMERAL;
1515 if (aPcmap == PCMAP_SOURCETEXT) {
1516 jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
1517 *_rval = pc - mFirstPC;
1518 } else if (aPcmap == PCMAP_PRETTYPRINT) {
1519 *_rval = PPLineToPc(aLine);
1521 return NS_ERROR_INVALID_ARG;
1528 jsdScript::EnableSingleStepInterrupts(PRBool enable)
1530 ASSERT_VALID_EPHEMERAL;
1532 /* Must have set interrupt hook before enabling */
1533 if (enable && !jsdService::GetService()->CheckInterruptHook())
1534 return NS_ERROR_NOT_INITIALIZED;
1536 return (JSD_EnableSingleStepInterrupts(mCx, mScript, enable) ? NS_OK : NS_ERROR_FAILURE);
1540 jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval)
1542 ASSERT_VALID_EPHEMERAL;
1543 if (aPcmap == PCMAP_SOURCETEXT) {
1544 jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
1545 *_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc));
1546 } else if (aPcmap == PCMAP_PRETTYPRINT) {
1547 if (!mPPLineMap && !CreatePPLineMap())
1548 return NS_ERROR_OUT_OF_MEMORY;
1550 for (PRUint32 i = 0; i < mPCMapSize; ++i) {
1551 if (mPPLineMap[i].line >= aLine) {
1552 *_rval = (mPPLineMap[i].line == aLine);
1557 return NS_ERROR_INVALID_ARG;
1564 jsdScript::SetBreakpoint(PRUint32 aPC)
1566 ASSERT_VALID_EPHEMERAL;
1567 jsuword pc = mFirstPC + aPC;
1568 JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, NULL);
1573 jsdScript::ClearBreakpoint(PRUint32 aPC)
1575 ASSERT_VALID_EPHEMERAL;
1576 jsuword pc = mFirstPC + aPC;
1577 JSD_ClearExecutionHook (mCx, mScript, pc);
1582 jsdScript::ClearAllBreakpoints()
1584 ASSERT_VALID_EPHEMERAL;
1585 JSD_LockScriptSubsystem(mCx);
1586 JSD_ClearAllExecutionHooksForScript (mCx, mScript);
1587 JSD_UnlockScriptSubsystem(mCx);
1592 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral)
1595 jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx)
1597 if (!aJSDCx || !aJSCx)
1600 nsCOMPtr<jsdIContext> jsdicx;
1601 nsCOMPtr<jsdIEphemeral> eph =
1602 jsds_FindEphemeral (&gLiveContexts, static_cast<void *>(aJSCx));
1605 jsdicx = do_QueryInterface(eph);
1609 nsCOMPtr<nsISupports> iscx;
1610 if (JS_GetOptions(aJSCx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
1611 iscx = static_cast<nsISupports *>(JS_GetContextPrivate(aJSCx));
1612 jsdicx = new jsdContext (aJSDCx, aJSCx, iscx);
1615 jsdIContext *ctx = nsnull;
1620 jsdContext::jsdContext (JSDContext *aJSDCx, JSContext *aJSCx,
1621 nsISupports *aISCx) : mValid(PR_TRUE), mTag(0),
1623 mJSCx(aJSCx), mISCx(aISCx)
1625 DEBUG_CREATE ("jsdContext", gContextCount);
1626 mLiveListEntry.value = this;
1627 mLiveListEntry.key = static_cast<void *>(aJSCx);
1628 jsds_InsertEphemeral (&gLiveContexts, &mLiveListEntry);
1631 jsdContext::~jsdContext()
1633 DEBUG_DESTROY ("jsdContext", gContextCount);
1636 /* call Invalidate() to take ourselves out of the live list */
1642 jsdContext::GetIsValid(PRBool *_rval)
1649 jsdContext::Invalidate()
1651 ASSERT_VALID_EPHEMERAL;
1653 jsds_RemoveEphemeral (&gLiveContexts, &mLiveListEntry);
1658 jsdContext::InvalidateAll()
1661 jsds_InvalidateAllEphemerals (&gLiveContexts);
1665 jsdContext::GetJSContext(JSContext **_rval)
1667 ASSERT_VALID_EPHEMERAL;
1673 jsdContext::GetOptions(PRUint32 *_rval)
1675 ASSERT_VALID_EPHEMERAL;
1676 *_rval = JS_GetOptions(mJSCx);
1681 jsdContext::SetOptions(PRUint32 options)
1683 ASSERT_VALID_EPHEMERAL;
1684 PRUint32 lastOptions = JS_GetOptions(mJSCx);
1686 /* don't let users change this option, they'd just be shooting themselves
1688 if ((options ^ lastOptions) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
1689 return NS_ERROR_ILLEGAL_VALUE;
1691 JS_SetOptions(mJSCx, options);
1696 jsdContext::GetPrivateData(nsISupports **_rval)
1698 ASSERT_VALID_EPHEMERAL;
1699 PRUint32 options = JS_GetOptions(mJSCx);
1700 if (options & JSOPTION_PRIVATE_IS_NSISUPPORTS)
1702 *_rval = static_cast<nsISupports*>(JS_GetContextPrivate(mJSCx));
1703 NS_IF_ADDREF(*_rval);
1714 jsdContext::GetWrappedContext(nsISupports **_rval)
1716 ASSERT_VALID_EPHEMERAL;
1717 NS_IF_ADDREF(*_rval = mISCx);
1722 jsdContext::GetTag(PRUint32 *_rval)
1724 ASSERT_VALID_EPHEMERAL;
1726 mTag = ++jsdContext::LastTag;
1733 jsdContext::GetVersion (PRInt32 *_rval)
1735 ASSERT_VALID_EPHEMERAL;
1736 *_rval = static_cast<PRInt32>(JS_GetVersion(mJSCx));
1741 jsdContext::SetVersion (PRInt32 id)
1743 ASSERT_VALID_EPHEMERAL;
1744 JSVersion ver = static_cast<JSVersion>(id);
1745 JS_SetVersion(mJSCx, ver);
1750 jsdContext::GetGlobalObject (jsdIValue **_rval)
1752 ASSERT_VALID_EPHEMERAL;
1753 JSObject *glob = JS_GetGlobalObject(mJSCx);
1754 JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
1756 return NS_ERROR_FAILURE;
1757 *_rval = jsdValue::FromPtr (mJSDCx, jsdv);
1759 return NS_ERROR_FAILURE;
1764 jsdContext::GetScriptsEnabled (PRBool *_rval)
1766 ASSERT_VALID_EPHEMERAL;
1772 nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
1774 return NS_ERROR_NO_INTERFACE;
1776 *_rval = context->GetScriptsEnabled();
1782 jsdContext::SetScriptsEnabled (PRBool _rval)
1784 ASSERT_VALID_EPHEMERAL;
1788 return NS_ERROR_NO_INTERFACE;
1791 nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
1793 return NS_ERROR_NO_INTERFACE;
1795 context->SetScriptsEnabled(_rval, PR_TRUE);
1801 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame, jsdIStackFrame, jsdIEphemeral)
1803 jsdStackFrame::jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState,
1804 JSDStackFrameInfo *aStackFrameInfo) :
1805 mCx(aCx), mThreadState(aThreadState), mStackFrameInfo(aStackFrameInfo)
1807 DEBUG_CREATE ("jsdStackFrame", gFrameCount);
1808 mValid = (aCx && aThreadState && aStackFrameInfo);
1810 mLiveListEntry.key = aStackFrameInfo;
1811 mLiveListEntry.value = this;
1812 jsds_InsertEphemeral (&gLiveStackFrames, &mLiveListEntry);
1816 jsdStackFrame::~jsdStackFrame()
1818 DEBUG_DESTROY ("jsdStackFrame", gFrameCount);
1821 /* call Invalidate() to take ourselves out of the live list */
1827 jsdStackFrame::FromPtr (JSDContext *aCx, JSDThreadState *aThreadState,
1828 JSDStackFrameInfo *aStackFrameInfo)
1830 if (!aStackFrameInfo)
1834 nsCOMPtr<jsdIStackFrame> frame;
1836 nsCOMPtr<jsdIEphemeral> eph =
1837 jsds_FindEphemeral (&gLiveStackFrames,
1838 reinterpret_cast<void *>(aStackFrameInfo));
1842 frame = do_QueryInterface(eph);
1847 rv = new jsdStackFrame (aCx, aThreadState, aStackFrameInfo);
1855 jsdStackFrame::Invalidate()
1857 ASSERT_VALID_EPHEMERAL;
1859 jsds_RemoveEphemeral (&gLiveStackFrames, &mLiveListEntry);
1864 jsdStackFrame::InvalidateAll()
1866 if (gLiveStackFrames)
1867 jsds_InvalidateAllEphemerals (&gLiveStackFrames);
1871 jsdStackFrame::GetJSDContext(JSDContext **_rval)
1873 ASSERT_VALID_EPHEMERAL;
1879 jsdStackFrame::GetJSDThreadState(JSDThreadState **_rval)
1881 ASSERT_VALID_EPHEMERAL;
1882 *_rval = mThreadState;
1887 jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo **_rval)
1889 ASSERT_VALID_EPHEMERAL;
1890 *_rval = mStackFrameInfo;
1895 jsdStackFrame::GetIsValid(PRBool *_rval)
1902 jsdStackFrame::GetCallingFrame(jsdIStackFrame **_rval)
1904 ASSERT_VALID_EPHEMERAL;
1905 JSDStackFrameInfo *sfi = JSD_GetCallingStackFrame (mCx, mThreadState,
1907 *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
1912 jsdStackFrame::GetExecutionContext(jsdIContext **_rval)
1914 ASSERT_VALID_EPHEMERAL;
1915 JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
1916 *_rval = jsdContext::FromPtr (mCx, cx);
1921 jsdStackFrame::GetFunctionName(nsACString &_rval)
1923 ASSERT_VALID_EPHEMERAL;
1924 JSString *str = JSD_GetIdForStackFrame(mCx, mThreadState, mStackFrameInfo);
1926 return AssignToJSString(&_rval, str);
1928 _rval.Assign("anonymous");
1933 jsdStackFrame::GetIsDebugger(PRBool *_rval)
1935 ASSERT_VALID_EPHEMERAL;
1936 *_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo);
1941 jsdStackFrame::GetIsConstructing(PRBool *_rval)
1943 ASSERT_VALID_EPHEMERAL;
1944 *_rval = JSD_IsStackFrameConstructing (mCx, mThreadState, mStackFrameInfo);
1949 jsdStackFrame::GetScript(jsdIScript **_rval)
1951 ASSERT_VALID_EPHEMERAL;
1952 JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1954 *_rval = jsdScript::FromPtr (mCx, script);
1959 jsdStackFrame::GetPc(PRUint32 *_rval)
1961 ASSERT_VALID_EPHEMERAL;
1962 JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1965 return NS_ERROR_FAILURE;
1966 jsuword pcbase = JSD_GetClosestPC(mCx, script, 0);
1968 jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
1970 *_rval = pc - pcbase;
1977 jsdStackFrame::GetLine(PRUint32 *_rval)
1979 ASSERT_VALID_EPHEMERAL;
1980 JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1983 jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
1984 *_rval = JSD_GetClosestLine (mCx, script, pc);
1986 return NS_ERROR_FAILURE;
1992 jsdStackFrame::GetCallee(jsdIValue **_rval)
1994 ASSERT_VALID_EPHEMERAL;
1995 JSDValue *jsdv = JSD_GetCallObjectForStackFrame (mCx, mThreadState,
1998 *_rval = jsdValue::FromPtr (mCx, jsdv);
2003 jsdStackFrame::GetScope(jsdIValue **_rval)
2005 ASSERT_VALID_EPHEMERAL;
2006 JSDValue *jsdv = JSD_GetScopeChainForStackFrame (mCx, mThreadState,
2009 *_rval = jsdValue::FromPtr (mCx, jsdv);
2014 jsdStackFrame::GetThisValue(jsdIValue **_rval)
2016 ASSERT_VALID_EPHEMERAL;
2017 JSDValue *jsdv = JSD_GetThisForStackFrame (mCx, mThreadState,
2020 *_rval = jsdValue::FromPtr (mCx, jsdv);
2026 jsdStackFrame::Eval (const nsAString &bytes, const nsACString &fileName,
2027 PRUint32 line, jsdIValue **result, PRBool *_rval)
2029 ASSERT_VALID_EPHEMERAL;
2031 if (bytes.IsEmpty())
2032 return NS_ERROR_INVALID_ARG;
2034 // get pointer to buffer contained in |bytes|
2035 nsAString::const_iterator h;
2036 bytes.BeginReading(h);
2037 const jschar *char_bytes = reinterpret_cast<const jschar *>(h.get());
2039 JSExceptionState *estate = 0;
2042 JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
2044 JSAutoRequest ar(cx);
2046 estate = JS_SaveExceptionState (cx);
2047 JS_ClearPendingException (cx);
2050 nsCOMPtr<nsIJSContextStack> stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
2051 if (NS_SUCCEEDED(rv))
2052 rv = stack->Push(cx);
2053 if (NS_FAILED(rv)) {
2054 JS_RestoreExceptionState (cx, estate);
2058 *_rval = JSD_AttemptUCScriptInStackFrame (mCx, mThreadState,
2060 char_bytes, bytes.Length(),
2061 PromiseFlatCString(fileName).get(),
2064 if (JS_IsExceptionPending(cx))
2065 JS_GetPendingException (cx, &jv);
2070 JS_RestoreExceptionState (cx, estate);
2073 JSContext* poppedCX;
2074 rv = stack->Pop(&poppedCX);
2075 NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == cx, "bad pop");
2077 (void) stack->Pop(nsnull);
2080 JSDValue *jsdv = JSD_NewValue (mCx, jv);
2082 return NS_ERROR_FAILURE;
2083 *result = jsdValue::FromPtr (mCx, jsdv);
2085 return NS_ERROR_FAILURE;
2091 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue, jsdIValue, jsdIEphemeral)
2093 jsdValue::FromPtr (JSDContext *aCx, JSDValue *aValue)
2095 /* value will be dropped by te jsdValue destructor. */
2100 jsdIValue *rv = new jsdValue (aCx, aValue);
2105 jsdValue::jsdValue (JSDContext *aCx, JSDValue *aValue) : mValid(PR_TRUE),
2109 DEBUG_CREATE ("jsdValue", gValueCount);
2110 mLiveListEntry.value = this;
2111 jsds_InsertEphemeral (&gLiveValues, &mLiveListEntry);
2114 jsdValue::~jsdValue()
2116 DEBUG_DESTROY ("jsdValue", gValueCount);
2118 /* call Invalidate() to take ourselves out of the live list */
2123 jsdValue::GetIsValid(PRBool *_rval)
2130 jsdValue::Invalidate()
2132 ASSERT_VALID_EPHEMERAL;
2134 jsds_RemoveEphemeral (&gLiveValues, &mLiveListEntry);
2135 JSD_DropValue (mCx, mValue);
2140 jsdValue::InvalidateAll()
2143 jsds_InvalidateAllEphemerals (&gLiveValues);
2147 jsdValue::GetJSDContext(JSDContext **_rval)
2149 ASSERT_VALID_EPHEMERAL;
2155 jsdValue::GetJSDValue (JSDValue **_rval)
2157 ASSERT_VALID_EPHEMERAL;
2163 jsdValue::GetIsNative (PRBool *_rval)
2165 ASSERT_VALID_EPHEMERAL;
2166 *_rval = JSD_IsValueNative (mCx, mValue);
2171 jsdValue::GetIsNumber (PRBool *_rval)
2173 ASSERT_VALID_EPHEMERAL;
2174 *_rval = JSD_IsValueNumber (mCx, mValue);
2179 jsdValue::GetIsPrimitive (PRBool *_rval)
2181 ASSERT_VALID_EPHEMERAL;
2182 *_rval = JSD_IsValuePrimitive (mCx, mValue);
2187 jsdValue::GetJsType (PRUint32 *_rval)
2189 ASSERT_VALID_EPHEMERAL;
2192 val = JSD_GetValueWrappedJSVal (mCx, mValue);
2194 if (JSVAL_IS_NULL(val))
2196 else if (JSVAL_IS_BOOLEAN(val))
2197 *_rval = TYPE_BOOLEAN;
2198 else if (JSVAL_IS_DOUBLE(val))
2199 *_rval = TYPE_DOUBLE;
2200 else if (JSVAL_IS_INT(val))
2202 else if (JSVAL_IS_STRING(val))
2203 *_rval = TYPE_STRING;
2204 else if (JSVAL_IS_VOID(val))
2206 else if (JSD_IsValueFunction (mCx, mValue))
2207 *_rval = TYPE_FUNCTION;
2208 else if (JSVAL_IS_OBJECT(val))
2209 *_rval = TYPE_OBJECT;
2211 NS_ASSERTION (0, "Value has no discernible type.");
2217 jsdValue::GetJsPrototype (jsdIValue **_rval)
2219 ASSERT_VALID_EPHEMERAL;
2220 JSDValue *jsdv = JSD_GetValuePrototype (mCx, mValue);
2221 *_rval = jsdValue::FromPtr (mCx, jsdv);
2226 jsdValue::GetJsParent (jsdIValue **_rval)
2228 ASSERT_VALID_EPHEMERAL;
2229 JSDValue *jsdv = JSD_GetValueParent (mCx, mValue);
2230 *_rval = jsdValue::FromPtr (mCx, jsdv);
2235 jsdValue::GetJsClassName(nsACString &_rval)
2237 ASSERT_VALID_EPHEMERAL;
2238 _rval.Assign(JSD_GetValueClassName(mCx, mValue));
2244 jsdValue::GetJsConstructor (jsdIValue **_rval)
2246 ASSERT_VALID_EPHEMERAL;
2247 JSDValue *jsdv = JSD_GetValueConstructor (mCx, mValue);
2248 *_rval = jsdValue::FromPtr (mCx, jsdv);
2253 jsdValue::GetJsFunctionName(nsACString &_rval)
2255 ASSERT_VALID_EPHEMERAL;
2256 return AssignToJSString(&_rval, JSD_GetValueFunctionId(mCx, mValue));
2260 jsdValue::GetBooleanValue(PRBool *_rval)
2262 ASSERT_VALID_EPHEMERAL;
2263 *_rval = JSD_GetValueBoolean (mCx, mValue);
2268 jsdValue::GetDoubleValue(double *_rval)
2270 ASSERT_VALID_EPHEMERAL;
2271 *_rval = JSD_GetValueDouble (mCx, mValue);
2276 jsdValue::GetIntValue(PRInt32 *_rval)
2278 ASSERT_VALID_EPHEMERAL;
2279 *_rval = JSD_GetValueInt (mCx, mValue);
2284 jsdValue::GetObjectValue(jsdIObject **_rval)
2286 ASSERT_VALID_EPHEMERAL;
2288 obj = JSD_GetObjectForValue (mCx, mValue);
2289 *_rval = jsdObject::FromPtr (mCx, obj);
2291 return NS_ERROR_FAILURE;
2296 jsdValue::GetStringValue(nsACString &_rval)
2298 ASSERT_VALID_EPHEMERAL;
2299 JSContext *cx = JSD_GetDefaultJSContext (mCx);
2301 NS_WARNING("No default context !?");
2302 return NS_ERROR_FAILURE;
2304 JSString *jstr_val = JSD_GetValueString(mCx, mValue);
2307 const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length);
2309 return NS_ERROR_FAILURE;
2310 nsDependentString depStr(chars, length);
2311 CopyUTF16toUTF8(depStr, _rval);
2319 jsdValue::GetPropertyCount (PRInt32 *_rval)
2321 ASSERT_VALID_EPHEMERAL;
2322 if (JSD_IsValueObject(mCx, mValue))
2323 *_rval = JSD_GetCountOfProperties (mCx, mValue);
2330 jsdValue::GetProperties (jsdIProperty ***propArray, PRUint32 *length)
2332 ASSERT_VALID_EPHEMERAL;
2333 *propArray = nsnull;
2337 PRUint32 prop_count = JSD_IsValueObject(mCx, mValue)
2338 ? JSD_GetCountOfProperties (mCx, mValue)
2340 NS_ENSURE_TRUE(prop_count, NS_OK);
2342 jsdIProperty **pa_temp =
2343 static_cast<jsdIProperty **>
2344 (nsMemory::Alloc(sizeof (jsdIProperty *) *
2346 NS_ENSURE_TRUE(pa_temp, NS_ERROR_OUT_OF_MEMORY);
2349 JSDProperty *iter = NULL;
2351 while ((prop = JSD_IterateProperties (mCx, mValue, &iter))) {
2352 pa_temp[i] = jsdProperty::FromPtr (mCx, prop);
2356 NS_ASSERTION (prop_count == i, "property count mismatch");
2358 /* if caller doesn't care about length, don't bother telling them */
2359 *propArray = pa_temp;
2361 *length = prop_count;
2367 jsdValue::GetProperty (const nsACString &name, jsdIProperty **_rval)
2369 ASSERT_VALID_EPHEMERAL;
2370 JSContext *cx = JSD_GetDefaultJSContext (mCx);
2372 JSAutoRequest ar(cx);
2374 /* not rooting this */
2375 JSString *jstr_name = JS_NewStringCopyZ(cx, PromiseFlatCString(name).get());
2377 return NS_ERROR_OUT_OF_MEMORY;
2379 JSDProperty *prop = JSD_GetValueProperty (mCx, mValue, jstr_name);
2381 *_rval = jsdProperty::FromPtr (mCx, prop);
2388 ASSERT_VALID_EPHEMERAL;
2389 JSD_RefreshValue (mCx, mValue);
2394 jsdValue::GetWrappedValue()
2396 ASSERT_VALID_EPHEMERAL;
2398 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2402 nsAXPCNativeCallContext *cc = nsnull;
2403 rv = xpc->GetCurrentNativeCallContext(&cc);
2408 rv = cc->GetRetValPtr(&result);
2415 rv = cc->GetJSContext(&cx);
2418 *result = JSD_GetValueWrappedJSVal (mCx, mValue);
2419 if (!JS_WrapValue(cx, result))
2420 return NS_ERROR_FAILURE;
2421 cc->SetReturnValueWasSet(PR_TRUE);
2428 jsdValue::GetScript(jsdIScript **_rval)
2430 ASSERT_VALID_EPHEMERAL;
2431 JSDScript *script = JSD_GetScriptForValue(mCx, mValue);
2432 *_rval = jsdScript::FromPtr(mCx, script);
2436 /******************************************************************************
2437 * debugger service implementation
2438 ******************************************************************************/
2439 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdService, jsdIDebuggerService)
2442 jsdService::GetJSDContext(JSDContext **_rval)
2449 jsdService::GetFlags (PRUint32 *_rval)
2451 ASSERT_VALID_CONTEXT;
2452 *_rval = JSD_GetContextFlags (mCx);
2457 jsdService::SetFlags (PRUint32 flags)
2459 ASSERT_VALID_CONTEXT;
2460 JSD_SetContextFlags (mCx, flags);
2465 jsdService::GetImplementationString(nsACString &aImplementationString)
2467 aImplementationString.AssignLiteral(implementationString);
2472 jsdService::GetImplementationMajor(PRUint32 *_rval)
2474 *_rval = JSDS_MAJOR_VERSION;
2479 jsdService::GetImplementationMinor(PRUint32 *_rval)
2481 *_rval = JSDS_MINOR_VERSION;
2486 jsdService::GetIsOn (PRBool *_rval)
2493 jsdService::On (void)
2495 return NS_ERROR_NOT_IMPLEMENTED;
2499 jsdService::AsyncOn (jsdIActivationCallback *activationCallback)
2503 /* get JS things from the CallContext */
2504 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2505 if (NS_FAILED(rv)) return rv;
2507 nsAXPCNativeCallContext *cc = nsnull;
2508 rv = xpc->GetCurrentNativeCallContext(&cc);
2509 if (NS_FAILED(rv)) return rv;
2512 rv = cc->GetJSContext (&cx);
2513 if (NS_FAILED(rv)) return rv;
2515 mActivationCallback = activationCallback;
2517 return xpc->SetDebugModeWhenPossible(PR_TRUE);
2521 jsdService::RecompileForDebugMode (JSContext *cx, JSCompartment *comp, JSBool mode) {
2522 NS_ASSERTION(NS_IsMainThread(), "wrong thread");
2523 /* XPConnect now does this work itself, so this IDL entry point is no longer used. */
2524 return NS_ERROR_NOT_IMPLEMENTED;
2528 jsdService::DeactivateDebugger ()
2533 jsdContext::InvalidateAll();
2534 jsdScript::InvalidateAll();
2535 jsdValue::InvalidateAll();
2536 jsdProperty::InvalidateAll();
2537 jsdStackFrame::InvalidateAll();
2538 ClearAllBreakpoints();
2540 JSD_SetErrorReporter (mCx, NULL, NULL);
2541 JSD_SetScriptHook (mCx, NULL, NULL);
2542 JSD_ClearThrowHook (mCx);
2543 JSD_ClearInterruptHook (mCx);
2544 JSD_ClearDebuggerHook (mCx);
2545 JSD_ClearDebugBreakHook (mCx);
2546 JSD_ClearTopLevelHook (mCx);
2547 JSD_ClearFunctionHook (mCx);
2549 JSD_DebuggerOff (mCx);
2560 jsdService::ActivateDebugger (JSRuntime *rt)
2563 return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED;
2567 if (gLastGCProc == jsds_GCCallbackProc)
2568 /* condition indicates that the callback proc has not been set yet */
2569 gLastGCProc = JS_SetGCCallbackRT (rt, jsds_GCCallbackProc);
2571 mCx = JSD_DebuggerOnForUser (rt, NULL, NULL);
2573 return NS_ERROR_FAILURE;
2575 JSContext *cx = JSD_GetDefaultJSContext (mCx);
2576 JSObject *glob = JS_GetGlobalObject (cx);
2578 /* init xpconnect on the debugger's context in case xpconnect tries to
2579 * use it for stuff. */
2581 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2585 xpc->InitClasses (cx, glob);
2587 /* Start watching for script creation/destruction and manage jsdScript
2588 * objects accordingly
2590 JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
2592 /* If any of these mFooHook objects are installed, do the required JSD
2593 * hookup now. See also, jsdService::SetFooHook().
2596 JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
2598 JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
2599 /* can't ignore script callbacks, as we need to |Release| the wrapper
2600 * stored in private data when a script is deleted. */
2602 JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
2604 JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
2606 JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
2608 JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
2610 JSD_ClearTopLevelHook (mCx);
2612 JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
2614 JSD_ClearFunctionHook (mCx);
2618 printf ("+++ JavaScript debugging hooks installed.\n");
2621 if (mActivationCallback)
2622 return mActivationCallback->OnDebuggerActivated();
2628 jsdService::Off (void)
2633 if (!mCx || !mRuntime)
2634 return NS_ERROR_NOT_INITIALIZED;
2637 if (gGCStatus != JSGC_END)
2638 return NS_ERROR_NOT_AVAILABLE;
2640 JSContext *cx = JSD_GetDefaultJSContext(mCx);
2641 while (gDeadScripts)
2642 jsds_NotifyPendingDeadScripts (cx);
2646 if (gLastGCProc != jsds_GCCallbackProc)
2647 JS_SetGCCallbackRT (mRuntime, gLastGCProc);
2650 DeactivateDebugger();
2653 printf ("+++ JavaScript debugging hooks removed.\n");
2657 nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2661 xpc->SetDebugModeWhenPossible(PR_FALSE);
2667 jsdService::GetPauseDepth(PRUint32 *_rval)
2669 NS_ENSURE_ARG_POINTER(_rval);
2670 *_rval = mPauseLevel;
2675 jsdService::Pause(PRUint32 *_rval)
2678 return NS_ERROR_NOT_INITIALIZED;
2680 if (++mPauseLevel == 1) {
2681 JSD_SetErrorReporter (mCx, NULL, NULL);
2682 JSD_ClearThrowHook (mCx);
2683 JSD_ClearInterruptHook (mCx);
2684 JSD_ClearDebuggerHook (mCx);
2685 JSD_ClearDebugBreakHook (mCx);
2686 JSD_ClearTopLevelHook (mCx);
2687 JSD_ClearFunctionHook (mCx);
2688 JSD_DebuggerPause (mCx);
2692 *_rval = mPauseLevel;
2698 jsdService::UnPause(PRUint32 *_rval)
2701 return NS_ERROR_NOT_INITIALIZED;
2703 if (mPauseLevel == 0)
2704 return NS_ERROR_NOT_AVAILABLE;
2706 /* check mOn before we muck with this stuff, it's possible the debugger
2707 * was turned off while we were paused.
2709 if (--mPauseLevel == 0 && mOn) {
2710 JSD_DebuggerUnpause (mCx);
2712 JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
2714 JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
2716 JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
2718 JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
2720 JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
2722 JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
2724 JSD_ClearTopLevelHook (mCx);
2726 JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
2728 JSD_ClearFunctionHook (mCx);
2732 *_rval = mPauseLevel;
2738 jsdService::EnumerateContexts (jsdIContextEnumerator *enumerator)
2740 ASSERT_VALID_CONTEXT;
2745 JSContext *iter = NULL;
2748 while ((cx = JS_ContextIterator (mRuntime, &iter)))
2750 nsCOMPtr<jsdIContext> jsdicx =
2751 getter_AddRefs(jsdContext::FromPtr(mCx, cx));
2754 if (NS_FAILED(enumerator->EnumerateContext(jsdicx)))
2763 jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator)
2765 ASSERT_VALID_CONTEXT;
2768 JSDScript *iter = NULL;
2769 nsresult rv = NS_OK;
2771 JSD_LockScriptSubsystem(mCx);
2772 while((script = JSD_IterateScripts(mCx, &iter))) {
2773 nsCOMPtr<jsdIScript> jsdis =
2774 getter_AddRefs(jsdScript::FromPtr(mCx, script));
2775 rv = enumerator->EnumerateScript (jsdis);
2779 JSD_UnlockScriptSubsystem(mCx);
2785 jsdService::GC (void)
2787 ASSERT_VALID_CONTEXT;
2788 JSContext *cx = JSD_GetDefaultJSContext (mCx);
2794 jsdService::DumpHeap(const nsACString &fileName)
2796 ASSERT_VALID_CONTEXT;
2798 return NS_ERROR_NOT_IMPLEMENTED;
2800 nsresult rv = NS_OK;
2801 FILE *file = !fileName.IsEmpty() ? fopen(PromiseFlatCString(fileName).get(), "w") : stdout;
2803 rv = NS_ERROR_FAILURE;
2805 JSContext *cx = JSD_GetDefaultJSContext (mCx);
2806 if (!JS_DumpHeap(cx, file, NULL, 0, NULL, (size_t)-1, NULL))
2807 rv = NS_ERROR_FAILURE;
2816 jsdService::ClearProfileData ()
2818 ASSERT_VALID_CONTEXT;
2819 JSD_ClearAllProfileData (mCx);
2824 jsdService::InsertFilter (jsdIFilter *filter, jsdIFilter *after)
2826 NS_ENSURE_ARG_POINTER (filter);
2827 if (jsds_FindFilter (filter))
2828 return NS_ERROR_INVALID_ARG;
2830 FilterRecord *rec = PR_NEWZAP (FilterRecord);
2832 return NS_ERROR_OUT_OF_MEMORY;
2834 if (!jsds_SyncFilter (rec, filter)) {
2836 return NS_ERROR_FAILURE;
2841 /* insert at head of list */
2842 PR_INSERT_LINK(&rec->links, &gFilters->links);
2845 /* insert somewhere in the list */
2846 FilterRecord *afterRecord = jsds_FindFilter (after);
2848 jsds_FreeFilter(rec);
2849 return NS_ERROR_INVALID_ARG;
2851 PR_INSERT_AFTER(&rec->links, &afterRecord->links);
2855 /* user asked to insert into the middle of an empty list, bail. */
2856 jsds_FreeFilter(rec);
2857 return NS_ERROR_NOT_INITIALIZED;
2859 PR_INIT_CLIST(&rec->links);
2867 jsdService::AppendFilter (jsdIFilter *filter)
2869 NS_ENSURE_ARG_POINTER (filter);
2870 if (jsds_FindFilter (filter))
2871 return NS_ERROR_INVALID_ARG;
2872 FilterRecord *rec = PR_NEWZAP (FilterRecord);
2874 if (!jsds_SyncFilter (rec, filter)) {
2876 return NS_ERROR_FAILURE;
2880 PR_INSERT_BEFORE(&rec->links, &gFilters->links);
2882 PR_INIT_CLIST(&rec->links);
2890 jsdService::RemoveFilter (jsdIFilter *filter)
2892 NS_ENSURE_ARG_POINTER(filter);
2893 FilterRecord *rec = jsds_FindFilter (filter);
2895 return NS_ERROR_INVALID_ARG;
2897 if (gFilters == rec) {
2898 gFilters = reinterpret_cast<FilterRecord *>
2899 (PR_NEXT_LINK(&rec->links));
2900 /* If we're the only filter left, null out the list head. */
2901 if (gFilters == rec)
2906 PR_REMOVE_LINK(&rec->links);
2907 jsds_FreeFilter (rec);
2913 jsdService::SwapFilters (jsdIFilter *filter_a, jsdIFilter *filter_b)
2915 NS_ENSURE_ARG_POINTER(filter_a);
2916 NS_ENSURE_ARG_POINTER(filter_b);
2918 FilterRecord *rec_a = jsds_FindFilter (filter_a);
2920 return NS_ERROR_INVALID_ARG;
2922 if (filter_a == filter_b) {
2923 /* just a refresh */
2924 if (!jsds_SyncFilter (rec_a, filter_a))
2925 return NS_ERROR_FAILURE;
2929 FilterRecord *rec_b = jsds_FindFilter (filter_b);
2931 /* filter_b is not in the list, replace filter_a with filter_b. */
2932 if (!jsds_SyncFilter (rec_a, filter_b))
2933 return NS_ERROR_FAILURE;
2935 /* both filters are in the list, swap. */
2936 if (!jsds_SyncFilter (rec_a, filter_b))
2937 return NS_ERROR_FAILURE;
2938 if (!jsds_SyncFilter (rec_b, filter_a))
2939 return NS_ERROR_FAILURE;
2946 jsdService::EnumerateFilters (jsdIFilterEnumerator *enumerator)
2951 FilterRecord *current = gFilters;
2953 jsds_SyncFilter (current, current->filterObject);
2954 /* SyncFilter failure would be bad, but what would we do about it? */
2956 nsresult rv = enumerator->EnumerateFilter (current->filterObject);
2960 current = reinterpret_cast<FilterRecord *>
2961 (PR_NEXT_LINK (¤t->links));
2962 } while (current != gFilters);
2968 jsdService::RefreshFilters ()
2970 return EnumerateFilters(nsnull);
2974 jsdService::ClearFilters ()
2979 FilterRecord *current = reinterpret_cast<FilterRecord *>
2980 (PR_NEXT_LINK (&gFilters->links));
2982 FilterRecord *next = reinterpret_cast<FilterRecord *>
2983 (PR_NEXT_LINK (¤t->links));
2984 PR_REMOVE_AND_INIT_LINK(¤t->links);
2985 jsds_FreeFilter(current);
2987 } while (current != gFilters);
2989 jsds_FreeFilter(current);
2996 jsdService::ClearAllBreakpoints (void)
2998 ASSERT_VALID_CONTEXT;
3000 JSD_LockScriptSubsystem(mCx);
3001 JSD_ClearAllExecutionHooks (mCx);
3002 JSD_UnlockScriptSubsystem(mCx);
3007 jsdService::WrapValue(jsdIValue **_rval)
3009 ASSERT_VALID_CONTEXT;
3012 nsCOMPtr<nsIXPConnect> xpc = do_GetService (nsIXPConnect::GetCID(), &rv);
3016 nsAXPCNativeCallContext *cc = nsnull;
3017 rv = xpc->GetCurrentNativeCallContext (&cc);
3022 rv = cc->GetArgc (&argc);
3026 return NS_ERROR_INVALID_ARG;
3029 rv = cc->GetArgvPtr (&argv);
3033 return WrapJSValue(argv[0], _rval);
3037 jsdService::WrapJSValue(const jsval &value, jsdIValue** _rval)
3039 JSDValue *jsdv = JSD_NewValue(mCx, value);
3041 return NS_ERROR_FAILURE;
3043 *_rval = jsdValue::FromPtr (mCx, jsdv);
3049 jsdService::EnterNestedEventLoop (jsdINestCallback *callback, PRUint32 *_rval)
3051 // Nesting event queues is a thing of the past. Now, we just spin the
3052 // current event loop.
3055 nsCOMPtr<nsIJSContextStack>
3056 stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
3059 PRUint32 nestLevel = ++mNestedLoopLevel;
3061 nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
3063 if (NS_SUCCEEDED(stack->Push(nsnull))) {
3066 rv = callback->OnNest();
3070 while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) {
3071 if (!NS_ProcessNextEvent(thread))
3072 rv = NS_ERROR_UNEXPECTED;
3077 NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
3080 rv = NS_ERROR_FAILURE;
3082 NS_ASSERTION (mNestedLoopLevel <= nestLevel,
3083 "nested event didn't unwind properly");
3084 if (mNestedLoopLevel == nestLevel)
3087 *_rval = mNestedLoopLevel;
3092 jsdService::ExitNestedEventLoop (PRUint32 *_rval)
3094 if (mNestedLoopLevel > 0)
3097 return NS_ERROR_FAILURE;
3099 *_rval = mNestedLoopLevel;
3103 /* hook attribute get/set functions */
3106 jsdService::SetErrorHook (jsdIErrorHook *aHook)
3110 /* if the debugger isn't initialized, that's all we can do for now. The
3111 * ActivateDebugger() method will do the rest when the coast is clear.
3113 if (!mCx || mPauseLevel)
3117 JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
3119 JSD_SetErrorReporter (mCx, NULL, NULL);
3125 jsdService::GetErrorHook (jsdIErrorHook **aHook)
3127 *aHook = mErrorHook;
3128 NS_IF_ADDREF(*aHook);
3134 jsdService::SetBreakpointHook (jsdIExecutionHook *aHook)
3136 mBreakpointHook = aHook;
3141 jsdService::GetBreakpointHook (jsdIExecutionHook **aHook)
3143 *aHook = mBreakpointHook;
3144 NS_IF_ADDREF(*aHook);
3150 jsdService::SetDebugHook (jsdIExecutionHook *aHook)
3154 /* if the debugger isn't initialized, that's all we can do for now. The
3155 * ActivateDebugger() method will do the rest when the coast is clear.
3157 if (!mCx || mPauseLevel)
3161 JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
3163 JSD_ClearDebugBreakHook (mCx);
3169 jsdService::GetDebugHook (jsdIExecutionHook **aHook)
3171 *aHook = mDebugHook;
3172 NS_IF_ADDREF(*aHook);
3178 jsdService::SetDebuggerHook (jsdIExecutionHook *aHook)
3180 mDebuggerHook = aHook;
3182 /* if the debugger isn't initialized, that's all we can do for now. The
3183 * ActivateDebugger() method will do the rest when the coast is clear.
3185 if (!mCx || mPauseLevel)
3189 JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
3191 JSD_ClearDebuggerHook (mCx);
3197 jsdService::GetDebuggerHook (jsdIExecutionHook **aHook)
3199 *aHook = mDebuggerHook;
3200 NS_IF_ADDREF(*aHook);
3206 jsdService::SetInterruptHook (jsdIExecutionHook *aHook)
3208 mInterruptHook = aHook;
3210 /* if the debugger isn't initialized, that's all we can do for now. The
3211 * ActivateDebugger() method will do the rest when the coast is clear.
3213 if (!mCx || mPauseLevel)
3217 JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
3219 JSD_ClearInterruptHook (mCx);
3225 jsdService::GetInterruptHook (jsdIExecutionHook **aHook)
3227 *aHook = mInterruptHook;
3228 NS_IF_ADDREF(*aHook);
3234 jsdService::SetScriptHook (jsdIScriptHook *aHook)
3236 mScriptHook = aHook;
3238 /* if the debugger isn't initialized, that's all we can do for now. The
3239 * ActivateDebugger() method will do the rest when the coast is clear.
3241 if (!mCx || mPauseLevel)
3245 JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
3246 /* we can't unset it if !aHook, because we still need to see script
3247 * deletes in order to Release the jsdIScripts held in JSDScript
3253 jsdService::GetScriptHook (jsdIScriptHook **aHook)
3255 *aHook = mScriptHook;
3256 NS_IF_ADDREF(*aHook);
3262 jsdService::SetThrowHook (jsdIExecutionHook *aHook)
3266 /* if the debugger isn't initialized, that's all we can do for now. The
3267 * ActivateDebugger() method will do the rest when the coast is clear.
3269 if (!mCx || mPauseLevel)
3273 JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
3275 JSD_ClearThrowHook (mCx);
3281 jsdService::GetThrowHook (jsdIExecutionHook **aHook)
3283 *aHook = mThrowHook;
3284 NS_IF_ADDREF(*aHook);
3290 jsdService::SetTopLevelHook (jsdICallHook *aHook)
3292 mTopLevelHook = aHook;
3294 /* if the debugger isn't initialized, that's all we can do for now. The
3295 * ActivateDebugger() method will do the rest when the coast is clear.
3297 if (!mCx || mPauseLevel)
3301 JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
3303 JSD_ClearTopLevelHook (mCx);
3309 jsdService::GetTopLevelHook (jsdICallHook **aHook)
3311 *aHook = mTopLevelHook;
3312 NS_IF_ADDREF(*aHook);
3318 jsdService::SetFunctionHook (jsdICallHook *aHook)
3320 mFunctionHook = aHook;
3322 /* if the debugger isn't initialized, that's all we can do for now. The
3323 * ActivateDebugger() method will do the rest when the coast is clear.
3325 if (!mCx || mPauseLevel)
3329 JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
3331 JSD_ClearFunctionHook (mCx);
3337 jsdService::GetFunctionHook (jsdICallHook **aHook)
3339 *aHook = mFunctionHook;
3340 NS_IF_ADDREF(*aHook);
3346 jsdService::~jsdService()
3349 mErrorHook = nsnull;
3350 mBreakpointHook = nsnull;
3351 mDebugHook = nsnull;
3352 mDebuggerHook = nsnull;
3353 mInterruptHook = nsnull;
3354 mScriptHook = nsnull;
3355 mThrowHook = nsnull;
3356 mTopLevelHook = nsnull;
3357 mFunctionHook = nsnull;
3358 gGCStatus = JSGC_END;
3364 jsdService::GetService ()
3367 gJsds = new jsdService();
3369 NS_IF_ADDREF(gJsds);
3373 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService, jsdService::GetService)
3375 /* app-start observer. turns on the debugger at app-start. this is inserted
3376 * and/or removed from the app-start category by the jsdService::initAtStartup
3379 class jsdASObserver : public nsIObserver
3388 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver, nsIObserver)
3391 jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic,
3392 const PRUnichar *aData)
3396 // Hmm. Why is the app-startup observer called multiple times?
3397 //NS_ASSERTION(!gJsds, "app startup observer called twice");
3398 nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
3403 rv = jsds->GetIsOn(&on);
3404 if (NS_FAILED(rv) || on)
3407 nsCOMPtr<nsIJSRuntimeService> rts = do_GetService(NS_JSRT_CTRID, &rv);
3412 rts->GetRuntime (&rt);
3416 rv = jsds->ActivateDebugger(rt);
3423 NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
3424 NS_DEFINE_NAMED_CID(JSDSERVICE_CID);
3425 NS_DEFINE_NAMED_CID(JSDASO_CID);
3427 static const mozilla::Module::CIDEntry kJSDCIDs[] = {
3428 { &kJSDSERVICE_CID, false, NULL, jsdServiceConstructor },
3429 { &kJSDASO_CID, false, NULL, jsdASObserverConstructor },
3433 static const mozilla::Module::ContractIDEntry kJSDContracts[] = {
3434 { jsdServiceCtrID, &kJSDSERVICE_CID },
3435 { jsdARObserverCtrID, &kJSDASO_CID },
3439 static const mozilla::Module kJSDModule = {
3440 mozilla::Module::kVersion,
3445 NSMODULE_DEFN(JavaScript_Debugger) = &kJSDModule;
3447 /********************************************************************************
3448 ********************************************************************************
3454 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState, jsdIThreadState);
3457 jsdThreadState::GetJSDContext(JSDContext **_rval)
3464 jsdThreadState::GetJSDThreadState(JSDThreadState **_rval)
3466 *_rval = mThreadState;
3471 jsdThreadState::GetFrameCount (PRUint32 *_rval)
3473 *_rval = JSD_GetCountOfStackFrames (mCx, mThreadState);
3478 jsdThreadState::GetTopFrame (jsdIStackFrame **_rval)
3480 JSDStackFrameInfo *sfi = JSD_GetStackFrame (mCx, mThreadState);
3482 *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
3487 jsdThreadState::GetPendingException(jsdIValue **_rval)
3489 JSDValue *jsdv = JSD_GetException (mCx, mThreadState);
3491 *_rval = jsdValue::FromPtr (mCx, jsdv);
3496 jsdThreadState::SetPendingException(jsdIValue *aException)
3500 nsresult rv = aException->GetJSDValue (&jsdv);
3502 return NS_ERROR_FAILURE;
3504 if (!JSD_SetException (mCx, mThreadState, jsdv))
3505 return NS_ERROR_FAILURE;