Thu, 15 Jan 2015 15:55:04 +0100
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(¤t->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(¤tFilter->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 (¤t->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 (¤t->links)); |
michael@0 | 2973 | PR_REMOVE_AND_INIT_LINK(¤t->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 |