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