~ubuntu-branches/ubuntu/saucy/mozjs17/saucy

« back to all changes in this revision

Viewing changes to js/jsd/jsd_xpc.cpp

  • Committer: Package Import Robot
  • Author(s): Rico Tzschichholz
  • Date: 2013-05-25 12:24:23 UTC
  • Revision ID: package-import@ubuntu.com-20130525122423-zmxucrhtensw90xy
Tags: upstream-17.0.0
ImportĀ upstreamĀ versionĀ 17.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 *
 
3
 * This Source Code Form is subject to the terms of the Mozilla Public
 
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
6
 
 
7
#include "jsdbgapi.h"
 
8
#include "jslock.h"
 
9
#include "jsd_xpc.h"
 
10
 
 
11
#include "nsIXPConnect.h"
 
12
#include "mozilla/ModuleUtils.h"
 
13
#include "nsIServiceManager.h"
 
14
#include "nsIScriptGlobalObject.h"
 
15
#include "nsIObserver.h"
 
16
#include "nsIObserverService.h"
 
17
#include "nsICategoryManager.h"
 
18
#include "nsIJSRuntimeService.h"
 
19
#include "nsIThreadInternal.h"
 
20
#include "nsThreadUtils.h"
 
21
#include "nsMemory.h"
 
22
#include "jsdebug.h"
 
23
#include "nsReadableUtils.h"
 
24
#include "nsCRT.h"
 
25
#include "nsCycleCollectionParticipant.h"
 
26
#include "mozilla/Attributes.h"
 
27
 
 
28
/* XXX DOM dependency */
 
29
#include "nsIScriptContext.h"
 
30
#include "nsIJSContextStack.h"
 
31
 
 
32
/*
 
33
 * defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
 
34
 * script hook.  This was a hack to avoid some js engine problems that should
 
35
 * be fixed now (see Mozilla bug 77636).
 
36
 */
 
37
#undef CAUTIOUS_SCRIPTHOOK
 
38
 
 
39
#ifdef DEBUG_verbose
 
40
#   define DEBUG_COUNT(name, count)                                             \
 
41
        { if ((count % 10) == 0) printf (name ": %i\n", count); }
 
42
#   define DEBUG_CREATE(name, count) {count++; DEBUG_COUNT ("+++++ "name,count)}
 
43
#   define DEBUG_DESTROY(name, count) {count--; DEBUG_COUNT ("----- "name,count)}
 
44
#else
 
45
#   define DEBUG_CREATE(name, count) 
 
46
#   define DEBUG_DESTROY(name, count)
 
47
#endif
 
48
 
 
49
#define ASSERT_VALID_CONTEXT   { if (!mCx) return NS_ERROR_NOT_AVAILABLE; }
 
50
#define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; }
 
51
 
 
52
#define JSDSERVICE_CID                               \
 
53
{ /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */         \
 
54
     0xf1299dc2,                                     \
 
55
     0x1dd1,                                         \
 
56
     0x11b2,                                         \
 
57
    {0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \
 
58
}
 
59
 
 
60
#define JSDASO_CID                                   \
 
61
{ /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */         \
 
62
     0x2fd6b7f6,                                     \
 
63
     0xeb8c,                                         \
 
64
     0x4f32,                                         \
 
65
    {0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \
 
66
}
 
67
 
 
68
#define JSDS_MAJOR_VERSION 1
 
69
#define JSDS_MINOR_VERSION 2
 
70
 
 
71
#define NS_CATMAN_CTRID   "@mozilla.org/categorymanager;1"
 
72
#define NS_JSRT_CTRID     "@mozilla.org/js/xpc/RuntimeService;1"
 
73
 
 
74
#define AUTOREG_CATEGORY  "xpcom-autoregistration"
 
75
#define APPSTART_CATEGORY "app-startup"
 
76
#define JSD_AUTOREG_ENTRY "JSDebugger Startup Observer"
 
77
#define JSD_STARTUP_ENTRY "JSDebugger Startup Observer"
 
78
 
 
79
static void
 
80
jsds_GCSliceCallbackProc (JSRuntime *rt, js::GCProgress progress, const js::GCDescription &desc);
 
81
 
 
82
/*******************************************************************************
 
83
 * global vars
 
84
 ******************************************************************************/
 
85
 
 
86
const char implementationString[] = "Mozilla JavaScript Debugger Service";
 
87
 
 
88
const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
 
89
const char jsdARObserverCtrID[] = "@mozilla.org/js/jsd/app-start-observer;2";
 
90
const char jsdASObserverCtrID[] = "service,@mozilla.org/js/jsd/app-start-observer;2";
 
91
 
 
92
#ifdef DEBUG_verbose
 
93
uint32_t gScriptCount   = 0;
 
94
uint32_t gValueCount    = 0;
 
95
uint32_t gPropertyCount = 0;
 
96
uint32_t gContextCount  = 0;
 
97
uint32_t gFrameCount  = 0;
 
98
#endif
 
99
 
 
100
static jsdService          *gJsds               = 0;
 
101
static js::GCSliceCallback gPrevGCSliceCallback = jsds_GCSliceCallbackProc;
 
102
static bool                gGCRunning           = false;
 
103
 
 
104
static struct DeadScript {
 
105
    PRCList     links;
 
106
    JSDContext *jsdc;
 
107
    jsdIScript *script;
 
108
} *gDeadScripts = nullptr;
 
109
 
 
110
enum PatternType {
 
111
    ptIgnore     = 0U,
 
112
    ptStartsWith = 1U,
 
113
    ptEndsWith   = 2U,
 
114
    ptContains   = 3U,
 
115
    ptEquals     = 4U
 
116
};
 
117
 
 
118
static struct FilterRecord {
 
119
    PRCList      links;
 
120
    jsdIFilter  *filterObject;
 
121
    void        *glob;
 
122
    nsCString    urlPattern;
 
123
    PatternType  patternType;
 
124
    uint32_t     startLine;
 
125
    uint32_t     endLine;
 
126
} *gFilters = nullptr;
 
127
 
 
128
static struct LiveEphemeral *gLiveValues      = nullptr;
 
129
static struct LiveEphemeral *gLiveProperties  = nullptr;
 
130
static struct LiveEphemeral *gLiveContexts    = nullptr;
 
131
static struct LiveEphemeral *gLiveStackFrames = nullptr;
 
132
 
 
133
/*******************************************************************************
 
134
 * utility functions for ephemeral lists
 
135
 *******************************************************************************/
 
136
already_AddRefed<jsdIEphemeral>
 
137
jsds_FindEphemeral (LiveEphemeral **listHead, void *key)
 
138
{
 
139
    if (!*listHead)
 
140
        return nullptr;
 
141
    
 
142
    LiveEphemeral *lv_record = 
 
143
        reinterpret_cast<LiveEphemeral *>
 
144
                        (PR_NEXT_LINK(&(*listHead)->links));
 
145
    do
 
146
    {
 
147
        if (lv_record->key == key)
 
148
        {
 
149
            NS_IF_ADDREF(lv_record->value);
 
150
            return lv_record->value;
 
151
        }
 
152
        lv_record = reinterpret_cast<LiveEphemeral *>
 
153
                                    (PR_NEXT_LINK(&lv_record->links));
 
154
    }
 
155
    while (lv_record != *listHead);
 
156
 
 
157
    return nullptr;
 
158
}
 
159
 
 
160
void
 
161
jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
 
162
{
 
163
    LiveEphemeral *lv_record = 
 
164
        reinterpret_cast<LiveEphemeral *>
 
165
                        (PR_NEXT_LINK(&(*listHead)->links));
 
166
    do
 
167
    {
 
168
        LiveEphemeral *next =
 
169
            reinterpret_cast<LiveEphemeral *>
 
170
                            (PR_NEXT_LINK(&lv_record->links));
 
171
        lv_record->value->Invalidate();
 
172
        lv_record = next;
 
173
    }
 
174
    while (*listHead);
 
175
}
 
176
 
 
177
void
 
178
jsds_InsertEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
 
179
{
 
180
    if (*listHead) {
 
181
        /* if the list exists, add to it */
 
182
        PR_APPEND_LINK(&item->links, &(*listHead)->links);
 
183
    } else {
 
184
        /* otherwise create the list */
 
185
        PR_INIT_CLIST(&item->links);
 
186
        *listHead = item;
 
187
    }
 
188
}
 
189
 
 
190
void
 
191
jsds_RemoveEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
 
192
{
 
193
    LiveEphemeral *next = reinterpret_cast<LiveEphemeral *>
 
194
                                          (PR_NEXT_LINK(&item->links));
 
195
 
 
196
    if (next == item)
 
197
    {
 
198
        /* if the current item is also the next item, we're the only element,
 
199
         * null out the list head */
 
200
        NS_ASSERTION (*listHead == item,
 
201
                      "How could we not be the head of a one item list?");
 
202
        *listHead = nullptr;
 
203
    }
 
204
    else if (item == *listHead)
 
205
    {
 
206
        /* otherwise, if we're currently the list head, change it */
 
207
        *listHead = next;
 
208
    }
 
209
    
 
210
    PR_REMOVE_AND_INIT_LINK(&item->links);
 
211
}
 
212
 
 
213
/*******************************************************************************
 
214
 * utility functions for filters
 
215
 *******************************************************************************/
 
216
void
 
217
jsds_FreeFilter (FilterRecord *rec)
 
218
{
 
219
    NS_IF_RELEASE (rec->filterObject);
 
220
    PR_Free (rec);
 
221
}
 
222
 
 
223
/* copies appropriate |filter| attributes into |rec|.
 
224
 * False return indicates failure, the contents of |rec| will not be changed.
 
225
 */
 
226
bool
 
227
jsds_SyncFilter (FilterRecord *rec, jsdIFilter *filter)
 
228
{
 
229
    NS_ASSERTION (rec, "jsds_SyncFilter without rec");
 
230
    NS_ASSERTION (filter, "jsds_SyncFilter without filter");
 
231
    
 
232
    JSObject *glob_proper = nullptr;
 
233
    nsCOMPtr<nsISupports> glob;
 
234
    nsresult rv = filter->GetGlobalObject(getter_AddRefs(glob));
 
235
    if (NS_FAILED(rv))
 
236
        return false;
 
237
    if (glob) {
 
238
        nsCOMPtr<nsIScriptGlobalObject> nsiglob = do_QueryInterface(glob);
 
239
        if (nsiglob)
 
240
            glob_proper = nsiglob->GetGlobalJSObject();
 
241
    }
 
242
    
 
243
    uint32_t startLine;
 
244
    rv = filter->GetStartLine(&startLine);
 
245
    if (NS_FAILED(rv))
 
246
        return false;
 
247
 
 
248
    uint32_t endLine;
 
249
    rv = filter->GetStartLine(&endLine);
 
250
    if (NS_FAILED(rv))
 
251
        return false;    
 
252
 
 
253
    nsCAutoString urlPattern;
 
254
    rv = filter->GetUrlPattern (urlPattern);
 
255
    if (NS_FAILED(rv))
 
256
        return false;
 
257
    
 
258
    uint32_t len = urlPattern.Length();
 
259
    if (len) {
 
260
        if (urlPattern[0] == '*') {
 
261
            /* pattern starts with a *, shift all chars once to the left,
 
262
             * including the trailing null. */
 
263
            urlPattern = Substring(urlPattern, 1, len);
 
264
 
 
265
            if (urlPattern[len - 2] == '*') {
 
266
                /* pattern is in the format "*foo*", overwrite the final * with
 
267
                 * a null. */
 
268
                urlPattern.Truncate(len - 2);
 
269
                rec->patternType = ptContains;
 
270
            } else {
 
271
                /* pattern is in the format "*foo", just make a note of the
 
272
                 * new length. */
 
273
                rec->patternType = ptEndsWith;
 
274
            }
 
275
        } else if (urlPattern[len - 1] == '*') {
 
276
            /* pattern is in the format "foo*", overwrite the final * with a 
 
277
             * null. */
 
278
            urlPattern.Truncate(len - 1);
 
279
            rec->patternType = ptStartsWith;
 
280
        } else {
 
281
            /* pattern is in the format "foo". */
 
282
            rec->patternType = ptEquals;
 
283
        }
 
284
    } else {
 
285
        rec->patternType = ptIgnore;
 
286
    }
 
287
 
 
288
    /* we got everything we need without failing, now copy it into rec. */
 
289
 
 
290
    if (rec->filterObject != filter) {
 
291
        NS_IF_RELEASE(rec->filterObject);
 
292
        NS_ADDREF(filter);
 
293
        rec->filterObject = filter;
 
294
    }
 
295
    
 
296
    rec->glob = glob_proper;
 
297
    
 
298
    rec->startLine     = startLine;
 
299
    rec->endLine       = endLine;
 
300
    
 
301
    rec->urlPattern = urlPattern;
 
302
 
 
303
    return true;
 
304
            
 
305
}
 
306
 
 
307
FilterRecord *
 
308
jsds_FindFilter (jsdIFilter *filter)
 
309
{
 
310
    if (!gFilters)
 
311
        return nullptr;
 
312
    
 
313
    FilterRecord *current = gFilters;
 
314
    
 
315
    do {
 
316
        if (current->filterObject == filter)
 
317
            return current;
 
318
        current = reinterpret_cast<FilterRecord *>
 
319
                                  (PR_NEXT_LINK(&current->links));
 
320
    } while (current != gFilters);
 
321
    
 
322
    return nullptr;
 
323
}
 
324
 
 
325
/* returns true if the hook should be executed. */
 
326
bool
 
327
jsds_FilterHook (JSDContext *jsdc, JSDThreadState *state)
 
328
{
 
329
    JSContext *cx = JSD_GetJSContext (jsdc, state);
 
330
    void *glob = static_cast<void *>(JS_GetGlobalObject (cx));
 
331
 
 
332
    if (!glob) {
 
333
        NS_WARNING("No global in threadstate");
 
334
        return false;
 
335
    }
 
336
    
 
337
    JSDStackFrameInfo *frame = JSD_GetStackFrame (jsdc, state);
 
338
 
 
339
    if (!frame) {
 
340
        NS_WARNING("No frame in threadstate");
 
341
        return false;
 
342
    }
 
343
 
 
344
    JSDScript *script = JSD_GetScriptForStackFrame (jsdc, state, frame);
 
345
    if (!script)
 
346
        return true;
 
347
 
 
348
    uintptr_t pc = JSD_GetPCForStackFrame (jsdc, state, frame);
 
349
 
 
350
    nsCString url(JSD_GetScriptFilename (jsdc, script));
 
351
    if (url.IsEmpty()) {
 
352
        NS_WARNING ("Script with no filename");
 
353
        return false;
 
354
    }
 
355
 
 
356
    if (!gFilters)
 
357
        return true;    
 
358
 
 
359
    uint32_t currentLine = JSD_GetClosestLine (jsdc, script, pc);
 
360
    uint32_t len = 0;
 
361
    FilterRecord *currentFilter = gFilters;
 
362
    do {
 
363
        uint32_t flags = 0;
 
364
 
 
365
#ifdef DEBUG
 
366
        nsresult rv =
 
367
#endif
 
368
            currentFilter->filterObject->GetFlags(&flags);
 
369
        NS_ASSERTION(NS_SUCCEEDED(rv), "Error getting flags for filter");
 
370
 
 
371
        if (flags & jsdIFilter::FLAG_ENABLED) {
 
372
            /* if there is no glob, or the globs match */
 
373
            if ((!currentFilter->glob || currentFilter->glob == glob) &&
 
374
                /* and there is no start line, or the start line is before 
 
375
                 * or equal to the current */
 
376
                (!currentFilter->startLine || 
 
377
                 currentFilter->startLine <= currentLine) &&
 
378
                /* and there is no end line, or the end line is after
 
379
                 * or equal to the current */
 
380
                (!currentFilter->endLine ||
 
381
                 currentFilter->endLine >= currentLine)) {
 
382
                /* then we're going to have to compare the url. */
 
383
                if (currentFilter->patternType == ptIgnore)
 
384
                    return !!(flags & jsdIFilter::FLAG_PASS);
 
385
 
 
386
                if (!len)
 
387
                    len = url.Length();
 
388
                nsCString urlPattern = currentFilter->urlPattern;
 
389
                uint32_t patternLength = urlPattern.Length();
 
390
                if (len >= patternLength) {
 
391
                    switch (currentFilter->patternType) {
 
392
                        case ptEquals:
 
393
                            if (urlPattern.Equals(url))
 
394
                                return !!(flags & jsdIFilter::FLAG_PASS);
 
395
                            break;
 
396
                        case ptStartsWith:
 
397
                            if (urlPattern.Equals(Substring(url, 0, patternLength)))
 
398
                                return !!(flags & jsdIFilter::FLAG_PASS);
 
399
                            break;
 
400
                        case ptEndsWith:
 
401
                            if (urlPattern.Equals(Substring(url, len - patternLength)))
 
402
                                return !!(flags & jsdIFilter::FLAG_PASS);
 
403
                            break;
 
404
                        case ptContains:
 
405
                            {
 
406
                                nsACString::const_iterator start, end;
 
407
                                url.BeginReading(start);
 
408
                                url.EndReading(end);
 
409
                                if (FindInReadable(currentFilter->urlPattern, start, end))
 
410
                                    return !!(flags & jsdIFilter::FLAG_PASS);
 
411
                            }
 
412
                            break;
 
413
                        default:
 
414
                            NS_ERROR("Invalid pattern type");
 
415
                    }
 
416
                }                
 
417
            }
 
418
        }
 
419
        currentFilter = reinterpret_cast<FilterRecord *>
 
420
                                        (PR_NEXT_LINK(&currentFilter->links));
 
421
    } while (currentFilter != gFilters);
 
422
 
 
423
    return true;
 
424
    
 
425
}
 
426
 
 
427
/*******************************************************************************
 
428
 * c callbacks
 
429
 *******************************************************************************/
 
430
 
 
431
static void
 
432
jsds_NotifyPendingDeadScripts (JSRuntime *rt)
 
433
{
 
434
    jsdService *jsds = gJsds;
 
435
 
 
436
    nsCOMPtr<jsdIScriptHook> hook;
 
437
    if (jsds) {
 
438
        NS_ADDREF(jsds);
 
439
        jsds->GetScriptHook (getter_AddRefs(hook));
 
440
        jsds->DoPause(nullptr, true);
 
441
    }
 
442
 
 
443
    DeadScript *deadScripts = gDeadScripts;
 
444
    gDeadScripts = nullptr;
 
445
    while (deadScripts) {
 
446
        DeadScript *ds = deadScripts;
 
447
        /* get next deleted script */
 
448
        deadScripts = reinterpret_cast<DeadScript *>
 
449
                                       (PR_NEXT_LINK(&ds->links));
 
450
        if (deadScripts == ds)
 
451
            deadScripts = nullptr;
 
452
 
 
453
        if (hook)
 
454
        {
 
455
            /* tell the user this script has been destroyed */
 
456
#ifdef CAUTIOUS_SCRIPTHOOK
 
457
            JS_UNKEEP_ATOMS(rt);
 
458
#endif
 
459
            hook->OnScriptDestroyed (ds->script);
 
460
#ifdef CAUTIOUS_SCRIPTHOOK
 
461
            JS_KEEP_ATOMS(rt);
 
462
#endif
 
463
        }
 
464
 
 
465
        /* take it out of the circular list */
 
466
        PR_REMOVE_LINK(&ds->links);
 
467
 
 
468
        /* addref came from the FromPtr call in jsds_ScriptHookProc */
 
469
        NS_RELEASE(ds->script);
 
470
        /* free the struct! */
 
471
        PR_Free(ds);
 
472
    }
 
473
 
 
474
    if (jsds) {
 
475
        jsds->DoUnPause(nullptr, true);
 
476
        NS_RELEASE(jsds);
 
477
    }
 
478
}
 
479
 
 
480
static void
 
481
jsds_GCSliceCallbackProc (JSRuntime *rt, js::GCProgress progress, const js::GCDescription &desc)
 
482
{
 
483
    if (progress == js::GC_CYCLE_END || progress == js::GC_SLICE_END) {
 
484
        NS_ASSERTION(gGCRunning, "GC slice callback was missed");
 
485
 
 
486
        while (gDeadScripts)
 
487
            jsds_NotifyPendingDeadScripts (rt);
 
488
 
 
489
        gGCRunning = false;
 
490
    } else {
 
491
        NS_ASSERTION(!gGCRunning, "should not re-enter GC");
 
492
        gGCRunning = true;
 
493
    }
 
494
 
 
495
    if (gPrevGCSliceCallback)
 
496
        (*gPrevGCSliceCallback)(rt, progress, desc);
 
497
}
 
498
 
 
499
static unsigned
 
500
jsds_ErrorHookProc (JSDContext *jsdc, JSContext *cx, const char *message,
 
501
                    JSErrorReport *report, void *callerdata)
 
502
{
 
503
    static bool running = false;
 
504
 
 
505
    nsCOMPtr<jsdIErrorHook> hook;
 
506
    gJsds->GetErrorHook(getter_AddRefs(hook));
 
507
    if (!hook)
 
508
        return JSD_ERROR_REPORTER_PASS_ALONG;
 
509
 
 
510
    if (running)
 
511
        return JSD_ERROR_REPORTER_PASS_ALONG;
 
512
    
 
513
    running = true;
 
514
    
 
515
    nsCOMPtr<jsdIValue> val;
 
516
    if (JS_IsExceptionPending(cx)) {
 
517
        jsval jv;
 
518
        JS_GetPendingException(cx, &jv);
 
519
        JSDValue *jsdv = JSD_NewValue (jsdc, jv);
 
520
        val = getter_AddRefs(jsdValue::FromPtr(jsdc, jsdv));
 
521
    }
 
522
    
 
523
    nsCAutoString fileName;
 
524
    uint32_t    line;
 
525
    uint32_t    pos;
 
526
    uint32_t    flags;
 
527
    uint32_t    errnum;
 
528
    bool        rval;
 
529
    if (report) {
 
530
        fileName.Assign(report->filename);
 
531
        line = report->lineno;
 
532
        pos = report->tokenptr - report->linebuf;
 
533
        flags = report->flags;
 
534
        errnum = report->errorNumber;
 
535
    }
 
536
    else
 
537
    {
 
538
        line     = 0;
 
539
        pos      = 0;
 
540
        flags    = 0;
 
541
        errnum   = 0;
 
542
    }
 
543
    
 
544
    gJsds->DoPause(nullptr, true);
 
545
    hook->OnError (nsDependentCString(message), fileName, line, pos, flags, errnum, val, &rval);
 
546
    gJsds->DoUnPause(nullptr, true);
 
547
    
 
548
    running = false;
 
549
    if (!rval)
 
550
        return JSD_ERROR_REPORTER_DEBUG;
 
551
    
 
552
    return JSD_ERROR_REPORTER_PASS_ALONG;
 
553
}
 
554
 
 
555
static JSBool
 
556
jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
 
557
                   unsigned type, void* callerdata)
 
558
{
 
559
    nsCOMPtr<jsdICallHook> hook;
 
560
 
 
561
    switch (type)
 
562
    {
 
563
        case JSD_HOOK_TOPLEVEL_START:
 
564
        case JSD_HOOK_TOPLEVEL_END:
 
565
            gJsds->GetTopLevelHook(getter_AddRefs(hook));
 
566
            break;
 
567
            
 
568
        case JSD_HOOK_FUNCTION_CALL:
 
569
        case JSD_HOOK_FUNCTION_RETURN:
 
570
            gJsds->GetFunctionHook(getter_AddRefs(hook));
 
571
            break;
 
572
 
 
573
        default:
 
574
            NS_ASSERTION (0, "Unknown hook type.");
 
575
    }
 
576
    
 
577
    if (!hook)
 
578
        return JS_TRUE;
 
579
 
 
580
    if (!jsds_FilterHook (jsdc, jsdthreadstate))
 
581
        return JS_FALSE;
 
582
 
 
583
    JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
 
584
    nsCOMPtr<jsdIStackFrame> frame =
 
585
        getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
 
586
                                              native_frame));
 
