Back to index

lightning-sunbird  0.9+nobinonly
jsd_xpc.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Robert Ginda, <rginda@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "jsd_xpc.h"
00041 #include "jsdbgapi.h"
00042 #include "jscntxt.h"
00043 #include "jsfun.h"
00044 
00045 #include "nsIXPConnect.h"
00046 #include "nsIGenericFactory.h"
00047 #include "nsIServiceManager.h"
00048 #include "nsIScriptGlobalObject.h"
00049 #include "nsIObserver.h"
00050 #include "nsIObserverService.h"
00051 #include "nsICategoryManager.h"
00052 #include "nsIJSRuntimeService.h"
00053 #include "nsIEventQueueService.h"
00054 #include "nsMemory.h"
00055 #include "jsdebug.h"
00056 #include "nsReadableUtils.h"
00057 #include "nsCRT.h"
00058 
00059 /* XXX this stuff is used by NestEventLoop, a temporary hack to be refactored
00060  * later */
00061 #include "nsWidgetsCID.h"
00062 #include "nsIScriptContext.h"
00063 #include "nsIAppShell.h"
00064 #include "nsIJSContextStack.h"
00065 
00066 /*
00067  * defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
00068  * script hook.  This was a hack to avoid some js engine problems that should
00069  * be fixed now (see Mozilla bug 77636).
00070  */
00071 #undef CAUTIOUS_SCRIPTHOOK
00072 
00073 #ifdef DEBUG_verbose
00074 #   define DEBUG_COUNT(name, count)                                             \
00075         { if ((count % 10) == 0) printf (name ": %i\n", count); }
00076 #   define DEBUG_CREATE(name, count) {count++; DEBUG_COUNT ("+++++ "name,count)}
00077 #   define DEBUG_DESTROY(name, count) {count--; DEBUG_COUNT ("----- "name,count)}
00078 #else
00079 #   define DEBUG_CREATE(name, count) 
00080 #   define DEBUG_DESTROY(name, count)
00081 #endif
00082 
00083 #define ASSERT_VALID_CONTEXT   { if (!mCx) return NS_ERROR_NOT_AVAILABLE; }
00084 #define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; }
00085 
00086 #define JSDSERVICE_CID                               \
00087 { /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */         \
00088      0xf1299dc2,                                     \
00089      0x1dd1,                                         \
00090      0x11b2,                                         \
00091     {0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \
00092 }
00093 
00094 #define JSDASO_CID                                   \
00095 { /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */         \
00096      0x2fd6b7f6,                                     \
00097      0xeb8c,                                         \
00098      0x4f32,                                         \
00099     {0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \
00100 }
00101 
00102 #define JSDS_MAJOR_VERSION 1
00103 #define JSDS_MINOR_VERSION 2
00104 
00105 #define NS_CATMAN_CTRID   "@mozilla.org/categorymanager;1"
00106 #define NS_JSRT_CTRID     "@mozilla.org/js/xpc/RuntimeService;1"
00107 
00108 #define AUTOREG_CATEGORY  "xpcom-autoregistration"
00109 #define APPSTART_CATEGORY "app-startup"
00110 #define JSD_AUTOREG_ENTRY "JSDebugger Startup Observer"
00111 #define JSD_STARTUP_ENTRY "JSDebugger Startup Observer,service"
00112 
00113 JS_STATIC_DLL_CALLBACK (JSBool)
00114 jsds_GCCallbackProc (JSContext *cx, JSGCStatus status);
00115 
00116 /*******************************************************************************
00117  * global vars
00118  ******************************************************************************/
00119 
00120 const char implementationString[] = "Mozilla JavaScript Debugger Service";
00121 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
00122 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00123 
00124 const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
00125 const char jsdASObserverCtrID[] = "@mozilla.org/js/jsd/app-start-observer;2";
00126 
00127 #ifdef DEBUG_verbose
00128 PRUint32 gScriptCount   = 0;
00129 PRUint32 gValueCount    = 0;
00130 PRUint32 gPropertyCount = 0;
00131 PRUint32 gContextCount  = 0;
00132 PRUint32 gFrameCount  = 0;
00133 #endif
00134 
00135 static jsdService   *gJsds       = 0;
00136 static JSGCCallback  gLastGCProc = jsds_GCCallbackProc;
00137 static JSGCStatus    gGCStatus   = JSGC_END;
00138 
00139 static struct DeadScript {
00140     PRCList     links;
00141     JSDContext *jsdc;
00142     jsdIScript *script;
00143 } *gDeadScripts = nsnull;
00144 
00145 enum PatternType {
00146     ptIgnore     = 0U,
00147     ptStartsWith = 1U,
00148     ptEndsWith   = 2U,
00149     ptContains   = 3U,
00150     ptEquals     = 4U
00151 };
00152 
00153 static struct FilterRecord {
00154     PRCList      links;
00155     jsdIFilter  *filterObject;
00156     void        *glob;
00157     char        *urlPattern;    
00158     PRUint32     patternLength;
00159     PatternType  patternType;
00160     PRUint32     startLine;
00161     PRUint32     endLine;
00162 } *gFilters = nsnull;
00163 
00164 static struct LiveEphemeral *gLiveValues      = nsnull;
00165 static struct LiveEphemeral *gLiveProperties  = nsnull;
00166 static struct LiveEphemeral *gLiveContexts    = nsnull;
00167 static struct LiveEphemeral *gLiveStackFrames = nsnull;
00168 
00169 /*******************************************************************************
00170  * utility functions for ephemeral lists
00171  *******************************************************************************/
00172 already_AddRefed<jsdIEphemeral>
00173 jsds_FindEphemeral (LiveEphemeral **listHead, void *key)
00174 {
00175     if (!*listHead)
00176         return nsnull;
00177     
00178     LiveEphemeral *lv_record = 
00179         NS_REINTERPRET_CAST (LiveEphemeral *,
00180                              PR_NEXT_LINK(&(*listHead)->links));
00181     do
00182     {
00183         if (lv_record->key == key)
00184         {
00185             NS_IF_ADDREF(lv_record->value);
00186             return lv_record->value;
00187         }
00188         lv_record = NS_REINTERPRET_CAST (LiveEphemeral *,
00189                                          PR_NEXT_LINK(&lv_record->links));
00190     }
00191     while (lv_record != *listHead);
00192 
00193     return nsnull;
00194 }
00195 
00196 void
00197 jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
00198 {
00199     LiveEphemeral *lv_record = 
00200         NS_REINTERPRET_CAST (LiveEphemeral *,
00201                              PR_NEXT_LINK(&(*listHead)->links));
00202     while (*listHead)
00203     {
00204         LiveEphemeral *next =
00205             NS_REINTERPRET_CAST (LiveEphemeral *,
00206                                  PR_NEXT_LINK(&lv_record->links));
00207         lv_record->value->Invalidate();
00208         lv_record = next;
00209     }
00210 }
00211 
00212 void
00213 jsds_InsertEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
00214 {
00215     if (*listHead) {
00216         /* if the list exists, add to it */
00217         PR_APPEND_LINK(&item->links, &(*listHead)->links);
00218     } else {
00219         /* otherwise create the list */
00220         PR_INIT_CLIST(&item->links);
00221         *listHead = item;
00222     }
00223 }
00224 
00225 void
00226 jsds_RemoveEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
00227 {
00228     LiveEphemeral *next = NS_REINTERPRET_CAST (LiveEphemeral *,
00229                                                PR_NEXT_LINK(&item->links));
00230 
00231     if (next == item)
00232     {
00233         /* if the current item is also the next item, we're the only element,
00234          * null out the list head */
00235         NS_ASSERTION (*listHead == item,
00236                       "How could we not be the head of a one item list?");
00237         *listHead = nsnull;
00238     }
00239     else if (item == *listHead)
00240     {
00241         /* otherwise, if we're currently the list head, change it */
00242         *listHead = next;
00243     }
00244     
00245     PR_REMOVE_AND_INIT_LINK(&item->links);
00246 }
00247 
00248 /*******************************************************************************
00249  * utility functions for filters
00250  *******************************************************************************/
00251 void
00252 jsds_FreeFilter (FilterRecord *filter)
00253 {
00254     NS_IF_RELEASE (filter->filterObject);
00255     if (filter->urlPattern)
00256         nsMemory::Free(filter->urlPattern);
00257     PR_Free (filter);
00258 }
00259 
00260 /* copies appropriate |filter| attributes into |rec|.
00261  * False return indicates failure, the contents of |rec| will not be changed.
00262  */
00263 PRBool
00264 jsds_SyncFilter (FilterRecord *rec, jsdIFilter *filter)
00265 {
00266     NS_ASSERTION (rec, "jsds_SyncFilter without rec");
00267     NS_ASSERTION (filter, "jsds_SyncFilter without filter");
00268     
00269     JSObject *glob_proper = nsnull;
00270     nsCOMPtr<nsISupports> glob;
00271     nsresult rv = filter->GetGlobalObject(getter_AddRefs(glob));
00272     if (NS_FAILED(rv))
00273         return PR_FALSE;
00274     if (glob) {
00275         nsCOMPtr<nsIScriptGlobalObject> nsiglob = do_QueryInterface(glob);
00276         if (nsiglob)
00277             glob_proper = nsiglob->GetGlobalJSObject();
00278     }
00279     
00280     PRUint32 startLine;
00281     rv = filter->GetStartLine(&startLine);
00282     if (NS_FAILED(rv))
00283         return PR_FALSE;
00284 
00285     PRUint32 endLine;
00286     rv = filter->GetStartLine(&endLine);
00287     if (NS_FAILED(rv))
00288         return PR_FALSE;    
00289 
00290     char *urlPattern;
00291     rv = filter->GetUrlPattern (&urlPattern);
00292     if (NS_FAILED(rv))
00293         return PR_FALSE;
00294     
00295     if (urlPattern) {
00296         PRUint32 len = PL_strlen(urlPattern);
00297         if (urlPattern[0] == '*') {
00298             /* pattern starts with a *, shift all chars once to the left,
00299              * including the trailing null. */
00300             memmove (&urlPattern[0], &urlPattern[1], len);
00301 
00302             if (urlPattern[len - 2] == '*') {
00303                 /* pattern is in the format "*foo*", overwrite the final * with
00304                  * a null. */
00305                 urlPattern[len - 2] = '\0';
00306                 rec->patternType = ptContains;
00307                 rec->patternLength = len - 2;
00308             } else {
00309                 /* pattern is in the format "*foo", just make a note of the
00310                  * new length. */
00311                 rec->patternType = ptEndsWith;
00312                 rec->patternLength = len - 1;
00313             }
00314         } else if (urlPattern[len - 1] == '*') {
00315             /* pattern is in the format "foo*", overwrite the final * with a 
00316              * null. */
00317             urlPattern[len - 1] = '\0';
00318             rec->patternType = ptStartsWith;
00319             rec->patternLength = len - 1;
00320         } else {
00321             /* pattern is in the format "foo". */
00322             rec->patternType = ptEquals;
00323             rec->patternLength = len;
00324         }
00325     } else {
00326         rec->patternType = ptIgnore;
00327         rec->patternLength = 0;
00328     }
00329 
00330     /* we got everything we need without failing, now copy it into rec. */
00331 
00332     if (rec->filterObject != filter) {
00333         NS_IF_RELEASE(rec->filterObject);
00334         NS_ADDREF(filter);
00335         rec->filterObject = filter;
00336     }
00337     
00338     rec->glob = glob_proper;
00339     
00340     rec->startLine     = startLine;
00341     rec->endLine       = endLine;
00342     
00343     if (rec->urlPattern)
00344         nsMemory::Free (rec->urlPattern);
00345     rec->urlPattern = urlPattern;
00346 
00347     return PR_TRUE;
00348             
00349 }
00350 
00351 FilterRecord *
00352 jsds_FindFilter (jsdIFilter *filter)
00353 {
00354     if (!gFilters)
00355         return nsnull;
00356     
00357     FilterRecord *current = gFilters;
00358     
00359     do {
00360         if (current->filterObject == filter)
00361             return current;
00362         current = NS_REINTERPRET_CAST(FilterRecord *,
00363                                       PR_NEXT_LINK(&current->links));
00364     } while (current != gFilters);
00365     
00366     return nsnull;
00367 }
00368 
00369 /* returns true if the hook should be executed. */
00370 PRBool
00371 jsds_FilterHook (JSDContext *jsdc, JSDThreadState *state)
00372 {
00373     JSContext *cx = JSD_GetJSContext (jsdc, state);
00374     void *glob = NS_STATIC_CAST(void *, JS_GetGlobalObject (cx));
00375 
00376     if (!glob) {
00377         NS_WARNING("No global in threadstate");
00378         return PR_FALSE;
00379     }
00380     
00381     JSDStackFrameInfo *frame = JSD_GetStackFrame (jsdc, state);
00382 
00383     if (!frame) {
00384         NS_WARNING("No frame in threadstate");
00385         return PR_FALSE;
00386     }
00387 
00388     JSDScript *script = JSD_GetScriptForStackFrame (jsdc, state, frame);
00389     if (!script)
00390         return PR_TRUE;
00391 
00392     jsuint pc = JSD_GetPCForStackFrame (jsdc, state, frame);
00393 
00394     const char *url = JSD_GetScriptFilename (jsdc, script);
00395     if (!url) {
00396         NS_WARNING ("Script with no filename");
00397         return PR_FALSE;
00398     }
00399 
00400     if (!gFilters)
00401         return PR_TRUE;    
00402 
00403     PRUint32 currentLine = JSD_GetClosestLine (jsdc, script, pc);
00404     PRUint32 len = 0;
00405     FilterRecord *currentFilter = gFilters;
00406     do {
00407         PRUint32 flags = 0;
00408         nsresult rv = currentFilter->filterObject->GetFlags(&flags);
00409         NS_ASSERTION(NS_SUCCEEDED(rv), "Error getting flags for filter");
00410         if (flags & jsdIFilter::FLAG_ENABLED) {
00411             /* if there is no glob, or the globs match */
00412             if ((!currentFilter->glob || currentFilter->glob == glob) &&
00413                 /* and there is no start line, or the start line is before 
00414                  * or equal to the current */
00415                 (!currentFilter->startLine || 
00416                  currentFilter->startLine <= currentLine) &&
00417                 /* and there is no end line, or the end line is after
00418                  * or equal to the current */
00419                 (!currentFilter->endLine ||
00420                  currentFilter->endLine >= currentLine)) {
00421                 /* then we're going to have to compare the url. */
00422                 if (currentFilter->patternType == ptIgnore)
00423                     return flags & jsdIFilter::FLAG_PASS;
00424 
00425                 if (!len)
00426                     len = PL_strlen(url);
00427                 
00428                 if (len >= currentFilter->patternLength) {
00429                     switch (currentFilter->patternType) {
00430                         case ptEquals:
00431                             if (!PL_strcmp(currentFilter->urlPattern, url))
00432                                 return flags & jsdIFilter::FLAG_PASS;
00433                             break;
00434                         case ptStartsWith:
00435                             if (!PL_strncmp(currentFilter->urlPattern, url, 
00436                                            currentFilter->patternLength))
00437                                 return flags & jsdIFilter::FLAG_PASS;
00438                             break;
00439                         case ptEndsWith:
00440                             if (!PL_strcmp(currentFilter->urlPattern,
00441                                            &url[len - 
00442                                                currentFilter->patternLength]))
00443                                 return flags & jsdIFilter::FLAG_PASS;
00444                             break;
00445                         case ptContains:
00446                             if (PL_strstr(url, currentFilter->urlPattern))
00447                                 return flags & jsdIFilter::FLAG_PASS;
00448                             break;
00449                         default:
00450                             NS_ASSERTION(0, "Invalid pattern type");
00451                     }
00452                 }                
00453             }
00454         }
00455         currentFilter = NS_REINTERPRET_CAST(FilterRecord *,
00456                                             PR_NEXT_LINK(&currentFilter->links));
00457     } while (currentFilter != gFilters);
00458 
00459     return PR_TRUE;
00460     
00461 }
00462 
00463 /*******************************************************************************
00464  * c callbacks
00465  *******************************************************************************/
00466 
00467 JS_STATIC_DLL_CALLBACK (void)
00468 jsds_NotifyPendingDeadScripts (JSContext *cx)
00469 {
00470     nsCOMPtr<jsdIScriptHook> hook = 0;   
00471     gJsds->GetScriptHook (getter_AddRefs(hook));
00472 
00473 #ifdef CAUTIOUS_SCRIPTHOOK
00474     JSRuntime *rt = JS_GetRuntime(cx);
00475 #endif
00476     gJsds->Pause(nsnull);
00477     DeadScript *deadScripts = gDeadScripts;
00478     gDeadScripts = nsnull;
00479     while (deadScripts) {
00480         DeadScript *ds = deadScripts;
00481         /* get next deleted script */
00482         deadScripts = NS_REINTERPRET_CAST(DeadScript *,
00483                                           PR_NEXT_LINK(&ds->links));
00484         if (deadScripts == ds)
00485             deadScripts = nsnull;
00486 
00487         if (hook)
00488         {
00489             /* tell the user this script has been destroyed */
00490 #ifdef CAUTIOUS_SCRIPTHOOK
00491             JS_UNKEEP_ATOMS(rt);
00492 #endif
00493             hook->OnScriptDestroyed (ds->script);
00494 #ifdef CAUTIOUS_SCRIPTHOOK
00495             JS_KEEP_ATOMS(rt);
00496 #endif
00497         }
00498 
00499         /* take it out of the circular list */
00500         PR_REMOVE_LINK(&ds->links);
00501 
00502         /* addref came from the FromPtr call in jsds_ScriptHookProc */
00503         NS_RELEASE(ds->script);
00504         /* free the struct! */
00505         PR_Free(ds);
00506     }
00507 
00508     gJsds->UnPause(nsnull);
00509 }
00510 
00511 JS_STATIC_DLL_CALLBACK (JSBool)
00512 jsds_GCCallbackProc (JSContext *cx, JSGCStatus status)
00513 {
00514 #ifdef DEBUG_verbose
00515     printf ("new gc status is %i\n", status);
00516 #endif
00517     if (status == JSGC_END) {
00518         /* just to guard against reentering. */
00519         gGCStatus = JSGC_BEGIN;
00520         while (gDeadScripts)
00521             jsds_NotifyPendingDeadScripts (cx);
00522     }
00523 
00524     gGCStatus = status;
00525     if (gLastGCProc)
00526         return gLastGCProc (cx, status);
00527     
00528     return JS_TRUE;
00529 }
00530 
00531 JS_STATIC_DLL_CALLBACK (uintN)
00532 jsds_ErrorHookProc (JSDContext *jsdc, JSContext *cx, const char *message,
00533                     JSErrorReport *report, void *callerdata)
00534 {
00535     static PRBool running = PR_FALSE;
00536 
00537     nsCOMPtr<jsdIErrorHook> hook;
00538     gJsds->GetErrorHook(getter_AddRefs(hook));
00539     if (!hook)
00540         return JSD_ERROR_REPORTER_PASS_ALONG;
00541 
00542     if (running)
00543         return JSD_ERROR_REPORTER_PASS_ALONG;
00544     
00545     running = PR_TRUE;
00546     
00547     nsCOMPtr<jsdIValue> val;
00548     if (JS_IsExceptionPending(cx)) {
00549         jsval jv;
00550         JS_GetPendingException(cx, &jv);
00551         JSDValue *jsdv = JSD_NewValue (jsdc, jv);
00552         val = getter_AddRefs(jsdValue::FromPtr(jsdc, jsdv));
00553     }
00554     
00555     const char *fileName;
00556     PRUint32    line;
00557     PRUint32    pos;
00558     PRUint32    flags;
00559     PRUint32    errnum;
00560     PRBool      rval;
00561     if (report) {
00562         fileName = report->filename;
00563         line = report->lineno;
00564         pos = report->tokenptr - report->linebuf;
00565         flags = report->flags;
00566         errnum = report->errorNumber;
00567     }
00568     else
00569     {
00570         fileName = 0;
00571         line     = 0;
00572         pos      = 0;
00573         flags    = 0;
00574         errnum   = 0;
00575     }
00576     
00577     gJsds->Pause(nsnull);
00578     hook->OnError (message, fileName, line, pos, flags, errnum, val, &rval);
00579     gJsds->UnPause(nsnull);
00580     
00581     running = PR_FALSE;
00582     if (!rval)
00583         return JSD_ERROR_REPORTER_DEBUG;
00584     
00585     return JSD_ERROR_REPORTER_PASS_ALONG;
00586 }
00587 
00588 JS_STATIC_DLL_CALLBACK (JSBool)
00589 jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
00590                    uintN type, void* callerdata)
00591 {
00592     nsCOMPtr<jsdICallHook> hook;
00593 
00594     switch (type)
00595     {
00596         case JSD_HOOK_TOPLEVEL_START:
00597         case JSD_HOOK_TOPLEVEL_END:
00598             gJsds->GetTopLevelHook(getter_AddRefs(hook));
00599             break;
00600             
00601         case JSD_HOOK_FUNCTION_CALL:
00602         case JSD_HOOK_FUNCTION_RETURN:
00603             gJsds->GetFunctionHook(getter_AddRefs(hook));
00604             break;
00605 
00606         default:
00607             NS_ASSERTION (0, "Unknown hook type.");
00608     }
00609     
00610     if (!hook)
00611         return JS_TRUE;
00612 
00613     if (!jsds_FilterHook (jsdc, jsdthreadstate))
00614         return JS_FALSE;
00615 
00616     JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
00617     nsCOMPtr<jsdIStackFrame> frame =
00618         getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
00619                                               native_frame));
00620     gJsds->Pause(nsnull);
00621     hook->OnCall(frame, type);    
00622     gJsds->UnPause(nsnull);
00623     jsdStackFrame::InvalidateAll();
00624 
00625     return JS_TRUE;
00626 }
00627 
00628 JS_STATIC_DLL_CALLBACK (PRUint32)
00629 jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
00630                         uintN type, void* callerdata, jsval* rval)
00631 {
00632     nsCOMPtr<jsdIExecutionHook> hook(0);
00633     PRUint32 hook_rv = JSD_HOOK_RETURN_CONTINUE;
00634     nsCOMPtr<jsdIValue> js_rv;
00635 
00636     switch (type)
00637     {
00638         case JSD_HOOK_INTERRUPTED:
00639             gJsds->GetInterruptHook(getter_AddRefs(hook));
00640             break;
00641         case JSD_HOOK_DEBUG_REQUESTED:
00642             gJsds->GetDebugHook(getter_AddRefs(hook));
00643             break;
00644         case JSD_HOOK_DEBUGGER_KEYWORD:
00645             gJsds->GetDebuggerHook(getter_AddRefs(hook));
00646             break;
00647         case JSD_HOOK_BREAKPOINT:
00648             {
00649                 /* we can't pause breakpoints the way we pause the other
00650                  * execution hooks (at least, not easily.)  Instead we bail
00651                  * here if the service is paused. */
00652                 PRUint32 level;
00653                 gJsds->GetPauseDepth(&level);
00654                 if (!level)
00655                     gJsds->GetBreakpointHook(getter_AddRefs(hook));
00656             }
00657             break;
00658         case JSD_HOOK_THROW:
00659         {
00660             hook_rv = JSD_HOOK_RETURN_CONTINUE_THROW;
00661             gJsds->GetThrowHook(getter_AddRefs(hook));
00662             if (hook) {
00663                 JSDValue *jsdv = JSD_GetException (jsdc, jsdthreadstate);
00664                 js_rv = getter_AddRefs(jsdValue::FromPtr (jsdc, jsdv));
00665             }
00666             break;
00667         }
00668         default:
00669             NS_ASSERTION (0, "Unknown hook type.");
00670     }
00671 
00672     if (!hook)
00673         return hook_rv;
00674     
00675     if (!jsds_FilterHook (jsdc, jsdthreadstate))
00676         return JSD_HOOK_RETURN_CONTINUE;
00677     
00678     JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
00679     nsCOMPtr<jsdIStackFrame> frame =
00680         getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
00681                                               native_frame));
00682     gJsds->Pause(nsnull);
00683     jsdIValue *inout_rv = js_rv;
00684     NS_IF_ADDREF(inout_rv);
00685     hook->OnExecute (frame, type, &inout_rv, &hook_rv);
00686     js_rv = inout_rv;
00687     NS_IF_RELEASE(inout_rv);
00688     gJsds->UnPause(nsnull);
00689     jsdStackFrame::InvalidateAll();
00690         
00691     if (hook_rv == JSD_HOOK_RETURN_RET_WITH_VAL ||
00692         hook_rv == JSD_HOOK_RETURN_THROW_WITH_VAL) {
00693         if (js_rv) {
00694             JSDValue *jsdv;
00695             js_rv->GetJSDValue (&jsdv);
00696             *rval = JSD_GetValueWrappedJSVal(jsdc, jsdv);
00697         } else {
00698             *rval = JSVAL_VOID;
00699         }
00700     }
00701     
00702     return hook_rv;
00703 }
00704 
00705 JS_STATIC_DLL_CALLBACK (void)
00706 jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating,
00707                      void* callerdata)
00708 {
00709 #ifdef CAUTIOUS_SCRIPTHOOK
00710     JSContext *cx = JSD_GetDefaultJSContext(jsdc);
00711     JSRuntime *rt = JS_GetRuntime(cx);
00712 #endif
00713 
00714     nsCOMPtr<jsdIScriptHook> hook;
00715     gJsds->GetScriptHook (getter_AddRefs(hook));
00716     
00717     if (creating) {
00718         /* a script is being created */
00719         if (!hook) {
00720             /* nobody cares, just exit */
00721             return;
00722         }
00723             
00724         nsCOMPtr<jsdIScript> script = 
00725             getter_AddRefs(jsdScript::FromPtr(jsdc, jsdscript));
00726 #ifdef CAUTIOUS_SCRIPTHOOK
00727         JS_UNKEEP_ATOMS(rt);
00728 #endif
00729         gJsds->Pause(nsnull);
00730         hook->OnScriptCreated (script);
00731         gJsds->UnPause(nsnull);
00732 #ifdef CAUTIOUS_SCRIPTHOOK
00733         JS_KEEP_ATOMS(rt);
00734 #endif
00735     } else {
00736         /* a script is being destroyed.  even if there is no registered hook
00737          * we'll still need to invalidate the jsdIScript record, in order
00738          * to remove the reference held in the JSDScript private data. */
00739         nsCOMPtr<jsdIScript> jsdis = 
00740             NS_STATIC_CAST(jsdIScript *, JSD_GetScriptPrivate(jsdscript));
00741         if (!jsdis)
00742             return;
00743         
00744         jsdis->Invalidate();
00745         if (!hook)
00746             return;
00747         
00748         if (gGCStatus == JSGC_END) {
00749             /* if GC *isn't* running, we can tell the user about the script
00750              * delete now. */
00751 #ifdef CAUTIOUS_SCRIPTHOOK
00752             JS_UNKEEP_ATOMS(rt);
00753 #endif
00754                 
00755             gJsds->Pause(nsnull);
00756             hook->OnScriptDestroyed (jsdis);
00757             gJsds->UnPause(nsnull);
00758 #ifdef CAUTIOUS_SCRIPTHOOK
00759             JS_KEEP_ATOMS(rt);
00760 #endif
00761         } else {
00762             /* if a GC *is* running, we've got to wait until it's done before
00763              * we can execute any JS, so we queue the notification in a PRCList
00764              * until GC tells us it's done. See jsds_GCCallbackProc(). */
00765             DeadScript *ds = PR_NEW(DeadScript);
00766             if (!ds)
00767                 return; /* NS_ERROR_OUT_OF_MEMORY */
00768         
00769             ds->jsdc = jsdc;
00770             ds->script = jsdis;
00771             NS_ADDREF(ds->script);
00772             if (gDeadScripts)
00773                 /* if the queue exists, add to it */
00774                 PR_APPEND_LINK(&ds->links, &gDeadScripts->links);
00775             else {
00776                 /* otherwise create the queue */
00777                 PR_INIT_CLIST(&ds->links);
00778                 gDeadScripts = ds;
00779             }
00780         }
00781     }            
00782 }
00783 
00784 /*******************************************************************************
00785  * reflected jsd data structures
00786  *******************************************************************************/
00787 
00788 /* Contexts */
00789 /*
00790 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdContext, jsdIContext); 
00791 
00792 NS_IMETHODIMP
00793 jsdContext::GetJSDContext(JSDContext **_rval)
00794 {
00795     *_rval = mCx;
00796     return NS_OK;
00797 }
00798 */
00799 
00800 /* Objects */
00801 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject, jsdIObject)
00802 
00803 NS_IMETHODIMP
00804 jsdObject::GetJSDContext(JSDContext **_rval)
00805 {
00806     *_rval = mCx;
00807     return NS_OK;
00808 }
00809 
00810 NS_IMETHODIMP
00811 jsdObject::GetJSDObject(JSDObject **_rval)
00812 {
00813     *_rval = mObject;
00814     return NS_OK;
00815 }
00816 
00817 NS_IMETHODIMP
00818 jsdObject::GetCreatorURL(char **_rval)
00819 {
00820     const char *url = JSD_GetObjectNewURL(mCx, mObject);
00821     if (url) {
00822         *_rval = PL_strdup(url);
00823         if (!*_rval)
00824             return NS_ERROR_OUT_OF_MEMORY;
00825     } else {
00826         *_rval = nsnull;
00827     }
00828     return NS_OK;
00829 }
00830 
00831 NS_IMETHODIMP
00832 jsdObject::GetCreatorLine(PRUint32 *_rval)
00833 {
00834     *_rval = JSD_GetObjectNewLineNumber(mCx, mObject);
00835     return NS_OK;
00836 }
00837 
00838 NS_IMETHODIMP
00839 jsdObject::GetConstructorURL(char **_rval)
00840 {
00841     const char *url = JSD_GetObjectConstructorURL(mCx, mObject);
00842     if (url) {
00843         *_rval = PL_strdup(url);
00844         if (!*_rval)
00845             return NS_ERROR_OUT_OF_MEMORY;
00846     } else {
00847         *_rval = nsnull;
00848     }
00849     return NS_OK;
00850 }
00851 
00852 NS_IMETHODIMP
00853 jsdObject::GetConstructorLine(PRUint32 *_rval)
00854 {
00855     *_rval = JSD_GetObjectConstructorLineNumber(mCx, mObject);
00856     return NS_OK;
00857 }
00858 
00859 NS_IMETHODIMP
00860 jsdObject::GetValue(jsdIValue **_rval)
00861 {
00862     JSDValue *jsdv = JSD_GetValueForObject (mCx, mObject);
00863     
00864     *_rval = jsdValue::FromPtr (mCx, jsdv);
00865     return NS_OK;
00866 }
00867 
00868 /* Properties */
00869 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty, jsdIProperty, jsdIEphemeral)
00870 
00871 jsdProperty::jsdProperty (JSDContext *aCx, JSDProperty *aProperty) :
00872     mCx(aCx), mProperty(aProperty)
00873 {
00874     DEBUG_CREATE ("jsdProperty", gPropertyCount);
00875     mValid = (aCx && aProperty);
00876     mLiveListEntry.value = this;
00877     jsds_InsertEphemeral (&gLiveProperties, &mLiveListEntry);
00878 }
00879 
00880 jsdProperty::~jsdProperty () 
00881 {
00882     DEBUG_DESTROY ("jsdProperty", gPropertyCount);
00883     if (mValid)
00884         Invalidate();
00885 }
00886 
00887 NS_IMETHODIMP
00888 jsdProperty::Invalidate()
00889 {
00890     ASSERT_VALID_EPHEMERAL;
00891     mValid = PR_FALSE;
00892     jsds_RemoveEphemeral (&gLiveProperties, &mLiveListEntry);
00893     JSD_DropProperty (mCx, mProperty);
00894     return NS_OK;
00895 }
00896 
00897 void
00898 jsdProperty::InvalidateAll()
00899 {
00900     if (gLiveProperties)
00901         jsds_InvalidateAllEphemerals (&gLiveProperties);
00902 }
00903 
00904 NS_IMETHODIMP
00905 jsdProperty::GetJSDContext(JSDContext **_rval)
00906 {
00907     *_rval = mCx;
00908     return NS_OK;
00909 }
00910 
00911 NS_IMETHODIMP
00912 jsdProperty::GetJSDProperty(JSDProperty **_rval)
00913 {
00914     *_rval = mProperty;
00915     return NS_OK;
00916 }
00917 
00918 NS_IMETHODIMP
00919 jsdProperty::GetIsValid(PRBool *_rval)
00920 {
00921     *_rval = mValid;
00922     return NS_OK;
00923 }
00924 
00925 NS_IMETHODIMP
00926 jsdProperty::GetAlias(jsdIValue **_rval)
00927 {
00928     JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
00929     
00930     *_rval = jsdValue::FromPtr (mCx, jsdv);
00931     return NS_OK;
00932 }
00933 
00934 NS_IMETHODIMP
00935 jsdProperty::GetFlags(PRUint32 *_rval)
00936 {
00937     *_rval = JSD_GetPropertyFlags (mCx, mProperty);
00938     return NS_OK;
00939 }
00940 
00941 NS_IMETHODIMP
00942 jsdProperty::GetName(jsdIValue **_rval)
00943 {
00944     JSDValue *jsdv = JSD_GetPropertyName (mCx, mProperty);
00945     
00946     *_rval = jsdValue::FromPtr (mCx, jsdv);
00947     return NS_OK;
00948 }
00949 
00950 NS_IMETHODIMP
00951 jsdProperty::GetValue(jsdIValue **_rval)
00952 {
00953     JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
00954     
00955     *_rval = jsdValue::FromPtr (mCx, jsdv);
00956     return NS_OK;
00957 }
00958 
00959 NS_IMETHODIMP
00960 jsdProperty::GetVarArgSlot(PRUint32 *_rval)
00961 {
00962     *_rval = JSD_GetPropertyVarArgSlot (mCx, mProperty);
00963     return NS_OK;
00964 }
00965 
00966 /* Scripts */
00967 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
00968 
00969 jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
00970                                                              mTag(0),
00971                                                              mCx(aCx),
00972                                                              mScript(aScript),
00973                                                              mFileName(0), 
00974                                                              mFunctionName(0),
00975                                                              mBaseLineNumber(0),
00976                                                              mLineExtent(0),
00977                                                              mPPLineMap(0),
00978                                                              mFirstPC(0)
00979 {
00980     DEBUG_CREATE ("jsdScript", gScriptCount);
00981 
00982     if (mScript) {
00983         /* copy the script's information now, so we have it later, when it
00984          * gets destroyed. */
00985         JSD_LockScriptSubsystem(mCx);
00986         mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
00987         mFunctionName =
00988             new nsCString(JSD_GetScriptFunctionName(mCx, mScript));
00989         mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
00990         mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
00991         mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
00992         JSD_UnlockScriptSubsystem(mCx);
00993         
00994         mValid = PR_TRUE;
00995     }
00996 }
00997 
00998 jsdScript::~jsdScript () 
00999 {
01000     DEBUG_DESTROY ("jsdScript", gScriptCount);
01001     if (mFileName)
01002         delete mFileName;
01003     if (mFunctionName)
01004         delete mFunctionName;
01005 
01006     if (mPPLineMap)
01007         PR_Free(mPPLineMap);
01008 
01009     /* Invalidate() needs to be called to release an owning reference to
01010      * ourselves, so if we got here without being invalidated, something
01011      * has gone wrong with our ref count. */
01012     NS_ASSERTION (!mValid, "Script destroyed without being invalidated.");
01013 }
01014 
01015 /*
01016  * This method populates a line <-> pc map for a pretty printed version of this
01017  * script.  It does this by decompiling, and then recompiling the script.  The
01018  * resulting script is scanned for the line map, and then left as GC fodder.
01019  */
01020 PCMapEntry *
01021 jsdScript::CreatePPLineMap()
01022 {    
01023     JSContext  *cx  = JSD_GetDefaultJSContext (mCx);
01024     JSObject   *obj = JS_NewObject(cx, NULL, NULL, NULL);
01025     JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
01026     JSScript   *script;
01027     PRUint32    baseLine;
01028     PRBool      scriptOwner = PR_FALSE;
01029     
01030     if (fun) {
01031         if (fun->nargs > 12)
01032             return nsnull;
01033         JSString *jsstr = JS_DecompileFunctionBody (cx, fun, 4);
01034         if (!jsstr)
01035             return nsnull;
01036     
01037         const char *argnames[] = {"arg1", "arg2", "arg3", "arg4", 
01038                                   "arg5", "arg6", "arg7", "arg8",
01039                                   "arg9", "arg10", "arg11", "arg12" };
01040         fun = JS_CompileUCFunction (cx, obj, "ppfun", fun->nargs, argnames,
01041                                     JS_GetStringChars(jsstr),
01042                                     JS_GetStringLength(jsstr),
01043                                     "x-jsd:ppbuffer?type=function", 3);
01044         if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
01045             return nsnull;
01046         baseLine = 3;
01047     } else {
01048         JSString *jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript),
01049                                               "ppscript", 4);
01050         if (!jsstr)
01051             return nsnull;
01052 
01053         script = JS_CompileUCScript (cx, obj,
01054                                      JS_GetStringChars(jsstr),
01055                                      JS_GetStringLength(jsstr),
01056                                      "x-jsd:ppbuffer?type=script", 1);
01057         if (!script)
01058             return nsnull;
01059         scriptOwner = PR_TRUE;
01060         baseLine = 1;
01061     }
01062         
01063     PRUint32 scriptExtent = JS_GetScriptLineExtent (cx, script);
01064     jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0);
01065     /* allocate worst case size of map (number of lines in script + 1
01066      * for our 0 record), we'll shrink it with a realloc later. */
01067     mPPLineMap = 
01068         NS_STATIC_CAST(PCMapEntry *,
01069                        PR_Malloc((scriptExtent + 1) * sizeof (PCMapEntry)));
01070     if (mPPLineMap) {             
01071         mPCMapSize = 0;
01072         for (PRUint32 line = baseLine; line < scriptExtent + baseLine; ++line) {
01073             jsbytecode* pc = JS_LineNumberToPC (cx, script, line);
01074             if (line == JS_PCToLineNumber (cx, script, pc)) {
01075                 mPPLineMap[mPCMapSize].line = line;
01076                 mPPLineMap[mPCMapSize].pc = pc - firstPC;
01077                 ++mPCMapSize;
01078             }
01079         }
01080         if (scriptExtent != mPCMapSize) {
01081             mPPLineMap =
01082                 NS_STATIC_CAST(PCMapEntry *,
01083                                PR_Realloc(mPPLineMap,
01084                                           mPCMapSize * sizeof(PCMapEntry)));
01085         }
01086     }
01087 
01088     if (scriptOwner)
01089         JS_DestroyScript (cx, script);
01090 
01091     return mPPLineMap;
01092 }
01093 
01094 PRUint32
01095 jsdScript::PPPcToLine (PRUint32 aPC)
01096 {
01097     if (!mPPLineMap && !CreatePPLineMap())
01098         return 0;
01099     PRUint32 i;
01100     for (i = 1; i < mPCMapSize; ++i) {
01101         if (mPPLineMap[i].pc > aPC)
01102             return mPPLineMap[i - 1].line;            
01103     }
01104 
01105     return mPPLineMap[mPCMapSize - 1].line;
01106 }
01107 
01108 PRUint32
01109 jsdScript::PPLineToPc (PRUint32 aLine)
01110 {
01111     if (!mPPLineMap && !CreatePPLineMap())
01112         return 0;
01113     PRUint32 i;
01114     for (i = 1; i < mPCMapSize; ++i) {
01115         if (mPPLineMap[i].line > aLine)
01116             return mPPLineMap[i - 1].pc;
01117     }
01118 
01119     return mPPLineMap[mPCMapSize - 1].pc;
01120 }
01121 
01122 NS_IMETHODIMP
01123 jsdScript::GetJSDContext(JSDContext **_rval)
01124 {
01125     ASSERT_VALID_EPHEMERAL;
01126     *_rval = mCx;
01127     return NS_OK;
01128 }
01129 
01130 NS_IMETHODIMP
01131 jsdScript::GetJSDScript(JSDScript **_rval)
01132 {
01133     ASSERT_VALID_EPHEMERAL;
01134     *_rval = mScript;
01135     return NS_OK;
01136 }
01137 
01138 NS_IMETHODIMP
01139 jsdScript::GetVersion (PRInt32 *_rval)
01140 {
01141     ASSERT_VALID_EPHEMERAL;
01142     JSContext *cx = JSD_GetDefaultJSContext (mCx);
01143     JSScript *script = JSD_GetJSScript(mCx, mScript);
01144     *_rval = NS_STATIC_CAST (PRInt32, JS_GetScriptVersion(cx, script));
01145     return NS_OK;
01146 }
01147 
01148 NS_IMETHODIMP
01149 jsdScript::GetTag(PRUint32 *_rval)
01150 {
01151     if (!mTag)
01152         mTag = ++jsdScript::LastTag;
01153     
01154     *_rval = mTag;
01155     return NS_OK;
01156 }
01157 
01158 NS_IMETHODIMP
01159 jsdScript::Invalidate()
01160 {
01161     ASSERT_VALID_EPHEMERAL;
01162     mValid = PR_FALSE;
01163     
01164     /* release the addref we do in FromPtr */
01165     jsdIScript *script = NS_STATIC_CAST(jsdIScript *,
01166                                         JSD_GetScriptPrivate(mScript));
01167     NS_ASSERTION (script == this, "That's not my script!");
01168     NS_RELEASE(script);
01169     JSD_SetScriptPrivate(mScript, NULL);
01170     return NS_OK;
01171 }
01172 
01173 void
01174 jsdScript::InvalidateAll ()
01175 {
01176     JSDContext *cx;
01177     gJsds->GetJSDContext (&cx);
01178     JSDScript *script;
01179     JSDScript *iter = NULL;
01180     
01181     JSD_LockScriptSubsystem(cx);
01182     while((script = JSD_IterateScripts(cx, &iter)) != NULL) {
01183         nsCOMPtr<jsdIScript> jsdis = 
01184             NS_STATIC_CAST(jsdIScript *, JSD_GetScriptPrivate(script));
01185         if (jsdis)
01186             jsdis->Invalidate();
01187     }
01188     JSD_UnlockScriptSubsystem(cx);
01189 }
01190 
01191 NS_IMETHODIMP
01192 jsdScript::GetIsValid(PRBool *_rval)
01193 {
01194     *_rval = mValid;
01195     return NS_OK;
01196 }
01197 
01198 NS_IMETHODIMP
01199 jsdScript::SetFlags(PRUint32 flags)
01200 {
01201     ASSERT_VALID_EPHEMERAL;
01202     JSD_SetScriptFlags(mCx, mScript, flags);
01203     return NS_OK;
01204 }
01205 
01206 NS_IMETHODIMP
01207 jsdScript::GetFlags(PRUint32 *_rval)
01208 {
01209     ASSERT_VALID_EPHEMERAL;
01210     *_rval = JSD_GetScriptFlags(mCx, mScript);
01211     return NS_OK;
01212 }
01213 
01214 NS_IMETHODIMP
01215 jsdScript::GetFileName(char **_rval)
01216 {
01217     *_rval = ToNewCString(*mFileName);
01218     if (!*_rval)
01219         return NS_ERROR_OUT_OF_MEMORY;
01220     return NS_OK;
01221 }
01222 
01223 NS_IMETHODIMP
01224 jsdScript::GetFunctionName(char **_rval)
01225 {
01226     *_rval = ToNewCString(*mFunctionName);
01227     if (!*_rval)
01228         return NS_ERROR_OUT_OF_MEMORY;
01229     return NS_OK;
01230 }
01231 
01232 NS_IMETHODIMP
01233 jsdScript::GetFunctionObject(jsdIValue **_rval)
01234 {
01235     JSFunction *fun = JSD_GetJSFunction(mCx, mScript);
01236     if (!fun)
01237         return NS_ERROR_NOT_AVAILABLE;
01238     
01239     JSObject *obj = JS_GetFunctionObject(fun);
01240     if (!obj)
01241         return NS_ERROR_FAILURE;
01242 
01243     JSDContext *cx;
01244     gJsds->GetJSDContext (&cx);
01245 
01246     JSDValue *jsdv = JSD_NewValue(cx, OBJECT_TO_JSVAL(obj));
01247     if (!jsdv)
01248         return NS_ERROR_FAILURE;
01249 
01250     *_rval = jsdValue::FromPtr(cx, jsdv);
01251     if (!*_rval) {
01252         JSD_DropValue(cx, jsdv);
01253         return NS_ERROR_FAILURE;
01254     }
01255 
01256     return NS_OK;
01257 }
01258 
01259 NS_IMETHODIMP
01260 jsdScript::GetFunctionSource(nsAString & aFunctionSource)
01261 {
01262     ASSERT_VALID_EPHEMERAL;
01263     JSContext *cx = JSD_GetDefaultJSContext (mCx);
01264     if (!cx) {
01265         NS_WARNING("No default context !?");
01266         return NS_ERROR_FAILURE;
01267     }
01268     JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
01269     JSString *jsstr;
01270     if (fun)
01271     {
01272         jsstr = JS_DecompileFunction (cx, fun, 4);
01273     }
01274     else
01275     {
01276         JSScript *script = JSD_GetJSScript (mCx, mScript);
01277         jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
01278     }
01279     if (!jsstr)
01280         return NS_ERROR_FAILURE;
01281     aFunctionSource = NS_REINTERPRET_CAST(PRUnichar*, JS_GetStringChars(jsstr));
01282     return NS_OK;
01283 }
01284 
01285 NS_IMETHODIMP
01286 jsdScript::GetBaseLineNumber(PRUint32 *_rval)
01287 {
01288     *_rval = mBaseLineNumber;
01289     return NS_OK;
01290 }
01291 
01292 NS_IMETHODIMP
01293 jsdScript::GetLineExtent(PRUint32 *_rval)
01294 {
01295     *_rval = mLineExtent;
01296     return NS_OK;
01297 }
01298 
01299 NS_IMETHODIMP
01300 jsdScript::GetCallCount(PRUint32 *_rval)
01301 {
01302     ASSERT_VALID_EPHEMERAL;
01303     *_rval = JSD_GetScriptCallCount (mCx, mScript);
01304     return NS_OK;
01305 }
01306 
01307 NS_IMETHODIMP
01308 jsdScript::GetMaxRecurseDepth(PRUint32 *_rval)
01309 {
01310     ASSERT_VALID_EPHEMERAL;
01311     *_rval = JSD_GetScriptMaxRecurseDepth (mCx, mScript);
01312     return NS_OK;
01313 }
01314 
01315 NS_IMETHODIMP
01316 jsdScript::GetMinExecutionTime(double *_rval)
01317 {
01318     ASSERT_VALID_EPHEMERAL;
01319     *_rval = JSD_GetScriptMinExecutionTime (mCx, mScript);
01320     return NS_OK;
01321 }
01322 
01323 NS_IMETHODIMP
01324 jsdScript::GetMaxExecutionTime(double *_rval)
01325 {
01326     ASSERT_VALID_EPHEMERAL;
01327     *_rval = JSD_GetScriptMaxExecutionTime (mCx, mScript);
01328     return NS_OK;
01329 }
01330 
01331 NS_IMETHODIMP
01332 jsdScript::GetTotalExecutionTime(double *_rval)
01333 {
01334     ASSERT_VALID_EPHEMERAL;
01335     *_rval = JSD_GetScriptTotalExecutionTime (mCx, mScript);
01336     return NS_OK;
01337 }
01338 
01339 NS_IMETHODIMP
01340 jsdScript::GetMinOwnExecutionTime(double *_rval)
01341 {
01342     ASSERT_VALID_EPHEMERAL;
01343     *_rval = JSD_GetScriptMinOwnExecutionTime (mCx, mScript);
01344     return NS_OK;
01345 }
01346 
01347 NS_IMETHODIMP
01348 jsdScript::GetMaxOwnExecutionTime(double *_rval)
01349 {
01350     ASSERT_VALID_EPHEMERAL;
01351     *_rval = JSD_GetScriptMaxOwnExecutionTime (mCx, mScript);
01352     return NS_OK;
01353 }
01354 
01355 NS_IMETHODIMP
01356 jsdScript::GetTotalOwnExecutionTime(double *_rval)
01357 {
01358     ASSERT_VALID_EPHEMERAL;
01359     *_rval = JSD_GetScriptTotalOwnExecutionTime (mCx, mScript);
01360     return NS_OK;
01361 }
01362 
01363 NS_IMETHODIMP
01364 jsdScript::ClearProfileData()
01365 {
01366     ASSERT_VALID_EPHEMERAL;
01367     JSD_ClearScriptProfileData(mCx, mScript);
01368     return NS_OK;
01369 }
01370 
01371 NS_IMETHODIMP
01372 jsdScript::PcToLine(PRUint32 aPC, PRUint32 aPcmap, PRUint32 *_rval)
01373 {
01374     ASSERT_VALID_EPHEMERAL;
01375     if (aPcmap == PCMAP_SOURCETEXT) {
01376         *_rval = JSD_GetClosestLine (mCx, mScript, mFirstPC + aPC);
01377     } else if (aPcmap == PCMAP_PRETTYPRINT) {
01378         *_rval = PPPcToLine(aPC);
01379     } else {
01380         return NS_ERROR_INVALID_ARG;
01381     }
01382     
01383     return NS_OK;
01384 }
01385 
01386 NS_IMETHODIMP
01387 jsdScript::LineToPc(PRUint32 aLine, PRUint32 aPcmap, PRUint32 *_rval)
01388 {
01389     ASSERT_VALID_EPHEMERAL;
01390     if (aPcmap == PCMAP_SOURCETEXT) {
01391         jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
01392         *_rval = pc - mFirstPC;
01393     } else if (aPcmap == PCMAP_PRETTYPRINT) {
01394         *_rval = PPLineToPc(aLine);
01395     } else {
01396         return NS_ERROR_INVALID_ARG;
01397     }
01398 
01399     return NS_OK;
01400 }
01401 
01402 NS_IMETHODIMP
01403 jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval)
01404 {
01405     ASSERT_VALID_EPHEMERAL;
01406     if (aPcmap == PCMAP_SOURCETEXT) {    
01407         jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
01408         *_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc));
01409     } else if (aPcmap == PCMAP_PRETTYPRINT) {
01410         if (!mPPLineMap && !CreatePPLineMap())
01411             return NS_ERROR_FAILURE;
01412         *_rval = PR_FALSE;
01413         for (PRUint32 i = 0; i < mPCMapSize; ++i) {
01414             if (mPPLineMap[i].line >= aLine) {
01415                 *_rval = (mPPLineMap[i].line == aLine);
01416                 break;
01417             }
01418         }
01419     } else {
01420         return NS_ERROR_INVALID_ARG;
01421     }
01422     
01423     return NS_OK;
01424 }
01425 
01426 NS_IMETHODIMP
01427 jsdScript::SetBreakpoint(PRUint32 aPC)
01428 {
01429     ASSERT_VALID_EPHEMERAL;
01430     jsuword pc = mFirstPC + aPC;
01431     JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc,
01432                           NS_REINTERPRET_CAST(void *, PRIVATE_TO_JSVAL(NULL)));
01433     return NS_OK;
01434 }
01435 
01436 NS_IMETHODIMP
01437 jsdScript::ClearBreakpoint(PRUint32 aPC)
01438 {
01439     ASSERT_VALID_EPHEMERAL;    
01440     jsuword pc = mFirstPC + aPC;
01441     JSD_ClearExecutionHook (mCx, mScript, pc);
01442     return NS_OK;
01443 }
01444 
01445 NS_IMETHODIMP
01446 jsdScript::ClearAllBreakpoints()
01447 {
01448     ASSERT_VALID_EPHEMERAL;
01449     JSD_LockScriptSubsystem(mCx);
01450     JSD_ClearAllExecutionHooksForScript (mCx, mScript);
01451     JSD_UnlockScriptSubsystem(mCx);
01452     return NS_OK;
01453 }
01454 
01455 /* Contexts */
01456 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral)
01457 
01458 jsdIContext *
01459 jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx)
01460 {
01461     if (!aJSDCx || !aJSCx ||
01462         !(JS_GetOptions(aJSCx) & JSOPTION_PRIVATE_IS_NSISUPPORTS))
01463     {
01464         return nsnull;
01465     }
01466     
01467     nsCOMPtr<jsdIContext> jsdicx;
01468     nsCOMPtr<jsdIEphemeral> eph = 
01469         jsds_FindEphemeral (&gLiveContexts, NS_STATIC_CAST(void *, aJSCx));
01470     if (eph)
01471     {
01472         jsdicx = do_QueryInterface(eph);
01473     }
01474     else
01475     {
01476         nsCOMPtr<nsISupports> iscx = 
01477             NS_STATIC_CAST(nsISupports *, JS_GetContextPrivate(aJSCx));
01478         if (!iscx)
01479             return nsnull;
01480         
01481         jsdicx = new jsdContext (aJSDCx, aJSCx, iscx);
01482     }
01483 
01484     jsdIContext *rv = jsdicx;
01485     NS_IF_ADDREF(rv);
01486     return rv;
01487 }
01488 
01489 jsdContext::jsdContext (JSDContext *aJSDCx, JSContext *aJSCx,
01490                         nsISupports *aISCx) : mValid(PR_TRUE), mTag(0),
01491                                               mJSDCx(aJSDCx),
01492                                               mJSCx(aJSCx), mISCx(aISCx)
01493 {
01494     DEBUG_CREATE ("jsdContext", gContextCount);
01495     mLiveListEntry.value = this;
01496     mLiveListEntry.key   = NS_STATIC_CAST (void *, aJSCx);
01497     jsds_InsertEphemeral (&gLiveContexts, &mLiveListEntry);
01498 }
01499 
01500 jsdContext::~jsdContext() 
01501 {
01502     DEBUG_DESTROY ("jsdContext", gContextCount);
01503     if (mValid)
01504     {
01505         /* call Invalidate() to take ourselves out of the live list */
01506         Invalidate();
01507     }
01508 }
01509 
01510 NS_IMETHODIMP
01511 jsdContext::GetIsValid(PRBool *_rval)
01512 {
01513     *_rval = mValid;
01514     return NS_OK;
01515 }
01516 
01517 NS_IMETHODIMP
01518 jsdContext::Invalidate()
01519 {
01520     ASSERT_VALID_EPHEMERAL;
01521     mValid = PR_FALSE;
01522     jsds_RemoveEphemeral (&gLiveContexts, &mLiveListEntry);
01523     return NS_OK;
01524 }
01525 
01526 void
01527 jsdContext::InvalidateAll()
01528 {
01529     if (gLiveContexts)
01530         jsds_InvalidateAllEphemerals (&gLiveContexts);
01531 }
01532 
01533 NS_IMETHODIMP
01534 jsdContext::GetJSContext(JSContext **_rval)
01535 {
01536     ASSERT_VALID_EPHEMERAL;
01537     *_rval = mJSCx;
01538     return NS_OK;
01539 }
01540 
01541 NS_IMETHODIMP
01542 jsdContext::GetOptions(PRUint32 *_rval)
01543 {
01544     ASSERT_VALID_EPHEMERAL;
01545     *_rval = JS_GetOptions(mJSCx);
01546     return NS_OK;
01547 }
01548 
01549 NS_IMETHODIMP
01550 jsdContext::SetOptions(PRUint32 options)
01551 {
01552     ASSERT_VALID_EPHEMERAL;
01553     PRUint32 lastOptions = JS_GetOptions(mJSCx);
01554 
01555     /* don't let users change this option, they'd just be shooting themselves
01556      * in the foot. */
01557     if ((options ^ lastOptions) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
01558         return NS_ERROR_ILLEGAL_VALUE;
01559 
01560     JS_SetOptions(mJSCx, options);
01561     return NS_OK;
01562 }
01563 
01564 NS_IMETHODIMP
01565 jsdContext::GetPrivateData(nsISupports **_rval)
01566 {
01567     ASSERT_VALID_EPHEMERAL;
01568     PRUint32 options = JS_GetOptions(mJSCx);
01569     if (options & JSOPTION_PRIVATE_IS_NSISUPPORTS)
01570     {
01571         *_rval = NS_STATIC_CAST(nsISupports*, JS_GetContextPrivate(mJSCx));
01572         NS_IF_ADDREF(*_rval);
01573     }
01574     else
01575     {
01576         *_rval = nsnull;
01577     }
01578     
01579     return NS_OK;
01580 }
01581         
01582 NS_IMETHODIMP
01583 jsdContext::GetWrappedContext(nsISupports **_rval)
01584 {
01585     ASSERT_VALID_EPHEMERAL;
01586     *_rval = mISCx;
01587     NS_IF_ADDREF(*_rval);
01588     return NS_OK;
01589 }
01590 
01591 NS_IMETHODIMP
01592 jsdContext::GetTag(PRUint32 *_rval)
01593 {
01594     ASSERT_VALID_EPHEMERAL;
01595     if (!mTag)
01596         mTag = ++jsdContext::LastTag;
01597     
01598     *_rval = mTag;
01599     return NS_OK;
01600 }
01601 
01602 NS_IMETHODIMP
01603 jsdContext::GetVersion (PRInt32 *_rval)
01604 {
01605     ASSERT_VALID_EPHEMERAL;
01606     *_rval = NS_STATIC_CAST (PRInt32, JS_GetVersion(mJSCx));
01607     return NS_OK;
01608 }
01609 
01610 NS_IMETHODIMP
01611 jsdContext::SetVersion (PRInt32 id)
01612 {
01613     ASSERT_VALID_EPHEMERAL;
01614     JSVersion ver = NS_STATIC_CAST (JSVersion, id);
01615     JS_SetVersion(mJSCx, ver);
01616     return NS_OK;
01617 }
01618 
01619 NS_IMETHODIMP
01620 jsdContext::GetGlobalObject (jsdIValue **_rval)
01621 {
01622     ASSERT_VALID_EPHEMERAL;
01623     JSObject *glob = JS_GetGlobalObject(mJSCx);
01624     JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
01625     if (!jsdv)
01626         return NS_ERROR_FAILURE;
01627     *_rval = jsdValue::FromPtr (mJSDCx, jsdv);
01628     if (!*_rval)
01629         return NS_ERROR_FAILURE;
01630     return NS_OK;
01631 }
01632 
01633 NS_IMETHODIMP
01634 jsdContext::GetScriptsEnabled (PRBool *_rval)
01635 {
01636     ASSERT_VALID_EPHEMERAL;
01637     nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
01638     if (!context)
01639         return NS_ERROR_NO_INTERFACE;
01640 
01641     *_rval = context->GetScriptsEnabled();
01642 
01643     return NS_OK;
01644 }
01645 
01646 NS_IMETHODIMP
01647 jsdContext::SetScriptsEnabled (PRBool _rval)
01648 {
01649     ASSERT_VALID_EPHEMERAL;
01650     nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
01651     if (!context)
01652         return NS_ERROR_NO_INTERFACE;
01653 
01654     context->SetScriptsEnabled(_rval, PR_TRUE);
01655 
01656     return NS_OK;
01657 }
01658 
01659 /* Stack Frames */
01660 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame, jsdIStackFrame, jsdIEphemeral)
01661 
01662 jsdStackFrame::jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState,
01663                               JSDStackFrameInfo *aStackFrameInfo) :
01664     mCx(aCx), mThreadState(aThreadState), mStackFrameInfo(aStackFrameInfo)
01665 {
01666     DEBUG_CREATE ("jsdStackFrame", gFrameCount);
01667     mValid = (aCx && aThreadState && aStackFrameInfo);
01668     if (mValid) {
01669         mLiveListEntry.key = aStackFrameInfo;
01670         mLiveListEntry.value = this;
01671         jsds_InsertEphemeral (&gLiveStackFrames, &mLiveListEntry);
01672     }
01673 }
01674 
01675 jsdStackFrame::~jsdStackFrame() 
01676 {
01677     DEBUG_DESTROY ("jsdStackFrame", gFrameCount);
01678     if (mValid)
01679     {
01680         /* call Invalidate() to take ourselves out of the live list */
01681         Invalidate();
01682     }
01683 }
01684 
01685 jsdIStackFrame *
01686 jsdStackFrame::FromPtr (JSDContext *aCx, JSDThreadState *aThreadState,
01687                         JSDStackFrameInfo *aStackFrameInfo)
01688 {
01689     if (!aStackFrameInfo)
01690         return nsnull;
01691 
01692     jsdIStackFrame *rv;
01693     nsCOMPtr<jsdIStackFrame> frame;
01694 
01695     nsCOMPtr<jsdIEphemeral> eph =
01696         jsds_FindEphemeral (&gLiveStackFrames,
01697                             NS_REINTERPRET_CAST(void *, aStackFrameInfo));
01698 
01699     if (eph)
01700     {
01701         frame = do_QueryInterface(eph);
01702         rv = frame;
01703     }
01704     else
01705     {
01706         rv = new jsdStackFrame (aCx, aThreadState, aStackFrameInfo);
01707     }
01708 
01709     NS_IF_ADDREF(rv);
01710     return rv;
01711 }
01712 
01713 NS_IMETHODIMP
01714 jsdStackFrame::Invalidate()
01715 {
01716     ASSERT_VALID_EPHEMERAL;
01717     mValid = PR_FALSE;
01718     jsds_RemoveEphemeral (&gLiveStackFrames, &mLiveListEntry);
01719     return NS_OK;
01720 }
01721 
01722 void
01723 jsdStackFrame::InvalidateAll()
01724 {
01725     if (gLiveStackFrames)
01726         jsds_InvalidateAllEphemerals (&gLiveStackFrames);
01727 }
01728 
01729 NS_IMETHODIMP
01730 jsdStackFrame::GetJSDContext(JSDContext **_rval)
01731 {
01732     ASSERT_VALID_EPHEMERAL;
01733     *_rval = mCx;
01734     return NS_OK;
01735 }
01736 
01737 NS_IMETHODIMP
01738 jsdStackFrame::GetJSDThreadState(JSDThreadState **_rval)
01739 {
01740     ASSERT_VALID_EPHEMERAL;
01741     *_rval = mThreadState;
01742     return NS_OK;
01743 }
01744 
01745 NS_IMETHODIMP
01746 jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo **_rval)
01747 {
01748     ASSERT_VALID_EPHEMERAL;
01749     *_rval = mStackFrameInfo;
01750     return NS_OK;
01751 }
01752 
01753 NS_IMETHODIMP
01754 jsdStackFrame::GetIsValid(PRBool *_rval)
01755 {
01756     *_rval = mValid;
01757     return NS_OK;
01758 }
01759 
01760 NS_IMETHODIMP
01761 jsdStackFrame::GetCallingFrame(jsdIStackFrame **_rval)
01762 {
01763     ASSERT_VALID_EPHEMERAL;
01764     JSDStackFrameInfo *sfi = JSD_GetCallingStackFrame (mCx, mThreadState,
01765                                                        mStackFrameInfo);
01766     *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
01767     return NS_OK;
01768 }
01769 
01770 NS_IMETHODIMP
01771 jsdStackFrame::GetExecutionContext(jsdIContext **_rval)
01772 {
01773     ASSERT_VALID_EPHEMERAL;
01774     JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
01775     *_rval = jsdContext::FromPtr (mCx, cx);
01776     return NS_OK;
01777 }
01778 
01779 NS_IMETHODIMP
01780 jsdStackFrame::GetFunctionName(char **_rval)
01781 {
01782     ASSERT_VALID_EPHEMERAL;
01783     const char *name = JSD_GetNameForStackFrame(mCx, mThreadState,
01784                                                 mStackFrameInfo);
01785     if (name) {
01786         *_rval = PL_strdup(name);
01787         if (!*_rval)
01788             return NS_ERROR_OUT_OF_MEMORY;
01789     } else {
01790         /* top level scripts have no function name */
01791         *_rval = nsnull;
01792         return NS_OK;
01793     }
01794     return NS_OK;
01795 }
01796 
01797 NS_IMETHODIMP
01798 jsdStackFrame::GetIsNative(PRBool *_rval)
01799 {
01800     ASSERT_VALID_EPHEMERAL;
01801     *_rval = JSD_IsStackFrameNative (mCx, mThreadState, mStackFrameInfo);
01802     return NS_OK;
01803 }
01804 
01805 NS_IMETHODIMP
01806 jsdStackFrame::GetIsDebugger(PRBool *_rval)
01807 {
01808     ASSERT_VALID_EPHEMERAL;
01809     *_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo);
01810     return NS_OK;
01811 }
01812 
01813 NS_IMETHODIMP
01814 jsdStackFrame::GetIsConstructing(PRBool *_rval)
01815 {
01816     ASSERT_VALID_EPHEMERAL;
01817     *_rval = JSD_IsStackFrameConstructing (mCx, mThreadState, mStackFrameInfo);
01818     return NS_OK;
01819 }
01820 
01821 NS_IMETHODIMP
01822 jsdStackFrame::GetScript(jsdIScript **_rval)
01823 {
01824     ASSERT_VALID_EPHEMERAL;
01825     JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
01826                                                     mStackFrameInfo);
01827     *_rval = jsdScript::FromPtr (mCx, script);
01828     return NS_OK;
01829 }
01830 
01831 NS_IMETHODIMP
01832 jsdStackFrame::GetPc(PRUint32 *_rval)
01833 {
01834     ASSERT_VALID_EPHEMERAL;
01835     JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
01836                                                     mStackFrameInfo);
01837     if (!script)
01838         return NS_ERROR_FAILURE;
01839     jsuword pcbase = JSD_GetClosestPC(mCx, script, 0);
01840     
01841     jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
01842     if (pc)
01843         *_rval = pc - pcbase;
01844     else
01845         *_rval = pcbase;
01846     return NS_OK;
01847 }
01848 
01849 NS_IMETHODIMP
01850 jsdStackFrame::GetLine(PRUint32 *_rval)
01851 {
01852     ASSERT_VALID_EPHEMERAL;
01853     JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
01854                                                     mStackFrameInfo);
01855     if (script) {
01856         jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
01857         *_rval = JSD_GetClosestLine (mCx, script, pc);
01858     } else {
01859         if (!JSD_IsStackFrameNative(mCx, mThreadState, mStackFrameInfo))
01860             return NS_ERROR_FAILURE;
01861         *_rval = 1;
01862     }
01863     return NS_OK;
01864 }
01865 
01866 NS_IMETHODIMP
01867 jsdStackFrame::GetCallee(jsdIValue **_rval)
01868 {
01869     ASSERT_VALID_EPHEMERAL;
01870     JSDValue *jsdv = JSD_GetCallObjectForStackFrame (mCx, mThreadState,
01871                                                      mStackFrameInfo);
01872     
01873     *_rval = jsdValue::FromPtr (mCx, jsdv);
01874     return NS_OK;
01875 }
01876 
01877 NS_IMETHODIMP
01878 jsdStackFrame::GetScope(jsdIValue **_rval)
01879 {
01880     ASSERT_VALID_EPHEMERAL;
01881     JSDValue *jsdv = JSD_GetScopeChainForStackFrame (mCx, mThreadState,
01882                                                      mStackFrameInfo);
01883     
01884     *_rval = jsdValue::FromPtr (mCx, jsdv);
01885     return NS_OK;
01886 }
01887 
01888 NS_IMETHODIMP
01889 jsdStackFrame::GetThisValue(jsdIValue **_rval)
01890 {
01891     ASSERT_VALID_EPHEMERAL;
01892     JSDValue *jsdv = JSD_GetThisForStackFrame (mCx, mThreadState,
01893                                                mStackFrameInfo);
01894     
01895     *_rval = jsdValue::FromPtr (mCx, jsdv);
01896     return NS_OK;
01897 }
01898 
01899 
01900 NS_IMETHODIMP
01901 jsdStackFrame::Eval (const nsAString &bytes, const char *fileName,
01902                      PRUint32 line, jsdIValue **result, PRBool *_rval)
01903 {
01904     ASSERT_VALID_EPHEMERAL;
01905 
01906     if (bytes.IsEmpty())
01907         return NS_ERROR_INVALID_ARG;
01908 
01909     // get pointer to buffer contained in |bytes|
01910     nsAString::const_iterator h;
01911     bytes.BeginReading(h);
01912     const jschar *char_bytes = NS_REINTERPRET_CAST(const jschar *, h.get());
01913 
01914     JSExceptionState *estate = 0;
01915     jsval jv;
01916 
01917     JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
01918     estate = JS_SaveExceptionState (cx);
01919     JS_ClearPendingException (cx);
01920 
01921     *_rval = JSD_AttemptUCScriptInStackFrame (mCx, mThreadState,
01922                                               mStackFrameInfo,
01923                                               char_bytes, bytes.Length(),
01924                                               fileName, line, &jv);
01925     if (!*_rval) {
01926         if (JS_IsExceptionPending(cx))
01927             JS_GetPendingException (cx, &jv);
01928         else
01929             jv = 0;
01930     }
01931 
01932     JS_RestoreExceptionState (cx, estate);
01933     JSDValue *jsdv = JSD_NewValue (mCx, jv);
01934     if (!jsdv)
01935         return NS_ERROR_FAILURE;
01936     *result = jsdValue::FromPtr (mCx, jsdv);
01937     if (!*result)
01938         return NS_ERROR_FAILURE;
01939     
01940     return NS_OK;
01941 }        
01942 
01943 /* Values */
01944 NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue, jsdIValue, jsdIEphemeral)
01945 jsdIValue *
01946 jsdValue::FromPtr (JSDContext *aCx, JSDValue *aValue)
01947 {
01948     /* value will be dropped by te jsdValue destructor. */
01949 
01950     if (!aValue)
01951         return nsnull;
01952     
01953     jsdIValue *rv = new jsdValue (aCx, aValue);
01954     NS_IF_ADDREF(rv);
01955     return rv;
01956 }
01957 
01958 jsdValue::jsdValue (JSDContext *aCx, JSDValue *aValue) : mValid(PR_TRUE),
01959                                                          mCx(aCx), 
01960                                                          mValue(aValue)
01961 {
01962     DEBUG_CREATE ("jsdValue", gValueCount);
01963     mLiveListEntry.value = this;
01964     jsds_InsertEphemeral (&gLiveValues, &mLiveListEntry);
01965 }
01966 
01967 jsdValue::~jsdValue() 
01968 {
01969     DEBUG_DESTROY ("jsdValue", gValueCount);
01970     if (mValid)
01971         /* call Invalidate() to take ourselves out of the live list */
01972         Invalidate();
01973 }   
01974 
01975 NS_IMETHODIMP
01976 jsdValue::GetIsValid(PRBool *_rval)
01977 {
01978     *_rval = mValid;
01979     return NS_OK;
01980 }
01981 
01982 NS_IMETHODIMP
01983 jsdValue::Invalidate()
01984 {
01985     ASSERT_VALID_EPHEMERAL;
01986     mValid = PR_FALSE;
01987     jsds_RemoveEphemeral (&gLiveValues, &mLiveListEntry);
01988     JSD_DropValue (mCx, mValue);
01989     return NS_OK;
01990 }
01991 
01992 void
01993 jsdValue::InvalidateAll()
01994 {
01995     if (gLiveValues)
01996         jsds_InvalidateAllEphemerals (&gLiveValues);
01997 }
01998 
01999 NS_IMETHODIMP
02000 jsdValue::GetJSDContext(JSDContext **_rval)
02001 {
02002     ASSERT_VALID_EPHEMERAL;
02003     *_rval = mCx;
02004     return NS_OK;
02005 }
02006 
02007 NS_IMETHODIMP
02008 jsdValue::GetJSDValue (JSDValue **_rval)
02009 {
02010     ASSERT_VALID_EPHEMERAL;
02011     *_rval = mValue;
02012     return NS_OK;
02013 }
02014 
02015 NS_IMETHODIMP
02016 jsdValue::GetIsNative (PRBool *_rval)
02017 {
02018     ASSERT_VALID_EPHEMERAL;
02019     *_rval = JSD_IsValueNative (mCx, mValue);
02020     return NS_OK;
02021 }
02022 
02023 NS_IMETHODIMP
02024 jsdValue::GetIsNumber (PRBool *_rval)
02025 {
02026     ASSERT_VALID_EPHEMERAL;
02027     *_rval = JSD_IsValueNumber (mCx, mValue);
02028     return NS_OK;
02029 }
02030 
02031 NS_IMETHODIMP
02032 jsdValue::GetIsPrimitive (PRBool *_rval)
02033 {
02034     ASSERT_VALID_EPHEMERAL;
02035     *_rval = JSD_IsValuePrimitive (mCx, mValue);
02036     return NS_OK;
02037 }
02038 
02039 NS_IMETHODIMP
02040 jsdValue::GetJsType (PRUint32 *_rval)
02041 {
02042     ASSERT_VALID_EPHEMERAL;
02043     jsval val;
02044 
02045     val = JSD_GetValueWrappedJSVal (mCx, mValue);
02046     
02047     if (JSVAL_IS_NULL(val))
02048         *_rval = TYPE_NULL;
02049     else if (JSVAL_IS_BOOLEAN(val))
02050         *_rval = TYPE_BOOLEAN;
02051     else if (JSVAL_IS_DOUBLE(val))
02052         *_rval = TYPE_DOUBLE;
02053     else if (JSVAL_IS_INT(val))
02054         *_rval = TYPE_INT;
02055     else if (JSVAL_IS_STRING(val))
02056         *_rval = TYPE_STRING;
02057     else if (JSVAL_IS_VOID(val))
02058         *_rval = TYPE_VOID;
02059     else if (JSD_IsValueFunction (mCx, mValue))
02060         *_rval = TYPE_FUNCTION;
02061     else if (JSVAL_IS_OBJECT(val))
02062         *_rval = TYPE_OBJECT;
02063     else
02064         NS_ASSERTION (0, "Value has no discernible type.");
02065 
02066     return NS_OK;
02067 }
02068 
02069 NS_IMETHODIMP
02070 jsdValue::GetJsPrototype (jsdIValue **_rval)
02071 {
02072     ASSERT_VALID_EPHEMERAL;
02073     JSDValue *jsdv = JSD_GetValuePrototype (mCx, mValue);
02074     *_rval = jsdValue::FromPtr (mCx, jsdv);
02075     return NS_OK;
02076 }
02077 
02078 NS_IMETHODIMP
02079 jsdValue::GetJsParent (jsdIValue **_rval)
02080 {
02081     ASSERT_VALID_EPHEMERAL;
02082     JSDValue *jsdv = JSD_GetValueParent (mCx, mValue);
02083     *_rval = jsdValue::FromPtr (mCx, jsdv);
02084     return NS_OK;
02085 }
02086 
02087 NS_IMETHODIMP
02088 jsdValue::GetJsClassName(char **_rval)
02089 {
02090     ASSERT_VALID_EPHEMERAL;
02091     const char *name = JSD_GetValueClassName(mCx, mValue);
02092     if (name) {
02093         *_rval = PL_strdup(name);
02094         if (!*_rval)
02095             return NS_ERROR_OUT_OF_MEMORY;
02096     } else {
02097         *_rval = nsnull;
02098     }
02099     
02100     return NS_OK;
02101 }
02102 
02103 NS_IMETHODIMP
02104 jsdValue::GetJsConstructor (jsdIValue **_rval)
02105 {
02106     ASSERT_VALID_EPHEMERAL;
02107     JSDValue *jsdv = JSD_GetValueConstructor (mCx, mValue);
02108     *_rval = jsdValue::FromPtr (mCx, jsdv);
02109     return NS_OK;
02110 }
02111 
02112 NS_IMETHODIMP
02113 jsdValue::GetJsFunctionName(char **_rval)
02114 {
02115     ASSERT_VALID_EPHEMERAL;
02116     const char *name = JSD_GetValueFunctionName(mCx, mValue);
02117     if (name) {
02118         *_rval = PL_strdup(name);
02119         if (!*_rval)
02120             return NS_ERROR_OUT_OF_MEMORY;
02121     } else {
02122         /* top level scripts have no function name */
02123         *_rval = nsnull;
02124         return NS_OK;
02125     }
02126 
02127     return NS_OK;
02128 }
02129 
02130 NS_IMETHODIMP
02131 jsdValue::GetBooleanValue(PRBool *_rval)
02132 {
02133     ASSERT_VALID_EPHEMERAL;
02134     *_rval = JSD_GetValueBoolean (mCx, mValue);
02135     return NS_OK;
02136 }
02137 
02138 NS_IMETHODIMP
02139 jsdValue::GetDoubleValue(double *_rval)
02140 {
02141     ASSERT_VALID_EPHEMERAL;
02142     double *dp = JSD_GetValueDouble (mCx, mValue);
02143     if (!dp)
02144         return NS_ERROR_FAILURE;
02145     *_rval = *dp;
02146     return NS_OK;
02147 }
02148 
02149 NS_IMETHODIMP
02150 jsdValue::GetIntValue(PRInt32 *_rval)
02151 {
02152     ASSERT_VALID_EPHEMERAL;
02153     *_rval = JSD_GetValueInt (mCx, mValue);
02154     return NS_OK;
02155 }
02156 
02157 NS_IMETHODIMP
02158 jsdValue::GetObjectValue(jsdIObject **_rval)
02159 {
02160     ASSERT_VALID_EPHEMERAL;
02161     JSDObject *obj;
02162     obj = JSD_GetObjectForValue (mCx, mValue);
02163     *_rval = jsdObject::FromPtr (mCx, obj);
02164     if (!*_rval)
02165         return NS_ERROR_FAILURE;
02166     return NS_OK;
02167 }
02168     
02169 NS_IMETHODIMP
02170 jsdValue::GetStringValue(char **_rval)
02171 {
02172     ASSERT_VALID_EPHEMERAL;
02173     JSString *jstr_val = JSD_GetValueString(mCx, mValue);
02174     if (jstr_val) {
02175         char *bytes = JS_GetStringBytes(jstr_val);
02176         *_rval = PL_strdup(bytes);
02177         if (!*_rval)
02178             return NS_ERROR_OUT_OF_MEMORY;
02179     } else {
02180         *_rval = nsnull;
02181     }
02182     return NS_OK;
02183 }
02184 
02185 NS_IMETHODIMP
02186 jsdValue::GetPropertyCount (PRInt32 *_rval)
02187 {
02188     ASSERT_VALID_EPHEMERAL;
02189     if (JSD_IsValueObject(mCx, mValue))
02190         *_rval = JSD_GetCountOfProperties (mCx, mValue);
02191     else
02192         *_rval = -1;
02193     return NS_OK;
02194 }
02195 
02196 NS_IMETHODIMP
02197 jsdValue::GetProperties (jsdIProperty ***propArray, PRUint32 *length)
02198 {
02199     ASSERT_VALID_EPHEMERAL;
02200     *propArray = nsnull;
02201     if (length)
02202         *length = 0;
02203 
02204     PRUint32 prop_count = JSD_IsValueObject(mCx, mValue)
02205         ? JSD_GetCountOfProperties (mCx, mValue)
02206         : 0;
02207     NS_ENSURE_TRUE(prop_count, NS_OK);
02208 
02209     jsdIProperty **pa_temp =
02210         NS_STATIC_CAST(jsdIProperty **,
02211                        nsMemory::Alloc(sizeof (jsdIProperty *) * 
02212                                        prop_count));
02213     NS_ENSURE_TRUE(pa_temp, NS_ERROR_OUT_OF_MEMORY);
02214 
02215     PRUint32     i    = 0;
02216     JSDProperty *iter = NULL;
02217     JSDProperty *prop;
02218     while ((prop = JSD_IterateProperties (mCx, mValue, &iter))) {
02219         pa_temp[i] = jsdProperty::FromPtr (mCx, prop);
02220         ++i;
02221     }
02222     
02223     NS_ASSERTION (prop_count == i, "property count mismatch");    
02224 
02225     /* if caller doesn't care about length, don't bother telling them */
02226     *propArray = pa_temp;
02227     if (length)
02228         *length = prop_count;
02229     
02230     return NS_OK;
02231 }
02232 
02233 NS_IMETHODIMP
02234 jsdValue::GetProperty (const char *name, jsdIProperty **_rval)
02235 {
02236     ASSERT_VALID_EPHEMERAL;
02237     JSContext *cx = JSD_GetDefaultJSContext (mCx);
02238     /* not rooting this */
02239     JSString *jstr_name = JS_NewStringCopyZ (cx, name);
02240 
02241     JSDProperty *prop = JSD_GetValueProperty (mCx, mValue, jstr_name);
02242     
02243     *_rval = jsdProperty::FromPtr (mCx, prop);
02244     return NS_OK;
02245 }
02246 
02247 NS_IMETHODIMP
02248 jsdValue::Refresh()
02249 {
02250     ASSERT_VALID_EPHEMERAL;
02251     JSD_RefreshValue (mCx, mValue);
02252     return NS_OK;
02253 }
02254 
02255 NS_IMETHODIMP
02256 jsdValue::GetWrappedValue()
02257 {
02258     ASSERT_VALID_EPHEMERAL;
02259     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
02260     if (!xpc)
02261         return NS_ERROR_FAILURE;
02262 
02263     nsresult rv;
02264     nsCOMPtr<nsIXPCNativeCallContext> cc;
02265     rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
02266     if (NS_FAILED(rv))
02267         return rv;
02268 
02269     jsval *result;
02270     rv = cc->GetRetValPtr(&result);
02271     if (NS_FAILED(rv))
02272         return rv;
02273 
02274     if (result)
02275     {
02276         *result = JSD_GetValueWrappedJSVal (mCx, mValue);
02277         cc->SetReturnValueWasSet(PR_TRUE);
02278     }
02279 
02280     return NS_OK;
02281 }
02282 
02283 /******************************************************************************
02284  * debugger service implementation
02285  ******************************************************************************/
02286 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdService, jsdIDebuggerService)
02287 
02288 NS_IMETHODIMP
02289 jsdService::GetJSDContext(JSDContext **_rval)
02290 {
02291     *_rval = mCx;
02292     return NS_OK;
02293 }
02294 
02295 NS_IMETHODIMP
02296 jsdService::GetInitAtStartup (PRBool *_rval)
02297 {
02298     nsresult rv;
02299     nsCOMPtr<nsICategoryManager>
02300         categoryManager(do_GetService(NS_CATMAN_CTRID, &rv));
02301     
02302     if (NS_FAILED(rv))
02303     {
02304         NS_WARNING("couldn't get category manager");
02305         return rv;
02306     }
02307 
02308     if (mInitAtStartup == triUnknown) {
02309         nsXPIDLCString notused;
02310         nsresult autoreg_rv, appstart_rv;
02311         
02312         autoreg_rv = categoryManager->GetCategoryEntry(AUTOREG_CATEGORY, 
02313                                                        JSD_AUTOREG_ENTRY,
02314                                                        getter_Copies(notused));
02315         appstart_rv = categoryManager->GetCategoryEntry(APPSTART_CATEGORY,
02316                                                         JSD_STARTUP_ENTRY,
02317                                                         getter_Copies(notused));
02318         if (autoreg_rv != appstart_rv) {
02319             /* we have an inconsistent state in the registry, attempt to fix.
02320              * we need to make mInitAtStartup disagree with the state passed
02321              * to SetInitAtStartup to make it actually do something.
02322              */
02323             mInitAtStartup = triYes;
02324             rv = SetInitAtStartup (PR_FALSE);
02325             if (NS_FAILED(rv))
02326             {
02327                 NS_WARNING("SetInitAtStartup failed");
02328                 return rv;
02329             }
02330         } else if (autoreg_rv == NS_ERROR_NOT_AVAILABLE) {
02331             mInitAtStartup = triNo;
02332         } else if (NS_SUCCEEDED(autoreg_rv)) {
02333             mInitAtStartup = triYes;
02334         } else {
02335             NS_WARN_IF_FALSE(NS_SUCCEEDED(autoreg_rv),
02336                              "couldn't get autoreg category");
02337             NS_WARN_IF_FALSE(NS_SUCCEEDED(appstart_rv),
02338                              "couldn't get appstart category");
02339             return rv;
02340         }
02341     }
02342     
02343     if (_rval)
02344         *_rval = (mInitAtStartup == triYes);
02345 
02346     return NS_OK;
02347 }
02348 
02349 /*
02350  * The initAtStartup property controls whether or not we register the
02351  * app start observer (jsdASObserver.)  We register for both 
02352  * "xpcom-autoregistration" and "app-startup" notifications if |state| is true.
02353  * the autoreg message is sent just before registration occurs (before
02354  * "app-startup".)  We care about autoreg because it may load javascript
02355  * components.  autoreg does *not* fire if components haven't changed since the
02356  * last autoreg, so we watch "app-startup" as a fallback.
02357  */
02358 NS_IMETHODIMP
02359 jsdService::SetInitAtStartup (PRBool state)
02360 { 
02361     nsresult rv;
02362 
02363     if (mInitAtStartup == triUnknown) {
02364         /* side effect sets mInitAtStartup */
02365         rv = GetInitAtStartup(nsnull);
02366         if (NS_FAILED(rv))
02367             return rv;
02368     }
02369 
02370     if (state && mInitAtStartup == triYes ||
02371         !state && mInitAtStartup == triNo) {
02372         /* already in the requested state */
02373         return NS_OK;
02374     }
02375     
02376     nsCOMPtr<nsICategoryManager>
02377         categoryManager(do_GetService(NS_CATMAN_CTRID, &rv));
02378 
02379     if (state) {
02380         rv = categoryManager->AddCategoryEntry(AUTOREG_CATEGORY,
02381                                                JSD_AUTOREG_ENTRY,
02382                                                jsdASObserverCtrID,
02383                                                PR_TRUE, PR_TRUE, nsnull);
02384         if (NS_FAILED(rv))
02385             return rv;
02386         rv = categoryManager->AddCategoryEntry(APPSTART_CATEGORY,
02387                                                JSD_STARTUP_ENTRY,
02388                                                jsdASObserverCtrID,
02389                                                PR_TRUE, PR_TRUE, nsnull);
02390         if (NS_FAILED(rv))
02391             return rv;
02392         mInitAtStartup = triYes;
02393     } else {
02394         rv = categoryManager->DeleteCategoryEntry(AUTOREG_CATEGORY,
02395                                                   JSD_AUTOREG_ENTRY, PR_TRUE);
02396         if (NS_FAILED(rv))
02397             return rv;
02398         rv = categoryManager->DeleteCategoryEntry(APPSTART_CATEGORY,
02399                                                   JSD_STARTUP_ENTRY, PR_TRUE);
02400         if (NS_FAILED(rv))
02401             return rv;
02402         mInitAtStartup = triNo;
02403     }
02404 
02405     return NS_OK;
02406 }
02407 
02408 NS_IMETHODIMP
02409 jsdService::GetFlags (PRUint32 *_rval)
02410 {
02411     *_rval = JSD_GetContextFlags (mCx);
02412     return NS_OK;
02413 }
02414 
02415 NS_IMETHODIMP
02416 jsdService::SetFlags (PRUint32 flags)
02417 {
02418     JSD_SetContextFlags (mCx, flags);
02419     return NS_OK;
02420 }
02421 
02422 NS_IMETHODIMP
02423 jsdService::GetImplementationString(char **_rval)
02424 {
02425     *_rval = PL_strdup(implementationString);
02426     if (!*_rval)
02427         return NS_ERROR_OUT_OF_MEMORY;
02428     return NS_OK;
02429 }
02430 
02431 NS_IMETHODIMP
02432 jsdService::GetImplementationMajor(PRUint32 *_rval)
02433 {
02434     *_rval = JSDS_MAJOR_VERSION;
02435     return NS_OK;
02436 }
02437 
02438 NS_IMETHODIMP
02439 jsdService::GetImplementationMinor(PRUint32 *_rval)
02440 {
02441     *_rval = JSDS_MINOR_VERSION;
02442     return NS_OK;
02443 }
02444 
02445 NS_IMETHODIMP
02446 jsdService::GetIsOn (PRBool *_rval)
02447 {
02448     *_rval = mOn;
02449     return NS_OK;
02450 }
02451 
02452 NS_IMETHODIMP
02453 jsdService::On (void)
02454 {
02455     nsresult  rv;
02456 
02457     /* get JS things from the CallContext */
02458     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
02459     if (!xpc) return NS_ERROR_FAILURE;
02460 
02461     nsCOMPtr<nsIXPCNativeCallContext> cc;
02462     rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
02463     if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02464 
02465     JSContext *cx;
02466     rv = cc->GetJSContext (&cx);
02467     if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02468     
02469     return OnForRuntime(JS_GetRuntime (cx));
02470     
02471 }
02472 
02473 NS_IMETHODIMP
02474 jsdService::OnForRuntime (JSRuntime *rt)
02475 {
02476     if (mOn)
02477         return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED;
02478 
02479     mRuntime = rt;
02480 
02481     if (gLastGCProc == jsds_GCCallbackProc)
02482         /* condition indicates that the callback proc has not been set yet */
02483         gLastGCProc = JS_SetGCCallbackRT (rt, jsds_GCCallbackProc);
02484 
02485     mCx = JSD_DebuggerOnForUser (rt, NULL, NULL);
02486     if (!mCx)
02487         return NS_ERROR_FAILURE;
02488 
02489     JSContext *cx   = JSD_GetDefaultJSContext (mCx);
02490     JSObject  *glob = JS_GetGlobalObject (cx);
02491 
02492     /* init xpconnect on the debugger's context in case xpconnect tries to
02493      * use it for stuff. */
02494     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
02495     if (!xpc)
02496         return NS_ERROR_FAILURE;
02497     
02498     xpc->InitClasses (cx, glob);
02499     
02500     /* If any of these mFooHook objects are installed, do the required JSD
02501      * hookup now.   See also, jsdService::SetFooHook().
02502      */
02503     if (mErrorHook)
02504         JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
02505     if (mThrowHook)
02506         JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
02507     /* can't ignore script callbacks, as we need to |Release| the wrapper 
02508      * stored in private data when a script is deleted. */
02509     if (mInterruptHook)
02510         JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
02511     if (mDebuggerHook)
02512         JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
02513     if (mDebugHook)
02514         JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
02515     if (mTopLevelHook)
02516         JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
02517     else
02518         JSD_ClearTopLevelHook (mCx);
02519     if (mFunctionHook)
02520         JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
02521     else
02522         JSD_ClearFunctionHook (mCx);
02523     mOn = PR_TRUE;
02524 
02525 #ifdef DEBUG
02526     printf ("+++ JavaScript debugging hooks installed.\n");
02527 #endif
02528     return NS_OK;
02529 }
02530 
02531 NS_IMETHODIMP
02532 jsdService::Off (void)
02533 {
02534     if (!mOn)
02535         return NS_OK;
02536     
02537     if (!mCx || !mRuntime)
02538         return NS_ERROR_NOT_INITIALIZED;
02539     
02540     if (gDeadScripts) {
02541         if (gGCStatus == JSGC_END)
02542         {
02543             JSContext *cx = JSD_GetDefaultJSContext(mCx);
02544             jsds_NotifyPendingDeadScripts(cx);
02545         }
02546         else
02547             return NS_ERROR_NOT_AVAILABLE;
02548     }
02549 
02550     /*
02551     if (gLastGCProc != jsds_GCCallbackProc)
02552         JS_SetGCCallbackRT (mRuntime, gLastGCProc);
02553     */
02554 
02555     jsdContext::InvalidateAll();
02556     jsdScript::InvalidateAll();
02557     jsdValue::InvalidateAll();
02558     jsdProperty::InvalidateAll();
02559     ClearAllBreakpoints();
02560 
02561     JSD_SetErrorReporter (mCx, NULL, NULL);
02562     JSD_ClearThrowHook (mCx);
02563     JSD_ClearInterruptHook (mCx);
02564     JSD_ClearDebuggerHook (mCx);
02565     JSD_ClearDebugBreakHook (mCx);
02566     JSD_ClearTopLevelHook (mCx);
02567     JSD_ClearFunctionHook (mCx);
02568     
02569     JSD_DebuggerOff (mCx);
02570 
02571     mCx = nsnull;
02572     mRuntime = nsnull;
02573     mOn = PR_FALSE;
02574 
02575 #ifdef DEBUG
02576     printf ("+++ JavaScript debugging hooks removed.\n");
02577 #endif
02578 
02579     return NS_OK;
02580 }
02581 
02582 NS_IMETHODIMP
02583 jsdService::GetPauseDepth(PRUint32 *_rval)
02584 {
02585     NS_ENSURE_ARG_POINTER(_rval);
02586     *_rval = mPauseLevel;
02587     return NS_OK;
02588 }
02589     
02590 NS_IMETHODIMP
02591 jsdService::Pause(PRUint32 *_rval)
02592 {
02593     if (!mCx)
02594         return NS_ERROR_NOT_INITIALIZED;
02595 
02596     if (++mPauseLevel == 1) {
02597         JSD_SetErrorReporter (mCx, NULL, NULL);
02598         JSD_ClearThrowHook (mCx);
02599         JSD_ClearInterruptHook (mCx);
02600         JSD_ClearDebuggerHook (mCx);
02601         JSD_ClearDebugBreakHook (mCx);
02602         JSD_ClearTopLevelHook (mCx);
02603         JSD_ClearFunctionHook (mCx);
02604     }
02605 
02606     if (_rval)
02607         *_rval = mPauseLevel;
02608 
02609     return NS_OK;
02610 }
02611 
02612 NS_IMETHODIMP
02613 jsdService::UnPause(PRUint32 *_rval)
02614 {
02615     if (!mCx)
02616         return NS_ERROR_NOT_INITIALIZED;
02617 
02618     if (mPauseLevel == 0)
02619         return NS_ERROR_NOT_AVAILABLE;
02620 
02621     /* check mOn before we muck with this stuff, it's possible the debugger
02622      * was turned off while we were paused.
02623      */
02624     if (--mPauseLevel == 0 && mOn) {
02625         if (mErrorHook)
02626             JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
02627         if (mThrowHook)
02628             JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
02629         if (mInterruptHook)
02630             JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
02631         if (mDebuggerHook)
02632             JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
02633         if (mDebugHook)
02634             JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
02635         if (mTopLevelHook)
02636             JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
02637         else
02638             JSD_ClearTopLevelHook (mCx);
02639         if (mFunctionHook)
02640             JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
02641         else
02642             JSD_ClearFunctionHook (mCx);
02643     }
02644     
02645     if (_rval)
02646         *_rval = mPauseLevel;
02647 
02648     return NS_OK;
02649 }
02650 
02651 NS_IMETHODIMP
02652 jsdService::EnumerateContexts (jsdIContextEnumerator *enumerator)
02653 {
02654     ASSERT_VALID_CONTEXT;
02655     
02656     if (!enumerator)
02657         return NS_OK;
02658     
02659     JSContext *iter = NULL;
02660     JSContext *cx;
02661 
02662     while ((cx = JS_ContextIterator (mRuntime, &iter)))
02663     {
02664         nsCOMPtr<jsdIContext> jsdicx = 
02665             getter_AddRefs(jsdContext::FromPtr(mCx, cx));
02666         if (jsdicx)
02667         {
02668             if (NS_FAILED(enumerator->EnumerateContext(jsdicx)))
02669                 break;
02670         }
02671     }
02672 
02673     return NS_OK;
02674 }
02675 
02676 NS_IMETHODIMP
02677 jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator)
02678 {
02679     ASSERT_VALID_CONTEXT;
02680     
02681     JSDScript *script;
02682     JSDScript *iter = NULL;
02683     nsresult rv = NS_OK;
02684     
02685     JSD_LockScriptSubsystem(mCx);
02686     while((script = JSD_IterateScripts(mCx, &iter))) {
02687         nsCOMPtr<jsdIScript> jsdis =
02688             getter_AddRefs(jsdScript::FromPtr(mCx, script));
02689         rv = enumerator->EnumerateScript (jsdis);
02690         if (NS_FAILED(rv))
02691             break;
02692     }
02693     JSD_UnlockScriptSubsystem(mCx);
02694 
02695     return rv;
02696 }
02697 
02698 #ifdef GC_MARK_DEBUG
02699 JS_BEGIN_EXTERN_C
02700 JS_FRIEND_DATA(FILE *) js_DumpGCHeap;
02701 JS_END_EXTERN_C
02702 #endif
02703 
02704 NS_IMETHODIMP
02705 jsdService::GC (void)
02706 {
02707     ASSERT_VALID_CONTEXT;
02708     JSContext *cx = JSD_GetDefaultJSContext (mCx);
02709 #ifdef GC_MARK_DEBUG
02710     FILE *file = fopen("jsds-roots.txt", "w");
02711     js_DumpGCHeap = file;
02712 #endif
02713     JS_GC(cx);
02714 #ifdef GC_MARK_DEBUG
02715     if (file)
02716         fclose (file);
02717     js_DumpGCHeap = NULL;
02718 #endif
02719     return NS_OK;
02720 }
02721     
02722 NS_IMETHODIMP
02723 jsdService::ClearProfileData ()
02724 {
02725     ASSERT_VALID_CONTEXT;
02726     JSD_ClearAllProfileData (mCx);
02727     return NS_OK;
02728 }
02729 
02730 NS_IMETHODIMP
02731 jsdService::InsertFilter (jsdIFilter *filter, jsdIFilter *after)
02732 {
02733     NS_ENSURE_ARG_POINTER (filter);
02734     if (jsds_FindFilter (filter))
02735         return NS_ERROR_INVALID_ARG;
02736 
02737     FilterRecord *rec = PR_NEWZAP (FilterRecord);
02738     if (!rec)
02739         return NS_ERROR_OUT_OF_MEMORY;
02740 
02741     if (!jsds_SyncFilter (rec, filter)) {
02742         PR_Free (rec);
02743         return NS_ERROR_FAILURE;
02744     }
02745     
02746     if (gFilters) {
02747         if (!after) {
02748             /* insert at head of list */
02749             PR_INSERT_LINK(&rec->links, &gFilters->links);
02750             gFilters = rec;
02751         } else {
02752             /* insert somewhere in the list */
02753             FilterRecord *afterRecord = jsds_FindFilter (after);
02754             if (!afterRecord) {
02755                 jsds_FreeFilter(rec);
02756                 return NS_ERROR_INVALID_ARG;
02757             }
02758             PR_INSERT_AFTER(&rec->links, &afterRecord->links);
02759         }
02760     } else {
02761         if (after) {
02762             /* user asked to insert into the middle of an empty list, bail. */
02763             jsds_FreeFilter(rec);
02764             return NS_ERROR_NOT_INITIALIZED;
02765         }
02766         PR_INIT_CLIST(&rec->links);
02767         gFilters = rec;
02768     }
02769     
02770     return NS_OK;
02771 }
02772 
02773 NS_IMETHODIMP
02774 jsdService::AppendFilter (jsdIFilter *filter)
02775 {
02776     NS_ENSURE_ARG_POINTER (filter);
02777     if (jsds_FindFilter (filter))
02778         return NS_ERROR_INVALID_ARG;
02779     FilterRecord *rec = PR_NEWZAP (FilterRecord);
02780 
02781     if (!jsds_SyncFilter (rec, filter)) {
02782         PR_Free (rec);
02783         return NS_ERROR_FAILURE;
02784     }
02785     
02786     if (gFilters) {
02787         PR_INSERT_BEFORE(&rec->links, &gFilters->links);
02788     } else {
02789         PR_INIT_CLIST(&rec->links);
02790         gFilters = rec;
02791     }
02792     
02793     return NS_OK;
02794 }
02795 
02796 NS_IMETHODIMP
02797 jsdService::RemoveFilter (jsdIFilter *filter)
02798 {
02799     NS_ENSURE_ARG_POINTER(filter);
02800     FilterRecord *rec = jsds_FindFilter (filter);
02801     if (!rec)
02802         return NS_ERROR_INVALID_ARG;
02803     
02804     if (gFilters == rec) {
02805         gFilters = NS_REINTERPRET_CAST(FilterRecord *,
02806                                        PR_NEXT_LINK(&rec->links));
02807         /* If we're the only filter left, null out the list head. */
02808         if (gFilters == rec)
02809             gFilters = nsnull;
02810     }
02811 
02812     
02813     PR_REMOVE_LINK(&rec->links);
02814     jsds_FreeFilter (rec);
02815     
02816     return NS_OK;
02817 }
02818 
02819 NS_IMETHODIMP
02820 jsdService::SwapFilters (jsdIFilter *filter_a, jsdIFilter *filter_b)
02821 {
02822     NS_ENSURE_ARG_POINTER(filter_a);
02823     NS_ENSURE_ARG_POINTER(filter_b);
02824     
02825     FilterRecord *rec_a = jsds_FindFilter (filter_a);
02826     if (!rec_a)
02827         return NS_ERROR_INVALID_ARG;
02828     
02829     if (filter_a == filter_b) {
02830         /* just a refresh */
02831         if (!jsds_SyncFilter (rec_a, filter_a))
02832             return NS_ERROR_FAILURE;
02833         return NS_OK;
02834     }
02835     
02836     FilterRecord *rec_b = jsds_FindFilter (filter_b);
02837     if (!rec_b) {
02838         /* filter_b is not in the list, replace filter_a with filter_b. */
02839         if (!jsds_SyncFilter (rec_a, filter_b))
02840             return NS_ERROR_FAILURE;
02841     } else {
02842         /* both filters are in the list, swap. */
02843         if (!jsds_SyncFilter (rec_a, filter_b))
02844             return NS_ERROR_FAILURE;
02845         if (!jsds_SyncFilter (rec_b, filter_a))
02846             return NS_ERROR_FAILURE;
02847     }
02848     
02849     return NS_OK;
02850 }
02851 
02852 NS_IMETHODIMP
02853 jsdService::EnumerateFilters (jsdIFilterEnumerator *enumerator) 
02854 {
02855     if (!gFilters)
02856         return NS_OK;
02857     
02858     FilterRecord *current = gFilters;
02859     do {
02860         jsds_SyncFilter (current, current->filterObject);
02861         /* SyncFilter failure would be bad, but what would we do about it? */
02862         if (enumerator) {
02863             nsresult rv = enumerator->EnumerateFilter (current->filterObject);
02864             if (NS_FAILED(rv))
02865                 return rv;
02866         }
02867         current = NS_REINTERPRET_CAST(FilterRecord *,
02868                                       PR_NEXT_LINK (&current->links));
02869     } while (current != gFilters);
02870     
02871     return NS_OK;
02872 }
02873 
02874 NS_IMETHODIMP
02875 jsdService::RefreshFilters ()
02876 {
02877     return EnumerateFilters(nsnull);
02878 }
02879 
02880 NS_IMETHODIMP
02881 jsdService::ClearFilters ()
02882 {
02883     if (!gFilters)
02884         return NS_OK;
02885 
02886     FilterRecord *current = NS_REINTERPRET_CAST(FilterRecord *,
02887                                                 PR_NEXT_LINK (&gFilters->links));
02888     do {
02889         FilterRecord *next = NS_REINTERPRET_CAST(FilterRecord *,
02890                                                  PR_NEXT_LINK (&current->links));
02891         PR_REMOVE_AND_INIT_LINK(&current->links);
02892         jsds_FreeFilter(current);
02893         current = next;
02894     } while (current != gFilters);
02895     
02896     jsds_FreeFilter(current);
02897     gFilters = nsnull;
02898     
02899     return NS_OK;
02900 }
02901         
02902 NS_IMETHODIMP
02903 jsdService::ClearAllBreakpoints (void)
02904 {
02905     ASSERT_VALID_CONTEXT;
02906 
02907     JSD_LockScriptSubsystem(mCx);
02908     JSD_ClearAllExecutionHooks (mCx);
02909     JSD_UnlockScriptSubsystem(mCx);
02910     return NS_OK;
02911 }
02912 
02913 NS_IMETHODIMP
02914 jsdService::WrapValue(jsdIValue **_rval)
02915 {
02916     ASSERT_VALID_CONTEXT;
02917 
02918     nsCOMPtr<nsIXPConnect> xpc = do_GetService (nsIXPConnect::GetCID());
02919     if (!xpc)
02920         return NS_ERROR_FAILURE;
02921 
02922     nsresult rv;
02923     nsCOMPtr<nsIXPCNativeCallContext> cc;
02924     rv = xpc->GetCurrentNativeCallContext (getter_AddRefs(cc));
02925     if (NS_FAILED(rv))
02926         return rv;
02927 
02928     PRUint32 argc;
02929     rv = cc->GetArgc (&argc);
02930     if (NS_FAILED(rv))
02931         return rv;
02932     if (argc < 1)
02933         return NS_ERROR_INVALID_ARG;
02934     
02935     jsval    *argv;
02936     rv = cc->GetArgvPtr (&argv);
02937     if (NS_FAILED(rv))
02938         return rv;
02939 
02940     JSDValue *jsdv = JSD_NewValue (mCx, argv[0]);
02941     if (!jsdv)
02942         return NS_ERROR_FAILURE;
02943     
02944     *_rval = jsdValue::FromPtr (mCx, jsdv);
02945     return NS_OK;
02946 }
02947 
02948 
02949 NS_IMETHODIMP
02950 jsdService::EnterNestedEventLoop (jsdINestCallback *callback, PRUint32 *_rval)
02951 {
02952     nsCOMPtr<nsIAppShell> appShell(do_CreateInstance(kAppShellCID));
02953     NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
02954     nsCOMPtr<nsIEventQueueService> 
02955         eventService(do_GetService(kEventQueueServiceCID));
02956     NS_ENSURE_TRUE(eventService, NS_ERROR_FAILURE);
02957     
02958     appShell->Create(0, nsnull);
02959     appShell->Spinup();
02960 
02961     nsCOMPtr<nsIJSContextStack> 
02962         stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
02963     nsresult rv = NS_OK;
02964     PRUint32 nestLevel = ++mNestedLoopLevel;
02965     
02966     nsCOMPtr<nsIEventQueue> eventQ;
02967     if (stack && NS_SUCCEEDED(stack->Push(nsnull)) &&
02968         NS_SUCCEEDED(eventService->PushThreadEventQueue(getter_AddRefs(eventQ))))
02969     {
02970         if (NS_SUCCEEDED(rv) && callback) {
02971             Pause(nsnull);
02972             rv = callback->OnNest();
02973             UnPause(nsnull);
02974         }
02975         
02976         while(NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel)
02977         {
02978             void* data;
02979             PRBool isRealEvent;
02980             //PRBool processEvent;
02981             
02982             rv = appShell->GetNativeEvent(isRealEvent, data);
02983             if(NS_SUCCEEDED(rv))
02984                 appShell->DispatchNativeEvent(isRealEvent, data);
02985             }
02986         JSContext* cx;
02987         stack->Pop(&cx);
02988         NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
02989     }
02990     else
02991         rv = NS_ERROR_FAILURE;
02992     
02993     eventService->PopThreadEventQueue(eventQ);
02994     appShell->Spindown();
02995 
02996     NS_ASSERTION (mNestedLoopLevel <= nestLevel,
02997                   "nested event didn't unwind properly");
02998     if (mNestedLoopLevel == nestLevel)
02999         --mNestedLoopLevel;
03000 
03001     *_rval = mNestedLoopLevel;
03002     return rv;
03003 }
03004 
03005 NS_IMETHODIMP
03006 jsdService::ExitNestedEventLoop (PRUint32 *_rval)
03007 {
03008     if (mNestedLoopLevel > 0)
03009         --mNestedLoopLevel;
03010     else
03011         return NS_ERROR_FAILURE;
03012 
03013     *_rval = mNestedLoopLevel;    
03014     return NS_OK;
03015 }    
03016 
03017 /* hook attribute get/set functions */
03018 
03019 NS_IMETHODIMP
03020 jsdService::SetErrorHook (jsdIErrorHook *aHook)
03021 {
03022     mErrorHook = aHook;
03023 
03024     /* if the debugger isn't initialized, that's all we can do for now.  The
03025      * OnForRuntime() method will do the rest when the coast is clear.
03026      */
03027     if (!mCx || mPauseLevel)
03028         return NS_OK;
03029 
03030     if (aHook)
03031         JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
03032     else
03033         JSD_SetErrorReporter (mCx, NULL, NULL);
03034 
03035     return NS_OK;
03036 }
03037 
03038 NS_IMETHODIMP
03039 jsdService::GetErrorHook (jsdIErrorHook **aHook)
03040 {
03041     *aHook = mErrorHook;
03042     NS_IF_ADDREF(*aHook);
03043     
03044     return NS_OK;
03045 }
03046 
03047 NS_IMETHODIMP
03048 jsdService::SetBreakpointHook (jsdIExecutionHook *aHook)
03049 {    
03050     mBreakpointHook = aHook;
03051     return NS_OK;
03052 }
03053 
03054 NS_IMETHODIMP
03055 jsdService::GetBreakpointHook (jsdIExecutionHook **aHook)
03056 {   
03057     *aHook = mBreakpointHook;
03058     NS_IF_ADDREF(*aHook);
03059     
03060     return NS_OK;
03061 }
03062 
03063 NS_IMETHODIMP
03064 jsdService::SetDebugHook (jsdIExecutionHook *aHook)
03065 {    
03066     mDebugHook = aHook;
03067 
03068     /* if the debugger isn't initialized, that's all we can do for now.  The
03069      * OnForRuntime() method will do the rest when the coast is clear.
03070      */
03071     if (!mCx || mPauseLevel)
03072         return NS_OK;
03073 
03074     if (aHook)
03075         JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
03076     else
03077         JSD_ClearDebugBreakHook (mCx);
03078     
03079     return NS_OK;
03080 }
03081 
03082 NS_IMETHODIMP
03083 jsdService::GetDebugHook (jsdIExecutionHook **aHook)
03084 {   
03085     *aHook = mDebugHook;
03086     NS_IF_ADDREF(*aHook);
03087     
03088     return NS_OK;
03089 }
03090 
03091 NS_IMETHODIMP
03092 jsdService::SetDebuggerHook (jsdIExecutionHook *aHook)
03093 {    
03094     mDebuggerHook = aHook;
03095 
03096     /* if the debugger isn't initialized, that's all we can do for now.  The
03097      * OnForRuntime() method will do the rest when the coast is clear.
03098      */
03099     if (!mCx || mPauseLevel)
03100         return NS_OK;
03101 
03102     if (aHook)
03103         JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
03104     else
03105         JSD_ClearDebuggerHook (mCx);
03106     
03107     return NS_OK;
03108 }
03109 
03110 NS_IMETHODIMP
03111 jsdService::GetDebuggerHook (jsdIExecutionHook **aHook)
03112 {   
03113     *aHook = mDebuggerHook;
03114     NS_IF_ADDREF(*aHook);
03115     
03116     return NS_OK;
03117 }
03118 
03119 NS_IMETHODIMP
03120 jsdService::SetInterruptHook (jsdIExecutionHook *aHook)
03121 {    
03122     mInterruptHook = aHook;
03123 
03124     /* if the debugger isn't initialized, that's all we can do for now.  The
03125      * OnForRuntime() method will do the rest when the coast is clear.
03126      */
03127     if (!mCx || mPauseLevel)
03128         return NS_OK;
03129 
03130     if (aHook)
03131         JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
03132     else
03133         JSD_ClearInterruptHook (mCx);
03134     
03135     return NS_OK;
03136 }
03137 
03138 NS_IMETHODIMP
03139 jsdService::GetInterruptHook (jsdIExecutionHook **aHook)
03140 {   
03141     *aHook = mInterruptHook;
03142     NS_IF_ADDREF(*aHook);
03143     
03144     return NS_OK;
03145 }
03146 
03147 NS_IMETHODIMP
03148 jsdService::SetScriptHook (jsdIScriptHook *aHook)
03149 {    
03150     mScriptHook = aHook;
03151 
03152     /* if the debugger isn't initialized, that's all we can do for now.  The
03153      * OnForRuntime() method will do the rest when the coast is clear.
03154      */
03155     if (!mCx || mPauseLevel)
03156         return NS_OK;
03157     
03158     if (aHook)
03159         JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
03160     /* we can't unset it if !aHook, because we still need to see script
03161      * deletes in order to Release the jsdIScripts held in JSDScript
03162      * private data. */
03163     return NS_OK;
03164 }
03165 
03166 NS_IMETHODIMP
03167 jsdService::GetScriptHook (jsdIScriptHook **aHook)
03168 {   
03169     *aHook = mScriptHook;
03170     NS_IF_ADDREF(*aHook);
03171     
03172     return NS_OK;
03173 }
03174 
03175 NS_IMETHODIMP
03176 jsdService::SetThrowHook (jsdIExecutionHook *aHook)
03177 {    
03178     mThrowHook = aHook;
03179 
03180     /* if the debugger isn't initialized, that's all we can do for now.  The
03181      * OnForRuntime() method will do the rest when the coast is clear.
03182      */
03183     if (!mCx || mPauseLevel)
03184         return NS_OK;
03185 
03186     if (aHook)
03187         JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
03188     else
03189         JSD_ClearThrowHook (mCx);
03190     
03191     return NS_OK;
03192 }
03193 
03194 NS_IMETHODIMP
03195 jsdService::GetThrowHook (jsdIExecutionHook **aHook)
03196 {   
03197     *aHook = mThrowHook;
03198     NS_IF_ADDREF(*aHook);
03199     
03200     return NS_OK;
03201 }
03202 
03203 NS_IMETHODIMP
03204 jsdService::SetTopLevelHook (jsdICallHook *aHook)
03205 {    
03206     mTopLevelHook = aHook;
03207 
03208     /* if the debugger isn't initialized, that's all we can do for now.  The
03209      * OnForRuntime() method will do the rest when the coast is clear.
03210      */
03211     if (!mCx || mPauseLevel)
03212         return NS_OK;
03213 
03214     if (aHook)
03215         JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
03216     else
03217         JSD_ClearTopLevelHook (mCx);
03218     
03219     return NS_OK;
03220 }
03221 
03222 NS_IMETHODIMP
03223 jsdService::GetTopLevelHook (jsdICallHook **aHook)
03224 {   
03225     *aHook = mTopLevelHook;
03226     NS_IF_ADDREF(*aHook);
03227     
03228     return NS_OK;
03229 }
03230 
03231 NS_IMETHODIMP
03232 jsdService::SetFunctionHook (jsdICallHook *aHook)
03233 {    
03234     mFunctionHook = aHook;
03235 
03236     /* if the debugger isn't initialized, that's all we can do for now.  The
03237      * OnForRuntime() method will do the rest when the coast is clear.
03238      */
03239     if (!mCx || mPauseLevel)
03240         return NS_OK;
03241 
03242     if (aHook)
03243         JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
03244     else
03245         JSD_ClearFunctionHook (mCx);
03246     
03247     return NS_OK;
03248 }
03249 
03250 NS_IMETHODIMP
03251 jsdService::GetFunctionHook (jsdICallHook **aHook)
03252 {   
03253     *aHook = mFunctionHook;
03254     NS_IF_ADDREF(*aHook);
03255     
03256     return NS_OK;
03257 }
03258 
03259 /* virtual */
03260 jsdService::~jsdService()
03261 {
03262     ClearFilters();
03263     Off();
03264     gJsds = nsnull;
03265 }
03266 
03267 jsdService *
03268 jsdService::GetService ()
03269 {
03270     if (!gJsds)
03271         gJsds = new jsdService();
03272         
03273     NS_IF_ADDREF(gJsds);
03274     return gJsds;
03275 }
03276 
03277 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService, jsdService::GetService)
03278 
03279 /* app-start observer.  turns on the debugger at app-start.  this is inserted
03280  * and/or removed from the app-start category by the jsdService::initAtStartup
03281  * property.
03282  */
03283 class jsdASObserver : public nsIObserver 
03284 {
03285   public:
03286     NS_DECL_ISUPPORTS
03287     NS_DECL_NSIOBSERVER
03288 
03289     jsdASObserver () {}    
03290 };
03291 
03292 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver, nsIObserver)
03293 
03294 NS_IMETHODIMP
03295 jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic,
03296                         const PRUnichar *aData)
03297 {
03298     nsresult rv;
03299 
03300     // Hmm.  Why is the app-startup observer called multiple times?
03301     //NS_ASSERTION(!gJsds, "app startup observer called twice");
03302     nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
03303 
03304     PRBool on;
03305     rv = jsds->GetIsOn(&on);
03306     if (NS_FAILED(rv) || on)
03307         return rv;
03308     
03309     nsCOMPtr<nsIJSRuntimeService> rts = do_GetService(NS_JSRT_CTRID, &rv);
03310     if (NS_FAILED(rv))
03311         return rv;    
03312 
03313     JSRuntime *rt;
03314     rts->GetRuntime (&rt);
03315     if (NS_FAILED(rv))
03316         return rv;
03317 
03318     rv = jsds->OnForRuntime(rt);
03319     if (NS_FAILED(rv))
03320         return rv;
03321     
03322     return jsds->SetFlags(JSD_DISABLE_OBJECT_TRACE);
03323 }
03324 
03325 NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
03326 
03327 static const nsModuleComponentInfo components[] = {
03328     {"JSDService", JSDSERVICE_CID,    jsdServiceCtrID, jsdServiceConstructor},
03329     {"JSDASObserver",  JSDASO_CID, jsdASObserverCtrID, jsdASObserverConstructor}
03330 };
03331 
03332 NS_IMPL_NSGETMODULE(JavaScript_Debugger, components)
03333 
03334 /********************************************************************************
03335  ********************************************************************************
03336  * graveyard
03337  */
03338 
03339 #if 0
03340 /* Thread States */
03341 NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState, jsdIThreadState); 
03342 
03343 NS_IMETHODIMP
03344 jsdThreadState::GetJSDContext(JSDContext **_rval)
03345 {
03346     *_rval = mCx;
03347     return NS_OK;
03348 }
03349 
03350 NS_IMETHODIMP
03351 jsdThreadState::GetJSDThreadState(JSDThreadState **_rval)
03352 {
03353     *_rval = mThreadState;
03354     return NS_OK;
03355 }
03356 
03357 NS_IMETHODIMP
03358 jsdThreadState::GetFrameCount (PRUint32 *_rval)
03359 {
03360     *_rval = JSD_GetCountOfStackFrames (mCx, mThreadState);
03361     return NS_OK;
03362 }
03363 
03364 NS_IMETHODIMP
03365 jsdThreadState::GetTopFrame (jsdIStackFrame **_rval)
03366 {
03367     JSDStackFrameInfo *sfi = JSD_GetStackFrame (mCx, mThreadState);
03368     
03369     *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
03370     return NS_OK;
03371 }
03372 
03373 NS_IMETHODIMP
03374 jsdThreadState::GetPendingException(jsdIValue **_rval)
03375 {
03376     JSDValue *jsdv = JSD_GetException (mCx, mThreadState);
03377     
03378     *_rval = jsdValue::FromPtr (mCx, jsdv);
03379     return NS_OK;
03380 }
03381 
03382 NS_IMETHODIMP
03383 jsdThreadState::SetPendingException(jsdIValue *aException)
03384 {
03385     JSDValue *jsdv;
03386     
03387     nsresult rv = aException->GetJSDValue (&jsdv);
03388     if (NS_FAILED(rv))
03389         return NS_ERROR_FAILURE;
03390     
03391     if (!JSD_SetException (mCx, mThreadState, jsdv))
03392         return NS_ERROR_FAILURE;
03393 
03394     return NS_OK;
03395 }
03396 
03397 #endif