js/jsd/jsd_xpc.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/jsd/jsd_xpc.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3495 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jsfriendapi.h"
    1.11 +#include "jsd_xpc.h"
    1.12 +#include "xpcpublic.h"
    1.13 +
    1.14 +#include "js/GCAPI.h"
    1.15 +#include "js/OldDebugAPI.h"
    1.16 +
    1.17 +#include "nsIXPConnect.h"
    1.18 +#include "mozilla/ModuleUtils.h"
    1.19 +#include "nsIServiceManager.h"
    1.20 +#include "nsIScriptGlobalObject.h"
    1.21 +#include "nsIObserver.h"
    1.22 +#include "nsIObserverService.h"
    1.23 +#include "nsICategoryManager.h"
    1.24 +#include "nsIJSRuntimeService.h"
    1.25 +#include "nsIThreadInternal.h"
    1.26 +#include "nsIScriptError.h"
    1.27 +#include "nsTArray.h"
    1.28 +#include "nsThreadUtils.h"
    1.29 +#include "nsMemory.h"
    1.30 +#include "jsdebug.h"
    1.31 +#include "nsReadableUtils.h"
    1.32 +#include "nsCRT.h"
    1.33 +#include "nsCycleCollectionParticipant.h"
    1.34 +#include "mozilla/Attributes.h"
    1.35 +
    1.36 +/* XXX DOM dependency */
    1.37 +#include "nsIScriptContext.h"
    1.38 +#include "nsPIDOMWindow.h"
    1.39 +#include "nsDOMJSUtils.h"
    1.40 +#include "SandboxPrivate.h"
    1.41 +#include "nsJSPrincipals.h"
    1.42 +#include "nsContentUtils.h"
    1.43 +#include "mozilla/dom/ScriptSettings.h"
    1.44 +
    1.45 +using mozilla::AutoSafeJSContext;
    1.46 +using mozilla::AutoPushJSContext;
    1.47 +using mozilla::dom::AutoNoJSAPI;
    1.48 +
    1.49 +/*
    1.50 + * defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
    1.51 + * script hook.  This was a hack to avoid some js engine problems that should
    1.52 + * be fixed now (see Mozilla bug 77636).
    1.53 + */
    1.54 +#undef CAUTIOUS_SCRIPTHOOK
    1.55 +
    1.56 +#ifdef DEBUG_verbose
    1.57 +#   define DEBUG_COUNT(name, count)                                             \
    1.58 +        { if ((count % 10) == 0) printf (name ": %i\n", count); }
    1.59 +#   define DEBUG_CREATE(name, count) {count++; DEBUG_COUNT ("+++++ " name,count)}
    1.60 +#   define DEBUG_DESTROY(name, count) {count--; DEBUG_COUNT ("----- " name,count)}
    1.61 +#else
    1.62 +#   define DEBUG_CREATE(name, count) 
    1.63 +#   define DEBUG_DESTROY(name, count)
    1.64 +#endif
    1.65 +
    1.66 +#define ASSERT_VALID_CONTEXT   { if (!mCx) return NS_ERROR_NOT_AVAILABLE; }
    1.67 +#define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; }
    1.68 +
    1.69 +#define JSDSERVICE_CID                               \
    1.70 +{ /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */         \
    1.71 +     0xf1299dc2,                                     \
    1.72 +     0x1dd1,                                         \
    1.73 +     0x11b2,                                         \
    1.74 +    {0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \
    1.75 +}
    1.76 +
    1.77 +#define JSDASO_CID                                   \
    1.78 +{ /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */         \
    1.79 +     0x2fd6b7f6,                                     \
    1.80 +     0xeb8c,                                         \
    1.81 +     0x4f32,                                         \
    1.82 +    {0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \
    1.83 +}
    1.84 +
    1.85 +#define JSDS_MAJOR_VERSION 1
    1.86 +#define JSDS_MINOR_VERSION 2
    1.87 +
    1.88 +#define NS_CATMAN_CTRID   "@mozilla.org/categorymanager;1"
    1.89 +#define NS_JSRT_CTRID     "@mozilla.org/js/xpc/RuntimeService;1"
    1.90 +
    1.91 +#define AUTOREG_CATEGORY  "xpcom-autoregistration"
    1.92 +#define APPSTART_CATEGORY "app-startup"
    1.93 +#define JSD_AUTOREG_ENTRY "JSDebugger Startup Observer"
    1.94 +#define JSD_STARTUP_ENTRY "JSDebugger Startup Observer"
    1.95 +
    1.96 +static void
    1.97 +jsds_GCSliceCallbackProc (JSRuntime *rt, JS::GCProgress progress, const JS::GCDescription &desc);
    1.98 +
    1.99 +/*******************************************************************************
   1.100 + * global vars
   1.101 + ******************************************************************************/
   1.102 +
   1.103 +const char implementationString[] = "Mozilla JavaScript Debugger Service";
   1.104 +
   1.105 +const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
   1.106 +const char jsdARObserverCtrID[] = "@mozilla.org/js/jsd/app-start-observer;2";
   1.107 +const char jsdASObserverCtrID[] = "service,@mozilla.org/js/jsd/app-start-observer;2";
   1.108 +
   1.109 +#ifdef DEBUG_verbose
   1.110 +uint32_t gScriptCount   = 0;
   1.111 +uint32_t gValueCount    = 0;
   1.112 +uint32_t gPropertyCount = 0;
   1.113 +uint32_t gContextCount  = 0;
   1.114 +uint32_t gFrameCount  = 0;
   1.115 +#endif
   1.116 +
   1.117 +static jsdService          *gJsds               = 0;
   1.118 +static JS::GCSliceCallback gPrevGCSliceCallback = jsds_GCSliceCallbackProc;
   1.119 +static bool                gGCRunning           = false;
   1.120 +
   1.121 +static struct DeadScript {
   1.122 +    PRCList     links;
   1.123 +    JSDContext *jsdc;
   1.124 +    jsdIScript *script;
   1.125 +} *gDeadScripts = nullptr;
   1.126 +
   1.127 +enum PatternType {
   1.128 +    ptIgnore     = 0U,
   1.129 +    ptStartsWith = 1U,
   1.130 +    ptEndsWith   = 2U,
   1.131 +    ptContains   = 3U,
   1.132 +    ptEquals     = 4U
   1.133 +};
   1.134 +
   1.135 +static struct FilterRecord {
   1.136 +    PRCList      links;
   1.137 +    jsdIFilter  *filterObject;
   1.138 +    nsCString    urlPattern;
   1.139 +    PatternType  patternType;
   1.140 +    uint32_t     startLine;
   1.141 +    uint32_t     endLine;
   1.142 +} *gFilters = nullptr;
   1.143 +
   1.144 +static struct LiveEphemeral *gLiveValues      = nullptr;
   1.145 +static struct LiveEphemeral *gLiveProperties  = nullptr;
   1.146 +static struct LiveEphemeral *gLiveContexts    = nullptr;
   1.147 +static struct LiveEphemeral *gLiveStackFrames = nullptr;
   1.148 +
   1.149 +/*******************************************************************************
   1.150 + * utility functions for ephemeral lists
   1.151 + *******************************************************************************/
   1.152 +already_AddRefed<jsdIEphemeral>
   1.153 +jsds_FindEphemeral (LiveEphemeral **listHead, void *key)
   1.154 +{
   1.155 +    if (!*listHead)
   1.156 +        return nullptr;
   1.157 +    
   1.158 +    LiveEphemeral *lv_record = 
   1.159 +        reinterpret_cast<LiveEphemeral *>
   1.160 +                        (PR_NEXT_LINK(&(*listHead)->links));
   1.161 +    do
   1.162 +    {
   1.163 +        if (lv_record->key == key)
   1.164 +        {
   1.165 +            nsCOMPtr<jsdIEphemeral> ret = lv_record->value;
   1.166 +            return ret.forget();
   1.167 +        }
   1.168 +        lv_record = reinterpret_cast<LiveEphemeral *>
   1.169 +                                    (PR_NEXT_LINK(&lv_record->links));
   1.170 +    }
   1.171 +    while (lv_record != *listHead);
   1.172 +
   1.173 +    return nullptr;
   1.174 +}
   1.175 +
   1.176 +void
   1.177 +jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
   1.178 +{
   1.179 +    LiveEphemeral *lv_record = 
   1.180 +        reinterpret_cast<LiveEphemeral *>
   1.181 +                        (PR_NEXT_LINK(&(*listHead)->links));
   1.182 +    do
   1.183 +    {
   1.184 +        LiveEphemeral *next =
   1.185 +            reinterpret_cast<LiveEphemeral *>
   1.186 +                            (PR_NEXT_LINK(&lv_record->links));
   1.187 +        lv_record->value->Invalidate();
   1.188 +        lv_record = next;
   1.189 +    }
   1.190 +    while (*listHead);
   1.191 +}
   1.192 +
   1.193 +void
   1.194 +jsds_InsertEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
   1.195 +{
   1.196 +    if (*listHead) {
   1.197 +        /* if the list exists, add to it */
   1.198 +        PR_APPEND_LINK(&item->links, &(*listHead)->links);
   1.199 +    } else {
   1.200 +        /* otherwise create the list */
   1.201 +        PR_INIT_CLIST(&item->links);
   1.202 +        *listHead = item;
   1.203 +    }
   1.204 +}
   1.205 +
   1.206 +void
   1.207 +jsds_RemoveEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
   1.208 +{
   1.209 +    LiveEphemeral *next = reinterpret_cast<LiveEphemeral *>
   1.210 +                                          (PR_NEXT_LINK(&item->links));
   1.211 +
   1.212 +    if (next == item)
   1.213 +    {
   1.214 +        /* if the current item is also the next item, we're the only element,
   1.215 +         * null out the list head */
   1.216 +        NS_ASSERTION (*listHead == item,
   1.217 +                      "How could we not be the head of a one item list?");
   1.218 +        *listHead = nullptr;
   1.219 +    }
   1.220 +    else if (item == *listHead)
   1.221 +    {
   1.222 +        /* otherwise, if we're currently the list head, change it */
   1.223 +        *listHead = next;
   1.224 +    }
   1.225 +    
   1.226 +    PR_REMOVE_AND_INIT_LINK(&item->links);
   1.227 +}
   1.228 +
   1.229 +/*******************************************************************************
   1.230 + * utility functions for filters
   1.231 + *******************************************************************************/
   1.232 +void
   1.233 +jsds_FreeFilter (FilterRecord *rec)
   1.234 +{
   1.235 +    NS_IF_RELEASE (rec->filterObject);
   1.236 +    PR_Free (rec);
   1.237 +}
   1.238 +
   1.239 +/* copies appropriate |filter| attributes into |rec|.
   1.240 + * False return indicates failure, the contents of |rec| will not be changed.
   1.241 + */
   1.242 +bool
   1.243 +jsds_SyncFilter (FilterRecord *rec, jsdIFilter *filter)
   1.244 +{
   1.245 +    NS_ASSERTION (rec, "jsds_SyncFilter without rec");
   1.246 +    NS_ASSERTION (filter, "jsds_SyncFilter without filter");
   1.247 +
   1.248 +    uint32_t startLine;
   1.249 +    nsresult rv = filter->GetStartLine(&startLine);
   1.250 +    if (NS_FAILED(rv))
   1.251 +        return false;
   1.252 +
   1.253 +    uint32_t endLine;
   1.254 +    rv = filter->GetStartLine(&endLine);
   1.255 +    if (NS_FAILED(rv))
   1.256 +        return false;    
   1.257 +
   1.258 +    nsAutoCString urlPattern;
   1.259 +    rv = filter->GetUrlPattern (urlPattern);
   1.260 +    if (NS_FAILED(rv))
   1.261 +        return false;
   1.262 +    
   1.263 +    uint32_t len = urlPattern.Length();
   1.264 +    if (len) {
   1.265 +        if (urlPattern[0] == '*') {
   1.266 +            /* pattern starts with a *, shift all chars once to the left,
   1.267 +             * including the trailing null. */
   1.268 +            urlPattern = Substring(urlPattern, 1, len);
   1.269 +
   1.270 +            if (urlPattern[len - 2] == '*') {
   1.271 +                /* pattern is in the format "*foo*", overwrite the final * with
   1.272 +                 * a null. */
   1.273 +                urlPattern.Truncate(len - 2);
   1.274 +                rec->patternType = ptContains;
   1.275 +            } else {
   1.276 +                /* pattern is in the format "*foo", just make a note of the
   1.277 +                 * new length. */
   1.278 +                rec->patternType = ptEndsWith;
   1.279 +            }
   1.280 +        } else if (urlPattern[len - 1] == '*') {
   1.281 +            /* pattern is in the format "foo*", overwrite the final * with a 
   1.282 +             * null. */
   1.283 +            urlPattern.Truncate(len - 1);
   1.284 +            rec->patternType = ptStartsWith;
   1.285 +        } else {
   1.286 +            /* pattern is in the format "foo". */
   1.287 +            rec->patternType = ptEquals;
   1.288 +        }
   1.289 +    } else {
   1.290 +        rec->patternType = ptIgnore;
   1.291 +    }
   1.292 +
   1.293 +    /* we got everything we need without failing, now copy it into rec. */
   1.294 +
   1.295 +    if (rec->filterObject != filter) {
   1.296 +        NS_IF_RELEASE(rec->filterObject);
   1.297 +        NS_ADDREF(filter);
   1.298 +        rec->filterObject = filter;
   1.299 +    }
   1.300 +    
   1.301 +    rec->startLine     = startLine;
   1.302 +    rec->endLine       = endLine;
   1.303 +    
   1.304 +    rec->urlPattern = urlPattern;
   1.305 +
   1.306 +    return true;
   1.307 +            
   1.308 +}
   1.309 +
   1.310 +FilterRecord *
   1.311 +jsds_FindFilter (jsdIFilter *filter)
   1.312 +{
   1.313 +    if (!gFilters)
   1.314 +        return nullptr;
   1.315 +    
   1.316 +    FilterRecord *current = gFilters;
   1.317 +    
   1.318 +    do {
   1.319 +        if (current->filterObject == filter)
   1.320 +            return current;
   1.321 +        current = reinterpret_cast<FilterRecord *>
   1.322 +                                  (PR_NEXT_LINK(&current->links));
   1.323 +    } while (current != gFilters);
   1.324 +    
   1.325 +    return nullptr;
   1.326 +}
   1.327 +
   1.328 +/* returns true if the hook should be executed. */
   1.329 +bool
   1.330 +jsds_FilterHook (JSDContext *jsdc, JSDThreadState *state)
   1.331 +{
   1.332 +    JSDStackFrameInfo *frame = JSD_GetStackFrame (jsdc, state);
   1.333 +
   1.334 +    if (!frame) {
   1.335 +        NS_WARNING("No frame in threadstate");
   1.336 +        return false;
   1.337 +    }
   1.338 +
   1.339 +    JSDScript *script = JSD_GetScriptForStackFrame (jsdc, state, frame);
   1.340 +    if (!script)
   1.341 +        return true;
   1.342 +
   1.343 +    uintptr_t pc = JSD_GetPCForStackFrame (jsdc, state, frame);
   1.344 +
   1.345 +    nsCString url(JSD_GetScriptFilename (jsdc, script));
   1.346 +    if (url.IsEmpty()) {
   1.347 +        NS_WARNING ("Script with no filename");
   1.348 +        return false;
   1.349 +    }
   1.350 +
   1.351 +    if (!gFilters)
   1.352 +        return true;    
   1.353 +
   1.354 +    uint32_t currentLine = JSD_GetClosestLine (jsdc, script, pc);
   1.355 +    uint32_t len = 0;
   1.356 +    FilterRecord *currentFilter = gFilters;
   1.357 +    do {
   1.358 +        uint32_t flags = 0;
   1.359 +
   1.360 +#ifdef DEBUG
   1.361 +        nsresult rv =
   1.362 +#endif
   1.363 +            currentFilter->filterObject->GetFlags(&flags);
   1.364 +        NS_ASSERTION(NS_SUCCEEDED(rv), "Error getting flags for filter");
   1.365 +
   1.366 +        if (flags & jsdIFilter::FLAG_ENABLED) {
   1.367 +            /* If there is no start line, or the start line is before 
   1.368 +             * or equal to the current */
   1.369 +            if ((!currentFilter->startLine ||
   1.370 +                 currentFilter->startLine <= currentLine) &&
   1.371 +                /* and there is no end line, or the end line is after
   1.372 +                 * or equal to the current */
   1.373 +                (!currentFilter->endLine ||
   1.374 +                 currentFilter->endLine >= currentLine)) {
   1.375 +                /* then we're going to have to compare the url. */
   1.376 +                if (currentFilter->patternType == ptIgnore)
   1.377 +                    return !!(flags & jsdIFilter::FLAG_PASS);
   1.378 +
   1.379 +                if (!len)
   1.380 +                    len = url.Length();
   1.381 +                nsCString urlPattern = currentFilter->urlPattern;
   1.382 +                uint32_t patternLength = urlPattern.Length();
   1.383 +                if (len >= patternLength) {
   1.384 +                    switch (currentFilter->patternType) {
   1.385 +                        case ptEquals:
   1.386 +                            if (urlPattern.Equals(url))
   1.387 +                                return !!(flags & jsdIFilter::FLAG_PASS);
   1.388 +                            break;
   1.389 +                        case ptStartsWith:
   1.390 +                            if (urlPattern.Equals(Substring(url, 0, patternLength)))
   1.391 +                                return !!(flags & jsdIFilter::FLAG_PASS);
   1.392 +                            break;
   1.393 +                        case ptEndsWith:
   1.394 +                            if (urlPattern.Equals(Substring(url, len - patternLength)))
   1.395 +                                return !!(flags & jsdIFilter::FLAG_PASS);
   1.396 +                            break;
   1.397 +                        case ptContains:
   1.398 +                            {
   1.399 +                                nsACString::const_iterator start, end;
   1.400 +                                url.BeginReading(start);
   1.401 +                                url.EndReading(end);
   1.402 +                                if (FindInReadable(currentFilter->urlPattern, start, end))
   1.403 +                                    return !!(flags & jsdIFilter::FLAG_PASS);
   1.404 +                            }
   1.405 +                            break;
   1.406 +                        default:
   1.407 +                            NS_ERROR("Invalid pattern type");
   1.408 +                    }
   1.409 +                }                
   1.410 +            }
   1.411 +        }
   1.412 +        currentFilter = reinterpret_cast<FilterRecord *>
   1.413 +                                        (PR_NEXT_LINK(&currentFilter->links));
   1.414 +    } while (currentFilter != gFilters);
   1.415 +
   1.416 +    return true;
   1.417 +    
   1.418 +}
   1.419 +
   1.420 +/*******************************************************************************
   1.421 + * c callbacks
   1.422 + *******************************************************************************/
   1.423 +
   1.424 +static void
   1.425 +jsds_NotifyPendingDeadScripts (JSRuntime *rt)
   1.426 +{
   1.427 +    jsdService *jsds = gJsds;
   1.428 +
   1.429 +    nsCOMPtr<jsdIScriptHook> hook;
   1.430 +    if (jsds) {
   1.431 +        NS_ADDREF(jsds);
   1.432 +        jsds->GetScriptHook (getter_AddRefs(hook));
   1.433 +        jsds->DoPause(nullptr, true);
   1.434 +    }
   1.435 +
   1.436 +    DeadScript *deadScripts = gDeadScripts;
   1.437 +    gDeadScripts = nullptr;
   1.438 +    while (deadScripts) {
   1.439 +        DeadScript *ds = deadScripts;
   1.440 +        /* get next deleted script */
   1.441 +        deadScripts = reinterpret_cast<DeadScript *>
   1.442 +                                       (PR_NEXT_LINK(&ds->links));
   1.443 +        if (deadScripts == ds)
   1.444 +            deadScripts = nullptr;
   1.445 +
   1.446 +        if (hook)
   1.447 +        {
   1.448 +            /* tell the user this script has been destroyed */
   1.449 +#ifdef CAUTIOUS_SCRIPTHOOK
   1.450 +            JS_UNKEEP_ATOMS(rt);
   1.451 +#endif
   1.452 +            hook->OnScriptDestroyed (ds->script);
   1.453 +#ifdef CAUTIOUS_SCRIPTHOOK
   1.454 +            JS_KEEP_ATOMS(rt);
   1.455 +#endif
   1.456 +        }
   1.457 +
   1.458 +        /* take it out of the circular list */
   1.459 +        PR_REMOVE_LINK(&ds->links);
   1.460 +
   1.461 +        /* addref came from the FromPtr call in jsds_ScriptHookProc */
   1.462 +        NS_RELEASE(ds->script);
   1.463 +        /* free the struct! */
   1.464 +        PR_Free(ds);
   1.465 +    }
   1.466 +
   1.467 +    if (jsds) {
   1.468 +        jsds->DoUnPause(nullptr, true);
   1.469 +        NS_RELEASE(jsds);
   1.470 +    }
   1.471 +}
   1.472 +
   1.473 +static void
   1.474 +jsds_GCSliceCallbackProc (JSRuntime *rt, JS::GCProgress progress, const JS::GCDescription &desc)
   1.475 +{
   1.476 +    if (progress == JS::GC_CYCLE_END || progress == JS::GC_SLICE_END) {
   1.477 +        NS_ASSERTION(gGCRunning, "GC slice callback was missed");
   1.478 +
   1.479 +        while (gDeadScripts)
   1.480 +            jsds_NotifyPendingDeadScripts (rt);
   1.481 +
   1.482 +        gGCRunning = false;
   1.483 +    } else {
   1.484 +        NS_ASSERTION(!gGCRunning, "should not re-enter GC");
   1.485 +        gGCRunning = true;
   1.486 +    }
   1.487 +
   1.488 +    if (gPrevGCSliceCallback)
   1.489 +        (*gPrevGCSliceCallback)(rt, progress, desc);
   1.490 +}
   1.491 +
   1.492 +static unsigned
   1.493 +jsds_ErrorHookProc (JSDContext *jsdc, JSContext *cx, const char *message,
   1.494 +                    JSErrorReport *report, void *callerdata)
   1.495 +{
   1.496 +    static bool running = false;
   1.497 +
   1.498 +    nsCOMPtr<jsdIErrorHook> hook;
   1.499 +    gJsds->GetErrorHook(getter_AddRefs(hook));
   1.500 +    if (!hook)
   1.501 +        return JSD_ERROR_REPORTER_PASS_ALONG;
   1.502 +
   1.503 +    if (running)
   1.504 +        return JSD_ERROR_REPORTER_PASS_ALONG;
   1.505 +
   1.506 +    running = true;
   1.507 +
   1.508 +    nsCOMPtr<jsdIValue> val;
   1.509 +    if (JS_IsExceptionPending(cx)) {
   1.510 +        JS::RootedValue jv(cx);
   1.511 +        JS_GetPendingException(cx, &jv);
   1.512 +        JSDValue *jsdv = JSD_NewValue (jsdc, jv);
   1.513 +        val = dont_AddRef(jsdValue::FromPtr(jsdc, jsdv));
   1.514 +    }
   1.515 +
   1.516 +    nsAutoCString fileName;
   1.517 +    uint32_t    line;
   1.518 +    uint32_t    pos;
   1.519 +    uint32_t    flags;
   1.520 +    uint32_t    errnum;
   1.521 +    bool        rval;
   1.522 +    if (report) {
   1.523 +        fileName.Assign(report->filename);
   1.524 +        line = report->lineno;
   1.525 +        pos = report->tokenptr - report->linebuf;
   1.526 +        flags = report->flags;
   1.527 +        errnum = report->errorNumber;
   1.528 +    }
   1.529 +    else
   1.530 +    {
   1.531 +        line     = 0;
   1.532 +        pos      = 0;
   1.533 +        flags    = 0;
   1.534 +        errnum   = 0;
   1.535 +    }
   1.536 +    
   1.537 +    gJsds->DoPause(nullptr, true);
   1.538 +    hook->OnError (nsDependentCString(message), fileName, line, pos, flags, errnum, val, &rval);
   1.539 +    gJsds->DoUnPause(nullptr, true);
   1.540 +    
   1.541 +    running = false;
   1.542 +    if (!rval)
   1.543 +        return JSD_ERROR_REPORTER_DEBUG;
   1.544 +    
   1.545 +    return JSD_ERROR_REPORTER_PASS_ALONG;
   1.546 +}
   1.547 +
   1.548 +static bool
   1.549 +jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
   1.550 +                   unsigned type, void* callerdata)
   1.551 +{
   1.552 +    nsCOMPtr<jsdICallHook> hook;
   1.553 +
   1.554 +    switch (type)
   1.555 +    {
   1.556 +        case JSD_HOOK_TOPLEVEL_START:
   1.557 +        case JSD_HOOK_TOPLEVEL_END:
   1.558 +            gJsds->GetTopLevelHook(getter_AddRefs(hook));
   1.559 +            break;
   1.560 +            
   1.561 +        case JSD_HOOK_FUNCTION_CALL:
   1.562 +        case JSD_HOOK_FUNCTION_RETURN:
   1.563 +            gJsds->GetFunctionHook(getter_AddRefs(hook));
   1.564 +            break;
   1.565 +
   1.566 +        default:
   1.567 +            NS_ASSERTION (0, "Unknown hook type.");
   1.568 +    }
   1.569 +    
   1.570 +    if (!hook)
   1.571 +        return true;
   1.572 +
   1.573 +    if (!jsds_FilterHook (jsdc, jsdthreadstate))
   1.574 +        return false;
   1.575 +
   1.576 +    JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
   1.577 +    nsCOMPtr<jsdIStackFrame> frame =
   1.578 +        dont_AddRef(jsdStackFrame::FromPtr(jsdc, jsdthreadstate, native_frame));
   1.579 +    gJsds->DoPause(nullptr, true);
   1.580 +    hook->OnCall(frame, type);    
   1.581 +    gJsds->DoUnPause(nullptr, true);
   1.582 +    jsdStackFrame::InvalidateAll();
   1.583 +
   1.584 +    return true;
   1.585 +}
   1.586 +
   1.587 +static uint32_t
   1.588 +jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
   1.589 +                        unsigned type, void* callerdata, jsval* rval)
   1.590 +{
   1.591 +    nsCOMPtr<jsdIExecutionHook> hook(0);
   1.592 +    uint32_t hook_rv = JSD_HOOK_RETURN_CONTINUE;
   1.593 +    nsCOMPtr<jsdIValue> js_rv;
   1.594 +
   1.595 +    switch (type)
   1.596 +    {
   1.597 +        case JSD_HOOK_INTERRUPTED:
   1.598 +            gJsds->GetInterruptHook(getter_AddRefs(hook));
   1.599 +            break;
   1.600 +        case JSD_HOOK_DEBUG_REQUESTED:
   1.601 +            gJsds->GetDebugHook(getter_AddRefs(hook));
   1.602 +            break;
   1.603 +        case JSD_HOOK_DEBUGGER_KEYWORD:
   1.604 +            gJsds->GetDebuggerHook(getter_AddRefs(hook));
   1.605 +            break;
   1.606 +        case JSD_HOOK_BREAKPOINT:
   1.607 +            {
   1.608 +                /* we can't pause breakpoints the way we pause the other
   1.609 +                 * execution hooks (at least, not easily.)  Instead we bail
   1.610 +                 * here if the service is paused. */
   1.611 +                uint32_t level;
   1.612 +                gJsds->GetPauseDepth(&level);
   1.613 +                if (!level)
   1.614 +                    gJsds->GetBreakpointHook(getter_AddRefs(hook));
   1.615 +            }
   1.616 +            break;
   1.617 +        case JSD_HOOK_THROW:
   1.618 +        {
   1.619 +            hook_rv = JSD_HOOK_RETURN_CONTINUE_THROW;
   1.620 +            gJsds->GetThrowHook(getter_AddRefs(hook));
   1.621 +            if (hook) {
   1.622 +                JSDValue *jsdv = JSD_GetException (jsdc, jsdthreadstate);
   1.623 +                js_rv = dont_AddRef(jsdValue::FromPtr (jsdc, jsdv));
   1.624 +            }
   1.625 +            break;
   1.626 +        }
   1.627 +        default:
   1.628 +            NS_ASSERTION (0, "Unknown hook type.");
   1.629 +    }
   1.630 +
   1.631 +    if (!hook)
   1.632 +        return hook_rv;
   1.633 +    
   1.634 +    if (!jsds_FilterHook (jsdc, jsdthreadstate))
   1.635 +        return JSD_HOOK_RETURN_CONTINUE;
   1.636 +    
   1.637 +    JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
   1.638 +    nsCOMPtr<jsdIStackFrame> frame =
   1.639 +        dont_AddRef(jsdStackFrame::FromPtr(jsdc, jsdthreadstate, native_frame));
   1.640 +    gJsds->DoPause(nullptr, true);
   1.641 +    jsdIValue *inout_rv = js_rv;
   1.642 +    NS_IF_ADDREF(inout_rv);
   1.643 +    hook->OnExecute (frame, type, &inout_rv, &hook_rv);
   1.644 +    js_rv = inout_rv;
   1.645 +    NS_IF_RELEASE(inout_rv);
   1.646 +    gJsds->DoUnPause(nullptr, true);
   1.647 +    jsdStackFrame::InvalidateAll();
   1.648 +        
   1.649 +    if (hook_rv == JSD_HOOK_RETURN_RET_WITH_VAL ||
   1.650 +        hook_rv == JSD_HOOK_RETURN_THROW_WITH_VAL) {
   1.651 +        *rval = JSVAL_VOID;
   1.652 +        if (js_rv) {
   1.653 +            JSDValue *jsdv;
   1.654 +            if (NS_SUCCEEDED(js_rv->GetJSDValue (&jsdv)))
   1.655 +                *rval = JSD_GetValueWrappedJSVal(jsdc, jsdv);
   1.656 +        }
   1.657 +    }
   1.658 +    
   1.659 +    return hook_rv;
   1.660 +}
   1.661 +
   1.662 +static void
   1.663 +jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, bool creating,
   1.664 +                     void* callerdata)
   1.665 +{
   1.666 +#ifdef CAUTIOUS_SCRIPTHOOK
   1.667 +    JSRuntime *rt = JS_GetRuntime(nsContentUtils::GetSafeJSContext());
   1.668 +#endif
   1.669 +
   1.670 +    if (creating) {
   1.671 +        nsCOMPtr<jsdIScriptHook> hook;
   1.672 +        gJsds->GetScriptHook(getter_AddRefs(hook));
   1.673 +
   1.674 +        /* a script is being created */
   1.675 +        if (!hook) {
   1.676 +            /* nobody cares, just exit */
   1.677 +            return;
   1.678 +        }
   1.679 +            
   1.680 +        nsCOMPtr<jsdIScript> script = 
   1.681 +            dont_AddRef(jsdScript::FromPtr(jsdc, jsdscript));
   1.682 +#ifdef CAUTIOUS_SCRIPTHOOK
   1.683 +        JS_UNKEEP_ATOMS(rt);
   1.684 +#endif
   1.685 +        gJsds->DoPause(nullptr, true);
   1.686 +        hook->OnScriptCreated (script);
   1.687 +        gJsds->DoUnPause(nullptr, true);
   1.688 +#ifdef CAUTIOUS_SCRIPTHOOK
   1.689 +        JS_KEEP_ATOMS(rt);
   1.690 +#endif
   1.691 +    } else {
   1.692 +        /* a script is being destroyed.  even if there is no registered hook
   1.693 +         * we'll still need to invalidate the jsdIScript record, in order
   1.694 +         * to remove the reference held in the JSDScript private data. */
   1.695 +        nsCOMPtr<jsdIScript> jsdis = 
   1.696 +            static_cast<jsdIScript *>(JSD_GetScriptPrivate(jsdscript));
   1.697 +        if (!jsdis)
   1.698 +            return;
   1.699 +
   1.700 +        jsdis->Invalidate();
   1.701 +
   1.702 +        if (!gGCRunning) {
   1.703 +            nsCOMPtr<jsdIScriptHook> hook;
   1.704 +            gJsds->GetScriptHook(getter_AddRefs(hook));
   1.705 +            if (!hook)
   1.706 +                return;
   1.707 +
   1.708 +            /* if GC *isn't* running, we can tell the user about the script
   1.709 +             * delete now. */
   1.710 +#ifdef CAUTIOUS_SCRIPTHOOK
   1.711 +            JS_UNKEEP_ATOMS(rt);
   1.712 +#endif
   1.713 +                
   1.714 +            gJsds->DoPause(nullptr, true);
   1.715 +            hook->OnScriptDestroyed (jsdis);
   1.716 +            gJsds->DoUnPause(nullptr, true);
   1.717 +#ifdef CAUTIOUS_SCRIPTHOOK
   1.718 +            JS_KEEP_ATOMS(rt);
   1.719 +#endif
   1.720 +        } else {
   1.721 +            /* if a GC *is* running, we've got to wait until it's done before
   1.722 +             * we can execute any JS, so we queue the notification in a PRCList
   1.723 +             * until GC tells us it's done. See jsds_GCCallbackProc(). */
   1.724 +            DeadScript *ds = PR_NEW(DeadScript);
   1.725 +            if (!ds)
   1.726 +                return; /* NS_ERROR_OUT_OF_MEMORY */
   1.727 +        
   1.728 +            ds->jsdc = jsdc;
   1.729 +            ds->script = jsdis;
   1.730 +            NS_ADDREF(ds->script);
   1.731 +            if (gDeadScripts)
   1.732 +                /* if the queue exists, add to it */
   1.733 +                PR_APPEND_LINK(&ds->links, &gDeadScripts->links);
   1.734 +            else {
   1.735 +                /* otherwise create the queue */
   1.736 +                PR_INIT_CLIST(&ds->links);
   1.737 +                gDeadScripts = ds;
   1.738 +            }
   1.739 +        }
   1.740 +    }            
   1.741 +}
   1.742 +
   1.743 +/*******************************************************************************
   1.744 + * reflected jsd data structures
   1.745 + *******************************************************************************/
   1.746 +
   1.747 +/* Contexts */
   1.748 +/*
   1.749 +NS_IMPL_ISUPPORTS(jsdContext, jsdIContext, jsdIEphemeral);
   1.750 +
   1.751 +NS_IMETHODIMP
   1.752 +jsdContext::GetJSDContext(JSDContext **_rval)
   1.753 +{
   1.754 +    *_rval = mCx;
   1.755 +    return NS_OK;
   1.756 +}
   1.757 +*/
   1.758 +
   1.759 +/* Objects */
   1.760 +NS_IMPL_ISUPPORTS(jsdObject, jsdIObject)
   1.761 +
   1.762 +NS_IMETHODIMP
   1.763 +jsdObject::GetJSDContext(JSDContext **_rval)
   1.764 +{
   1.765 +    *_rval = mCx;
   1.766 +    return NS_OK;
   1.767 +}
   1.768 +
   1.769 +NS_IMETHODIMP
   1.770 +jsdObject::GetJSDObject(JSDObject **_rval)
   1.771 +{
   1.772 +    *_rval = mObject;
   1.773 +    return NS_OK;
   1.774 +}
   1.775 +
   1.776 +NS_IMETHODIMP
   1.777 +jsdObject::GetCreatorURL(nsACString &_rval)
   1.778 +{
   1.779 +    _rval.Assign(JSD_GetObjectNewURL(mCx, mObject));
   1.780 +    return NS_OK;
   1.781 +}
   1.782 +
   1.783 +NS_IMETHODIMP
   1.784 +jsdObject::GetCreatorLine(uint32_t *_rval)
   1.785 +{
   1.786 +    *_rval = JSD_GetObjectNewLineNumber(mCx, mObject);
   1.787 +    return NS_OK;
   1.788 +}
   1.789 +
   1.790 +NS_IMETHODIMP
   1.791 +jsdObject::GetConstructorURL(nsACString &_rval)
   1.792 +{
   1.793 +    _rval.Assign(JSD_GetObjectConstructorURL(mCx, mObject));
   1.794 +    return NS_OK;
   1.795 +}
   1.796 +
   1.797 +NS_IMETHODIMP
   1.798 +jsdObject::GetConstructorLine(uint32_t *_rval)
   1.799 +{
   1.800 +    *_rval = JSD_GetObjectConstructorLineNumber(mCx, mObject);
   1.801 +    return NS_OK;
   1.802 +}
   1.803 +
   1.804 +NS_IMETHODIMP
   1.805 +jsdObject::GetValue(jsdIValue **_rval)
   1.806 +{
   1.807 +    JSDValue *jsdv = JSD_GetValueForObject (mCx, mObject);
   1.808 +    
   1.809 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
   1.810 +    return NS_OK;
   1.811 +}
   1.812 +
   1.813 +/* Properties */
   1.814 +NS_IMPL_ISUPPORTS(jsdProperty, jsdIProperty, jsdIEphemeral)
   1.815 +
   1.816 +jsdProperty::jsdProperty (JSDContext *aCx, JSDProperty *aProperty) :
   1.817 +    mCx(aCx), mProperty(aProperty)
   1.818 +{
   1.819 +    DEBUG_CREATE ("jsdProperty", gPropertyCount);
   1.820 +    mValid = (aCx && aProperty);
   1.821 +    mLiveListEntry.value = this;
   1.822 +    jsds_InsertEphemeral (&gLiveProperties, &mLiveListEntry);
   1.823 +}
   1.824 +
   1.825 +jsdProperty::~jsdProperty () 
   1.826 +{
   1.827 +    DEBUG_DESTROY ("jsdProperty", gPropertyCount);
   1.828 +    if (mValid)
   1.829 +        Invalidate();
   1.830 +}
   1.831 +
   1.832 +NS_IMETHODIMP
   1.833 +jsdProperty::Invalidate()
   1.834 +{
   1.835 +    ASSERT_VALID_EPHEMERAL;
   1.836 +    mValid = false;
   1.837 +    jsds_RemoveEphemeral (&gLiveProperties, &mLiveListEntry);
   1.838 +    JSD_DropProperty (mCx, mProperty);
   1.839 +    return NS_OK;
   1.840 +}
   1.841 +
   1.842 +void
   1.843 +jsdProperty::InvalidateAll()
   1.844 +{
   1.845 +    if (gLiveProperties)
   1.846 +        jsds_InvalidateAllEphemerals (&gLiveProperties);
   1.847 +}
   1.848 +
   1.849 +NS_IMETHODIMP
   1.850 +jsdProperty::GetJSDContext(JSDContext **_rval)
   1.851 +{
   1.852 +    *_rval = mCx;
   1.853 +    return NS_OK;
   1.854 +}
   1.855 +
   1.856 +NS_IMETHODIMP
   1.857 +jsdProperty::GetJSDProperty(JSDProperty **_rval)
   1.858 +{
   1.859 +    *_rval = mProperty;
   1.860 +    return NS_OK;
   1.861 +}
   1.862 +
   1.863 +NS_IMETHODIMP
   1.864 +jsdProperty::GetIsValid(bool *_rval)
   1.865 +{
   1.866 +    *_rval = mValid;
   1.867 +    return NS_OK;
   1.868 +}
   1.869 +
   1.870 +NS_IMETHODIMP
   1.871 +jsdProperty::GetAlias(jsdIValue **_rval)
   1.872 +{
   1.873 +    JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
   1.874 +    
   1.875 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
   1.876 +    return NS_OK;
   1.877 +}
   1.878 +
   1.879 +NS_IMETHODIMP
   1.880 +jsdProperty::GetFlags(uint32_t *_rval)
   1.881 +{
   1.882 +    *_rval = JSD_GetPropertyFlags (mCx, mProperty);
   1.883 +    return NS_OK;
   1.884 +}
   1.885 +
   1.886 +NS_IMETHODIMP
   1.887 +jsdProperty::GetName(jsdIValue **_rval)
   1.888 +{
   1.889 +    JSDValue *jsdv = JSD_GetPropertyName (mCx, mProperty);
   1.890 +    
   1.891 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
   1.892 +    return NS_OK;
   1.893 +}
   1.894 +
   1.895 +NS_IMETHODIMP
   1.896 +jsdProperty::GetValue(jsdIValue **_rval)
   1.897 +{
   1.898 +    JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
   1.899 +    
   1.900 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
   1.901 +    return NS_OK;
   1.902 +}
   1.903 +
   1.904 +/* Scripts */
   1.905 +NS_IMPL_ISUPPORTS(jsdScript, jsdIScript, jsdIEphemeral)
   1.906 +
   1.907 +static NS_IMETHODIMP
   1.908 +AssignToJSString(JSDContext *aCx, nsACString *x, JSString *str_)
   1.909 +{
   1.910 +    if (!str_) {
   1.911 +        x->SetLength(0);
   1.912 +        return NS_OK;
   1.913 +    }
   1.914 +    JS::RootedString str(JSD_GetJSRuntime(aCx), str_);
   1.915 +    AutoSafeJSContext cx;
   1.916 +    JSAutoCompartment ac(cx, JSD_GetDefaultGlobal(aCx)); // Just in case.
   1.917 +    size_t length = JS_GetStringEncodingLength(cx, str);
   1.918 +    if (length == size_t(-1))
   1.919 +        return NS_ERROR_FAILURE;
   1.920 +    x->SetLength(uint32_t(length));
   1.921 +    if (x->Length() != uint32_t(length))
   1.922 +        return NS_ERROR_OUT_OF_MEMORY;
   1.923 +    JS_EncodeStringToBuffer(cx, str, x->BeginWriting(), length);
   1.924 +    return NS_OK;
   1.925 +}
   1.926 +
   1.927 +jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(false),
   1.928 +                                                             mTag(0),
   1.929 +                                                             mCx(aCx),
   1.930 +                                                             mScript(aScript),
   1.931 +                                                             mFileName(0), 
   1.932 +                                                             mFunctionName(0),
   1.933 +                                                             mBaseLineNumber(0),
   1.934 +                                                             mLineExtent(0),
   1.935 +                                                             mPPLineMap(0),
   1.936 +                                                             mFirstPC(0)
   1.937 +{
   1.938 +    DEBUG_CREATE ("jsdScript", gScriptCount);
   1.939 +
   1.940 +    if (mScript) {
   1.941 +        /* copy the script's information now, so we have it later, when it
   1.942 +         * gets destroyed. */
   1.943 +        JSD_LockScriptSubsystem(mCx);
   1.944 +        mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
   1.945 +        mFunctionName = new nsCString();
   1.946 +        if (mFunctionName) {
   1.947 +            JSString *str = JSD_GetScriptFunctionId(mCx, mScript);
   1.948 +            if (str)
   1.949 +                AssignToJSString(mCx, mFunctionName, str);
   1.950 +        }
   1.951 +        mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
   1.952 +        mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
   1.953 +        mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
   1.954 +        JSD_UnlockScriptSubsystem(mCx);
   1.955 +        
   1.956 +        mValid = true;
   1.957 +    }
   1.958 +}
   1.959 +
   1.960 +jsdScript::~jsdScript () 
   1.961 +{
   1.962 +    DEBUG_DESTROY ("jsdScript", gScriptCount);
   1.963 +    delete mFileName;
   1.964 +    delete mFunctionName;
   1.965 +
   1.966 +    if (mPPLineMap)
   1.967 +        PR_Free(mPPLineMap);
   1.968 +
   1.969 +    /* Invalidate() needs to be called to release an owning reference to
   1.970 +     * ourselves, so if we got here without being invalidated, something
   1.971 +     * has gone wrong with our ref count. */
   1.972 +    NS_ASSERTION (!mValid, "Script destroyed without being invalidated.");
   1.973 +}
   1.974 +
   1.975 +/*
   1.976 + * This method populates a line <-> pc map for a pretty printed version of this
   1.977 + * script.  It does this by decompiling, and then recompiling the script.  The
   1.978 + * resulting script is scanned for the line map, and then left as GC fodder.
   1.979 + */
   1.980 +PCMapEntry *
   1.981 +jsdScript::CreatePPLineMap()
   1.982 +{
   1.983 +    AutoSafeJSContext cx;
   1.984 +    JSAutoCompartment ac(cx, JSD_GetDefaultGlobal (mCx)); // Just in case.
   1.985 +    JS::RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
   1.986 +    if (!obj)
   1.987 +        return nullptr;
   1.988 +    JS::RootedFunction fun(cx, JSD_GetJSFunction (mCx, mScript));
   1.989 +    JS::RootedScript script(cx); /* In JSD compartment */
   1.990 +    uint32_t    baseLine;
   1.991 +    JS::RootedString jsstr(cx);
   1.992 +    size_t      length;
   1.993 +    const jschar *chars;
   1.994 +
   1.995 +    if (fun) {
   1.996 +        unsigned nargs;
   1.997 +
   1.998 +        {
   1.999 +            JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
  1.1000 +            nargs = JS_GetFunctionArgumentCount(cx, fun);
  1.1001 +            if (nargs > 12)
  1.1002 +                return nullptr;
  1.1003 +            jsstr = JS_DecompileFunctionBody (cx, fun, 4);
  1.1004 +            if (!jsstr)
  1.1005 +                return nullptr;
  1.1006 +
  1.1007 +            if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
  1.1008 +                return nullptr;
  1.1009 +        }
  1.1010 +
  1.1011 +        JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
  1.1012 +        static const char *const argnames[] = {
  1.1013 +            "arg1", "arg2", "arg3", "arg4",
  1.1014 +            "arg5", "arg6", "arg7", "arg8",
  1.1015 +            "arg9", "arg10", "arg11", "arg12"
  1.1016 +        };
  1.1017 +        JS::CompileOptions options(cx);
  1.1018 +        options.setFileAndLine("x-jsd:ppbuffer?type=function", 3);
  1.1019 +        fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
  1.1020 +                                    length, options);
  1.1021 +        if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
  1.1022 +            return nullptr;
  1.1023 +        baseLine = 3;
  1.1024 +    } else {
  1.1025 +        script = JSD_GetJSScript(mCx, mScript);
  1.1026 +        JSString *jsstr;
  1.1027 +
  1.1028 +        {
  1.1029 +            JSAutoCompartment ac(cx, script);
  1.1030 +
  1.1031 +            jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
  1.1032 +            if (!jsstr)
  1.1033 +                return nullptr;
  1.1034 +
  1.1035 +            if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
  1.1036 +                return nullptr;
  1.1037 +        }
  1.1038 +
  1.1039 +        JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
  1.1040 +        JS::CompileOptions options(cx);
  1.1041 +        options.setFileAndLine("x-jsd:ppbuffer?type=script", 1);
  1.1042 +        script = JS_CompileUCScript(cx, obj, chars, length, options);
  1.1043 +        if (!script)
  1.1044 +            return nullptr;
  1.1045 +        baseLine = 1;
  1.1046 +    }
  1.1047 +
  1.1048 +    uint32_t scriptExtent = JS_GetScriptLineExtent (cx, script);
  1.1049 +    jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0);
  1.1050 +    /* allocate worst case size of map (number of lines in script + 1
  1.1051 +     * for our 0 record), we'll shrink it with a realloc later. */
  1.1052 +    PCMapEntry *lineMap =
  1.1053 +        static_cast<PCMapEntry *>
  1.1054 +                   (PR_Malloc((scriptExtent + 1) * sizeof (PCMapEntry)));
  1.1055 +    uint32_t lineMapSize = 0;
  1.1056 +
  1.1057 +    if (lineMap) {
  1.1058 +        for (uint32_t line = baseLine; line < scriptExtent + baseLine; ++line) {
  1.1059 +            jsbytecode* pc = JS_LineNumberToPC (cx, script, line);
  1.1060 +            if (line == JS_PCToLineNumber (cx, script, pc)) {
  1.1061 +                lineMap[lineMapSize].line = line;
  1.1062 +                lineMap[lineMapSize].pc = pc - firstPC;
  1.1063 +                ++lineMapSize;
  1.1064 +            }
  1.1065 +        }
  1.1066 +        if (scriptExtent != lineMapSize) {
  1.1067 +            lineMap =
  1.1068 +                static_cast<PCMapEntry *>
  1.1069 +                           (PR_Realloc(mPPLineMap = lineMap,
  1.1070 +                                       lineMapSize * sizeof(PCMapEntry)));
  1.1071 +            if (!lineMap) {
  1.1072 +                PR_Free(mPPLineMap);
  1.1073 +                lineMapSize = 0;
  1.1074 +            }
  1.1075 +        }
  1.1076 +    }
  1.1077 +
  1.1078 +    mPCMapSize = lineMapSize;
  1.1079 +    return mPPLineMap = lineMap;
  1.1080 +}
  1.1081 +
  1.1082 +uint32_t
  1.1083 +jsdScript::PPPcToLine (uint32_t aPC)
  1.1084 +{
  1.1085 +    if (!mPPLineMap && !CreatePPLineMap())
  1.1086 +        return 0;
  1.1087 +    uint32_t i;
  1.1088 +    for (i = 1; i < mPCMapSize; ++i) {
  1.1089 +        if (mPPLineMap[i].pc > aPC)
  1.1090 +            return mPPLineMap[i - 1].line;            
  1.1091 +    }
  1.1092 +
  1.1093 +    return mPPLineMap[mPCMapSize - 1].line;
  1.1094 +}
  1.1095 +
  1.1096 +uint32_t
  1.1097 +jsdScript::PPLineToPc (uint32_t aLine)
  1.1098 +{
  1.1099 +    if (!mPPLineMap && !CreatePPLineMap())
  1.1100 +        return 0;
  1.1101 +    uint32_t i;
  1.1102 +    for (i = 1; i < mPCMapSize; ++i) {
  1.1103 +        if (mPPLineMap[i].line > aLine)
  1.1104 +            return mPPLineMap[i - 1].pc;
  1.1105 +    }
  1.1106 +
  1.1107 +    return mPPLineMap[mPCMapSize - 1].pc;
  1.1108 +}
  1.1109 +
  1.1110 +NS_IMETHODIMP
  1.1111 +jsdScript::GetJSDContext(JSDContext **_rval)
  1.1112 +{
  1.1113 +    ASSERT_VALID_EPHEMERAL;
  1.1114 +    *_rval = mCx;
  1.1115 +    return NS_OK;
  1.1116 +}
  1.1117 +
  1.1118 +NS_IMETHODIMP
  1.1119 +jsdScript::GetJSDScript(JSDScript **_rval)
  1.1120 +{
  1.1121 +    ASSERT_VALID_EPHEMERAL;
  1.1122 +    *_rval = mScript;
  1.1123 +    return NS_OK;
  1.1124 +}
  1.1125 +
  1.1126 +NS_IMETHODIMP
  1.1127 +jsdScript::GetVersion (int32_t *_rval)
  1.1128 +{
  1.1129 +    ASSERT_VALID_EPHEMERAL;
  1.1130 +    AutoSafeJSContext cx;
  1.1131 +    JS::RootedScript script(cx, JSD_GetJSScript(mCx, mScript));
  1.1132 +    JSAutoCompartment ac(cx, script);
  1.1133 +    *_rval = static_cast<int32_t>(JS_GetScriptVersion(cx, script));
  1.1134 +    return NS_OK;
  1.1135 +}
  1.1136 +
  1.1137 +NS_IMETHODIMP
  1.1138 +jsdScript::GetTag(uint32_t *_rval)
  1.1139 +{
  1.1140 +    if (!mTag)
  1.1141 +        mTag = ++jsdScript::LastTag;
  1.1142 +    
  1.1143 +    *_rval = mTag;
  1.1144 +    return NS_OK;
  1.1145 +}
  1.1146 +
  1.1147 +NS_IMETHODIMP
  1.1148 +jsdScript::Invalidate()
  1.1149 +{
  1.1150 +    ASSERT_VALID_EPHEMERAL;
  1.1151 +    mValid = false;
  1.1152 +    
  1.1153 +    /* release the addref we do in FromPtr */
  1.1154 +    jsdIScript *script = static_cast<jsdIScript *>
  1.1155 +                                    (JSD_GetScriptPrivate(mScript));
  1.1156 +    NS_ASSERTION (script == this, "That's not my script!");
  1.1157 +    NS_RELEASE(script);
  1.1158 +    JSD_SetScriptPrivate(mScript, nullptr);
  1.1159 +    return NS_OK;
  1.1160 +}
  1.1161 +
  1.1162 +void
  1.1163 +jsdScript::InvalidateAll ()
  1.1164 +{
  1.1165 +    JSDContext *cx;
  1.1166 +    if (NS_FAILED(gJsds->GetJSDContext (&cx)))
  1.1167 +        return;
  1.1168 +
  1.1169 +    JSDScript *script;
  1.1170 +    JSDScript *iter = nullptr;
  1.1171 +    
  1.1172 +    JSD_LockScriptSubsystem(cx);
  1.1173 +    while((script = JSD_IterateScripts(cx, &iter)) != nullptr) {
  1.1174 +        nsCOMPtr<jsdIScript> jsdis = 
  1.1175 +            static_cast<jsdIScript *>(JSD_GetScriptPrivate(script));
  1.1176 +        if (jsdis)
  1.1177 +            jsdis->Invalidate();
  1.1178 +    }
  1.1179 +    JSD_UnlockScriptSubsystem(cx);
  1.1180 +}
  1.1181 +
  1.1182 +NS_IMETHODIMP
  1.1183 +jsdScript::GetIsValid(bool *_rval)
  1.1184 +{
  1.1185 +    *_rval = mValid;
  1.1186 +    return NS_OK;
  1.1187 +}
  1.1188 +
  1.1189 +NS_IMETHODIMP
  1.1190 +jsdScript::SetFlags(uint32_t flags)
  1.1191 +{
  1.1192 +    ASSERT_VALID_EPHEMERAL;
  1.1193 +    JSD_SetScriptFlags(mCx, mScript, flags);
  1.1194 +    return NS_OK;
  1.1195 +}
  1.1196 +
  1.1197 +NS_IMETHODIMP
  1.1198 +jsdScript::GetFlags(uint32_t *_rval)
  1.1199 +{
  1.1200 +    ASSERT_VALID_EPHEMERAL;
  1.1201 +    *_rval = JSD_GetScriptFlags(mCx, mScript);
  1.1202 +    return NS_OK;
  1.1203 +}
  1.1204 +
  1.1205 +NS_IMETHODIMP
  1.1206 +jsdScript::GetFileName(nsACString &_rval)
  1.1207 +{
  1.1208 +    _rval.Assign(*mFileName);
  1.1209 +    return NS_OK;
  1.1210 +}
  1.1211 +
  1.1212 +NS_IMETHODIMP
  1.1213 +jsdScript::GetFunctionName(nsACString &_rval)
  1.1214 +{
  1.1215 +    _rval.Assign(*mFunctionName);
  1.1216 +    return NS_OK;
  1.1217 +}
  1.1218 +
  1.1219 +NS_IMETHODIMP
  1.1220 +jsdScript::GetParameterNames(uint32_t* count, char16_t*** paramNames)
  1.1221 +{
  1.1222 +    ASSERT_VALID_EPHEMERAL;
  1.1223 +    AutoSafeJSContext cx;
  1.1224 +    JS::RootedFunction fun(cx, JSD_GetJSFunction (mCx, mScript));
  1.1225 +    if (!fun) {
  1.1226 +        *count = 0;
  1.1227 +        *paramNames = nullptr;
  1.1228 +        return NS_OK;
  1.1229 +    }
  1.1230 +
  1.1231 +    JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
  1.1232 +
  1.1233 +    unsigned nargs;
  1.1234 +    if (!JS_FunctionHasLocalNames(cx, fun) ||
  1.1235 +        (nargs = JS_GetFunctionArgumentCount(cx, fun)) == 0) {
  1.1236 +        *count = 0;
  1.1237 +        *paramNames = nullptr;
  1.1238 +        return NS_OK;
  1.1239 +    }
  1.1240 +
  1.1241 +    char16_t **ret =
  1.1242 +        static_cast<char16_t**>(NS_Alloc(nargs * sizeof(char16_t*)));
  1.1243 +    if (!ret)
  1.1244 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1245 +
  1.1246 +    void *mark;
  1.1247 +    uintptr_t *names = JS_GetFunctionLocalNameArray(cx, fun, &mark);
  1.1248 +    if (!names) {
  1.1249 +        NS_Free(ret);
  1.1250 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1251 +    }
  1.1252 +
  1.1253 +    nsresult rv = NS_OK;
  1.1254 +    for (unsigned i = 0; i < nargs; ++i) {
  1.1255 +        JSAtom *atom = JS_LocalNameToAtom(names[i]);
  1.1256 +        if (!atom) {
  1.1257 +            ret[i] = 0;
  1.1258 +        } else {
  1.1259 +            JSString *str = JS_AtomKey(atom);
  1.1260 +            ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str));
  1.1261 +            if (!ret[i]) {
  1.1262 +                NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
  1.1263 +                rv = NS_ERROR_OUT_OF_MEMORY;
  1.1264 +                break;
  1.1265 +            }
  1.1266 +        }
  1.1267 +    }
  1.1268 +    JS_ReleaseFunctionLocalNameArray(cx, mark);
  1.1269 +    if (NS_FAILED(rv))
  1.1270 +        return rv;
  1.1271 +    *count = nargs;
  1.1272 +    *paramNames = ret;
  1.1273 +    return NS_OK;
  1.1274 +}
  1.1275 +
  1.1276 +NS_IMETHODIMP
  1.1277 +jsdScript::GetFunctionObject(jsdIValue **_rval)
  1.1278 +{
  1.1279 +    JS::RootedFunction fun(JSD_GetJSRuntime(mCx), JSD_GetJSFunction(mCx, mScript));
  1.1280 +    if (!fun)
  1.1281 +        return NS_ERROR_NOT_AVAILABLE;
  1.1282 +
  1.1283 +    AutoSafeJSContext jsContext;
  1.1284 +    JS::RootedObject obj(jsContext, JS_GetFunctionObject(fun));
  1.1285 +    if (!obj)
  1.1286 +        return NS_ERROR_FAILURE;
  1.1287 +
  1.1288 +    JSDContext *cx;
  1.1289 +    if (NS_FAILED(gJsds->GetJSDContext (&cx)))
  1.1290 +        return NS_ERROR_NOT_INITIALIZED;
  1.1291 +
  1.1292 +    JSDValue *jsdv = JSD_NewValue(cx, OBJECT_TO_JSVAL(obj));
  1.1293 +    if (!jsdv)
  1.1294 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1295 +
  1.1296 +    *_rval = jsdValue::FromPtr(cx, jsdv);
  1.1297 +    if (!*_rval) {
  1.1298 +        JSD_DropValue(cx, jsdv);
  1.1299 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1300 +    }
  1.1301 +
  1.1302 +    return NS_OK;
  1.1303 +}
  1.1304 +
  1.1305 +NS_IMETHODIMP
  1.1306 +jsdScript::GetFunctionSource(nsAString & aFunctionSource)
  1.1307 +{
  1.1308 +    ASSERT_VALID_EPHEMERAL;
  1.1309 +    AutoSafeJSContext cx_;
  1.1310 +    JSContext *cx = cx_; // Appease the type system with Maybe<>s below.
  1.1311 +    JS::RootedFunction fun(cx, JSD_GetJSFunction (mCx, mScript));
  1.1312 +
  1.1313 +    JSString *jsstr;
  1.1314 +    mozilla::Maybe<JSAutoCompartment> ac;
  1.1315 +    if (fun) {
  1.1316 +        ac.construct(cx, JS_GetFunctionObject(fun));
  1.1317 +        jsstr = JS_DecompileFunction (cx, fun, 4);
  1.1318 +    } else {
  1.1319 +        JS::RootedScript script(cx, JSD_GetJSScript (mCx, mScript));
  1.1320 +        ac.construct(cx, script);
  1.1321 +        jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
  1.1322 +    }
  1.1323 +    if (!jsstr)
  1.1324 +        return NS_ERROR_FAILURE;
  1.1325 +
  1.1326 +    size_t length;
  1.1327 +    const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length);
  1.1328 +    if (!chars)
  1.1329 +        return NS_ERROR_FAILURE;
  1.1330 +
  1.1331 +    aFunctionSource = nsDependentString(chars, length);
  1.1332 +    return NS_OK;
  1.1333 +}
  1.1334 +
  1.1335 +NS_IMETHODIMP
  1.1336 +jsdScript::GetBaseLineNumber(uint32_t *_rval)
  1.1337 +{
  1.1338 +    *_rval = mBaseLineNumber;
  1.1339 +    return NS_OK;
  1.1340 +}
  1.1341 +
  1.1342 +NS_IMETHODIMP
  1.1343 +jsdScript::GetLineExtent(uint32_t *_rval)
  1.1344 +{
  1.1345 +    *_rval = mLineExtent;
  1.1346 +    return NS_OK;
  1.1347 +}
  1.1348 +
  1.1349 +NS_IMETHODIMP
  1.1350 +jsdScript::GetCallCount(uint32_t *_rval)
  1.1351 +{
  1.1352 +    ASSERT_VALID_EPHEMERAL;
  1.1353 +    *_rval = JSD_GetScriptCallCount (mCx, mScript);
  1.1354 +    return NS_OK;
  1.1355 +}
  1.1356 +
  1.1357 +NS_IMETHODIMP
  1.1358 +jsdScript::GetMaxRecurseDepth(uint32_t *_rval)
  1.1359 +{
  1.1360 +    ASSERT_VALID_EPHEMERAL;
  1.1361 +    *_rval = JSD_GetScriptMaxRecurseDepth (mCx, mScript);
  1.1362 +    return NS_OK;
  1.1363 +}
  1.1364 +
  1.1365 +NS_IMETHODIMP
  1.1366 +jsdScript::GetMinExecutionTime(double *_rval)
  1.1367 +{
  1.1368 +    ASSERT_VALID_EPHEMERAL;
  1.1369 +    *_rval = JSD_GetScriptMinExecutionTime (mCx, mScript);
  1.1370 +    return NS_OK;
  1.1371 +}
  1.1372 +
  1.1373 +NS_IMETHODIMP
  1.1374 +jsdScript::GetMaxExecutionTime(double *_rval)
  1.1375 +{
  1.1376 +    ASSERT_VALID_EPHEMERAL;
  1.1377 +    *_rval = JSD_GetScriptMaxExecutionTime (mCx, mScript);
  1.1378 +    return NS_OK;
  1.1379 +}
  1.1380 +
  1.1381 +NS_IMETHODIMP
  1.1382 +jsdScript::GetTotalExecutionTime(double *_rval)
  1.1383 +{
  1.1384 +    ASSERT_VALID_EPHEMERAL;
  1.1385 +    *_rval = JSD_GetScriptTotalExecutionTime (mCx, mScript);
  1.1386 +    return NS_OK;
  1.1387 +}
  1.1388 +
  1.1389 +NS_IMETHODIMP
  1.1390 +jsdScript::GetMinOwnExecutionTime(double *_rval)
  1.1391 +{
  1.1392 +    ASSERT_VALID_EPHEMERAL;
  1.1393 +    *_rval = JSD_GetScriptMinOwnExecutionTime (mCx, mScript);
  1.1394 +    return NS_OK;
  1.1395 +}
  1.1396 +
  1.1397 +NS_IMETHODIMP
  1.1398 +jsdScript::GetMaxOwnExecutionTime(double *_rval)
  1.1399 +{
  1.1400 +    ASSERT_VALID_EPHEMERAL;
  1.1401 +    *_rval = JSD_GetScriptMaxOwnExecutionTime (mCx, mScript);
  1.1402 +    return NS_OK;
  1.1403 +}
  1.1404 +
  1.1405 +NS_IMETHODIMP
  1.1406 +jsdScript::GetTotalOwnExecutionTime(double *_rval)
  1.1407 +{
  1.1408 +    ASSERT_VALID_EPHEMERAL;
  1.1409 +    *_rval = JSD_GetScriptTotalOwnExecutionTime (mCx, mScript);
  1.1410 +    return NS_OK;
  1.1411 +}
  1.1412 +
  1.1413 +NS_IMETHODIMP
  1.1414 +jsdScript::ClearProfileData()
  1.1415 +{
  1.1416 +    ASSERT_VALID_EPHEMERAL;
  1.1417 +    JSD_ClearScriptProfileData(mCx, mScript);
  1.1418 +    return NS_OK;
  1.1419 +}
  1.1420 +
  1.1421 +NS_IMETHODIMP
  1.1422 +jsdScript::PcToLine(uint32_t aPC, uint32_t aPcmap, uint32_t *_rval)
  1.1423 +{
  1.1424 +    ASSERT_VALID_EPHEMERAL;
  1.1425 +    if (aPcmap == PCMAP_SOURCETEXT) {
  1.1426 +        *_rval = JSD_GetClosestLine (mCx, mScript, mFirstPC + aPC);
  1.1427 +    } else if (aPcmap == PCMAP_PRETTYPRINT) {
  1.1428 +        *_rval = PPPcToLine(aPC);
  1.1429 +    } else {
  1.1430 +        return NS_ERROR_INVALID_ARG;
  1.1431 +    }
  1.1432 +    
  1.1433 +    return NS_OK;
  1.1434 +}
  1.1435 +
  1.1436 +NS_IMETHODIMP
  1.1437 +jsdScript::LineToPc(uint32_t aLine, uint32_t aPcmap, uint32_t *_rval)
  1.1438 +{
  1.1439 +    ASSERT_VALID_EPHEMERAL;
  1.1440 +    if (aPcmap == PCMAP_SOURCETEXT) {
  1.1441 +        uintptr_t pc = JSD_GetClosestPC (mCx, mScript, aLine);
  1.1442 +        *_rval = pc - mFirstPC;
  1.1443 +    } else if (aPcmap == PCMAP_PRETTYPRINT) {
  1.1444 +        *_rval = PPLineToPc(aLine);
  1.1445 +    } else {
  1.1446 +        return NS_ERROR_INVALID_ARG;
  1.1447 +    }
  1.1448 +
  1.1449 +    return NS_OK;
  1.1450 +}
  1.1451 +
  1.1452 +NS_IMETHODIMP
  1.1453 +jsdScript::EnableSingleStepInterrupts(bool enable)
  1.1454 +{
  1.1455 +    ASSERT_VALID_EPHEMERAL;
  1.1456 +
  1.1457 +    /* Must have set interrupt hook before enabling */
  1.1458 +    if (enable && !jsdService::GetService()->CheckInterruptHook())
  1.1459 +        return NS_ERROR_NOT_INITIALIZED;
  1.1460 +
  1.1461 +    return (JSD_EnableSingleStepInterrupts(mCx, mScript, enable) ? NS_OK : NS_ERROR_FAILURE);
  1.1462 +}
  1.1463 +
  1.1464 +NS_IMETHODIMP
  1.1465 +jsdScript::GetExecutableLines(uint32_t aPcmap, uint32_t aStartLine, uint32_t aMaxLines,
  1.1466 +                              uint32_t* aCount, uint32_t** aExecutableLines)
  1.1467 +{
  1.1468 +    ASSERT_VALID_EPHEMERAL;
  1.1469 +    if (aPcmap == PCMAP_SOURCETEXT) {
  1.1470 +        uintptr_t start = JSD_GetClosestPC(mCx, mScript, 0);
  1.1471 +        unsigned lastLine = JSD_GetScriptBaseLineNumber(mCx, mScript)
  1.1472 +                       + JSD_GetScriptLineExtent(mCx, mScript) - 1;
  1.1473 +        uintptr_t end = JSD_GetClosestPC(mCx, mScript, lastLine + 1);
  1.1474 +
  1.1475 +        *aExecutableLines = static_cast<uint32_t*>(NS_Alloc((end - start + 1) * sizeof(uint32_t)));
  1.1476 +        if (!JSD_GetLinePCs(mCx, mScript, aStartLine, aMaxLines, aCount, aExecutableLines,
  1.1477 +                            nullptr))
  1.1478 +            return NS_ERROR_OUT_OF_MEMORY;
  1.1479 +        
  1.1480 +        return NS_OK;
  1.1481 +    }
  1.1482 +
  1.1483 +    if (aPcmap == PCMAP_PRETTYPRINT) {
  1.1484 +        if (!mPPLineMap) {
  1.1485 +            if (!CreatePPLineMap())
  1.1486 +                return NS_ERROR_OUT_OF_MEMORY;
  1.1487 +        }
  1.1488 +
  1.1489 +        nsTArray<uint32_t> lines;
  1.1490 +        uint32_t i;
  1.1491 +
  1.1492 +        for (i = 0; i < mPCMapSize; ++i) {
  1.1493 +            if (mPPLineMap[i].line >= aStartLine)
  1.1494 +                break;
  1.1495 +        }
  1.1496 +
  1.1497 +        for (; i < mPCMapSize && lines.Length() < aMaxLines; ++i) {
  1.1498 +            lines.AppendElement(mPPLineMap[i].line);
  1.1499 +        }
  1.1500 +
  1.1501 +        if (aCount)
  1.1502 +            *aCount = lines.Length();
  1.1503 +
  1.1504 +        *aExecutableLines = static_cast<uint32_t*>(NS_Alloc(lines.Length() * sizeof(uint32_t)));
  1.1505 +        if (!*aExecutableLines)
  1.1506 +            return NS_ERROR_OUT_OF_MEMORY;
  1.1507 +
  1.1508 +        for (i = 0; i < lines.Length(); ++i)
  1.1509 +            (*aExecutableLines)[i] = lines[i];
  1.1510 +
  1.1511 +        return NS_OK;
  1.1512 +    }
  1.1513 +
  1.1514 +    return NS_ERROR_INVALID_ARG;
  1.1515 +}
  1.1516 +
  1.1517 +NS_IMETHODIMP
  1.1518 +jsdScript::IsLineExecutable(uint32_t aLine, uint32_t aPcmap, bool *_rval)
  1.1519 +{
  1.1520 +    ASSERT_VALID_EPHEMERAL;
  1.1521 +    if (aPcmap == PCMAP_SOURCETEXT) {    
  1.1522 +        uintptr_t pc = JSD_GetClosestPC (mCx, mScript, aLine);
  1.1523 +        *_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc));
  1.1524 +    } else if (aPcmap == PCMAP_PRETTYPRINT) {
  1.1525 +        if (!mPPLineMap && !CreatePPLineMap())
  1.1526 +            return NS_ERROR_OUT_OF_MEMORY;
  1.1527 +        *_rval = false;
  1.1528 +        for (uint32_t i = 0; i < mPCMapSize; ++i) {
  1.1529 +            if (mPPLineMap[i].line >= aLine) {
  1.1530 +                *_rval = (mPPLineMap[i].line == aLine);
  1.1531 +                break;
  1.1532 +            }
  1.1533 +        }
  1.1534 +    } else {
  1.1535 +        return NS_ERROR_INVALID_ARG;
  1.1536 +    }
  1.1537 +    
  1.1538 +    return NS_OK;
  1.1539 +}
  1.1540 +
  1.1541 +NS_IMETHODIMP
  1.1542 +jsdScript::SetBreakpoint(uint32_t aPC)
  1.1543 +{
  1.1544 +    ASSERT_VALID_EPHEMERAL;
  1.1545 +    uintptr_t pc = mFirstPC + aPC;
  1.1546 +    JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, nullptr);
  1.1547 +    return NS_OK;
  1.1548 +}
  1.1549 +
  1.1550 +NS_IMETHODIMP
  1.1551 +jsdScript::ClearBreakpoint(uint32_t aPC)
  1.1552 +{
  1.1553 +    ASSERT_VALID_EPHEMERAL;    
  1.1554 +    uintptr_t pc = mFirstPC + aPC;
  1.1555 +    JSD_ClearExecutionHook (mCx, mScript, pc);
  1.1556 +    return NS_OK;
  1.1557 +}
  1.1558 +
  1.1559 +NS_IMETHODIMP
  1.1560 +jsdScript::ClearAllBreakpoints()
  1.1561 +{
  1.1562 +    ASSERT_VALID_EPHEMERAL;
  1.1563 +    JSD_LockScriptSubsystem(mCx);
  1.1564 +    JSD_ClearAllExecutionHooksForScript (mCx, mScript);
  1.1565 +    JSD_UnlockScriptSubsystem(mCx);
  1.1566 +    return NS_OK;
  1.1567 +}
  1.1568 +
  1.1569 +/* Contexts */
  1.1570 +NS_IMPL_ISUPPORTS(jsdContext, jsdIContext, jsdIEphemeral)
  1.1571 +
  1.1572 +jsdIContext *
  1.1573 +jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx)
  1.1574 +{
  1.1575 +    if (!aJSDCx || !aJSCx)
  1.1576 +        return nullptr;
  1.1577 +
  1.1578 +    nsCOMPtr<jsdIContext> jsdicx;
  1.1579 +    nsCOMPtr<jsdIEphemeral> eph = 
  1.1580 +        jsds_FindEphemeral (&gLiveContexts, static_cast<void *>(aJSCx));
  1.1581 +    if (eph)
  1.1582 +    {
  1.1583 +        jsdicx = do_QueryInterface(eph);
  1.1584 +    }
  1.1585 +    else
  1.1586 +    {
  1.1587 +        nsCOMPtr<nsISupports> iscx;
  1.1588 +        if (JS::ContextOptionsRef(aJSCx).privateIsNSISupports())
  1.1589 +            iscx = static_cast<nsISupports *>(JS_GetContextPrivate(aJSCx));
  1.1590 +        jsdicx = new jsdContext (aJSDCx, aJSCx, iscx);
  1.1591 +    }
  1.1592 +
  1.1593 +    jsdIContext *ctx = nullptr;
  1.1594 +    jsdicx.swap(ctx);
  1.1595 +    return ctx;
  1.1596 +}
  1.1597 +
  1.1598 +jsdContext::jsdContext (JSDContext *aJSDCx, JSContext *aJSCx,
  1.1599 +                        nsISupports *aISCx) : mValid(true),
  1.1600 +                                              mScriptDisabledForWindowWithID(0),
  1.1601 +                                              mTag(0),
  1.1602 +                                              mJSDCx(aJSDCx),
  1.1603 +                                              mJSCx(aJSCx), mISCx(aISCx)
  1.1604 +{
  1.1605 +    DEBUG_CREATE ("jsdContext", gContextCount);
  1.1606 +    mLiveListEntry.value = this;
  1.1607 +    mLiveListEntry.key   = static_cast<void *>(aJSCx);
  1.1608 +    jsds_InsertEphemeral (&gLiveContexts, &mLiveListEntry);
  1.1609 +}
  1.1610 +
  1.1611 +jsdContext::~jsdContext() 
  1.1612 +{
  1.1613 +    DEBUG_DESTROY ("jsdContext", gContextCount);
  1.1614 +    if (mValid)
  1.1615 +    {
  1.1616 +        /* call Invalidate() to take ourselves out of the live list */
  1.1617 +        Invalidate();
  1.1618 +    }
  1.1619 +}
  1.1620 +
  1.1621 +NS_IMETHODIMP
  1.1622 +jsdContext::GetIsValid(bool *_rval)
  1.1623 +{
  1.1624 +    *_rval = mValid;
  1.1625 +    return NS_OK;
  1.1626 +}
  1.1627 +
  1.1628 +NS_IMETHODIMP
  1.1629 +jsdContext::Invalidate()
  1.1630 +{
  1.1631 +    ASSERT_VALID_EPHEMERAL;
  1.1632 +    mValid = false;
  1.1633 +    jsds_RemoveEphemeral (&gLiveContexts, &mLiveListEntry);
  1.1634 +    return NS_OK;
  1.1635 +}
  1.1636 +
  1.1637 +void
  1.1638 +jsdContext::InvalidateAll()
  1.1639 +{
  1.1640 +    if (gLiveContexts)
  1.1641 +        jsds_InvalidateAllEphemerals (&gLiveContexts);
  1.1642 +}
  1.1643 +
  1.1644 +NS_IMETHODIMP
  1.1645 +jsdContext::GetJSContext(JSContext **_rval)
  1.1646 +{
  1.1647 +    ASSERT_VALID_EPHEMERAL;
  1.1648 +    *_rval = mJSCx;
  1.1649 +    return NS_OK;
  1.1650 +}
  1.1651 +
  1.1652 +/* Simulate the old options API in terms of the new one for backwards
  1.1653 + * compatibility */
  1.1654 +
  1.1655 +#define JSOPTION_EXTRA_WARNINGS                 JS_BIT(0)
  1.1656 +#define JSOPTION_WERROR                         JS_BIT(1)
  1.1657 +#define JSOPTION_VAROBJFIX                      JS_BIT(2)
  1.1658 +#define JSOPTION_PRIVATE_IS_NSISUPPORTS         JS_BIT(3)
  1.1659 +#define JSOPTION_DONT_REPORT_UNCAUGHT           JS_BIT(8)
  1.1660 +#define JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT  JS_BIT(11)
  1.1661 +#define JSOPTION_NO_SCRIPT_RVAL                 JS_BIT(12)
  1.1662 +#define JSOPTION_STRICT_MODE                    JS_BIT(17)
  1.1663 +#define JSOPTION_MASK                           JS_BITMASK(20)
  1.1664 +
  1.1665 +NS_IMETHODIMP
  1.1666 +jsdContext::GetOptions(uint32_t *_rval)
  1.1667 +{
  1.1668 +    ASSERT_VALID_EPHEMERAL;
  1.1669 +    *_rval = (JS::ContextOptionsRef(mJSCx).extraWarnings() ? JSOPTION_EXTRA_WARNINGS : 0)
  1.1670 +           | (JS::ContextOptionsRef(mJSCx).werror() ? JSOPTION_WERROR : 0)
  1.1671 +           | (JS::ContextOptionsRef(mJSCx).varObjFix() ? JSOPTION_VAROBJFIX : 0)
  1.1672 +           | (JS::ContextOptionsRef(mJSCx).privateIsNSISupports() ? JSOPTION_PRIVATE_IS_NSISUPPORTS : 0)
  1.1673 +           | (JS::ContextOptionsRef(mJSCx).dontReportUncaught() ? JSOPTION_DONT_REPORT_UNCAUGHT : 0)
  1.1674 +           | (JS::ContextOptionsRef(mJSCx).noDefaultCompartmentObject() ? JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT : 0)
  1.1675 +           | (JS::ContextOptionsRef(mJSCx).noScriptRval() ? JSOPTION_NO_SCRIPT_RVAL : 0)
  1.1676 +           | (JS::ContextOptionsRef(mJSCx).strictMode() ? JSOPTION_STRICT_MODE : 0);
  1.1677 +    return NS_OK;
  1.1678 +}
  1.1679 +
  1.1680 +NS_IMETHODIMP
  1.1681 +jsdContext::SetOptions(uint32_t options)
  1.1682 +{
  1.1683 +    ASSERT_VALID_EPHEMERAL;
  1.1684 +
  1.1685 +    /* don't let users change this option, they'd just be shooting themselves
  1.1686 +     * in the foot. */
  1.1687 +    if (JS::ContextOptionsRef(mJSCx).privateIsNSISupports() !=
  1.1688 +        (options & JSOPTION_PRIVATE_IS_NSISUPPORTS))
  1.1689 +        return NS_ERROR_ILLEGAL_VALUE;
  1.1690 +
  1.1691 +    JS::ContextOptionsRef(mJSCx).setExtraWarnings(options & JSOPTION_EXTRA_WARNINGS)
  1.1692 +                                .setWerror(options & JSOPTION_WERROR)
  1.1693 +                                .setVarObjFix(options & JSOPTION_VAROBJFIX)
  1.1694 +                                .setDontReportUncaught(options & JSOPTION_DONT_REPORT_UNCAUGHT)
  1.1695 +                                .setNoDefaultCompartmentObject(options & JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT)
  1.1696 +                                .setNoScriptRval(options & JSOPTION_NO_SCRIPT_RVAL)
  1.1697 +                                .setStrictMode(options & JSOPTION_STRICT_MODE);
  1.1698 +    return NS_OK;
  1.1699 +}
  1.1700 +
  1.1701 +NS_IMETHODIMP
  1.1702 +jsdContext::GetPrivateData(nsISupports **_rval)
  1.1703 +{
  1.1704 +    ASSERT_VALID_EPHEMERAL;
  1.1705 +    if (JS::ContextOptionsRef(mJSCx).privateIsNSISupports()) 
  1.1706 +    {
  1.1707 +        *_rval = static_cast<nsISupports*>(JS_GetContextPrivate(mJSCx));
  1.1708 +        NS_IF_ADDREF(*_rval);
  1.1709 +    }
  1.1710 +    else
  1.1711 +    {
  1.1712 +        *_rval = nullptr;
  1.1713 +    }
  1.1714 +
  1.1715 +    return NS_OK;
  1.1716 +}
  1.1717 +
  1.1718 +NS_IMETHODIMP
  1.1719 +jsdContext::GetWrappedContext(nsISupports **_rval)
  1.1720 +{
  1.1721 +    ASSERT_VALID_EPHEMERAL;
  1.1722 +    NS_IF_ADDREF(*_rval = mISCx);
  1.1723 +    return NS_OK;
  1.1724 +}
  1.1725 +
  1.1726 +NS_IMETHODIMP
  1.1727 +jsdContext::GetTag(uint32_t *_rval)
  1.1728 +{
  1.1729 +    ASSERT_VALID_EPHEMERAL;
  1.1730 +    if (!mTag)
  1.1731 +        mTag = ++jsdContext::LastTag;
  1.1732 +    
  1.1733 +    *_rval = mTag;
  1.1734 +    return NS_OK;
  1.1735 +}
  1.1736 +
  1.1737 +NS_IMETHODIMP
  1.1738 +jsdContext::GetGlobalObject (jsdIValue **_rval)
  1.1739 +{
  1.1740 +    ASSERT_VALID_EPHEMERAL;
  1.1741 +    JSObject *glob = GetDefaultScopeFromJSContext(mJSCx);
  1.1742 +    JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
  1.1743 +    if (!jsdv)
  1.1744 +        return NS_ERROR_FAILURE;
  1.1745 +    *_rval = jsdValue::FromPtr (mJSDCx, jsdv);
  1.1746 +    if (!*_rval)
  1.1747 +        return NS_ERROR_FAILURE;
  1.1748 +    return NS_OK;
  1.1749 +}
  1.1750 +
  1.1751 +NS_IMETHODIMP
  1.1752 +jsdContext::GetScriptsEnabled (bool *_rval)
  1.1753 +{
  1.1754 +    ASSERT_VALID_EPHEMERAL;
  1.1755 +    *_rval = IsScriptEnabled();
  1.1756 +    return NS_OK;
  1.1757 +}
  1.1758 +
  1.1759 +NS_IMETHODIMP
  1.1760 +jsdContext::SetScriptsEnabled (bool _rval)
  1.1761 +{
  1.1762 +    ASSERT_VALID_EPHEMERAL;
  1.1763 +    if (_rval == IsScriptEnabled())
  1.1764 +        return NS_OK;
  1.1765 +
  1.1766 +    nsCOMPtr<nsIScriptContext> scx = do_QueryInterface(mISCx);
  1.1767 +    NS_ENSURE_TRUE(scx && scx->GetWindowProxy(), NS_ERROR_NO_INTERFACE);
  1.1768 +    nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(scx->GetGlobalObject());
  1.1769 +    NS_ENSURE_TRUE(piWin, NS_ERROR_NO_INTERFACE);
  1.1770 +    uint64_t currentWindowID = piWin->WindowID();
  1.1771 +
  1.1772 +    if (_rval) {
  1.1773 +        if (mScriptDisabledForWindowWithID != currentWindowID) {
  1.1774 +            NS_WARNING("Please stop abusing JSD and fix your code!");
  1.1775 +            return NS_ERROR_UNEXPECTED;
  1.1776 +        }
  1.1777 +        xpc::Scriptability::Get(scx->GetWindowProxy()).Unblock();
  1.1778 +        piWin->ResumeTimeouts();
  1.1779 +        mScriptDisabledForWindowWithID = 0;
  1.1780 +    }
  1.1781 +    else {
  1.1782 +        piWin->SuspendTimeouts();
  1.1783 +        xpc::Scriptability::Get(scx->GetWindowProxy()).Block();
  1.1784 +        mScriptDisabledForWindowWithID = currentWindowID;
  1.1785 +    }
  1.1786 +
  1.1787 +    return NS_OK;
  1.1788 +}
  1.1789 +
  1.1790 +/* Stack Frames */
  1.1791 +NS_IMPL_ISUPPORTS(jsdStackFrame, jsdIStackFrame, jsdIEphemeral)
  1.1792 +
  1.1793 +jsdStackFrame::jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState,
  1.1794 +                              JSDStackFrameInfo *aStackFrameInfo) :
  1.1795 +    mCx(aCx), mThreadState(aThreadState), mStackFrameInfo(aStackFrameInfo)
  1.1796 +{
  1.1797 +    DEBUG_CREATE ("jsdStackFrame", gFrameCount);
  1.1798 +    mValid = (aCx && aThreadState && aStackFrameInfo);
  1.1799 +    if (mValid) {
  1.1800 +        mLiveListEntry.key = aStackFrameInfo;
  1.1801 +        mLiveListEntry.value = this;
  1.1802 +        jsds_InsertEphemeral (&gLiveStackFrames, &mLiveListEntry);
  1.1803 +    }
  1.1804 +}
  1.1805 +
  1.1806 +jsdStackFrame::~jsdStackFrame() 
  1.1807 +{
  1.1808 +    DEBUG_DESTROY ("jsdStackFrame", gFrameCount);
  1.1809 +    if (mValid)
  1.1810 +    {
  1.1811 +        /* call Invalidate() to take ourselves out of the live list */
  1.1812 +        Invalidate();
  1.1813 +    }
  1.1814 +}
  1.1815 +
  1.1816 +jsdIStackFrame *
  1.1817 +jsdStackFrame::FromPtr (JSDContext *aCx, JSDThreadState *aThreadState,
  1.1818 +                        JSDStackFrameInfo *aStackFrameInfo)
  1.1819 +{
  1.1820 +    if (!aStackFrameInfo)
  1.1821 +        return nullptr;
  1.1822 +
  1.1823 +    jsdIStackFrame *rv;
  1.1824 +    nsCOMPtr<jsdIStackFrame> frame;
  1.1825 +
  1.1826 +    nsCOMPtr<jsdIEphemeral> eph =
  1.1827 +        jsds_FindEphemeral (&gLiveStackFrames,
  1.1828 +                            reinterpret_cast<void *>(aStackFrameInfo));
  1.1829 +
  1.1830 +    if (eph)
  1.1831 +    {
  1.1832 +        frame = do_QueryInterface(eph);
  1.1833 +        rv = frame;
  1.1834 +    }
  1.1835 +    else
  1.1836 +    {
  1.1837 +        rv = new jsdStackFrame (aCx, aThreadState, aStackFrameInfo);
  1.1838 +    }
  1.1839 +
  1.1840 +    NS_IF_ADDREF(rv);
  1.1841 +    return rv;
  1.1842 +}
  1.1843 +
  1.1844 +NS_IMETHODIMP
  1.1845 +jsdStackFrame::Invalidate()
  1.1846 +{
  1.1847 +    ASSERT_VALID_EPHEMERAL;
  1.1848 +    mValid = false;
  1.1849 +    jsds_RemoveEphemeral (&gLiveStackFrames, &mLiveListEntry);
  1.1850 +    return NS_OK;
  1.1851 +}
  1.1852 +
  1.1853 +void
  1.1854 +jsdStackFrame::InvalidateAll()
  1.1855 +{
  1.1856 +    if (gLiveStackFrames)
  1.1857 +        jsds_InvalidateAllEphemerals (&gLiveStackFrames);
  1.1858 +}
  1.1859 +
  1.1860 +NS_IMETHODIMP
  1.1861 +jsdStackFrame::GetJSDContext(JSDContext **_rval)
  1.1862 +{
  1.1863 +    ASSERT_VALID_EPHEMERAL;
  1.1864 +    *_rval = mCx;
  1.1865 +    return NS_OK;
  1.1866 +}
  1.1867 +
  1.1868 +NS_IMETHODIMP
  1.1869 +jsdStackFrame::GetJSDThreadState(JSDThreadState **_rval)
  1.1870 +{
  1.1871 +    ASSERT_VALID_EPHEMERAL;
  1.1872 +    *_rval = mThreadState;
  1.1873 +    return NS_OK;
  1.1874 +}
  1.1875 +
  1.1876 +NS_IMETHODIMP
  1.1877 +jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo **_rval)
  1.1878 +{
  1.1879 +    ASSERT_VALID_EPHEMERAL;
  1.1880 +    *_rval = mStackFrameInfo;
  1.1881 +    return NS_OK;
  1.1882 +}
  1.1883 +
  1.1884 +NS_IMETHODIMP
  1.1885 +jsdStackFrame::GetIsValid(bool *_rval)
  1.1886 +{
  1.1887 +    *_rval = mValid;
  1.1888 +    return NS_OK;
  1.1889 +}
  1.1890 +
  1.1891 +NS_IMETHODIMP
  1.1892 +jsdStackFrame::GetCallingFrame(jsdIStackFrame **_rval)
  1.1893 +{
  1.1894 +    ASSERT_VALID_EPHEMERAL;
  1.1895 +    JSDStackFrameInfo *sfi = JSD_GetCallingStackFrame (mCx, mThreadState,
  1.1896 +                                                       mStackFrameInfo);
  1.1897 +    *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
  1.1898 +    return NS_OK;
  1.1899 +}
  1.1900 +
  1.1901 +NS_IMETHODIMP
  1.1902 +jsdStackFrame::GetExecutionContext(jsdIContext **_rval)
  1.1903 +{
  1.1904 +    ASSERT_VALID_EPHEMERAL;
  1.1905 +    JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
  1.1906 +    *_rval = jsdContext::FromPtr (mCx, cx);
  1.1907 +    return NS_OK;
  1.1908 +}
  1.1909 +
  1.1910 +NS_IMETHODIMP
  1.1911 +jsdStackFrame::GetFunctionName(nsACString &_rval)
  1.1912 +{
  1.1913 +    ASSERT_VALID_EPHEMERAL;
  1.1914 +    JSString *str = JSD_GetIdForStackFrame(mCx, mThreadState, mStackFrameInfo);
  1.1915 +    if (str)
  1.1916 +        return AssignToJSString(mCx, &_rval, str);
  1.1917 +    
  1.1918 +    _rval.Assign("anonymous");
  1.1919 +    return NS_OK;
  1.1920 +}
  1.1921 +
  1.1922 +NS_IMETHODIMP
  1.1923 +jsdStackFrame::GetIsDebugger(bool *_rval)
  1.1924 +{
  1.1925 +    ASSERT_VALID_EPHEMERAL;
  1.1926 +    *_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo);
  1.1927 +    return NS_OK;
  1.1928 +}
  1.1929 +
  1.1930 +NS_IMETHODIMP
  1.1931 +jsdStackFrame::GetIsConstructing(bool *_rval)
  1.1932 +{
  1.1933 +    ASSERT_VALID_EPHEMERAL;
  1.1934 +    *_rval = JSD_IsStackFrameConstructing (mCx, mThreadState, mStackFrameInfo);
  1.1935 +    return NS_OK;
  1.1936 +}
  1.1937 +
  1.1938 +NS_IMETHODIMP
  1.1939 +jsdStackFrame::GetScript(jsdIScript **_rval)
  1.1940 +{
  1.1941 +    ASSERT_VALID_EPHEMERAL;
  1.1942 +    JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
  1.1943 +                                                    mStackFrameInfo);
  1.1944 +    *_rval = jsdScript::FromPtr (mCx, script);
  1.1945 +    return NS_OK;
  1.1946 +}
  1.1947 +
  1.1948 +NS_IMETHODIMP
  1.1949 +jsdStackFrame::GetPc(uint32_t *_rval)
  1.1950 +{
  1.1951 +    ASSERT_VALID_EPHEMERAL;
  1.1952 +    JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
  1.1953 +                                                    mStackFrameInfo);
  1.1954 +    if (!script)
  1.1955 +        return NS_ERROR_FAILURE;
  1.1956 +    uintptr_t pcbase = JSD_GetClosestPC(mCx, script, 0);
  1.1957 +    
  1.1958 +    uintptr_t pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
  1.1959 +    if (pc)
  1.1960 +        *_rval = pc - pcbase;
  1.1961 +    else
  1.1962 +        *_rval = pcbase;
  1.1963 +    return NS_OK;
  1.1964 +}
  1.1965 +
  1.1966 +NS_IMETHODIMP
  1.1967 +jsdStackFrame::GetLine(uint32_t *_rval)
  1.1968 +{
  1.1969 +    ASSERT_VALID_EPHEMERAL;
  1.1970 +    JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
  1.1971 +                                                    mStackFrameInfo);
  1.1972 +    if (script) {
  1.1973 +        uintptr_t pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
  1.1974 +        *_rval = JSD_GetClosestLine (mCx, script, pc);
  1.1975 +    } else {
  1.1976 +        return NS_ERROR_FAILURE;
  1.1977 +    }
  1.1978 +    return NS_OK;
  1.1979 +}
  1.1980 +
  1.1981 +NS_IMETHODIMP
  1.1982 +jsdStackFrame::GetCallee(jsdIValue **_rval)
  1.1983 +{
  1.1984 +    ASSERT_VALID_EPHEMERAL;
  1.1985 +    JSDValue *jsdv = JSD_GetCallObjectForStackFrame (mCx, mThreadState,
  1.1986 +                                                     mStackFrameInfo);
  1.1987 +    
  1.1988 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
  1.1989 +    return NS_OK;
  1.1990 +}
  1.1991 +
  1.1992 +NS_IMETHODIMP
  1.1993 +jsdStackFrame::GetScope(jsdIValue **_rval)
  1.1994 +{
  1.1995 +    ASSERT_VALID_EPHEMERAL;
  1.1996 +    JSDValue *jsdv = JSD_GetScopeChainForStackFrame (mCx, mThreadState,
  1.1997 +                                                     mStackFrameInfo);
  1.1998 +    
  1.1999 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
  1.2000 +    return NS_OK;
  1.2001 +}
  1.2002 +
  1.2003 +NS_IMETHODIMP
  1.2004 +jsdStackFrame::GetThisValue(jsdIValue **_rval)
  1.2005 +{
  1.2006 +    ASSERT_VALID_EPHEMERAL;
  1.2007 +    JSDValue *jsdv = JSD_GetThisForStackFrame (mCx, mThreadState,
  1.2008 +                                               mStackFrameInfo);
  1.2009 +    
  1.2010 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
  1.2011 +    return NS_OK;
  1.2012 +}
  1.2013 +
  1.2014 +
  1.2015 +NS_IMETHODIMP
  1.2016 +jsdStackFrame::Eval (const nsAString &bytes, const nsACString &fileName,
  1.2017 +                     uint32_t line, jsdIValue **result, bool *_rval)
  1.2018 +{
  1.2019 +    ASSERT_VALID_EPHEMERAL;
  1.2020 +
  1.2021 +    if (bytes.IsEmpty())
  1.2022 +        return NS_ERROR_INVALID_ARG;
  1.2023 +
  1.2024 +    // get pointer to buffer contained in |bytes|
  1.2025 +    nsAString::const_iterator h;
  1.2026 +    bytes.BeginReading(h);
  1.2027 +    const jschar *char_bytes = reinterpret_cast<const jschar *>(h.get());
  1.2028 +
  1.2029 +    JSExceptionState *estate = 0;
  1.2030 +
  1.2031 +    AutoPushJSContext cx(JSD_GetJSContext (mCx, mThreadState));
  1.2032 +
  1.2033 +    JS::RootedValue jv(cx);
  1.2034 +
  1.2035 +    estate = JS_SaveExceptionState (cx);
  1.2036 +    JS_ClearPendingException (cx);
  1.2037 +
  1.2038 +    *_rval = JSD_AttemptUCScriptInStackFrame (mCx, mThreadState,
  1.2039 +                                              mStackFrameInfo,
  1.2040 +                                              char_bytes, bytes.Length(),
  1.2041 +                                              PromiseFlatCString(fileName).get(),
  1.2042 +                                              line, &jv);
  1.2043 +    if (!*_rval) {
  1.2044 +        if (JS_IsExceptionPending(cx))
  1.2045 +            JS_GetPendingException (cx, &jv);
  1.2046 +        else
  1.2047 +            jv = JSVAL_NULL;
  1.2048 +    }
  1.2049 +
  1.2050 +    JS_RestoreExceptionState (cx, estate);
  1.2051 +
  1.2052 +    JSDValue *jsdv = JSD_NewValue (mCx, jv);
  1.2053 +    if (!jsdv)
  1.2054 +        return NS_ERROR_FAILURE;
  1.2055 +    *result = jsdValue::FromPtr (mCx, jsdv);
  1.2056 +    if (!*result)
  1.2057 +        return NS_ERROR_FAILURE;
  1.2058 +    
  1.2059 +    return NS_OK;
  1.2060 +}        
  1.2061 +
  1.2062 +/* Values */
  1.2063 +NS_IMPL_ISUPPORTS(jsdValue, jsdIValue, jsdIEphemeral)
  1.2064 +jsdIValue *
  1.2065 +jsdValue::FromPtr (JSDContext *aCx, JSDValue *aValue)
  1.2066 +{
  1.2067 +    /* value will be dropped by te jsdValue destructor. */
  1.2068 +
  1.2069 +    if (!aValue)
  1.2070 +        return nullptr;
  1.2071 +    
  1.2072 +    jsdIValue *rv = new jsdValue (aCx, aValue);
  1.2073 +    NS_IF_ADDREF(rv);
  1.2074 +    return rv;
  1.2075 +}
  1.2076 +
  1.2077 +jsdValue::jsdValue (JSDContext *aCx, JSDValue *aValue) : mValid(true),
  1.2078 +                                                         mCx(aCx), 
  1.2079 +                                                         mValue(aValue)
  1.2080 +{
  1.2081 +    DEBUG_CREATE ("jsdValue", gValueCount);
  1.2082 +    mLiveListEntry.value = this;
  1.2083 +    jsds_InsertEphemeral (&gLiveValues, &mLiveListEntry);
  1.2084 +}
  1.2085 +
  1.2086 +jsdValue::~jsdValue() 
  1.2087 +{
  1.2088 +    DEBUG_DESTROY ("jsdValue", gValueCount);
  1.2089 +    if (mValid)
  1.2090 +        /* call Invalidate() to take ourselves out of the live list */
  1.2091 +        Invalidate();
  1.2092 +}   
  1.2093 +
  1.2094 +NS_IMETHODIMP
  1.2095 +jsdValue::GetIsValid(bool *_rval)
  1.2096 +{
  1.2097 +    *_rval = mValid;
  1.2098 +    return NS_OK;
  1.2099 +}
  1.2100 +
  1.2101 +NS_IMETHODIMP
  1.2102 +jsdValue::Invalidate()
  1.2103 +{
  1.2104 +    ASSERT_VALID_EPHEMERAL;
  1.2105 +    mValid = false;
  1.2106 +    jsds_RemoveEphemeral (&gLiveValues, &mLiveListEntry);
  1.2107 +    JSD_DropValue (mCx, mValue);
  1.2108 +    return NS_OK;
  1.2109 +}
  1.2110 +
  1.2111 +void
  1.2112 +jsdValue::InvalidateAll()
  1.2113 +{
  1.2114 +    if (gLiveValues)
  1.2115 +        jsds_InvalidateAllEphemerals (&gLiveValues);
  1.2116 +}
  1.2117 +
  1.2118 +NS_IMETHODIMP
  1.2119 +jsdValue::GetJSDContext(JSDContext **_rval)
  1.2120 +{
  1.2121 +    ASSERT_VALID_EPHEMERAL;
  1.2122 +    *_rval = mCx;
  1.2123 +    return NS_OK;
  1.2124 +}
  1.2125 +
  1.2126 +NS_IMETHODIMP
  1.2127 +jsdValue::GetJSDValue (JSDValue **_rval)
  1.2128 +{
  1.2129 +    ASSERT_VALID_EPHEMERAL;
  1.2130 +    *_rval = mValue;
  1.2131 +    return NS_OK;
  1.2132 +}
  1.2133 +
  1.2134 +NS_IMETHODIMP
  1.2135 +jsdValue::GetIsNative (bool *_rval)
  1.2136 +{
  1.2137 +    ASSERT_VALID_EPHEMERAL;
  1.2138 +    *_rval = JSD_IsValueNative (mCx, mValue);
  1.2139 +    return NS_OK;
  1.2140 +}
  1.2141 +
  1.2142 +NS_IMETHODIMP
  1.2143 +jsdValue::GetIsNumber (bool *_rval)
  1.2144 +{
  1.2145 +    ASSERT_VALID_EPHEMERAL;
  1.2146 +    *_rval = JSD_IsValueNumber (mCx, mValue);
  1.2147 +    return NS_OK;
  1.2148 +}
  1.2149 +
  1.2150 +NS_IMETHODIMP
  1.2151 +jsdValue::GetIsPrimitive (bool *_rval)
  1.2152 +{
  1.2153 +    ASSERT_VALID_EPHEMERAL;
  1.2154 +    *_rval = JSD_IsValuePrimitive (mCx, mValue);
  1.2155 +    return NS_OK;
  1.2156 +}
  1.2157 +
  1.2158 +NS_IMETHODIMP
  1.2159 +jsdValue::GetJsType (uint32_t *_rval)
  1.2160 +{
  1.2161 +    ASSERT_VALID_EPHEMERAL;
  1.2162 +    JS::RootedValue val(JSD_GetJSRuntime(mCx), JSD_GetValueWrappedJSVal (mCx, mValue));
  1.2163 +
  1.2164 +    if (JSVAL_IS_NULL(val))
  1.2165 +        *_rval = TYPE_NULL;
  1.2166 +    else if (JSVAL_IS_BOOLEAN(val))
  1.2167 +        *_rval = TYPE_BOOLEAN;
  1.2168 +    else if (JSVAL_IS_DOUBLE(val))
  1.2169 +        *_rval = TYPE_DOUBLE;
  1.2170 +    else if (JSVAL_IS_INT(val))
  1.2171 +        *_rval = TYPE_INT;
  1.2172 +    else if (JSVAL_IS_STRING(val))
  1.2173 +        *_rval = TYPE_STRING;
  1.2174 +    else if (JSVAL_IS_VOID(val))
  1.2175 +        *_rval = TYPE_VOID;
  1.2176 +    else if (JSD_IsValueFunction (mCx, mValue))
  1.2177 +        *_rval = TYPE_FUNCTION;
  1.2178 +    else if (!JSVAL_IS_PRIMITIVE(val))
  1.2179 +        *_rval = TYPE_OBJECT;
  1.2180 +    else
  1.2181 +        NS_ASSERTION (0, "Value has no discernible type.");
  1.2182 +
  1.2183 +    return NS_OK;
  1.2184 +}
  1.2185 +
  1.2186 +NS_IMETHODIMP
  1.2187 +jsdValue::GetJsPrototype (jsdIValue **_rval)
  1.2188 +{
  1.2189 +    ASSERT_VALID_EPHEMERAL;
  1.2190 +    JSDValue *jsdv = JSD_GetValuePrototype (mCx, mValue);
  1.2191 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
  1.2192 +    return NS_OK;
  1.2193 +}
  1.2194 +
  1.2195 +NS_IMETHODIMP
  1.2196 +jsdValue::GetJsParent (jsdIValue **_rval)
  1.2197 +{
  1.2198 +    ASSERT_VALID_EPHEMERAL;
  1.2199 +    JSDValue *jsdv = JSD_GetValueParent (mCx, mValue);
  1.2200 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
  1.2201 +    return NS_OK;
  1.2202 +}
  1.2203 +
  1.2204 +NS_IMETHODIMP
  1.2205 +jsdValue::GetJsClassName(nsACString &_rval)
  1.2206 +{
  1.2207 +    ASSERT_VALID_EPHEMERAL;
  1.2208 +    _rval.Assign(JSD_GetValueClassName(mCx, mValue));
  1.2209 +    
  1.2210 +    return NS_OK;
  1.2211 +}
  1.2212 +
  1.2213 +NS_IMETHODIMP
  1.2214 +jsdValue::GetJsConstructor (jsdIValue **_rval)
  1.2215 +{
  1.2216 +    ASSERT_VALID_EPHEMERAL;
  1.2217 +    JSDValue *jsdv = JSD_GetValueConstructor (mCx, mValue);
  1.2218 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
  1.2219 +    return NS_OK;
  1.2220 +}
  1.2221 +
  1.2222 +NS_IMETHODIMP
  1.2223 +jsdValue::GetJsFunctionName(nsACString &_rval)
  1.2224 +{
  1.2225 +    ASSERT_VALID_EPHEMERAL;
  1.2226 +    return AssignToJSString(mCx, &_rval, JSD_GetValueFunctionId(mCx, mValue));
  1.2227 +}
  1.2228 +
  1.2229 +NS_IMETHODIMP
  1.2230 +jsdValue::GetBooleanValue(bool *_rval)
  1.2231 +{
  1.2232 +    ASSERT_VALID_EPHEMERAL;
  1.2233 +    *_rval = JSD_GetValueBoolean (mCx, mValue);
  1.2234 +    return NS_OK;
  1.2235 +}
  1.2236 +
  1.2237 +NS_IMETHODIMP
  1.2238 +jsdValue::GetDoubleValue(double *_rval)
  1.2239 +{
  1.2240 +    ASSERT_VALID_EPHEMERAL;
  1.2241 +    *_rval = JSD_GetValueDouble (mCx, mValue);
  1.2242 +    return NS_OK;
  1.2243 +}
  1.2244 +
  1.2245 +NS_IMETHODIMP
  1.2246 +jsdValue::GetIntValue(int32_t *_rval)
  1.2247 +{
  1.2248 +    ASSERT_VALID_EPHEMERAL;
  1.2249 +    *_rval = JSD_GetValueInt (mCx, mValue);
  1.2250 +    return NS_OK;
  1.2251 +}
  1.2252 +
  1.2253 +NS_IMETHODIMP
  1.2254 +jsdValue::GetObjectValue(jsdIObject **_rval)
  1.2255 +{
  1.2256 +    ASSERT_VALID_EPHEMERAL;
  1.2257 +    JSDObject *obj;
  1.2258 +    obj = JSD_GetObjectForValue (mCx, mValue);
  1.2259 +    *_rval = jsdObject::FromPtr (mCx, obj);
  1.2260 +    if (!*_rval)
  1.2261 +        return NS_ERROR_FAILURE;
  1.2262 +    return NS_OK;
  1.2263 +}
  1.2264 +    
  1.2265 +NS_IMETHODIMP
  1.2266 +jsdValue::GetStringValue(nsACString &_rval)
  1.2267 +{
  1.2268 +    ASSERT_VALID_EPHEMERAL;
  1.2269 +    AutoSafeJSContext cx;
  1.2270 +    JSString *jstr_val = JSD_GetValueString(mCx, mValue);
  1.2271 +    if (jstr_val) {
  1.2272 +        size_t length;
  1.2273 +        const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length);
  1.2274 +        if (!chars)
  1.2275 +            return NS_ERROR_FAILURE;
  1.2276 +        nsDependentString depStr(chars, length);
  1.2277 +        CopyUTF16toUTF8(depStr, _rval);
  1.2278 +    } else {
  1.2279 +        _rval.Truncate();
  1.2280 +    }
  1.2281 +    return NS_OK;
  1.2282 +}
  1.2283 +
  1.2284 +NS_IMETHODIMP
  1.2285 +jsdValue::GetPropertyCount (int32_t *_rval)
  1.2286 +{
  1.2287 +    ASSERT_VALID_EPHEMERAL;
  1.2288 +    if (JSD_IsValueObject(mCx, mValue))
  1.2289 +        *_rval = JSD_GetCountOfProperties (mCx, mValue);
  1.2290 +    else
  1.2291 +        *_rval = -1;
  1.2292 +    return NS_OK;
  1.2293 +}
  1.2294 +
  1.2295 +NS_IMETHODIMP
  1.2296 +jsdValue::GetProperties (jsdIProperty ***propArray, uint32_t *length)
  1.2297 +{
  1.2298 +    ASSERT_VALID_EPHEMERAL;
  1.2299 +    *propArray = nullptr;
  1.2300 +    if (length)
  1.2301 +        *length = 0;
  1.2302 +
  1.2303 +    uint32_t prop_count = JSD_IsValueObject(mCx, mValue)
  1.2304 +        ? JSD_GetCountOfProperties (mCx, mValue)
  1.2305 +        : 0;
  1.2306 +    NS_ENSURE_TRUE(prop_count, NS_OK);
  1.2307 +
  1.2308 +    jsdIProperty **pa_temp =
  1.2309 +        static_cast<jsdIProperty **>
  1.2310 +                   (nsMemory::Alloc(sizeof (jsdIProperty *) * 
  1.2311 +                                       prop_count));
  1.2312 +    NS_ENSURE_TRUE(pa_temp, NS_ERROR_OUT_OF_MEMORY);
  1.2313 +
  1.2314 +    uint32_t     i    = 0;
  1.2315 +    JSDProperty *iter = nullptr;
  1.2316 +    JSDProperty *prop;
  1.2317 +    while ((prop = JSD_IterateProperties (mCx, mValue, &iter))) {
  1.2318 +        pa_temp[i] = jsdProperty::FromPtr (mCx, prop);
  1.2319 +        ++i;
  1.2320 +    }
  1.2321 +    
  1.2322 +    NS_ASSERTION (prop_count == i, "property count mismatch");    
  1.2323 +
  1.2324 +    /* if caller doesn't care about length, don't bother telling them */
  1.2325 +    *propArray = pa_temp;
  1.2326 +    if (length)
  1.2327 +        *length = prop_count;
  1.2328 +    
  1.2329 +    return NS_OK;
  1.2330 +}
  1.2331 +
  1.2332 +NS_IMETHODIMP
  1.2333 +jsdValue::GetProperty (const nsACString &name, jsdIProperty **_rval)
  1.2334 +{
  1.2335 +    ASSERT_VALID_EPHEMERAL;
  1.2336 +    AutoSafeJSContext cx;
  1.2337 +    JSAutoCompartment ac(cx, JSD_GetDefaultGlobal (mCx)); // Just in case.
  1.2338 +
  1.2339 +    /* not rooting this */
  1.2340 +    JSString *jstr_name = JS_NewStringCopyZ(cx, PromiseFlatCString(name).get());
  1.2341 +    if (!jstr_name)
  1.2342 +        return NS_ERROR_OUT_OF_MEMORY;
  1.2343 +
  1.2344 +    JSDProperty *prop = JSD_GetValueProperty (mCx, mValue, jstr_name);
  1.2345 +    
  1.2346 +    *_rval = jsdProperty::FromPtr (mCx, prop);
  1.2347 +    return NS_OK;
  1.2348 +}
  1.2349 +
  1.2350 +NS_IMETHODIMP
  1.2351 +jsdValue::Refresh()
  1.2352 +{
  1.2353 +    ASSERT_VALID_EPHEMERAL;
  1.2354 +    JSD_RefreshValue (mCx, mValue);
  1.2355 +    return NS_OK;
  1.2356 +}
  1.2357 +
  1.2358 +NS_IMETHODIMP
  1.2359 +jsdValue::GetWrappedValue(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval)
  1.2360 +{
  1.2361 +    ASSERT_VALID_EPHEMERAL;
  1.2362 +
  1.2363 +    aRetval.set(JSD_GetValueWrappedJSVal(mCx, mValue));
  1.2364 +    if (!JS_WrapValue(aCx, aRetval))
  1.2365 +        return NS_ERROR_FAILURE;
  1.2366 +
  1.2367 +    return NS_OK;
  1.2368 +}
  1.2369 +
  1.2370 +NS_IMETHODIMP
  1.2371 +jsdValue::GetScript(jsdIScript **_rval)
  1.2372 +{
  1.2373 +    ASSERT_VALID_EPHEMERAL;
  1.2374 +    JSDScript *script = JSD_GetScriptForValue(mCx, mValue);
  1.2375 +    *_rval = jsdScript::FromPtr(mCx, script);
  1.2376 +    return NS_OK;
  1.2377 +}
  1.2378 +
  1.2379 +/******************************************************************************
  1.2380 + * debugger service implementation
  1.2381 + ******************************************************************************/
  1.2382 +
  1.2383 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(jsdService)
  1.2384 +  NS_INTERFACE_MAP_ENTRY(jsdIDebuggerService)
  1.2385 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, jsdIDebuggerService)
  1.2386 +NS_INTERFACE_MAP_END
  1.2387 +
  1.2388 +NS_IMPL_CYCLE_COLLECTION(jsdService,
  1.2389 +                         mErrorHook, mBreakpointHook, mDebugHook,
  1.2390 +                         mDebuggerHook, mInterruptHook, mScriptHook,
  1.2391 +                         mThrowHook, mTopLevelHook, mFunctionHook,
  1.2392 +                         mActivationCallback)
  1.2393 +NS_IMPL_CYCLE_COLLECTING_ADDREF(jsdService)
  1.2394 +NS_IMPL_CYCLE_COLLECTING_RELEASE(jsdService)
  1.2395 +
  1.2396 +NS_IMETHODIMP
  1.2397 +jsdService::GetJSDContext(JSDContext **_rval)
  1.2398 +{
  1.2399 +    *_rval = mCx;
  1.2400 +    return NS_OK;
  1.2401 +}
  1.2402 +
  1.2403 +NS_IMETHODIMP
  1.2404 +jsdService::GetFlags (uint32_t *_rval)
  1.2405 +{
  1.2406 +    ASSERT_VALID_CONTEXT;
  1.2407 +    *_rval = JSD_GetContextFlags (mCx);
  1.2408 +    return NS_OK;
  1.2409 +}
  1.2410 +
  1.2411 +NS_IMETHODIMP
  1.2412 +jsdService::SetFlags (uint32_t flags)
  1.2413 +{
  1.2414 +    ASSERT_VALID_CONTEXT;
  1.2415 +    JSD_SetContextFlags (mCx, flags);
  1.2416 +    return NS_OK;
  1.2417 +}
  1.2418 +
  1.2419 +NS_IMETHODIMP
  1.2420 +jsdService::GetImplementationString(nsACString &aImplementationString)
  1.2421 +{
  1.2422 +    aImplementationString.AssignLiteral(implementationString);
  1.2423 +    return NS_OK;
  1.2424 +}
  1.2425 +
  1.2426 +NS_IMETHODIMP
  1.2427 +jsdService::GetImplementationMajor(uint32_t *_rval)
  1.2428 +{
  1.2429 +    *_rval = JSDS_MAJOR_VERSION;
  1.2430 +    return NS_OK;
  1.2431 +}
  1.2432 +
  1.2433 +NS_IMETHODIMP
  1.2434 +jsdService::GetImplementationMinor(uint32_t *_rval)
  1.2435 +{
  1.2436 +    *_rval = JSDS_MINOR_VERSION;
  1.2437 +    return NS_OK;
  1.2438 +}
  1.2439 +
  1.2440 +NS_IMETHODIMP
  1.2441 +jsdService::GetIsOn (bool *_rval)
  1.2442 +{
  1.2443 +    *_rval = mOn;
  1.2444 +    return NS_OK;
  1.2445 +}
  1.2446 +
  1.2447 +NS_IMETHODIMP
  1.2448 +jsdService::On (void)
  1.2449 +{
  1.2450 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.2451 +}
  1.2452 +
  1.2453 +NS_IMETHODIMP
  1.2454 +jsdService::AsyncOn (jsdIActivationCallback *activationCallback)
  1.2455 +{
  1.2456 +    nsresult  rv;
  1.2457 +
  1.2458 +    // Warn that JSD is deprecated, unless the caller has told us
  1.2459 +    // that they know already.
  1.2460 +    if (mDeprecationAcknowledged) {
  1.2461 +        mDeprecationAcknowledged = false;
  1.2462 +    } else if (!mWarnedAboutDeprecation) {
  1.2463 +        // In any case, warn only once.
  1.2464 +        mWarnedAboutDeprecation = true;
  1.2465 +
  1.2466 +        // Ignore errors: simply being unable to print the message
  1.2467 +        // shouldn't (effectively) disable JSD.
  1.2468 +        nsContentUtils::ReportToConsoleNonLocalized(
  1.2469 +            NS_LITERAL_STRING("\
  1.2470 +The jsdIDebuggerService and its associated interfaces are deprecated. \
  1.2471 +Please use Debugger, via IJSDebugger, instead."),
  1.2472 +            nsIScriptError::warningFlag,
  1.2473 +            NS_LITERAL_CSTRING("JSD"),
  1.2474 +            nullptr);
  1.2475 +    }
  1.2476 +
  1.2477 +    nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
  1.2478 +    if (NS_FAILED(rv)) return rv;
  1.2479 +
  1.2480 +    mActivationCallback = activationCallback;
  1.2481 +
  1.2482 +    return xpc->SetDebugModeWhenPossible(true, true);
  1.2483 +}
  1.2484 +
  1.2485 +NS_IMETHODIMP
  1.2486 +jsdService::RecompileForDebugMode (JSContext *cx, JSCompartment *comp, bool mode) {
  1.2487 +  NS_ASSERTION(NS_IsMainThread(), "wrong thread");
  1.2488 +  /* XPConnect now does this work itself, so this IDL entry point is no longer used. */
  1.2489 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.2490 +}
  1.2491 +
  1.2492 +NS_IMETHODIMP
  1.2493 +jsdService::DeactivateDebugger ()
  1.2494 +{
  1.2495 +    if (!mCx)
  1.2496 +        return NS_OK;
  1.2497 +
  1.2498 +    jsdContext::InvalidateAll();
  1.2499 +    jsdScript::InvalidateAll();
  1.2500 +    jsdValue::InvalidateAll();
  1.2501 +    jsdProperty::InvalidateAll();
  1.2502 +    jsdStackFrame::InvalidateAll();
  1.2503 +    ClearAllBreakpoints();
  1.2504 +
  1.2505 +    JSD_SetErrorReporter (mCx, nullptr, nullptr);
  1.2506 +    JSD_SetScriptHook (mCx, nullptr, nullptr);
  1.2507 +    JSD_ClearThrowHook (mCx);
  1.2508 +    JSD_ClearInterruptHook (mCx);
  1.2509 +    JSD_ClearDebuggerHook (mCx);
  1.2510 +    JSD_ClearDebugBreakHook (mCx);
  1.2511 +    JSD_ClearTopLevelHook (mCx);
  1.2512 +    JSD_ClearFunctionHook (mCx);
  1.2513 +
  1.2514 +    JSD_DebuggerOff (mCx);
  1.2515 +
  1.2516 +    mCx = nullptr;
  1.2517 +    mRuntime = nullptr;
  1.2518 +    mOn = false;
  1.2519 +
  1.2520 +    return NS_OK;
  1.2521 +}
  1.2522 +
  1.2523 +
  1.2524 +NS_IMETHODIMP
  1.2525 +jsdService::ActivateDebugger (JSRuntime *rt)
  1.2526 +{
  1.2527 +    if (mOn)
  1.2528 +        return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED;
  1.2529 +
  1.2530 +    mRuntime = rt;
  1.2531 +
  1.2532 +    if (gPrevGCSliceCallback == jsds_GCSliceCallbackProc)
  1.2533 +        /* condition indicates that the callback proc has not been set yet */
  1.2534 +        gPrevGCSliceCallback = JS::SetGCSliceCallback (rt, jsds_GCSliceCallbackProc);
  1.2535 +
  1.2536 +    mCx = JSD_DebuggerOnForUser (rt, nullptr, nullptr);
  1.2537 +    if (!mCx)
  1.2538 +        return NS_ERROR_FAILURE;
  1.2539 +
  1.2540 +    AutoSafeJSContext cx;
  1.2541 +    JS::RootedObject glob(cx, JSD_GetDefaultGlobal (mCx));
  1.2542 +    JSAutoCompartment ac(cx, glob);
  1.2543 +
  1.2544 +    /* init xpconnect on the debugger's context in case xpconnect tries to
  1.2545 +     * use it for stuff. */
  1.2546 +    nsresult rv;
  1.2547 +    nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
  1.2548 +    if (NS_FAILED(rv))
  1.2549 +        return rv;
  1.2550 +
  1.2551 +    xpc->InitClasses (cx, glob);
  1.2552 +
  1.2553 +    /* Start watching for script creation/destruction and manage jsdScript
  1.2554 +     * objects accordingly
  1.2555 +     */
  1.2556 +    JSD_SetScriptHook (mCx, jsds_ScriptHookProc, nullptr);
  1.2557 +
  1.2558 +    /* If any of these mFooHook objects are installed, do the required JSD
  1.2559 +     * hookup now.   See also, jsdService::SetFooHook().
  1.2560 +     */
  1.2561 +    if (mErrorHook)
  1.2562 +        JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, nullptr);
  1.2563 +    if (mThrowHook)
  1.2564 +        JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.2565 +    /* can't ignore script callbacks, as we need to |Release| the wrapper 
  1.2566 +     * stored in private data when a script is deleted. */
  1.2567 +    if (mInterruptHook)
  1.2568 +        JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.2569 +    if (mDebuggerHook)
  1.2570 +        JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.2571 +    if (mDebugHook)
  1.2572 +        JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.2573 +    if (mTopLevelHook)
  1.2574 +        JSD_SetTopLevelHook (mCx, jsds_CallHookProc, nullptr);
  1.2575 +    else
  1.2576 +        JSD_ClearTopLevelHook (mCx);
  1.2577 +    if (mFunctionHook)
  1.2578 +        JSD_SetFunctionHook (mCx, jsds_CallHookProc, nullptr);
  1.2579 +    else
  1.2580 +        JSD_ClearFunctionHook (mCx);
  1.2581 +    mOn = true;
  1.2582 +
  1.2583 +#ifdef DEBUG
  1.2584 +    printf ("+++ JavaScript debugging hooks installed.\n");
  1.2585 +#endif
  1.2586 +
  1.2587 +    nsCOMPtr<jsdIActivationCallback> activationCallback;
  1.2588 +    mActivationCallback.swap(activationCallback);
  1.2589 +    if (activationCallback)
  1.2590 +        return activationCallback->OnDebuggerActivated();
  1.2591 +
  1.2592 +    return NS_OK;
  1.2593 +}
  1.2594 +
  1.2595 +NS_IMETHODIMP
  1.2596 +jsdService::Off (void)
  1.2597 +{
  1.2598 +    if (!mOn)
  1.2599 +        return NS_OK;
  1.2600 +    
  1.2601 +    if (!mCx || !mRuntime)
  1.2602 +        return NS_ERROR_NOT_INITIALIZED;
  1.2603 +    
  1.2604 +    if (gDeadScripts) {
  1.2605 +        if (gGCRunning)
  1.2606 +            return NS_ERROR_NOT_AVAILABLE;
  1.2607 +
  1.2608 +        while (gDeadScripts)
  1.2609 +            jsds_NotifyPendingDeadScripts (JS_GetRuntime(nsContentUtils::GetSafeJSContext()));
  1.2610 +    }
  1.2611 +
  1.2612 +    DeactivateDebugger();
  1.2613 +
  1.2614 +#ifdef DEBUG
  1.2615 +    printf ("+++ JavaScript debugging hooks removed.\n");
  1.2616 +#endif
  1.2617 +
  1.2618 +    nsresult rv;
  1.2619 +    nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
  1.2620 +    if (NS_FAILED(rv))
  1.2621 +        return rv;
  1.2622 +
  1.2623 +    xpc->SetDebugModeWhenPossible(false, true);
  1.2624 +
  1.2625 +    return NS_OK;
  1.2626 +}
  1.2627 +
  1.2628 +NS_IMETHODIMP
  1.2629 +jsdService::GetPauseDepth(uint32_t *_rval)
  1.2630 +{
  1.2631 +    NS_ENSURE_ARG_POINTER(_rval);
  1.2632 +    *_rval = mPauseLevel;
  1.2633 +    return NS_OK;
  1.2634 +}
  1.2635 +    
  1.2636 +NS_IMETHODIMP
  1.2637 +jsdService::Pause(uint32_t *_rval)
  1.2638 +{
  1.2639 +    return DoPause(_rval, false);
  1.2640 +}
  1.2641 +
  1.2642 +nsresult
  1.2643 +jsdService::DoPause(uint32_t *_rval, bool internalCall)
  1.2644 +{
  1.2645 +    if (!mCx)
  1.2646 +        return NS_ERROR_NOT_INITIALIZED;
  1.2647 +
  1.2648 +    if (++mPauseLevel == 1) {
  1.2649 +        JSD_SetErrorReporter (mCx, nullptr, nullptr);
  1.2650 +        JSD_ClearThrowHook (mCx);
  1.2651 +        JSD_ClearInterruptHook (mCx);
  1.2652 +        JSD_ClearDebuggerHook (mCx);
  1.2653 +        JSD_ClearDebugBreakHook (mCx);
  1.2654 +        JSD_ClearTopLevelHook (mCx);
  1.2655 +        JSD_ClearFunctionHook (mCx);
  1.2656 +        JSD_DebuggerPause (mCx);
  1.2657 +
  1.2658 +        nsresult rv;
  1.2659 +        nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
  1.2660 +        if (NS_FAILED(rv)) return rv;
  1.2661 +
  1.2662 +        if (!internalCall) {
  1.2663 +            rv = xpc->SetDebugModeWhenPossible(false, false);
  1.2664 +            NS_ENSURE_SUCCESS(rv, rv);
  1.2665 +        }
  1.2666 +    }
  1.2667 +
  1.2668 +    if (_rval)
  1.2669 +        *_rval = mPauseLevel;
  1.2670 +
  1.2671 +    return NS_OK;
  1.2672 +}
  1.2673 +
  1.2674 +NS_IMETHODIMP
  1.2675 +jsdService::UnPause(uint32_t *_rval)
  1.2676 +{
  1.2677 +    return DoUnPause(_rval, false);
  1.2678 +}
  1.2679 +
  1.2680 +nsresult
  1.2681 +jsdService::DoUnPause(uint32_t *_rval, bool internalCall)
  1.2682 +{
  1.2683 +    if (!mCx)
  1.2684 +        return NS_ERROR_NOT_INITIALIZED;
  1.2685 +
  1.2686 +    if (mPauseLevel == 0)
  1.2687 +        return NS_ERROR_NOT_AVAILABLE;
  1.2688 +
  1.2689 +    /* check mOn before we muck with this stuff, it's possible the debugger
  1.2690 +     * was turned off while we were paused.
  1.2691 +     */
  1.2692 +    if (--mPauseLevel == 0 && mOn) {
  1.2693 +        JSD_DebuggerUnpause (mCx);
  1.2694 +        if (mErrorHook)
  1.2695 +            JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, nullptr);
  1.2696 +        if (mThrowHook)
  1.2697 +            JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.2698 +        if (mInterruptHook)
  1.2699 +            JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.2700 +        if (mDebuggerHook)
  1.2701 +            JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.2702 +        if (mDebugHook)
  1.2703 +            JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.2704 +        if (mTopLevelHook)
  1.2705 +            JSD_SetTopLevelHook (mCx, jsds_CallHookProc, nullptr);
  1.2706 +        else
  1.2707 +            JSD_ClearTopLevelHook (mCx);
  1.2708 +        if (mFunctionHook)
  1.2709 +            JSD_SetFunctionHook (mCx, jsds_CallHookProc, nullptr);
  1.2710 +        else
  1.2711 +            JSD_ClearFunctionHook (mCx);
  1.2712 +
  1.2713 +        nsresult rv;
  1.2714 +        nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
  1.2715 +        if (NS_FAILED(rv)) return rv;
  1.2716 +
  1.2717 +        if (!internalCall) {
  1.2718 +            rv = xpc->SetDebugModeWhenPossible(true, false);
  1.2719 +            NS_ENSURE_SUCCESS(rv, rv);
  1.2720 +        }
  1.2721 +    }
  1.2722 +    
  1.2723 +    if (_rval)
  1.2724 +        *_rval = mPauseLevel;
  1.2725 +
  1.2726 +    return NS_OK;
  1.2727 +}
  1.2728 +
  1.2729 +NS_IMETHODIMP
  1.2730 +jsdService::EnumerateContexts (jsdIContextEnumerator *enumerator)
  1.2731 +{
  1.2732 +    ASSERT_VALID_CONTEXT;
  1.2733 +    
  1.2734 +    if (!enumerator)
  1.2735 +        return NS_OK;
  1.2736 +    
  1.2737 +    JSContext *iter = nullptr;
  1.2738 +    JSContext *cx;
  1.2739 +
  1.2740 +    while ((cx = JS_ContextIterator (mRuntime, &iter)))
  1.2741 +    {
  1.2742 +        nsCOMPtr<jsdIContext> jsdicx = 
  1.2743 +            dont_AddRef(jsdContext::FromPtr(mCx, cx));
  1.2744 +        if (jsdicx)
  1.2745 +        {
  1.2746 +            if (NS_FAILED(enumerator->EnumerateContext(jsdicx)))
  1.2747 +                break;
  1.2748 +        }
  1.2749 +    }
  1.2750 +
  1.2751 +    return NS_OK;
  1.2752 +}
  1.2753 +
  1.2754 +NS_IMETHODIMP
  1.2755 +jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator)
  1.2756 +{
  1.2757 +    ASSERT_VALID_CONTEXT;
  1.2758 +    
  1.2759 +    JSDScript *script;
  1.2760 +    JSDScript *iter = nullptr;
  1.2761 +    nsresult rv = NS_OK;
  1.2762 +    
  1.2763 +    JSD_LockScriptSubsystem(mCx);
  1.2764 +    while((script = JSD_IterateScripts(mCx, &iter))) {
  1.2765 +        nsCOMPtr<jsdIScript> jsdis =
  1.2766 +            dont_AddRef(jsdScript::FromPtr(mCx, script));
  1.2767 +        rv = enumerator->EnumerateScript (jsdis);
  1.2768 +        if (NS_FAILED(rv))
  1.2769 +            break;
  1.2770 +    }
  1.2771 +    JSD_UnlockScriptSubsystem(mCx);
  1.2772 +
  1.2773 +    return rv;
  1.2774 +}
  1.2775 +
  1.2776 +NS_IMETHODIMP
  1.2777 +jsdService::GC (void)
  1.2778 +{
  1.2779 +    ASSERT_VALID_CONTEXT;
  1.2780 +    JSRuntime *rt = JSD_GetJSRuntime (mCx);
  1.2781 +    JS_GC(rt);
  1.2782 +    return NS_OK;
  1.2783 +}
  1.2784 +    
  1.2785 +NS_IMETHODIMP
  1.2786 +jsdService::DumpHeap(const nsACString &fileName)
  1.2787 +{
  1.2788 +    ASSERT_VALID_CONTEXT;
  1.2789 +#ifndef DEBUG
  1.2790 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.2791 +#else
  1.2792 +    nsresult rv = NS_OK;
  1.2793 +    FILE *file = !fileName.IsEmpty() ? fopen(PromiseFlatCString(fileName).get(), "w") : stdout;
  1.2794 +    if (!file) {
  1.2795 +        rv = NS_ERROR_FAILURE;
  1.2796 +    } else {
  1.2797 +        if (!JS_DumpHeap(JS_GetRuntime(nsContentUtils::GetSafeJSContext()),
  1.2798 +                         file, nullptr, JSTRACE_OBJECT, nullptr, (size_t)-1, nullptr))
  1.2799 +            rv = NS_ERROR_FAILURE;
  1.2800 +        if (file != stdout)
  1.2801 +            fclose(file);
  1.2802 +    }
  1.2803 +    return rv;
  1.2804 +#endif
  1.2805 +}
  1.2806 +
  1.2807 +NS_IMETHODIMP
  1.2808 +jsdService::ClearProfileData ()
  1.2809 +{
  1.2810 +    ASSERT_VALID_CONTEXT;
  1.2811 +    JSD_ClearAllProfileData (mCx);
  1.2812 +    return NS_OK;
  1.2813 +}
  1.2814 +
  1.2815 +NS_IMETHODIMP
  1.2816 +jsdService::InsertFilter (jsdIFilter *filter, jsdIFilter *after)
  1.2817 +{
  1.2818 +    NS_ENSURE_ARG_POINTER (filter);
  1.2819 +    if (jsds_FindFilter (filter))
  1.2820 +        return NS_ERROR_INVALID_ARG;
  1.2821 +
  1.2822 +    FilterRecord *rec = PR_NEWZAP (FilterRecord);
  1.2823 +    if (!rec)
  1.2824 +        return NS_ERROR_OUT_OF_MEMORY;
  1.2825 +
  1.2826 +    if (!jsds_SyncFilter (rec, filter)) {
  1.2827 +        PR_Free (rec);
  1.2828 +        return NS_ERROR_FAILURE;
  1.2829 +    }
  1.2830 +    
  1.2831 +    if (gFilters) {
  1.2832 +        if (!after) {
  1.2833 +            /* insert at head of list */
  1.2834 +            PR_INSERT_LINK(&rec->links, &gFilters->links);
  1.2835 +            gFilters = rec;
  1.2836 +        } else {
  1.2837 +            /* insert somewhere in the list */
  1.2838 +            FilterRecord *afterRecord = jsds_FindFilter (after);
  1.2839 +            if (!afterRecord) {
  1.2840 +                jsds_FreeFilter(rec);
  1.2841 +                return NS_ERROR_INVALID_ARG;
  1.2842 +            }
  1.2843 +            PR_INSERT_AFTER(&rec->links, &afterRecord->links);
  1.2844 +        }
  1.2845 +    } else {
  1.2846 +        if (after) {
  1.2847 +            /* user asked to insert into the middle of an empty list, bail. */
  1.2848 +            jsds_FreeFilter(rec);
  1.2849 +            return NS_ERROR_NOT_INITIALIZED;
  1.2850 +        }
  1.2851 +        PR_INIT_CLIST(&rec->links);
  1.2852 +        gFilters = rec;
  1.2853 +    }
  1.2854 +    
  1.2855 +    return NS_OK;
  1.2856 +}
  1.2857 +
  1.2858 +NS_IMETHODIMP
  1.2859 +jsdService::AppendFilter (jsdIFilter *filter)
  1.2860 +{
  1.2861 +    NS_ENSURE_ARG_POINTER (filter);
  1.2862 +    if (jsds_FindFilter (filter))
  1.2863 +        return NS_ERROR_INVALID_ARG;
  1.2864 +    FilterRecord *rec = PR_NEWZAP (FilterRecord);
  1.2865 +
  1.2866 +    if (!jsds_SyncFilter (rec, filter)) {
  1.2867 +        PR_Free (rec);
  1.2868 +        return NS_ERROR_FAILURE;
  1.2869 +    }
  1.2870 +    
  1.2871 +    if (gFilters) {
  1.2872 +        PR_INSERT_BEFORE(&rec->links, &gFilters->links);
  1.2873 +    } else {
  1.2874 +        PR_INIT_CLIST(&rec->links);
  1.2875 +        gFilters = rec;
  1.2876 +    }
  1.2877 +    
  1.2878 +    return NS_OK;
  1.2879 +}
  1.2880 +
  1.2881 +NS_IMETHODIMP
  1.2882 +jsdService::RemoveFilter (jsdIFilter *filter)
  1.2883 +{
  1.2884 +    NS_ENSURE_ARG_POINTER(filter);
  1.2885 +    FilterRecord *rec = jsds_FindFilter (filter);
  1.2886 +    if (!rec)
  1.2887 +        return NS_ERROR_INVALID_ARG;
  1.2888 +    
  1.2889 +    if (gFilters == rec) {
  1.2890 +        gFilters = reinterpret_cast<FilterRecord *>
  1.2891 +                                   (PR_NEXT_LINK(&rec->links));
  1.2892 +        /* If we're the only filter left, null out the list head. */
  1.2893 +        if (gFilters == rec)
  1.2894 +            gFilters = nullptr;
  1.2895 +    }
  1.2896 +
  1.2897 +    
  1.2898 +    PR_REMOVE_LINK(&rec->links);
  1.2899 +    jsds_FreeFilter (rec);
  1.2900 +    
  1.2901 +    return NS_OK;
  1.2902 +}
  1.2903 +
  1.2904 +NS_IMETHODIMP
  1.2905 +jsdService::SwapFilters (jsdIFilter *filter_a, jsdIFilter *filter_b)
  1.2906 +{
  1.2907 +    NS_ENSURE_ARG_POINTER(filter_a);
  1.2908 +    NS_ENSURE_ARG_POINTER(filter_b);
  1.2909 +    
  1.2910 +    FilterRecord *rec_a = jsds_FindFilter (filter_a);
  1.2911 +    if (!rec_a)
  1.2912 +        return NS_ERROR_INVALID_ARG;
  1.2913 +    
  1.2914 +    if (filter_a == filter_b) {
  1.2915 +        /* just a refresh */
  1.2916 +        if (!jsds_SyncFilter (rec_a, filter_a))
  1.2917 +            return NS_ERROR_FAILURE;
  1.2918 +        return NS_OK;
  1.2919 +    }
  1.2920 +    
  1.2921 +    FilterRecord *rec_b = jsds_FindFilter (filter_b);
  1.2922 +    if (!rec_b) {
  1.2923 +        /* filter_b is not in the list, replace filter_a with filter_b. */
  1.2924 +        if (!jsds_SyncFilter (rec_a, filter_b))
  1.2925 +            return NS_ERROR_FAILURE;
  1.2926 +    } else {
  1.2927 +        /* both filters are in the list, swap. */
  1.2928 +        if (!jsds_SyncFilter (rec_a, filter_b))
  1.2929 +            return NS_ERROR_FAILURE;
  1.2930 +        if (!jsds_SyncFilter (rec_b, filter_a))
  1.2931 +            return NS_ERROR_FAILURE;
  1.2932 +    }
  1.2933 +    
  1.2934 +    return NS_OK;
  1.2935 +}
  1.2936 +
  1.2937 +NS_IMETHODIMP
  1.2938 +jsdService::EnumerateFilters (jsdIFilterEnumerator *enumerator) 
  1.2939 +{
  1.2940 +    if (!gFilters)
  1.2941 +        return NS_OK;
  1.2942 +    
  1.2943 +    FilterRecord *current = gFilters;
  1.2944 +    do {
  1.2945 +        jsds_SyncFilter (current, current->filterObject);
  1.2946 +        /* SyncFilter failure would be bad, but what would we do about it? */
  1.2947 +        if (enumerator) {
  1.2948 +            nsresult rv = enumerator->EnumerateFilter (current->filterObject);
  1.2949 +            if (NS_FAILED(rv))
  1.2950 +                return rv;
  1.2951 +        }
  1.2952 +        current = reinterpret_cast<FilterRecord *>
  1.2953 +                                  (PR_NEXT_LINK (&current->links));
  1.2954 +    } while (current != gFilters);
  1.2955 +    
  1.2956 +    return NS_OK;
  1.2957 +}
  1.2958 +
  1.2959 +NS_IMETHODIMP
  1.2960 +jsdService::RefreshFilters ()
  1.2961 +{
  1.2962 +    return EnumerateFilters(nullptr);
  1.2963 +}
  1.2964 +
  1.2965 +NS_IMETHODIMP
  1.2966 +jsdService::ClearFilters ()
  1.2967 +{
  1.2968 +    if (!gFilters)
  1.2969 +        return NS_OK;
  1.2970 +
  1.2971 +    FilterRecord *current = reinterpret_cast<FilterRecord *>
  1.2972 +                                            (PR_NEXT_LINK (&gFilters->links));
  1.2973 +    do {
  1.2974 +        FilterRecord *next = reinterpret_cast<FilterRecord *>
  1.2975 +                                             (PR_NEXT_LINK (&current->links));
  1.2976 +        PR_REMOVE_AND_INIT_LINK(&current->links);
  1.2977 +        jsds_FreeFilter(current);
  1.2978 +        current = next;
  1.2979 +    } while (current != gFilters);
  1.2980 +    
  1.2981 +    jsds_FreeFilter(current);
  1.2982 +    gFilters = nullptr;
  1.2983 +    
  1.2984 +    return NS_OK;
  1.2985 +}
  1.2986 +        
  1.2987 +NS_IMETHODIMP
  1.2988 +jsdService::ClearAllBreakpoints (void)
  1.2989 +{
  1.2990 +    ASSERT_VALID_CONTEXT;
  1.2991 +
  1.2992 +    JSD_LockScriptSubsystem(mCx);
  1.2993 +    JSD_ClearAllExecutionHooks (mCx);
  1.2994 +    JSD_UnlockScriptSubsystem(mCx);
  1.2995 +    return NS_OK;
  1.2996 +}
  1.2997 +
  1.2998 +NS_IMETHODIMP
  1.2999 +jsdService::WrapValue(JS::Handle<JS::Value> value, jsdIValue **_rval)
  1.3000 +{
  1.3001 +    ASSERT_VALID_CONTEXT;
  1.3002 +    JSDValue *jsdv = JSD_NewValue(mCx, value);
  1.3003 +    if (!jsdv)
  1.3004 +        return NS_ERROR_FAILURE;
  1.3005 +    
  1.3006 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
  1.3007 +    return NS_OK;
  1.3008 +}
  1.3009 +
  1.3010 +
  1.3011 +NS_IMETHODIMP
  1.3012 +jsdService::EnterNestedEventLoop (jsdINestCallback *callback, uint32_t *_rval)
  1.3013 +{
  1.3014 +    // Nesting event queues is a thing of the past.  Now, we just spin the
  1.3015 +    // current event loop.
  1.3016 +    nsresult rv = NS_OK;
  1.3017 +    AutoNoJSAPI nojsapi;
  1.3018 +    uint32_t nestLevel = ++mNestedLoopLevel;
  1.3019 +    nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
  1.3020 +
  1.3021 +    if (callback) {
  1.3022 +        DoPause(nullptr, true);
  1.3023 +        rv = callback->OnNest();
  1.3024 +        DoUnPause(nullptr, true);
  1.3025 +    }
  1.3026 +
  1.3027 +    while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) {
  1.3028 +        if (!NS_ProcessNextEvent(thread))
  1.3029 +            rv = NS_ERROR_UNEXPECTED;
  1.3030 +    }
  1.3031 +
  1.3032 +    NS_ASSERTION (mNestedLoopLevel <= nestLevel,
  1.3033 +                  "nested event didn't unwind properly");
  1.3034 +    if (mNestedLoopLevel == nestLevel)
  1.3035 +        --mNestedLoopLevel;
  1.3036 +
  1.3037 +    *_rval = mNestedLoopLevel;
  1.3038 +    return rv;
  1.3039 +}
  1.3040 +
  1.3041 +NS_IMETHODIMP
  1.3042 +jsdService::ExitNestedEventLoop (uint32_t *_rval)
  1.3043 +{
  1.3044 +    if (mNestedLoopLevel > 0)
  1.3045 +        --mNestedLoopLevel;
  1.3046 +    else
  1.3047 +        return NS_ERROR_FAILURE;
  1.3048 +
  1.3049 +    *_rval = mNestedLoopLevel;    
  1.3050 +    return NS_OK;
  1.3051 +}    
  1.3052 +
  1.3053 +NS_IMETHODIMP
  1.3054 +jsdService::AcknowledgeDeprecation()
  1.3055 +{
  1.3056 +    mDeprecationAcknowledged = true;
  1.3057 +    return NS_OK;
  1.3058 +}
  1.3059 +
  1.3060 +/* hook attribute get/set functions */
  1.3061 +
  1.3062 +NS_IMETHODIMP
  1.3063 +jsdService::SetErrorHook (jsdIErrorHook *aHook)
  1.3064 +{
  1.3065 +    mErrorHook = aHook;
  1.3066 +
  1.3067 +    /* if the debugger isn't initialized, that's all we can do for now.  The
  1.3068 +     * ActivateDebugger() method will do the rest when the coast is clear.
  1.3069 +     */
  1.3070 +    if (!mCx || mPauseLevel)
  1.3071 +        return NS_OK;
  1.3072 +
  1.3073 +    if (aHook)
  1.3074 +        JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, nullptr);
  1.3075 +    else
  1.3076 +        JSD_SetErrorReporter (mCx, nullptr, nullptr);
  1.3077 +
  1.3078 +    return NS_OK;
  1.3079 +}
  1.3080 +
  1.3081 +NS_IMETHODIMP
  1.3082 +jsdService::GetErrorHook (jsdIErrorHook **aHook)
  1.3083 +{
  1.3084 +    *aHook = mErrorHook;
  1.3085 +    NS_IF_ADDREF(*aHook);
  1.3086 +    
  1.3087 +    return NS_OK;
  1.3088 +}
  1.3089 +
  1.3090 +NS_IMETHODIMP
  1.3091 +jsdService::SetBreakpointHook (jsdIExecutionHook *aHook)
  1.3092 +{    
  1.3093 +    mBreakpointHook = aHook;
  1.3094 +    return NS_OK;
  1.3095 +}
  1.3096 +
  1.3097 +NS_IMETHODIMP
  1.3098 +jsdService::GetBreakpointHook (jsdIExecutionHook **aHook)
  1.3099 +{   
  1.3100 +    *aHook = mBreakpointHook;
  1.3101 +    NS_IF_ADDREF(*aHook);
  1.3102 +    
  1.3103 +    return NS_OK;
  1.3104 +}
  1.3105 +
  1.3106 +NS_IMETHODIMP
  1.3107 +jsdService::SetDebugHook (jsdIExecutionHook *aHook)
  1.3108 +{    
  1.3109 +    mDebugHook = aHook;
  1.3110 +
  1.3111 +    /* if the debugger isn't initialized, that's all we can do for now.  The
  1.3112 +     * ActivateDebugger() method will do the rest when the coast is clear.
  1.3113 +     */
  1.3114 +    if (!mCx || mPauseLevel)
  1.3115 +        return NS_OK;
  1.3116 +
  1.3117 +    if (aHook)
  1.3118 +        JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.3119 +    else
  1.3120 +        JSD_ClearDebugBreakHook (mCx);
  1.3121 +    
  1.3122 +    return NS_OK;
  1.3123 +}
  1.3124 +
  1.3125 +NS_IMETHODIMP
  1.3126 +jsdService::GetDebugHook (jsdIExecutionHook **aHook)
  1.3127 +{   
  1.3128 +    *aHook = mDebugHook;
  1.3129 +    NS_IF_ADDREF(*aHook);
  1.3130 +    
  1.3131 +    return NS_OK;
  1.3132 +}
  1.3133 +
  1.3134 +NS_IMETHODIMP
  1.3135 +jsdService::SetDebuggerHook (jsdIExecutionHook *aHook)
  1.3136 +{    
  1.3137 +    mDebuggerHook = aHook;
  1.3138 +
  1.3139 +    /* if the debugger isn't initialized, that's all we can do for now.  The
  1.3140 +     * ActivateDebugger() method will do the rest when the coast is clear.
  1.3141 +     */
  1.3142 +    if (!mCx || mPauseLevel)
  1.3143 +        return NS_OK;
  1.3144 +
  1.3145 +    if (aHook)
  1.3146 +        JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.3147 +    else
  1.3148 +        JSD_ClearDebuggerHook (mCx);
  1.3149 +    
  1.3150 +    return NS_OK;
  1.3151 +}
  1.3152 +
  1.3153 +NS_IMETHODIMP
  1.3154 +jsdService::GetDebuggerHook (jsdIExecutionHook **aHook)
  1.3155 +{   
  1.3156 +    *aHook = mDebuggerHook;
  1.3157 +    NS_IF_ADDREF(*aHook);
  1.3158 +    
  1.3159 +    return NS_OK;
  1.3160 +}
  1.3161 +
  1.3162 +NS_IMETHODIMP
  1.3163 +jsdService::SetInterruptHook (jsdIExecutionHook *aHook)
  1.3164 +{    
  1.3165 +    mInterruptHook = aHook;
  1.3166 +
  1.3167 +    /* if the debugger isn't initialized, that's all we can do for now.  The
  1.3168 +     * ActivateDebugger() method will do the rest when the coast is clear.
  1.3169 +     */
  1.3170 +    if (!mCx || mPauseLevel)
  1.3171 +        return NS_OK;
  1.3172 +
  1.3173 +    if (aHook)
  1.3174 +        JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.3175 +    else
  1.3176 +        JSD_ClearInterruptHook (mCx);
  1.3177 +    
  1.3178 +    return NS_OK;
  1.3179 +}
  1.3180 +
  1.3181 +NS_IMETHODIMP
  1.3182 +jsdService::GetInterruptHook (jsdIExecutionHook **aHook)
  1.3183 +{   
  1.3184 +    *aHook = mInterruptHook;
  1.3185 +    NS_IF_ADDREF(*aHook);
  1.3186 +    
  1.3187 +    return NS_OK;
  1.3188 +}
  1.3189 +
  1.3190 +NS_IMETHODIMP
  1.3191 +jsdService::SetScriptHook (jsdIScriptHook *aHook)
  1.3192 +{    
  1.3193 +    mScriptHook = aHook;
  1.3194 +
  1.3195 +    /* if the debugger isn't initialized, that's all we can do for now.  The
  1.3196 +     * ActivateDebugger() method will do the rest when the coast is clear.
  1.3197 +     */
  1.3198 +    if (!mCx || mPauseLevel)
  1.3199 +        return NS_OK;
  1.3200 +    
  1.3201 +    if (aHook)
  1.3202 +        JSD_SetScriptHook (mCx, jsds_ScriptHookProc, nullptr);
  1.3203 +    /* we can't unset it if !aHook, because we still need to see script
  1.3204 +     * deletes in order to Release the jsdIScripts held in JSDScript
  1.3205 +     * private data. */
  1.3206 +    return NS_OK;
  1.3207 +}
  1.3208 +
  1.3209 +NS_IMETHODIMP
  1.3210 +jsdService::GetScriptHook (jsdIScriptHook **aHook)
  1.3211 +{   
  1.3212 +    *aHook = mScriptHook;
  1.3213 +    NS_IF_ADDREF(*aHook);
  1.3214 +    
  1.3215 +    return NS_OK;
  1.3216 +}
  1.3217 +
  1.3218 +NS_IMETHODIMP
  1.3219 +jsdService::SetThrowHook (jsdIExecutionHook *aHook)
  1.3220 +{    
  1.3221 +    mThrowHook = aHook;
  1.3222 +
  1.3223 +    /* if the debugger isn't initialized, that's all we can do for now.  The
  1.3224 +     * ActivateDebugger() method will do the rest when the coast is clear.
  1.3225 +     */
  1.3226 +    if (!mCx || mPauseLevel)
  1.3227 +        return NS_OK;
  1.3228 +
  1.3229 +    if (aHook)
  1.3230 +        JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, nullptr);
  1.3231 +    else
  1.3232 +        JSD_ClearThrowHook (mCx);
  1.3233 +    
  1.3234 +    return NS_OK;
  1.3235 +}
  1.3236 +
  1.3237 +NS_IMETHODIMP
  1.3238 +jsdService::GetThrowHook (jsdIExecutionHook **aHook)
  1.3239 +{   
  1.3240 +    *aHook = mThrowHook;
  1.3241 +    NS_IF_ADDREF(*aHook);
  1.3242 +    
  1.3243 +    return NS_OK;
  1.3244 +}
  1.3245 +
  1.3246 +NS_IMETHODIMP
  1.3247 +jsdService::SetTopLevelHook (jsdICallHook *aHook)
  1.3248 +{    
  1.3249 +    mTopLevelHook = aHook;
  1.3250 +
  1.3251 +    /* if the debugger isn't initialized, that's all we can do for now.  The
  1.3252 +     * ActivateDebugger() method will do the rest when the coast is clear.
  1.3253 +     */
  1.3254 +    if (!mCx || mPauseLevel)
  1.3255 +        return NS_OK;
  1.3256 +
  1.3257 +    if (aHook)
  1.3258 +        JSD_SetTopLevelHook (mCx, jsds_CallHookProc, nullptr);
  1.3259 +    else
  1.3260 +        JSD_ClearTopLevelHook (mCx);
  1.3261 +    
  1.3262 +    return NS_OK;
  1.3263 +}
  1.3264 +
  1.3265 +NS_IMETHODIMP
  1.3266 +jsdService::GetTopLevelHook (jsdICallHook **aHook)
  1.3267 +{   
  1.3268 +    *aHook = mTopLevelHook;
  1.3269 +    NS_IF_ADDREF(*aHook);
  1.3270 +    
  1.3271 +    return NS_OK;
  1.3272 +}
  1.3273 +
  1.3274 +NS_IMETHODIMP
  1.3275 +jsdService::SetFunctionHook (jsdICallHook *aHook)
  1.3276 +{    
  1.3277 +    mFunctionHook = aHook;
  1.3278 +
  1.3279 +    /* if the debugger isn't initialized, that's all we can do for now.  The
  1.3280 +     * ActivateDebugger() method will do the rest when the coast is clear.
  1.3281 +     */
  1.3282 +    if (!mCx || mPauseLevel)
  1.3283 +        return NS_OK;
  1.3284 +
  1.3285 +    if (aHook)
  1.3286 +        JSD_SetFunctionHook (mCx, jsds_CallHookProc, nullptr);
  1.3287 +    else
  1.3288 +        JSD_ClearFunctionHook (mCx);
  1.3289 +    
  1.3290 +    return NS_OK;
  1.3291 +}
  1.3292 +
  1.3293 +NS_IMETHODIMP
  1.3294 +jsdService::GetFunctionHook (jsdICallHook **aHook)
  1.3295 +{   
  1.3296 +    *aHook = mFunctionHook;
  1.3297 +    NS_IF_ADDREF(*aHook);
  1.3298 +    
  1.3299 +    return NS_OK;
  1.3300 +}
  1.3301 +
  1.3302 +/* virtual */
  1.3303 +jsdService::~jsdService()
  1.3304 +{
  1.3305 +    ClearFilters();
  1.3306 +    mErrorHook = nullptr;
  1.3307 +    mBreakpointHook = nullptr;
  1.3308 +    mDebugHook = nullptr;
  1.3309 +    mDebuggerHook = nullptr;
  1.3310 +    mInterruptHook = nullptr;
  1.3311 +    mScriptHook = nullptr;
  1.3312 +    mThrowHook = nullptr;
  1.3313 +    mTopLevelHook = nullptr;
  1.3314 +    mFunctionHook = nullptr;
  1.3315 +    Off();
  1.3316 +    gJsds = nullptr;
  1.3317 +}
  1.3318 +
  1.3319 +jsdService *
  1.3320 +jsdService::GetService ()
  1.3321 +{
  1.3322 +    if (!gJsds)
  1.3323 +        gJsds = new jsdService();
  1.3324 +        
  1.3325 +    NS_IF_ADDREF(gJsds);
  1.3326 +    return gJsds;
  1.3327 +}
  1.3328 +
  1.3329 +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService, jsdService::GetService)
  1.3330 +
  1.3331 +/* app-start observer.  turns on the debugger at app-start.  this is inserted
  1.3332 + * and/or removed from the app-start category by the jsdService::initAtStartup
  1.3333 + * property.
  1.3334 + */
  1.3335 +class jsdASObserver MOZ_FINAL : public nsIObserver
  1.3336 +{
  1.3337 +  public:
  1.3338 +    NS_DECL_THREADSAFE_ISUPPORTS
  1.3339 +    NS_DECL_NSIOBSERVER
  1.3340 +
  1.3341 +    jsdASObserver () {}    
  1.3342 +};
  1.3343 +
  1.3344 +NS_IMPL_ISUPPORTS(jsdASObserver, nsIObserver)
  1.3345 +
  1.3346 +NS_IMETHODIMP
  1.3347 +jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic,
  1.3348 +                        const char16_t *aData)
  1.3349 +{
  1.3350 +    nsresult rv;
  1.3351 +
  1.3352 +    // Hmm.  Why is the app-startup observer called multiple times?
  1.3353 +    //NS_ASSERTION(!gJsds, "app startup observer called twice");
  1.3354 +    nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
  1.3355 +    if (NS_FAILED(rv))
  1.3356 +        return rv;
  1.3357 +
  1.3358 +    bool on;
  1.3359 +    rv = jsds->GetIsOn(&on);
  1.3360 +    if (NS_FAILED(rv) || on)
  1.3361 +        return rv;
  1.3362 +    
  1.3363 +    nsCOMPtr<nsIJSRuntimeService> rts = do_GetService(NS_JSRT_CTRID, &rv);
  1.3364 +    if (NS_FAILED(rv))
  1.3365 +        return rv;    
  1.3366 +
  1.3367 +    JSRuntime *rt;
  1.3368 +    rts->GetRuntime (&rt);
  1.3369 +    if (NS_FAILED(rv))
  1.3370 +        return rv;
  1.3371 +
  1.3372 +    rv = jsds->ActivateDebugger(rt);
  1.3373 +    if (NS_FAILED(rv))
  1.3374 +        return rv;
  1.3375 +    
  1.3376 +    return NS_OK;
  1.3377 +}
  1.3378 +
  1.3379 +NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
  1.3380 +NS_DEFINE_NAMED_CID(JSDSERVICE_CID);
  1.3381 +NS_DEFINE_NAMED_CID(JSDASO_CID);
  1.3382 +
  1.3383 +static const mozilla::Module::CIDEntry kJSDCIDs[] = {
  1.3384 +    { &kJSDSERVICE_CID, false, nullptr, jsdServiceConstructor },
  1.3385 +    { &kJSDASO_CID, false, nullptr, jsdASObserverConstructor },
  1.3386 +    { nullptr }
  1.3387 +};
  1.3388 +
  1.3389 +static const mozilla::Module::ContractIDEntry kJSDContracts[] = {
  1.3390 +    { jsdServiceCtrID, &kJSDSERVICE_CID },
  1.3391 +    { jsdARObserverCtrID, &kJSDASO_CID },
  1.3392 +    { nullptr }
  1.3393 +};
  1.3394 +
  1.3395 +static const mozilla::Module kJSDModule = {
  1.3396 +    mozilla::Module::kVersion,
  1.3397 +    kJSDCIDs,
  1.3398 +    kJSDContracts
  1.3399 +};
  1.3400 +
  1.3401 +NSMODULE_DEFN(JavaScript_Debugger) = &kJSDModule;
  1.3402 +
  1.3403 +void
  1.3404 +global_finalize(JSFreeOp *aFop, JSObject *aObj)
  1.3405 +{
  1.3406 +    nsIScriptObjectPrincipal *sop =
  1.3407 +        static_cast<nsIScriptObjectPrincipal *>(js::GetObjectPrivate(aObj));
  1.3408 +    MOZ_ASSERT(sop);
  1.3409 +    static_cast<SandboxPrivate *>(sop)->ForgetGlobalObject();
  1.3410 +    NS_IF_RELEASE(sop);
  1.3411 +}
  1.3412 +
  1.3413 +JSObject *
  1.3414 +CreateJSDGlobal(JSContext *aCx, const JSClass *aClasp)
  1.3415 +{
  1.3416 +    nsresult rv;
  1.3417 +    nsCOMPtr<nsIPrincipal> nullPrin = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
  1.3418 +    NS_ENSURE_SUCCESS(rv, nullptr);
  1.3419 +
  1.3420 +    JSPrincipals *jsPrin = nsJSPrincipals::get(nullPrin);
  1.3421 +    JS::RootedObject global(aCx, JS_NewGlobalObject(aCx, aClasp, jsPrin, JS::DontFireOnNewGlobalHook));
  1.3422 +    NS_ENSURE_TRUE(global, nullptr);
  1.3423 +
  1.3424 +    // We have created a new global let's attach a private to it
  1.3425 +    // that implements nsIGlobalObject.
  1.3426 +    nsCOMPtr<nsIScriptObjectPrincipal> sbp =
  1.3427 +        new SandboxPrivate(nullPrin, global);
  1.3428 +    JS_SetPrivate(global, sbp.forget().take());
  1.3429 +
  1.3430 +    JS_FireOnNewGlobalObject(aCx, global);
  1.3431 +
  1.3432 +    return global;
  1.3433 +}
  1.3434 +
  1.3435 +/********************************************************************************
  1.3436 + ********************************************************************************
  1.3437 + * graveyard
  1.3438 + */
  1.3439 +
  1.3440 +#if 0
  1.3441 +/* Thread States */
  1.3442 +NS_IMPL_ISUPPORTS(jsdThreadState, jsdIThreadState); 
  1.3443 +
  1.3444 +NS_IMETHODIMP
  1.3445 +jsdThreadState::GetJSDContext(JSDContext **_rval)
  1.3446 +{
  1.3447 +    *_rval = mCx;
  1.3448 +    return NS_OK;
  1.3449 +}
  1.3450 +
  1.3451 +NS_IMETHODIMP
  1.3452 +jsdThreadState::GetJSDThreadState(JSDThreadState **_rval)
  1.3453 +{
  1.3454 +    *_rval = mThreadState;
  1.3455 +    return NS_OK;
  1.3456 +}
  1.3457 +
  1.3458 +NS_IMETHODIMP
  1.3459 +jsdThreadState::GetFrameCount (uint32_t *_rval)
  1.3460 +{
  1.3461 +    *_rval = JSD_GetCountOfStackFrames (mCx, mThreadState);
  1.3462 +    return NS_OK;
  1.3463 +}
  1.3464 +
  1.3465 +NS_IMETHODIMP
  1.3466 +jsdThreadState::GetTopFrame (jsdIStackFrame **_rval)
  1.3467 +{
  1.3468 +    JSDStackFrameInfo *sfi = JSD_GetStackFrame (mCx, mThreadState);
  1.3469 +    
  1.3470 +    *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
  1.3471 +    return NS_OK;
  1.3472 +}
  1.3473 +
  1.3474 +NS_IMETHODIMP
  1.3475 +jsdThreadState::GetPendingException(jsdIValue **_rval)
  1.3476 +{
  1.3477 +    JSDValue *jsdv = JSD_GetException (mCx, mThreadState);
  1.3478 +    
  1.3479 +    *_rval = jsdValue::FromPtr (mCx, jsdv);
  1.3480 +    return NS_OK;
  1.3481 +}
  1.3482 +
  1.3483 +NS_IMETHODIMP
  1.3484 +jsdThreadState::SetPendingException(jsdIValue *aException)
  1.3485 +{
  1.3486 +    JSDValue *jsdv;
  1.3487 +    
  1.3488 +    nsresult rv = aException->GetJSDValue (&jsdv);
  1.3489 +    if (NS_FAILED(rv))
  1.3490 +        return NS_ERROR_FAILURE;
  1.3491 +    
  1.3492 +    if (!JSD_SetException (mCx, mThreadState, jsdv))
  1.3493 +        return NS_ERROR_FAILURE;
  1.3494 +
  1.3495 +    return NS_OK;
  1.3496 +}
  1.3497 +
  1.3498 +#endif

mercurial