587
    gJsds->DoPause(nullptr, true);
 
588
    hook->OnCall(frame, type);    
 
589
    gJsds->DoUnPause(nullptr, true);
 
590
    jsdStackFrame::InvalidateAll();
 
591
 
 
592
    return JS_TRUE;
 
593
}
 
594
 
 
595
static uint32_t
 
596
jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
 
597
                        unsigned type, void* callerdata, jsval* rval)
 
598
{
 
599
    nsCOMPtr<jsdIExecutionHook> hook(0);
 
600
    uint32_t hook_rv = JSD_HOOK_RETURN_CONTINUE;
 
601
    nsCOMPtr<jsdIValue> js_rv;
 
602
 
 
603
    switch (type)
 
604
    {
 
605
        case JSD_HOOK_INTERRUPTED:
 
606
            gJsds->GetInterruptHook(getter_AddRefs(hook));
 
607
            break;
 
608
        case JSD_HOOK_DEBUG_REQUESTED:
 
609
            gJsds->GetDebugHook(getter_AddRefs(hook));
 
610
            break;
 
611
        case JSD_HOOK_DEBUGGER_KEYWORD:
 
612
            gJsds->GetDebuggerHook(getter_AddRefs(hook));
 
613
            break;
 
614
        case JSD_HOOK_BREAKPOINT:
 
615
            {
 
616
                /* we can't pause breakpoints the way we pause the other
 
617
                 * execution hooks (at least, not easily.)  Instead we bail
 
618
                 * here if the service is paused. */
 
619
                uint32_t level;
 
620
                gJsds->GetPauseDepth(&level);
 
621
                if (!level)
 
622
                    gJsds->GetBreakpointHook(getter_AddRefs(hook));
 
623
            }
 
624
            break;
 
625
        case JSD_HOOK_THROW:
 
626
        {
 
627
            hook_rv = JSD_HOOK_RETURN_CONTINUE_THROW;
 
628
            gJsds->GetThrowHook(getter_AddRefs(hook));
 
629
            if (hook) {
 
630
                JSDValue *jsdv = JSD_GetException (jsdc, jsdthreadstate);
 
631
                js_rv = getter_AddRefs(jsdValue::FromPtr (jsdc, jsdv));
 
632
            }
 
633
            break;
 
634
        }
 
635
        default:
 
636
            NS_ASSERTION (0, "Unknown hook type.");
 
637
    }
 
638
 
 
639
    if (!hook)
 
640
        return hook_rv;
 
641
    
 
642
    if (!jsds_FilterHook (jsdc, jsdthreadstate))
 
643
        return JSD_HOOK_RETURN_CONTINUE;
 
644
    
 
645
    JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
 
646
    nsCOMPtr<jsdIStackFrame> frame =
 
647
        getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
 
648
                                              native_frame));
 
649
    gJsds->DoPause(nullptr, true);
 
650
    jsdIValue *inout_rv = js_rv;
 
651
    NS_IF_ADDREF(inout_rv);
 
652
    hook->OnExecute (frame, type, &inout_rv, &hook_rv);
 
653
    js_rv = inout_rv;
 
654
    NS_IF_RELEASE(inout_rv);
 
655
    gJsds->DoUnPause(nullptr, true);
 
656
    jsdStackFrame::InvalidateAll();
 
657
        
 
658
    if (hook_rv == JSD_HOOK_RETURN_RET_WITH_VAL ||
 
659
        hook_rv == JSD_HOOK_RETURN_THROW_WITH_VAL) {
 
660
        *rval = JSVAL_VOID;
 
661
        if (js_rv) {
 
662
            JSDValue *jsdv;
 
663
            if (NS_SUCCEEDED(js_rv->GetJSDValue (&jsdv)))
 
664
                *rval = JSD_GetValueWrappedJSVal(jsdc, jsdv);
 
665
        }
 
666
    }
 
667
    
 
668
    return hook_rv;
 
669
}
 
670
 
 
671
static void
 
672
jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating,
 
673
                     void* callerdata)
 
674
{
 
675
#ifdef CAUTIOUS_SCRIPTHOOK
 
676
    JSContext *cx = JSD_GetDefaultJSContext(jsdc);
 
677
    JSRuntime *rt = JS_GetRuntime(cx);
 
678
#endif
 
679
 
 
680
    if (creating) {
 
681
        nsCOMPtr<jsdIScriptHook> hook;
 
682
        gJsds->GetScriptHook(getter_AddRefs(hook));
 
683
 
 
684
        /* a script is being created */
 
685
        if (!hook) {
 
686
            /* nobody cares, just exit */
 
687
            return;
 
688
        }
 
689
            
 
690
        nsCOMPtr<jsdIScript> script = 
 
691
            getter_AddRefs(jsdScript::FromPtr(jsdc, jsdscript));
 
692
#ifdef CAUTIOUS_SCRIPTHOOK
 
693
        JS_UNKEEP_ATOMS(rt);
 
694
#endif
 
695
        gJsds->DoPause(nullptr, true);
 
696
        hook->OnScriptCreated (script);
 
697
        gJsds->DoUnPause(nullptr, true);
 
698
#ifdef CAUTIOUS_SCRIPTHOOK
 
699
        JS_KEEP_ATOMS(rt);
 
700
#endif
 
701
    } else {
 
702
        /* a script is being destroyed.  even if there is no registered hook
 
703
         * we'll still need to invalidate the jsdIScript record, in order
 
704
         * to remove the reference held in the JSDScript private data. */
 
705
        nsCOMPtr<jsdIScript> jsdis = 
 
706
            static_cast<jsdIScript *>(JSD_GetScriptPrivate(jsdscript));
 
707
        if (!jsdis)
 
708
            return;
 
709
 
 
710
        jsdis->Invalidate();
 
711
 
 
712
        if (!gGCRunning) {
 
713
            nsCOMPtr<jsdIScriptHook> hook;
 
714
            gJsds->GetScriptHook(getter_AddRefs(hook));
 
715
            if (!hook)
 
716
                return;
 
717
 
 
718
            /* if GC *isn't* running, we can tell the user about the script
 
719
             * delete now. */
 
720
#ifdef CAUTIOUS_SCRIPTHOOK
 
721
            JS_UNKEEP_ATOMS(rt);
 
722
#endif
 
723
                
 
724
            gJsds->DoPause(nullptr, true);
 
725
            hook->OnScriptDestroyed (jsdis);
 
726
            gJsds->DoUnPause(nullptr, true);
 
727
#ifdef CAUTIOUS_SCRIPTHOOK
 
728
            JS_KEEP_ATOMS(rt);
 
729
#endif
 
730
        } else {
 
731
            /* if a GC *is* running, we've got to wait until it's done before
 
732
             * we can execute any JS, so we queue the notification in a PRCList
 
733
             * until GC tells us it's done. See jsds_GCCallbackProc(). */
 
734
            DeadScript *ds = PR_NEW(DeadScript);
 
735
            if (!ds)
 
736
                return; /* NS_ERROR_OUT_OF_MEMORY */
 
737
        
 
738
            ds->jsdc = jsdc;
 
739
            ds->script = jsdis;
 
740
            NS_ADDREF(ds->script);
 
741
            if (gDeadScripts)
 
742
                /* if the queue exists, add to it */
 
743
                PR_APPEND_LINK(&ds->links, &gDeadScripts->links);
 
744
            else {
 
745
                /* otherwise create the queue */
 
746
                PR_INIT_CLIST(&ds->links);
 
747
                gDeadScripts = ds;
 
748
            }
 
749
        }
 
750
    }            
 
751
}
 
752
 
 
753
/*******************************************************************************
 
754
 * reflected jsd data structures
 
755
 *******************************************************************************/
 
756
 
 
757
/* Contexts */
 
758
/*
 
759
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral);
 
760
 
 
761
NS_IMETHODIMP
 
762
jsdContext::GetJSDContext(JSDContext **_rval)
 
763
{
 
764
    *_rval = mCx;
 
765
    return NS_OK;
 
766
}
 
767
*/
 
768
 
 
769
/* Objects */
 
770
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject, jsdIObject)
 
771
 
 
772
NS_IMETHODIMP
 
773
jsdObject::GetJSDContext(JSDContext **_rval)
 
774
{
 
775
    *_rval = mCx;
 
776
    return NS_OK;
 
777
}
 
778
 
 
779
NS_IMETHODIMP
 
780
jsdObject::GetJSDObject(JSDObject **_rval)
 
781
{
 
782
    *_rval = mObject;
 
783
    return NS_OK;
 
784
}
 
785
 
 
786
NS_IMETHODIMP
 
787
jsdObject::GetCreatorURL(nsACString &_rval)
 
788
{
 
789
    _rval.Assign(JSD_GetObjectNewURL(mCx, mObject));
 
790
    return NS_OK;
 
791
}
 
792
 
 
793
NS_IMETHODIMP
 
794
jsdObject::GetCreatorLine(uint32_t *_rval)
 
795
{
 
796
    *_rval = JSD_GetObjectNewLineNumber(mCx, mObject);
 
797
    return NS_OK;
 
798
}
 
799
 
 
800
NS_IMETHODIMP
 
801
jsdObject::GetConstructorURL(nsACString &_rval)
 
802
{
 
803
    _rval.Assign(JSD_GetObjectConstructorURL(mCx, mObject));
 
804
    return NS_OK;
 
805
}
 
806
 
 
807
NS_IMETHODIMP
 
808
jsdObject::GetConstructorLine(uint32_t *_rval)
 
809
{
 
810
    *_rval = JSD_GetObjectConstructorLineNumber(mCx, mObject);
 
811
    return NS_OK;
 
812
}
 
813
 
 
814
NS_IMETHODIMP
 
815
jsdObject::GetValue(jsdIValue **_rval)
 
816
{
 
817
    JSDValue *jsdv = JSD_GetValueForObject (mCx, mObject);
 
818
    
 
819
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
820
    return NS_OK;
 
821
}
 
822
 
 
823
/* Properties */
 
824
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty, jsdIProperty, jsdIEphemeral)
 
825
 
 
826
jsdProperty::jsdProperty (JSDContext *aCx, JSDProperty *aProperty) :
 
827
    mCx(aCx), mProperty(aProperty)
 
828
{
 
829
    DEBUG_CREATE ("jsdProperty", gPropertyCount);
 
830
    mValid = (aCx && aProperty);
 
831
    mLiveListEntry.value = this;
 
832
    jsds_InsertEphemeral (&gLiveProperties, &mLiveListEntry);
 
833
}
 
834
 
 
835
jsdProperty::~jsdProperty () 
 
836
{
 
837
    DEBUG_DESTROY ("jsdProperty", gPropertyCount);
 
838
    if (mValid)
 
839
        Invalidate();
 
840
}
 
841
 
 
842
NS_IMETHODIMP
 
843
jsdProperty::Invalidate()
 
844
{
 
845
    ASSERT_VALID_EPHEMERAL;
 
846
    mValid = false;
 
847
    jsds_RemoveEphemeral (&gLiveProperties, &mLiveListEntry);
 
848
    JSD_DropProperty (mCx, mProperty);
 
849
    return NS_OK;
 
850
}
 
851
 
 
852
void
 
853
jsdProperty::InvalidateAll()
 
854
{
 
855
    if (gLiveProperties)
 
856
        jsds_InvalidateAllEphemerals (&gLiveProperties);
 
857
}
 
858
 
 
859
NS_IMETHODIMP
 
860
jsdProperty::GetJSDContext(JSDContext **_rval)
 
861
{
 
862
    *_rval = mCx;
 
863
    return NS_OK;
 
864
}
 
865
 
 
866
NS_IMETHODIMP
 
867
jsdProperty::GetJSDProperty(JSDProperty **_rval)
 
868
{
 
869
    *_rval = mProperty;
 
870
    return NS_OK;
 
871
}
 
872
 
 
873
NS_IMETHODIMP
 
874
jsdProperty::GetIsValid(bool *_rval)
 
875
{
 
876
    *_rval = mValid;
 
877
    return NS_OK;
 
878
}
 
879
 
 
880
NS_IMETHODIMP
 
881
jsdProperty::GetAlias(jsdIValue **_rval)
 
