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