js/jsd/jsd_xpc.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

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

mercurial