882
{
 
883
    JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
 
884
    
 
885
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
886
    return NS_OK;
 
887
}
 
888
 
 
889
NS_IMETHODIMP
 
890
jsdProperty::GetFlags(uint32_t *_rval)
 
891
{
 
892
    *_rval = JSD_GetPropertyFlags (mCx, mProperty);
 
893
    return NS_OK;
 
894
}
 
895
 
 
896
NS_IMETHODIMP
 
897
jsdProperty::GetName(jsdIValue **_rval)
 
898
{
 
899
    JSDValue *jsdv = JSD_GetPropertyName (mCx, mProperty);
 
900
    
 
901
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
902
    return NS_OK;
 
903
}
 
904
 
 
905
NS_IMETHODIMP
 
906
jsdProperty::GetValue(jsdIValue **_rval)
 
907
{
 
908
    JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
 
909
    
 
910
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
911
    return NS_OK;
 
912
}
 
913
 
 
914
/* Scripts */
 
915
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
 
916
 
 
917
static NS_IMETHODIMP
 
918
AssignToJSString(nsACString *x, JSString *str)
 
919
{
 
920
    if (!str) {
 
921
        x->SetLength(0);
 
922
        return NS_OK;
 
923
    }
 
924
    size_t length = JS_GetStringEncodingLength(NULL, str);
 
925
    if (length == size_t(-1))
 
926
        return NS_ERROR_FAILURE;
 
927
    x->SetLength(uint32_t(length));
 
928
    if (x->Length() != uint32_t(length))
 
929
        return NS_ERROR_OUT_OF_MEMORY;
 
930
    JS_EncodeStringToBuffer(str, x->BeginWriting(), length);
 
931
    return NS_OK;
 
932
}
 
933
 
 
934
jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(false),
 
935
                                                             mTag(0),
 
936
                                                             mCx(aCx),
 
937
                                                             mScript(aScript),
 
938
                                                             mFileName(0), 
 
939
                                                             mFunctionName(0),
 
940
                                                             mBaseLineNumber(0),
 
941
                                                             mLineExtent(0),
 
942
                                                             mPPLineMap(0),
 
943
                                                             mFirstPC(0)
 
944
{
 
945
    DEBUG_CREATE ("jsdScript", gScriptCount);
 
946
 
 
947
    if (mScript) {
 
948
        /* copy the script's information now, so we have it later, when it
 
949
         * gets destroyed. */
 
950
        JSD_LockScriptSubsystem(mCx);
 
951
        mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
 
952
        mFunctionName = new nsCString();
 
953
        if (mFunctionName) {
 
954
            JSString *str = JSD_GetScriptFunctionId(mCx, mScript);
 
955
            if (str)
 
956
                AssignToJSString(mFunctionName, str);
 
957
        }
 
958
        mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
 
959
        mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
 
960
        mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
 
961
        JSD_UnlockScriptSubsystem(mCx);
 
962
        
 
963
        mValid = true;
 
964
    }
 
965
}
 
966
 
 
967
jsdScript::~jsdScript () 
 
968
{
 
969
    DEBUG_DESTROY ("jsdScript", gScriptCount);
 
970
    delete mFileName;
 
971
    delete mFunctionName;
 
972
 
 
973
    if (mPPLineMap)
 
974
        PR_Free(mPPLineMap);
 
975
 
 
976
    /* Invalidate() needs to be called to release an owning reference to
 
977
     * ourselves, so if we got here without being invalidated, something
 
978
     * has gone wrong with our ref count. */
 
979
    NS_ASSERTION (!mValid, "Script destroyed without being invalidated.");
 
980
}
 
981
 
 
982
/*
 
983
 * This method populates a line <-> pc map for a pretty printed version of this
 
984
 * script.  It does this by decompiling, and then recompiling the script.  The
 
985
 * resulting script is scanned for the line map, and then left as GC fodder.
 
986
 */
 
987
PCMapEntry *
 
988
jsdScript::CreatePPLineMap()
 
989
{    
 
990
    JSContext  *cx  = JSD_GetDefaultJSContext (mCx);
 
991
    JSAutoRequest ar(cx);
 
992
    JSObject   *obj = JS_NewObject(cx, NULL, NULL, NULL);
 
993
    JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
 
994
    JSScript   *script; /* In JSD compartment */
 
995
    uint32_t    baseLine;
 
996
    JSString   *jsstr;
 
997
    size_t      length;
 
998
    const jschar *chars;
 
999
    
 
1000
    if (fun) {
 
1001
        unsigned nargs;
 
1002
 
 
1003
        {
 
1004
            JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
 
1005
            nargs = JS_GetFunctionArgumentCount(cx, fun);
 
1006
            if (nargs > 12)
 
1007
                return nullptr;
 
1008
            jsstr = JS_DecompileFunctionBody (cx, fun, 4);
 
1009
            if (!jsstr)
 
1010
                return nullptr;
 
1011
 
 
1012
            if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
 
1013
                return nullptr;
 
1014
        }
 
1015
 
 
1016
        JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
 
1017
        const char *argnames[] = {"arg1", "arg2", "arg3", "arg4", 
 
1018
                                  "arg5", "arg6", "arg7", "arg8",
 
1019
                                  "arg9", "arg10", "arg11", "arg12" };
 
1020
        fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
 
1021
                                    length, "x-jsd:ppbuffer?type=function", 3);
 
1022
        if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
 
1023
            return nullptr;
 
1024
        baseLine = 3;
 
1025
    } else {
 
1026
        script = JSD_GetJSScript(mCx, mScript);
 
1027
        JSString *jsstr;
 
1028
 
 
1029
        {
 
1030
            JS::AutoEnterScriptCompartment ac;
 
1031
            if (!ac.enter(cx, script))
 
1032
                return nullptr;
 
1033
 
 
1034
            jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
 
1035
            if (!jsstr)
 
1036
                return nullptr;
 
1037
 
 
1038
            if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
 
1039
                return nullptr;
 
1040
        }
 
1041
 
 
1042
        JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
 
1043
        script = JS_CompileUCScript (cx, obj, chars, length, "x-jsd:ppbuffer?type=script", 1);
 
1044
        if (!script)
 
1045
            return nullptr;
 
1046
        baseLine = 1;
 
1047
    }
 
1048
 
 
1049
    uint32_t scriptExtent = JS_GetScriptLineExtent (cx, script);
 
1050
    jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0);
 
1051
    /* allocate worst case size of map (number of lines in script + 1
 
1052
     * for our 0 record), we'll shrink it with a realloc later. */
 
1053
    PCMapEntry *lineMap =
 
1054
        static_cast<PCMapEntry *>
 
1055
                   (PR_Malloc((scriptExtent + 1) * sizeof (PCMapEntry)));
 
1056
    uint32_t lineMapSize = 0;
 
1057
 
 
1058
    if (lineMap) {
 
1059
        for (uint32_t line = baseLine; line < scriptExtent + baseLine; ++line) {
 
1060
            jsbytecode* pc = JS_LineNumberToPC (cx, script, line);
 
1061
            if (line == JS_PCToLineNumber (cx, script, pc)) {
 
1062
                lineMap[lineMapSize].line = line;
 
1063
                lineMap[lineMapSize].pc = pc - firstPC;
 
1064
                ++lineMapSize;
 
1065
            }
 
1066
        }
 
1067
        if (scriptExtent != lineMapSize) {
 
1068
            lineMap =
 
1069
                static_cast<PCMapEntry *>
 
1070
                           (PR_Realloc(mPPLineMap = lineMap,
 
1071
                                       lineMapSize * sizeof(PCMapEntry)));
 
1072
            if (!lineMap) {
 
1073
                PR_Free(mPPLineMap);
 
1074
                lineMapSize = 0;
 
1075
            }
 
1076
        }
 
1077
    }
 
1078
 
 
1079
    mPCMapSize = lineMapSize;
 
1080
    return mPPLineMap = lineMap;
 
1081
}
 
1082
 
 
1083
uint32_t
 
1084
jsdScript::PPPcToLine (uint32_t aPC)
 
1085
{
 
1086
    if (!mPPLineMap && !CreatePPLineMap())
 
1087
        return 0;
 
1088
    uint32_t i;
 
1089
    for (i = 1; i < mPCMapSize; ++i) {
 
1090
        if (mPPLineMap[i].pc > aPC)
 
1091
            return mPPLineMap[i - 1].line;            
 
1092
    }
 
1093
 
 
1094
    return mPPLineMap[mPCMapSize - 1].line;
 
1095
}
 
1096
 
 
1097
uint32_t
 
1098
jsdScript::PPLineToPc (uint32_t aLine)
 
1099
{
 
1100
    if (!mPPLineMap && !CreatePPLineMap())
 
1101
        return 0;
 
1102
    uint32_t i;
 
1103
    for (i = 1; i < mPCMapSize; ++i) {
 
1104
        if (mPPLineMap[i].line > aLine)
 
1105
            return mPPLineMap[i - 1].pc;
 
1106
    }
 
1107
 
 
1108
    return mPPLineMap[mPCMapSize - 1].pc;
 
1109
}
 
1110
 
 
1111
NS_IMETHODIMP
 
1112
jsdScript::GetJSDContext(JSDContext **_rval)
 
1113
{
 
1114
    ASSERT_VALID_EPHEMERAL;
 
1115
    *_rval = mCx;
 
1116
    return NS_OK;
 
1117
}
 
1118
 
 
1119
NS_IMETHODIMP
 
1120
jsdScript::GetJSDScript(JSDScript **_rval)
 
1121
{
 
1122
    ASSERT_VALID_EPHEMERAL;
 
1123
    *_rval = mScript;
 
1124
    return NS_OK;
 
1125
}
 
1126
 
 
1127
NS_IMETHODIMP
 
1128
jsdScript::GetVersion (int32_t *_rval)
 
1129
{
 
1130
    ASSERT_VALID_EPHEMERAL;
 
1131
    JSContext *cx = JSD_GetDefaultJSContext (mCx);
 
1132
    JSScript *script = JSD_GetJSScript(mCx, mScript);
 
1133
    JS::AutoEnterScriptCompartment ac;
 
1134
    if (!ac.enter(cx, script))
 
1135
        return NS_ERROR_FAILURE;
 
1136
    *_rval = static_cast<int32_t>(JS_GetScriptVersion(cx, script));
 
1137
    return NS_OK;
 
1138
}
 
1139
 
 
1140
NS_IMETHODIMP
 
1141
jsdScript::GetTag(uint32_t *_rval)
 
1142
{
 
1143
    if (!mTag)
 
1144
        mTag = ++jsdScript::LastTag;
 
1145
    
 
1146
    *_rval = mTag;
 
1147
    return NS_OK;
 
1148
}
 
1149
 
 
1150
NS_IMETHODIMP
 
1151
jsdScript::Invalidate()
 
1152
{
 
1153
    ASSERT_VALID_EPHEMERAL;
 
1154
    mValid = false;
 
1155
    
 
1156
    /* release the addref we do in FromPtr */
 
1157
    jsdIScript *script = static_cast<jsdIScript *>
 
1158
                                    (JSD_GetScriptPrivate(mScript));
 
1159
    NS_ASSERTION (script == this, "That's not my script!");
 
1160
    NS_RELEASE(script);
 
1161
    JSD_SetScriptPrivate(mScript, NULL);
 
1162
    return NS_OK;
 
1163
}
 
1164
 
 
1165
void
 
1166
jsdScript::InvalidateAll ()
 
1167
{
 
1168
    JSDContext *cx;
 
1169
    if (NS_FAILED(gJsds->GetJSDContext (&cx)))
 
1170
        return;
 
1171
 
 
1172
    JSDScript *script;
 
1173
    JSDScript *iter = NULL;
 
1174
    
 
1175
    JSD_LockScriptSubsystem(cx);
 
1176
    while((script = JSD_IterateScripts(cx, &iter)) != NULL) {
 
1177
        nsCOMPtr<jsdIScript> jsdis = 
 
1178
            static_cast<jsdIScript *>(JSD_GetScriptPrivate(script));
 
1179
        if (jsdis)
 
1180
            jsdis->Invalidate();
 
1181
    }
 
1182
    JSD_UnlockScriptSubsystem(cx);
 
1183
}
 
1184
 
 
1185
NS_IMETHODIMP
 
1186
jsdScript::GetIsValid(bool *_rval)
 
1187
{
 
1188
    *_rval = mValid;
 
1189
    return NS_OK;
 
1190
}
 
1191
 
 
1192
NS_IMETHODIMP
 
1193
jsdScript::SetFlags(uint32_t flags)
 
1194
{
 
1195
    ASSERT_VALID_EPHEMERAL;
 
1196
    JSD_SetScriptFlags(mCx, mScript, flags);
 
1197
    return NS_OK;
 
1198
}
 
1199
 
 
1200
NS_IMETHODIMP
 
1201
jsdScript::GetFlags(uint32_t *_rval)
 
1202
{
 
1203
    ASSERT_VALID_EPHEMERAL;
 
1204
    *_rval = JSD_GetScriptFlags(mCx, mScript);
 
1205
    return NS_OK;
 
1206
}
 
1207
 
 
1208
NS_IMETHODIMP
 
1209
jsdScript::GetFileName(nsACString &_rval)
 
1210
{
 
1211
    _rval.Assign(*mFileName);
 
1212
    return NS_OK;
 
1213
}
 
1214
 
 
1215
NS_IMETHODIMP
 
1216
jsdScript::GetFunctionName(nsACString &_rval)
 
1217
{
 
1218
    _rval.Assign(*mFunctionName);
 
1219
    return NS_OK;
 
1220
}
 
1221
 
 
1222
NS_IMETHODIMP
 
1223
jsdScript::GetParameterNames(uint32_t* count, PRUnichar*** paramNames)
 
1224
{
 
1225
    ASSERT_VALID_EPHEMERAL;
 
1226
    JSContext *cx = JSD_GetDefaultJSContext (mCx);
 
1227
    if (!cx) {
 
1228
        NS_WARNING("No default context !?");
 
1229
        return NS_ERROR_FAILURE;
 
1230
    }
 
1231
    JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
 
1232
    if (!fun) {
 
1233
        *count = 0;
 
1234
        *paramNames = nullptr;
 
1235
        return NS_OK;
 
1236
    }
 
1237
 
 
1238
    JSAutoRequest ar(cx);
 
1239
    JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
 
1240
 
 
1241
    unsigned nargs;
 
1242
    if (!JS_FunctionHasLocalNames(cx, fun) ||
 
1243
        (nargs = JS_GetFunctionArgumentCount(cx, fun)) == 0) {
 
1244
        *count = 0;
 
1245
        *paramNames = nullptr;
 
1246
        return NS_OK;
 
1247
    }
 
1248
 
 
1249
    PRUnichar **ret =
 
1250
        static_cast<PRUnichar**>(NS_Alloc(nargs * sizeof(PRUnichar*)));
 
1251
    if (!ret)
 
1252
        return NS_ERROR_OUT_OF_MEMORY;
 
1253
 
 
1254
    void *mark;
 
1255
    uintptr_t *names = JS_GetFunctionLocalNameArray(cx, fun, &mark);
 
1256
    if (!names) {
 
1257
        NS_Free(ret);
 
1258
        return NS_ERROR_OUT_OF_MEMORY;
 
1259
    }
 
1260
 
 
1261
    nsresult rv = NS_OK;
 
1262
    for (unsigned i = 0; i < nargs; ++i) {
 
1263
        JSAtom *atom = JS_LocalNameToAtom(names[i]);
 
1264
        if (!atom) {
 
1265
            ret[i] = 0;
 
1266
        } else {
 
1267
            JSString *str = JS_AtomKey(atom);
 
1268
            ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str));
 
1269
            if (!ret[i]) {
 
1270
                NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
 
1271
                rv = NS_ERROR_OUT_OF_MEMORY;
 
1272
                break;
 
1273
            }
 
1274
        }
 
1275
    }
 
1276
    JS_ReleaseFunctionLocalNameArray(cx, mark);
 
1277
    if (NS_FAILED(rv))
 
1278
        return rv;
 
1279
    *count = nargs;
 
1280
    *paramNames = ret;
 
1281
    return NS_OK;
 
1282
}
 
1283
 
 
1284
NS_IMETHODIMP
 
1285
jsdScript::GetFunctionObject(jsdIValue **_rval)
 
1286
{
 
1287
    JSFunction *fun = JSD_GetJSFunction(mCx, mScript);
 
1288
    if (!fun)
 
1289
        return NS_ERROR_NOT_AVAILABLE;
 
1290
    
 
1291
    JSObject *obj = JS_GetFunctionObject(fun);
 
1292
    if (!obj)
 
1293
        return NS_ERROR_FAILURE;
 
1294
 
 
1295
    JSDContext *cx;
 
1296
    if (NS_FAILED(gJsds->GetJSDContext (&cx)))
 
1297
        return NS_ERROR_NOT_INITIALIZED;
 
1298
 
 
1299
    JSDValue *jsdv = JSD_NewValue(cx, OBJECT_TO_JSVAL(obj));
 
1300
    if (!jsdv)
 
1301
        return NS_ERROR_OUT_OF_MEMORY;
 
1302
 
 
1303
    *_rval = jsdValue::FromPtr(cx, jsdv);
 
1304
    if (!*_rval) {
 
1305
        JSD_DropValue(cx, jsdv);
 
1306
        return NS_ERROR_OUT_OF_MEMORY;
 
1307
    }
 
1308
 
 
1309
    return NS_OK;
 
1310
}
 
1311
 
 
1312
NS_IMETHODIMP
 
1313
jsdScript::GetFunctionSource(nsAString & aFunctionSource)
 
