js/jsd/jsd_xpc.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "jsfriendapi.h"
     8 #include "jsd_xpc.h"
     9 #include "xpcpublic.h"
    11 #include "js/GCAPI.h"
    12 #include "js/OldDebugAPI.h"
    14 #include "nsIXPConnect.h"
    15 #include "mozilla/ModuleUtils.h"
    16 #include "nsIServiceManager.h"
    17 #include "nsIScriptGlobalObject.h"
    18 #include "nsIObserver.h"
    19 #include "nsIObserverService.h"
    20 #include "nsICategoryManager.h"
    21 #include "nsIJSRuntimeService.h"
    22 #include "nsIThreadInternal.h"
    23 #include "nsIScriptError.h"
    24 #include "nsTArray.h"
    25 #include "nsThreadUtils.h"
    26 #include "nsMemory.h"
    27 #include "jsdebug.h"
    28 #include "nsReadableUtils.h"
    29 #include "nsCRT.h"
    30 #include "nsCycleCollectionParticipant.h"
    31 #include "mozilla/Attributes.h"
    33 /* XXX DOM dependency */
    34 #include "nsIScriptContext.h"
    35 #include "nsPIDOMWindow.h"
    36 #include "nsDOMJSUtils.h"
    37 #include "SandboxPrivate.h"
    38 #include "nsJSPrincipals.h"
    39 #include "nsContentUtils.h"
    40 #include "mozilla/dom/ScriptSettings.h"
    42 using mozilla::AutoSafeJSContext;
    43 using mozilla::AutoPushJSContext;
    44 using mozilla::dom::AutoNoJSAPI;
    46 /*
    47  * defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
    48  * script hook.  This was a hack to avoid some js engine problems that should
    49  * be fixed now (see Mozilla bug 77636).
    50  */
    51 #undef CAUTIOUS_SCRIPTHOOK
    53 #ifdef DEBUG_verbose
    54 #   define DEBUG_COUNT(name, count)                                             \
    55         { if ((count % 10) == 0) printf (name ": %i\n", count); }
    56 #   define DEBUG_CREATE(name, count) {count++; DEBUG_COUNT ("+++++ " name,count)}
    57 #   define DEBUG_DESTROY(name, count) {count--; DEBUG_COUNT ("----- " name,count)}
    58 #else
    59 #   define DEBUG_CREATE(name, count) 
    60 #   define DEBUG_DESTROY(name, count)
    61 #endif
    63 #define ASSERT_VALID_CONTEXT   { if (!mCx) return NS_ERROR_NOT_AVAILABLE; }
    64 #define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; }
    66 #define JSDSERVICE_CID                               \
    67 { /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */         \
    68      0xf1299dc2,                                     \
    69      0x1dd1,                                         \
    70      0x11b2,                                         \
    71     {0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \
    72 }
    74 #define JSDASO_CID                                   \
    75 { /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */         \
    76      0x2fd6b7f6,                                     \
    77      0xeb8c,                                         \
    78      0x4f32,                                         \
    79     {0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \
    80 }
    82 #define JSDS_MAJOR_VERSION 1
    83 #define JSDS_MINOR_VERSION 2
    85 #define NS_CATMAN_CTRID   "@mozilla.org/categorymanager;1"
    86 #define NS_JSRT_CTRID     "@mozilla.org/js/xpc/RuntimeService;1"
    88 #define AUTOREG_CATEGORY  "xpcom-autoregistration"
    89 #define APPSTART_CATEGORY "app-startup"
    90 #define JSD_AUTOREG_ENTRY "JSDebugger Startup Observer"
    91 #define JSD_STARTUP_ENTRY "JSDebugger Startup Observer"
    93 static void
    94 jsds_GCSliceCallbackProc (JSRuntime *rt, JS::GCProgress progress, const JS::GCDescription &desc);
    96 /*******************************************************************************
    97  * global vars
    98  ******************************************************************************/
   100 const char implementationString[] = "Mozilla JavaScript Debugger Service";
   102 const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
   103 const char jsdARObserverCtrID[] = "@mozilla.org/js/jsd/app-start-observer;2";
   104 const char jsdASObserverCtrID[] = "service,@mozilla.org/js/jsd/app-start-observer;2";
   106 #ifdef DEBUG_verbose
   107 uint32_t gScriptCount   = 0;
   108 uint32_t gValueCount    = 0;
   109 uint32_t gPropertyCount = 0;
   110 uint32_t gContextCount  = 0;
   111 uint32_t gFrameCount  = 0;
   112 #endif
   114 static jsdService          *gJsds               = 0;
   115 static JS::GCSliceCallback gPrevGCSliceCallback = jsds_GCSliceCallbackProc;
   116 static bool                gGCRunning           = false;
   118 static struct DeadScript {
   119     PRCList     links;
   120     JSDContext *jsdc;
   121     jsdIScript *script;
   122 } *gDeadScripts = nullptr;
   124 enum PatternType {
   125     ptIgnore     = 0U,
   126     ptStartsWith = 1U,
   127     ptEndsWith   = 2U,
   128     ptContains   = 3U,
   129     ptEquals     = 4U
   130 };
   132 static struct FilterRecord {
   133     PRCList      links;
   134     jsdIFilter  *filterObject;
   135     nsCString    urlPattern;
   136     PatternType  patternType;
   137     uint32_t     startLine;
   138     uint32_t     endLine;
   139 } *gFilters = nullptr;
   141 static struct LiveEphemeral *gLiveValues      = nullptr;
   142 static struct LiveEphemeral *gLiveProperties  = nullptr;
   143 static struct LiveEphemeral *gLiveContexts    = nullptr;
   144 static struct LiveEphemeral *gLiveStackFrames = nullptr;
   146 /*******************************************************************************
   147  * utility functions for ephemeral lists
   148  *******************************************************************************/
   149 already_AddRefed<jsdIEphemeral>
   150 jsds_FindEphemeral (LiveEphemeral **listHead, void *key)
   151 {
   152     if (!*listHead)
   153         return nullptr;
   155     LiveEphemeral *lv_record = 
   156         reinterpret_cast<LiveEphemeral *>
   157                         (PR_NEXT_LINK(&(*listHead)->links));
   158     do
   159     {
   160         if (lv_record->key == key)
   161         {
   162             nsCOMPtr<jsdIEphemeral> ret = lv_record->value;
   163             return ret.forget();
   164         }
   165         lv_record = reinterpret_cast<LiveEphemeral *>
   166                                     (PR_NEXT_LINK(&lv_record->links));
   167     }
   168     while (lv_record != *listHead);
   170     return nullptr;
   171 }
   173 void
   174 jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
   175 {
   176     LiveEphemeral *lv_record = 
   177         reinterpret_cast<LiveEphemeral *>
   178                         (PR_NEXT_LINK(&(*listHead)->links));
   179     do
   180     {
   181         LiveEphemeral *next =
   182             reinterpret_cast<LiveEphemeral *>
   183                             (PR_NEXT_LINK(&lv_record->links));
   184         lv_record->value->Invalidate();
   185         lv_record = next;
   186     }
   187     while (*listHead);
   188 }
   190 void
   191 jsds_InsertEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
   192 {
   193     if (*listHead) {
   194         /* if the list exists, add to it */
   195         PR_APPEND_LINK(&item->links, &(*listHead)->links);
   196     } else {
   197         /* otherwise create the list */
   198         PR_INIT_CLIST(&item->links);
   199         *listHead = item;
   200     }
   201 }
   203 void
   204 jsds_RemoveEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
   205 {
   206     LiveEphemeral *next = reinterpret_cast<LiveEphemeral *>
   207                                           (PR_NEXT_LINK(&item->links));
   209     if (next == item)
   210     {
   211         /* if the current item is also the next item, we're the only element,
   212          * null out the list head */
   213         NS_ASSERTION (*listHead == item,
   214                       "How could we not be the head of a one item list?");
   215         *listHead = nullptr;
   216     }
   217     else if (item == *listHead)
   218     {
   219         /* otherwise, if we're currently the list head, change it */
   220         *listHead = next;
   221     }
   223     PR_REMOVE_AND_INIT_LINK(&item->links);
   224 }
   226 /*******************************************************************************
   227  * utility functions for filters
   228  *******************************************************************************/
   229 void
   230 jsds_FreeFilter (FilterRecord *rec)
   231 {
   232     NS_IF_RELEASE (rec->filterObject);
   233     PR_Free (rec);
   234 }
   236 /* copies appropriate |filter| attributes into |rec|.
   237  * False return indicates failure, the contents of |rec| will not be changed.
   238  */
   239 bool
   240 jsds_SyncFilter (FilterRecord *rec, jsdIFilter *filter)
   241 {
   242     NS_ASSERTION (rec, "jsds_SyncFilter without rec");
   243     NS_ASSERTION (filter, "jsds_SyncFilter without filter");
   245     uint32_t startLine;
   246     nsresult rv = filter->GetStartLine(&startLine);
   247     if (NS_FAILED(rv))
   248         return false;
   250     uint32_t endLine;
   251     rv = filter->GetStartLine(&endLine);
   252     if (NS_FAILED(rv))
   253         return false;    
   255     nsAutoCString urlPattern;
   256     rv = filter->GetUrlPattern (urlPattern);
   257     if (NS_FAILED(rv))
   258         return false;
   260     uint32_t len = urlPattern.Length();
   261     if (len) {
   262         if (urlPattern[0] == '*') {
   263             /* pattern starts with a *, shift all chars once to the left,
   264              * including the trailing null. */
   265             urlPattern = Substring(urlPattern, 1, len);
   267             if (urlPattern[len - 2] == '*') {
   268                 /* pattern is in the format "*foo*", overwrite the final * with
   269                  * a null. */
   270                 urlPattern.Truncate(len - 2);
   271                 rec->patternType = ptContains;
   272             } else {
   273                 /* pattern is in the format "*foo", just make a note of the
   274                  * new length. */
   275                 rec->patternType = ptEndsWith;
   276             }
   277         } else if (urlPattern[len - 1] == '*') {
   278             /* pattern is in the format "foo*", overwrite the final * with a 
   279              * null. */
   280             urlPattern.Truncate(len - 1);
   281             rec->patternType = ptStartsWith;
   282         } else {
   283             /* pattern is in the format "foo". */
   284             rec->patternType = ptEquals;
   285         }
   286     } else {
   287         rec->patternType = ptIgnore;
   288     }
   290     /* we got everything we need without failing, now copy it into rec. */
   292     if (rec->filterObject != filter) {
   293         NS_IF_RELEASE(rec->filterObject);
   294         NS_ADDREF(filter);
   295         rec->filterObject = filter;
   296     }
   298     rec->startLine     = startLine;
   299     rec->endLine       = endLine;
   301     rec->urlPattern = urlPattern;
   303     return true;
   305 }
   307 FilterRecord *
   308 jsds_FindFilter (jsdIFilter *filter)
   309 {
   310     if (!gFilters)
   311         return nullptr;
   313     FilterRecord *current = gFilters;
   315     do {
   316         if (current->filterObject == filter)
   317             return current;
   318         current = reinterpret_cast<FilterRecord *>
   319                                   (PR_NEXT_LINK(&current->links));
   320     } while (current != gFilters);
   322     return nullptr;
   323 }
   325 /* returns true if the hook should be executed. */
   326 bool
   327 jsds_FilterHook (JSDContext *jsdc, JSDThreadState *state)
   328 {
   329     JSDStackFrameInfo *frame = JSD_GetStackFrame (jsdc, state);
   331     if (!frame) {
   332         NS_WARNING("No frame in threadstate");
   333         return false;
   334     }
   336     JSDScript *script = JSD_GetScriptForStackFrame (jsdc, state, frame);
   337     if (!script)
   338         return true;
   340     uintptr_t pc = JSD_GetPCForStackFrame (jsdc, state, frame);
   342     nsCString url(JSD_GetScriptFilename (jsdc, script));
   343     if (url.IsEmpty()) {
   344         NS_WARNING ("Script with no filename");
   345         return false;
   346     }
   348     if (!gFilters)
   349         return true;    
   351     uint32_t currentLine = JSD_GetClosestLine (jsdc, script, pc);
   352     uint32_t len = 0;
   353     FilterRecord *currentFilter = gFilters;
   354     do {
   355         uint32_t flags = 0;
   357 #ifdef DEBUG
   358         nsresult rv =
   359 #endif
   360             currentFilter->filterObject->GetFlags(&flags);
   361         NS_ASSERTION(NS_SUCCEEDED(rv), "Error getting flags for filter");
   363         if (flags & jsdIFilter::FLAG_ENABLED) {
   364             /* If there is no start line, or the start line is before 
   365              * or equal to the current */
   366             if ((!currentFilter->startLine ||
   367                  currentFilter->startLine <= currentLine) &&
   368                 /* and there is no end line, or the end line is after
   369                  * or equal to the current */
   370                 (!currentFilter->endLine ||
   371                  currentFilter->endLine >= currentLine)) {
   372                 /* then we're going to have to compare the url. */
   373                 if (currentFilter->patternType == ptIgnore)
   374                     return !!(flags & jsdIFilter::FLAG_PASS);
   376                 if (!len)
   377                     len = url.Length();
   378                 nsCString urlPattern = currentFilter->urlPattern;
   379                 uint32_t patternLength = urlPattern.Length();
   380                 if (len >= patternLength) {
   381                     switch (currentFilter->patternType) {
   382                         case ptEquals:
   383                             if (urlPattern.Equals(url))
   384                                 return !!(flags & jsdIFilter::FLAG_PASS);
   385                             break;
   386                         case ptStartsWith:
   387                             if (urlPattern.Equals(Substring(url, 0, patternLength)))
   388                                 return !!(flags & jsdIFilter::FLAG_PASS);
   389                             break;
   390                         case ptEndsWith:
   391                             if (urlPattern.Equals(Substring(url, len - patternLength)))
   392                                 return !!(flags & jsdIFilter::FLAG_PASS);
   393                             break;
   394                         case ptContains:
   395                             {
   396                                 nsACString::const_iterator start, end;
   397                                 url.BeginReading(start);
   398                                 url.EndReading(end);
   399                                 if (FindInReadable(currentFilter->urlPattern, start, end))
   400                                     return !!(flags & jsdIFilter::FLAG_PASS);
   401                             }
   402                             break;
   403                         default:
   404                             NS_ERROR("Invalid pattern type");
   405                     }
   406                 }                
   407             }
   408         }
   409         currentFilter = reinterpret_cast<FilterRecord *>
   410                                         (PR_NEXT_LINK(&currentFilter->links));
   411     } while (currentFilter != gFilters);
   413     return true;
   415 }
   417 /*******************************************************************************
   418  * c callbacks
   419  *******************************************************************************/
   421 static void
   422 jsds_NotifyPendingDeadScripts (JSRuntime *rt)
   423 {
   424     jsdService *jsds = gJsds;
   426     nsCOMPtr<jsdIScriptHook> hook;
   427     if (jsds) {
   428         NS_ADDREF(jsds);
   429         jsds->GetScriptHook (getter_AddRefs(hook));
   430         jsds->DoPause(nullptr, true);
   431     }
   433     DeadScript *deadScripts = gDeadScripts;
   434     gDeadScripts = nullptr;
   435     while (deadScripts) {
   436         DeadScript *ds = deadScripts;
   437         /* get next deleted script */
   438         deadScripts = reinterpret_cast<DeadScript *>
   439                                        (PR_NEXT_LINK(&ds->links));
   440         if (deadScripts == ds)
   441             deadScripts = nullptr;
   443         if (hook)
   444         {
   445             /* tell the user this script has been destroyed */
   446 #ifdef CAUTIOUS_SCRIPTHOOK
   447             JS_UNKEEP_ATOMS(rt);
   448 #endif
   449             hook->OnScriptDestroyed (ds->script);
   450 #ifdef CAUTIOUS_SCRIPTHOOK
   451             JS_KEEP_ATOMS(rt);
   452 #endif
   453         }
   455         /* take it out of the circular list */
   456         PR_REMOVE_LINK(&ds->links);
   458         /* addref came from the FromPtr call in jsds_ScriptHookProc */
   459         NS_RELEASE(ds->script);
   460         /* free the struct! */
   461         PR_Free(ds);
   462     }
   464     if (jsds) {
   465         jsds->DoUnPause(nullptr, true);
   466         NS_RELEASE(jsds);
   467     }
   468 }
   470 static void
   471 jsds_GCSliceCallbackProc (JSRuntime *rt, JS::GCProgress progress, const JS::GCDescription &desc)
   472 {
   473     if (progress == JS::GC_CYCLE_END || progress == JS::GC_SLICE_END) {
   474         NS_ASSERTION(gGCRunning, "GC slice callback was missed");
   476         while (gDeadScripts)
   477             jsds_NotifyPendingDeadScripts (rt);
   479         gGCRunning = false;
   480     } else {
   481         NS_ASSERTION(!gGCRunning, "should not re-enter GC");
   482         gGCRunning = true;
   483     }
   485     if (gPrevGCSliceCallback)
   486         (*gPrevGCSliceCallback)(rt, progress, desc);
   487 }
   489 static unsigned
   490 jsds_ErrorHookProc (JSDContext *jsdc, JSContext *cx, const char *message,
   491                     JSErrorReport *report, void *callerdata)
   492 {
   493     static bool running = false;
   495     nsCOMPtr<jsdIErrorHook> hook;
   496     gJsds->GetErrorHook(getter_AddRefs(hook));
   497     if (!hook)
   498         return JSD_ERROR_REPORTER_PASS_ALONG;
   500     if (running)
   501         return JSD_ERROR_REPORTER_PASS_ALONG;
   503     running = true;
   505     nsCOMPtr<jsdIValue> val;
   506     if (JS_IsExceptionPending(cx)) {
   507         JS::RootedValue jv(cx);
   508         JS_GetPendingException(cx, &jv);
   509         JSDValue *jsdv = JSD_NewValue (jsdc, jv);
   510         val = dont_AddRef(jsdValue::FromPtr(jsdc, jsdv));
   511     }
   513     nsAutoCString fileName;
   514     uint32_t    line;
   515     uint32_t    pos;
   516     uint32_t    flags;
   517     uint32_t    errnum;
   518     bool        rval;
   519     if (report) {
   520         fileName.Assign(report->filename);
   521         line = report->lineno;
   522         pos = report->tokenptr - report->linebuf;
   523         flags = report->flags;
   524         errnum = report->errorNumber;
   525     }
   526     else
   527     {
   528         line     = 0;
   529         pos      = 0;
   530         flags    = 0;
   531         errnum   = 0;
   532     }
   534     gJsds->DoPause(nullptr, true);
   535     hook->OnError (nsDependentCString(message), fileName, line, pos, flags, errnum, val, &rval);
   536     gJsds->DoUnPause(nullptr, true);
   538     running = false;
   539     if (!rval)
   540         return JSD_ERROR_REPORTER_DEBUG;
   542     return JSD_ERROR_REPORTER_PASS_ALONG;
   543 }
   545 static bool
   546 jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
   547                    unsigned type, void* callerdata)
   548 {
   549     nsCOMPtr<jsdICallHook> hook;
   551     switch (type)
   552     {
   553         case JSD_HOOK_TOPLEVEL_START:
   554         case JSD_HOOK_TOPLEVEL_END:
   555             gJsds->GetTopLevelHook(getter_AddRefs(hook));
   556             break;
   558         case JSD_HOOK_FUNCTION_CALL:
   559         case JSD_HOOK_FUNCTION_RETURN:
   560             gJsds->GetFunctionHook(getter_AddRefs(hook));
   561             break;
   563         default:
   564             NS_ASSERTION (0, "Unknown hook type.");
   565     }
   567     if (!hook)
   568         return true;
   570     if (!jsds_FilterHook (jsdc, jsdthreadstate))
   571         return false;
   573     JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
   574     nsCOMPtr<jsdIStackFrame> frame =
   575         dont_AddRef(jsdStackFrame::FromPtr(jsdc, jsdthreadstate, native_frame));
   576     gJsds->DoPause(nullptr, true);
   577     hook->OnCall(frame, type);    
   578     gJsds->DoUnPause(nullptr, true);
   579     jsdStackFrame::InvalidateAll();
   581     return true;
   582 }
   584 static uint32_t
   585 jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
   586                         unsigned type, void* callerdata, jsval* rval)
   587 {
   588     nsCOMPtr<jsdIExecutionHook> hook(0);
   589     uint32_t hook_rv = JSD_HOOK_RETURN_CONTINUE;
   590     nsCOMPtr<jsdIValue> js_rv;
   592     switch (type)
   593     {
   594         case JSD_HOOK_INTERRUPTED:
   595             gJsds->GetInterruptHook(getter_AddRefs(hook));
   596             break;
   597         case JSD_HOOK_DEBUG_REQUESTED:
   598             gJsds->GetDebugHook(getter_AddRefs(hook));
   599             break;
   600         case JSD_HOOK_DEBUGGER_KEYWORD:
   601             gJsds->GetDebuggerHook(getter_AddRefs(hook));
   602             break;
   603         case JSD_HOOK_BREAKPOINT:
   604             {
   605                 /* we can't pause breakpoints the way we pause the other
   606                  * execution hooks (at least, not easily.)  Instead we bail
   607                  * here if the service is paused. */
   608                 uint32_t level;
   609                 gJsds->GetPauseDepth(&level);
   610                 if (!level)
   611                     gJsds->GetBreakpointHook(getter_AddRefs(hook));
   612             }
   613             break;
   614         case JSD_HOOK_THROW:
   615         {
   616             hook_rv = JSD_HOOK_RETURN_CONTINUE_THROW;
   617             gJsds->GetThrowHook(getter_AddRefs(hook));
   618             if (hook) {
   619                 JSDValue *jsdv = JSD_GetException (jsdc, jsdthreadstate);
   620                 js_rv = dont_AddRef(jsdValue::FromPtr (jsdc, jsdv));
   621             }
   622             break;
   623         }
   624         default:
   625             NS_ASSERTION (0, "Unknown hook type.");
   626     }
   628     if (!hook)
   629         return hook_rv;
   631     if (!jsds_FilterHook (jsdc, jsdthreadstate))
   632         return JSD_HOOK_RETURN_CONTINUE;
   634     JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
   635     nsCOMPtr<jsdIStackFrame> frame =
   636         dont_AddRef(jsdStackFrame::FromPtr(jsdc, jsdthreadstate, native_frame));
   637     gJsds->DoPause(nullptr, true);
   638     jsdIValue *inout_rv = js_rv;
   639     NS_IF_ADDREF(inout_rv);
   640     hook->OnExecute (frame, type, &inout_rv, &hook_rv);
   641     js_rv = inout_rv;
   642     NS_IF_RELEASE(inout_rv);
   643     gJsds->DoUnPause(nullptr, true);
   644     jsdStackFrame::InvalidateAll();
   646     if (hook_rv == JSD_HOOK_RETURN_RET_WITH_VAL ||
   647         hook_rv == JSD_HOOK_RETURN_THROW_WITH_VAL) {
   648         *rval = JSVAL_VOID;
   649         if (js_rv) {
   650             JSDValue *jsdv;
   651             if (NS_SUCCEEDED(js_rv->GetJSDValue (&jsdv)))
   652                 *rval = JSD_GetValueWrappedJSVal(jsdc, jsdv);
   653         }
   654     }
   656     return hook_rv;
   657 }
   659 static void
   660 jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, bool creating,
   661                      void* callerdata)
   662 {
   663 #ifdef CAUTIOUS_SCRIPTHOOK
   664     JSRuntime *rt = JS_GetRuntime(nsContentUtils::GetSafeJSContext());
   665 #endif
   667     if (creating) {
   668         nsCOMPtr<jsdIScriptHook> hook;
   669         gJsds->GetScriptHook(getter_AddRefs(hook));
   671         /* a script is being created */
   672         if (!hook) {
   673             /* nobody cares, just exit */
   674             return;
   675         }
   677         nsCOMPtr<jsdIScript> script = 
   678             dont_AddRef(jsdScript::FromPtr(jsdc, jsdscript));
   679 #ifdef CAUTIOUS_SCRIPTHOOK
   680         JS_UNKEEP_ATOMS(rt);
   681 #endif
   682         gJsds->DoPause(nullptr, true);
   683         hook->OnScriptCreated (script);
   684         gJsds->DoUnPause(nullptr, true);
   685 #ifdef CAUTIOUS_SCRIPTHOOK
   686         JS_KEEP_ATOMS(rt);
   687 #endif
   688     } else {
   689         /* a script is being destroyed.  even if there is no registered hook
   690          * we'll still need to invalidate the jsdIScript record, in order
   691          * to remove the reference held in the JSDScript private data. */
   692         nsCOMPtr<jsdIScript> jsdis = 
   693             static_cast<jsdIScript *>(JSD_GetScriptPrivate(jsdscript));
   694         if (!jsdis)
   695             return;
   697         jsdis->Invalidate();
   699         if (!gGCRunning) {
   700             nsCOMPtr<jsdIScriptHook> hook;
   701             gJsds->GetScriptHook(getter_AddRefs(hook));
   702             if (!hook)
   703                 return;
   705             /* if GC *isn't* running, we can tell the user about the script
   706              * delete now. */
   707 #ifdef CAUTIOUS_SCRIPTHOOK
   708             JS_UNKEEP_ATOMS(rt);
   709 #endif
   711             gJsds->DoPause(nullptr, true);
   712             hook->OnScriptDestroyed (jsdis);
   713             gJsds->DoUnPause(nullptr, true);
   714 #ifdef CAUTIOUS_SCRIPTHOOK
   715             JS_KEEP_ATOMS(rt);
   716 #endif
   717         } else {
   718             /* if a GC *is* running, we've got to wait until it's done before
   719              * we can execute any JS, so we queue the notification in a PRCList
   720              * until GC tells us it's done. See jsds_GCCallbackProc(). */
   721             DeadScript *ds = PR_NEW(DeadScript);
   722             if (!ds)
   723                 return; /* NS_ERROR_OUT_OF_MEMORY */
   725             ds->jsdc = jsdc;
   726             ds->script = jsdis;
   727             NS_ADDREF(ds->script);
   728             if (gDeadScripts)
   729                 /* if the queue exists, add to it */
   730                 PR_APPEND_LINK(&ds->links, &gDeadScripts->links);
   731             else {
   732                 /* otherwise create the queue */
   733                 PR_INIT_CLIST(&ds->links);
   734                 gDeadScripts = ds;
   735             }
   736         }
   737     }            
   738 }
   740 /*******************************************************************************
   741  * reflected jsd data structures
   742  *******************************************************************************/
   744 /* Contexts */
   745 /*
   746 NS_IMPL_ISUPPORTS(jsdContext, jsdIContext, jsdIEphemeral);
   748 NS_IMETHODIMP
   749 jsdContext::GetJSDContext(JSDContext **_rval)
   750 {
   751     *_rval = mCx;
   752     return NS_OK;
   753 }
   754 */
   756 /* Objects */
   757 NS_IMPL_ISUPPORTS(jsdObject, jsdIObject)
   759 NS_IMETHODIMP
   760 jsdObject::GetJSDContext(JSDContext **_rval)
   761 {
   762     *_rval = mCx;
   763     return NS_OK;
   764 }
   766 NS_IMETHODIMP
   767 jsdObject::GetJSDObject(JSDObject **_rval)
   768 {
   769     *_rval = mObject;
   770     return NS_OK;
   771 }
   773 NS_IMETHODIMP
   774 jsdObject::GetCreatorURL(nsACString &_rval)
   775 {
   776     _rval.Assign(JSD_GetObjectNewURL(mCx, mObject));
   777     return NS_OK;
   778 }
   780 NS_IMETHODIMP
   781 jsdObject::GetCreatorLine(uint32_t *_rval)
   782 {
   783     *_rval = JSD_GetObjectNewLineNumber(mCx, mObject);
   784     return NS_OK;
   785 }
   787 NS_IMETHODIMP
   788 jsdObject::GetConstructorURL(nsACString &_rval)
   789 {
   790     _rval.Assign(JSD_GetObjectConstructorURL(mCx, mObject));
   791     return NS_OK;
   792 }
   794 NS_IMETHODIMP
   795 jsdObject::GetConstructorLine(uint32_t *_rval)
   796 {
   797     *_rval = JSD_GetObjectConstructorLineNumber(mCx, mObject);
   798     return NS_OK;
   799 }
   801 NS_IMETHODIMP
   802 jsdObject::GetValue(jsdIValue **_rval)
   803 {
   804     JSDValue *jsdv = JSD_GetValueForObject (mCx, mObject);
   806     *_rval = jsdValue::FromPtr (mCx, jsdv);
   807     return NS_OK;
   808 }
   810 /* Properties */
   811 NS_IMPL_ISUPPORTS(jsdProperty, jsdIProperty, jsdIEphemeral)
   813 jsdProperty::jsdProperty (JSDContext *aCx, JSDProperty *aProperty) :
   814     mCx(aCx), mProperty(aProperty)
   815 {
   816     DEBUG_CREATE ("jsdProperty", gPropertyCount);
   817     mValid = (aCx && aProperty);
   818     mLiveListEntry.value = this;
   819     jsds_InsertEphemeral (&gLiveProperties, &mLiveListEntry);
   820 }
   822 jsdProperty::~jsdProperty () 
   823 {
   824     DEBUG_DESTROY ("jsdProperty", gPropertyCount);
   825     if (mValid)
   826         Invalidate();
   827 }
   829 NS_IMETHODIMP
   830 jsdProperty::Invalidate()
   831 {
   832     ASSERT_VALID_EPHEMERAL;
   833     mValid = false;
   834     jsds_RemoveEphemeral (&gLiveProperties, &mLiveListEntry);
   835     JSD_DropProperty (mCx, mProperty);
   836     return NS_OK;
   837 }
   839 void
   840 jsdProperty::InvalidateAll()
   841 {
   842     if (gLiveProperties)
   843         jsds_InvalidateAllEphemerals (&gLiveProperties);
   844 }
   846 NS_IMETHODIMP
   847 jsdProperty::GetJSDContext(JSDContext **_rval)
   848 {
   849     *_rval = mCx;
   850     return NS_OK;
   851 }
   853 NS_IMETHODIMP
   854 jsdProperty::GetJSDProperty(JSDProperty **_rval)
   855 {
   856     *_rval = mProperty;
   857     return NS_OK;
   858 }
   860 NS_IMETHODIMP
   861 jsdProperty::GetIsValid(bool *_rval)
   862 {
   863     *_rval = mValid;
   864     return NS_OK;
   865 }
   867 NS_IMETHODIMP
   868 jsdProperty::GetAlias(jsdIValue **_rval)
   869 {
   870     JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
   872     *_rval = jsdValue::FromPtr (mCx, jsdv);
   873     return NS_OK;
   874 }
   876 NS_IMETHODIMP
   877 jsdProperty::GetFlags(uint32_t *_rval)
   878 {
   879     *_rval = JSD_GetPropertyFlags (mCx, mProperty);
   880     return NS_OK;
   881 }
   883 NS_IMETHODIMP
   884 jsdProperty::GetName(jsdIValue **_rval)
   885 {
   886     JSDValue *jsdv = JSD_GetPropertyName (mCx, mProperty);
   888     *_rval = jsdValue::FromPtr (mCx, jsdv);
   889     return NS_OK;
   890 }
   892 NS_IMETHODIMP
   893 jsdProperty::GetValue(jsdIValue **_rval)
   894 {
   895     JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
   897     *_rval = jsdValue::FromPtr (mCx, jsdv);
   898     return NS_OK;
   899 }
   901 /* Scripts */
   902 NS_IMPL_ISUPPORTS(jsdScript, jsdIScript, jsdIEphemeral)
   904 static NS_IMETHODIMP
   905 AssignToJSString(JSDContext *aCx, nsACString *x, JSString *str_)
   906 {
   907     if (!str_) {
   908         x->SetLength(0);
   909         return NS_OK;
   910     }
   911     JS::RootedString str(JSD_GetJSRuntime(aCx), str_);
   912     AutoSafeJSContext cx;
   913     JSAutoCompartment ac(cx, JSD_GetDefaultGlobal(aCx)); // Just in case.
   914     size_t length = JS_GetStringEncodingLength(cx, str);
   915     if (length == size_t(-1))
   916         return NS_ERROR_FAILURE;
   917     x->SetLength(uint32_t(length));
   918     if (x->Length() != uint32_t(length))
   919         return NS_ERROR_OUT_OF_MEMORY;
   920     JS_EncodeStringToBuffer(cx, str, x->BeginWriting(), length);
   921     return NS_OK;
   922 }
   924 jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(false),
   925                                                              mTag(0),
   926                                                              mCx(aCx),
   927                                                              mScript(aScript),
   928                                                              mFileName(0), 
   929                                                              mFunctionName(0),
   930                                                              mBaseLineNumber(0),
   931                                                              mLineExtent(0),
   932                                                              mPPLineMap(0),
   933                                                              mFirstPC(0)
   934 {
   935     DEBUG_CREATE ("jsdScript", gScriptCount);
   937     if (mScript) {
   938         /* copy the script's information now, so we have it later, when it
   939          * gets destroyed. */
   940         JSD_LockScriptSubsystem(mCx);
   941         mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
   942         mFunctionName = new nsCString();
   943         if (mFunctionName) {
   944             JSString *str = JSD_GetScriptFunctionId(mCx, mScript);
   945             if (str)
   946                 AssignToJSString(mCx, mFunctionName, str);
   947         }
   948         mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
   949         mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
   950         mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
   951         JSD_UnlockScriptSubsystem(mCx);
   953         mValid = true;
   954     }
   955 }
   957 jsdScript::~jsdScript () 
   958 {
   959     DEBUG_DESTROY ("jsdScript", gScriptCount);
   960     delete mFileName;
   961     delete mFunctionName;
   963     if (mPPLineMap)
   964         PR_Free(mPPLineMap);
   966     /* Invalidate() needs to be called to release an owning reference to
   967      * ourselves, so if we got here without being invalidated, something
   968      * has gone wrong with our ref count. */
   969     NS_ASSERTION (!mValid, "Script destroyed without being invalidated.");
   970 }
   972 /*
   973  * This method populates a line <-> pc map for a pretty printed version of this
   974  * script.  It does this by decompiling, and then recompiling the script.  The
   975  * resulting script is scanned for the line map, and then left as GC fodder.
   976  */
   977 PCMapEntry *
   978 jsdScript::CreatePPLineMap()
   979 {
   980     AutoSafeJSContext cx;
   981     JSAutoCompartment ac(cx, JSD_GetDefaultGlobal (mCx)); // Just in case.
   982     JS::RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
   983     if (!obj)
   984         return nullptr;
   985     JS::RootedFunction fun(cx, JSD_GetJSFunction (mCx, mScript));
   986     JS::RootedScript script(cx); /* In JSD compartment */
   987     uint32_t    baseLine;
   988     JS::RootedString jsstr(cx);
   989     size_t      length;
   990     const jschar *chars;
   992     if (fun) {
   993         unsigned nargs;
   995         {
   996             JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
   997             nargs = JS_GetFunctionArgumentCount(cx, fun);
   998             if (nargs > 12)
   999                 return nullptr;
  1000             jsstr = JS_DecompileFunctionBody (cx, fun, 4);
  1001             if (!jsstr)
  1002                 return nullptr;
  1004             if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
  1005                 return nullptr;
  1008         JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
  1009         static const char *const argnames[] = {
  1010             "arg1", "arg2", "arg3", "arg4",
  1011             "arg5", "arg6", "arg7", "arg8",
  1012             "arg9", "arg10", "arg11", "arg12"
  1013         };
  1014         JS::CompileOptions options(cx);
  1015         options.setFileAndLine("x-jsd:ppbuffer?type=function", 3);
  1016         fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
  1017                                     length, options);
  1018         if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
  1019             return nullptr;
  1020         baseLine = 3;
  1021     } else {
  1022         script = JSD_GetJSScript(mCx, mScript);
  1023         JSString *jsstr;
  1026             JSAutoCompartment ac(cx, script);
  1028             jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
  1029             if (!jsstr)
  1030                 return nullptr;
  1032             if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
  1033                 return nullptr;
  1036         JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
  1037         JS::CompileOptions options(cx);
  1038         options.setFileAndLine("x-jsd:ppbuffer?type=script", 1);
  1039         script = JS_CompileUCScript(cx, obj, chars, length, options);
  1040         if (!script)
  1041             return nullptr;
  1042         baseLine = 1;
  1045     uint32_t scriptExtent = JS_GetScriptLineExtent (cx, script);
  1046     jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0);
  1047     /* allocate worst case size of map (number of lines in script + 1
  1048      * for our 0 record), we'll shrink it with a realloc later. */
  1049     PCMapEntry *lineMap =
  1050         static_cast<PCMapEntry *>
  1051                    (PR_Malloc((scriptExtent + 1) * sizeof (PCMapEntry)));
  1052     uint32_t lineMapSize = 0;
  1054     if (lineMap) {
  1055         for (uint32_t line = baseLine; line < scriptExtent + baseLine; ++line) {
  1056             jsbytecode* pc = JS_LineNumberToPC (cx, script, line);
  1057             if (line == JS_PCToLineNumber (cx, script, pc)) {
  1058                 lineMap[lineMapSize].line = line;
  1059                 lineMap[lineMapSize].pc = pc - firstPC;
  1060                 ++lineMapSize;
  1063         if (scriptExtent != lineMapSize) {
  1064             lineMap =
  1065                 static_cast<PCMapEntry *>
  1066                            (PR_Realloc(mPPLineMap = lineMap,
  1067                                        lineMapSize * sizeof(PCMapEntry)));
  1068             if (!lineMap) {
  1069                 PR_Free(mPPLineMap);
  1070                 lineMapSize = 0;
  1075     mPCMapSize = lineMapSize;
  1076     return mPPLineMap = lineMap;
  1079 uint32_t
  1080 jsdScript::PPPcToLine (uint32_t aPC)
  1082     if (!mPPLineMap && !CreatePPLineMap())
  1083         return 0;
  1084     uint32_t i;
  1085     for (i = 1; i < mPCMapSize; ++i) {
  1086         if (mPPLineMap[i].pc > aPC)
  1087             return mPPLineMap[i - 1].line;            
  1090     return mPPLineMap[mPCMapSize - 1].line;
  1093 uint32_t
  1094 jsdScript::PPLineToPc (uint32_t aLine)
  1096     if (!mPPLineMap && !CreatePPLineMap())
  1097         return 0;
  1098     uint32_t i;
  1099     for (i = 1; i < mPCMapSize; ++i) {
  1100         if (mPPLineMap[i].line > aLine)
  1101             return mPPLineMap[i - 1].pc;
  1104     return mPPLineMap[mPCMapSize - 1].pc;
  1107 NS_IMETHODIMP
  1108 jsdScript::GetJSDContext(JSDContext **_rval)
  1110     ASSERT_VALID_EPHEMERAL;
  1111     *_rval = mCx;
  1112     return NS_OK;
  1115 NS_IMETHODIMP
  1116 jsdScript::GetJSDScript(JSDScript **_rval)
  1118     ASSERT_VALID_EPHEMERAL;
  1119     *_rval = mScript;
  1120     return NS_OK;
  1123 NS_IMETHODIMP
  1124 jsdScript::GetVersion (int32_t *_rval)
  1126     ASSERT_VALID_EPHEMERAL;
  1127     AutoSafeJSContext cx;
  1128     JS::RootedScript script(cx, JSD_GetJSScript(mCx, mScript));
  1129     JSAutoCompartment ac(cx, script);
  1130     *_rval = static_cast<int32_t>(JS_GetScriptVersion(cx, script));
  1131     return NS_OK;
  1134 NS_IMETHODIMP
  1135 jsdScript::GetTag(uint32_t *_rval)
  1137     if (!mTag)
  1138         mTag = ++jsdScript::LastTag;
  1140     *_rval = mTag;
  1141     return NS_OK;
  1144 NS_IMETHODIMP
  1145 jsdScript::Invalidate()
  1147     ASSERT_VALID_EPHEMERAL;
  1148     mValid = false;
  1150     /* release the addref we do in FromPtr */
  1151     jsdIScript *script = static_cast<jsdIScript *>
  1152                                     (JSD_GetScriptPrivate(mScript));
  1153     NS_ASSERTION (script == this, "That's not my script!");
  1154     NS_RELEASE(script);
  1155     JSD_SetScriptPrivate(mScript, nullptr);
  1156     return NS_OK;
  1159 void
  1160 jsdScript::InvalidateAll ()
  1162     JSDContext *cx;
  1163     if (NS_FAILED(gJsds->GetJSDContext (&cx)))
  1164         return;
  1166     JSDScript *script;
  1167     JSDScript *iter = nullptr;
  1169     JSD_LockScriptSubsystem(cx);
  1170     while((script = JSD_IterateScripts(cx, &iter)) != nullptr) {
  1171         nsCOMPtr<jsdIScript> jsdis = 
  1172             static_cast<jsdIScript *>(JSD_GetScriptPrivate(script));
  1173         if (jsdis)
  1174             jsdis->Invalidate();
  1176     JSD_UnlockScriptSubsystem(cx);
  1179 NS_IMETHODIMP
  1180 jsdScript::GetIsValid(bool *_rval)
  1182     *_rval = mValid;
  1183     return NS_OK;
  1186 NS_IMETHODIMP
  1187 jsdScript::SetFlags(uint32_t flags)
  1189     ASSERT_VALID_EPHEMERAL;
  1190     JSD_SetScriptFlags(mCx, mScript, flags);
  1191     return NS_OK;
  1194 NS_IMETHODIMP
  1195 jsdScript::GetFlags(uint32_t *_rval)
  1197     ASSERT_VALID_EPHEMERAL;
  1198     *_rval = JSD_GetScriptFlags(mCx, mScript);
  1199     return NS_OK;
  1202 NS_IMETHODIMP
  1203 jsdScript::GetFileName(nsACString &_rval)
  1205     _rval.Assign(*mFileName);
  1206     return NS_OK;
  1209 NS_IMETHODIMP
  1210 jsdScript::GetFunctionName(nsACString &_rval)
  1212     _rval.Assign(*mFunctionName);
  1213     return NS_OK;
  1216 NS_IMETHODIMP
  1217 jsdScript::GetParameterNames(uint32_t* count, char16_t*** paramNames)
  1219     ASSERT_VALID_EPHEMERAL;
  1220     AutoSafeJSContext cx;
  1221     JS::RootedFunction fun(cx, JSD_GetJSFunction (mCx, mScript));
  1222     if (!fun) {
  1223         *count = 0;
  1224         *paramNames = nullptr;
  1225         return NS_OK;
  1228     JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
  1230     unsigned nargs;
  1231     if (!JS_FunctionHasLocalNames(cx, fun) ||
  1232         (nargs = JS_GetFunctionArgumentCount(cx, fun)) == 0) {
  1233         *count = 0;
  1234         *paramNames = nullptr;
  1235         return NS_OK;
  1238     char16_t **ret =
  1239         static_cast<char16_t**>(NS_Alloc(nargs * sizeof(char16_t*)));
  1240     if (!ret)
  1241         return NS_ERROR_OUT_OF_MEMORY;
  1243     void *mark;
  1244     uintptr_t *names = JS_GetFunctionLocalNameArray(cx, fun, &mark);
  1245     if (!names) {
  1246         NS_Free(ret);
  1247         return NS_ERROR_OUT_OF_MEMORY;
  1250     nsresult rv = NS_OK;
  1251     for (unsigned i = 0; i < nargs; ++i) {
  1252         JSAtom *atom = JS_LocalNameToAtom(names[i]);
  1253         if (!atom) {
  1254             ret[i] = 0;
  1255         } else {
  1256             JSString *str = JS_AtomKey(atom);
  1257             ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str));
  1258             if (!ret[i]) {
  1259                 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
  1260                 rv = NS_ERROR_OUT_OF_MEMORY;
  1261                 break;
  1265     JS_ReleaseFunctionLocalNameArray(cx, mark);
  1266     if (NS_FAILED(rv))
  1267         return rv;
  1268     *count = nargs;
  1269     *paramNames = ret;
  1270     return NS_OK;
  1273 NS_IMETHODIMP
  1274 jsdScript::GetFunctionObject(jsdIValue **_rval)
  1276     JS::RootedFunction fun(JSD_GetJSRuntime(mCx), JSD_GetJSFunction(mCx, mScript));
  1277     if (!fun)
  1278         return NS_ERROR_NOT_AVAILABLE;
  1280     AutoSafeJSContext jsContext;
  1281     JS::RootedObject obj(jsContext, JS_GetFunctionObject(fun));
  1282     if (!obj)
  1283         return NS_ERROR_FAILURE;
  1285     JSDContext *cx;
  1286     if (NS_FAILED(gJsds->GetJSDContext (&cx)))
  1287         return NS_ERROR_NOT_INITIALIZED;
  1289     JSDValue *jsdv = JSD_NewValue(cx, OBJECT_TO_JSVAL(obj));
  1290     if (!jsdv)
  1291         return NS_ERROR_OUT_OF_MEMORY;
  1293     *_rval = jsdValue::FromPtr(cx, jsdv);
  1294     if (!*_rval) {
  1295         JSD_DropValue(cx, jsdv);
  1296         return NS_ERROR_OUT_OF_MEMORY;
  1299     return NS_OK;
  1302 NS_IMETHODIMP
  1303 jsdScript::GetFunctionSource(nsAString & aFunctionSource)
  1305     ASSERT_VALID_EPHEMERAL;
  1306     AutoSafeJSContext cx_;
  1307     JSContext *cx = cx_; // Appease the type system with Maybe<>s below.
  1308     JS::RootedFunction fun(cx, JSD_GetJSFunction (mCx, mScript));
  1310     JSString *jsstr;
  1311     mozilla::Maybe<JSAutoCompartment> ac;
  1312     if (fun) {
  1313         ac.construct(cx, JS_GetFunctionObject(fun));
  1314         jsstr = JS_DecompileFunction (cx, fun, 4);
  1315     } else {
  1316         JS::RootedScript script(cx, JSD_GetJSScript (mCx, mScript));
  1317         ac.construct(cx, script);
  1318         jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
  1320     if (!jsstr)
  1321         return NS_ERROR_FAILURE;
  1323     size_t length;
  1324     const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length);
  1325     if (!chars)
  1326         return NS_ERROR_FAILURE;
  1328     aFunctionSource = nsDependentString(chars, length);
  1329     return NS_OK;
  1332 NS_IMETHODIMP
  1333 jsdScript::GetBaseLineNumber(uint32_t *_rval)
  1335     *_rval = mBaseLineNumber;
  1336     return NS_OK;
  1339 NS_IMETHODIMP
  1340 jsdScript::GetLineExtent(uint32_t *_rval)
  1342     *_rval = mLineExtent;
  1343     return NS_OK;
  1346 NS_IMETHODIMP
  1347 jsdScript::GetCallCount(uint32_t *_rval)
  1349     ASSERT_VALID_EPHEMERAL;
  1350     *_rval = JSD_GetScriptCallCount (mCx, mScript);
  1351     return NS_OK;
  1354 NS_IMETHODIMP
  1355 jsdScript::GetMaxRecurseDepth(uint32_t *_rval)
  1357     ASSERT_VALID_EPHEMERAL;
  1358     *_rval = JSD_GetScriptMaxRecurseDepth (mCx, mScript);
  1359     return NS_OK;
  1362 NS_IMETHODIMP
  1363 jsdScript::GetMinExecutionTime(double *_rval)
  1365     ASSERT_VALID_EPHEMERAL;
  1366     *_rval = JSD_GetScriptMinExecutionTime (mCx, mScript);
  1367     return NS_OK;
  1370 NS_IMETHODIMP
  1371 jsdScript::GetMaxExecutionTime(double *_rval)
  1373     ASSERT_VALID_EPHEMERAL;
  1374     *_rval = JSD_GetScriptMaxExecutionTime (mCx, mScript);
  1375     return NS_OK;
  1378 NS_IMETHODIMP
  1379 jsdScript::GetTotalExecutionTime(double *_rval)
  1381     ASSERT_VALID_EPHEMERAL;
  1382     *_rval = JSD_GetScriptTotalExecutionTime (mCx, mScript);
  1383     return NS_OK;
  1386 NS_IMETHODIMP
  1387 jsdScript::GetMinOwnExecutionTime(double *_rval)
  1389     ASSERT_VALID_EPHEMERAL;
  1390     *_rval = JSD_GetScriptMinOwnExecutionTime (mCx, mScript);
  1391     return NS_OK;
  1394 NS_IMETHODIMP
  1395 jsdScript::GetMaxOwnExecutionTime(double *_rval)
  1397     ASSERT_VALID_EPHEMERAL;
  1398     *_rval = JSD_GetScriptMaxOwnExecutionTime (mCx, mScript);
  1399     return NS_OK;
  1402 NS_IMETHODIMP
  1403 jsdScript::GetTotalOwnExecutionTime(double *_rval)
  1405     ASSERT_VALID_EPHEMERAL;
  1406     *_rval = JSD_GetScriptTotalOwnExecutionTime (mCx, mScript);
  1407     return NS_OK;
  1410 NS_IMETHODIMP
  1411 jsdScript::ClearProfileData()
  1413     ASSERT_VALID_EPHEMERAL;
  1414     JSD_ClearScriptProfileData(mCx, mScript);
  1415     return NS_OK;
  1418 NS_IMETHODIMP
  1419 jsdScript::PcToLine(uint32_t aPC, uint32_t aPcmap, uint32_t *_rval)
  1421     ASSERT_VALID_EPHEMERAL;
  1422     if (aPcmap == PCMAP_SOURCETEXT) {
  1423         *_rval = JSD_GetClosestLine (mCx, mScript, mFirstPC + aPC);
  1424     } else if (aPcmap == PCMAP_PRETTYPRINT) {
  1425         *_rval = PPPcToLine(aPC);
  1426     } else {
  1427         return NS_ERROR_INVALID_ARG;
  1430     return NS_OK;
  1433 NS_IMETHODIMP
  1434 jsdScript::LineToPc(uint32_t aLine, uint32_t aPcmap, uint32_t *_rval)
  1436     ASSERT_VALID_EPHEMERAL;
  1437     if (aPcmap == PCMAP_SOURCETEXT) {
  1438         uintptr_t pc = JSD_GetClosestPC (mCx, mScript, aLine);
  1439         *_rval = pc - mFirstPC;
  1440     } else if (aPcmap == PCMAP_PRETTYPRINT) {
  1441         *_rval = PPLineToPc(aLine);
  1442     } else {
  1443         return NS_ERROR_INVALID_ARG;
  1446     return NS_OK;
  1449 NS_IMETHODIMP
  1450 jsdScript::EnableSingleStepInterrupts(bool enable)
  1452     ASSERT_VALID_EPHEMERAL;
  1454     /* Must have set interrupt hook before enabling */
  1455     if (enable && !jsdService::GetService()->CheckInterruptHook())
  1456         return NS_ERROR_NOT_INITIALIZED;
  1458     return (JSD_EnableSingleStepInterrupts(mCx, mScript, enable) ? NS_OK : NS_ERROR_FAILURE);
  1461 NS_IMETHODIMP
  1462 jsdScript::GetExecutableLines(uint32_t aPcmap, uint32_t aStartLine, uint32_t aMaxLines,
  1463                               uint32_t* aCount, uint32_t** aExecutableLines)
  1465     ASSERT_VALID_EPHEMERAL;
  1466     if (aPcmap == PCMAP_SOURCETEXT) {
  1467         uintptr_t start = JSD_GetClosestPC(mCx, mScript, 0);
  1468         unsigned lastLine = JSD_GetScriptBaseLineNumber(mCx, mScript)
  1469                        + JSD_GetScriptLineExtent(mCx, mScript) - 1;
  1470         uintptr_t end = JSD_GetClosestPC(mCx, mScript, lastLine + 1);
  1472         *aExecutableLines = static_cast<uint32_t*>(NS_Alloc((end - start + 1) * sizeof(uint32_t)));
  1473         if (!JSD_GetLinePCs(mCx, mScript, aStartLine, aMaxLines, aCount, aExecutableLines,
  1474                             nullptr))
  1475             return NS_ERROR_OUT_OF_MEMORY;
  1477         return NS_OK;
  1480     if (aPcmap == PCMAP_PRETTYPRINT) {
  1481         if (!mPPLineMap) {
  1482             if (!CreatePPLineMap())
  1483                 return NS_ERROR_OUT_OF_MEMORY;
  1486         nsTArray<uint32_t> lines;
  1487         uint32_t i;
  1489         for (i = 0; i < mPCMapSize; ++i) {
  1490             if (mPPLineMap[i].line >= aStartLine)
  1491                 break;
  1494         for (; i < mPCMapSize && lines.Length() < aMaxLines; ++i) {
  1495             lines.AppendElement(mPPLineMap[i].line);
  1498         if (aCount)
  1499             *aCount = lines.Length();
  1501         *aExecutableLines = static_cast<uint32_t*>(NS_Alloc(lines.Length() * sizeof(uint32_t)));
  1502         if (!*aExecutableLines)
  1503             return NS_ERROR_OUT_OF_MEMORY;
  1505         for (i = 0; i < lines.Length(); ++i)
  1506             (*aExecutableLines)[i] = lines[i];
  1508         return NS_OK;
  1511     return NS_ERROR_INVALID_ARG;
  1514 NS_IMETHODIMP
  1515 jsdScript::IsLineExecutable(uint32_t aLine, uint32_t aPcmap, bool *_rval)
  1517     ASSERT_VALID_EPHEMERAL;
  1518     if (aPcmap == PCMAP_SOURCETEXT) {    
  1519         uintptr_t pc = JSD_GetClosestPC (mCx, mScript, aLine);
  1520         *_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc));
  1521     } else if (aPcmap == PCMAP_PRETTYPRINT) {
  1522         if (!mPPLineMap && !CreatePPLineMap())
  1523             return NS_ERROR_OUT_OF_MEMORY;
  1524         *_rval = false;
  1525         for (uint32_t i = 0; i < mPCMapSize; ++i) {
  1526             if (mPPLineMap[i].line >= aLine) {
  1527                 *_rval = (mPPLineMap[i].line == aLine);
  1528                 break;
  1531     } else {
  1532         return NS_ERROR_INVALID_ARG;
  1535     return NS_OK;
  1538 NS_IMETHODIMP
  1539 jsdScript::SetBreakpoint(uint32_t aPC)
  1541     ASSERT_VALID_EPHEMERAL;
  1542     uintptr_t pc = mFirstPC + aPC;
  1543     JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, nullptr);
  1544     return NS_OK;
  1547 NS_IMETHODIMP
  1548 jsdScript::ClearBreakpoint(uint32_t aPC)
  1550     ASSERT_VALID_EPHEMERAL;    
  1551     uintptr_t pc = mFirstPC + aPC;
  1552     JSD_ClearExecutionHook (mCx, mScript, pc);
  1553     return NS_OK;
  1556 NS_IMETHODIMP
  1557 jsdScript::ClearAllBreakpoints()
  1559     ASSERT_VALID_EPHEMERAL;
  1560     JSD_LockScriptSubsystem(mCx);
  1561     JSD_ClearAllExecutionHooksForScript (mCx, mScript);
  1562     JSD_UnlockScriptSubsystem(mCx);
  1563     return NS_OK;
  1566 /* Contexts */
  1567 NS_IMPL_ISUPPORTS(jsdContext, jsdIContext, jsdIEphemeral)
  1569 jsdIContext *
  1570 jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx)
  1572     if (!aJSDCx || !aJSCx)
  1573         return nullptr;
  1575     nsCOMPtr<jsdIContext> jsdicx;
  1576     nsCOMPtr<jsdIEphemeral> eph = 
  1577         jsds_FindEphemeral (&gLiveContexts, static_cast<void *>(aJSCx));
  1578     if (eph)
  1580         jsdicx = do_QueryInterface(eph);
  1582     else
  1584         nsCOMPtr<nsISupports> iscx;
  1585         if (JS::ContextOptionsRef(aJSCx).privateIsNSISupports())
  1586             iscx = static_cast<nsISupports *>(JS_GetContextPrivate(aJSCx));
  1587         jsdicx = new jsdContext (aJSDCx, aJSCx, iscx);
  1590     jsdIContext *ctx = nullptr;
  1591     jsdicx.swap(ctx);
  1592     return ctx;
  1595 jsdContext::jsdContext (JSDContext *aJSDCx, JSContext *aJSCx,
  1596                         nsISupports *aISCx) : mValid(true),
  1597                                               mScriptDisabledForWindowWithID(0),
  1598                                               mTag(0),
  1599                                               mJSDCx(aJSDCx),
  1600                                               mJSCx(aJSCx), mISCx(aISCx)
  1602     DEBUG_CREATE ("jsdContext", gContextCount);
  1603     mLiveListEntry.value = this;
  1604     mLiveListEntry.key   = static_cast<void *>(aJSCx);
  1605     jsds_InsertEphemeral (&gLiveContexts, &mLiveListEntry);
  1608 jsdContext::~jsdContext() 
  1610     DEBUG_DESTROY ("jsdContext", gContextCount);
  1611     if (mValid)
  1613         /* call Invalidate() to take ourselves out of the live list */
  1614         Invalidate();
  1618 NS_IMETHODIMP
  1619 jsdContext::GetIsValid(bool *_rval)
  1621     *_rval = mValid;
  1622     return NS_OK;
  1625 NS_IMETHODIMP
  1626 jsdContext::Invalidate()
  1628     ASSERT_VALID_EPHEMERAL;
  1629     mValid = false;
  1630     jsds_RemoveEphemeral (&gLiveContexts, &mLiveListEntry);
  1631     return NS_OK;
  1634 void
  1635 jsdContext::InvalidateAll()
  1637     if (gLiveContexts)
  1638         jsds_InvalidateAllEphemerals (&gLiveContexts);
  1641 NS_IMETHODIMP
  1642 jsdContext::GetJSContext(JSContext **_rval)
  1644     ASSERT_VALID_EPHEMERAL;
  1645     *_rval = mJSCx;
  1646     return NS_OK;
  1649 /* Simulate the old options API in terms of the new one for backwards
  1650  * compatibility */
  1652 #define JSOPTION_EXTRA_WARNINGS                 JS_BIT(0)
  1653 #define JSOPTION_WERROR                         JS_BIT(1)
  1654 #define JSOPTION_VAROBJFIX                      JS_BIT(2)
  1655 #define JSOPTION_PRIVATE_IS_NSISUPPORTS         JS_BIT(3)
  1656 #define JSOPTION_DONT_REPORT_UNCAUGHT           JS_BIT(8)
  1657 #define JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT  JS_BIT(11)
  1658 #define JSOPTION_NO_SCRIPT_RVAL                 JS_BIT(12)
  1659 #define JSOPTION_STRICT_MODE                    JS_BIT(17)
  1660 #define JSOPTION_MASK                           JS_BITMASK(20)
  1662 NS_IMETHODIMP
  1663 jsdContext::GetOptions(uint32_t *_rval)
  1665     ASSERT_VALID_EPHEMERAL;
  1666     *_rval = (JS::ContextOptionsRef(mJSCx).extraWarnings() ? JSOPTION_EXTRA_WARNINGS : 0)
  1667            | (JS::ContextOptionsRef(mJSCx).werror() ? JSOPTION_WERROR : 0)
  1668            | (JS::ContextOptionsRef(mJSCx).varObjFix() ? JSOPTION_VAROBJFIX : 0)
  1669            | (JS::ContextOptionsRef(mJSCx).privateIsNSISupports() ? JSOPTION_PRIVATE_IS_NSISUPPORTS : 0)
  1670            | (JS::ContextOptionsRef(mJSCx).dontReportUncaught() ? JSOPTION_DONT_REPORT_UNCAUGHT : 0)
  1671            | (JS::ContextOptionsRef(mJSCx).noDefaultCompartmentObject() ? JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT : 0)
  1672            | (JS::ContextOptionsRef(mJSCx).noScriptRval() ? JSOPTION_NO_SCRIPT_RVAL : 0)
  1673            | (JS::ContextOptionsRef(mJSCx).strictMode() ? JSOPTION_STRICT_MODE : 0);
  1674     return NS_OK;
  1677 NS_IMETHODIMP
  1678 jsdContext::SetOptions(uint32_t options)
  1680     ASSERT_VALID_EPHEMERAL;
  1682     /* don't let users change this option, they'd just be shooting themselves
  1683      * in the foot. */
  1684     if (JS::ContextOptionsRef(mJSCx).privateIsNSISupports() !=
  1685         (options & JSOPTION_PRIVATE_IS_NSISUPPORTS))
  1686         return NS_ERROR_ILLEGAL_VALUE;
  1688     JS::ContextOptionsRef(mJSCx).setExtraWarnings(options & JSOPTION_EXTRA_WARNINGS)
  1689                                 .setWerror(options & JSOPTION_WERROR)
  1690                                 .setVarObjFix(options & JSOPTION_VAROBJFIX)
  1691                                 .setDontReportUncaught(options & JSOPTION_DONT_REPORT_UNCAUGHT)
  1692                                 .setNoDefaultCompartmentObject(options & JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT)
  1693                                 .setNoScriptRval(options & JSOPTION_NO_SCRIPT_RVAL)
  1694                                 .setStrictMode(options & JSOPTION_STRICT_MODE);
  1695     return NS_OK;
  1698 NS_IMETHODIMP
  1699 jsdContext::GetPrivateData(nsISupports **_rval)
  1701     ASSERT_VALID_EPHEMERAL;
  1702     if (JS::ContextOptionsRef(mJSCx).privateIsNSISupports()) 
  1704         *_rval = static_cast<nsISupports*>(JS_GetContextPrivate(mJSCx));
  1705         NS_IF_ADDREF(*_rval);
  1707     else
  1709         *_rval = nullptr;
  1712     return NS_OK;
  1715 NS_IMETHODIMP
  1716 jsdContext::GetWrappedContext(nsISupports **_rval)
  1718     ASSERT_VALID_EPHEMERAL;
  1719     NS_IF_ADDREF(*_rval = mISCx);
  1720     return NS_OK;
  1723 NS_IMETHODIMP
  1724 jsdContext::GetTag(uint32_t *_rval)
  1726     ASSERT_VALID_EPHEMERAL;
  1727     if (!mTag)
  1728         mTag = ++jsdContext::LastTag;
  1730     *_rval = mTag;
  1731     return NS_OK;
  1734 NS_IMETHODIMP
  1735 jsdContext::GetGlobalObject (jsdIValue **_rval)
  1737     ASSERT_VALID_EPHEMERAL;
  1738     JSObject *glob = GetDefaultScopeFromJSContext(mJSCx);
  1739     JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
  1740     if (!jsdv)
  1741         return NS_ERROR_FAILURE;
  1742     *_rval = jsdValue::FromPtr (mJSDCx, jsdv);
  1743     if (!*_rval)
  1744         return NS_ERROR_FAILURE;
  1745     return NS_OK;
  1748 NS_IMETHODIMP
  1749 jsdContext::GetScriptsEnabled (bool *_rval)
  1751     ASSERT_VALID_EPHEMERAL;
  1752     *_rval = IsScriptEnabled();
  1753     return NS_OK;
  1756 NS_IMETHODIMP
  1757 jsdContext::SetScriptsEnabled (bool _rval)
  1759     ASSERT_VALID_EPHEMERAL;
  1760     if (_rval == IsScriptEnabled())
  1761         return NS_OK;
  1763     nsCOMPtr<nsIScriptContext> scx = do_QueryInterface(mISCx);
  1764     NS_ENSURE_TRUE(scx && scx->GetWindowProxy(), NS_ERROR_NO_INTERFACE);
  1765     nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(scx->GetGlobalObject());
  1766     NS_ENSURE_TRUE(piWin, NS_ERROR_NO_INTERFACE);
  1767     uint64_t currentWindowID = piWin->WindowID();
  1769     if (_rval) {
  1770         if (mScriptDisabledForWindowWithID != currentWindowID) {
  1771             NS_WARNING("Please stop abusing JSD and fix your code!");
  1772             return NS_ERROR_UNEXPECTED;
  1774         xpc::Scriptability::Get(scx->GetWindowProxy()).Unblock();
  1775         piWin->ResumeTimeouts();
  1776         mScriptDisabledForWindowWithID = 0;
  1778     else {
  1779         piWin->SuspendTimeouts();
  1780         xpc::Scriptability::Get(scx->GetWindowProxy()).Block();
  1781         mScriptDisabledForWindowWithID = currentWindowID;
  1784     return NS_OK;
  1787 /* Stack Frames */
  1788 NS_IMPL_ISUPPORTS(jsdStackFrame, jsdIStackFrame, jsdIEphemeral)
  1790 jsdStackFrame::jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState,
  1791                               JSDStackFrameInfo *aStackFrameInfo) :
  1792     mCx(aCx), mThreadState(aThreadState), mStackFrameInfo(aStackFrameInfo)
  1794     DEBUG_CREATE ("jsdStackFrame", gFrameCount);
  1795     mValid = (aCx && aThreadState && aStackFrameInfo);
  1796     if (mValid) {
  1797         mLiveListEntry.key = aStackFrameInfo;
  1798         mLiveListEntry.value = this;
  1799         jsds_InsertEphemeral (&gLiveStackFrames, &mLiveListEntry);
  1803 jsdStackFrame::~jsdStackFrame() 
  1805     DEBUG_DESTROY ("jsdStackFrame", gFrameCount);
  1806     if (mValid)
  1808         /* call Invalidate() to take ourselves out of the live list */
  1809         Invalidate();
  1813 jsdIStackFrame *
  1814 jsdStackFrame::FromPtr (JSDContext *aCx, JSDThreadState *aThreadState,
  1815                         JSDStackFrameInfo *aStackFrameInfo)
  1817     if (!aStackFrameInfo)
  1818         return nullptr;
  1820     jsdIStackFrame *rv;
  1821     nsCOMPtr<jsdIStackFrame> frame;
  1823     nsCOMPtr<jsdIEphemeral> eph =
  1824         jsds_FindEphemeral (&gLiveStackFrames,
  1825                             reinterpret_cast<void *>(aStackFrameInfo));
  1827     if (eph)
  1829         frame = do_QueryInterface(eph);
  1830         rv = frame;
  1832     else
  1834         rv = new jsdStackFrame (aCx, aThreadState, aStackFrameInfo);
  1837     NS_IF_ADDREF(rv);
  1838     return rv;
  1841 NS_IMETHODIMP
  1842 jsdStackFrame::Invalidate()
  1844     ASSERT_VALID_EPHEMERAL;
  1845     mValid = false;
  1846     jsds_RemoveEphemeral (&gLiveStackFrames, &mLiveListEntry);
  1847     return NS_OK;
  1850 void
  1851 jsdStackFrame::InvalidateAll()
  1853     if (gLiveStackFrames)
  1854         jsds_InvalidateAllEphemerals (&gLiveStackFrames);
  1857 NS_IMETHODIMP
  1858 jsdStackFrame::GetJSDContext(JSDContext **_rval)
  1860     ASSERT_VALID_EPHEMERAL;
  1861     *_rval = mCx;
  1862     return NS_OK;
  1865 NS_IMETHODIMP
  1866 jsdStackFrame::GetJSDThreadState(JSDThreadState **_rval)
  1868     ASSERT_VALID_EPHEMERAL;
  1869     *_rval = mThreadState;
  1870     return NS_OK;
  1873 NS_IMETHODIMP
  1874 jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo **_rval)
  1876     ASSERT_VALID_EPHEMERAL;
  1877     *_rval = mStackFrameInfo;
  1878     return NS_OK;
  1881 NS_IMETHODIMP
  1882 jsdStackFrame::GetIsValid(bool *_rval)
  1884     *_rval = mValid;
  1885     return NS_OK;
  1888 NS_IMETHODIMP
  1889 jsdStackFrame::GetCallingFrame(jsdIStackFrame **_rval)
  1891     ASSERT_VALID_EPHEMERAL;
  1892     JSDStackFrameInfo *sfi = JSD_GetCallingStackFrame (mCx, mThreadState,
  1893                                                        mStackFrameInfo);
  1894     *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
  1895     return NS_OK;
  1898 NS_IMETHODIMP
  1899 jsdStackFrame::GetExecutionContext(jsdIContext **_rval)
  1901     ASSERT_VALID_EPHEMERAL;
  1902     JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
  1903     *_rval = jsdContext::FromPtr (mCx, cx);
  1904     return NS_OK;
  1907 NS_IMETHODIMP
  1908 jsdStackFrame::GetFunctionName(nsACString &_rval)
  1910     ASSERT_VALID_EPHEMERAL;
  1911     JSString *str = JSD_GetIdForStackFrame(mCx, mThreadState, mStackFrameInfo);
  1912     if (str)
  1913         return AssignToJSString(mCx, &_rval, str);
  1915     _rval.Assign("anonymous");
  1916     return NS_OK;
  1919 NS_IMETHODIMP
  1920 jsdStackFrame::GetIsDebugger(bool *_rval)
  1922     ASSERT_VALID_EPHEMERAL;
  1923     *_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo);
  1924     return NS_OK;
  1927 NS_IMETHODIMP
  1928 jsdStackFrame::GetIsConstructing(bool *_rval)
  1930     ASSERT_VALID_EPHEMERAL;
  1931     *_rval = JSD_IsStackFrameConstructing (mCx, mThreadState, mStackFrameInfo);
  1932     return NS_OK;
  1935 NS_IMETHODIMP
  1936 jsdStackFrame::GetScript(jsdIScript **_rval)
  1938     ASSERT_VALID_EPHEMERAL;
  1939     JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
  1940                                                     mStackFrameInfo);
  1941     *_rval = jsdScript::FromPtr (mCx, script);
  1942     return NS_OK;
  1945 NS_IMETHODIMP
  1946 jsdStackFrame::GetPc(uint32_t *_rval)
  1948     ASSERT_VALID_EPHEMERAL;
  1949     JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
  1950                                                     mStackFrameInfo);
  1951     if (!script)
  1952         return NS_ERROR_FAILURE;
  1953     uintptr_t pcbase = JSD_GetClosestPC(mCx, script, 0);
  1955     uintptr_t pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
  1956     if (pc)
  1957         *_rval = pc - pcbase;
  1958     else
  1959         *_rval = pcbase;
  1960     return NS_OK;
  1963 NS_IMETHODIMP
  1964 jsdStackFrame::GetLine(uint32_t *_rval)
  1966     ASSERT_VALID_EPHEMERAL;
  1967     JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
  1968                                                     mStackFrameInfo);
  1969     if (script) {
  1970         uintptr_t pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
  1971         *_rval = JSD_GetClosestLine (mCx, script, pc);
  1972     } else {
  1973         return NS_ERROR_FAILURE;
  1975     return NS_OK;
  1978 NS_IMETHODIMP
  1979 jsdStackFrame::GetCallee(jsdIValue **_rval)
  1981     ASSERT_VALID_EPHEMERAL;
  1982     JSDValue *jsdv = JSD_GetCallObjectForStackFrame (mCx, mThreadState,
  1983                                                      mStackFrameInfo);
  1985     *_rval = jsdValue::FromPtr (mCx, jsdv);
  1986     return NS_OK;
  1989 NS_IMETHODIMP
  1990 jsdStackFrame::GetScope(jsdIValue **_rval)
  1992     ASSERT_VALID_EPHEMERAL;
  1993     JSDValue *jsdv = JSD_GetScopeChainForStackFrame (mCx, mThreadState,
  1994                                                      mStackFrameInfo);
  1996     *_rval = jsdValue::FromPtr (mCx, jsdv);
  1997     return NS_OK;
  2000 NS_IMETHODIMP
  2001 jsdStackFrame::GetThisValue(jsdIValue **_rval)
  2003     ASSERT_VALID_EPHEMERAL;
  2004     JSDValue *jsdv = JSD_GetThisForStackFrame (mCx, mThreadState,
  2005                                                mStackFrameInfo);
  2007     *_rval = jsdValue::FromPtr (mCx, jsdv);
  2008     return NS_OK;
  2012 NS_IMETHODIMP
  2013 jsdStackFrame::Eval (const nsAString &bytes, const nsACString &fileName,
  2014                      uint32_t line, jsdIValue **result, bool *_rval)
  2016     ASSERT_VALID_EPHEMERAL;
  2018     if (bytes.IsEmpty())
  2019         return NS_ERROR_INVALID_ARG;
  2021     // get pointer to buffer contained in |bytes|
  2022     nsAString::const_iterator h;
  2023     bytes.BeginReading(h);
  2024     const jschar *char_bytes = reinterpret_cast<const jschar *>(h.get());
  2026     JSExceptionState *estate = 0;
  2028     AutoPushJSContext cx(JSD_GetJSContext (mCx, mThreadState));
  2030     JS::RootedValue jv(cx);
  2032     estate = JS_SaveExceptionState (cx);
  2033     JS_ClearPendingException (cx);
  2035     *_rval = JSD_AttemptUCScriptInStackFrame (mCx, mThreadState,
  2036                                               mStackFrameInfo,
  2037                                               char_bytes, bytes.Length(),
  2038                                               PromiseFlatCString(fileName).get(),
  2039                                               line, &jv);
  2040     if (!*_rval) {
  2041         if (JS_IsExceptionPending(cx))
  2042             JS_GetPendingException (cx, &jv);
  2043         else
  2044             jv = JSVAL_NULL;
  2047     JS_RestoreExceptionState (cx, estate);
  2049     JSDValue *jsdv = JSD_NewValue (mCx, jv);
  2050     if (!jsdv)
  2051         return NS_ERROR_FAILURE;
  2052     *result = jsdValue::FromPtr (mCx, jsdv);
  2053     if (!*result)
  2054         return NS_ERROR_FAILURE;
  2056     return NS_OK;
  2059 /* Values */
  2060 NS_IMPL_ISUPPORTS(jsdValue, jsdIValue, jsdIEphemeral)
  2061 jsdIValue *
  2062 jsdValue::FromPtr (JSDContext *aCx, JSDValue *aValue)
  2064     /* value will be dropped by te jsdValue destructor. */
  2066     if (!aValue)
  2067         return nullptr;
  2069     jsdIValue *rv = new jsdValue (aCx, aValue);
  2070     NS_IF_ADDREF(rv);
  2071     return rv;
  2074 jsdValue::jsdValue (JSDContext *aCx, JSDValue *aValue) : mValid(true),
  2075                                                          mCx(aCx), 
  2076                                                          mValue(aValue)
  2078     DEBUG_CREATE ("jsdValue", gValueCount);
  2079     mLiveListEntry.value = this;
  2080     jsds_InsertEphemeral (&gLiveValues, &mLiveListEntry);
  2083 jsdValue::~jsdValue() 
  2085     DEBUG_DESTROY ("jsdValue", gValueCount);
  2086     if (mValid)
  2087         /* call Invalidate() to take ourselves out of the live list */
  2088         Invalidate();
  2091 NS_IMETHODIMP
  2092 jsdValue::GetIsValid(bool *_rval)
  2094     *_rval = mValid;
  2095     return NS_OK;
  2098 NS_IMETHODIMP
  2099 jsdValue::Invalidate()
  2101     ASSERT_VALID_EPHEMERAL;
  2102     mValid = false;
  2103     jsds_RemoveEphemeral (&gLiveValues, &mLiveListEntry);
  2104     JSD_DropValue (mCx, mValue);
  2105     return NS_OK;
  2108 void
  2109 jsdValue::InvalidateAll()
  2111     if (gLiveValues)
  2112         jsds_InvalidateAllEphemerals (&gLiveValues);
  2115 NS_IMETHODIMP
  2116 jsdValue::GetJSDContext(JSDContext **_rval)
  2118     ASSERT_VALID_EPHEMERAL;
  2119     *_rval = mCx;
  2120     return NS_OK;
  2123 NS_IMETHODIMP
  2124 jsdValue::GetJSDValue (JSDValue **_rval)
  2126     ASSERT_VALID_EPHEMERAL;
  2127     *_rval = mValue;
  2128     return NS_OK;
  2131 NS_IMETHODIMP
  2132 jsdValue::GetIsNative (bool *_rval)
  2134     ASSERT_VALID_EPHEMERAL;
  2135     *_rval = JSD_IsValueNative (mCx, mValue);
  2136     return NS_OK;
  2139 NS_IMETHODIMP
  2140 jsdValue::GetIsNumber (bool *_rval)
  2142     ASSERT_VALID_EPHEMERAL;
  2143     *_rval = JSD_IsValueNumber (mCx, mValue);
  2144     return NS_OK;
  2147 NS_IMETHODIMP
  2148 jsdValue::GetIsPrimitive (bool *_rval)
  2150     ASSERT_VALID_EPHEMERAL;
  2151     *_rval = JSD_IsValuePrimitive (mCx, mValue);
  2152     return NS_OK;
  2155 NS_IMETHODIMP
  2156 jsdValue::GetJsType (uint32_t *_rval)
  2158     ASSERT_VALID_EPHEMERAL;
  2159     JS::RootedValue val(JSD_GetJSRuntime(mCx), JSD_GetValueWrappedJSVal (mCx, mValue));
  2161     if (JSVAL_IS_NULL(val))
  2162         *_rval = TYPE_NULL;
  2163     else if (JSVAL_IS_BOOLEAN(val))
  2164         *_rval = TYPE_BOOLEAN;
  2165     else if (JSVAL_IS_DOUBLE(val))
  2166         *_rval = TYPE_DOUBLE;
  2167     else if (JSVAL_IS_INT(val))
  2168         *_rval = TYPE_INT;
  2169     else if (JSVAL_IS_STRING(val))
  2170         *_rval = TYPE_STRING;
  2171     else if (JSVAL_IS_VOID(val))
  2172         *_rval = TYPE_VOID;
  2173     else if (JSD_IsValueFunction (mCx, mValue))
  2174         *_rval = TYPE_FUNCTION;
  2175     else if (!JSVAL_IS_PRIMITIVE(val))
  2176         *_rval = TYPE_OBJECT;
  2177     else
  2178         NS_ASSERTION (0, "Value has no discernible type.");
  2180     return NS_OK;
  2183 NS_IMETHODIMP
  2184 jsdValue::GetJsPrototype (jsdIValue **_rval)
  2186     ASSERT_VALID_EPHEMERAL;
  2187     JSDValue *jsdv = JSD_GetValuePrototype (mCx, mValue);
  2188     *_rval = jsdValue::FromPtr (mCx, jsdv);
  2189     return NS_OK;
  2192 NS_IMETHODIMP
  2193 jsdValue::GetJsParent (jsdIValue **_rval)
  2195     ASSERT_VALID_EPHEMERAL;
  2196     JSDValue *jsdv = JSD_GetValueParent (mCx, mValue);
  2197     *_rval = jsdValue::FromPtr (mCx, jsdv);
  2198     return NS_OK;
  2201 NS_IMETHODIMP
  2202 jsdValue::GetJsClassName(nsACString &_rval)
  2204     ASSERT_VALID_EPHEMERAL;
  2205     _rval.Assign(JSD_GetValueClassName(mCx, mValue));
  2207     return NS_OK;
  2210 NS_IMETHODIMP
  2211 jsdValue::GetJsConstructor (jsdIValue **_rval)
  2213     ASSERT_VALID_EPHEMERAL;
  2214     JSDValue *jsdv = JSD_GetValueConstructor (mCx, mValue);
  2215     *_rval = jsdValue::FromPtr (mCx, jsdv);
  2216     return NS_OK;
  2219 NS_IMETHODIMP
  2220 jsdValue::GetJsFunctionName(nsACString &_rval)
  2222     ASSERT_VALID_EPHEMERAL;
  2223     return AssignToJSString(mCx, &_rval, JSD_GetValueFunctionId(mCx, mValue));
  2226 NS_IMETHODIMP
  2227 jsdValue::GetBooleanValue(bool *_rval)
  2229     ASSERT_VALID_EPHEMERAL;
  2230     *_rval = JSD_GetValueBoolean (mCx, mValue);
  2231     return NS_OK;
  2234 NS_IMETHODIMP
  2235 jsdValue::GetDoubleValue(double *_rval)
  2237     ASSERT_VALID_EPHEMERAL;
  2238     *_rval = JSD_GetValueDouble (mCx, mValue);
  2239     return NS_OK;
  2242 NS_IMETHODIMP
  2243 jsdValue::GetIntValue(int32_t *_rval)
  2245     ASSERT_VALID_EPHEMERAL;
  2246     *_rval = JSD_GetValueInt (mCx, mValue);
  2247     return NS_OK;
  2250 NS_IMETHODIMP
  2251 jsdValue::GetObjectValue(jsdIObject **_rval)
  2253     ASSERT_VALID_EPHEMERAL;
  2254     JSDObject *obj;
  2255     obj = JSD_GetObjectForValue (mCx, mValue);
  2256     *_rval = jsdObject::FromPtr (mCx, obj);
  2257     if (!*_rval)
  2258         return NS_ERROR_FAILURE;
  2259     return NS_OK;
  2262 NS_IMETHODIMP
  2263 jsdValue::GetStringValue(nsACString &_rval)
  2265     ASSERT_VALID_EPHEMERAL;
  2266     AutoSafeJSContext cx;
  2267     JSString *jstr_val = JSD_GetValueString(mCx, mValue);
  2268     if (jstr_val) {
  2269         size_t length;
  2270         const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length);
  2271         if (!chars)
  2272             return NS_ERROR_FAILURE;
  2273         nsDependentString depStr(chars, length);
  2274         CopyUTF16toUTF8(depStr, _rval);
  2275     } else {
  2276         _rval.Truncate();
  2278     return NS_OK;
  2281 NS_IMETHODIMP
  2282 jsdValue::GetPropertyCount (int32_t *_rval)
  2284     ASSERT_VALID_EPHEMERAL;
  2285     if (JSD_IsValueObject(mCx, mValue))
  2286         *_rval = JSD_GetCountOfProperties (mCx, mValue);
  2287     else
  2288         *_rval = -1;
  2289     return NS_OK;
  2292 NS_IMETHODIMP
  2293 jsdValue::GetProperties (jsdIProperty ***propArray, uint32_t *length)
  2295     ASSERT_VALID_EPHEMERAL;
  2296     *propArray = nullptr;
  2297     if (length)
  2298         *length = 0;
  2300     uint32_t prop_count = JSD_IsValueObject(mCx, mValue)
  2301         ? JSD_GetCountOfProperties (mCx, mValue)
  2302         : 0;
  2303     NS_ENSURE_TRUE(prop_count, NS_OK);
  2305     jsdIProperty **pa_temp =
  2306         static_cast<jsdIProperty **>
  2307                    (nsMemory::Alloc(sizeof (jsdIProperty *) * 
  2308                                        prop_count));
  2309     NS_ENSURE_TRUE(pa_temp, NS_ERROR_OUT_OF_MEMORY);
  2311     uint32_t     i    = 0;
  2312     JSDProperty *iter = nullptr;
  2313     JSDProperty *prop;
  2314     while ((prop = JSD_IterateProperties (mCx, mValue, &iter))) {
  2315         pa_temp[i] = jsdProperty::FromPtr (mCx, prop);
  2316         ++i;
  2319     NS_ASSERTION (prop_count == i, "property count mismatch");    
  2321     /* if caller doesn't care about length, don't bother telling them */
  2322     *propArray = pa_temp;
  2323     if (length)
  2324         *length = prop_count;
  2326     return NS_OK;
  2329 NS_IMETHODIMP
  2330 jsdValue::GetProperty (const nsACString &name, jsdIProperty **_rval)
  2332     ASSERT_VALID_EPHEMERAL;
  2333     AutoSafeJSContext cx;
  2334     JSAutoCompartment ac(cx, JSD_GetDefaultGlobal (mCx)); // Just in case.
  2336     /* not rooting this */
  2337     JSString *jstr_name = JS_NewStringCopyZ(cx, PromiseFlatCString(name).get());
  2338     if (!jstr_name)
  2339         return NS_ERROR_OUT_OF_MEMORY;
  2341     JSDProperty *prop = JSD_GetValueProperty (mCx, mValue, jstr_name);
  2343     *_rval = jsdProperty::FromPtr (mCx, prop);
  2344     return NS_OK;
  2347 NS_IMETHODIMP
  2348 jsdValue::Refresh()
  2350     ASSERT_VALID_EPHEMERAL;
  2351     JSD_RefreshValue (mCx, mValue);
  2352     return NS_OK;
  2355 NS_IMETHODIMP
  2356 jsdValue::GetWrappedValue(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval)
  2358     ASSERT_VALID_EPHEMERAL;
  2360     aRetval.set(JSD_GetValueWrappedJSVal(mCx, mValue));
  2361     if (!JS_WrapValue(aCx, aRetval))
  2362         return NS_ERROR_FAILURE;
  2364     return NS_OK;
  2367 NS_IMETHODIMP
  2368 jsdValue::GetScript(jsdIScript **_rval)
  2370     ASSERT_VALID_EPHEMERAL;
  2371     JSDScript *script = JSD_GetScriptForValue(mCx, mValue);
  2372     *_rval = jsdScript::FromPtr(mCx, script);
  2373     return NS_OK;
  2376 /******************************************************************************
  2377  * debugger service implementation
  2378  ******************************************************************************/
  2380 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(jsdService)
  2381   NS_INTERFACE_MAP_ENTRY(jsdIDebuggerService)
  2382   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, jsdIDebuggerService)
  2383 NS_INTERFACE_MAP_END
  2385 NS_IMPL_CYCLE_COLLECTION(jsdService,
  2386                          mErrorHook, mBreakpointHook, mDebugHook,
  2387                          mDebuggerHook, mInterruptHook, mScriptHook,
  2388                          mThrowHook, mTopLevelHook, mFunctionHook,
  2389                          mActivationCallback)
  2390 NS_IMPL_CYCLE_COLLECTING_ADDREF(jsdService)
  2391 NS_IMPL_CYCLE_COLLECTING_RELEASE(jsdService)
  2393 NS_IMETHODIMP
  2394 jsdService::GetJSDContext(JSDContext **_rval)
  2396     *_rval = mCx;
  2397     return NS_OK;
  2400 NS_IMETHODIMP
  2401 jsdService::GetFlags (uint32_t *_rval)
  2403     ASSERT_VALID_CONTEXT;
  2404     *_rval = JSD_GetContextFlags (mCx);
  2405     return NS_OK;
  2408 NS_IMETHODIMP
  2409 jsdService::SetFlags (uint32_t flags)
  2411     ASSERT_VALID_CONTEXT;
  2412     JSD_SetContextFlags (mCx, flags);
  2413     return NS_OK;
  2416 NS_IMETHODIMP
  2417 jsdService::GetImplementationString(nsACString &aImplementationString)
  2419     aImplementationString.AssignLiteral(implementationString);
  2420     return NS_OK;
  2423 NS_IMETHODIMP
  2424 jsdService::GetImplementationMajor(uint32_t *_rval)
  2426     *_rval = JSDS_MAJOR_VERSION;
  2427     return NS_OK;
  2430 NS_IMETHODIMP
  2431 jsdService::GetImplementationMinor(uint32_t *_rval)
  2433     *_rval = JSDS_MINOR_VERSION;
  2434     return NS_OK;
  2437 NS_IMETHODIMP
  2438 jsdService::GetIsOn (bool *_rval)
  2440     *_rval = mOn;
  2441     return NS_OK;
  2444 NS_IMETHODIMP
  2445 jsdService::On (void)
  2447     return NS_ERROR_NOT_IMPLEMENTED;
  2450 NS_IMETHODIMP
  2451 jsdService::AsyncOn (jsdIActivationCallback *activationCallback)
  2453     nsresult  rv;
  2455     // Warn that JSD is deprecated, unless the caller has told us
  2456     // that they know already.
  2457     if (mDeprecationAcknowledged) {
  2458         mDeprecationAcknowledged = false;
  2459     } else if (!mWarnedAboutDeprecation) {
  2460         // In any case, warn only once.
  2461         mWarnedAboutDeprecation = true;
  2463         // Ignore errors: simply being unable to print the message
  2464         // shouldn't (effectively) disable JSD.
  2465         nsContentUtils::ReportToConsoleNonLocalized(
  2466             NS_LITERAL_STRING("\
  2467 The jsdIDebuggerService and its associated interfaces are deprecated. \
  2468 Please use Debugger, via IJSDebugger, instead."),
  2469             nsIScriptError::warningFlag,
  2470             NS_LITERAL_CSTRING("JSD"),
  2471             nullptr);
  2474     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
  2475     if (NS_FAILED(rv)) return rv;
  2477     mActivationCallback = activationCallback;
  2479     return xpc->SetDebugModeWhenPossible(true, true);
  2482 NS_IMETHODIMP
  2483 jsdService::RecompileForDebugMode (JSContext *cx, JSCompartment *comp, bool mode) {
  2484   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
  2485   /* XPConnect now does this work itself, so this IDL entry point is no longer used. */
  2486   return NS_ERROR_NOT_IMPLEMENTED;
  2489 NS_IMETHODIMP
  2490 jsdService::DeactivateDebugger ()
  2492     if (!mCx)
  2493         return NS_OK;
  2495     jsdContext::InvalidateAll();
  2496     jsdScript::InvalidateAll();
  2497     jsdValue::InvalidateAll();
  2498     jsdProperty::InvalidateAll();
  2499     jsdStackFrame::InvalidateAll();
  2500     ClearAllBreakpoints();
  2502     JSD_SetErrorReporter (mCx, nullptr, nullptr);
  2503     JSD_SetScriptHook (mCx, nullptr, nullptr);
  2504     JSD_ClearThrowHook (mCx);
  2505     JSD_ClearInterruptHook (mCx);
  2506     JSD_ClearDebuggerHook (mCx);
  2507     JSD_ClearDebugBreakHook (mCx);
  2508     JSD_ClearTopLevelHook (mCx);
  2509     JSD_ClearFunctionHook (mCx);
  2511     JSD_DebuggerOff (mCx);
  2513     mCx = nullptr;
  2514     mRuntime = nullptr;
  2515     mOn = false;
  2517     return NS_OK;
  2521 NS_IMETHODIMP
  2522 jsdService::ActivateDebugger (JSRuntime *rt)
  2524     if (mOn)
  2525         return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED;
  2527     mRuntime = rt;
  2529     if (gPrevGCSliceCallback == jsds_GCSliceCallbackProc)
  2530         /* condition indicates that the callback proc has not been set yet */
  2531         gPrevGCSliceCallback = JS::SetGCSliceCallback (rt, jsds_GCSliceCallbackProc);
  2533     mCx = JSD_DebuggerOnForUser (rt, nullptr, nullptr);
  2534     if (!mCx)
  2535         return NS_ERROR_FAILURE;
  2537     AutoSafeJSContext cx;
  2538     JS::RootedObject glob(cx, JSD_GetDefaultGlobal (mCx));
  2539     JSAutoCompartment ac(cx, glob);
  2541     /* init xpconnect on the debugger's context in case xpconnect tries to
  2542      * use it for stuff. */
  2543     nsresult rv;
  2544     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
  2545     if (NS_FAILED(rv))
  2546         return rv;
  2548     xpc->InitClasses (cx, glob);
  2550     /* Start watching for script creation/destruction and manage jsdScript
  2551      * objects accordingly
  2552      */
  2553     JSD_SetScriptHook (mCx, jsds_ScriptHookProc, nullptr);
  2555     /* If any of these mFooHook objects are installed, do the required JSD
  2556      * hookup now.   See also, jsdService::SetFooHook().
  2557      */
  2558     if (mErrorHook)
  2559         JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, nullptr);
  2560     if (mThrowHook)
  2561         JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, nullptr);
  2562     /* can't ignore script callbacks, as we need to |Release| the wrapper 
  2563      * stored in private data when a script is deleted. */
  2564     if (mInterruptHook)
  2565         JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, nullptr);
  2566     if (mDebuggerHook)
  2567         JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, nullptr);
  2568     if (mDebugHook)
  2569         JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, nullptr);
  2570     if (mTopLevelHook)
  2571         JSD_SetTopLevelHook (mCx, jsds_CallHookProc, nullptr);
  2572     else
  2573         JSD_ClearTopLevelHook (mCx);
  2574     if (mFunctionHook)
  2575         JSD_SetFunctionHook (mCx, jsds_CallHookProc, nullptr);
  2576     else
  2577         JSD_ClearFunctionHook (mCx);
  2578     mOn = true;
  2580 #ifdef DEBUG
  2581     printf ("+++ JavaScript debugging hooks installed.\n");
  2582 #endif
  2584     nsCOMPtr<jsdIActivationCallback> activationCallback;
  2585     mActivationCallback.swap(activationCallback);
  2586     if (activationCallback)
  2587         return activationCallback->OnDebuggerActivated();
  2589     return NS_OK;
  2592 NS_IMETHODIMP
  2593 jsdService::Off (void)
  2595     if (!mOn)
  2596         return NS_OK;
  2598     if (!mCx || !mRuntime)
  2599         return NS_ERROR_NOT_INITIALIZED;
  2601     if (gDeadScripts) {
  2602         if (gGCRunning)
  2603             return NS_ERROR_NOT_AVAILABLE;
  2605         while (gDeadScripts)
  2606             jsds_NotifyPendingDeadScripts (JS_GetRuntime(nsContentUtils::GetSafeJSContext()));
  2609     DeactivateDebugger();
  2611 #ifdef DEBUG
  2612     printf ("+++ JavaScript debugging hooks removed.\n");
  2613 #endif
  2615     nsresult rv;
  2616     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
  2617     if (NS_FAILED(rv))
  2618         return rv;
  2620     xpc->SetDebugModeWhenPossible(false, true);
  2622     return NS_OK;
  2625 NS_IMETHODIMP
  2626 jsdService::GetPauseDepth(uint32_t *_rval)
  2628     NS_ENSURE_ARG_POINTER(_rval);
  2629     *_rval = mPauseLevel;
  2630     return NS_OK;
  2633 NS_IMETHODIMP
  2634 jsdService::Pause(uint32_t *_rval)
  2636     return DoPause(_rval, false);
  2639 nsresult
  2640 jsdService::DoPause(uint32_t *_rval, bool internalCall)
  2642     if (!mCx)
  2643         return NS_ERROR_NOT_INITIALIZED;
  2645     if (++mPauseLevel == 1) {
  2646         JSD_SetErrorReporter (mCx, nullptr, nullptr);
  2647         JSD_ClearThrowHook (mCx);
  2648         JSD_ClearInterruptHook (mCx);
  2649         JSD_ClearDebuggerHook (mCx);
  2650         JSD_ClearDebugBreakHook (mCx);
  2651         JSD_ClearTopLevelHook (mCx);
  2652         JSD_ClearFunctionHook (mCx);
  2653         JSD_DebuggerPause (mCx);
  2655         nsresult rv;
  2656         nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
  2657         if (NS_FAILED(rv)) return rv;
  2659         if (!internalCall) {
  2660             rv = xpc->SetDebugModeWhenPossible(false, false);
  2661             NS_ENSURE_SUCCESS(rv, rv);
  2665     if (_rval)
  2666         *_rval = mPauseLevel;
  2668     return NS_OK;
  2671 NS_IMETHODIMP
  2672 jsdService::UnPause(uint32_t *_rval)
  2674     return DoUnPause(_rval, false);
  2677 nsresult
  2678 jsdService::DoUnPause(uint32_t *_rval, bool internalCall)
  2680     if (!mCx)
  2681         return NS_ERROR_NOT_INITIALIZED;
  2683     if (mPauseLevel == 0)
  2684         return NS_ERROR_NOT_AVAILABLE;
  2686     /* check mOn before we muck with this stuff, it's possible the debugger
  2687      * was turned off while we were paused.
  2688      */
  2689     if (--mPauseLevel == 0 && mOn) {
  2690         JSD_DebuggerUnpause (mCx);
  2691         if (mErrorHook)
  2692             JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, nullptr);
  2693         if (mThrowHook)
  2694             JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, nullptr);
  2695         if (mInterruptHook)
  2696             JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, nullptr);
  2697         if (mDebuggerHook)
  2698             JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, nullptr);
  2699         if (mDebugHook)
  2700             JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, nullptr);
  2701         if (mTopLevelHook)
  2702             JSD_SetTopLevelHook (mCx, jsds_CallHookProc, nullptr);
  2703         else
  2704             JSD_ClearTopLevelHook (mCx);
  2705         if (mFunctionHook)
  2706             JSD_SetFunctionHook (mCx, jsds_CallHookProc, nullptr);
  2707         else
  2708             JSD_ClearFunctionHook (mCx);
  2710         nsresult rv;
  2711         nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
  2712         if (NS_FAILED(rv)) return rv;
  2714         if (!internalCall) {
  2715             rv = xpc->SetDebugModeWhenPossible(true, false);
  2716             NS_ENSURE_SUCCESS(rv, rv);
  2720     if (_rval)
  2721         *_rval = mPauseLevel;
  2723     return NS_OK;
  2726 NS_IMETHODIMP
  2727 jsdService::EnumerateContexts (jsdIContextEnumerator *enumerator)
  2729     ASSERT_VALID_CONTEXT;
  2731     if (!enumerator)
  2732         return NS_OK;
  2734     JSContext *iter = nullptr;
  2735     JSContext *cx;
  2737     while ((cx = JS_ContextIterator (mRuntime, &iter)))
  2739         nsCOMPtr<jsdIContext> jsdicx = 
  2740             dont_AddRef(jsdContext::FromPtr(mCx, cx));
  2741         if (jsdicx)
  2743             if (NS_FAILED(enumerator->EnumerateContext(jsdicx)))
  2744                 break;
  2748     return NS_OK;
  2751 NS_IMETHODIMP
  2752 jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator)
  2754     ASSERT_VALID_CONTEXT;
  2756     JSDScript *script;
  2757     JSDScript *iter = nullptr;
  2758     nsresult rv = NS_OK;
  2760     JSD_LockScriptSubsystem(mCx);
  2761     while((script = JSD_IterateScripts(mCx, &iter))) {
  2762         nsCOMPtr<jsdIScript> jsdis =
  2763             dont_AddRef(jsdScript::FromPtr(mCx, script));
  2764         rv = enumerator->EnumerateScript (jsdis);
  2765         if (NS_FAILED(rv))
  2766             break;
  2768     JSD_UnlockScriptSubsystem(mCx);
  2770     return rv;
  2773 NS_IMETHODIMP
  2774 jsdService::GC (void)
  2776     ASSERT_VALID_CONTEXT;
  2777     JSRuntime *rt = JSD_GetJSRuntime (mCx);
  2778     JS_GC(rt);
  2779     return NS_OK;
  2782 NS_IMETHODIMP
  2783 jsdService::DumpHeap(const nsACString &fileName)
  2785     ASSERT_VALID_CONTEXT;
  2786 #ifndef DEBUG
  2787     return NS_ERROR_NOT_IMPLEMENTED;
  2788 #else
  2789     nsresult rv = NS_OK;
  2790     FILE *file = !fileName.IsEmpty() ? fopen(PromiseFlatCString(fileName).get(), "w") : stdout;
  2791     if (!file) {
  2792         rv = NS_ERROR_FAILURE;
  2793     } else {
  2794         if (!JS_DumpHeap(JS_GetRuntime(nsContentUtils::GetSafeJSContext()),
  2795                          file, nullptr, JSTRACE_OBJECT, nullptr, (size_t)-1, nullptr))
  2796             rv = NS_ERROR_FAILURE;
  2797         if (file != stdout)
  2798             fclose(file);
  2800     return rv;
  2801 #endif
  2804 NS_IMETHODIMP
  2805 jsdService::ClearProfileData ()
  2807     ASSERT_VALID_CONTEXT;
  2808     JSD_ClearAllProfileData (mCx);
  2809     return NS_OK;
  2812 NS_IMETHODIMP
  2813 jsdService::InsertFilter (jsdIFilter *filter, jsdIFilter *after)
  2815     NS_ENSURE_ARG_POINTER (filter);
  2816     if (jsds_FindFilter (filter))
  2817         return NS_ERROR_INVALID_ARG;
  2819     FilterRecord *rec = PR_NEWZAP (FilterRecord);
  2820     if (!rec)
  2821         return NS_ERROR_OUT_OF_MEMORY;
  2823     if (!jsds_SyncFilter (rec, filter)) {
  2824         PR_Free (rec);
  2825         return NS_ERROR_FAILURE;
  2828     if (gFilters) {
  2829         if (!after) {
  2830             /* insert at head of list */
  2831             PR_INSERT_LINK(&rec->links, &gFilters->links);
  2832             gFilters = rec;
  2833         } else {
  2834             /* insert somewhere in the list */
  2835             FilterRecord *afterRecord = jsds_FindFilter (after);
  2836             if (!afterRecord) {
  2837                 jsds_FreeFilter(rec);
  2838                 return NS_ERROR_INVALID_ARG;
  2840             PR_INSERT_AFTER(&rec->links, &afterRecord->links);
  2842     } else {
  2843         if (after) {
  2844             /* user asked to insert into the middle of an empty list, bail. */
  2845             jsds_FreeFilter(rec);
  2846             return NS_ERROR_NOT_INITIALIZED;
  2848         PR_INIT_CLIST(&rec->links);
  2849         gFilters = rec;
  2852     return NS_OK;
  2855 NS_IMETHODIMP
  2856 jsdService::AppendFilter (jsdIFilter *filter)
  2858     NS_ENSURE_ARG_POINTER (filter);
  2859     if (jsds_FindFilter (filter))
  2860         return NS_ERROR_INVALID_ARG;
  2861     FilterRecord *rec = PR_NEWZAP (FilterRecord);
  2863     if (!jsds_SyncFilter (rec, filter)) {
  2864         PR_Free (rec);
  2865         return NS_ERROR_FAILURE;
  2868     if (gFilters) {
  2869         PR_INSERT_BEFORE(&rec->links, &gFilters->links);
  2870     } else {
  2871         PR_INIT_CLIST(&rec->links);
  2872         gFilters = rec;
  2875     return NS_OK;
  2878 NS_IMETHODIMP
  2879 jsdService::RemoveFilter (jsdIFilter *filter)
  2881     NS_ENSURE_ARG_POINTER(filter);
  2882     FilterRecord *rec = jsds_FindFilter (filter);
  2883     if (!rec)
  2884         return NS_ERROR_INVALID_ARG;
  2886     if (gFilters == rec) {
  2887         gFilters = reinterpret_cast<FilterRecord *>
  2888                                    (PR_NEXT_LINK(&rec->links));
  2889         /* If we're the only filter left, null out the list head. */
  2890         if (gFilters == rec)
  2891             gFilters = nullptr;
  2895     PR_REMOVE_LINK(&rec->links);
  2896     jsds_FreeFilter (rec);
  2898     return NS_OK;
  2901 NS_IMETHODIMP
  2902 jsdService::SwapFilters (jsdIFilter *filter_a, jsdIFilter *filter_b)
  2904     NS_ENSURE_ARG_POINTER(filter_a);
  2905     NS_ENSURE_ARG_POINTER(filter_b);
  2907     FilterRecord *rec_a = jsds_FindFilter (filter_a);
  2908     if (!rec_a)
  2909         return NS_ERROR_INVALID_ARG;
  2911     if (filter_a == filter_b) {
  2912         /* just a refresh */
  2913         if (!jsds_SyncFilter (rec_a, filter_a))
  2914             return NS_ERROR_FAILURE;
  2915         return NS_OK;
  2918     FilterRecord *rec_b = jsds_FindFilter (filter_b);
  2919     if (!rec_b) {
  2920         /* filter_b is not in the list, replace filter_a with filter_b. */
  2921         if (!jsds_SyncFilter (rec_a, filter_b))
  2922             return NS_ERROR_FAILURE;
  2923     } else {
  2924         /* both filters are in the list, swap. */
  2925         if (!jsds_SyncFilter (rec_a, filter_b))
  2926             return NS_ERROR_FAILURE;
  2927         if (!jsds_SyncFilter (rec_b, filter_a))
  2928             return NS_ERROR_FAILURE;
  2931     return NS_OK;
  2934 NS_IMETHODIMP
  2935 jsdService::EnumerateFilters (jsdIFilterEnumerator *enumerator) 
  2937     if (!gFilters)
  2938         return NS_OK;
  2940     FilterRecord *current = gFilters;
  2941     do {
  2942         jsds_SyncFilter (current, current->filterObject);
  2943         /* SyncFilter failure would be bad, but what would we do about it? */
  2944         if (enumerator) {
  2945             nsresult rv = enumerator->EnumerateFilter (current->filterObject);
  2946             if (NS_FAILED(rv))
  2947                 return rv;
  2949         current = reinterpret_cast<FilterRecord *>
  2950                                   (PR_NEXT_LINK (&current->links));
  2951     } while (current != gFilters);
  2953     return NS_OK;
  2956 NS_IMETHODIMP
  2957 jsdService::RefreshFilters ()
  2959     return EnumerateFilters(nullptr);
  2962 NS_IMETHODIMP
  2963 jsdService::ClearFilters ()
  2965     if (!gFilters)
  2966         return NS_OK;
  2968     FilterRecord *current = reinterpret_cast<FilterRecord *>
  2969                                             (PR_NEXT_LINK (&gFilters->links));
  2970     do {
  2971         FilterRecord *next = reinterpret_cast<FilterRecord *>
  2972                                              (PR_NEXT_LINK (&current->links));
  2973         PR_REMOVE_AND_INIT_LINK(&current->links);
  2974         jsds_FreeFilter(current);
  2975         current = next;
  2976     } while (current != gFilters);
  2978     jsds_FreeFilter(current);
  2979     gFilters = nullptr;
  2981     return NS_OK;
  2984 NS_IMETHODIMP
  2985 jsdService::ClearAllBreakpoints (void)
  2987     ASSERT_VALID_CONTEXT;
  2989     JSD_LockScriptSubsystem(mCx);
  2990     JSD_ClearAllExecutionHooks (mCx);
  2991     JSD_UnlockScriptSubsystem(mCx);
  2992     return NS_OK;
  2995 NS_IMETHODIMP
  2996 jsdService::WrapValue(JS::Handle<JS::Value> value, jsdIValue **_rval)
  2998     ASSERT_VALID_CONTEXT;
  2999     JSDValue *jsdv = JSD_NewValue(mCx, value);
  3000     if (!jsdv)
  3001         return NS_ERROR_FAILURE;
  3003     *_rval = jsdValue::FromPtr (mCx, jsdv);
  3004     return NS_OK;
  3008 NS_IMETHODIMP
  3009 jsdService::EnterNestedEventLoop (jsdINestCallback *callback, uint32_t *_rval)
  3011     // Nesting event queues is a thing of the past.  Now, we just spin the
  3012     // current event loop.
  3013     nsresult rv = NS_OK;
  3014     AutoNoJSAPI nojsapi;
  3015     uint32_t nestLevel = ++mNestedLoopLevel;
  3016     nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
  3018     if (callback) {
  3019         DoPause(nullptr, true);
  3020         rv = callback->OnNest();
  3021         DoUnPause(nullptr, true);
  3024     while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) {
  3025         if (!NS_ProcessNextEvent(thread))
  3026             rv = NS_ERROR_UNEXPECTED;
  3029     NS_ASSERTION (mNestedLoopLevel <= nestLevel,
  3030                   "nested event didn't unwind properly");
  3031     if (mNestedLoopLevel == nestLevel)
  3032         --mNestedLoopLevel;
  3034     *_rval = mNestedLoopLevel;
  3035     return rv;
  3038 NS_IMETHODIMP
  3039 jsdService::ExitNestedEventLoop (uint32_t *_rval)
  3041     if (mNestedLoopLevel > 0)
  3042         --mNestedLoopLevel;
  3043     else
  3044         return NS_ERROR_FAILURE;
  3046     *_rval = mNestedLoopLevel;    
  3047     return NS_OK;
  3050 NS_IMETHODIMP
  3051 jsdService::AcknowledgeDeprecation()
  3053     mDeprecationAcknowledged = true;
  3054     return NS_OK;
  3057 /* hook attribute get/set functions */
  3059 NS_IMETHODIMP
  3060 jsdService::SetErrorHook (jsdIErrorHook *aHook)
  3062     mErrorHook = aHook;
  3064     /* if the debugger isn't initialized, that's all we can do for now.  The
  3065      * ActivateDebugger() method will do the rest when the coast is clear.
  3066      */
  3067     if (!mCx || mPauseLevel)
  3068         return NS_OK;
  3070     if (aHook)
  3071         JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, nullptr);
  3072     else
  3073         JSD_SetErrorReporter (mCx, nullptr, nullptr);
  3075     return NS_OK;
  3078 NS_IMETHODIMP
  3079 jsdService::GetErrorHook (jsdIErrorHook **aHook)
  3081     *aHook = mErrorHook;
  3082     NS_IF_ADDREF(*aHook);
  3084     return NS_OK;
  3087 NS_IMETHODIMP
  3088 jsdService::SetBreakpointHook (jsdIExecutionHook *aHook)
  3090     mBreakpointHook = aHook;
  3091     return NS_OK;
  3094 NS_IMETHODIMP
  3095 jsdService::GetBreakpointHook (jsdIExecutionHook **aHook)
  3097     *aHook = mBreakpointHook;
  3098     NS_IF_ADDREF(*aHook);
  3100     return NS_OK;
  3103 NS_IMETHODIMP
  3104 jsdService::SetDebugHook (jsdIExecutionHook *aHook)
  3106     mDebugHook = aHook;
  3108     /* if the debugger isn't initialized, that's all we can do for now.  The
  3109      * ActivateDebugger() method will do the rest when the coast is clear.
  3110      */
  3111     if (!mCx || mPauseLevel)
  3112         return NS_OK;
  3114     if (aHook)
  3115         JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, nullptr);
  3116     else
  3117         JSD_ClearDebugBreakHook (mCx);
  3119     return NS_OK;
  3122 NS_IMETHODIMP
  3123 jsdService::GetDebugHook (jsdIExecutionHook **aHook)
  3125     *aHook = mDebugHook;
  3126     NS_IF_ADDREF(*aHook);
  3128     return NS_OK;
  3131 NS_IMETHODIMP
  3132 jsdService::SetDebuggerHook (jsdIExecutionHook *aHook)
  3134     mDebuggerHook = aHook;
  3136     /* if the debugger isn't initialized, that's all we can do for now.  The
  3137      * ActivateDebugger() method will do the rest when the coast is clear.
  3138      */
  3139     if (!mCx || mPauseLevel)
  3140         return NS_OK;
  3142     if (aHook)
  3143         JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, nullptr);
  3144     else
  3145         JSD_ClearDebuggerHook (mCx);
  3147     return NS_OK;
  3150 NS_IMETHODIMP
  3151 jsdService::GetDebuggerHook (jsdIExecutionHook **aHook)
  3153     *aHook = mDebuggerHook;
  3154     NS_IF_ADDREF(*aHook);
  3156     return NS_OK;
  3159 NS_IMETHODIMP
  3160 jsdService::SetInterruptHook (jsdIExecutionHook *aHook)
  3162     mInterruptHook = aHook;
  3164     /* if the debugger isn't initialized, that's all we can do for now.  The
  3165      * ActivateDebugger() method will do the rest when the coast is clear.
  3166      */
  3167     if (!mCx || mPauseLevel)
  3168         return NS_OK;
  3170     if (aHook)
  3171         JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, nullptr);
  3172     else
  3173         JSD_ClearInterruptHook (mCx);
  3175     return NS_OK;
  3178 NS_IMETHODIMP
  3179 jsdService::GetInterruptHook (jsdIExecutionHook **aHook)
  3181     *aHook = mInterruptHook;
  3182     NS_IF_ADDREF(*aHook);
  3184     return NS_OK;
  3187 NS_IMETHODIMP
  3188 jsdService::SetScriptHook (jsdIScriptHook *aHook)
  3190     mScriptHook = aHook;
  3192     /* if the debugger isn't initialized, that's all we can do for now.  The
  3193      * ActivateDebugger() method will do the rest when the coast is clear.
  3194      */
  3195     if (!mCx || mPauseLevel)
  3196         return NS_OK;
  3198     if (aHook)
  3199         JSD_SetScriptHook (mCx, jsds_ScriptHookProc, nullptr);
  3200     /* we can't unset it if !aHook, because we still need to see script
  3201      * deletes in order to Release the jsdIScripts held in JSDScript
  3202      * private data. */
  3203     return NS_OK;
  3206 NS_IMETHODIMP
  3207 jsdService::GetScriptHook (jsdIScriptHook **aHook)
  3209     *aHook = mScriptHook;
  3210     NS_IF_ADDREF(*aHook);
  3212     return NS_OK;
  3215 NS_IMETHODIMP
  3216 jsdService::SetThrowHook (jsdIExecutionHook *aHook)
  3218     mThrowHook = aHook;
  3220     /* if the debugger isn't initialized, that's all we can do for now.  The
  3221      * ActivateDebugger() method will do the rest when the coast is clear.
  3222      */
  3223     if (!mCx || mPauseLevel)
  3224         return NS_OK;
  3226     if (aHook)
  3227         JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, nullptr);
  3228     else
  3229         JSD_ClearThrowHook (mCx);
  3231     return NS_OK;
  3234 NS_IMETHODIMP
  3235 jsdService::GetThrowHook (jsdIExecutionHook **aHook)
  3237     *aHook = mThrowHook;
  3238     NS_IF_ADDREF(*aHook);
  3240     return NS_OK;
  3243 NS_IMETHODIMP
  3244 jsdService::SetTopLevelHook (jsdICallHook *aHook)
  3246     mTopLevelHook = aHook;
  3248     /* if the debugger isn't initialized, that's all we can do for now.  The
  3249      * ActivateDebugger() method will do the rest when the coast is clear.
  3250      */
  3251     if (!mCx || mPauseLevel)
  3252         return NS_OK;
  3254     if (aHook)
  3255         JSD_SetTopLevelHook (mCx, jsds_CallHookProc, nullptr);
  3256     else
  3257         JSD_ClearTopLevelHook (mCx);
  3259     return NS_OK;
  3262 NS_IMETHODIMP
  3263 jsdService::GetTopLevelHook (jsdICallHook **aHook)
  3265     *aHook = mTopLevelHook;
  3266     NS_IF_ADDREF(*aHook);
  3268     return NS_OK;
  3271 NS_IMETHODIMP
  3272 jsdService::SetFunctionHook (jsdICallHook *aHook)
  3274     mFunctionHook = aHook;
  3276     /* if the debugger isn't initialized, that's all we can do for now.  The
  3277      * ActivateDebugger() method will do the rest when the coast is clear.
  3278      */
  3279     if (!mCx || mPauseLevel)
  3280         return NS_OK;
  3282     if (aHook)
  3283         JSD_SetFunctionHook (mCx, jsds_CallHookProc, nullptr);
  3284     else
  3285         JSD_ClearFunctionHook (mCx);
  3287     return NS_OK;
  3290 NS_IMETHODIMP
  3291 jsdService::GetFunctionHook (jsdICallHook **aHook)
  3293     *aHook = mFunctionHook;
  3294     NS_IF_ADDREF(*aHook);
  3296     return NS_OK;
  3299 /* virtual */
  3300 jsdService::~jsdService()
  3302     ClearFilters();
  3303     mErrorHook = nullptr;
  3304     mBreakpointHook = nullptr;
  3305     mDebugHook = nullptr;
  3306     mDebuggerHook = nullptr;
  3307     mInterruptHook = nullptr;
  3308     mScriptHook = nullptr;
  3309     mThrowHook = nullptr;
  3310     mTopLevelHook = nullptr;
  3311     mFunctionHook = nullptr;
  3312     Off();
  3313     gJsds = nullptr;
  3316 jsdService *
  3317 jsdService::GetService ()
  3319     if (!gJsds)
  3320         gJsds = new jsdService();
  3322     NS_IF_ADDREF(gJsds);
  3323     return gJsds;
  3326 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService, jsdService::GetService)
  3328 /* app-start observer.  turns on the debugger at app-start.  this is inserted
  3329  * and/or removed from the app-start category by the jsdService::initAtStartup
  3330  * property.
  3331  */
  3332 class jsdASObserver MOZ_FINAL : public nsIObserver
  3334   public:
  3335     NS_DECL_THREADSAFE_ISUPPORTS
  3336     NS_DECL_NSIOBSERVER
  3338     jsdASObserver () {}    
  3339 };
  3341 NS_IMPL_ISUPPORTS(jsdASObserver, nsIObserver)
  3343 NS_IMETHODIMP
  3344 jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic,
  3345                         const char16_t *aData)
  3347     nsresult rv;
  3349     // Hmm.  Why is the app-startup observer called multiple times?
  3350     //NS_ASSERTION(!gJsds, "app startup observer called twice");
  3351     nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
  3352     if (NS_FAILED(rv))
  3353         return rv;
  3355     bool on;
  3356     rv = jsds->GetIsOn(&on);
  3357     if (NS_FAILED(rv) || on)
  3358         return rv;
  3360     nsCOMPtr<nsIJSRuntimeService> rts = do_GetService(NS_JSRT_CTRID, &rv);
  3361     if (NS_FAILED(rv))
  3362         return rv;    
  3364     JSRuntime *rt;
  3365     rts->GetRuntime (&rt);
  3366     if (NS_FAILED(rv))
  3367         return rv;
  3369     rv = jsds->ActivateDebugger(rt);
  3370     if (NS_FAILED(rv))
  3371         return rv;
  3373     return NS_OK;
  3376 NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
  3377 NS_DEFINE_NAMED_CID(JSDSERVICE_CID);
  3378 NS_DEFINE_NAMED_CID(JSDASO_CID);
  3380 static const mozilla::Module::CIDEntry kJSDCIDs[] = {
  3381     { &kJSDSERVICE_CID, false, nullptr, jsdServiceConstructor },
  3382     { &kJSDASO_CID, false, nullptr, jsdASObserverConstructor },
  3383     { nullptr }
  3384 };
  3386 static const mozilla::Module::ContractIDEntry kJSDContracts[] = {
  3387     { jsdServiceCtrID, &kJSDSERVICE_CID },
  3388     { jsdARObserverCtrID, &kJSDASO_CID },
  3389     { nullptr }
  3390 };
  3392 static const mozilla::Module kJSDModule = {
  3393     mozilla::Module::kVersion,
  3394     kJSDCIDs,
  3395     kJSDContracts
  3396 };
  3398 NSMODULE_DEFN(JavaScript_Debugger) = &kJSDModule;
  3400 void
  3401 global_finalize(JSFreeOp *aFop, JSObject *aObj)
  3403     nsIScriptObjectPrincipal *sop =
  3404         static_cast<nsIScriptObjectPrincipal *>(js::GetObjectPrivate(aObj));
  3405     MOZ_ASSERT(sop);
  3406     static_cast<SandboxPrivate *>(sop)->ForgetGlobalObject();
  3407     NS_IF_RELEASE(sop);
  3410 JSObject *
  3411 CreateJSDGlobal(JSContext *aCx, const JSClass *aClasp)
  3413     nsresult rv;
  3414     nsCOMPtr<nsIPrincipal> nullPrin = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
  3415     NS_ENSURE_SUCCESS(rv, nullptr);
  3417     JSPrincipals *jsPrin = nsJSPrincipals::get(nullPrin);
  3418     JS::RootedObject global(aCx, JS_NewGlobalObject(aCx, aClasp, jsPrin, JS::DontFireOnNewGlobalHook));
  3419     NS_ENSURE_TRUE(global, nullptr);
  3421     // We have created a new global let's attach a private to it
  3422     // that implements nsIGlobalObject.
  3423     nsCOMPtr<nsIScriptObjectPrincipal> sbp =
  3424         new SandboxPrivate(nullPrin, global);
  3425     JS_SetPrivate(global, sbp.forget().take());
  3427     JS_FireOnNewGlobalObject(aCx, global);
  3429     return global;
  3432 /********************************************************************************
  3433  ********************************************************************************
  3434  * graveyard
  3435  */
  3437 #if 0
  3438 /* Thread States */
  3439 NS_IMPL_ISUPPORTS(jsdThreadState, jsdIThreadState); 
  3441 NS_IMETHODIMP
  3442 jsdThreadState::GetJSDContext(JSDContext **_rval)
  3444     *_rval = mCx;
  3445     return NS_OK;
  3448 NS_IMETHODIMP
  3449 jsdThreadState::GetJSDThreadState(JSDThreadState **_rval)
  3451     *_rval = mThreadState;
  3452     return NS_OK;
  3455 NS_IMETHODIMP
  3456 jsdThreadState::GetFrameCount (uint32_t *_rval)
  3458     *_rval = JSD_GetCountOfStackFrames (mCx, mThreadState);
  3459     return NS_OK;
  3462 NS_IMETHODIMP
  3463 jsdThreadState::GetTopFrame (jsdIStackFrame **_rval)
  3465     JSDStackFrameInfo *sfi = JSD_GetStackFrame (mCx, mThreadState);
  3467     *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
  3468     return NS_OK;
  3471 NS_IMETHODIMP
  3472 jsdThreadState::GetPendingException(jsdIValue **_rval)
  3474     JSDValue *jsdv = JSD_GetException (mCx, mThreadState);
  3476     *_rval = jsdValue::FromPtr (mCx, jsdv);
  3477     return NS_OK;
  3480 NS_IMETHODIMP
  3481 jsdThreadState::SetPendingException(jsdIValue *aException)
  3483     JSDValue *jsdv;
  3485     nsresult rv = aException->GetJSDValue (&jsdv);
  3486     if (NS_FAILED(rv))
  3487         return NS_ERROR_FAILURE;
  3489     if (!JSD_SetException (mCx, mThreadState, jsdv))
  3490         return NS_ERROR_FAILURE;
  3492     return NS_OK;
  3495 #endif

mercurial