1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3
* The contents of this file are subject to the Mozilla Public License
4
* Version 1.1 (the "License"); you may not use this file except in
5
* compliance with the License. You may obtain a copy of the License at
6
* http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS IS" basis,
9
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
10
* for the specific language governing rights and limitations under the
13
* The Original Code is mozilla.org code
15
* The Initial Developer of the Original Code is
16
* Netscape Communications Corporation
17
* Portions created by Netscape are
18
* Copyright (C) 1998 Netscape Communications Corporation.
20
* Alternatively, the contents of this file may be used under the
21
* terms of the GNU Public License (the "GPL"), in which case the
22
* provisions of the GPL are applicable instead of those above.
23
* If you wish to allow use of your version of this file only
24
* under the terms of the GPL and not to allow others to use your
25
* version of this file under the MPL, indicate your decision by
26
* deleting the provisions above and replace them with the notice
27
* and other provisions required by the GPL. If you do not delete
28
* the provisions above, a recipient may use your version of this
29
* file under either the MPL or the GPL.
32
* Robert Ginda, <rginda@netscape.com>
41
#include "nsIXPConnect.h"
42
#include "nsIGenericFactory.h"
43
#include "nsIServiceManager.h"
44
#include "nsIScriptGlobalObject.h"
45
#include "nsIObserver.h"
46
#include "nsIObserverService.h"
47
#include "nsICategoryManager.h"
48
#include "nsIJSRuntimeService.h"
49
#include "nsIEventQueueService.h"
52
#include "nsReadableUtils.h"
55
/* XXX this stuff is used by NestEventLoop, a temporary hack to be refactored
57
#include "nsWidgetsCID.h"
58
#include "nsIScriptContext.h"
59
#include "nsIAppShell.h"
60
#include "nsIJSContextStack.h"
63
* defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
64
* script hook. This was a hack to avoid some js engine problems that should
65
* be fixed now (see Mozilla bug 77636).
67
#undef CAUTIOUS_SCRIPTHOOK
70
# define DEBUG_COUNT(name, count) \
71
{ if ((count % 10) == 0) printf (name ": %i\n", count); }
72
# define DEBUG_CREATE(name, count) {count++; DEBUG_COUNT ("+++++ "name,count)}
73
# define DEBUG_DESTROY(name, count) {count--; DEBUG_COUNT ("----- "name,count)}
75
# define DEBUG_CREATE(name, count)
76
# define DEBUG_DESTROY(name, count)
79
#define ASSERT_VALID_CONTEXT { if (!mCx) return NS_ERROR_NOT_AVAILABLE; }
80
#define ASSERT_VALID_EPHEMERAL { if (!mValid) return NS_ERROR_NOT_AVAILABLE; }
82
#define JSDSERVICE_CID \
83
{ /* f1299dc2-1dd1-11b2-a347-ee6b7660e048 */ \
87
{0xa3, 0x47, 0xee, 0x6b, 0x76, 0x60, 0xe0, 0x48} \
91
{ /* 2fd6b7f6-eb8c-4f32-ad26-113f2c02d0fe */ \
95
{0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \
98
#define JSDS_MAJOR_VERSION 1
99
#define JSDS_MINOR_VERSION 2
101
#define NS_CATMAN_CTRID "@mozilla.org/categorymanager;1"
102
#define NS_JSRT_CTRID "@mozilla.org/js/xpc/RuntimeService;1"
104
#define AUTOREG_CATEGORY "xpcom-autoregistration"
105
#define APPSTART_CATEGORY "app-startup"
106
#define JSD_AUTOREG_ENTRY "JSDebugger Startup Observer"
107
#define JSD_STARTUP_ENTRY "JSDebugger Startup Observer,service"
109
JS_STATIC_DLL_CALLBACK (JSBool)
110
jsds_GCCallbackProc (JSContext *cx, JSGCStatus status);
112
/*******************************************************************************
114
******************************************************************************/
116
const char implementationString[] = "Mozilla JavaScript Debugger Service";
117
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
118
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
120
const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
121
const char jsdASObserverCtrID[] = "@mozilla.org/js/jsd/app-start-observer;2";
124
PRUint32 gScriptCount = 0;
125
PRUint32 gValueCount = 0;
126
PRUint32 gPropertyCount = 0;
127
PRUint32 gContextCount = 0;
128
PRUint32 gFrameCount = 0;
131
static jsdService *gJsds = 0;
132
static JSGCCallback gLastGCProc = jsds_GCCallbackProc;
133
static JSGCStatus gGCStatus = JSGC_END;
135
static struct DeadScript {
139
} *gDeadScripts = nsnull;
149
static struct FilterRecord {
151
jsdIFilter *filterObject;
154
PRUint32 patternLength;
155
PatternType patternType;
158
} *gFilters = nsnull;
160
static struct LiveEphemeral *gLiveValues = nsnull;
161
static struct LiveEphemeral *gLiveProperties = nsnull;
162
static struct LiveEphemeral *gLiveContexts = nsnull;
163
static struct LiveEphemeral *gLiveStackFrames = nsnull;
165
/*******************************************************************************
166
* utility functions for ephemeral lists
167
*******************************************************************************/
168
already_AddRefed<jsdIEphemeral>
169
jsds_FindEphemeral (LiveEphemeral **listHead, void *key)
174
LiveEphemeral *lv_record =
175
NS_REINTERPRET_CAST (LiveEphemeral *,
176
PR_NEXT_LINK(&(*listHead)->links));
179
if (lv_record->key == key)
181
NS_IF_ADDREF(lv_record->value);
182
return lv_record->value;
184
lv_record = NS_REINTERPRET_CAST (LiveEphemeral *,
185
PR_NEXT_LINK(&lv_record->links));
187
while (lv_record != *listHead);
193
jsds_InvalidateAllEphemerals (LiveEphemeral **listHead)
195
LiveEphemeral *lv_record =
196
NS_REINTERPRET_CAST (LiveEphemeral *,
197
PR_NEXT_LINK(&(*listHead)->links));
200
LiveEphemeral *next =
201
NS_REINTERPRET_CAST (LiveEphemeral *,
202
PR_NEXT_LINK(&lv_record->links));
203
lv_record->value->Invalidate();
209
jsds_InsertEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
212
/* if the list exists, add to it */
213
PR_APPEND_LINK(&item->links, &(*listHead)->links);
215
/* otherwise create the list */
216
PR_INIT_CLIST(&item->links);
222
jsds_RemoveEphemeral (LiveEphemeral **listHead, LiveEphemeral *item)
224
LiveEphemeral *next = NS_REINTERPRET_CAST (LiveEphemeral *,
225
PR_NEXT_LINK(&item->links));
229
/* if the current item is also the next item, we're the only element,
230
* null out the list head */
231
NS_ASSERTION (*listHead == item,
232
"How could we not be the head of a one item list?");
235
else if (item == *listHead)
237
/* otherwise, if we're currently the list head, change it */
241
PR_REMOVE_AND_INIT_LINK(&item->links);
244
/*******************************************************************************
245
* utility functions for filters
246
*******************************************************************************/
248
jsds_FreeFilter (FilterRecord *filter)
250
NS_IF_RELEASE (filter->filterObject);
251
if (filter->urlPattern)
252
nsMemory::Free(filter->urlPattern);
256
/* copies appropriate |filter| attributes into |rec|.
257
* False return indicates failure, the contents of |rec| will not be changed.
260
jsds_SyncFilter (FilterRecord *rec, jsdIFilter *filter)
262
NS_ASSERTION (rec, "jsds_SyncFilter without rec");
263
NS_ASSERTION (filter, "jsds_SyncFilter without filter");
265
JSObject *glob_proper = nsnull;
266
nsCOMPtr<nsISupports> glob;
267
nsresult rv = filter->GetGlobalObject(getter_AddRefs(glob));
271
nsCOMPtr<nsIScriptGlobalObject> nsiglob = do_QueryInterface(glob);
273
glob_proper = nsiglob->GetGlobalJSObject();
277
rv = filter->GetStartLine(&startLine);
282
rv = filter->GetStartLine(&endLine);
287
rv = filter->GetUrlPattern (&urlPattern);
292
PRUint32 len = PL_strlen(urlPattern);
293
if (urlPattern[0] == '*') {
294
/* pattern starts with a *, shift all chars once to the left,
295
* including the trailing null. */
296
memmove (&urlPattern[0], &urlPattern[1], len);
298
if (urlPattern[len - 2] == '*') {
299
/* pattern is in the format "*foo*", overwrite the final * with
301
urlPattern[len - 2] = '\0';
302
rec->patternType = ptContains;
303
rec->patternLength = len - 2;
305
/* pattern is in the format "*foo", just make a note of the
307
rec->patternType = ptEndsWith;
308
rec->patternLength = len - 1;
310
} else if (urlPattern[len - 1] == '*') {
311
/* pattern is in the format "foo*", overwrite the final * with a
313
urlPattern[len - 1] = '\0';
314
rec->patternType = ptStartsWith;
315
rec->patternLength = len - 1;
317
/* pattern is in the format "foo". */
318
rec->patternType = ptEquals;
319
rec->patternLength = len;
322
rec->patternType = ptIgnore;
323
rec->patternLength = 0;
326
/* we got everything we need without failing, now copy it into rec. */
328
if (rec->filterObject != filter) {
329
NS_IF_RELEASE(rec->filterObject);
331
rec->filterObject = filter;
334
rec->glob = glob_proper;
336
rec->startLine = startLine;
337
rec->endLine = endLine;
340
nsMemory::Free (rec->urlPattern);
341
rec->urlPattern = urlPattern;
348
jsds_FindFilter (jsdIFilter *filter)
353
FilterRecord *current = gFilters;
356
if (current->filterObject == filter)
358
current = NS_REINTERPRET_CAST(FilterRecord *,
359
PR_NEXT_LINK(¤t->links));
360
} while (current != gFilters);
365
/* returns true if the hook should be executed. */
367
jsds_FilterHook (JSDContext *jsdc, JSDThreadState *state)
369
JSContext *cx = JSD_GetJSContext (jsdc, state);
370
void *glob = NS_STATIC_CAST(void *, JS_GetGlobalObject (cx));
373
NS_WARNING("No global in threadstate");
377
JSDStackFrameInfo *frame = JSD_GetStackFrame (jsdc, state);
380
NS_WARNING("No frame in threadstate");
384
JSDScript *script = JSD_GetScriptForStackFrame (jsdc, state, frame);
388
jsuint pc = JSD_GetPCForStackFrame (jsdc, state, frame);
390
const char *url = JSD_GetScriptFilename (jsdc, script);
392
NS_WARNING ("Script with no filename");
399
PRUint32 currentLine = JSD_GetClosestLine (jsdc, script, pc);
401
FilterRecord *currentFilter = gFilters;
404
nsresult rv = currentFilter->filterObject->GetFlags(&flags);
405
NS_ASSERTION(NS_SUCCEEDED(rv), "Error getting flags for filter");
406
if (flags & jsdIFilter::FLAG_ENABLED) {
407
/* if there is no glob, or the globs match */
408
if ((!currentFilter->glob || currentFilter->glob == glob) &&
409
/* and there is no start line, or the start line is before
410
* or equal to the current */
411
(!currentFilter->startLine ||
412
currentFilter->startLine <= currentLine) &&
413
/* and there is no end line, or the end line is after
414
* or equal to the current */
415
(!currentFilter->endLine ||
416
currentFilter->endLine >= currentLine)) {
417
/* then we're going to have to compare the url. */
418
if (currentFilter->patternType == ptIgnore)
419
return flags & jsdIFilter::FLAG_PASS;
422
len = PL_strlen(url);
424
if (len >= currentFilter->patternLength) {
425
switch (currentFilter->patternType) {
427
if (!PL_strcmp(currentFilter->urlPattern, url))
428
return flags & jsdIFilter::FLAG_PASS;
431
if (!PL_strncmp(currentFilter->urlPattern, url,
432
currentFilter->patternLength))
433
return flags & jsdIFilter::FLAG_PASS;
436
if (!PL_strcmp(currentFilter->urlPattern,
438
currentFilter->patternLength]))
439
return flags & jsdIFilter::FLAG_PASS;
442
if (PL_strstr(url, currentFilter->urlPattern))
443
return flags & jsdIFilter::FLAG_PASS;
446
NS_ASSERTION(0, "Invalid pattern type");
451
currentFilter = NS_REINTERPRET_CAST(FilterRecord *,
452
PR_NEXT_LINK(¤tFilter->links));
453
} while (currentFilter != gFilters);
459
/*******************************************************************************
461
*******************************************************************************/
463
JS_STATIC_DLL_CALLBACK (void)
464
jsds_NotifyPendingDeadScripts (JSContext *cx)
466
nsCOMPtr<jsdIScriptHook> hook = 0;
467
gJsds->GetScriptHook (getter_AddRefs(hook));
470
#ifdef CAUTIOUS_SCRIPTHOOK
471
JSRuntime *rt = JS_GetRuntime(cx);
473
gJsds->Pause(nsnull);
474
while (gDeadScripts) {
479
/* tell the user this script has been destroyed */
480
#ifdef CAUTIOUS_SCRIPTHOOK
483
hook->OnScriptDestroyed (ds->script);
484
#ifdef CAUTIOUS_SCRIPTHOOK
488
/* get next deleted script */
489
gDeadScripts = NS_REINTERPRET_CAST(DeadScript *,
490
PR_NEXT_LINK(&ds->links));
491
if (gDeadScripts == ds) {
492
/* last script in the list */
493
gDeadScripts = nsnull;
496
/* take ourselves out of the circular list */
497
PR_REMOVE_LINK(&ds->links);
498
/* addref came from the FromPtr call in jsds_ScriptHookProc */
499
NS_RELEASE(ds->script);
500
/* free the struct! */
504
gJsds->UnPause(nsnull);
507
JS_STATIC_DLL_CALLBACK (JSBool)
508
jsds_GCCallbackProc (JSContext *cx, JSGCStatus status)
512
printf ("new gc status is %i\n", status);
514
if (status == JSGC_END && gDeadScripts)
515
jsds_NotifyPendingDeadScripts (cx);
518
return gLastGCProc (cx, status);
523
JS_STATIC_DLL_CALLBACK (uintN)
524
jsds_ErrorHookProc (JSDContext *jsdc, JSContext *cx, const char *message,
525
JSErrorReport *report, void *callerdata)
527
static PRBool running = PR_FALSE;
529
nsCOMPtr<jsdIErrorHook> hook;
530
gJsds->GetErrorHook(getter_AddRefs(hook));
532
return JSD_ERROR_REPORTER_PASS_ALONG;
535
return JSD_ERROR_REPORTER_PASS_ALONG;
539
nsCOMPtr<jsdIValue> val;
540
if (JS_IsExceptionPending(cx)) {
542
JS_GetPendingException(cx, &jv);
543
JSDValue *jsdv = JSD_NewValue (jsdc, jv);
544
val = getter_AddRefs(jsdValue::FromPtr(jsdc, jsdv));
547
const char *fileName;
554
fileName = report->filename;
555
line = report->lineno;
556
pos = report->tokenptr - report->linebuf;
557
flags = report->flags;
558
errnum = report->errorNumber;
569
gJsds->Pause(nsnull);
570
hook->OnError (message, fileName, line, pos, flags, errnum, val, &rval);
571
gJsds->UnPause(nsnull);
575
return JSD_ERROR_REPORTER_DEBUG;
577
return JSD_ERROR_REPORTER_PASS_ALONG;
580
JS_STATIC_DLL_CALLBACK (JSBool)
581
jsds_CallHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
582
uintN type, void* callerdata)
584
nsCOMPtr<jsdICallHook> hook;
588
case JSD_HOOK_TOPLEVEL_START:
589
case JSD_HOOK_TOPLEVEL_END:
590
gJsds->GetTopLevelHook(getter_AddRefs(hook));
593
case JSD_HOOK_FUNCTION_CALL:
594
case JSD_HOOK_FUNCTION_RETURN:
595
gJsds->GetFunctionHook(getter_AddRefs(hook));
599
NS_ASSERTION (0, "Unknown hook type.");
605
if (!jsds_FilterHook (jsdc, jsdthreadstate))
608
JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
609
nsCOMPtr<jsdIStackFrame> frame =
610
getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
612
gJsds->Pause(nsnull);
613
hook->OnCall(frame, type);
614
gJsds->UnPause(nsnull);
615
jsdStackFrame::InvalidateAll();
620
JS_STATIC_DLL_CALLBACK (PRUint32)
621
jsds_ExecutionHookProc (JSDContext* jsdc, JSDThreadState* jsdthreadstate,
622
uintN type, void* callerdata, jsval* rval)
624
nsCOMPtr<jsdIExecutionHook> hook(0);
625
PRUint32 hook_rv = JSD_HOOK_RETURN_CONTINUE;
626
nsCOMPtr<jsdIValue> js_rv;
630
case JSD_HOOK_INTERRUPTED:
631
gJsds->GetInterruptHook(getter_AddRefs(hook));
633
case JSD_HOOK_DEBUG_REQUESTED:
634
gJsds->GetDebugHook(getter_AddRefs(hook));
636
case JSD_HOOK_DEBUGGER_KEYWORD:
637
gJsds->GetDebuggerHook(getter_AddRefs(hook));
639
case JSD_HOOK_BREAKPOINT:
641
/* we can't pause breakpoints the way we pause the other
642
* execution hooks (at least, not easily.) Instead we bail
643
* here if the service is paused. */
645
gJsds->GetPauseDepth(&level);
647
gJsds->GetBreakpointHook(getter_AddRefs(hook));
652
hook_rv = JSD_HOOK_RETURN_CONTINUE_THROW;
653
gJsds->GetThrowHook(getter_AddRefs(hook));
655
JSDValue *jsdv = JSD_GetException (jsdc, jsdthreadstate);
656
js_rv = getter_AddRefs(jsdValue::FromPtr (jsdc, jsdv));
661
NS_ASSERTION (0, "Unknown hook type.");
667
if (!jsds_FilterHook (jsdc, jsdthreadstate))
668
return JSD_HOOK_RETURN_CONTINUE;
670
JSDStackFrameInfo *native_frame = JSD_GetStackFrame (jsdc, jsdthreadstate);
671
nsCOMPtr<jsdIStackFrame> frame =
672
getter_AddRefs(jsdStackFrame::FromPtr(jsdc, jsdthreadstate,
674
gJsds->Pause(nsnull);
675
jsdIValue *inout_rv = js_rv;
676
NS_IF_ADDREF(inout_rv);
677
hook->OnExecute (frame, type, &inout_rv, &hook_rv);
679
NS_IF_RELEASE(inout_rv);
680
gJsds->UnPause(nsnull);
681
jsdStackFrame::InvalidateAll();
683
if (hook_rv == JSD_HOOK_RETURN_RET_WITH_VAL ||
684
hook_rv == JSD_HOOK_RETURN_THROW_WITH_VAL) {
687
js_rv->GetJSDValue (&jsdv);
688
*rval = JSD_GetValueWrappedJSVal(jsdc, jsdv);
697
JS_STATIC_DLL_CALLBACK (void)
698
jsds_ScriptHookProc (JSDContext* jsdc, JSDScript* jsdscript, JSBool creating,
701
#ifdef CAUTIOUS_SCRIPTHOOK
702
JSContext *cx = JSD_GetDefaultJSContext(jsdc);
703
JSRuntime *rt = JS_GetRuntime(cx);
706
nsCOMPtr<jsdIScriptHook> hook;
707
gJsds->GetScriptHook (getter_AddRefs(hook));
710
/* a script is being created */
712
/* nobody cares, just exit */
716
nsCOMPtr<jsdIScript> script =
717
getter_AddRefs(jsdScript::FromPtr(jsdc, jsdscript));
718
#ifdef CAUTIOUS_SCRIPTHOOK
721
gJsds->Pause(nsnull);
722
hook->OnScriptCreated (script);
723
gJsds->UnPause(nsnull);
724
#ifdef CAUTIOUS_SCRIPTHOOK
728
/* a script is being destroyed. even if there is no registered hook
729
* we'll still need to invalidate the jsdIScript record, in order
730
* to remove the reference held in the JSDScript private data. */
731
nsCOMPtr<jsdIScript> jsdis =
732
NS_STATIC_CAST(jsdIScript *, JSD_GetScriptPrivate(jsdscript));
740
if (gGCStatus == JSGC_END) {
741
/* if GC *isn't* running, we can tell the user about the script
743
#ifdef CAUTIOUS_SCRIPTHOOK
747
gJsds->Pause(nsnull);
748
hook->OnScriptDestroyed (jsdis);
749
gJsds->UnPause(nsnull);
750
#ifdef CAUTIOUS_SCRIPTHOOK
754
/* if a GC *is* running, we've got to wait until it's done before
755
* we can execute any JS, so we queue the notification in a PRCList
756
* until GC tells us it's done. See jsds_GCCallbackProc(). */
757
DeadScript *ds = PR_NEW(DeadScript);
759
return; /* NS_ERROR_OUT_OF_MEMORY */
763
NS_ADDREF(ds->script);
765
/* if the queue exists, add to it */
766
PR_APPEND_LINK(&ds->links, &gDeadScripts->links);
768
/* otherwise create the queue */
769
PR_INIT_CLIST(&ds->links);
776
/*******************************************************************************
777
* reflected jsd data structures
778
*******************************************************************************/
782
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdContext, jsdIContext);
785
jsdContext::GetJSDContext(JSDContext **_rval)
793
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdObject, jsdIObject)
796
jsdObject::GetJSDContext(JSDContext **_rval)
803
jsdObject::GetJSDObject(JSDObject **_rval)
810
jsdObject::GetCreatorURL(char **_rval)
812
const char *url = JSD_GetObjectNewURL(mCx, mObject);
814
*_rval = PL_strdup(url);
816
return NS_ERROR_OUT_OF_MEMORY;
824
jsdObject::GetCreatorLine(PRUint32 *_rval)
826
*_rval = JSD_GetObjectNewLineNumber(mCx, mObject);
831
jsdObject::GetConstructorURL(char **_rval)
833
const char *url = JSD_GetObjectConstructorURL(mCx, mObject);
835
*_rval = PL_strdup(url);
837
return NS_ERROR_OUT_OF_MEMORY;
845
jsdObject::GetConstructorLine(PRUint32 *_rval)
847
*_rval = JSD_GetObjectConstructorLineNumber(mCx, mObject);
852
jsdObject::GetValue(jsdIValue **_rval)
854
JSDValue *jsdv = JSD_GetValueForObject (mCx, mObject);
856
*_rval = jsdValue::FromPtr (mCx, jsdv);
861
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdProperty, jsdIProperty, jsdIEphemeral)
863
jsdProperty::jsdProperty (JSDContext *aCx, JSDProperty *aProperty) :
864
mCx(aCx), mProperty(aProperty)
866
DEBUG_CREATE ("jsdProperty", gPropertyCount);
867
mValid = (aCx && aProperty);
868
mLiveListEntry.value = this;
869
jsds_InsertEphemeral (&gLiveProperties, &mLiveListEntry);
872
jsdProperty::~jsdProperty ()
874
DEBUG_DESTROY ("jsdProperty", gPropertyCount);
880
jsdProperty::Invalidate()
882
ASSERT_VALID_EPHEMERAL;
884
jsds_RemoveEphemeral (&gLiveProperties, &mLiveListEntry);
885
JSD_DropProperty (mCx, mProperty);
890
jsdProperty::InvalidateAll()
893
jsds_InvalidateAllEphemerals (&gLiveProperties);
897
jsdProperty::GetJSDContext(JSDContext **_rval)
904
jsdProperty::GetJSDProperty(JSDProperty **_rval)
911
jsdProperty::GetIsValid(PRBool *_rval)
918
jsdProperty::GetAlias(jsdIValue **_rval)
920
JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
922
*_rval = jsdValue::FromPtr (mCx, jsdv);
927
jsdProperty::GetFlags(PRUint32 *_rval)
929
*_rval = JSD_GetPropertyFlags (mCx, mProperty);
934
jsdProperty::GetName(jsdIValue **_rval)
936
JSDValue *jsdv = JSD_GetPropertyName (mCx, mProperty);
938
*_rval = jsdValue::FromPtr (mCx, jsdv);
943
jsdProperty::GetValue(jsdIValue **_rval)
945
JSDValue *jsdv = JSD_GetPropertyValue (mCx, mProperty);
947
*_rval = jsdValue::FromPtr (mCx, jsdv);
952
jsdProperty::GetVarArgSlot(PRUint32 *_rval)
954
*_rval = JSD_GetPropertyVarArgSlot (mCx, mProperty);
959
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
961
jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(PR_FALSE),
972
DEBUG_CREATE ("jsdScript", gScriptCount);
975
/* copy the script's information now, so we have it later, when it
977
JSD_LockScriptSubsystem(mCx);
978
mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
980
new nsCString(JSD_GetScriptFunctionName(mCx, mScript));
981
mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
982
mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
983
mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
984
JSD_UnlockScriptSubsystem(mCx);
990
jsdScript::~jsdScript ()
992
DEBUG_DESTROY ("jsdScript", gScriptCount);
996
delete mFunctionName;
1001
/* Invalidate() needs to be called to release an owning reference to
1002
* ourselves, so if we got here without being invalidated, something
1003
* has gone wrong with our ref count. */
1004
NS_ASSERTION (!mValid, "Script destroyed without being invalidated.");
1008
* This method populates a line <-> pc map for a pretty printed version of this
1009
* script. It does this by decompiling, and then recompiling the script. The
1010
* resulting script is scanned for the line map, and then left as GC fodder.
1013
jsdScript::CreatePPLineMap()
1015
JSContext *cx = JSD_GetDefaultJSContext (mCx);
1016
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
1017
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
1020
PRBool scriptOwner = PR_FALSE;
1023
if (fun->nargs > 12)
1025
JSString *jsstr = JS_DecompileFunctionBody (cx, fun, 4);
1029
const char *argnames[] = {"arg1", "arg2", "arg3", "arg4",
1030
"arg5", "arg6", "arg7", "arg8",
1031
"arg9", "arg10", "arg11", "arg12" };
1032
fun = JS_CompileUCFunction (cx, obj, "ppfun", fun->nargs, argnames,
1033
JS_GetStringChars(jsstr),
1034
JS_GetStringLength(jsstr),
1035
"x-jsd:ppbuffer?type=function", 3);
1036
if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
1040
JSString *jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript),
1045
script = JS_CompileUCScript (cx, obj,
1046
JS_GetStringChars(jsstr),
1047
JS_GetStringLength(jsstr),
1048
"x-jsd:ppbuffer?type=script", 1);
1051
scriptOwner = PR_TRUE;
1055
PRUint32 scriptExtent = JS_GetScriptLineExtent (cx, script);
1056
jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0);
1057
/* allocate worst case size of map (number of lines in script + 1
1058
* for our 0 record), we'll shrink it with a realloc later. */
1060
NS_STATIC_CAST(PCMapEntry *,
1061
PR_Malloc((scriptExtent + 1) * sizeof (PCMapEntry)));
1064
for (PRUint32 line = baseLine; line < scriptExtent + baseLine; ++line) {
1065
jsbytecode* pc = JS_LineNumberToPC (cx, script, line);
1066
if (line == JS_PCToLineNumber (cx, script, pc)) {
1067
mPPLineMap[mPCMapSize].line = line;
1068
mPPLineMap[mPCMapSize].pc = pc - firstPC;
1072
if (scriptExtent != mPCMapSize) {
1074
NS_STATIC_CAST(PCMapEntry *,
1075
PR_Realloc(mPPLineMap,
1076
mPCMapSize * sizeof(PCMapEntry)));
1081
JS_DestroyScript (cx, script);
1087
jsdScript::PPPcToLine (PRUint32 aPC)
1089
if (!mPPLineMap && !CreatePPLineMap())
1092
for (i = 1; i < mPCMapSize; ++i) {
1093
if (mPPLineMap[i].pc > aPC)
1094
return mPPLineMap[i - 1].line;
1097
return mPPLineMap[mPCMapSize - 1].line;
1101
jsdScript::PPLineToPc (PRUint32 aLine)
1103
if (!mPPLineMap && !CreatePPLineMap())
1106
for (i = 1; i < mPCMapSize; ++i) {
1107
if (mPPLineMap[i].line > aLine)
1108
return mPPLineMap[i - 1].pc;
1111
return mPPLineMap[mPCMapSize - 1].pc;
1115
jsdScript::GetJSDContext(JSDContext **_rval)
1117
ASSERT_VALID_EPHEMERAL;
1123
jsdScript::GetJSDScript(JSDScript **_rval)
1125
ASSERT_VALID_EPHEMERAL;
1131
jsdScript::GetVersion (PRInt32 *_rval)
1133
ASSERT_VALID_EPHEMERAL;
1134
JSContext *cx = JSD_GetDefaultJSContext (mCx);
1135
JSScript *script = JSD_GetJSScript(mCx, mScript);
1136
*_rval = NS_STATIC_CAST (PRInt32, JS_GetScriptVersion(cx, script));
1141
jsdScript::GetTag(PRUint32 *_rval)
1144
mTag = ++jsdScript::LastTag;
1151
jsdScript::Invalidate()
1153
ASSERT_VALID_EPHEMERAL;
1156
/* release the addref we do in FromPtr */
1157
jsdIScript *script = NS_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
gJsds->GetJSDContext (&cx);
1171
JSDScript *iter = NULL;
1173
JSD_LockScriptSubsystem(cx);
1174
while((script = JSD_IterateScripts(cx, &iter)) != NULL) {
1175
nsCOMPtr<jsdIScript> jsdis =
1176
NS_STATIC_CAST(jsdIScript *, JSD_GetScriptPrivate(script));
1178
jsdis->Invalidate();
1180
JSD_UnlockScriptSubsystem(cx);
1184
jsdScript::GetIsValid(PRBool *_rval)
1191
jsdScript::SetFlags(PRUint32 flags)
1193
ASSERT_VALID_EPHEMERAL;
1194
JSD_SetScriptFlags(mCx, mScript, flags);
1199
jsdScript::GetFlags(PRUint32 *_rval)
1201
ASSERT_VALID_EPHEMERAL;
1202
*_rval = JSD_GetScriptFlags(mCx, mScript);
1207
jsdScript::GetFileName(char **_rval)
1209
*_rval = ToNewCString(*mFileName);
1211
return NS_ERROR_OUT_OF_MEMORY;
1216
jsdScript::GetFunctionName(char **_rval)
1218
*_rval = ToNewCString(*mFunctionName);
1220
return NS_ERROR_OUT_OF_MEMORY;
1225
jsdScript::GetFunctionObject(jsdIValue **_rval)
1227
JSFunction *fun = JSD_GetJSFunction(mCx, mScript);
1229
return NS_ERROR_NOT_AVAILABLE;
1231
JSObject *obj = JS_GetFunctionObject(fun);
1233
return NS_ERROR_FAILURE;
1236
gJsds->GetJSDContext (&cx);
1238
JSDValue *jsdv = JSD_NewValue(cx, OBJECT_TO_JSVAL(obj));
1240
return NS_ERROR_FAILURE;
1242
*_rval = jsdValue::FromPtr(cx, jsdv);
1244
JSD_DropValue(cx, jsdv);
1245
return NS_ERROR_FAILURE;
1252
jsdScript::GetFunctionSource(nsAString & aFunctionSource)
1254
ASSERT_VALID_EPHEMERAL;
1255
JSContext *cx = JSD_GetDefaultJSContext (mCx);
1257
NS_WARNING("No default context !?");
1258
return NS_ERROR_FAILURE;
1260
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
1264
jsstr = JS_DecompileFunction (cx, fun, 4);
1268
JSScript *script = JSD_GetJSScript (mCx, mScript);
1269
jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
1272
return NS_ERROR_FAILURE;
1273
aFunctionSource = NS_REINTERPRET_CAST(PRUnichar*, JS_GetStringChars(jsstr));
1278
jsdScript::GetBaseLineNumber(PRUint32 *_rval)
1280
*_rval = mBaseLineNumber;
1285
jsdScript::GetLineExtent(PRUint32 *_rval)
1287
*_rval = mLineExtent;
1292
jsdScript::GetCallCount(PRUint32 *_rval)
1294
ASSERT_VALID_EPHEMERAL;
1295
*_rval = JSD_GetScriptCallCount (mCx, mScript);
1300
jsdScript::GetMaxRecurseDepth(PRUint32 *_rval)
1302
ASSERT_VALID_EPHEMERAL;
1303
*_rval = JSD_GetScriptMaxRecurseDepth (mCx, mScript);
1308
jsdScript::GetMinExecutionTime(double *_rval)
1310
ASSERT_VALID_EPHEMERAL;
1311
*_rval = JSD_GetScriptMinExecutionTime (mCx, mScript);
1316
jsdScript::GetMaxExecutionTime(double *_rval)
1318
ASSERT_VALID_EPHEMERAL;
1319
*_rval = JSD_GetScriptMaxExecutionTime (mCx, mScript);
1324
jsdScript::GetTotalExecutionTime(double *_rval)
1326
ASSERT_VALID_EPHEMERAL;
1327
*_rval = JSD_GetScriptTotalExecutionTime (mCx, mScript);
1332
jsdScript::ClearProfileData()
1334
ASSERT_VALID_EPHEMERAL;
1335
JSD_ClearScriptProfileData(mCx, mScript);
1340
jsdScript::PcToLine(PRUint32 aPC, PRUint32 aPcmap, PRUint32 *_rval)
1342
ASSERT_VALID_EPHEMERAL;
1343
if (aPcmap == PCMAP_SOURCETEXT) {
1344
*_rval = JSD_GetClosestLine (mCx, mScript, mFirstPC + aPC);
1345
} else if (aPcmap == PCMAP_PRETTYPRINT) {
1346
*_rval = PPPcToLine(aPC);
1348
return NS_ERROR_INVALID_ARG;
1355
jsdScript::LineToPc(PRUint32 aLine, PRUint32 aPcmap, PRUint32 *_rval)
1357
ASSERT_VALID_EPHEMERAL;
1358
if (aPcmap == PCMAP_SOURCETEXT) {
1359
jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
1360
*_rval = pc - mFirstPC;
1361
} else if (aPcmap == PCMAP_PRETTYPRINT) {
1362
*_rval = PPLineToPc(aLine);
1364
return NS_ERROR_INVALID_ARG;
1371
jsdScript::IsLineExecutable(PRUint32 aLine, PRUint32 aPcmap, PRBool *_rval)
1373
ASSERT_VALID_EPHEMERAL;
1374
if (aPcmap == PCMAP_SOURCETEXT) {
1375
jsuword pc = JSD_GetClosestPC (mCx, mScript, aLine);
1376
*_rval = (aLine == JSD_GetClosestLine (mCx, mScript, pc));
1377
} else if (aPcmap == PCMAP_PRETTYPRINT) {
1378
if (!mPPLineMap && !CreatePPLineMap())
1379
return NS_ERROR_FAILURE;
1381
for (PRUint32 i = 0; i < mPCMapSize; ++i) {
1382
if (mPPLineMap[i].line >= aLine) {
1383
*_rval = (mPPLineMap[i].line == aLine);
1388
return NS_ERROR_INVALID_ARG;
1395
jsdScript::SetBreakpoint(PRUint32 aPC)
1397
ASSERT_VALID_EPHEMERAL;
1398
jsuword pc = mFirstPC + aPC;
1399
JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc,
1400
NS_REINTERPRET_CAST(void *, PRIVATE_TO_JSVAL(NULL)));
1405
jsdScript::ClearBreakpoint(PRUint32 aPC)
1407
ASSERT_VALID_EPHEMERAL;
1408
jsuword pc = mFirstPC + aPC;
1409
JSD_ClearExecutionHook (mCx, mScript, pc);
1414
jsdScript::ClearAllBreakpoints()
1416
ASSERT_VALID_EPHEMERAL;
1417
JSD_LockScriptSubsystem(mCx);
1418
JSD_ClearAllExecutionHooksForScript (mCx, mScript);
1419
JSD_UnlockScriptSubsystem(mCx);
1424
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdContext, jsdIContext, jsdIEphemeral)
1427
jsdContext::FromPtr (JSDContext *aJSDCx, JSContext *aJSCx)
1429
if (!aJSDCx || !aJSCx ||
1430
!(JS_GetOptions(aJSCx) & JSOPTION_PRIVATE_IS_NSISUPPORTS))
1435
nsCOMPtr<jsdIContext> jsdicx;
1436
nsCOMPtr<jsdIEphemeral> eph =
1437
jsds_FindEphemeral (&gLiveContexts, NS_STATIC_CAST(void *, aJSCx));
1440
jsdicx = do_QueryInterface(eph);
1444
nsCOMPtr<nsISupports> iscx =
1445
NS_STATIC_CAST(nsISupports *, JS_GetContextPrivate(aJSCx));
1449
jsdicx = new jsdContext (aJSDCx, aJSCx, iscx);
1452
jsdIContext *rv = jsdicx;
1457
jsdContext::jsdContext (JSDContext *aJSDCx, JSContext *aJSCx,
1458
nsISupports *aISCx) : mValid(PR_TRUE), mTag(0),
1460
mJSCx(aJSCx), mISCx(aISCx)
1462
DEBUG_CREATE ("jsdContext", gContextCount);
1463
mLiveListEntry.value = this;
1464
mLiveListEntry.key = NS_STATIC_CAST (void *, aJSCx);
1465
jsds_InsertEphemeral (&gLiveContexts, &mLiveListEntry);
1468
jsdContext::~jsdContext()
1470
DEBUG_DESTROY ("jsdContext", gContextCount);
1473
/* call Invalidate() to take ourselves out of the live list */
1479
jsdContext::GetIsValid(PRBool *_rval)
1486
jsdContext::Invalidate()
1488
ASSERT_VALID_EPHEMERAL;
1490
jsds_RemoveEphemeral (&gLiveContexts, &mLiveListEntry);
1495
jsdContext::InvalidateAll()
1498
jsds_InvalidateAllEphemerals (&gLiveContexts);
1502
jsdContext::GetJSContext(JSContext **_rval)
1504
ASSERT_VALID_EPHEMERAL;
1510
jsdContext::GetOptions(PRUint32 *_rval)
1512
ASSERT_VALID_EPHEMERAL;
1513
*_rval = JS_GetOptions(mJSCx);
1518
jsdContext::SetOptions(PRUint32 options)
1520
ASSERT_VALID_EPHEMERAL;
1521
PRUint32 lastOptions = JS_GetOptions(mJSCx);
1523
/* don't let users change this option, they'd just be shooting themselves
1525
if ((options ^ lastOptions) & JSOPTION_PRIVATE_IS_NSISUPPORTS)
1526
return NS_ERROR_ILLEGAL_VALUE;
1528
JS_SetOptions(mJSCx, options);
1533
jsdContext::GetPrivateData(nsISupports **_rval)
1535
ASSERT_VALID_EPHEMERAL;
1536
PRUint32 options = JS_GetOptions(mJSCx);
1537
if (options & JSOPTION_PRIVATE_IS_NSISUPPORTS)
1539
*_rval = NS_STATIC_CAST(nsISupports*, JS_GetContextPrivate(mJSCx));
1540
NS_IF_ADDREF(*_rval);
1551
jsdContext::GetWrappedContext(nsISupports **_rval)
1553
ASSERT_VALID_EPHEMERAL;
1555
NS_IF_ADDREF(*_rval);
1560
jsdContext::GetTag(PRUint32 *_rval)
1562
ASSERT_VALID_EPHEMERAL;
1564
mTag = ++jsdContext::LastTag;
1571
jsdContext::GetVersion (PRInt32 *_rval)
1573
ASSERT_VALID_EPHEMERAL;
1574
*_rval = NS_STATIC_CAST (PRInt32, JS_GetVersion(mJSCx));
1579
jsdContext::SetVersion (PRInt32 id)
1581
ASSERT_VALID_EPHEMERAL;
1582
JSVersion ver = NS_STATIC_CAST (JSVersion, id);
1583
JS_SetVersion(mJSCx, ver);
1588
jsdContext::GetGlobalObject (jsdIValue **_rval)
1590
ASSERT_VALID_EPHEMERAL;
1591
JSObject *glob = JS_GetGlobalObject(mJSCx);
1592
JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
1594
return NS_ERROR_FAILURE;
1595
*_rval = jsdValue::FromPtr (mJSDCx, jsdv);
1597
return NS_ERROR_FAILURE;
1602
jsdContext::GetScriptsEnabled (PRBool *_rval)
1604
ASSERT_VALID_EPHEMERAL;
1605
nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
1607
return NS_ERROR_NO_INTERFACE;
1609
*_rval = context->GetScriptsEnabled();
1615
jsdContext::SetScriptsEnabled (PRBool _rval)
1617
ASSERT_VALID_EPHEMERAL;
1618
nsCOMPtr<nsIScriptContext> context = do_QueryInterface(mISCx);
1620
return NS_ERROR_NO_INTERFACE;
1622
context->SetScriptsEnabled(_rval, PR_TRUE);
1628
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdStackFrame, jsdIStackFrame, jsdIEphemeral)
1630
jsdStackFrame::jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState,
1631
JSDStackFrameInfo *aStackFrameInfo) :
1632
mCx(aCx), mThreadState(aThreadState), mStackFrameInfo(aStackFrameInfo)
1634
DEBUG_CREATE ("jsdStackFrame", gFrameCount);
1635
mValid = (aCx && aThreadState && aStackFrameInfo);
1637
mLiveListEntry.key = aStackFrameInfo;
1638
mLiveListEntry.value = this;
1639
jsds_InsertEphemeral (&gLiveStackFrames, &mLiveListEntry);
1643
jsdStackFrame::~jsdStackFrame()
1645
DEBUG_DESTROY ("jsdStackFrame", gFrameCount);
1648
/* call Invalidate() to take ourselves out of the live list */
1654
jsdStackFrame::FromPtr (JSDContext *aCx, JSDThreadState *aThreadState,
1655
JSDStackFrameInfo *aStackFrameInfo)
1657
if (!aStackFrameInfo)
1661
nsCOMPtr<jsdIStackFrame> frame;
1663
nsCOMPtr<jsdIEphemeral> eph =
1664
jsds_FindEphemeral (&gLiveStackFrames,
1665
NS_REINTERPRET_CAST(void *, aStackFrameInfo));
1669
frame = do_QueryInterface(eph);
1674
rv = new jsdStackFrame (aCx, aThreadState, aStackFrameInfo);
1682
jsdStackFrame::Invalidate()
1684
ASSERT_VALID_EPHEMERAL;
1686
jsds_RemoveEphemeral (&gLiveStackFrames, &mLiveListEntry);
1691
jsdStackFrame::InvalidateAll()
1693
if (gLiveStackFrames)
1694
jsds_InvalidateAllEphemerals (&gLiveStackFrames);
1698
jsdStackFrame::GetJSDContext(JSDContext **_rval)
1700
ASSERT_VALID_EPHEMERAL;
1706
jsdStackFrame::GetJSDThreadState(JSDThreadState **_rval)
1708
ASSERT_VALID_EPHEMERAL;
1709
*_rval = mThreadState;
1714
jsdStackFrame::GetJSDStackFrameInfo(JSDStackFrameInfo **_rval)
1716
ASSERT_VALID_EPHEMERAL;
1717
*_rval = mStackFrameInfo;
1722
jsdStackFrame::GetIsValid(PRBool *_rval)
1729
jsdStackFrame::GetCallingFrame(jsdIStackFrame **_rval)
1731
ASSERT_VALID_EPHEMERAL;
1732
JSDStackFrameInfo *sfi = JSD_GetCallingStackFrame (mCx, mThreadState,
1734
*_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
1739
jsdStackFrame::GetExecutionContext(jsdIContext **_rval)
1741
ASSERT_VALID_EPHEMERAL;
1742
JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
1743
*_rval = jsdContext::FromPtr (mCx, cx);
1748
jsdStackFrame::GetFunctionName(char **_rval)
1750
ASSERT_VALID_EPHEMERAL;
1751
const char *name = JSD_GetNameForStackFrame(mCx, mThreadState,
1754
*_rval = PL_strdup(name);
1756
return NS_ERROR_OUT_OF_MEMORY;
1758
/* top level scripts have no function name */
1766
jsdStackFrame::GetIsNative(PRBool *_rval)
1768
ASSERT_VALID_EPHEMERAL;
1769
*_rval = JSD_IsStackFrameNative (mCx, mThreadState, mStackFrameInfo);
1774
jsdStackFrame::GetIsDebugger(PRBool *_rval)
1776
ASSERT_VALID_EPHEMERAL;
1777
*_rval = JSD_IsStackFrameDebugger (mCx, mThreadState, mStackFrameInfo);
1782
jsdStackFrame::GetIsConstructing(PRBool *_rval)
1784
ASSERT_VALID_EPHEMERAL;
1785
*_rval = JSD_IsStackFrameConstructing (mCx, mThreadState, mStackFrameInfo);
1790
jsdStackFrame::GetScript(jsdIScript **_rval)
1792
ASSERT_VALID_EPHEMERAL;
1793
JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1795
*_rval = jsdScript::FromPtr (mCx, script);
1800
jsdStackFrame::GetPc(PRUint32 *_rval)
1802
ASSERT_VALID_EPHEMERAL;
1803
JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1806
return NS_ERROR_FAILURE;
1807
jsuword pcbase = JSD_GetClosestPC(mCx, script, 0);
1809
jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
1811
*_rval = pc - pcbase;
1818
jsdStackFrame::GetLine(PRUint32 *_rval)
1820
ASSERT_VALID_EPHEMERAL;
1821
JSDScript *script = JSD_GetScriptForStackFrame (mCx, mThreadState,
1824
jsuword pc = JSD_GetPCForStackFrame (mCx, mThreadState, mStackFrameInfo);
1825
*_rval = JSD_GetClosestLine (mCx, script, pc);
1827
if (!JSD_IsStackFrameNative(mCx, mThreadState, mStackFrameInfo))
1828
return NS_ERROR_FAILURE;
1835
jsdStackFrame::GetCallee(jsdIValue **_rval)
1837
ASSERT_VALID_EPHEMERAL;
1838
JSDValue *jsdv = JSD_GetCallObjectForStackFrame (mCx, mThreadState,
1841
*_rval = jsdValue::FromPtr (mCx, jsdv);
1846
jsdStackFrame::GetScope(jsdIValue **_rval)
1848
ASSERT_VALID_EPHEMERAL;
1849
JSDValue *jsdv = JSD_GetScopeChainForStackFrame (mCx, mThreadState,
1852
*_rval = jsdValue::FromPtr (mCx, jsdv);
1857
jsdStackFrame::GetThisValue(jsdIValue **_rval)
1859
ASSERT_VALID_EPHEMERAL;
1860
JSDValue *jsdv = JSD_GetThisForStackFrame (mCx, mThreadState,
1863
*_rval = jsdValue::FromPtr (mCx, jsdv);
1869
jsdStackFrame::Eval (const nsAString &bytes, const char *fileName,
1870
PRUint32 line, jsdIValue **result, PRBool *_rval)
1872
ASSERT_VALID_EPHEMERAL;
1874
if (bytes.IsEmpty())
1875
return NS_ERROR_INVALID_ARG;
1877
// get pointer to buffer contained in |bytes|
1878
nsAString::const_iterator h;
1879
bytes.BeginReading(h);
1880
const jschar *char_bytes = NS_REINTERPRET_CAST(const jschar *, h.get());
1882
JSExceptionState *estate = 0;
1885
JSContext *cx = JSD_GetJSContext (mCx, mThreadState);
1886
estate = JS_SaveExceptionState (cx);
1887
JS_ClearPendingException (cx);
1889
*_rval = JSD_AttemptUCScriptInStackFrame (mCx, mThreadState,
1891
char_bytes, bytes.Length(),
1892
fileName, line, &jv);
1894
if (JS_IsExceptionPending(cx))
1895
JS_GetPendingException (cx, &jv);
1900
JS_RestoreExceptionState (cx, estate);
1901
JSDValue *jsdv = JSD_NewValue (mCx, jv);
1903
return NS_ERROR_FAILURE;
1904
*result = jsdValue::FromPtr (mCx, jsdv);
1906
return NS_ERROR_FAILURE;
1912
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdValue, jsdIValue, jsdIEphemeral)
1914
jsdValue::FromPtr (JSDContext *aCx, JSDValue *aValue)
1916
/* value will be dropped by te jsdValue destructor. */
1921
jsdIValue *rv = new jsdValue (aCx, aValue);
1926
jsdValue::jsdValue (JSDContext *aCx, JSDValue *aValue) : mValid(PR_TRUE),
1930
DEBUG_CREATE ("jsdValue", gValueCount);
1931
mLiveListEntry.value = this;
1932
jsds_InsertEphemeral (&gLiveValues, &mLiveListEntry);
1935
jsdValue::~jsdValue()
1937
DEBUG_DESTROY ("jsdValue", gValueCount);
1939
/* call Invalidate() to take ourselves out of the live list */
1944
jsdValue::GetIsValid(PRBool *_rval)
1951
jsdValue::Invalidate()
1953
ASSERT_VALID_EPHEMERAL;
1955
jsds_RemoveEphemeral (&gLiveValues, &mLiveListEntry);
1956
JSD_DropValue (mCx, mValue);
1961
jsdValue::InvalidateAll()
1964
jsds_InvalidateAllEphemerals (&gLiveValues);
1968
jsdValue::GetJSDContext(JSDContext **_rval)
1970
ASSERT_VALID_EPHEMERAL;
1976
jsdValue::GetJSDValue (JSDValue **_rval)
1978
ASSERT_VALID_EPHEMERAL;
1984
jsdValue::GetIsNative (PRBool *_rval)
1986
ASSERT_VALID_EPHEMERAL;
1987
*_rval = JSD_IsValueNative (mCx, mValue);
1992
jsdValue::GetIsNumber (PRBool *_rval)
1994
ASSERT_VALID_EPHEMERAL;
1995
*_rval = JSD_IsValueNumber (mCx, mValue);
2000
jsdValue::GetIsPrimitive (PRBool *_rval)
2002
ASSERT_VALID_EPHEMERAL;
2003
*_rval = JSD_IsValuePrimitive (mCx, mValue);
2008
jsdValue::GetJsType (PRUint32 *_rval)
2010
ASSERT_VALID_EPHEMERAL;
2013
val = JSD_GetValueWrappedJSVal (mCx, mValue);
2015
if (JSVAL_IS_NULL(val))
2017
else if (JSVAL_IS_BOOLEAN(val))
2018
*_rval = TYPE_BOOLEAN;
2019
else if (JSVAL_IS_DOUBLE(val))
2020
*_rval = TYPE_DOUBLE;
2021
else if (JSVAL_IS_INT(val))
2023
else if (JSVAL_IS_STRING(val))
2024
*_rval = TYPE_STRING;
2025
else if (JSVAL_IS_VOID(val))
2027
else if (JSD_IsValueFunction (mCx, mValue))
2028
*_rval = TYPE_FUNCTION;
2029
else if (JSVAL_IS_OBJECT(val))
2030
*_rval = TYPE_OBJECT;
2032
NS_ASSERTION (0, "Value has no discernible type.");
2038
jsdValue::GetJsPrototype (jsdIValue **_rval)
2040
ASSERT_VALID_EPHEMERAL;
2041
JSDValue *jsdv = JSD_GetValuePrototype (mCx, mValue);
2042
*_rval = jsdValue::FromPtr (mCx, jsdv);
2047
jsdValue::GetJsParent (jsdIValue **_rval)
2049
ASSERT_VALID_EPHEMERAL;
2050
JSDValue *jsdv = JSD_GetValueParent (mCx, mValue);
2051
*_rval = jsdValue::FromPtr (mCx, jsdv);
2056
jsdValue::GetJsClassName(char **_rval)
2058
ASSERT_VALID_EPHEMERAL;
2059
const char *name = JSD_GetValueClassName(mCx, mValue);
2061
*_rval = PL_strdup(name);
2063
return NS_ERROR_OUT_OF_MEMORY;
2072
jsdValue::GetJsConstructor (jsdIValue **_rval)
2074
ASSERT_VALID_EPHEMERAL;
2075
JSDValue *jsdv = JSD_GetValueConstructor (mCx, mValue);
2076
*_rval = jsdValue::FromPtr (mCx, jsdv);
2081
jsdValue::GetJsFunctionName(char **_rval)
2083
ASSERT_VALID_EPHEMERAL;
2084
const char *name = JSD_GetValueFunctionName(mCx, mValue);
2086
*_rval = PL_strdup(name);
2088
return NS_ERROR_OUT_OF_MEMORY;
2090
/* top level scripts have no function name */
2099
jsdValue::GetBooleanValue(PRBool *_rval)
2101
ASSERT_VALID_EPHEMERAL;
2102
*_rval = JSD_GetValueBoolean (mCx, mValue);
2107
jsdValue::GetDoubleValue(double *_rval)
2109
ASSERT_VALID_EPHEMERAL;
2110
double *dp = JSD_GetValueDouble (mCx, mValue);
2112
return NS_ERROR_FAILURE;
2118
jsdValue::GetIntValue(PRInt32 *_rval)
2120
ASSERT_VALID_EPHEMERAL;
2121
*_rval = JSD_GetValueInt (mCx, mValue);
2126
jsdValue::GetObjectValue(jsdIObject **_rval)
2128
ASSERT_VALID_EPHEMERAL;
2130
obj = JSD_GetObjectForValue (mCx, mValue);
2131
*_rval = jsdObject::FromPtr (mCx, obj);
2133
return NS_ERROR_FAILURE;
2138
jsdValue::GetStringValue(char **_rval)
2140
ASSERT_VALID_EPHEMERAL;
2141
JSString *jstr_val = JSD_GetValueString(mCx, mValue);
2143
char *bytes = JS_GetStringBytes(jstr_val);
2144
*_rval = PL_strdup(bytes);
2146
return NS_ERROR_OUT_OF_MEMORY;
2154
jsdValue::GetPropertyCount (PRInt32 *_rval)
2156
ASSERT_VALID_EPHEMERAL;
2157
if (JSD_IsValueObject(mCx, mValue))
2158
*_rval = JSD_GetCountOfProperties (mCx, mValue);
2165
jsdValue::GetProperties (jsdIProperty ***propArray, PRUint32 *length)
2167
ASSERT_VALID_EPHEMERAL;
2168
if (!JSD_IsValueObject(mCx, mValue)) {
2174
jsdIProperty **pa_temp;
2175
PRUint32 prop_count = JSD_GetCountOfProperties (mCx, mValue);
2177
pa_temp = NS_STATIC_CAST(jsdIProperty **,
2178
nsMemory::Alloc(sizeof (jsdIProperty *) *
2182
JSDProperty *iter = NULL;
2184
while ((prop = JSD_IterateProperties (mCx, mValue, &iter))) {
2185
pa_temp[i] = jsdProperty::FromPtr (mCx, prop);
2189
NS_ASSERTION (prop_count == i, "property count mismatch");
2191
/* if caller doesn't care about length, don't bother telling them */
2192
*propArray = pa_temp;
2194
*length = prop_count;
2200
jsdValue::GetProperty (const char *name, jsdIProperty **_rval)
2202
ASSERT_VALID_EPHEMERAL;
2203
JSContext *cx = JSD_GetDefaultJSContext (mCx);
2204
/* not rooting this */
2205
JSString *jstr_name = JS_NewStringCopyZ (cx, name);
2207
JSDProperty *prop = JSD_GetValueProperty (mCx, mValue, jstr_name);
2209
*_rval = jsdProperty::FromPtr (mCx, prop);
2216
ASSERT_VALID_EPHEMERAL;
2217
JSD_RefreshValue (mCx, mValue);
2222
jsdValue::GetWrappedValue()
2224
ASSERT_VALID_EPHEMERAL;
2225
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
2227
return NS_ERROR_FAILURE;
2230
nsCOMPtr<nsIXPCNativeCallContext> cc;
2231
rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
2236
rv = cc->GetRetValPtr(&result);
2242
*result = JSD_GetValueWrappedJSVal (mCx, mValue);
2243
cc->SetReturnValueWasSet(PR_TRUE);
2249
/******************************************************************************
2250
* debugger service implementation
2251
******************************************************************************/
2252
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdService, jsdIDebuggerService)
2255
jsdService::GetJSDContext(JSDContext **_rval)
2262
jsdService::GetInitAtStartup (PRBool *_rval)
2265
nsCOMPtr<nsICategoryManager>
2266
categoryManager(do_GetService(NS_CATMAN_CTRID, &rv));
2270
NS_WARNING("couldn't get category manager");
2274
if (mInitAtStartup == triUnknown) {
2275
nsXPIDLCString notused;
2276
nsresult autoreg_rv, appstart_rv;
2278
autoreg_rv = categoryManager->GetCategoryEntry(AUTOREG_CATEGORY,
2280
getter_Copies(notused));
2281
appstart_rv = categoryManager->GetCategoryEntry(APPSTART_CATEGORY,
2283
getter_Copies(notused));
2284
if (autoreg_rv != appstart_rv) {
2285
/* we have an inconsistent state in the registry, attempt to fix.
2286
* we need to make mInitAtStartup disagree with the state passed
2287
* to SetInitAtStartup to make it actually do something.
2289
mInitAtStartup = triYes;
2290
rv = SetInitAtStartup (PR_FALSE);
2293
NS_WARNING("SetInitAtStartup failed");
2296
} else if (autoreg_rv == NS_ERROR_NOT_AVAILABLE) {
2297
mInitAtStartup = triNo;
2298
} else if (NS_SUCCEEDED(autoreg_rv)) {
2299
mInitAtStartup = triYes;
2301
NS_WARN_IF_FALSE(NS_SUCCEEDED(autoreg_rv),
2302
"couldn't get autoreg category");
2303
NS_WARN_IF_FALSE(NS_SUCCEEDED(appstart_rv),
2304
"couldn't get appstart category");
2310
*_rval = (mInitAtStartup == triYes);
2316
* The initAtStartup property controls whether or not we register the
2317
* app start observer (jsdASObserver.) We register for both
2318
* "xpcom-autoregistration" and "app-startup" notifications if |state| is true.
2319
* the autoreg message is sent just before registration occurs (before
2320
* "app-startup".) We care about autoreg because it may load javascript
2321
* components. autoreg does *not* fire if components haven't changed since the
2322
* last autoreg, so we watch "app-startup" as a fallback.
2325
jsdService::SetInitAtStartup (PRBool state)
2329
if (mInitAtStartup == triUnknown) {
2330
/* side effect sets mInitAtStartup */
2331
rv = GetInitAtStartup(nsnull);
2336
if (state && mInitAtStartup == triYes ||
2337
!state && mInitAtStartup == triNo) {
2338
/* already in the requested state */
2342
nsCOMPtr<nsICategoryManager>
2343
categoryManager(do_GetService(NS_CATMAN_CTRID, &rv));
2346
rv = categoryManager->AddCategoryEntry(AUTOREG_CATEGORY,
2349
PR_TRUE, PR_TRUE, nsnull);
2352
rv = categoryManager->AddCategoryEntry(APPSTART_CATEGORY,
2355
PR_TRUE, PR_TRUE, nsnull);
2358
mInitAtStartup = triYes;
2360
rv = categoryManager->DeleteCategoryEntry(AUTOREG_CATEGORY,
2361
JSD_AUTOREG_ENTRY, PR_TRUE);
2364
rv = categoryManager->DeleteCategoryEntry(APPSTART_CATEGORY,
2365
JSD_STARTUP_ENTRY, PR_TRUE);
2368
mInitAtStartup = triNo;
2375
jsdService::GetFlags (PRUint32 *_rval)
2377
*_rval = JSD_GetContextFlags (mCx);
2382
jsdService::SetFlags (PRUint32 flags)
2384
JSD_SetContextFlags (mCx, flags);
2389
jsdService::GetImplementationString(char **_rval)
2391
*_rval = PL_strdup(implementationString);
2393
return NS_ERROR_OUT_OF_MEMORY;
2398
jsdService::GetImplementationMajor(PRUint32 *_rval)
2400
*_rval = JSDS_MAJOR_VERSION;
2405
jsdService::GetImplementationMinor(PRUint32 *_rval)
2407
*_rval = JSDS_MINOR_VERSION;
2412
jsdService::GetIsOn (PRBool *_rval)
2419
jsdService::On (void)
2423
/* get JS things from the CallContext */
2424
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
2425
if (!xpc) return NS_ERROR_FAILURE;
2427
nsCOMPtr<nsIXPCNativeCallContext> cc;
2428
rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
2429
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2432
rv = cc->GetJSContext (&cx);
2433
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2435
return OnForRuntime(JS_GetRuntime (cx));
2440
jsdService::OnForRuntime (JSRuntime *rt)
2443
return (rt == mRuntime) ? NS_OK : NS_ERROR_ALREADY_INITIALIZED;
2447
if (gLastGCProc == jsds_GCCallbackProc)
2448
/* condition indicates that the callback proc has not been set yet */
2449
gLastGCProc = JS_SetGCCallbackRT (rt, jsds_GCCallbackProc);
2451
mCx = JSD_DebuggerOnForUser (rt, NULL, NULL);
2453
return NS_ERROR_FAILURE;
2455
JSContext *cx = JSD_GetDefaultJSContext (mCx);
2456
JSObject *glob = JS_GetGlobalObject (cx);
2458
/* init xpconnect on the debugger's context in case xpconnect tries to
2459
* use it for stuff. */
2460
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
2462
return NS_ERROR_FAILURE;
2464
xpc->InitClasses (cx, glob);
2466
/* If any of these mFooHook objects are installed, do the required JSD
2467
* hookup now. See also, jsdService::SetFooHook().
2470
JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
2472
JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
2473
/* can't ignore script callbacks, as we need to |Release| the wrapper
2474
* stored in private data when a script is deleted. */
2476
JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
2478
JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
2480
JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
2482
JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
2484
JSD_ClearTopLevelHook (mCx);
2486
JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
2488
JSD_ClearFunctionHook (mCx);
2492
printf ("+++ JavaScript debugging hooks installed.\n");
2498
jsdService::Off (void)
2503
if (!mCx || !mRuntime)
2504
return NS_ERROR_NOT_INITIALIZED;
2507
if (gGCStatus == JSGC_END)
2509
JSContext *cx = JSD_GetDefaultJSContext(mCx);
2510
jsds_NotifyPendingDeadScripts(cx);
2513
return NS_ERROR_NOT_AVAILABLE;
2517
if (gLastGCProc != jsds_GCCallbackProc)
2518
JS_SetGCCallbackRT (mRuntime, gLastGCProc);
2521
jsdContext::InvalidateAll();
2522
jsdScript::InvalidateAll();
2523
jsdValue::InvalidateAll();
2524
jsdProperty::InvalidateAll();
2525
ClearAllBreakpoints();
2527
JSD_SetErrorReporter (mCx, NULL, NULL);
2528
JSD_ClearThrowHook (mCx);
2529
JSD_ClearInterruptHook (mCx);
2530
JSD_ClearDebuggerHook (mCx);
2531
JSD_ClearDebugBreakHook (mCx);
2532
JSD_ClearTopLevelHook (mCx);
2533
JSD_ClearFunctionHook (mCx);
2535
JSD_DebuggerOff (mCx);
2542
printf ("+++ JavaScript debugging hooks removed.\n");
2549
jsdService::GetPauseDepth(PRUint32 *_rval)
2551
NS_ENSURE_ARG_POINTER(_rval);
2552
*_rval = mPauseLevel;
2557
jsdService::Pause(PRUint32 *_rval)
2559
if (++mPauseLevel == 1) {
2560
JSD_SetErrorReporter (mCx, NULL, NULL);
2561
JSD_ClearThrowHook (mCx);
2562
JSD_ClearInterruptHook (mCx);
2563
JSD_ClearDebuggerHook (mCx);
2564
JSD_ClearDebugBreakHook (mCx);
2565
JSD_ClearTopLevelHook (mCx);
2566
JSD_ClearFunctionHook (mCx);
2570
*_rval = mPauseLevel;
2576
jsdService::UnPause(PRUint32 *_rval)
2578
if (mPauseLevel == 0)
2579
return NS_ERROR_NOT_AVAILABLE;
2581
/* check mOn before we muck with this stuff, it's possible the debugger
2582
* was turned off while we were paused.
2584
if (--mPauseLevel == 0 && mOn) {
2586
JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
2588
JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
2590
JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
2592
JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
2594
JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
2596
JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
2598
JSD_ClearTopLevelHook (mCx);
2600
JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
2602
JSD_ClearFunctionHook (mCx);
2606
*_rval = mPauseLevel;
2612
jsdService::EnumerateContexts (jsdIContextEnumerator *enumerator)
2614
ASSERT_VALID_CONTEXT;
2619
JSContext *iter = NULL;
2622
while ((cx = JS_ContextIterator (mRuntime, &iter)))
2624
nsCOMPtr<jsdIContext> jsdicx =
2625
getter_AddRefs(jsdContext::FromPtr(mCx, cx));
2628
if (NS_FAILED(enumerator->EnumerateContext(jsdicx)))
2637
jsdService::EnumerateScripts (jsdIScriptEnumerator *enumerator)
2639
ASSERT_VALID_CONTEXT;
2642
JSDScript *iter = NULL;
2643
nsresult rv = NS_OK;
2645
JSD_LockScriptSubsystem(mCx);
2646
while((script = JSD_IterateScripts(mCx, &iter))) {
2647
nsCOMPtr<jsdIScript> jsdis =
2648
getter_AddRefs(jsdScript::FromPtr(mCx, script));
2649
rv = enumerator->EnumerateScript (jsdis);
2653
JSD_UnlockScriptSubsystem(mCx);
2658
#ifdef GC_MARK_DEBUG
2660
JS_FRIEND_DATA(FILE *) js_DumpGCHeap;
2665
jsdService::GC (void)
2667
ASSERT_VALID_CONTEXT;
2668
JSContext *cx = JSD_GetDefaultJSContext (mCx);
2669
#ifdef GC_MARK_DEBUG
2670
FILE *file = fopen("jsds-roots.txt", "w");
2671
js_DumpGCHeap = file;
2674
#ifdef GC_MARK_DEBUG
2677
js_DumpGCHeap = NULL;
2683
jsdService::ClearProfileData ()
2685
ASSERT_VALID_CONTEXT;
2686
JSD_ClearAllProfileData (mCx);
2691
jsdService::InsertFilter (jsdIFilter *filter, jsdIFilter *after)
2693
NS_ENSURE_ARG_POINTER (filter);
2694
if (jsds_FindFilter (filter))
2695
return NS_ERROR_INVALID_ARG;
2697
FilterRecord *rec = PR_NEWZAP (FilterRecord);
2699
return NS_ERROR_OUT_OF_MEMORY;
2701
if (!jsds_SyncFilter (rec, filter)) {
2703
return NS_ERROR_FAILURE;
2708
/* insert at head of list */
2709
PR_INSERT_LINK(&rec->links, &gFilters->links);
2712
/* insert somewhere in the list */
2713
FilterRecord *afterRecord = jsds_FindFilter (after);
2715
jsds_FreeFilter(rec);
2716
return NS_ERROR_INVALID_ARG;
2718
PR_INSERT_AFTER(&rec->links, &afterRecord->links);
2722
/* user asked to insert into the middle of an empty list, bail. */
2723
jsds_FreeFilter(rec);
2724
return NS_ERROR_NOT_INITIALIZED;
2726
PR_INIT_CLIST(&rec->links);
2734
jsdService::AppendFilter (jsdIFilter *filter)
2736
NS_ENSURE_ARG_POINTER (filter);
2737
if (jsds_FindFilter (filter))
2738
return NS_ERROR_INVALID_ARG;
2739
FilterRecord *rec = PR_NEWZAP (FilterRecord);
2741
if (!jsds_SyncFilter (rec, filter)) {
2743
return NS_ERROR_FAILURE;
2747
PR_INSERT_BEFORE(&rec->links, &gFilters->links);
2749
PR_INIT_CLIST(&rec->links);
2757
jsdService::RemoveFilter (jsdIFilter *filter)
2759
NS_ENSURE_ARG_POINTER(filter);
2760
FilterRecord *rec = jsds_FindFilter (filter);
2762
return NS_ERROR_INVALID_ARG;
2764
if (gFilters == rec) {
2765
gFilters = NS_REINTERPRET_CAST(FilterRecord *,
2766
PR_NEXT_LINK(&rec->links));
2767
/* If we're the only filter left, null out the list head. */
2768
if (gFilters == rec)
2773
PR_REMOVE_LINK(&rec->links);
2774
jsds_FreeFilter (rec);
2780
jsdService::SwapFilters (jsdIFilter *filter_a, jsdIFilter *filter_b)
2782
NS_ENSURE_ARG_POINTER(filter_a);
2783
NS_ENSURE_ARG_POINTER(filter_b);
2785
FilterRecord *rec_a = jsds_FindFilter (filter_a);
2787
return NS_ERROR_INVALID_ARG;
2789
if (filter_a == filter_b) {
2790
/* just a refresh */
2791
if (!jsds_SyncFilter (rec_a, filter_a))
2792
return NS_ERROR_FAILURE;
2796
FilterRecord *rec_b = jsds_FindFilter (filter_b);
2798
/* filter_b is not in the list, replace filter_a with filter_b. */
2799
if (!jsds_SyncFilter (rec_a, filter_b))
2800
return NS_ERROR_FAILURE;
2802
/* both filters are in the list, swap. */
2803
if (!jsds_SyncFilter (rec_a, filter_b))
2804
return NS_ERROR_FAILURE;
2805
if (!jsds_SyncFilter (rec_b, filter_a))
2806
return NS_ERROR_FAILURE;
2813
jsdService::EnumerateFilters (jsdIFilterEnumerator *enumerator)
2818
FilterRecord *current = gFilters;
2820
jsds_SyncFilter (current, current->filterObject);
2821
/* SyncFilter failure would be bad, but what would we do about it? */
2823
nsresult rv = enumerator->EnumerateFilter (current->filterObject);
2827
current = NS_REINTERPRET_CAST(FilterRecord *,
2828
PR_NEXT_LINK (¤t->links));
2829
} while (current != gFilters);
2835
jsdService::RefreshFilters ()
2837
return EnumerateFilters(nsnull);
2841
jsdService::ClearFilters ()
2846
FilterRecord *current = NS_REINTERPRET_CAST(FilterRecord *,
2847
PR_NEXT_LINK (&gFilters->links));
2849
FilterRecord *next = NS_REINTERPRET_CAST(FilterRecord *,
2850
PR_NEXT_LINK (¤t->links));
2851
PR_REMOVE_AND_INIT_LINK(¤t->links);
2852
jsds_FreeFilter(current);
2854
} while (current != gFilters);
2856
jsds_FreeFilter(current);
2863
jsdService::ClearAllBreakpoints (void)
2865
ASSERT_VALID_CONTEXT;
2867
JSD_LockScriptSubsystem(mCx);
2868
JSD_ClearAllExecutionHooks (mCx);
2869
JSD_UnlockScriptSubsystem(mCx);
2874
jsdService::WrapValue(jsdIValue **_rval)
2876
ASSERT_VALID_CONTEXT;
2878
nsCOMPtr<nsIXPConnect> xpc = do_GetService (nsIXPConnect::GetCID());
2880
return NS_ERROR_FAILURE;
2883
nsCOMPtr<nsIXPCNativeCallContext> cc;
2884
rv = xpc->GetCurrentNativeCallContext (getter_AddRefs(cc));
2889
rv = cc->GetArgc (&argc);
2893
return NS_ERROR_INVALID_ARG;
2896
rv = cc->GetArgvPtr (&argv);
2900
JSDValue *jsdv = JSD_NewValue (mCx, argv[0]);
2902
return NS_ERROR_FAILURE;
2904
*_rval = jsdValue::FromPtr (mCx, jsdv);
2910
jsdService::EnterNestedEventLoop (jsdINestCallback *callback, PRUint32 *_rval)
2912
nsCOMPtr<nsIAppShell> appShell(do_CreateInstance(kAppShellCID));
2913
NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
2914
nsCOMPtr<nsIEventQueueService>
2915
eventService(do_GetService(kEventQueueServiceCID));
2916
NS_ENSURE_TRUE(eventService, NS_ERROR_FAILURE);
2918
appShell->Create(0, nsnull);
2921
nsCOMPtr<nsIJSContextStack>
2922
stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
2923
nsresult rv = NS_OK;
2924
PRUint32 nestLevel = ++mNestedLoopLevel;
2926
nsCOMPtr<nsIEventQueue> eventQ;
2927
if (stack && NS_SUCCEEDED(stack->Push(nsnull)) &&
2928
NS_SUCCEEDED(eventService->PushThreadEventQueue(getter_AddRefs(eventQ))))
2930
if (NS_SUCCEEDED(rv) && callback) {
2932
rv = callback->OnNest();
2936
while(NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel)
2940
//PRBool processEvent;
2942
rv = appShell->GetNativeEvent(isRealEvent, data);
2943
if(NS_SUCCEEDED(rv))
2944
appShell->DispatchNativeEvent(isRealEvent, data);
2948
NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
2951
rv = NS_ERROR_FAILURE;
2953
eventService->PopThreadEventQueue(eventQ);
2954
appShell->Spindown();
2956
NS_ASSERTION (mNestedLoopLevel <= nestLevel,
2957
"nested event didn't unwind properly");
2958
if (mNestedLoopLevel == nestLevel)
2961
*_rval = mNestedLoopLevel;
2966
jsdService::ExitNestedEventLoop (PRUint32 *_rval)
2968
if (mNestedLoopLevel > 0)
2971
return NS_ERROR_FAILURE;
2973
*_rval = mNestedLoopLevel;
2977
/* hook attribute get/set functions */
2980
jsdService::SetErrorHook (jsdIErrorHook *aHook)
2984
/* if the debugger isn't initialized, that's all we can do for now. The
2985
* OnForRuntime() method will do the rest when the coast is clear.
2987
if (!mCx || mPauseLevel)
2991
JSD_SetErrorReporter (mCx, jsds_ErrorHookProc, NULL);
2993
JSD_SetErrorReporter (mCx, NULL, NULL);
2999
jsdService::GetErrorHook (jsdIErrorHook **aHook)
3001
*aHook = mErrorHook;
3002
NS_IF_ADDREF(*aHook);
3008
jsdService::SetBreakpointHook (jsdIExecutionHook *aHook)
3010
mBreakpointHook = aHook;
3015
jsdService::GetBreakpointHook (jsdIExecutionHook **aHook)
3017
*aHook = mBreakpointHook;
3018
NS_IF_ADDREF(*aHook);
3024
jsdService::SetDebugHook (jsdIExecutionHook *aHook)
3028
/* if the debugger isn't initialized, that's all we can do for now. The
3029
* OnForRuntime() method will do the rest when the coast is clear.
3031
if (!mCx || mPauseLevel)
3035
JSD_SetDebugBreakHook (mCx, jsds_ExecutionHookProc, NULL);
3037
JSD_ClearDebugBreakHook (mCx);
3043
jsdService::GetDebugHook (jsdIExecutionHook **aHook)
3045
*aHook = mDebugHook;
3046
NS_IF_ADDREF(*aHook);
3052
jsdService::SetDebuggerHook (jsdIExecutionHook *aHook)
3054
mDebuggerHook = aHook;
3056
/* if the debugger isn't initialized, that's all we can do for now. The
3057
* OnForRuntime() method will do the rest when the coast is clear.
3059
if (!mCx || mPauseLevel)
3063
JSD_SetDebuggerHook (mCx, jsds_ExecutionHookProc, NULL);
3065
JSD_ClearDebuggerHook (mCx);
3071
jsdService::GetDebuggerHook (jsdIExecutionHook **aHook)
3073
*aHook = mDebuggerHook;
3074
NS_IF_ADDREF(*aHook);
3080
jsdService::SetInterruptHook (jsdIExecutionHook *aHook)
3082
mInterruptHook = aHook;
3084
/* if the debugger isn't initialized, that's all we can do for now. The
3085
* OnForRuntime() method will do the rest when the coast is clear.
3087
if (!mCx || mPauseLevel)
3091
JSD_SetInterruptHook (mCx, jsds_ExecutionHookProc, NULL);
3093
JSD_ClearInterruptHook (mCx);
3099
jsdService::GetInterruptHook (jsdIExecutionHook **aHook)
3101
*aHook = mInterruptHook;
3102
NS_IF_ADDREF(*aHook);
3108
jsdService::SetScriptHook (jsdIScriptHook *aHook)
3110
mScriptHook = aHook;
3112
/* if the debugger isn't initialized, that's all we can do for now. The
3113
* OnForRuntime() method will do the rest when the coast is clear.
3115
if (!mCx || mPauseLevel)
3119
JSD_SetScriptHook (mCx, jsds_ScriptHookProc, NULL);
3120
/* we can't unset it if !aHook, because we still need to see script
3121
* deletes in order to Release the jsdIScripts held in JSDScript
3127
jsdService::GetScriptHook (jsdIScriptHook **aHook)
3129
*aHook = mScriptHook;
3130
NS_IF_ADDREF(*aHook);
3136
jsdService::SetThrowHook (jsdIExecutionHook *aHook)
3140
/* if the debugger isn't initialized, that's all we can do for now. The
3141
* OnForRuntime() method will do the rest when the coast is clear.
3143
if (!mCx || mPauseLevel)
3147
JSD_SetThrowHook (mCx, jsds_ExecutionHookProc, NULL);
3149
JSD_ClearThrowHook (mCx);
3155
jsdService::GetThrowHook (jsdIExecutionHook **aHook)
3157
*aHook = mThrowHook;
3158
NS_IF_ADDREF(*aHook);
3164
jsdService::SetTopLevelHook (jsdICallHook *aHook)
3166
mTopLevelHook = aHook;
3168
/* if the debugger isn't initialized, that's all we can do for now. The
3169
* OnForRuntime() method will do the rest when the coast is clear.
3171
if (!mCx || mPauseLevel)
3175
JSD_SetTopLevelHook (mCx, jsds_CallHookProc, NULL);
3177
JSD_ClearTopLevelHook (mCx);
3183
jsdService::GetTopLevelHook (jsdICallHook **aHook)
3185
*aHook = mTopLevelHook;
3186
NS_IF_ADDREF(*aHook);
3192
jsdService::SetFunctionHook (jsdICallHook *aHook)
3194
mFunctionHook = aHook;
3196
/* if the debugger isn't initialized, that's all we can do for now. The
3197
* OnForRuntime() method will do the rest when the coast is clear.
3199
if (!mCx || mPauseLevel)
3203
JSD_SetFunctionHook (mCx, jsds_CallHookProc, NULL);
3205
JSD_ClearFunctionHook (mCx);
3211
jsdService::GetFunctionHook (jsdICallHook **aHook)
3213
*aHook = mFunctionHook;
3214
NS_IF_ADDREF(*aHook);
3220
jsdService::~jsdService()
3228
jsdService::GetService ()
3231
gJsds = new jsdService();
3233
NS_IF_ADDREF(gJsds);
3237
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(jsdService, jsdService::GetService)
3239
/* app-start observer. turns on the debugger at app-start. this is inserted
3240
* and/or removed from the app-start category by the jsdService::initAtStartup
3243
class jsdASObserver : public nsIObserver
3252
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdASObserver, nsIObserver)
3255
jsdASObserver::Observe (nsISupports *aSubject, const char *aTopic,
3256
const PRUnichar *aData)
3260
// Hmm. Why is the app-startup observer called multiple times?
3261
//NS_ASSERTION(!gJsds, "app startup observer called twice");
3262
nsCOMPtr<jsdIDebuggerService> jsds = do_GetService(jsdServiceCtrID, &rv);
3265
rv = jsds->GetIsOn(&on);
3266
if (NS_FAILED(rv) || on)
3269
nsCOMPtr<nsIJSRuntimeService> rts = do_GetService(NS_JSRT_CTRID, &rv);
3274
rts->GetRuntime (&rt);
3278
rv = jsds->OnForRuntime(rt);
3282
return jsds->SetFlags(JSD_DISABLE_OBJECT_TRACE);
3285
NS_GENERIC_FACTORY_CONSTRUCTOR(jsdASObserver)
3287
static const nsModuleComponentInfo components[] = {
3288
{"JSDService", JSDSERVICE_CID, jsdServiceCtrID, jsdServiceConstructor},
3289
{"JSDASObserver", JSDASO_CID, jsdASObserverCtrID, jsdASObserverConstructor}
3292
NS_IMPL_NSGETMODULE(JavaScript_Debugger, components)
3294
/********************************************************************************
3295
********************************************************************************
3301
NS_IMPL_THREADSAFE_ISUPPORTS1(jsdThreadState, jsdIThreadState);
3304
jsdThreadState::GetJSDContext(JSDContext **_rval)
3311
jsdThreadState::GetJSDThreadState(JSDThreadState **_rval)
3313
*_rval = mThreadState;
3318
jsdThreadState::GetFrameCount (PRUint32 *_rval)
3320
*_rval = JSD_GetCountOfStackFrames (mCx, mThreadState);
3325
jsdThreadState::GetTopFrame (jsdIStackFrame **_rval)
3327
JSDStackFrameInfo *sfi = JSD_GetStackFrame (mCx, mThreadState);
3329
*_rval = jsdStackFrame::FromPtr (mCx, mThreadState, sfi);
3334
jsdThreadState::GetPendingException(jsdIValue **_rval)
3336
JSDValue *jsdv = JSD_GetException (mCx, mThreadState);
3338
*_rval = jsdValue::FromPtr (mCx, jsdv);
3343
jsdThreadState::SetPendingException(jsdIValue *aException)
3347
nsresult rv = aException->GetJSDValue (&jsdv);
3349
return NS_ERROR_FAILURE;
3351
if (!JSD_SetException (mCx, mThreadState, jsdv))
3352
return NS_ERROR_FAILURE;