1314
{
 
1315
    ASSERT_VALID_EPHEMERAL;
 
1316
    JSContext *cx = JSD_GetDefaultJSContext (mCx);
 
1317
    if (!cx) {
 
1318
        NS_WARNING("No default context !?");
 
1319
        return NS_ERROR_FAILURE;
 
1320
    }
 
1321
    JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
 
1322
 
 
1323
    JSAutoRequest ar(cx);
 
1324
 
 
1325
    JSString *jsstr;
 
1326
    mozilla::Maybe<JSAutoCompartment> ac;
 
1327
    JS::AutoEnterScriptCompartment asc;
 
1328
    if (fun) {
 
1329
        ac.construct(cx, JS_GetFunctionObject(fun));
 
1330
        jsstr = JS_DecompileFunction (cx, fun, 4);
 
1331
    } else {
 
1332
        JSScript *script = JSD_GetJSScript (mCx, mScript);
 
1333
        if (!asc.enter(cx, script))
 
1334
            return NS_ERROR_FAILURE;
 
1335
        jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
 
1336
    }
 
1337
    if (!jsstr)
 
1338
        return NS_ERROR_FAILURE;
 
1339
 
 
1340
    size_t length;
 
1341
    const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length);
 
1342
    if (!chars)
 
1343
        return NS_ERROR_FAILURE;
 
1344
 
 
1345
    aFunctionSource = nsDependentString(chars, length);
 
1346
    return NS_OK;
 
1347
}
 
1348
 
 
1349
NS_IMETHODIMP
 
1350
jsdScript::GetBaseLineNumber(uint32_t *_rval)
 
1351
{
 
1352
    *_rval = mBaseLineNumber;
 
1353
    return NS_OK;
 
1354
}
 
1355
 
 
1356
NS_IMETHODIMP
 
1357
jsdScript::GetLineExtent(uint32_t *_rval)
 
1358
{
 
1359
    *_rval = mLineExtent;
 
1360
    return NS_OK;
 
1361
}
 
1362
 
 
1363
NS_IMETHODIMP
 
1364
jsdScript::GetCallCount(uint32_t *_rval)
 
1365
{
 
1366
    ASSERT_VALID_EPHEMERAL;
 
1367
    *_rval = JSD_GetScriptCallCount (mCx, mScript);
 
1368
    return NS_OK;
 
1369
}
 
1370
 
 
1371
NS_IMETHODIMP
 
1372
jsdScript::GetMaxRecurseDepth(uint32_t *_rval)
 
1373
{
 
1374
    ASSERT_VALID_EPHEMERAL;
 
1375
    *_rval = JSD_GetScriptMaxRecurseDepth (mCx, mScript);
 
1376
    return NS_OK;
 
1377
}
 
1378
 
 
1379
NS_IMETHODIMP
 
1380
jsdScript::GetMinExecutionTime(double *_rval)
 
1381
{
 
1382
    ASSERT_VALID_EPHEMERAL;
 
1383
    *_rval = JSD_GetScriptMinExecutionTime (mCx, mScript);
 
1384
    return NS_OK;
 
1385
}
 
1386
 
 
1387
NS_IMETHODIMP
 
1388
jsdScript::GetMaxExecutionTime(double *_rval)
 
1389
{
 
1390
    ASSERT_VALID_EPHEMERAL;
 
1391
    *_rval = JSD_GetScriptMaxExecutionTime (mCx, mScript);
 
1392
    return NS_OK;
 
1393
}
 
1394
 
 
1395
NS_IMETHODIMP
 
1396
jsdScript::GetTotalExecutionTime(double *_rval)
 
1397
{
 
1398
    ASSERT_VALID_EPHEMERAL;
 
1399
    *_rval = JSD_GetScriptTotalExecutionTime (mCx, mScript);
 
1400
    return NS_OK;
 
1401
}
 
1402
 
 
1403
NS_IMETHODIMP
 
1404
jsdScript::GetMinOwnExecutionTime(double *_rval)
 
1405
{
 
1406
    ASSERT_VALID_EPHEMERAL;
 
1407
    *_rval = JSD_GetScriptMinOwnExecutionTime (mCx, mScript);
 
1408
    return NS_OK;
 
1409
}
 
1410
 
 
1411
NS_IMETHODIMP
 
1412
jsdScript::GetMaxOwnExecutionTime(double *_rval)
 
1413
{
 
1414
    ASSERT_VALID_EPHEMERAL;
 
1415
    *_rval = JSD_GetScriptMaxOwnExecutionTime (mCx, mScript);
 
1416
    return NS_OK;
 
1417
}
 
1418
 
 
1419
NS_IMETHODIMP
 
1420
jsdScript::GetTotalOwnExecutionTime(double *_rval)
 
1421
{
 
1422
    ASSERT_VALID_EPHEMERAL;
 
1423
    *_rval = JSD_GetScriptTotalOwnExecutionTime (mCx, mScript);
 
1424
    return NS_OK;
 
1425
}
 
1426
 
 
1427
NS_IMETHODIMP
 
1428
jsdScript::ClearProfileData()
 
1429
{
 
1430
    ASSERT_VALID_EPHEMERAL;
 
1431
    JSD_ClearScriptProfileData(mCx, mScript);
 
1432
    return NS_OK;
 
1433
}
 
1434
 
 
1435
NS_IMETHODIMP
 
1436
jsdScript::PcToLine(uint32_t aPC, uint32_t aPcmap, uint32_t *_rval)
 
1437
{
 
1438
    ASSERT_VALID_EPHEMERAL;
 
1439
    if (aPcmap == PCMAP_SOURCETEXT) {
 
1440
        *_rval = JSD_GetClosestLine (mCx, mScript, mFirstPC + aPC);
 
1441
    } else if (aPcmap == PCMAP_PRETTYPRINT) {
 
1442
        *_rval = PPPcToLine(aPC);
 
1443
    } else {
 
1444
        return NS_ERROR_INVALID_ARG;
 
1445
    }
 
1446
    
 
1447
    return NS_OK;
 
1448
}
 
1449
 
 
1450
NS_IMETHODIMP
 
1451
jsdScript::LineToPc(uint32_t aLine, uint32_t aPcmap, uint32_t *_rval)
 
1452
{
 
1453
    ASSERT_VALID_EPHEMERAL;
 
1454
    if (aPcmap == PCMAP_SOURCETEXT) {
 
1455
        uintptr_t pc = JSD_GetClosestPC (mCx, mScript, aLine);
 
1456
        *_rval = pc - mFirstPC;
 
1457
    } else if (aPcmap == PCMAP_PRETTYPRINT) {
 
1458
        *_rval = PPLineToPc(aLine);
 
1459
    } else {
 
1460
        return NS_ERROR_INVALID_ARG;
 
1461
    }
 
1462
 
 
1463
    return NS_OK;
 
1464
}
 
1465
 
 
1466
NS_IMETHODIMP
 
1467
jsdScript::EnableSingleStepInterrupts(bool enable)
 
1468
{
 
1469
    ASSERT_VALID_EPHEMERAL;
 
1470
 
 
1471
    /* Must have set interrupt hook before enabling */
 
1472
    if (enable && !jsdService::GetService()->CheckInterruptHook())
 
1473
        return NS_ERROR_NOT_INITIALIZED;
 
1474
 
 
1475
    return (JSD_EnableSingleStepInterrupts(mCx, mScript, enable) ? NS_OK : NS_ERROR_FAILURE);
 
1476
}
 
1477
 
 
1478
NS_IMETHODIMP
 
1479
jsdScript::GetExecutableLines(uint32_t aPcmap, uint32_t aStartLine, uint32_t aMaxLines,
 
1480
                              uint32_t* aCount, uint32_t** aExecutableLines)
 
1481
{
 
1482
    ASSERT_VALID_EPHEMERAL;
 
1483
    if (aPcmap == PCMAP_SOURCETEXT) {
 
1484
        uintptr_t start = JSD_GetClosestPC(mCx, mScript, 0);
 
1485
        unsigned lastLine = JSD_GetScriptBaseLineNumber(mCx, mScript)
 
1486
                       + JSD_GetScriptLineExtent(mCx, mScript) - 1;
 
1487
        uintptr_t end = JSD_GetClosestPC(mCx, mScript, lastLine + 1);
 
1488
 
 
1489
        *aExecutableLines = static_cast<uint32_t*>(NS_Alloc((end - start + 1) * sizeof(uint32_t)));
 
1490
        if (!JSD_GetLinePCs(mCx, mScript, aStartLine, aMaxLines, aCount, aExecutableLines, NULL))
 
1491
            return NS_ERROR_OUT_OF_MEMORY;
 
1492
        
 
1493
        return NS_OK;
 
1494
    }
 
1495
 
 
1496
    if (aPcmap == PCMAP_PRETTYPRINT) {
 
1497
        if (!mPPLineMap) {
 
1498
            if (!CreatePPLineMap())
 
1499
                return NS_ERROR_OUT_OF_MEMORY;
 
1500
        }
 
1501
 
 
1502
        nsTArray<uint32_t> lines;
 
1503
        uint32_t i;
 
1504
 
 
1505
        for (i = 0; i < mPCMapSize; ++i) {
 
1506
            if (mPPLineMap[i].line >= aStartLine)
 
1507
                break;
 
1508
        }
 
1509
 
 
1510
        for (; i < mPCMapSize && lines.Length() < aMaxLines; ++i) {
 
1511
            lines.AppendElement(mPPLineMap[i].line);
 
1512
        }
 
1513
 
 
1514
        if (aCount)
 
1515
            *aCount = lines.Length();
 
1516
 
 
1517
        *aExecutableLines = static_cast<uint32_t*>(NS_Alloc(lines.Length() * sizeof(uint32_t)));
 
1518
        if (!*aExecutableLines)
 
1519
            return NS_ERROR_OUT_OF_MEMORY;
 
1520
 
 
1521
        for (i = 0; i < lines.Length(); ++i)
 
1522
            (*aExecutableLines)[i] = lines[i];
 
1523
 
 
1524
        return NS_OK;
 
1525
    }
 
1526
 
 
1527
    return NS_ERROR_INVALID_ARG;
 
1528
}
 
1529
 
 
1530
NS_IMETHODIMP
 
1531
jsdScript::IsLineExecutable(uint32_t aLine, uint32_t aPcmap, bool *_rval)
 
1532
{
 
1533
    ASSERT_VALID_EPHEMERAL;
 
1534
    if (aPcmap == PCMAP_SOURCETEXT) {    
 
1535
        uintptr_t pc = JSD_GetClosestPC (mCx, mScript, aLine);
 
1536
        *_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc));
 
1537
    } else if (aPcmap == PCMAP_PRETTYPRINT) {
 
1538
        if (!mPPLineMap && !CreatePPLineMap())
 
1539
            return NS_ERROR_OUT_OF_MEMORY;
 
1540
        *_rval = false;
 
1541
        for (uint32_t i = 0; i < mPCMapSize; ++i) {
 
1542
            if (mPPLineMap[i].line >= aLine) {
 
1543
                *_rval = (mPPLineMap[i].line == aLine);
 
1544
                break;
 
1545
            }
 
1546
        }
 
1547
    } else {
 
1548
        return NS_ERROR_INVALID_ARG;
 
1549
    }
 
1550
    
 
1551
    return NS_OK;
 
1552
}
 
1553
 
 
1554
NS_IMETHODIMP
 
1555
jsdScript::SetBreakpoint(uint32_t aPC)
 
1556
{
 
1557
    ASSERT_VALID_EPHEMERAL;
 
1558
    uintptr_t pc = mFirstPC + aPC;
 
1559
    JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, NULL);
 
1560
    return NS_OK;
 
1561
}
 
1562
 
 
1563
NS_IMETHODIMP
 
1564
jsdScript::ClearBreakpoint(uint32_t aPC)
 
1565
{
 
1566
    ASSERT_VALID_EPHEMERAL;    
 
1567
    uintptr_t pc = mFirstPC + aPC;
 
1568
    JSD_ClearExecutionHook (mCx, mScript, pc);
 
1569
    return NS_OK;
 
1570
}
 
1571
 
 
1572
NS_IMETHODIMP
 
1573
jsdScript::ClearAllBreakpoints()
 
1574
{
 
1575
    ASSERT_VALID_EPHEMERAL;
 
1576
    JSD_LockScriptSubsystem(mCx);
 
1577
    JSD_ClearAllExecutionHooksForScript (mCx, mScript);
 
1578
    JSD_UnlockScriptSubsystem(mCx);
 
1579
    return NS_OK;
 
1580
}
 
1581
 
 
1582
/* Contexts */
 
1583
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral)
 
1584
 
 
1585
jsdIContext *
 
1586
jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx)
 
1587
{
 
1588
    if (!aJSDCx || !aJSCx)
 
1589
        return nullptr;
 
1590
 
 
1591
    nsCOMPtr<jsdIContext> jsdicx;
 
1592
    nsCOMPtr<jsdIEphemeral> eph = 
 
1593
        jsds_FindEphemeral (&gLiveContexts, static_cast<void *>(aJSCx));
 
1594
    if (eph)
 
1595
    {
 
1596
        jsdicx = do_QueryInterface(eph);
 
1597
    }
 
1598
    else
 
1599
    {
 
1600
        nsCOMPtr<nsISupports> iscx;
 
1601
        if (JS_GetOptions(aJSCx) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
 
1602
            iscx = static_cast<nsISupports *>(JS_GetContextPrivate(aJSCx));
 
1603
        jsdicx = new jsdContext (aJSDCx, aJSCx, iscx);
 
1604
    }
 
1605
 
 
1606
    jsdIContext *ctx = nullptr;
 
1607
    jsdicx.swap(ctx);
 
1608
    return ctx;
 
1609
}
 
1610
 
 
1611
jsdContext::jsdContext (JSDContext *aJSDCx, JSContext *aJSCx,
 
1612
                        nsISupports *aISCx) : mValid(true), mTag(0),
 
1613
                                              mJSDCx(aJSDCx),
 
1614
                                              mJSCx(aJSCx), mISCx(aISCx)
 
1615
{
 
1616
    DEBUG_CREATE ("jsdContext", gContextCount);
 
1617
    mLiveListEntry.value = this;
 
1618
    mLiveListEntry.key   = static_cast<void *>(aJSCx);
 
1619
    jsds_InsertEphemeral (&gLiveContexts, &mLiveListEntry);
 
1620
}
 
1621
 
 
1622
jsdContext::~jsdContext() 
 
1623
{
 
1624
    DEBUG_DESTROY ("jsdContext", gContextCount);
 
1625
    if (mValid)
 
1626
    {
 
1627
        /* call Invalidate() to take ourselves out of the live list */
 
1628
        Invalidate();
 
1629
    }
 
1630
}
 
1631
 
 
1632
NS_IMETHODIMP
 
1633
jsdContext::GetIsValid(bool *_rval)
 
1634
{
 
1635
    *_rval = mValid;
 
1636
    return NS_OK;
 
1637
}
 
1638
 
 
1639
NS_IMETHODIMP
 
1640
jsdContext::Invalidate()
 
1641
{
 
1642
    ASSERT_VALID_EPHEMERAL;
 
1643
    mValid = false;
 
1644
    jsds_RemoveEphemeral (&gLiveContexts, &mLiveListEntry);
 
1645
    return NS_OK;
 
1646
}
 
1647
 
 
1648
void
 
1649
jsdContext::InvalidateAll()
 
1650
{
 
1651
    if (gLiveContexts)
 
1652
        jsds_InvalidateAllEphemerals (&gLiveContexts);
 
1653
}
 
1654
 
 
1655
NS_IMETHODIMP
 
1656
jsdContext::GetJSContext(JSContext **_rval)
 
1657
{
 
1658
    ASSERT_VALID_EPHEMERAL;
 
1659
    *_rval = mJSCx;
 
1660
    return NS_OK;
 
1661
}
 
1662
 
 
1663
NS_IMETHODIMP
 
1664
jsdContext::GetOptions(uint32_t *_rval)
 
1665
{
 
1666
    ASSERT_VALID_EPHEMERAL;
 
1667
    *_rval = JS_GetOptions(mJSCx);
 
1668
    return NS_OK;
 
1669
}
 
1670
 
 
1671
NS_IMETHODIMP
 
1672
jsdContext::SetOptions(uint32_t options)
 
1673
{
 
1674
    ASSERT_VALID_EPHEMERAL;
 
1675
    uint32_t lastOptions = JS_GetOptions(mJSCx);
 
1676
 
 
1677
    /* don't let users change this option, they'd just be shooting themselves
 
1678
     * in the foot. */
 
1679
    if ((options ^ lastOptions) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
 
1680
        return NS_ERROR_ILLEGAL_VALUE;
 
1681
 
 
1682
    JS_SetOptions(mJSCx, options);
 
1683
    return NS_OK;
 
1684
}
 
1685
 
 
1686
NS_IMETHODIMP
 
1687
jsdContext::GetPrivateData(nsISupports **_rval)
 
1688
{
 
1689
    ASSERT_VALID_EPHEMERAL;
 
1690
    uint32_t options = JS_GetOptions(mJSCx);
 
1691
    if (options & JSOPTION_PRIVATE_IS_NSISUPPORTS)
 
1692
    {
 
1693
        *_rval = static_cast<nsISupports*>(JS_GetContextPrivate(mJSCx));
 
1694
        NS_IF_ADDREF(*_rval);
 
1695
    }
 
1696
    else
 
1697
    {
 
1698
        *_rval = nullptr;
 
1699
    }
 
1700
    
 
1701
    return NS_OK;
 
1702
}
 
1703
        
 
1704
NS_IMETHODIMP
 
1705
jsdContext::GetWrappedContext(nsISupports **_rval)
 
1706
{
 
1707
    ASSERT_VALID_EPHEMERAL;
 
1708
    NS_IF_ADDREF(*_rval = mISCx);
 
1709
    return NS_OK;
 
1710
}
 
1711
 
 
1712
NS_IMETHODIMP
 
1713
jsdContext::GetTag(uint32_t *_rval)
 
1714
{
 
1715
    ASSERT_VALID_EPHEMERAL;
 
1716
    if (!mTag)
 
1717
        mTag = ++jsdContext::LastTag;
 
1718
    
 
1719
    *_rval = mTag;
 
1720
    return NS_OK;
 
1721
}
 
1722
 
 
1723
NS_IMETHODIMP
 
1724
jsdContext::GetVersion (int32_t *_rval)
 
1725
{
 
1726
    ASSERT_VALID_EPHEMERAL;
 
1727
    *_rval = static_cast<int32_t>(JS_GetVersion(mJSCx));
 
1728
    return NS_OK;
 
1729
}
 
1730
 
 
1731
NS_IMETHODIMP
 
1732
jsdContext::SetVersion (int32_t id)
 
1733
{
 
1734
    ASSERT_VALID_EPHEMERAL;
 
1735
    JSVersion ver = static_cast<JSVersion>(id);
 
1736
    JS_SetVersion(mJSCx, ver);
 
1737
    return NS_OK;
 
1738
}
 
1739
 
 
1740
NS_IMETHODIMP
 
1741
jsdContext::GetGlobalObject (jsdIValue **_rval)
 
1742
{
 
1743
    ASSERT_VALID_EPHEMERAL;
 
1744
    JSObject *glob = JS_GetGlobalObject(mJSCx);
 
1745
    JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
 
1746
    if (!jsdv)
 
1747
        return NS_ERROR_FAILURE;
 
1748
    *_rval = jsdValue::FromPtr (mJSDCx, jsdv);
 
1749
    if (!*_rval)
 
1750
        return NS_ERROR_FAILURE;
 
1751
    return NS_OK;
 
1752
}
 
1753
 
 
1754
NS_IMETHODIMP
 
1755
jsdContext::GetScriptsEnabled (bool *_rval)
 
1756
{
 
1757
    ASSERT_VALID_EPHEMERAL;
 
1758
    if (!mISCx) {
 
1759
        *_rval = true;
 
1760
        return NS_OK;
 
1761
    }
 
1762
 
 
1763
    nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
 
1764
    if (!context)
 
1765
        return NS_ERROR_NO_INTERFACE;
 
1766
 
 
1767
    *_rval = context->GetScriptsEnabled();
 
1768
 
 
1769
    return NS_OK;
 
1770
}
 
1771
 
 
1772
NS_IMETHODIMP
 
1773
jsdContext::SetScriptsEnabled (bool _rval)
 
1774
{
 
1775
    ASSERT_VALID_EPHEMERAL;
 
1776
    if (!mISCx) {
 
1777
        if (_rval)
 
1778
            return NS_OK;
 
1779
        return NS_ERROR_NO_INTERFACE;
 
1780
    }
 
1781
 
 
1782
    nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
 
1783
    if (!context)
 
1784
        return NS_ERROR_NO_INTERFACE;
 
1785
 
 
1786
    context->SetScriptsEnabled(_rval, true);
 
1787
 
 
1788
    return NS_OK;
 
1789
}
 
1790
 
 
1791
/* Stack Frames */
 
1792
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame, jsdIStackFrame, jsdIEphemeral)
 
1793
 
 
1794
jsdStackFrame::jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState,
 
1795
                              JSDStackFrameInfo *aStackFrameInfo) :
 
