1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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/. */
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"
23
#include "nsReadableUtils.h"
25
#include "nsCycleCollectionParticipant.h"
26
#include "mozilla/Attributes.h"
28
/* XXX DOM dependency */
29
#include "nsIScriptContext.h"
30
#include "nsIJSContextStack.h"
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).
37
#undef CAUTIOUS_SCRIPTHOOK
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)}
45
# define DEBUG_CREATE(name, count)
46
# define DEBUG_DESTROY(name, count)
49
#define ASSERT_VALID_CONTEXT { if (!mCx) return NS_ERROR_NOT_AVAILABLE; }
50
#define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; }
52
#define JSDSERVICE_CID \
53
{ /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */ \
57
{0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \
61
{ /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */ \
65
{0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \
68
#define JSDS_MAJOR_VERSION 1
69
#define JSDS_MINOR_VERSION 2
71
#define NS_CATMAN_CTRID "@mozilla.org/categorymanager;1"
72
#define NS_JSRT_CTRID "@mozilla.org/js/xpc/RuntimeService;1"
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"
80
jsds_GCSliceCallbackProc (JSRuntime *rt, js::GCProgress progress, const js::GCDescription &desc);
82
/*******************************************************************************
84
******************************************************************************/
86
const char implementationString[] = "Mozilla JavaScript Debugger Service";
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";
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;
100
static jsdService *gJsds = 0;
101
static js::GCSliceCallback gPrevGCSliceCallback = jsds_GCSliceCallbackProc;
102
static bool gGCRunning = false;
104
static struct DeadScript {
108
} *gDeadScripts = nullptr;
118
static struct FilterRecord {
120
jsdIFilter *filterObject;
122
nsCString urlPattern;
123
PatternType patternType;
126
} *gFilters = nullptr;
128
static struct LiveEphemeral *gLiveValues = nullptr;
129
static struct LiveEphemeral *gLiveProperties = nullptr;
130
static struct LiveEphemeral *gLiveContexts = nullptr;
131
static struct LiveEphemeral *gLiveStackFrames = nullptr;
133
/*******************************************************************************
134
* utility functions for ephemeral lists
135
*******************************************************************************/
136
already_AddRefed<jsdIEphemeral>
137
jsds_FindEphemeral (LiveEphemeral **listHead, void *key)
142
LiveEphemeral *lv_record =
143
reinterpret_cast<LiveEphemeral *>
144
(PR_NEXT_LINK(&(*listHead)->links));
147
if (lv_record->key == key)
149
NS_IF_ADDREF(lv_record->value);
150
return lv_record->value;
152
lv_record = reinterpret_cast<LiveEphemeral *>
153
(PR_NEXT_LINK(&lv_record->links));
155
while (lv_record != *listHead);
161
jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
163
LiveEphemeral *lv_record =
164
reinterpret_cast<LiveEphemeral *>
165
(PR_NEXT_LINK(&(*listHead)->links));
168
LiveEphemeral *next =
169
reinterpret_cast<LiveEphemeral *>
170
(PR_NEXT_LINK(&lv_record->links));
171
lv_record->value->Invalidate();
178
jsds_InsertEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
181
/* if the list exists, add to it */
182
PR_APPEND_LINK(&item->links, &(*listHead)->links);
184
/* otherwise create the list */
185
PR_INIT_CLIST(&item->links);
191
jsds_RemoveEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
193
LiveEphemeral *next = reinterpret_cast<LiveEphemeral *>
194
(PR_NEXT_LINK(&item->links));
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?");
204
else if (item == *listHead)
206
/* otherwise, if we're currently the list head, change it */
210
PR_REMOVE_AND_INIT_LINK(&item->links);
213
/*******************************************************************************
214
* utility functions for filters
215
*******************************************************************************/
217
jsds_FreeFilter (FilterRecord *rec)
219
NS_IF_RELEASE (rec->filterObject);
223
/* copies appropriate |filter| attributes into |rec|.
224
* False return indicates failure, the contents of |rec| will not be changed.
227
jsds_SyncFilter (FilterRecord *rec, jsdIFilter *filter)
229
NS_ASSERTION (rec, "jsds_SyncFilter without rec");
230
NS_ASSERTION (filter, "jsds_SyncFilter without filter");
232
JSObject *glob_proper = nullptr;
233
nsCOMPtr<nsISupports> glob;
234
nsresult rv = filter->GetGlobalObject(getter_AddRefs(glob));
238
nsCOMPtr<nsIScriptGlobalObject> nsiglob = do_QueryInterface(glob);
240
glob_proper = nsiglob->GetGlobalJSObject();
244
rv = filter->GetStartLine(&startLine);
249
rv = filter->GetStartLine(&endLine);
253
nsCAutoString urlPattern;
254
rv = filter->GetUrlPattern (urlPattern);
258
uint32_t len = urlPattern.Length();
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);
265
if (urlPattern[len - 2] == '*') {
266
/* pattern is in the format "*foo*", overwrite the final * with
268
urlPattern.Truncate(len - 2);
269
rec->patternType = ptContains;
271
/* pattern is in the format "*foo", just make a note of the
273
rec->patternType = ptEndsWith;
275
} else if (urlPattern[len - 1] == '*') {
276
/* pattern is in the format "foo*", overwrite the final * with a
278
urlPattern.Truncate(len - 1);
279
rec->patternType = ptStartsWith;
281
/* pattern is in the format "foo". */
282
rec->patternType = ptEquals;
285
rec->patternType = ptIgnore;
288
/* we got everything we need without failing, now copy it into rec. */
290
if (rec->filterObject != filter) {
291
NS_IF_RELEASE(rec->filterObject);
293
rec->filterObject = filter;
296
rec->glob = glob_proper;
298
rec->startLine = startLine;
299
rec->endLine = endLine;
301
rec->urlPattern = urlPattern;
308
jsds_FindFilter (jsdIFilter *filter)
313
FilterRecord *current = gFilters;
316
if (current->filterObject == filter)
318
current = reinterpret_cast<FilterRecord *>
319
(PR_NEXT_LINK(¤t->links));
320
} while (current != gFilters);
325
/* returns true if the hook should be executed. */
327
jsds_FilterHook (JSDContext *jsdc, JSDThreadState *state)
329
JSContext *cx = JSD_GetJSContext (jsdc, state);
330
void *glob = static_cast<void *>(JS_GetGlobalObject (cx));
333
NS_WARNING("No global in threadstate");
337
JSDStackFrameInfo *frame = JSD_GetStackFrame (jsdc, state);
340
NS_WARNING("No frame in threadstate");
344
JSDScript *script = JSD_GetScriptForStackFrame (jsdc, state, frame);
348
uintptr_t pc = JSD_GetPCForStackFrame (jsdc, state, frame);
350
nsCString url(JSD_GetScriptFilename (jsdc, script));
352
NS_WARNING ("Script with no filename");
359
uint32_t currentLine = JSD_GetClosestLine (jsdc, script, pc);
361
FilterRecord *currentFilter = gFilters;
368
currentFilter->filterObject->GetFlags(&flags);
369
NS_ASSERTION(NS_SUCCEEDED(rv), "Error getting flags for filter");
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);
388
nsCString urlPattern = currentFilter->urlPattern;
389
uint32_t patternLength = urlPattern.Length();
390
if (len >= patternLength) {
391
switch (currentFilter->patternType) {
393
if (urlPattern.Equals(url))
394
return !!(flags & jsdIFilter::FLAG_PASS);
397
if (urlPattern.Equals(Substring(url, 0, patternLength)))
398
return !!(flags & jsdIFilter::FLAG_PASS);
401
if (urlPattern.Equals(Substring(url, len - patternLength)))
402
return !!(flags & jsdIFilter::FLAG_PASS);
406
nsACString::const_iterator start, end;
407
url.BeginReading(start);
409
if (FindInReadable(currentFilter->urlPattern, start, end))
410
return !!(flags & jsdIFilter::FLAG_PASS);
414
NS_ERROR("Invalid pattern type");
419
currentFilter = reinterpret_cast<FilterRecord *>
420
(PR_NEXT_LINK(¤tFilter->links));
421
} while (currentFilter != gFilters);
427
/*******************************************************************************
429
*******************************************************************************/
432
jsds_NotifyPendingDeadScripts (JSRuntime *rt)
434
jsdService *jsds = gJsds;
436
nsCOMPtr<jsdIScriptHook> hook;
439
jsds->GetScriptHook (getter_AddRefs(hook));
440
jsds->DoPause(nullptr, true);
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;
455
/* tell the user this script has been destroyed */
456
#ifdef CAUTIOUS_SCRIPTHOOK
459
hook->OnScriptDestroyed (ds->script);
460
#ifdef CAUTIOUS_SCRIPTHOOK
465
/* take it out of the circular list */
466
PR_REMOVE_LINK(&ds->links);
468
/* addref came from the FromPtr call in jsds_ScriptHookProc */
469
NS_RELEASE(ds->script);
470
/* free the struct! */
475
jsds->DoUnPause(nullptr, true);
481
jsds_GCSliceCallbackProc (JSRuntime *rt, js::GCProgress progress, const js::GCDescription &desc)
483
if (progress == js::GC_CYCLE_END || progress == js::GC_SLICE_END) {
484
NS_ASSERTION(gGCRunning, "GC slice callback was missed");
487
jsds_NotifyPendingDeadScripts (rt);
491
NS_ASSERTION(!gGCRunning, "should not re-enter GC");
495
if (gPrevGCSliceCallback)
496
(*gPrevGCSliceCallback)(rt, progress, desc);
500
jsds_ErrorHookProc (JSDContext *jsdc, JSContext *cx, const char *message,
501
JSErrorReport *report, void *callerdata)
503
static bool running = false;
505
nsCOMPtr<jsdIErrorHook> hook;
506
gJsds->GetErrorHook(getter_AddRefs(hook));
508
return JSD_ERROR_REPORTER_PASS_ALONG;
511
return JSD_ERROR_REPORTER_PASS_ALONG;
515
nsCOMPtr<jsdIValue> val;
516
if (JS_IsExceptionPending(cx)) {
518
JS_GetPendingException(cx, &jv);
519
JSDValue *jsdv = JSD_NewValue (jsdc, jv);
520
val = getter_AddRefs(jsdValue::FromPtr(jsdc, jsdv));
523
nsCAutoString fileName;
530
fileName.Assign(report->filename);
531
line = report->lineno;
532
pos = report->tokenptr - report->linebuf;
533
flags = report->flags;
534
errnum = report->errorNumber;
544
gJsds->DoPause(nullptr, true);
545
hook->OnError (nsDependentCString(message), fileName, line, pos, flags, errnum, val, &rval);
546
gJsds->DoUnPause(nullptr, true);
550
return JSD_ERROR_REPORTER_DEBUG;
552
return JSD_ERROR_REPORTER_PASS_ALONG;
556
jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
557
unsigned type, void* callerdata)
559
nsCOMPtr<jsdICallHook> hook;
563
case JSD_HOOK_TOPLEVEL_START:
564
case JSD_HOOK_TOPLEVEL_END:
565
gJsds->GetTopLevelHook(getter_AddRefs(hook));
568
case JSD_HOOK_FUNCTION_CALL:
569
case JSD_HOOK_FUNCTION_RETURN:
570
gJsds->GetFunctionHook(getter_AddRefs(hook));
574
NS_ASSERTION (0, "Unknown hook type.");
580
if (!jsds_FilterHook (jsdc, jsdthreadstate))
583
JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
584
nsCOMPtr<jsdIStackFrame> frame =
585
getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
587
gJsds->DoPause(nullptr, true);
588
hook->OnCall(frame, type);
589
gJsds->DoUnPause(nullptr, true);
590
jsdStackFrame::InvalidateAll();
596
jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
597
unsigned type, void* callerdata, jsval* rval)
599
nsCOMPtr<jsdIExecutionHook> hook(0);
600
uint32_t hook_rv = JSD_HOOK_RETURN_CONTINUE;
601
nsCOMPtr<jsdIValue> js_rv;
605
case JSD_HOOK_INTERRUPTED:
606
gJsds->GetInterruptHook(getter_AddRefs(hook));
608
case JSD_HOOK_DEBUG_REQUESTED:
609
gJsds->GetDebugHook(getter_AddRefs(hook));
611
case JSD_HOOK_DEBUGGER_KEYWORD:
612
gJsds->GetDebuggerHook(getter_AddRefs(hook));
614
case JSD_HOOK_BREAKPOINT:
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. */
620
gJsds->GetPauseDepth(&level);
622
gJsds->GetBreakpointHook(getter_AddRefs(hook));
627
hook_rv = JSD_HOOK_RETURN_CONTINUE_THROW;
628
gJsds->GetThrowHook(getter_AddRefs(hook));
630
JSDValue *jsdv = JSD_GetException (jsdc, jsdthreadstate);
631
js_rv = getter_AddRefs(jsdValue::FromPtr (jsdc, jsdv));
636
NS_ASSERTION (0, "Unknown hook type.");
642
if (!jsds_FilterHook (jsdc, jsdthreadstate))
643
return JSD_HOOK_RETURN_CONTINUE;
645
JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
646
nsCOMPtr<jsdIStackFrame> frame =
647
getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
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);
654
NS_IF_RELEASE(inout_rv);
655
gJsds->DoUnPause(nullptr, true);
656
jsdStackFrame::InvalidateAll();
658
if (hook_rv == JSD_HOOK_RETURN_RET_WITH_VAL ||
659
hook_rv == JSD_HOOK_RETURN_THROW_WITH_VAL) {
663
if (NS_SUCCEEDED(js_rv->GetJSDValue (&jsdv)))
664
*rval = JSD_GetValueWrappedJSVal(jsdc, jsdv);
672
jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating,
675
#ifdef CAUTIOUS_SCRIPTHOOK
676
JSContext *cx = JSD_GetDefaultJSContext(jsdc);
677
JSRuntime *rt = JS_GetRuntime(cx);
681
nsCOMPtr<jsdIScriptHook> hook;
682
gJsds->GetScriptHook(getter_AddRefs(hook));
684
/* a script is being created */
686
/* nobody cares, just exit */
690
nsCOMPtr<jsdIScript> script =
691
getter_AddRefs(jsdScript::FromPtr(jsdc, jsdscript));
692
#ifdef CAUTIOUS_SCRIPTHOOK
695
gJsds->DoPause(nullptr, true);
696
hook->OnScriptCreated (script);
697
gJsds->DoUnPause(nullptr, true);
698
#ifdef CAUTIOUS_SCRIPTHOOK
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));
713
nsCOMPtr<jsdIScriptHook> hook;
714
gJsds->GetScriptHook(getter_AddRefs(hook));
718
/* if GC *isn't* running, we can tell the user about the script
720
#ifdef CAUTIOUS_SCRIPTHOOK
724
gJsds->DoPause(nullptr, true);
725
hook->OnScriptDestroyed (jsdis);
726
gJsds->DoUnPause(nullptr, true);
727
#ifdef CAUTIOUS_SCRIPTHOOK
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);
736
return; /* NS_ERROR_OUT_OF_MEMORY */
740
NS_ADDREF(ds->script);
742
/* if the queue exists, add to it */
743
PR_APPEND_LINK(&ds->links, &gDeadScripts->links);
745
/* otherwise create the queue */
746
PR_INIT_CLIST(&ds->links);
753
/*******************************************************************************
754
* reflected jsd data structures
755
*******************************************************************************/
759
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral);
762
jsdContext::GetJSDContext(JSDContext **_rval)
770
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject, jsdIObject)
773
jsdObject::GetJSDContext(JSDContext **_rval)
780
jsdObject::GetJSDObject(JSDObject **_rval)
787
jsdObject::GetCreatorURL(nsACString &_rval)
789
_rval.Assign(JSD_GetObjectNewURL(mCx, mObject));
794
jsdObject::GetCreatorLine(uint32_t *_rval)
796
*_rval = JSD_GetObjectNewLineNumber(mCx, mObject);
801
jsdObject::GetConstructorURL(nsACString &_rval)
803
_rval.Assign(JSD_GetObjectConstructorURL(mCx, mObject));
808
jsdObject::GetConstructorLine(uint32_t *_rval)
810
*_rval = JSD_GetObjectConstructorLineNumber(mCx, mObject);
815
jsdObject::GetValue(jsdIValue **_rval)
817
JSDValue *jsdv = JSD_GetValueForObject (mCx, mObject);
819
*_rval = jsdValue::FromPtr (mCx, jsdv);
824
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty, jsdIProperty, jsdIEphemeral)
826
jsdProperty::jsdProperty (JSDContext *aCx, JSDProperty *aProperty) :
827
mCx(aCx), mProperty(aProperty)
829
DEBUG_CREATE ("jsdProperty", gPropertyCount);
830
mValid = (aCx && aProperty);
831
mLiveListEntry.value = this;
832
jsds_InsertEphemeral (&gLiveProperties, &mLiveListEntry);
835
jsdProperty::~jsdProperty ()
837
DEBUG_DESTROY ("jsdProperty", gPropertyCount);
843
jsdProperty::Invalidate()
845
ASSERT_VALID_EPHEMERAL;
847
jsds_RemoveEphemeral (&gLiveProperties, &mLiveListEntry);
848
JSD_DropProperty (mCx, mProperty);
853
jsdProperty::InvalidateAll()
856
jsds_InvalidateAllEphemerals (&gLiveProperties);
860
jsdProperty::GetJSDContext(JSDContext **_rval)
867
jsdProperty::GetJSDProperty(JSDProperty **_rval)
874
jsdProperty::GetIsValid(bool *_rval)
881
jsdProperty::GetAlias(jsdIValue **_rval)
883
JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
885
*_rval = jsdValue::FromPtr (mCx, jsdv);
890
jsdProperty::GetFlags(uint32_t *_rval)
892
*_rval = JSD_GetPropertyFlags (mCx, mProperty);
897
jsdProperty::GetName(jsdIValue **_rval)
899
JSDValue *jsdv = JSD_GetPropertyName (mCx, mProperty);
901
*_rval = jsdValue::FromPtr (mCx, jsdv);
906
jsdProperty::GetValue(jsdIValue **_rval)
908
JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
910
*_rval = jsdValue::FromPtr (mCx, jsdv);
915
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
918
AssignToJSString(nsACString *x, JSString *str)
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);
934
jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(false),
945
DEBUG_CREATE ("jsdScript", gScriptCount);
948
/* copy the script's information now, so we have it later, when it
950
JSD_LockScriptSubsystem(mCx);
951
mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
952
mFunctionName = new nsCString();
954
JSString *str = JSD_GetScriptFunctionId(mCx, mScript);
956
AssignToJSString(mFunctionName, str);
958
mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
959
mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
960
mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
961
JSD_UnlockScriptSubsystem(mCx);
967
jsdScript::~jsdScript ()
969
DEBUG_DESTROY ("jsdScript", gScriptCount);
971
delete mFunctionName;
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.");
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.
988
jsdScript::CreatePPLineMap()
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 */
1004
JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
1005
nargs = JS_GetFunctionArgumentCount(cx, fun);
1008
jsstr = JS_DecompileFunctionBody (cx, fun, 4);
1012
if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
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)))
1026
script = JSD_GetJSScript(mCx, mScript);
1030
JS::AutoEnterScriptCompartment ac;
1031
if (!ac.enter(cx, script))
1034
jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
1038
if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
1042
JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
1043
script = JS_CompileUCScript (cx, obj, chars, length, "x-jsd:ppbuffer?type=script", 1);
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;
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;
1067
if (scriptExtent != lineMapSize) {
1069
static_cast<PCMapEntry *>
1070
(PR_Realloc(mPPLineMap = lineMap,
1071
lineMapSize * sizeof(PCMapEntry)));
1073
PR_Free(mPPLineMap);
1079
mPCMapSize = lineMapSize;
1080
return mPPLineMap = lineMap;
1084
jsdScript::PPPcToLine (uint32_t aPC)
1086
if (!mPPLineMap && !CreatePPLineMap())
1089
for (i = 1; i < mPCMapSize; ++i) {
1090
if (mPPLineMap[i].pc > aPC)
1091
return mPPLineMap[i - 1].line;
1094
return mPPLineMap[mPCMapSize - 1].line;
1098
jsdScript::PPLineToPc (uint32_t aLine)
1100
if (!mPPLineMap && !CreatePPLineMap())
1103
for (i = 1; i < mPCMapSize; ++i) {
1104
if (mPPLineMap[i].line > aLine)
1105
return mPPLineMap[i - 1].pc;
1108
return mPPLineMap[mPCMapSize - 1].pc;
1112
jsdScript::GetJSDContext(JSDContext **_rval)
1114
ASSERT_VALID_EPHEMERAL;
1120
jsdScript::GetJSDScript(JSDScript **_rval)
1122
ASSERT_VALID_EPHEMERAL;
1128
jsdScript::GetVersion (int32_t *_rval)
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));
1141
jsdScript::GetTag(uint32_t *_rval)
1144
mTag = ++jsdScript::LastTag;
1151
jsdScript::Invalidate()
1153
ASSERT_VALID_EPHEMERAL;
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!");
1161
JSD_SetScriptPrivate(mScript, NULL);
1166
jsdScript::InvalidateAll ()
1169
if (NS_FAILED(gJsds->GetJSDContext (&cx)))
1173
JSDScript *iter = NULL;
1175
JSD_LockScriptSubsystem(cx);
1176
while((script = JSD_IterateScripts(cx, &iter)) != NULL) {
1177
nsCOMPtr<jsdIScript> jsdis =
1178
static_cast<jsdIScript *>(JSD_GetScriptPrivate(script));
1180
jsdis->Invalidate();
1182
JSD_UnlockScriptSubsystem(cx);
1186
jsdScript::GetIsValid(bool *_rval)
1193
jsdScript::SetFlags(uint32_t flags)
1195
ASSERT_VALID_EPHEMERAL;
1196
JSD_SetScriptFlags(mCx, mScript, flags);
1201
jsdScript::GetFlags(uint32_t *_rval)
1203
ASSERT_VALID_EPHEMERAL;
1204
*_rval = JSD_GetScriptFlags(mCx, mScript);
1209
jsdScript::GetFileName(nsACString &_rval)
1211
_rval.Assign(*mFileName);
1216
jsdScript::GetFunctionName(nsACString &_rval)
1218
_rval.Assign(*mFunctionName);
1223
jsdScript::GetParameterNames(uint32_t* count, PRUnichar*** paramNames)
1225
ASSERT_VALID_EPHEMERAL;
1226
JSContext *cx = JSD_GetDefaultJSContext (mCx);
1228
NS_WARNING("No default context !?");
1229
return NS_ERROR_FAILURE;
1231
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
1234
*paramNames = nullptr;
1238
JSAutoRequest ar(cx);
1239
JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
1242
if (!JS_FunctionHasLocalNames(cx, fun) ||
1243
(nargs = JS_GetFunctionArgumentCount(cx, fun)) == 0) {
1245
*paramNames = nullptr;
1250
static_cast<PRUnichar**>(NS_Alloc(nargs * sizeof(PRUnichar*)));
1252
return NS_ERROR_OUT_OF_MEMORY;
1255
uintptr_t *names = JS_GetFunctionLocalNameArray(cx, fun, &mark);
1258
return NS_ERROR_OUT_OF_MEMORY;
1261
nsresult rv = NS_OK;
1262
for (unsigned i = 0; i < nargs; ++i) {
1263
JSAtom *atom = JS_LocalNameToAtom(names[i]);
1267
JSString *str = JS_AtomKey(atom);
1268
ret[i] = NS_strndup(JS_GetInternedStringChars(str), JS_GetStringLength(str));
1270
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
1271
rv = NS_ERROR_OUT_OF_MEMORY;
1276
JS_ReleaseFunctionLocalNameArray(cx, mark);
1285
jsdScript::GetFunctionObject(jsdIValue **_rval)
1287
JSFunction *fun = JSD_GetJSFunction(mCx, mScript);
1289
return NS_ERROR_NOT_AVAILABLE;
1291
JSObject *obj = JS_GetFunctionObject(fun);
1293
return NS_ERROR_FAILURE;
1296
if (NS_FAILED(gJsds->GetJSDContext (&cx)))
1297
return NS_ERROR_NOT_INITIALIZED;
1299
JSDValue *jsdv = JSD_NewValue(cx, OBJECT_TO_JSVAL(obj));
1301
return NS_ERROR_OUT_OF_MEMORY;
1303
*_rval = jsdValue::FromPtr(cx, jsdv);
1305
JSD_DropValue(cx, jsdv);
1306
return NS_ERROR_OUT_OF_MEMORY;
1313
jsdScript::GetFunctionSource(nsAString & aFunctionSource)
1315
ASSERT_VALID_EPHEMERAL;
1316
JSContext *cx = JSD_GetDefaultJSContext (mCx);
1318
NS_WARNING("No default context !?");
1319
return NS_ERROR_FAILURE;
1321
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
1323
JSAutoRequest ar(cx);
1326
mozilla::Maybe<JSAutoCompartment> ac;
1327
JS::AutoEnterScriptCompartment asc;
1329
ac.construct(cx, JS_GetFunctionObject(fun));
1330
jsstr = JS_DecompileFunction (cx, fun, 4);
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);
1338
return NS_ERROR_FAILURE;
1341
const jschar *chars = JS_GetStringCharsZAndLength(cx, jsstr, &length);
1343
return NS_ERROR_FAILURE;
1345
aFunctionSource = nsDependentString(chars, length);
1350
jsdScript::GetBaseLineNumber(uint32_t *_rval)
1352
*_rval = mBaseLineNumber;
1357
jsdScript::GetLineExtent(uint32_t *_rval)
1359
*_rval = mLineExtent;
1364
jsdScript::GetCallCount(uint32_t *_rval)
1366
ASSERT_VALID_EPHEMERAL;
1367
*_rval = JSD_GetScriptCallCount (mCx, mScript);
1372
jsdScript::GetMaxRecurseDepth(uint32_t *_rval)
1374
ASSERT_VALID_EPHEMERAL;
1375
*_rval = JSD_GetScriptMaxRecurseDepth (mCx, mScript);
1380
jsdScript::GetMinExecutionTime(double *_rval)
1382
ASSERT_VALID_EPHEMERAL;
1383
*_rval = JSD_GetScriptMinExecutionTime (mCx, mScript);
1388
jsdScript::GetMaxExecutionTime(double *_rval)
1390
ASSERT_VALID_EPHEMERAL;
1391
*_rval = JSD_GetScriptMaxExecutionTime (mCx, mScript);
1396
jsdScript::GetTotalExecutionTime(double *_rval)
1398
ASSERT_VALID_EPHEMERAL;
1399
*_rval = JSD_GetScriptTotalExecutionTime (mCx, mScript);
1404
jsdScript::GetMinOwnExecutionTime(double *_rval)
1406
ASSERT_VALID_EPHEMERAL;
1407
*_rval = JSD_GetScriptMinOwnExecutionTime (mCx, mScript);
1412
jsdScript::GetMaxOwnExecutionTime(double *_rval)
1414
ASSERT_VALID_EPHEMERAL;
1415
*_rval = JSD_GetScriptMaxOwnExecutionTime (mCx, mScript);
1420
jsdScript::GetTotalOwnExecutionTime(double *_rval)
1422
ASSERT_VALID_EPHEMERAL;
1423
*_rval = JSD_GetScriptTotalOwnExecutionTime (mCx, mScript);
1428
jsdScript::ClearProfileData()
1430
ASSERT_VALID_EPHEMERAL;
1431
JSD_ClearScriptProfileData(mCx, mScript);
1436
jsdScript::PcToLine(uint32_t aPC, uint32_t aPcmap, uint32_t *_rval)
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);
1444
return NS_ERROR_INVALID_ARG;
1451
jsdScript::LineToPc(uint32_t aLine, uint32_t aPcmap, uint32_t *_rval)
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);
1460
return NS_ERROR_INVALID_ARG;
1467
jsdScript::EnableSingleStepInterrupts(bool enable)
1469
ASSERT_VALID_EPHEMERAL;
1471
/* Must have set interrupt hook before enabling */
1472
if (enable && !jsdService::GetService()->CheckInterruptHook())
1473
return NS_ERROR_NOT_INITIALIZED;
1475
return (JSD_EnableSingleStepInterrupts(mCx, mScript, enable) ? NS_OK : NS_ERROR_FAILURE);
1479
jsdScript::GetExecutableLines(uint32_t aPcmap, uint32_t aStartLine, uint32_t aMaxLines,
1480
uint32_t* aCount, uint32_t** aExecutableLines)
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);
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;
1496
if (aPcmap == PCMAP_PRETTYPRINT) {
1498
if (!CreatePPLineMap())
1499
return NS_ERROR_OUT_OF_MEMORY;
1502
nsTArray<uint32_t> lines;
1505
for (i = 0; i < mPCMapSize; ++i) {
1506
if (mPPLineMap[i].line >= aStartLine)
1510
for (; i < mPCMapSize && lines.Length() < aMaxLines; ++i) {
1511
lines.AppendElement(mPPLineMap[i].line);
1515
*aCount = lines.Length();
1517
*aExecutableLines = static_cast<uint32_t*>(NS_Alloc(lines.Length() * sizeof(uint32_t)));
1518
if (!*aExecutableLines)
1519
return NS_ERROR_OUT_OF_MEMORY;
1521
for (i = 0; i < lines.Length(); ++i)
1522
(*aExecutableLines)[i] = lines[i];
1527
return NS_ERROR_INVALID_ARG;
1531
jsdScript::IsLineExecutable(uint32_t aLine, uint32_t aPcmap, bool *_rval)
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;
1541
for (uint32_t i = 0; i < mPCMapSize; ++i) {
1542
if (mPPLineMap[i].line >= aLine) {
1543
*_rval = (mPPLineMap[i].line == aLine);
1548
return NS_ERROR_INVALID_ARG;
1555
jsdScript::SetBreakpoint(uint32_t aPC)
1557
ASSERT_VALID_EPHEMERAL;
1558
uintptr_t pc = mFirstPC + aPC;
1559
JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, NULL);
1564
jsdScript::ClearBreakpoint(uint32_t aPC)
1566
ASSERT_VALID_EPHEMERAL;
1567
uintptr_t pc = mFirstPC + aPC;
1568
JSD_ClearExecutionHook (mCx, mScript, pc);
1573
jsdScript::ClearAllBreakpoints()
1575
ASSERT_VALID_EPHEMERAL;
1576
JSD_LockScriptSubsystem(mCx);
1577
JSD_ClearAllExecutionHooksForScript (mCx, mScript);
1578
JSD_UnlockScriptSubsystem(mCx);
1583
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral)
1586
jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx)
1588
if (!aJSDCx || !aJSCx)
1591
nsCOMPtr<jsdIContext> jsdicx;
1592
nsCOMPtr<jsdIEphemeral> eph =
1593
jsds_FindEphemeral (&gLiveContexts, static_cast<void *>(aJSCx));
1596
jsdicx = do_QueryInterface(eph);
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);
1606
jsdIContext *ctx = nullptr;
1611
jsdContext::jsdContext (JSDContext *aJSDCx, JSContext *aJSCx,
1612
nsISupports *aISCx) : mValid(true), mTag(0),
1614
mJSCx(aJSCx), mISCx(aISCx)
1616
DEBUG_CREATE ("jsdContext", gContextCount);
1617
mLiveListEntry.value = this;
1618
mLiveListEntry.key = static_cast<void *>(aJSCx);
1619
jsds_InsertEphemeral (&gLiveContexts, &mLiveListEntry);
1622
jsdContext::~jsdContext()
1624
DEBUG_DESTROY ("jsdContext", gContextCount);
1627
/* call Invalidate() to take ourselves out of the live list */
1633
jsdContext::GetIsValid(bool *_rval)
1640
jsdContext::Invalidate()
1642
ASSERT_VALID_EPHEMERAL;
1644
jsds_RemoveEphemeral (&gLiveContexts, &mLiveListEntry);
1649
jsdContext::InvalidateAll()
1652
jsds_InvalidateAllEphemerals (&gLiveContexts);
1656
jsdContext::GetJSContext(JSContext **_rval)
1658
ASSERT_VALID_EPHEMERAL;
1664
jsdContext::GetOptions(uint32_t *_rval)
1666
ASSERT_VALID_EPHEMERAL;
1667
*_rval = JS_GetOptions(mJSCx);
1672
jsdContext::SetOptions(uint32_t options)
1674
ASSERT_VALID_EPHEMERAL;
1675
uint32_t lastOptions = JS_GetOptions(mJSCx);
1677
/* don't let users change this option, they'd just be shooting themselves
1679
if ((options ^ lastOptions) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
1680
return NS_ERROR_ILLEGAL_VALUE;
1682
JS_SetOptions(mJSCx, options);
1687
jsdContext::GetPrivateData(nsISupports **_rval)
1689
ASSERT_VALID_EPHEMERAL;
1690
uint32_t options = JS_GetOptions(mJSCx);
1691
if (options & JSOPTION_PRIVATE_IS_NSISUPPORTS)
1693
*_rval = static_cast<nsISupports*>(JS_GetContextPrivate(mJSCx));
1694
NS_IF_ADDREF(*_rval);
1705
jsdContext::GetWrappedContext(nsISupports **_rval)
1707
ASSERT_VALID_EPHEMERAL;
1708
NS_IF_ADDREF(*_rval = mISCx);
1713
jsdContext::GetTag(uint32_t *_rval)
1715
ASSERT_VALID_EPHEMERAL;
1717
mTag = ++jsdContext::LastTag;
1724
jsdContext::GetVersion (int32_t *_rval)
1726
ASSERT_VALID_EPHEMERAL;
1727
*_rval = static_cast<int32_t>(JS_GetVersion(mJSCx));
1732
jsdContext::SetVersion (int32_t id)
1734
ASSERT_VALID_EPHEMERAL;
1735
JSVersion ver = static_cast<JSVersion>(id);
1736
JS_SetVersion(mJSCx, ver);
1741
jsdContext::GetGlobalObject (jsdIValue **_rval)
1743
ASSERT_VALID_EPHEMERAL;
1744
JSObject *glob = JS_GetGlobalObject(mJSCx);
1745
JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
1747
return NS_ERROR_FAILURE;
1748
*_rval = jsdValue::FromPtr (mJSDCx, jsdv);
1750
return NS_ERROR_FAILURE;
1755
jsdContext::GetScriptsEnabled (bool *_rval)
1757
ASSERT_VALID_EPHEMERAL;
1763
nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
1765
return NS_ERROR_NO_INTERFACE;
1767
*_rval = context->GetScriptsEnabled();
1773
jsdContext::SetScriptsEnabled (bool _rval)
1775
ASSERT_VALID_EPHEMERAL;
1779
return NS_ERROR_NO_INTERFACE;
1782
nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
1784
return NS_ERROR_NO_INTERFACE;
1786
context->SetScriptsEnabled(_rval, true);
1792
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame, jsdIStackFrame, jsdIEphemeral)
1794
jsdStackFrame::jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState,
1795
JSDStackFrameInfo *aStackFrameInfo) :
1796
mCx(aCx), mThreadState(aThreadState), mStackFrameInfo(aStackFrameInfo)
1798
DEBUG_CREATE ("jsdStackFrame", gFrameCount);
1799
mValid = (aCx && aThreadState && aStackFrameInfo);
1801
mLiveListEntry.key = aStackFrameInfo;
1802
mLiveListEntry.value = this;
1803
jsds_InsertEphemeral (&gLiveStackFrames, &mLiveListEntry);
1807
jsdStackFrame::~jsdStackFrame()
1809
DEBUG_DESTROY ("jsdStackFrame", gFrameCount);
1812
/* call Invalidate() to take ourselves out of the live list */
1818
jsdStackFrame::FromPtr (JSDContext *aCx, JSDThreadState *aThreadState,
1819
JSDStackFrameInfo *aStackFrameInfo)
1821
if (!aStackFrameInfo)
1825
nsCOMPtr<jsdIStackFrame> frame;
1827
nsCOMPtr<jsdIEphemeral> eph =
1828
jsds_FindEphemeral (&gLiveStackFrames,
1829
reinterpret_cast<void *>(aStackFrameInfo));
1833
frame = do_QueryInterface(eph);
1838
rv = new jsdStackFrame (aCx, aThreadState, aStackFrameInfo);
1846
jsdStackFrame::Invalidate()
1848
ASSERT_VALID_EPHEMERAL;
1850
jsds_RemoveEphemeral (&gLiveStackFrames, &mLiveListEntry);
1855
jsdStackFrame::InvalidateAll()
1857
if (gLiveStackFrames)
1858
jsds_InvalidateAllEphemerals (&gLiveStackFrames);
1862
jsdStackFrame::GetJSDContext(JSDContext **_rval)
1864
ASSERT_VALID_EPHEMERAL;
1870
jsdStackFrame::GetJSDThreadState(JSDThreadState **_rval)
1872
ASSERT_VALID_EPHEMERAL;
1873
*_rval = mThreadState;
1878
jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo **_rval)
1880
ASSERT_VALID_EPHEMERAL;
1881
*_rval = mStackFrameInfo;
1886
jsdStackFrame::GetIsValid(bool *_rval)
1893
jsdStackFrame::GetCallingFrame(jsdIStackFrame **_rval)
1895
ASSERT_VALID_EPHEMERAL;
1896
JSDStackFrameInfo *sfi = JSD_GetCallingStackFrame (mCx, mThreadState,
1898
*_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
1903
jsdStackFrame::GetExecutionContext(jsdIContext **_rval)
1905
ASSERT_VALID_EPHEMERAL;
1906
JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
1907
*_rval = jsdContext::FromPtr (mCx, cx);
1912
jsdStackFrame::GetFunctionName(nsACString &_rval)
1914
ASSERT_VALID_EPHEMERAL;
1915
JSString *str = JSD_GetIdForStackFrame(mCx, mThreadState, mStackFrameInfo);
1917
return AssignToJSString(&_rval, str);
1919
_rval.Assign("anonymous");
1924
jsdStackFrame::GetIsDebugger(bool *_rval)
1926
ASSERT_VALID_EPHEMERAL;
1927
*_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo);
1932
jsdStackFrame::GetIsConstructing(bool *_rval)
1934
ASSERT_VALID_EPHEMERAL;
1935
*_rval = JSD_IsStackFrameConstructing (mCx, mThreadState, mStackFrameInfo);
1940
jsdStackFrame::GetScript(jsdIScript **_rval)
1942
ASSERT_VALID_EPHEMERAL;
1943
JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1945
*_rval = jsdScript::FromPtr (mCx, script);
1950
jsdStackFrame::GetPc(uint32_t *_rval)
1952
ASSERT_VALID_EPHEMERAL;
1953
JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1956
return NS_ERROR_FAILURE;
1957
uintptr_t pcbase = JSD_GetClosestPC(mCx, script, 0);
1959
uintptr_t pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
1961
*_rval = pc - pcbase;
1968
jsdStackFrame::GetLine(uint32_t *_rval)
1970
ASSERT_VALID_EPHEMERAL;
1971
JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1974
uintptr_t pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
1975
*_rval = JSD_GetClosestLine (mCx, script, pc);
1977
return NS_ERROR_FAILURE;
1983
jsdStackFrame::GetCallee(jsdIValue **_rval)
1985
ASSERT_VALID_EPHEMERAL;
1986
JSDValue *jsdv = JSD_GetCallObjectForStackFrame (mCx, mThreadState,
1989
*_rval = jsdValue::FromPtr (mCx, jsdv);
1994
jsdStackFrame::GetScope(jsdIValue **_rval)
1996
ASSERT_VALID_EPHEMERAL;
1997
JSDValue *jsdv = JSD_GetScopeChainForStackFrame (mCx, mThreadState,
2000
*_rval = jsdValue::FromPtr (mCx, jsdv);
2005
jsdStackFrame::GetThisValue(jsdIValue **_rval)
2007
ASSERT_VALID_EPHEMERAL;
2008
JSDValue *jsdv = JSD_GetThisForStackFrame (mCx, mThreadState,
2011
*_rval = jsdValue::FromPtr (mCx, jsdv);
2017
jsdStackFrame::Eval (const nsAString &bytes, const nsACString &fileName,
2018
uint32_t line, jsdIValue **result, bool *_rval)
2020
ASSERT_VALID_EPHEMERAL;
2022
if (bytes.IsEmpty())
2023
return NS_ERROR_INVALID_ARG;
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());
2030
JSExceptionState *estate = 0;
2033
JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
2035
JSAutoRequest ar(cx);
2037
estate = JS_SaveExceptionState (cx);
2038
JS_ClearPendingException (cx);
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);
2049
*_rval = JSD_AttemptUCScriptInStackFrame (mCx, mThreadState,
2051
char_bytes, bytes.Length(),
2052
PromiseFlatCString(fileName).get(),
2055
if (JS_IsExceptionPending(cx))
2056
JS_GetPendingException (cx, &jv);
2061
JS_RestoreExceptionState (cx, estate);
2064
JSContext* poppedCX;
2065
rv = stack->Pop(&poppedCX);
2066
NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == cx, "bad pop");
2068
(void) stack->Pop(nullptr);
2071
JSDValue *jsdv = JSD_NewValue (mCx, jv);
2073
return NS_ERROR_FAILURE;
2074
*result = jsdValue::FromPtr (mCx, jsdv);
2076
return NS_ERROR_FAILURE;
2082
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue, jsdIValue, jsdIEphemeral)
2084
jsdValue::FromPtr (JSDContext *aCx, JSDValue *aValue)
2086
/* value will be dropped by te jsdValue destructor. */
2091
jsdIValue *rv = new jsdValue (aCx, aValue);
2096
jsdValue::jsdValue (JSDContext *aCx, JSDValue *aValue) : mValid(true),
2100
DEBUG_CREATE ("jsdValue", gValueCount);
2101
mLiveListEntry.value = this;
2102
jsds_InsertEphemeral (&gLiveValues, &mLiveListEntry);
2105
jsdValue::~jsdValue()
2107
DEBUG_DESTROY ("jsdValue", gValueCount);
2109
/* call Invalidate() to take ourselves out of the live list */
2114
jsdValue::GetIsValid(bool *_rval)
2121
jsdValue::Invalidate()
2123
ASSERT_VALID_EPHEMERAL;
2125
jsds_RemoveEphemeral (&gLiveValues, &mLiveListEntry);
2126
JSD_DropValue (mCx, mValue);
2131
jsdValue::InvalidateAll()
2134
jsds_InvalidateAllEphemerals (&gLiveValues);
2138
jsdValue::GetJSDContext(JSDContext **_rval)
2140
ASSERT_VALID_EPHEMERAL;
2146
jsdValue::GetJSDValue (JSDValue **_rval)
2148
ASSERT_VALID_EPHEMERAL;
2154
jsdValue::GetIsNative (bool *_rval)
2156
ASSERT_VALID_EPHEMERAL;
2157
*_rval = JSD_IsValueNative (mCx, mValue);
2162
jsdValue::GetIsNumber (bool *_rval)
2164
ASSERT_VALID_EPHEMERAL;
2165
*_rval = JSD_IsValueNumber (mCx, mValue);
2170
jsdValue::GetIsPrimitive (bool *_rval)
2172
ASSERT_VALID_EPHEMERAL;
2173
*_rval = JSD_IsValuePrimitive (mCx, mValue);
2178
jsdValue::GetJsType (uint32_t *_rval)
2180
ASSERT_VALID_EPHEMERAL;
2183
val = JSD_GetValueWrappedJSVal (mCx, mValue);
2185
if (JSVAL_IS_NULL(val))
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))
2193
else if (JSVAL_IS_STRING(val))
2194
*_rval = TYPE_STRING;
2195
else if (JSVAL_IS_VOID(val))
2197
else if (JSD_IsValueFunction (mCx, mValue))
2198
*_rval = TYPE_FUNCTION;
2199
else if (!JSVAL_IS_PRIMITIVE(val))
2200
*_rval = TYPE_OBJECT;
2202
NS_ASSERTION (0, "Value has no discernible type.");
2208
jsdValue::GetJsPrototype (jsdIValue **_rval)
2210
ASSERT_VALID_EPHEMERAL;
2211
JSDValue *jsdv = JSD_GetValuePrototype (mCx, mValue);
2212
*_rval = jsdValue::FromPtr (mCx, jsdv);
2217
jsdValue::GetJsParent (jsdIValue **_rval)
2219
ASSERT_VALID_EPHEMERAL;
2220
JSDValue *jsdv = JSD_GetValueParent (mCx, mValue);
2221
*_rval = jsdValue::FromPtr (mCx, jsdv);
2226
jsdValue::GetJsClassName(nsACString &_rval)
2228
ASSERT_VALID_EPHEMERAL;
2229
_rval.Assign(JSD_GetValueClassName(mCx, mValue));
2235
jsdValue::GetJsConstructor (jsdIValue **_rval)
2237
ASSERT_VALID_EPHEMERAL;
2238
JSDValue *jsdv = JSD_GetValueConstructor (mCx, mValue);
2239
*_rval = jsdValue::FromPtr (mCx, jsdv);
2244
jsdValue::GetJsFunctionName(nsACString &_rval)
2246
ASSERT_VALID_EPHEMERAL;
2247
return AssignToJSString(&_rval, JSD_GetValueFunctionId(mCx, mValue));
2251
jsdValue::GetBooleanValue(bool *_rval)
2253
ASSERT_VALID_EPHEMERAL;
2254
*_rval = JSD_GetValueBoolean (mCx, mValue);
2259
jsdValue::GetDoubleValue(double *_rval)
2261
ASSERT_VALID_EPHEMERAL;
2262
*_rval = JSD_GetValueDouble (mCx, mValue);
2267
jsdValue::GetIntValue(int32_t *_rval)
2269
ASSERT_VALID_EPHEMERAL;
2270
*_rval = JSD_GetValueInt (mCx, mValue);
2275
jsdValue::GetObjectValue(jsdIObject **_rval)
2277
ASSERT_VALID_EPHEMERAL;
2279
obj = JSD_GetObjectForValue (mCx, mValue);
2280
*_rval = jsdObject::FromPtr (mCx, obj);
2282
return NS_ERROR_FAILURE;
2287
jsdValue::GetStringValue(nsACString &_rval)
2289
ASSERT_VALID_EPHEMERAL;
2290
JSContext *cx = JSD_GetDefaultJSContext (mCx);
2292
NS_WARNING("No default context !?");
2293
return NS_ERROR_FAILURE;
2295
JSString *jstr_val = JSD_GetValueString(mCx, mValue);
2298
const jschar *chars = JS_GetStringCharsZAndLength(cx, jstr_val, &length);
2300
return NS_ERROR_FAILURE;
2301
nsDependentString depStr(chars, length);
2302
CopyUTF16toUTF8(depStr, _rval);
2310
jsdValue::GetPropertyCount (int32_t *_rval)
2312
ASSERT_VALID_EPHEMERAL;
2313
if (JSD_IsValueObject(mCx, mValue))
2314
*_rval = JSD_GetCountOfProperties (mCx, mValue);
2321
jsdValue::GetProperties (jsdIProperty ***propArray, uint32_t *length)
2323
ASSERT_VALID_EPHEMERAL;
2324
*propArray = nullptr;
2328
uint32_t prop_count = JSD_IsValueObject(mCx, mValue)
2329
? JSD_GetCountOfProperties (mCx, mValue)
2331
NS_ENSURE_TRUE(prop_count, NS_OK);
2333
jsdIProperty **pa_temp =
2334
static_cast<jsdIProperty **>
2335
(nsMemory::Alloc(sizeof (jsdIProperty *) *
2337
NS_ENSURE_TRUE(pa_temp, NS_ERROR_OUT_OF_MEMORY);
2340
JSDProperty *iter = NULL;
2342
while ((prop = JSD_IterateProperties (mCx, mValue, &iter))) {
2343
pa_temp[i] = jsdProperty::FromPtr (mCx, prop);
2347
NS_ASSERTION (prop_count == i, "property count mismatch");
2349
/* if caller doesn't care about length, don't bother telling them */
2350
*propArray = pa_temp;
2352
*length = prop_count;
2358
jsdValue::GetProperty (const nsACString &name, jsdIProperty **_rval)
2360
ASSERT_VALID_EPHEMERAL;
2361
JSContext *cx = JSD_GetDefaultJSContext (mCx);
2363
JSAutoRequest ar(cx);
2365
/* not rooting this */
2366
JSString *jstr_name = JS_NewStringCopyZ(cx, PromiseFlatCString(name).get());
2368
return NS_ERROR_OUT_OF_MEMORY;
2370
JSDProperty *prop = JSD_GetValueProperty (mCx, mValue, jstr_name);
2372
*_rval = jsdProperty::FromPtr (mCx, prop);
2379
ASSERT_VALID_EPHEMERAL;
2380
JSD_RefreshValue (mCx, mValue);
2385
jsdValue::GetWrappedValue(JSContext* aCx, JS::Value* aRetval)
2387
ASSERT_VALID_EPHEMERAL;
2389
*aRetval = JSD_GetValueWrappedJSVal(mCx, mValue);
2390
if (!JS_WrapValue(aCx, aRetval)) {
2391
return NS_ERROR_FAILURE;
2398
jsdValue::GetScript(jsdIScript **_rval)
2400
ASSERT_VALID_EPHEMERAL;
2401
JSDScript *script = JSD_GetScriptForValue(mCx, mValue);
2402
*_rval = jsdScript::FromPtr(mCx, script);
2406
/******************************************************************************
2407
* debugger service implementation
2408
******************************************************************************/
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
2415
/* NS_IMPL_CYCLE_COLLECTION_10(jsdService, ...) */
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
2443
NS_IMPL_CYCLE_COLLECTING_ADDREF(jsdService)
2444
NS_IMPL_CYCLE_COLLECTING_RELEASE(jsdService)
2447
jsdService::GetJSDContext(JSDContext **_rval)
2454
jsdService::GetFlags (uint32_t *_rval)
2456
ASSERT_VALID_CONTEXT;
2457
*_rval = JSD_GetContextFlags (mCx);
2462
jsdService::SetFlags (uint32_t flags)
2464
ASSERT_VALID_CONTEXT;
2465
JSD_SetContextFlags (mCx, flags);
2470
jsdService::GetImplementationString(nsACString &aImplementationString)
2472
aImplementationString.AssignLiteral(implementationString);
2477
jsdService::GetImplementationMajor(uint32_t *_rval)
2479
*_rval = JSDS_MAJOR_VERSION;
2484
jsdService::GetImplementationMinor(uint32_t *_rval)
2486
*_rval = JSDS_MINOR_VERSION;
2491
jsdService::GetIsOn (bool *_rval)
2498
jsdService::On (void)
2500
return NS_ERROR_NOT_IMPLEMENTED;
2504
jsdService::AsyncOn (jsdIActivationCallback *activationCallback)
2508
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2509
if (NS_FAILED(rv)) return rv;
2511
mActivationCallback = activationCallback;
2513
return xpc->SetDebugModeWhenPossible(true, true);
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;
2524
jsdService::DeactivateDebugger ()
2529
jsdContext::InvalidateAll();
2530
jsdScript::InvalidateAll();
2531
jsdValue::InvalidateAll();
2532
jsdProperty::InvalidateAll();
2533
jsdStackFrame::InvalidateAll();
2534
ClearAllBreakpoints();
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);
2545
JSD_DebuggerOff (mCx);
2556
jsdService::ActivateDebugger (JSRuntime *rt)
2559
return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED;
2563
if (gPrevGCSliceCallback == jsds_GCSliceCallbackProc)
2564
/* condition indicates that the callback proc has not been set yet */
2565
gPrevGCSliceCallback = js::SetGCSliceCallback (rt, jsds_GCSliceCallbackProc);
2567
mCx = JSD_DebuggerOnForUser (rt, NULL, NULL);
2569
return NS_ERROR_FAILURE;
2571
JSContext *cx = JSD_GetDefaultJSContext (mCx);
2572
JSObject *glob = JS_GetGlobalObject (cx);
2574
/* init xpconnect on the debugger's context in case xpconnect tries to
2575
* use it for stuff. */
2577
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2581
xpc->InitClasses (cx, glob);
2583
/* Start watching for script creation/destruction and manage jsdScript
2584
* objects accordingly
2586
JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
2588
/* If any of these mFooHook objects are installed, do the required JSD
2589
* hookup now. See also, jsdService::SetFooHook().
2592
JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
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. */
2598
JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
2600
JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
2602
JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
2604
JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
2606
JSD_ClearTopLevelHook (mCx);
2608
JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
2610
JSD_ClearFunctionHook (mCx);
2614
printf ("+++ JavaScript debugging hooks installed.\n");
2617
nsCOMPtr<jsdIActivationCallback> activationCallback;
2618
mActivationCallback.swap(activationCallback);
2619
if (activationCallback)
2620
return activationCallback->OnDebuggerActivated();
2626
jsdService::Off (void)
2631
if (!mCx || !mRuntime)
2632
return NS_ERROR_NOT_INITIALIZED;
2636
return NS_ERROR_NOT_AVAILABLE;
2638
JSContext *cx = JSD_GetDefaultJSContext(mCx);
2639
while (gDeadScripts)
2640
jsds_NotifyPendingDeadScripts (JS_GetRuntime(cx));
2643
DeactivateDebugger();
2646
printf ("+++ JavaScript debugging hooks removed.\n");
2650
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2654
xpc->SetDebugModeWhenPossible(false, true);
2660
jsdService::GetPauseDepth(uint32_t *_rval)
2662
NS_ENSURE_ARG_POINTER(_rval);
2663
*_rval = mPauseLevel;
2668
jsdService::Pause(uint32_t *_rval)
2670
return DoPause(_rval, false);
2674
jsdService::DoPause(uint32_t *_rval, bool internalCall)
2677
return NS_ERROR_NOT_INITIALIZED;
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);
2690
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2691
if (NS_FAILED(rv)) return rv;
2693
if (!internalCall) {
2694
rv = xpc->SetDebugModeWhenPossible(false, false);
2695
NS_ENSURE_SUCCESS(rv, rv);
2700
*_rval = mPauseLevel;
2706
jsdService::UnPause(uint32_t *_rval)
2708
return DoUnPause(_rval, false);
2712
jsdService::DoUnPause(uint32_t *_rval, bool internalCall)
2715
return NS_ERROR_NOT_INITIALIZED;
2717
if (mPauseLevel == 0)
2718
return NS_ERROR_NOT_AVAILABLE;
2720
/* check mOn before we muck with this stuff, it's possible the debugger
2721
* was turned off while we were paused.
2723
if (--mPauseLevel == 0 && mOn) {
2724
JSD_DebuggerUnpause (mCx);
2726
JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
2728
JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
2730
JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
2732
JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
2734
JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
2736
JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
2738
JSD_ClearTopLevelHook (mCx);
2740
JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
2742
JSD_ClearFunctionHook (mCx);
2745
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
2746
if (NS_FAILED(rv)) return rv;
2748
if (!internalCall) {
2749
rv = xpc->SetDebugModeWhenPossible(true, false);
2750
NS_ENSURE_SUCCESS(rv, rv);
2755
*_rval = mPauseLevel;
2761
jsdService::EnumerateContexts (jsdIContextEnumerator *enumerator)
2763
ASSERT_VALID_CONTEXT;
2768
JSContext *iter = NULL;
2771
while ((cx = JS_ContextIterator (mRuntime, &iter)))
2773
nsCOMPtr<jsdIContext> jsdicx =
2774
getter_AddRefs(jsdContext::FromPtr(mCx, cx));
2777
if (NS_FAILED(enumerator->EnumerateContext(jsdicx)))
2786
jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator)
2788
ASSERT_VALID_CONTEXT;
2791
JSDScript *iter = NULL;
2792
nsresult rv = NS_OK;
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);
2802
JSD_UnlockScriptSubsystem(mCx);
2808
jsdService::GC (void)
2810
ASSERT_VALID_CONTEXT;
2811
JSRuntime *rt = JSD_GetJSRuntime (mCx);
2817
jsdService::DumpHeap(const nsACString &fileName)
2819
ASSERT_VALID_CONTEXT;
2821
return NS_ERROR_NOT_IMPLEMENTED;
2823
nsresult rv = NS_OK;
2824
FILE *file = !fileName.IsEmpty() ? fopen(PromiseFlatCString(fileName).get(), "w") : stdout;
2826
rv = NS_ERROR_FAILURE;
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;
2839
jsdService::ClearProfileData ()
2841
ASSERT_VALID_CONTEXT;
2842
JSD_ClearAllProfileData (mCx);
2847
jsdService::InsertFilter (jsdIFilter *filter, jsdIFilter *after)
2849
NS_ENSURE_ARG_POINTER (filter);
2850
if (jsds_FindFilter (filter))
2851
return NS_ERROR_INVALID_ARG;
2853
FilterRecord *rec = PR_NEWZAP (FilterRecord);
2855
return NS_ERROR_OUT_OF_MEMORY;
2857
if (!jsds_SyncFilter (rec, filter)) {
2859
return NS_ERROR_FAILURE;
2864
/* insert at head of list */
2865
PR_INSERT_LINK(&rec->links, &gFilters->links);
2868
/* insert somewhere in the list */
2869
FilterRecord *afterRecord = jsds_FindFilter (after);
2871
jsds_FreeFilter(rec);
2872
return NS_ERROR_INVALID_ARG;
2874
PR_INSERT_AFTER(&rec->links, &afterRecord->links);
2878
/* user asked to insert into the middle of an empty list, bail. */
2879
jsds_FreeFilter(rec);
2880
return NS_ERROR_NOT_INITIALIZED;
2882
PR_INIT_CLIST(&rec->links);
2890
jsdService::AppendFilter (jsdIFilter *filter)
2892
NS_ENSURE_ARG_POINTER (filter);
2893
if (jsds_FindFilter (filter))
2894
return NS_ERROR_INVALID_ARG;
2895
FilterRecord *rec = PR_NEWZAP (FilterRecord);
2897
if (!jsds_SyncFilter (rec, filter)) {
2899
return NS_ERROR_FAILURE;
2903
PR_INSERT_BEFORE(&rec->links, &gFilters->links);
2905
PR_INIT_CLIST(&rec->links);
2913
jsdService::RemoveFilter (jsdIFilter *filter)
2915
NS_ENSURE_ARG_POINTER(filter);
2916
FilterRecord *rec = jsds_FindFilter (filter);
2918
return NS_ERROR_INVALID_ARG;
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)
2929
PR_REMOVE_LINK(&rec->links);
2930
jsds_FreeFilter (rec);
2936
jsdService::SwapFilters (jsdIFilter *filter_a, jsdIFilter *filter_b)
2938
NS_ENSURE_ARG_POINTER(filter_a);
2939
NS_ENSURE_ARG_POINTER(filter_b);
2941
FilterRecord *rec_a = jsds_FindFilter (filter_a);
2943
return NS_ERROR_INVALID_ARG;
2945
if (filter_a == filter_b) {
2946
/* just a refresh */
2947
if (!jsds_SyncFilter (rec_a, filter_a))
2948
return NS_ERROR_FAILURE;
2952
FilterRecord *rec_b = jsds_FindFilter (filter_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;
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;
2969
jsdService::EnumerateFilters (jsdIFilterEnumerator *enumerator)
2974
FilterRecord *current = gFilters;
2976
jsds_SyncFilter (current, current->filterObject);
2977
/* SyncFilter failure would be bad, but what would we do about it? */
2979
nsresult rv = enumerator->EnumerateFilter (current->filterObject);
2983
current = reinterpret_cast<FilterRecord *>
2984
(PR_NEXT_LINK (¤t->links));
2985
} while (current != gFilters);
2991
jsdService::RefreshFilters ()
2993
return EnumerateFilters(nullptr);
2997
jsdService::ClearFilters ()
3002
FilterRecord *current = reinterpret_cast<FilterRecord *>
3003
(PR_NEXT_LINK (&gFilters->links));
3005
FilterRecord *next = reinterpret_cast<FilterRecord *>
3006
(PR_NEXT_LINK (¤t->links));
3007
PR_REMOVE_AND_INIT_LINK(¤t->links);
3008
jsds_FreeFilter(current);
3010
} while (current != gFilters);
3012
jsds_FreeFilter(current);
3019
jsdService::ClearAllBreakpoints (void)
3021
ASSERT_VALID_CONTEXT;
3023
JSD_LockScriptSubsystem(mCx);
3024
JSD_ClearAllExecutionHooks (mCx);
3025
JSD_UnlockScriptSubsystem(mCx);
3030
jsdService::WrapValue(const JS::Value &value, jsdIValue **_rval)
3032
ASSERT_VALID_CONTEXT;
3033
JSDValue *jsdv = JSD_NewValue(mCx, value);
3035
return NS_ERROR_FAILURE;
3037
*_rval = jsdValue::FromPtr (mCx, jsdv);
3043
jsdService::EnterNestedEventLoop (jsdINestCallback *callback, uint32_t *_rval)
3045
// Nesting event queues is a thing of the past. Now, we just spin the
3046
// current event loop.
3049
nsCOMPtr<nsIJSContextStack>
3050
stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
3053
uint32_t nestLevel = ++mNestedLoopLevel;
3055
nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
3057
if (NS_SUCCEEDED(stack->Push(nullptr))) {
3059
DoPause(nullptr, true);
3060
rv = callback->OnNest();
3061
DoUnPause(nullptr, true);
3064
while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) {
3065
if (!NS_ProcessNextEvent(thread))
3066
rv = NS_ERROR_UNEXPECTED;
3071
NS_ASSERTION(cx == nullptr, "JSContextStack mismatch");
3074
rv = NS_ERROR_FAILURE;
3076
NS_ASSERTION (mNestedLoopLevel <= nestLevel,
3077
"nested event didn't unwind properly");
3078
if (mNestedLoopLevel == nestLevel)
3081
*_rval = mNestedLoopLevel;
3086
jsdService::ExitNestedEventLoop (uint32_t *_rval)
3088
if (mNestedLoopLevel > 0)
3091
return NS_ERROR_FAILURE;
3093
*_rval = mNestedLoopLevel;
3097
/* hook attribute get/set functions */
3100
jsdService::SetErrorHook (jsdIErrorHook *aHook)
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.
3107
if (!mCx || mPauseLevel)
3111
JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
3113
JSD_SetErrorReporter (mCx, NULL, NULL);
3119
jsdService::GetErrorHook (jsdIErrorHook **aHook)
3121
*aHook = mErrorHook;
3122
NS_IF_ADDREF(*aHook);
3128
jsdService::SetBreakpointHook (jsdIExecutionHook *aHook)
3130
mBreakpointHook = aHook;
3135
jsdService::GetBreakpointHook (jsdIExecutionHook **aHook)
3137
*aHook = mBreakpointHook;
3138
NS_IF_ADDREF(*aHook);
3144
jsdService::SetDebugHook (jsdIExecutionHook *aHook)
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.
3151
if (!mCx || mPauseLevel)
3155
JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
3157
JSD_ClearDebugBreakHook (mCx);
3163
jsdService::GetDebugHook (jsdIExecutionHook **aHook)
3165
*aHook = mDebugHook;
3166
NS_IF_ADDREF(*aHook);
3172
jsdService::SetDebuggerHook (jsdIExecutionHook *aHook)
3174
mDebuggerHook = aHook;
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.
3179
if (!mCx || mPauseLevel)
3183
JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
3185
JSD_ClearDebuggerHook (mCx);
3191
jsdService::GetDebuggerHook (jsdIExecutionHook **aHook)
3193
*aHook = mDebuggerHook;
3194
NS_IF_ADDREF(*aHook);
3200
jsdService::SetInterruptHook (jsdIExecutionHook *aHook)
3202
mInterruptHook = aHook;
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.
3207
if (!mCx || mPauseLevel)
3211
JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
3213
JSD_ClearInterruptHook (mCx);
3219
jsdService::GetInterruptHook (jsdIExecutionHook **aHook)
3221
*aHook = mInterruptHook;
3222
NS_IF_ADDREF(*aHook);
3228
jsdService::SetScriptHook (jsdIScriptHook *aHook)
3230
mScriptHook = aHook;
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.
3235
if (!mCx || mPauseLevel)
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
3247
jsdService::GetScriptHook (jsdIScriptHook **aHook)
3249
*aHook = mScriptHook;
3250
NS_IF_ADDREF(*aHook);
3256
jsdService::SetThrowHook (jsdIExecutionHook *aHook)
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.
3263
if (!mCx || mPauseLevel)
3267
JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
3269
JSD_ClearThrowHook (mCx);
3275
jsdService::GetThrowHook (jsdIExecutionHook **aHook)
3277
*aHook = mThrowHook;
3278
NS_IF_ADDREF(*aHook);
3284
jsdService::SetTopLevelHook (jsdICallHook *aHook)
3286
mTopLevelHook = aHook;
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.
3291
if (!mCx || mPauseLevel)
3295
JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
3297
JSD_ClearTopLevelHook (mCx);
3303
jsdService::GetTopLevelHook (jsdICallHook **aHook)
3305
*aHook = mTopLevelHook;
3306
NS_IF_ADDREF(*aHook);
3312
jsdService::SetFunctionHook (jsdICallHook *aHook)
3314
mFunctionHook = aHook;
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.
3319
if (!mCx || mPauseLevel)
3323
JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
3325
JSD_ClearFunctionHook (mCx);
3331
jsdService::GetFunctionHook (jsdICallHook **aHook)
3333
*aHook = mFunctionHook;
3334
NS_IF_ADDREF(*aHook);
3340
jsdService::~jsdService()
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;
3357
jsdService::GetService ()
3360
gJsds = new jsdService();
3362
NS_IF_ADDREF(gJsds);
3366
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService, jsdService::GetService)
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
3372
class jsdASObserver MOZ_FINAL : public nsIObserver
3381
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver, nsIObserver)
3384
jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic,
3385
const PRUnichar *aData)
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);
3396
rv = jsds->GetIsOn(&on);
3397
if (NS_FAILED(rv) || on)
3400
nsCOMPtr<nsIJSRuntimeService> rts = do_GetService(NS_JSRT_CTRID, &rv);
3405
rts->GetRuntime (&rt);
3409
rv = jsds->ActivateDebugger(rt);
3416
NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
3417
NS_DEFINE_NAMED_CID(JSDSERVICE_CID);
3418
NS_DEFINE_NAMED_CID(JSDASO_CID);
3420
static const mozilla::Module::CIDEntry kJSDCIDs[] = {
3421
{ &kJSDSERVICE_CID, false, NULL, jsdServiceConstructor },
3422
{ &kJSDASO_CID, false, NULL, jsdASObserverConstructor },
3426
static const mozilla::Module::ContractIDEntry kJSDContracts[] = {
3427
{ jsdServiceCtrID, &kJSDSERVICE_CID },
3428
{ jsdARObserverCtrID, &kJSDASO_CID },
3432
static const mozilla::Module kJSDModule = {
3433
mozilla::Module::kVersion,
3438
NSMODULE_DEFN(JavaScript_Debugger) = &kJSDModule;
3440
/********************************************************************************
3441
********************************************************************************
3447
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState, jsdIThreadState);
3450
jsdThreadState::GetJSDContext(JSDContext **_rval)
3457
jsdThreadState::GetJSDThreadState(JSDThreadState **_rval)
3459
*_rval = mThreadState;
3464
jsdThreadState::GetFrameCount (uint32_t *_rval)
3466
*_rval = JSD_GetCountOfStackFrames (mCx, mThreadState);
3471
jsdThreadState::GetTopFrame (jsdIStackFrame **_rval)
3473
JSDStackFrameInfo *sfi = JSD_GetStackFrame (mCx, mThreadState);
3475
*_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
3480
jsdThreadState::GetPendingException(jsdIValue **_rval)
3482
JSDValue *jsdv = JSD_GetException (mCx, mThreadState);
3484
*_rval = jsdValue::FromPtr (mCx, jsdv);
3489
jsdThreadState::SetPendingException(jsdIValue *aException)
3493
nsresult rv = aException->GetJSDValue (&jsdv);
3495
return NS_ERROR_FAILURE;
3497
if (!JSD_SetException (mCx, mThreadState, jsdv))
3498
return NS_ERROR_FAILURE;