1796
    mCx(aCx), mThreadState(aThreadState), mStackFrameInfo(aStackFrameInfo)
 
1797
{
 
1798
    DEBUG_CREATE ("jsdStackFrame", gFrameCount);
 
1799
    mValid = (aCx && aThreadState && aStackFrameInfo);
 
1800
    if (mValid) {
 
1801
        mLiveListEntry.key = aStackFrameInfo;
 
1802
        mLiveListEntry.value = this;
 
1803
        jsds_InsertEphemeral (&gLiveStackFrames, &mLiveListEntry);
 
1804
    }
 
1805
}
 
1806
 
 
1807
jsdStackFrame::~jsdStackFrame() 
 
1808
{
 
1809
    DEBUG_DESTROY ("jsdStackFrame", gFrameCount);
 
1810
    if (mValid)
 
1811
    {
 
1812
        /* call Invalidate() to take ourselves out of the live list */
 
1813
        Invalidate();
 
1814
    }
 
1815
}
 
1816
 
 
1817
jsdIStackFrame *
 
1818
jsdStackFrame::FromPtr (JSDContext *aCx, JSDThreadState *aThreadState,
 
1819
                        JSDStackFrameInfo *aStackFrameInfo)
 
1820
{
 
1821
    if (!aStackFrameInfo)
 
1822
        return nullptr;
 
1823
 
 
1824
    jsdIStackFrame *rv;
 
1825
    nsCOMPtr<jsdIStackFrame> frame;
 
1826
 
 
1827
    nsCOMPtr<jsdIEphemeral> eph =
 
1828
        jsds_FindEphemeral (&gLiveStackFrames,
 
1829
                            reinterpret_cast<void *>(aStackFrameInfo));
 
1830
 
 
1831
    if (eph)
 
1832
    {
 
1833
        frame = do_QueryInterface(eph);
 
1834
        rv = frame;
 
1835
    }
 
1836
    else
 
1837
    {
 
1838
        rv = new jsdStackFrame (aCx, aThreadState, aStackFrameInfo);
 
1839
    }
 
1840
 
 
1841
    NS_IF_ADDREF(rv);
 
1842
    return rv;
 
1843
}
 
1844
 
 
1845
NS_IMETHODIMP
 
1846
jsdStackFrame::Invalidate()
 
1847
{
 
1848
    ASSERT_VALID_EPHEMERAL;
 
1849
    mValid = false;
 
1850
    jsds_RemoveEphemeral (&gLiveStackFrames, &mLiveListEntry);
 
1851
    return NS_OK;
 
1852
}
 
1853
 
 
1854
void
 
1855
jsdStackFrame::InvalidateAll()
 
1856
{
 
1857
    if (gLiveStackFrames)
 
1858
        jsds_InvalidateAllEphemerals (&gLiveStackFrames);
 
1859
}
 
1860
 
 
1861
NS_IMETHODIMP
 
1862
jsdStackFrame::GetJSDContext(JSDContext **_rval)
 
1863
{
 
1864
    ASSERT_VALID_EPHEMERAL;
 
1865
    *_rval = mCx;
 
1866
    return NS_OK;
 
1867
}
 
1868
 
 
1869
NS_IMETHODIMP
 
1870
jsdStackFrame::GetJSDThreadState(JSDThreadState **_rval)
 
1871
{
 
1872
    ASSERT_VALID_EPHEMERAL;
 
1873
    *_rval = mThreadState;
 
1874
    return NS_OK;
 
1875
}
 
1876
 
 
1877
NS_IMETHODIMP
 
1878
jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo **_rval)
 
1879
{
 
1880
    ASSERT_VALID_EPHEMERAL;
 
1881
    *_rval = mStackFrameInfo;
 
1882
    return NS_OK;
 
1883
}
 
1884
 
 
1885
NS_IMETHODIMP
 
1886
jsdStackFrame::GetIsValid(bool *_rval)
 
1887
{
 
1888
    *_rval = mValid;
 
1889
    return NS_OK;
 
1890
}
 
1891
 
 
1892
NS_IMETHODIMP
 
1893
jsdStackFrame::GetCallingFrame(jsdIStackFrame **_rval)
 
1894
{
 
1895
    ASSERT_VALID_EPHEMERAL;
 
1896
    JSDStackFrameInfo *sfi = JSD_GetCallingStackFrame (mCx, mThreadState,
 
1897
                                                       mStackFrameInfo);
 
1898
    *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
 
1899
    return NS_OK;
 
1900
}
 
1901
 
 
1902
NS_IMETHODIMP
 
1903
jsdStackFrame::GetExecutionContext(jsdIContext **_rval)
 
1904
{
 
1905
    ASSERT_VALID_EPHEMERAL;
 
1906
    JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
 
1907
    *_rval = jsdContext::FromPtr (mCx, cx);
 
1908
    return NS_OK;
 
1909
}
 
1910
 
 
1911
NS_IMETHODIMP
 
1912
jsdStackFrame::GetFunctionName(nsACString &_rval)
 
1913
{
 
1914
    ASSERT_VALID_EPHEMERAL;
 
1915
    JSString *str = JSD_GetIdForStackFrame(mCx, mThreadState, mStackFrameInfo);
 
1916
    if (str)
 
1917
        return AssignToJSString(&_rval, str);
 
1918
    
 
1919
    _rval.Assign("anonymous");
 
1920
    return NS_OK;
 
1921
}
 
1922
 
 
1923
NS_IMETHODIMP
 
1924
jsdStackFrame::GetIsDebugger(bool *_rval)
 
1925
{
 
1926
    ASSERT_VALID_EPHEMERAL;
 
1927
    *_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo);
 
1928
    return NS_OK;
 
1929
}
 
1930
 
 
1931
NS_IMETHODIMP
 
1932
jsdStackFrame::GetIsConstructing(bool *_rval)
 
1933
{
 
1934
    ASSERT_VALID_EPHEMERAL;
 
1935
    *_rval = JSD_IsStackFrameConstructing (mCx, mThreadState, mStackFrameInfo);
 
1936
    return NS_OK;
 
1937
}
 
1938
 
 
1939
NS_IMETHODIMP
 
1940
jsdStackFrame::GetScript(jsdIScript **_rval)
 
1941
{
 
1942
    ASSERT_VALID_EPHEMERAL;
 
1943
    JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
 
1944
                                                    mStackFrameInfo);
 
1945
    *_rval = jsdScript::FromPtr (mCx, script);
 
1946
    return NS_OK;
 
1947
}
 
1948
 
 
1949
NS_IMETHODIMP
 
1950
jsdStackFrame::GetPc(uint32_t *_rval)
 
1951
{
 
1952
    ASSERT_VALID_EPHEMERAL;
 
1953
    JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
 
1954
                                                    mStackFrameInfo);
 
1955
    if (!script)
 
1956
        return NS_ERROR_FAILURE;
 
1957
    uintptr_t pcbase = JSD_GetClosestPC(mCx, script, 0);
 
1958
    
 
1959
    uintptr_t pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
 
1960
    if (pc)
 
1961
        *_rval = pc - pcbase;
 
1962
    else
 
1963
        *_rval = pcbase;
 
1964
    return NS_OK;
 
1965
}
 
1966
 
 
1967
NS_IMETHODIMP
 
1968
jsdStackFrame::GetLine(uint32_t *_rval)
 
1969
{
 
1970
    ASSERT_VALID_EPHEMERAL;
 
1971
    JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
 
1972
                                                    mStackFrameInfo);
 
1973
    if (script) {
 
1974
        uintptr_t pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
 
1975
        *_rval = JSD_GetClosestLine (mCx, script, pc);
 
1976
    } else {
 
1977
        return NS_ERROR_FAILURE;
 
1978
    }
 
1979
    return NS_OK;
 
1980
}
 
1981
 
 
1982
NS_IMETHODIMP
 
1983
jsdStackFrame::GetCallee(jsdIValue **_rval)
 
1984
{
 
1985
    ASSERT_VALID_EPHEMERAL;
 
1986
    JSDValue *jsdv = JSD_GetCallObjectForStackFrame (mCx, mThreadState,
 
1987
                                                     mStackFrameInfo);
 
1988
    
 
1989
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
1990
    return NS_OK;
 
1991
}
 
1992
 
 
1993
NS_IMETHODIMP
 
1994
jsdStackFrame::GetScope(jsdIValue **_rval)
 
1995
{
 
1996
    ASSERT_VALID_EPHEMERAL;
 
1997
    JSDValue *jsdv = JSD_GetScopeChainForStackFrame (mCx, mThreadState,
 
1998
                                                     mStackFrameInfo);
 
1999
    
 
2000
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
2001
    return NS_OK;
 
2002
}
 
2003
 
 
2004
NS_IMETHODIMP
 
2005
jsdStackFrame::GetThisValue(jsdIValue **_rval)
 
2006
{
 
2007
    ASSERT_VALID_EPHEMERAL;
 
2008
    JSDValue *jsdv = JSD_GetThisForStackFrame (mCx, mThreadState,
 
2009
                                               mStackFrameInfo);
 
2010
    
 
2011
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
2012
    return NS_OK;
 
2013
}
 
2014
 
 
2015
 
 
2016
NS_IMETHODIMP
 
2017
jsdStackFrame::Eval (const nsAString &bytes, const nsACString &fileName,
 
2018
                     uint32_t line, jsdIValue **result, bool *_rval)
 
2019
{
 
2020
    ASSERT_VALID_EPHEMERAL;
 
2021
 
 
2022
    if (bytes.IsEmpty())
 
2023
        return NS_ERROR_INVALID_ARG;
 
2024
 
 
2025
    // get pointer to buffer contained in |bytes|
 
2026
    nsAString::const_iterator h;
 
2027
    bytes.BeginReading(h);
 
2028
    const jschar *char_bytes = reinterpret_cast<const jschar *>(h.get());
 
2029
 
 
2030
    JSExceptionState *estate = 0;
 
2031
    jsval jv;
 
2032
 
 
2033
    JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
 
2034
 
 
2035
    JSAutoRequest ar(cx);
 
2036
 
 
2037
    estate = JS_SaveExceptionState (cx);
 
2038
    JS_ClearPendingException (cx);
 
2039
 
 
2040
    nsresult rv;
 
2041
    nsCOMPtr<nsIJSContextStack> stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
 
2042
    if (NS_SUCCEEDED(rv))
 
2043
        rv = stack->Push(cx);
 
2044
    if (NS_FAILED(rv)) {
 
2045
        JS_RestoreExceptionState (cx, estate);
 
2046
        return rv;
 
2047
    }
 
2048
 
 
2049
    *_rval = JSD_AttemptUCScriptInStackFrame (mCx, mThreadState,
 
2050
                                              mStackFrameInfo,
 
2051
                                              char_bytes, bytes.Length(),
 
2052
                                              PromiseFlatCString(fileName).get(),
 
2053
                                              line, &jv);
 
2054
    if (!*_rval) {
 
2055
        if (JS_IsExceptionPending(cx))
 
2056
            JS_GetPendingException (cx, &jv);
 
2057
        else
 
2058
            jv = JSVAL_NULL;
 
2059
    }
 
2060
 
 
2061
    JS_RestoreExceptionState (cx, estate);
 
2062
 
 
2063
#ifdef DEBUG
 
2064
    JSContext* poppedCX;
 
2065
    rv = stack->Pop(&poppedCX);
 
2066
    NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == cx, "bad pop");
 
2067
#else
 
2068
    (void) stack->Pop(nullptr);
 
2069
#endif
 
2070
 
 
2071
    JSDValue *jsdv = JSD_NewValue (mCx, jv);
 
2072
    if (!jsdv)
 
2073
        return NS_ERROR_FAILURE;
 
2074
    *result = jsdValue::FromPtr (mCx, jsdv);
 
2075
    if (!*result)
 
2076
        return NS_ERROR_FAILURE;
 
2077
    
 
2078
    return NS_OK;
 
2079
}        
 
2080
 
 
2081
/* Values */
 
2082
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue, jsdIValue, jsdIEphemeral)
 
2083
jsdIValue *
 
2084
jsdValue::FromPtr (JSDContext *aCx, JSDValue *aValue)
 
2085
{
 
2086
    /* value will be dropped by te jsdValue destructor. */
 
2087
 
 
2088
    if (!aValue)
 
2089
        return nullptr;
 
2090
    
 
2091
    jsdIValue *rv = new jsdValue (aCx, aValue);
 
2092
    NS_IF_ADDREF(rv);
 
2093
    return rv;
 
2094
}
 
2095
 
 
2096
jsdValue::jsdValue (JSDContext *aCx, JSDValue *aValue) : mValid(true),
 
2097
                                                         mCx(aCx), 
 
2098
                                                         mValue(aValue)
 
2099
{
 
2100
    DEBUG_CREATE ("jsdValue", gValueCount);
 
2101
    mLiveListEntry.value = this;
 
2102
    jsds_InsertEphemeral (&gLiveValues, &mLiveListEntry);
 
2103
}
 
2104
 
 
2105
jsdValue::~jsdValue() 
 
2106
{
 
2107
    DEBUG_DESTROY ("jsdValue", gValueCount);
 
2108
    if (mValid)
 
2109
        /* call Invalidate() to take ourselves out of the live list */
 
2110
        Invalidate();
 
2111
}   
 
2112
 
 
2113
NS_IMETHODIMP
 
2114
jsdValue::GetIsValid(bool *_rval)
 
2115
{
 
2116
    *_rval = mValid;
 
2117
    return NS_OK;
 
2118
}
 
2119
 
 
2120
NS_IMETHODIMP
 
2121
jsdValue::Invalidate()
 
2122
{
 
2123
    ASSERT_VALID_EPHEMERAL;
 
2124
    mValid = false;
 
2125
    jsds_RemoveEphemeral (&gLiveValues, &mLiveListEntry);
 
2126
    JSD_DropValue (mCx, mValue);
 
2127
    return NS_OK;
 
2128
}
 
2129
 
 
2130
void
 
2131
jsdValue::InvalidateAll()
 
2132
{
 
2133
    if (gLiveValues)
 
2134
        jsds_InvalidateAllEphemerals (&gLiveValues);
 
2135
}
 
2136
 
 
2137
NS_IMETHODIMP
 
2138
jsdValue::GetJSDContext(JSDContext **_rval)
 
2139
{
 
2140
    ASSERT_VALID_EPHEMERAL;
 
2141
    *_rval = mCx;
 
2142
    return NS_OK;
 
2143
}
 
2144
 
 
2145
NS_IMETHODIMP
 
2146
jsdValue::GetJSDValue (JSDValue **_rval)
 
2147
{
 
2148
    ASSERT_VALID_EPHEMERAL;
 
2149
    *_rval = mValue;
 
2150
    return NS_OK;
 
2151
}
 
2152
 
 
2153
NS_IMETHODIMP
 
2154
jsdValue::GetIsNative (bool *_rval)
 
2155
{
 
2156
    ASSERT_VALID_EPHEMERAL;
 
2157
    *_rval = JSD_IsValueNative (mCx, mValue);
 
2158
    return NS_OK;
 
2159
}
 
2160
 
 
2161
NS_IMETHODIMP
 
2162
jsdValue::GetIsNumber (bool *_rval)
 
2163
{
 
2164
    ASSERT_VALID_EPHEMERAL;
 
2165
    *_rval = JSD_IsValueNumber (mCx, mValue);
 
2166
    return NS_OK;
 
2167
}
 
2168
 
 
2169
NS_IMETHODIMP
 
2170
jsdValue::GetIsPrimitive (bool *_rval)
 
2171
{
 
2172
    ASSERT_VALID_EPHEMERAL;
 
2173
    *_rval = JSD_IsValuePrimitive (mCx, mValue);
 
2174
    return NS_OK;
 
2175
}
 
2176
 
 
2177
NS_IMETHODIMP
 
2178
jsdValue::GetJsType (uint32_t *_rval)
 
2179
{
 
2180
    ASSERT_VALID_EPHEMERAL;
 
2181
    jsval val;
 
2182
 
 
2183
    val = JSD_GetValueWrappedJSVal (mCx, mValue);
 
2184
    
 
2185
    if (JSVAL_IS_NULL(val))
 
2186
        *_rval = TYPE_NULL;
 
2187
    else if (JSVAL_IS_BOOLEAN(val))
 
2188
        *_rval = TYPE_BOOLEAN;
 
2189
    else if (JSVAL_IS_DOUBLE(val))
 
2190
        *_rval = TYPE_DOUBLE;
 
2191
    else if (JSVAL_IS_INT(val))
 
2192
        *_rval = TYPE_INT;
 
2193
    else if (JSVAL_IS_STRING(val))
 
2194
        *_rval = TYPE_STRING;
 
2195
    else if (JSVAL_IS_VOID(val))
 
2196
        *_rval = TYPE_VOID;
 
2197
    else if (JSD_IsValueFunction (mCx, mValue))
 
2198
        *_rval = TYPE_FUNCTION;
 
2199
    else if (!JSVAL_IS_PRIMITIVE(val))
 
2200
        *_rval = TYPE_OBJECT;
 
2201
    else
 
2202
        NS_ASSERTION (0, "Value has no discernible type.");
 
2203
 
 
2204
    return NS_OK;
 
2205
}
 
2206
 
 
2207
NS_IMETHODIMP
 
2208
jsdValue::GetJsPrototype (jsdIValue **_rval)
 
2209
{
 
2210
    ASSERT_VALID_EPHEMERAL;
 
2211
    JSDValue *jsdv = JSD_GetValuePrototype (mCx, mValue);
 
2212
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
2213
    return NS_OK;
 
2214
}
 
2215
 
 
2216
NS_IMETHODIMP
 
2217
jsdValue::GetJsParent (jsdIValue **_rval)
 
2218
{
 
2219
    ASSERT_VALID_EPHEMERAL;
 
2220
    JSDValue *jsdv = JSD_GetValueParent (mCx, mValue);
 
2221
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
2222
    return NS_OK;
 
2223
}
 
2224
 
 
2225
NS_IMETHODIMP
 
2226
jsdValue::GetJsClassName(nsACString &_rval)
 
2227
{
 
2228
    ASSERT_VALID_EPHEMERAL;
 
2229
    _rval.Assign(JSD_GetValueClassName(mCx, mValue));
 
2230
    
 
2231
    return NS_OK;
 
2232
}
 
2233
 
 
2234
NS_IMETHODIMP
 
2235
jsdValue::GetJsConstructor (jsdIValue **_rval)
 
2236
{
 
2237
    ASSERT_VALID_EPHEMERAL;
 
2238
    JSDValue *jsdv = JSD_GetValueConstructor (mCx, mValue);
 
2239
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
2240
    return NS_OK;
 
2241
}
 
2242
 
 
2243
NS_IMETHODIMP
 
2244
jsdValue::GetJsFunctionName(nsACString &_rval)
 
2245
{
 
2246
    ASSERT_VALID_EPHEMERAL;
 
2247
    return AssignToJSString(&_rval, JSD_GetValueFunctionId(mCx, mValue));
 
2248
}
 
2249
 
 
2250
NS_IMETHODIMP
 
2251
jsdValue::GetBooleanValue(bool *_rval)
 
2252
{
 
2253
    ASSERT_VALID_EPHEMERAL;
 
2254
    *_rval = JSD_GetValueBoolean (mCx, mValue);
 
2255
    return NS_OK;
 
2256
}
 
2257
 
 
2258
NS_IMETHODIMP
 
2259
jsdValue::GetDoubleValue(double *_rval)
 
2260
{
 
2261
    ASSERT_VALID_EPHEMERAL;
 
2262
    *_rval = JSD_GetValueDouble (mCx, mValue);
 
2263
    return NS_OK;
 
2264
}
 
2265
 
 
2266
NS_IMETHODIMP
 
2267
jsdValue::GetIntValue(int32_t *_rval)
 
2268
{
 
2269
    ASSERT_VALID_EPHEMERAL;
 
2270
    *_rval = JSD_GetValueInt (mCx, mValue);
 
2271
    return NS_OK;
 
2272
}
 
2273
 
 
2274
NS_IMETHODIMP
 
2275
jsdValue::GetObjectValue(jsdIObject **_rval)
 
2276
{
 
2277
    ASSERT_VALID_EPHEMERAL;
 
2278
    JSDObject *obj;
 
2279
    obj = JSD_GetObjectForValue (mCx, mValue);
 
2280
    *_rval = jsdObject::FromPtr (mCx, obj);
 
2281
    if (!*_rval)
 
2282
        return NS_ERROR_FAILURE;
 
2283
    return NS_OK;
 
2284
}
 
2285
    
 
2286
NS_IMETHODIMP
 
2287
jsdValue::GetStringValue(nsACString &_rval)
 
2288
{
 
2289
    ASSERT_VALID_EPHEMERAL;
 
2290
    JSContext *cx = JSD_GetDefaultJSContext (mCx);
 
2291
    if (!cx) {
 
2292
        NS_WARNING("No default context !?");
 
2293
        return NS_ERROR_FAILURE;
 
2294
    }
 
2295
    JSString *jstr_val = JSD_GetValueString(mCx, mValue);
 
2296
    if (jstr_val) {
 
2297
        size_t length;
 
2298
        const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length);
 
2299
        if (!chars)
 
2300
            return NS_ERROR_FAILURE;
 
2301
        nsDependentString depStr(chars, length);
 
2302
        CopyUTF16toUTF8(depStr, _rval);
 
2303
    } else {
 
2304
        _rval.Truncate();
 
2305
    }
 
2306
    return NS_OK;
 
2307
}
 
2308
 
 
2309
NS_IMETHODIMP
 
2310
jsdValue::GetPropertyCount (int32_t *_rval)
 
2311
{
 
2312
    ASSERT_VALID_EPHEMERAL;
 
2313
    if (JSD_IsValueObject(mCx, mValue))
 
2314
        *_rval = JSD_GetCountOfProperties (mCx, mValue);
 
2315
    else
 
2316
        *_rval = -1;
 
2317
    return NS_OK;
 
2318
}
 
2319
 
 
2320
NS_IMETHODIMP
 
2321
jsdValue::GetProperties (jsdIProperty ***propArray, uint32_t *length)
 
2322
{
 
2323
    ASSERT_VALID_EPHEMERAL;
 
2324
    *propArray = nullptr;
 
2325
    if (length)
 
2326
        *length = 0;
 
2327
 
 
2328
    uint32_t prop_count = JSD_IsValueObject(mCx, mValue)
 
2329
        ? JSD_GetCountOfProperties (mCx, mValue)
 
2330
        : 0;
 
2331
    NS_ENSURE_TRUE(prop_count, NS_OK);
 
2332
 
 
2333
    jsdIProperty **pa_temp =
 
2334
        static_cast<jsdIProperty **>
 
2335
                   (nsMemory::Alloc(sizeof (jsdIProperty *) * 
 
2336
                                       prop_count));
 
2337
    NS_ENSURE_TRUE(pa_temp, NS_ERROR_OUT_OF_MEMORY);
 
2338
 
 
2339
    uint32_t     i    = 0;
 
2340
    JSDProperty *iter = NULL;
 
2341
    JSDProperty *prop;
 
2342
    while ((prop = JSD_IterateProperties (mCx, mValue, &iter))) {
 
2343
        pa_temp[i] = jsdProperty::FromPtr (mCx, prop);
 
2344
        ++i;
 
2345
    }
 
2346
    
 
2347
    NS_ASSERTION (prop_count == i, "property count mismatch");    
 
2348
 
 
2349
    /* if caller doesn't care about length, don't bother telling them */
 
2350
    *propArray = pa_temp;
 
2351
    if (length)
 
2352
        *length = prop_count;
 
2353
    
 
2354
    return NS_OK;
 
2355
}
 
2356
 
 
2357
NS_IMETHODIMP
 
2358
jsdValue::GetProperty (const nsACString &name, jsdIProperty **_rval)
 
2359
{
 
2360
    ASSERT_VALID_EPHEMERAL;
 
2361
    JSContext *cx = JSD_GetDefaultJSContext (mCx);
 
2362
 
 
2363
    JSAutoRequest ar(cx);
 
2364
 
 
2365
    /* not rooting this */
 
2366
    JSString *jstr_name = JS_NewStringCopyZ(cx, PromiseFlatCString(name).get());
 
2367
    if (!jstr_name)
 
2368
        return NS_ERROR_OUT_OF_MEMORY;
 
2369
 
 
2370
    JSDProperty *prop = JSD_GetValueProperty (mCx, mValue, jstr_name);
 
2371
    
 
2372
    *_rval = jsdProperty::FromPtr (mCx, prop);
 
2373
    return NS_OK;
 
2374
}
 
2375
 
 
2376
NS_IMETHODIMP
 
2377
jsdValue::Refresh()
 
2378
{
 
2379
    ASSERT_VALID_EPHEMERAL;
 
2380
    JSD_RefreshValue (mCx, mValue);
 
2381
    return NS_OK;
 
2382
}
 
2383
 
 
2384
NS_IMETHODIMP
 
2385
jsdValue::GetWrappedValue(JSContext* aCx, JS::Value* aRetval)
 
2386
{
 
2387
    ASSERT_VALID_EPHEMERAL;
 
2388
 
 
2389
    *aRetval = JSD_GetValueWrappedJSVal(mCx, mValue);
 
2390
    if (!JS_WrapValue(aCx, aRetval)) {
 
2391
        return NS_ERROR_FAILURE;
 
2392
    }
 
2393
 
 
2394
    return NS_OK;
 
2395
}
 
2396
 
 
2397
NS_IMETHODIMP
 
2398
jsdValue::GetScript(jsdIScript **_rval)
 
2399
{
 
2400
    ASSERT_VALID_EPHEMERAL;
 
2401
    JSDScript *script = JSD_GetScriptForValue(mCx, mValue);
 
2402
    *_rval = jsdScript::FromPtr(mCx, script);
 
2403
    return NS_OK;
 
2404
}
 
2405
 
 
2406
/******************************************************************************
 
2407
 * debugger service implementation
 
2408
 ******************************************************************************/
 
2409
 
 
2410
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(jsdService)
 
2411
  NS_INTERFACE_MAP_ENTRY(jsdIDebuggerService)
 
2412
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, jsdIDebuggerService)
 
2413
NS_INTERFACE_MAP_END
 
2414
 
 
2415
/* NS_IMPL_CYCLE_COLLECTION_10(jsdService, ...) */
 
2416
 
 
2417
NS_IMPL_CYCLE_COLLECTION_CLASS(jsdService)
 
2418
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(jsdService)
 
2419
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mErrorHook)
 
2420
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mBreakpointHook)
 
2421
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDebugHook)
 
2422
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDebuggerHook)
 
2423
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInterruptHook)
 
2424
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScriptHook)
 
2425
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mThrowHook)
 
2426
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTopLevelHook)
 
2427
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFunctionHook)
 
2428
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mActivationCallback)
 
2429
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
2430
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(jsdService)
 
2431
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mErrorHook)
 
2432
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBreakpointHook)
 
2433
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDebugHook)
 
2434
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDebuggerHook)
 
2435
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInterruptHook)
 
2436
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptHook)
 
2437
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mThrowHook)
 
2438
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTopLevelHook)
 
2439
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFunctionHook)
 
2440
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mActivationCallback)
 
2441
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
2442
 
 
2443
NS_IMPL_CYCLE_COLLECTING_ADDREF(jsdService)
 
2444
NS_IMPL_CYCLE_COLLECTING_RELEASE(jsdService)
 
2445
 
 
2446
NS_IMETHODIMP
 
2447
jsdService::GetJSDContext(JSDContext **_rval)
 
2448
{
 
2449
    *_rval = mCx;
 
2450
    return NS_OK;
 
2451
}
 
2452
 
 
2453
NS_IMETHODIMP
 
2454
jsdService::GetFlags (uint32_t *_rval)
 
2455
{
 
2456
    ASSERT_VALID_CONTEXT;
 
2457
    *_rval = JSD_GetContextFlags (mCx);
 
2458
    return NS_OK;
 
2459
}
 
2460
 
 
2461
NS_IMETHODIMP
 
2462
jsdService::SetFlags (uint32_t flags)
 
2463
{
 
2464
    ASSERT_VALID_CONTEXT;
 
2465
    JSD_SetContextFlags (mCx, flags);
 
2466
    return NS_OK;
 
2467
}
 
2468
 
 
2469
NS_IMETHODIMP
 
2470
jsdService::GetImplementationString(nsACString &aImplementationString)
 
2471
{
 
2472
    aImplementationString.AssignLiteral(implementationString);
 
2473
    return NS_OK;
 
2474
}
 
2475
 
 
2476
NS_IMETHODIMP
 
2477
jsdService::GetImplementationMajor(uint32_t *_rval)
 
2478
{
 
2479
    *_rval = JSDS_MAJOR_VERSION;
 
2480
    return NS_OK;
 
2481
}
 
2482
 
 
2483
NS_IMETHODIMP
 
2484
jsdService::GetImplementationMinor(uint32_t *_rval)
 
2485
{
 
2486
    *_rval = JSDS_MINOR_VERSION;
 
2487
    return NS_OK;
 
2488
}
 
2489
 
 
2490
NS_IMETHODIMP
 
2491
jsdService::GetIsOn (bool *_rval)
 
2492
{
 
2493
    *_rval = mOn;
 
2494
    return NS_OK;
 
2495
}
 
2496
 
 
2497
NS_IMETHODIMP
 
2498
jsdService::On (void)
 
2499
{
 
2500
    return NS_ERROR_NOT_IMPLEMENTED;
 
2501
}
 
2502
 
 
2503
NS_IMETHODIMP
 
2504
jsdService::AsyncOn (jsdIActivationCallback *activationCallback)
 
2505
{
 
2506
    nsresult  rv;
 
2507
 
 
2508
    nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
 
2509
    if (NS_FAILED(rv)) return rv;
 
2510
 
 
2511
    mActivationCallback = activationCallback;
 
2512
    
 
2513
    return xpc->SetDebugModeWhenPossible(true, true);
 
2514
}
 
2515
 
 
2516
NS_IMETHODIMP
 
2517
jsdService::RecompileForDebugMode (JSContext *cx, JSCompartment *comp, bool mode) {
 
2518
  NS_ASSERTION(NS_IsMainThread(), "wrong thread");
 
2519
  /* XPConnect now does this work itself, so this IDL entry point is no longer used. */
 
2520
  return NS_ERROR_NOT_IMPLEMENTED;
 
2521
}
 
2522
 
 
2523
NS_IMETHODIMP
 
2524
jsdService::DeactivateDebugger ()
 
2525
{
 
2526
    if (!mCx)
 
2527
        return NS_OK;
 
2528
 
 
2529
    jsdContext::InvalidateAll();
 
2530
    jsdScript::InvalidateAll();
 
2531
    jsdValue::InvalidateAll();
 
2532
    jsdProperty::InvalidateAll();
 
2533
    jsdStackFrame::InvalidateAll();
 
2534
    ClearAllBreakpoints();
 
2535
 
 
2536
    JSD_SetErrorReporter (mCx, NULL, NULL);
 
2537
    JSD_SetScriptHook (mCx, NULL, NULL);
 
2538
    JSD_ClearThrowHook (mCx);
 
2539
    JSD_ClearInterruptHook (mCx);
 
2540
    JSD_ClearDebuggerHook (mCx);
 
2541
    JSD_ClearDebugBreakHook (mCx);
 
2542
    JSD_ClearTopLevelHook (mCx);
 
2543
    JSD_ClearFunctionHook (mCx);
 
2544
    
 
2545
    JSD_DebuggerOff (mCx);
 
2546
 
 
2547
    mCx = nullptr;
 
2548
    mRuntime = nullptr;
 
2549
    mOn = false;
 
2550
 
 
2551
    return NS_OK;
 
2552
}
 
2553
 
 
2554
 
 
2555
NS_IMETHODIMP
 
2556
jsdService::ActivateDebugger (JSRuntime *rt)
 
2557
{
 
2558
    if (mOn)
 
2559
        return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED;
 
2560
 
 
2561
    mRuntime = rt;
 
2562
 
 
2563
    if (gPrevGCSliceCallback == jsds_GCSliceCallbackProc)
 
2564
        /* condition indicates that the callback proc has not been set yet */
 
2565
        gPrevGCSliceCallback = js::SetGCSliceCallback (rt, jsds_GCSliceCallbackProc);
 
2566
 
 
2567
    mCx = JSD_DebuggerOnForUser (rt, NULL, NULL);
 
2568
    if (!mCx)
 
2569
        return NS_ERROR_FAILURE;
 
2570
 
 
2571
    JSContext *cx   = JSD_GetDefaultJSContext (mCx);
 
2572
    JSObject  *glob = JS_GetGlobalObject (cx);
 
2573
 
 
2574
    /* init xpconnect on the debugger's context in case xpconnect tries to
 
2575
     * use it for stuff. */
 
2576
    nsresult rv;
 
2577
    nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
 
2578
    if (NS_FAILED(rv))
 
2579
        return rv;
 
2580
    
 
2581
    xpc->InitClasses (cx, glob);
 
2582
 
 
2583
    /* Start watching for script creation/destruction and manage jsdScript
 
2584
     * objects accordingly
 
2585
     */
 
2586
    JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
 
2587
 
 
2588
    /* If any of these mFooHook objects are installed, do the required JSD
 
2589
     * hookup now.   See also, jsdService::SetFooHook().
 
2590
     */
 
2591
    if (mErrorHook)
 
2592
        JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
 
2593
    if (mThrowHook)
 
2594
        JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
 
2595
    /* can't ignore script callbacks, as we need to |Release| the wrapper 
 
2596
     * stored in private data when a script is deleted. */
 
2597
    if (mInterruptHook)
 
2598
        JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
 
2599
    if (mDebuggerHook)
 
2600
        JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
 
2601
    if (mDebugHook)
 
2602
        JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
 
2603
    if (mTopLevelHook)
 
2604
        JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
 
2605
    else
 
2606
        JSD_ClearTopLevelHook (mCx);
 
2607
    if (mFunctionHook)
 
2608
        JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
 
2609
    else
 
2610
        JSD_ClearFunctionHook (mCx);
 
2611
    mOn = true;
 
2612
 
 
2613
#ifdef DEBUG
 
2614
    printf ("+++ JavaScript debugging hooks installed.\n");
 
2615
#endif
 
2616
 
 
2617
    nsCOMPtr<jsdIActivationCallback> activationCallback;
 
2618
    mActivationCallback.swap(activationCallback);
 
2619
    if (activationCallback)
 
2620
        return activationCallback->OnDebuggerActivated();
 
2621
 
 
2622
    return NS_OK;
 
2623
}
 
2624
 
 
2625
NS_IMETHODIMP
 
2626
jsdService::Off (void)
 
2627
{
 
2628
    if (!mOn)
 
2629
        return NS_OK;
 
2630
    
 
2631
    if (!mCx || !mRuntime)
 
2632
        return NS_ERROR_NOT_INITIALIZED;
 
2633
    
 
2634
    if (gDeadScripts) {
 
2635
        if (gGCRunning)
 
2636
            return NS_ERROR_NOT_AVAILABLE;
 
2637
 
 
2638
        JSContext *cx = JSD_GetDefaultJSContext(mCx);
 
2639
        while (gDeadScripts)
 
2640
            jsds_NotifyPendingDeadScripts (JS_GetRuntime(cx));
 
2641
    }
 
2642
 
 
2643
    DeactivateDebugger();
 
2644
 
 
2645
#ifdef DEBUG
 
2646
    printf ("+++ JavaScript debugging hooks removed.\n");
 
2647
#endif
 
2648
 
 
2649
    nsresult rv;
 
2650
    nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
 
2651
    if (NS_FAILED(rv))
 
2652
        return rv;
 
2653
 
 
2654
    xpc->SetDebugModeWhenPossible(false, true);
 
2655
 
 
2656
    return NS_OK;
 
2657
}
 
2658
 
 
2659
NS_IMETHODIMP
 
2660
jsdService::GetPauseDepth(uint32_t *_rval)
 
2661
{
 
2662
    NS_ENSURE_ARG_POINTER(_rval);
 
2663
    *_rval = mPauseLevel;
 
2664
    return NS_OK;
 
2665
}
 
2666
    
 
2667
NS_IMETHODIMP
 
2668
jsdService::Pause(uint32_t *_rval)
 
2669
{
 
2670
    return DoPause(_rval, false);
 
2671
}
 
2672
 
 
2673
nsresult
 
2674
jsdService::DoPause(uint32_t *_rval, bool internalCall)
 
2675
{
 
2676
    if (!mCx)
 
2677
        return NS_ERROR_NOT_INITIALIZED;
 
2678
 
 
2679
    if (++mPauseLevel == 1) {
 
2680
        JSD_SetErrorReporter (mCx, NULL, NULL);
 
2681
        JSD_ClearThrowHook (mCx);
 
2682
        JSD_ClearInterruptHook (mCx);
 
2683
        JSD_ClearDebuggerHook (mCx);
 
2684
        JSD_ClearDebugBreakHook (mCx);
 
2685
        JSD_ClearTopLevelHook (mCx);
 
2686
        JSD_ClearFunctionHook (mCx);
 
2687
        JSD_DebuggerPause (mCx);
 
2688
 
 
2689
        nsresult rv;
 
2690
        nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
 
2691
        if (NS_FAILED(rv)) return rv;
 
2692
 
 
2693
        if (!internalCall) {
 
2694
            rv = xpc->SetDebugModeWhenPossible(false, false);
 
2695
            NS_ENSURE_SUCCESS(rv, rv);
 
2696
        }
 
2697
    }
 
2698
 
 
2699
    if (_rval)
 
2700
        *_rval = mPauseLevel;
 
2701
 
 
2702
    return NS_OK;
 
2703
}
 
2704
 
 
2705
NS_IMETHODIMP
 
2706
jsdService::UnPause(uint32_t *_rval)
 
2707
{
 
2708
    return DoUnPause(_rval, false);
 
2709
}
 
2710
 
 
2711
nsresult
 
2712
jsdService::DoUnPause(uint32_t *_rval, bool internalCall)
 
2713
{
 
2714
    if (!mCx)
 
2715
        return NS_ERROR_NOT_INITIALIZED;
 
2716
 
 
2717
    if (mPauseLevel == 0)
 
2718
        return NS_ERROR_NOT_AVAILABLE;
 
2719
 
 
2720
    /* check mOn before we muck with this stuff, it's possible the debugger
 
2721
     * was turned off while we were paused.
 
2722
     */
 
2723
    if (--mPauseLevel == 0 && mOn) {
 
2724
        JSD_DebuggerUnpause (mCx);
 
2725
        if (mErrorHook)
 
2726
            JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
 
2727
        if (mThrowHook)
 
2728
            JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
 
2729
        if (mInterruptHook)
 
2730
            JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
 
2731
        if (mDebuggerHook)
 
2732
            JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
 
2733
        if (mDebugHook)
 
2734
            JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
 
2735
        if (mTopLevelHook)
 
2736
            JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
 
2737
        else
 
2738
            JSD_ClearTopLevelHook (mCx);
 
2739
        if (mFunctionHook)
 
2740
            JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
 
2741
        else
 
2742
            JSD_ClearFunctionHook (mCx);
 
2743
 
 
2744
        nsresult rv;
 
2745
        nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
 
2746
        if (NS_FAILED(rv)) return rv;
 
2747
 
 
2748
        if (!internalCall) {
 
2749
            rv = xpc->SetDebugModeWhenPossible(true, false);
 
2750
            NS_ENSURE_SUCCESS(rv, rv);
 
2751
        }
 
2752
    }
 
2753
    
 
2754
    if (_rval)
 
2755
        *_rval = mPauseLevel;
 
2756
 
 
2757
    return NS_OK;
 
2758
}
 
2759
 
 
2760
NS_IMETHODIMP
 
2761
jsdService::EnumerateContexts (jsdIContextEnumerator *enumerator)
 
2762
{
 
2763
    ASSERT_VALID_CONTEXT;
 
2764
    
 
2765
    if (!enumerator)
 
2766
        return NS_OK;
 
2767
    
 
2768
    JSContext *iter = NULL;
 
2769
    JSContext *cx;
 
2770
 
 
2771
    while ((cx = JS_ContextIterator (mRuntime, &iter)))
 
2772
    {
 
2773
        nsCOMPtr<jsdIContext> jsdicx = 
 
2774
            getter_AddRefs(jsdContext::FromPtr(mCx, cx));
 
2775
        if (jsdicx)
 
2776
        {
 
2777
            if (NS_FAILED(enumerator->EnumerateContext(jsdicx)))
 
2778
                break;
 
2779
        }
 
2780
    }
 
2781
 
 
2782
    return NS_OK;
 
2783
}
 
2784
 
 
2785
NS_IMETHODIMP
 
2786
jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator)
 
2787
{
 
2788
    ASSERT_VALID_CONTEXT;
 
2789
    
 
2790
    JSDScript *script;
 
2791
    JSDScript *iter = NULL;
 
2792
    nsresult rv = NS_OK;
 
2793
    
 
2794
    JSD_LockScriptSubsystem(mCx);
 
2795
    while((script = JSD_IterateScripts(mCx, &iter))) {
 
2796
        nsCOMPtr<jsdIScript> jsdis =
 
2797
            getter_AddRefs(jsdScript::FromPtr(mCx, script));
 
2798
        rv = enumerator->EnumerateScript (jsdis);
 
2799
        if (NS_FAILED(rv))
 
2800
            break;
 
2801
    }
 
2802
    JSD_UnlockScriptSubsystem(mCx);
 
2803
 
 
2804
    return rv;
 
2805
}
 
2806
 
 
2807
NS_IMETHODIMP
 
2808
jsdService::GC (void)
 
2809
{
 
2810
    ASSERT_VALID_CONTEXT;
 
2811
    JSRuntime *rt = JSD_GetJSRuntime (mCx);
 
2812
    JS_GC(rt);
 
2813
    return NS_OK;
 
2814
}
 
2815
    
 
2816
NS_IMETHODIMP
 
2817
jsdService::DumpHeap(const nsACString &fileName)
 
2818
{
 
2819
    ASSERT_VALID_CONTEXT;
 
2820
#ifndef DEBUG
 
2821
    return NS_ERROR_NOT_IMPLEMENTED;
 
2822
#else
 
2823
    nsresult rv = NS_OK;
 
2824
    FILE *file = !fileName.IsEmpty() ? fopen(PromiseFlatCString(fileName).get(), "w") : stdout;
 
2825
    if (!file) {
 
2826
        rv = NS_ERROR_FAILURE;
 
2827
    } else {
 
2828
        JSContext *cx = JSD_GetDefaultJSContext (mCx);
 
2829
        if (!JS_DumpHeap(JS_GetRuntime(cx), file, NULL, JSTRACE_OBJECT, NULL, (size_t)-1, NULL))
 
2830
            rv = NS_ERROR_FAILURE;
 
2831
        if (file != stdout)
 
2832
            fclose(file);
 
2833
    }
 
2834
    return rv;
 
2835
#endif
 
2836
}
 
2837
 
 
2838
NS_IMETHODIMP
 
2839
jsdService::ClearProfileData ()
 
2840
{
 
2841
    ASSERT_VALID_CONTEXT;
 
2842
    JSD_ClearAllProfileData (mCx);
 
2843
    return NS_OK;
 
2844
}
 
2845
 
 
2846
NS_IMETHODIMP
 
2847
jsdService::InsertFilter (jsdIFilter *filter, jsdIFilter *after)
 
2848
{
 
2849
    NS_ENSURE_ARG_POINTER (filter);
 
2850
    if (jsds_FindFilter (filter))
 
2851
        return NS_ERROR_INVALID_ARG;
 
2852
 
 
2853
    FilterRecord *rec = PR_NEWZAP (FilterRecord);
 
2854
    if (!rec)
 
2855
        return NS_ERROR_OUT_OF_MEMORY;
 
2856
 
 
2857
    if (!jsds_SyncFilter (rec, filter)) {
 
2858
        PR_Free (rec);
 
2859
        return NS_ERROR_FAILURE;
 
2860
    }
 
2861
    
 
2862
    if (gFilters) {
 
2863
        if (!after) {
 
2864
            /* insert at head of list */
 
2865
            PR_INSERT_LINK(&rec->links, &gFilters->links);
 
2866
            gFilters = rec;
 
2867
        } else {
 
2868
            /* insert somewhere in the list */
 
2869
            FilterRecord *afterRecord = jsds_FindFilter (after);
 
2870
            if (!afterRecord) {
 
2871
                jsds_FreeFilter(rec);
 
2872
                return NS_ERROR_INVALID_ARG;
 
2873
            }
 
2874
            PR_INSERT_AFTER(&rec->links, &afterRecord->links);
 
2875
        }
 
2876
    } else {
 
2877
        if (after) {
 
2878
            /* user asked to insert into the middle of an empty list, bail. */
 
2879
            jsds_FreeFilter(rec);
 
2880
            return NS_ERROR_NOT_INITIALIZED;
 
2881
        }
 
2882
        PR_INIT_CLIST(&rec->links);
 
2883
        gFilters = rec;
 
2884
    }
 
2885
    
 
2886
    return NS_OK;
 
2887
}
 
2888
 
 
2889
NS_IMETHODIMP
 
2890
jsdService::AppendFilter (jsdIFilter *filter)
 
2891
{
 
2892
    NS_ENSURE_ARG_POINTER (filter);
 
2893
    if (jsds_FindFilter (filter))
 
2894
        return NS_ERROR_INVALID_ARG;
 
2895
    FilterRecord *rec = PR_NEWZAP (FilterRecord);
 
2896
 
 
2897
    if (!jsds_SyncFilter (rec, filter)) {
 
2898
        PR_Free (rec);
 
2899
        return NS_ERROR_FAILURE;
 
2900
    }
 
2901
    
 
2902
    if (gFilters) {
 
2903
        PR_INSERT_BEFORE(&rec->links, &gFilters->links);
 
2904
    } else {
 
2905
        PR_INIT_CLIST(&rec->links);
 
2906
        gFilters = rec;
 
2907
    }
 
2908
    
 
2909
    return NS_OK;
 
2910
}
 
2911
 
 
2912
NS_IMETHODIMP
 
2913
jsdService::RemoveFilter (jsdIFilter *filter)
 
2914
{
 
2915
    NS_ENSURE_ARG_POINTER(filter);
 
2916
    FilterRecord *rec = jsds_FindFilter (filter);
 
2917
    if (!rec)
 
2918
        return NS_ERROR_INVALID_ARG;
 
2919
    
 
2920
    if (gFilters == rec) {
 
2921
        gFilters = reinterpret_cast<FilterRecord *>
 
2922
                                   (PR_NEXT_LINK(&rec->links));
 
2923
        /* If we're the only filter left, null out the list head. */
 
2924
        if (gFilters == rec)
 
2925
            gFilters = nullptr;
 
2926
    }
 
2927
 
 
2928
    
 
2929
    PR_REMOVE_LINK(&rec->links);
 
2930
    jsds_FreeFilter (rec);
 
2931
    
 
2932
    return NS_OK;
 
2933
}
 
2934
 
 
2935
NS_IMETHODIMP
 
2936
jsdService::SwapFilters (jsdIFilter *filter_a, jsdIFilter *filter_b)
 
2937
{
 
2938
    NS_ENSURE_ARG_POINTER(filter_a);
 
2939
    NS_ENSURE_ARG_POINTER(filter_b);
 
2940
    
 
2941
    FilterRecord *rec_a = jsds_FindFilter (filter_a);
 
2942
    if (!rec_a)
 
2943
        return NS_ERROR_INVALID_ARG;
 
2944
    
 
2945
    if (filter_a == filter_b) {
 
2946
        /* just a refresh */
 
2947
        if (!jsds_SyncFilter (rec_a, filter_a))
 
2948
            return NS_ERROR_FAILURE;
 
2949
        return NS_OK;
 
2950
    }
 
2951
    
 
2952
    FilterRecord *rec_b = jsds_FindFilter (filter_b);
 
2953
    if (!rec_b) {
 
2954
        /* filter_b is not in the list, replace filter_a with filter_b. */
 
2955
        if (!jsds_SyncFilter (rec_a, filter_b))
 
2956
            return NS_ERROR_FAILURE;
 
2957
    } else {
 
2958
        /* both filters are in the list, swap. */
 
2959
        if (!jsds_SyncFilter (rec_a, filter_b))
 
2960
            return NS_ERROR_FAILURE;
 
2961
        if (!jsds_SyncFilter (rec_b, filter_a))
 
2962
            return NS_ERROR_FAILURE;
 
2963
    }
 
2964
    
 
2965
    return NS_OK;
 
2966
}
 
2967
 
 
2968
NS_IMETHODIMP
 
2969
jsdService::EnumerateFilters (jsdIFilterEnumerator *enumerator) 
 
2970
{
 
2971
    if (!gFilters)
 
2972
        return NS_OK;
 
2973
    
 
2974
    FilterRecord *current = gFilters;
 
2975
    do {
 
2976
        jsds_SyncFilter (current, current->filterObject);
 
2977
        /* SyncFilter failure would be bad, but what would we do about it? */
 
2978
        if (enumerator) {
 
2979
            nsresult rv = enumerator->EnumerateFilter (current->filterObject);
 
2980
            if (NS_FAILED(rv))
 
2981
                return rv;
 
2982
        }
 
2983
        current = reinterpret_cast<FilterRecord *>
 
2984
                                  (PR_NEXT_LINK (&current->links));
 
2985
    } while (current != gFilters);
 
2986
    
 
2987
    return NS_OK;
 
2988
}
 
2989
 
 
2990
NS_IMETHODIMP
 
2991
jsdService::RefreshFilters ()
 
2992
{
 
2993
    return EnumerateFilters(nullptr);
 
2994
}
 
2995
 
 
2996
NS_IMETHODIMP
 
2997
jsdService::ClearFilters ()
 
2998
{
 
2999
    if (!gFilters)
 
3000
        return NS_OK;
 
3001
 
 
3002
    FilterRecord *current = reinterpret_cast<FilterRecord *>
 
3003
                                            (PR_NEXT_LINK (&gFilters->links));
 
3004
    do {
 
3005
        FilterRecord *next = reinterpret_cast<FilterRecord *>
 
3006
                                             (PR_NEXT_LINK (&current->links));
 
3007
        PR_REMOVE_AND_INIT_LINK(&current->links);
 
3008
        jsds_FreeFilter(current);
 
3009
        current = next;
 
3010
    } while (current != gFilters);
 
3011
    
 
3012
    jsds_FreeFilter(current);
 
3013
    gFilters = nullptr;
 
3014
    
 
3015
    return NS_OK;
 
3016
}
 
3017
        
 
3018
NS_IMETHODIMP
 
3019
jsdService::ClearAllBreakpoints (void)
 
3020
{
 
3021
    ASSERT_VALID_CONTEXT;
 
3022
 
 
3023
    JSD_LockScriptSubsystem(mCx);
 
3024
    JSD_ClearAllExecutionHooks (mCx);
 
3025
    JSD_UnlockScriptSubsystem(mCx);
 
3026
    return NS_OK;
 
3027
}
 
3028
 
 
3029
NS_IMETHODIMP
 
3030
jsdService::WrapValue(const JS::Value &value, jsdIValue **_rval)
 
3031
{
 
3032
    ASSERT_VALID_CONTEXT;
 
3033
    JSDValue *jsdv = JSD_NewValue(mCx, value);
 
3034
    if (!jsdv)
 
3035
        return NS_ERROR_FAILURE;
 
3036
    
 
3037
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
3038
    return NS_OK;
 
3039
}
 
3040
 
 
3041
 
 
3042
NS_IMETHODIMP
 
3043
jsdService::EnterNestedEventLoop (jsdINestCallback *callback, uint32_t *_rval)
 
3044
{
 
3045
    // Nesting event queues is a thing of the past.  Now, we just spin the
 
3046
    // current event loop.
 
3047
 
 
3048
    nsresult rv;
 
3049
    nsCOMPtr<nsIJSContextStack> 
 
3050
        stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
 
3051
    if (NS_FAILED(rv))
 
3052
        return rv;
 
3053
    uint32_t nestLevel = ++mNestedLoopLevel;
 
3054
    
 
3055
    nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
 
3056
 
 
3057
    if (NS_SUCCEEDED(stack->Push(nullptr))) {
 
3058
        if (callback) {
 
3059
            DoPause(nullptr, true);
 
3060
            rv = callback->OnNest();
 
3061
            DoUnPause(nullptr, true);
 
3062
        }
 
3063
        
 
3064
        while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) {
 
3065
            if (!NS_ProcessNextEvent(thread))
 
3066
                rv = NS_ERROR_UNEXPECTED;
 
3067
        }
 
3068
 
 
3069
        JSContext* cx;
 
3070
        stack->Pop(&cx);
 
3071
        NS_ASSERTION(cx == nullptr, "JSContextStack mismatch");
 
3072
    }
 
3073
    else
 
3074
        rv = NS_ERROR_FAILURE;
 
3075
    
 
3076
    NS_ASSERTION (mNestedLoopLevel <= nestLevel,
 
3077
                  "nested event didn't unwind properly");
 
3078
    if (mNestedLoopLevel == nestLevel)
 
3079
        --mNestedLoopLevel;
 
3080
 
 
3081
    *_rval = mNestedLoopLevel;
 
3082
    return rv;
 
3083
}
 
3084
 
 
3085
NS_IMETHODIMP
 
3086
jsdService::ExitNestedEventLoop (uint32_t *_rval)
 
3087
{
 
3088
    if (mNestedLoopLevel > 0)
 
3089
        --mNestedLoopLevel;
 
3090
    else
 
3091
        return NS_ERROR_FAILURE;
 
3092
 
 
3093
    *_rval = mNestedLoopLevel;    
 
3094
    return NS_OK;
 
3095
}    
 
3096
 
 
3097
/* hook attribute get/set functions */
 
3098
 
 
3099
NS_IMETHODIMP
 
3100
jsdService::SetErrorHook (jsdIErrorHook *aHook)
 
3101
{
 
3102
    mErrorHook = aHook;
 
3103
 
 
3104
    /* if the debugger isn't initialized, that's all we can do for now.  The
 
3105
     * ActivateDebugger() method will do the rest when the coast is clear.
 
3106
     */
 
3107
    if (!mCx || mPauseLevel)
 
3108
        return NS_OK;
 
3109
 
 
3110
    if (aHook)
 
3111
        JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
 
3112
    else
 
3113
        JSD_SetErrorReporter (mCx, NULL, NULL);
 
3114
 
 
3115
    return NS_OK;
 
3116
}
 
3117
 
 
3118
NS_IMETHODIMP
 
3119
jsdService::GetErrorHook (jsdIErrorHook **aHook)
 
3120
{
 
3121
    *aHook = mErrorHook;
 
3122
    NS_IF_ADDREF(*aHook);
 
3123
    
 
3124
    return NS_OK;
 
3125
}
 
3126
 
 
3127
NS_IMETHODIMP
 
3128
jsdService::SetBreakpointHook (jsdIExecutionHook *aHook)
 
3129
{    
 
3130
    mBreakpointHook = aHook;
 
3131
    return NS_OK;
 
3132
}
 
3133
 
 
3134
NS_IMETHODIMP
 
3135
jsdService::GetBreakpointHook (jsdIExecutionHook **aHook)
 
3136
{   
 
3137
    *aHook = mBreakpointHook;
 
3138
    NS_IF_ADDREF(*aHook);
 
3139
    
 
3140
    return NS_OK;
 
3141
}
 
3142
 
 
3143
NS_IMETHODIMP
 
3144
jsdService::SetDebugHook (jsdIExecutionHook *aHook)
 
3145
{    
 
3146
    mDebugHook = aHook;
 
3147
 
 
3148
    /* if the debugger isn't initialized, that's all we can do for now.  The
 
3149
     * ActivateDebugger() method will do the rest when the coast is clear.
 
3150
     */
 
3151
    if (!mCx || mPauseLevel)
 
3152
        return NS_OK;
 
3153
 
 
3154
    if (aHook)
 
3155
        JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
 
3156
    else
 
3157
        JSD_ClearDebugBreakHook (mCx);
 
3158
    
 
3159
    return NS_OK;
 
3160
}
 
3161
 
 
3162
NS_IMETHODIMP
 
3163
jsdService::GetDebugHook (jsdIExecutionHook **aHook)
 
3164
{   
 
3165
    *aHook = mDebugHook;
 
3166
    NS_IF_ADDREF(*aHook);
 
3167
    
 
3168
    return NS_OK;
 
3169
}
 
3170
 
 
3171
NS_IMETHODIMP
 
3172
jsdService::SetDebuggerHook (jsdIExecutionHook *aHook)
 
3173
{    
 
3174
    mDebuggerHook = aHook;
 
3175
 
 
3176
    /* if the debugger isn't initialized, that's all we can do for now.  The
 
3177
     * ActivateDebugger() method will do the rest when the coast is clear.
 
3178
     */
 
3179
    if (!mCx || mPauseLevel)
 
3180
        return NS_OK;
 
3181
 
 
3182
    if (aHook)
 
3183
        JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
 
3184
    else
 
3185
        JSD_ClearDebuggerHook (mCx);
 
3186
    
 
3187
    return NS_OK;
 
3188
}
 
3189
 
 
3190
NS_IMETHODIMP
 
3191
jsdService::GetDebuggerHook (jsdIExecutionHook **aHook)
 
3192
{   
 
3193
    *aHook = mDebuggerHook;
 
3194
    NS_IF_ADDREF(*aHook);
 
3195
    
 
3196
    return NS_OK;
 
3197
}
 
3198
 
 
3199
NS_IMETHODIMP
 
3200
jsdService::SetInterruptHook (jsdIExecutionHook *aHook)
 
3201
{    
 
3202
    mInterruptHook = aHook;
 
3203
 
 
3204
    /* if the debugger isn't initialized, that's all we can do for now.  The
 
3205
     * ActivateDebugger() method will do the rest when the coast is clear.
 
3206
     */
 
3207
    if (!mCx || mPauseLevel)
 
3208
        return NS_OK;
 
3209
 
 
3210
    if (aHook)
 
3211
        JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
 
3212
    else
 
3213
        JSD_ClearInterruptHook (mCx);
 
3214
    
 
3215
    return NS_OK;
 
3216
}
 
3217
 
 
3218
NS_IMETHODIMP
 
3219
jsdService::GetInterruptHook (jsdIExecutionHook **aHook)
 
3220
{   
 
3221
    *aHook = mInterruptHook;
 
3222
    NS_IF_ADDREF(*aHook);
 
3223
    
 
3224
    return NS_OK;
 
3225
}
 
3226
 
 
3227
NS_IMETHODIMP
 
3228
jsdService::SetScriptHook (jsdIScriptHook *aHook)
 
3229
{    
 
3230
    mScriptHook = aHook;
 
3231
 
 
3232
    /* if the debugger isn't initialized, that's all we can do for now.  The
 
3233
     * ActivateDebugger() method will do the rest when the coast is clear.
 
3234
     */
 
3235
    if (!mCx || mPauseLevel)
 
3236
        return NS_OK;
 
3237
    
 
3238
    if (aHook)
 
3239
        JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
 
3240
    /* we can't unset it if !aHook, because we still need to see script
 
3241
     * deletes in order to Release the jsdIScripts held in JSDScript
 
3242
     * private data. */
 
3243
    return NS_OK;
 
3244
}
 
3245
 
 
3246
NS_IMETHODIMP
 
3247
jsdService::GetScriptHook (jsdIScriptHook **aHook)
 
3248
{   
 
3249
    *aHook = mScriptHook;
 
3250
    NS_IF_ADDREF(*aHook);
 
3251
    
 
3252
    return NS_OK;
 
3253
}
 
3254
 
 
3255
NS_IMETHODIMP
 
3256
jsdService::SetThrowHook (jsdIExecutionHook *aHook)
 
3257
{    
 
3258
    mThrowHook = aHook;
 
3259
 
 
3260
    /* if the debugger isn't initialized, that's all we can do for now.  The
 
3261
     * ActivateDebugger() method will do the rest when the coast is clear.
 
3262
     */
 
3263
    if (!mCx || mPauseLevel)
 
3264
        return NS_OK;
 
3265
 
 
3266
    if (aHook)
 
3267
        JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
 
3268
    else
 
3269
        JSD_ClearThrowHook (mCx);
 
3270
    
 
3271
    return NS_OK;
 
3272
}
 
3273
 
 
3274
NS_IMETHODIMP
 
3275
jsdService::GetThrowHook (jsdIExecutionHook **aHook)
 
3276
{   
 
3277
    *aHook = mThrowHook;
 
3278
    NS_IF_ADDREF(*aHook);
 
3279
    
 
3280
    return NS_OK;
 
3281
}
 
3282
 
 
3283
NS_IMETHODIMP
 
3284
jsdService::SetTopLevelHook (jsdICallHook *aHook)
 
3285
{    
 
3286
    mTopLevelHook = aHook;
 
3287
 
 
3288
    /* if the debugger isn't initialized, that's all we can do for now.  The
 
3289
     * ActivateDebugger() method will do the rest when the coast is clear.
 
3290
     */
 
3291
    if (!mCx || mPauseLevel)
 
3292
        return NS_OK;
 
3293
 
 
3294
    if (aHook)
 
3295
        JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
 
3296
    else
 
3297
        JSD_ClearTopLevelHook (mCx);
 
3298
    
 
3299
    return NS_OK;
 
3300
}
 
3301
 
 
3302
NS_IMETHODIMP
 
3303
jsdService::GetTopLevelHook (jsdICallHook **aHook)
 
3304
{   
 
3305
    *aHook = mTopLevelHook;
 
3306
    NS_IF_ADDREF(*aHook);
 
3307
    
 
3308
    return NS_OK;
 
3309
}
 
3310
 
 
3311
NS_IMETHODIMP
 
3312
jsdService::SetFunctionHook (jsdICallHook *aHook)
 
3313
{    
 
3314
    mFunctionHook = aHook;
 
3315
 
 
3316
    /* if the debugger isn't initialized, that's all we can do for now.  The
 
3317
     * ActivateDebugger() method will do the rest when the coast is clear.
 
3318
     */
 
3319
    if (!mCx || mPauseLevel)
 
3320
        return NS_OK;
 
3321
 
 
3322
    if (aHook)
 
3323
        JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
 
3324
    else
 
3325
        JSD_ClearFunctionHook (mCx);
 
3326
    
 
3327
    return NS_OK;
 
3328
}
 
3329
 
 
3330
NS_IMETHODIMP
 
3331
jsdService::GetFunctionHook (jsdICallHook **aHook)
 
3332
{   
 
3333
    *aHook = mFunctionHook;
 
3334
    NS_IF_ADDREF(*aHook);
 
3335
    
 
3336
    return NS_OK;
 
3337
}
 
3338
 
 
3339
/* virtual */
 
3340
jsdService::~jsdService()
 
3341
{
 
3342
    ClearFilters();
 
3343
    mErrorHook = nullptr;
 
3344
    mBreakpointHook = nullptr;
 
3345
    mDebugHook = nullptr;
 
3346
    mDebuggerHook = nullptr;
 
3347
    mInterruptHook = nullptr;
 
3348
    mScriptHook = nullptr;
 
3349
    mThrowHook = nullptr;
 
3350
    mTopLevelHook = nullptr;
 
3351
    mFunctionHook = nullptr;
 
3352
    Off();
 
3353
    gJsds = nullptr;
 
3354
}
 
3355
 
 
3356
jsdService *
 
3357
jsdService::GetService ()
 
3358
{
 
3359
    if (!gJsds)
 
3360
        gJsds = new jsdService();
 
3361
        
 
3362
    NS_IF_ADDREF(gJsds);
 
3363
    return gJsds;
 
3364
}
 
3365
 
 
3366
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService, jsdService::GetService)
 
3367
 
 
3368
/* app-start observer.  turns on the debugger at app-start.  this is inserted
 
3369
 * and/or removed from the app-start category by the jsdService::initAtStartup
 
3370
 * property.
 
3371
 */
 
3372
class jsdASObserver MOZ_FINAL : public nsIObserver
 
3373
{
 
3374
  public:
 
3375
    NS_DECL_ISUPPORTS
 
3376
    NS_DECL_NSIOBSERVER
 
3377
 
 
3378
    jsdASObserver () {}    
 
3379
};
 
3380
 
 
3381
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver, nsIObserver)
 
3382
 
 
3383
NS_IMETHODIMP
 
3384
jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic,
 
3385
                        const PRUnichar *aData)
 
3386
{
 
3387
    nsresult rv;
 
3388
 
 
3389
    // Hmm.  Why is the app-startup observer called multiple times?
 
3390
    //NS_ASSERTION(!gJsds, "app startup observer called twice");
 
3391
    nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
 
3392
    if (NS_FAILED(rv))
 
3393
        return rv;
 
3394
 
 
3395
    bool on;
 
3396
    rv = jsds->GetIsOn(&on);
 
3397
    if (NS_FAILED(rv) || on)
 
3398
        return rv;
 
3399
    
 
3400
    nsCOMPtr<nsIJSRuntimeService> rts = do_GetService(NS_JSRT_CTRID, &rv);
 
3401
    if (NS_FAILED(rv))
 
3402
        return rv;    
 
3403
 
 
3404
    JSRuntime *rt;
 
3405
    rts->GetRuntime (&rt);
 
3406
    if (NS_FAILED(rv))
 
3407
        return rv;
 
3408
 
 
3409
    rv = jsds->ActivateDebugger(rt);
 
3410
    if (NS_FAILED(rv))
 
3411
        return rv;
 
3412
    
 
3413
    return NS_OK;
 
3414
}
 
3415
 
 
3416
NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
 
3417
NS_DEFINE_NAMED_CID(JSDSERVICE_CID);
 
3418
NS_DEFINE_NAMED_CID(JSDASO_CID);
 
3419
 
 
3420
static const mozilla::Module::CIDEntry kJSDCIDs[] = {
 
3421
    { &kJSDSERVICE_CID, false, NULL, jsdServiceConstructor },
 
3422
    { &kJSDASO_CID, false, NULL, jsdASObserverConstructor },
 
3423
    { NULL }
 
3424
};
 
3425
 
 
3426
static const mozilla::Module::ContractIDEntry kJSDContracts[] = {
 
3427
    { jsdServiceCtrID, &kJSDSERVICE_CID },
 
3428
    { jsdARObserverCtrID, &kJSDASO_CID },
 
3429
    { NULL }
 
3430
};
 
3431
 
 
3432
static const mozilla::Module kJSDModule = {
 
3433
    mozilla::Module::kVersion,
 
3434
    kJSDCIDs,
 
3435
    kJSDContracts
 
3436
};
 
3437
 
 
3438
NSMODULE_DEFN(JavaScript_Debugger) = &kJSDModule;
 
3439
 
 
3440
/********************************************************************************
 
3441
 ********************************************************************************
 
3442
 * graveyard
 
3443
 */
 
3444
 
 
3445
#if 0
 
3446
/* Thread States */
 
3447
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState, jsdIThreadState); 
 
3448
 
 
3449
NS_IMETHODIMP
 
3450
jsdThreadState::GetJSDContext(JSDContext **_rval)
 
3451
{
 
3452
    *_rval = mCx;
 
3453
    return NS_OK;
 
3454
}
 
3455
 
 
3456
NS_IMETHODIMP
 
3457
jsdThreadState::GetJSDThreadState(JSDThreadState **_rval)
 
3458
{
 
3459
    *_rval = mThreadState;
 
3460
    return NS_OK;
 
3461
}
 
3462
 
 
3463
NS_IMETHODIMP
 
3464
jsdThreadState::GetFrameCount (uint32_t *_rval)
 
3465
{
 
3466
    *_rval = JSD_GetCountOfStackFrames (mCx, mThreadState);
 
3467
    return NS_OK;
 
3468
}
 
3469
 
 
3470
NS_IMETHODIMP
 
3471
jsdThreadState::GetTopFrame (jsdIStackFrame **_rval)
 
3472
{
 
3473
    JSDStackFrameInfo *sfi = JSD_GetStackFrame (mCx, mThreadState);
 
3474
    
 
3475
    *_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
 
3476
    return NS_OK;
 
3477
}
 
3478
 
 
3479
NS_IMETHODIMP
 
3480
jsdThreadState::GetPendingException(jsdIValue **_rval)
 
3481
{
 
3482
    JSDValue *jsdv = JSD_GetException (mCx, mThreadState);
 
3483
    
 
3484
    *_rval = jsdValue::FromPtr (mCx, jsdv);
 
3485
    return NS_OK;
 
3486
}
 
3487
 
 
3488
NS_IMETHODIMP
 
3489
jsdThreadState::SetPendingException(jsdIValue *aException)
 
3490
{
 
3491
    JSDValue *jsdv;
 
3492
    
 
3493
    nsresult rv = aException->GetJSDValue (&jsdv);
 
3494
    if (NS_FAILED(rv))
 
3495
        return NS_ERROR_FAILURE;
 
3496
    
 
3497
    if (!JSD_SetException (mCx, mThreadState, jsdv))
 
3498
        return NS_ERROR_FAILURE;
 
3499
 
 
3500
    return NS_OK;
 
3501
}
 
3502
 
 
3503
#endif