Source.cpp (21108B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "debugger/Source.h" 8 9 #include "mozilla/Assertions.h" // for AssertionConditionType, MOZ_ASSERT 10 #include "mozilla/Maybe.h" // for Some, Maybe, Nothing 11 #include "mozilla/Variant.h" // for AsVariant, Variant 12 13 #include <stdint.h> // for uint32_t 14 #include <string.h> // for memcpy 15 #include <utility> // for move 16 17 #include "debugger/Debugger.h" // for DebuggerSourceReferent, Debugger 18 #include "debugger/Script.h" // for DebuggerScript 19 #include "frontend/FrontendContext.h" // for AutoReportFrontendContext 20 #include "gc/Tracer.h" // for TraceManuallyBarrieredCrossCompartmentEdge 21 #include "js/ColumnNumber.h" // JS::WasmFunctionIndex, JS::ColumnNumberOneOrigin 22 #include "js/CompilationAndEvaluation.h" // for Compile 23 #include "js/ErrorReport.h" // for JS_ReportErrorASCII, JS_ReportErrorNumberASCII 24 #include "js/experimental/TypedData.h" // for JS_NewUint8Array 25 #include "js/friend/ErrorMessages.h" // for GetErrorMessage, JSMSG_* 26 #include "js/GCVariant.h" // for GCVariant 27 #include "js/SourceText.h" // for JS::SourceOwnership 28 #include "js/String.h" // for JS_CopyStringCharsZ 29 #include "vm/BytecodeUtil.h" // for JSDVG_SEARCH_STACK 30 #include "vm/JSContext.h" // for JSContext (ptr only) 31 #include "vm/JSObject.h" // for JSObject, RequireObject 32 #include "vm/JSScript.h" // for ScriptSource, ScriptSourceObject 33 #include "vm/StringType.h" // for NewStringCopyZ, JSString (ptr only) 34 #include "vm/TypedArrayObject.h" // for TypedArrayObject, JSObject::is 35 #include "wasm/WasmCode.h" // for Metadata 36 #include "wasm/WasmDebug.h" // for DebugState 37 #include "wasm/WasmInstance.h" // for Instance 38 #include "wasm/WasmJS.h" // for WasmInstanceObject 39 #include "wasm/WasmTypeDecls.h" // for Bytes, Rooted<WasmInstanceObject*> 40 41 #include "debugger/Debugger-inl.h" // for Debugger::fromJSObject 42 #include "vm/JSObject-inl.h" // for InitClass 43 #include "vm/NativeObject-inl.h" // for NewTenuredObjectWithGivenProto 44 #include "wasm/WasmInstance-inl.h" 45 46 namespace js { 47 class GlobalObject; 48 } 49 50 using namespace js; 51 52 using mozilla::AsVariant; 53 using mozilla::Maybe; 54 using mozilla::Nothing; 55 using mozilla::Some; 56 57 const JSClassOps DebuggerSource::classOps_ = { 58 nullptr, // addProperty 59 nullptr, // delProperty 60 nullptr, // enumerate 61 nullptr, // newEnumerate 62 nullptr, // resolve 63 nullptr, // mayResolve 64 nullptr, // finalize 65 nullptr, // call 66 nullptr, // construct 67 CallTraceMethod<DebuggerSource>, // trace 68 }; 69 70 const JSClass DebuggerSource::class_ = { 71 "Source", 72 JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS), 73 &classOps_, 74 }; 75 76 /* static */ 77 NativeObject* DebuggerSource::initClass(JSContext* cx, 78 Handle<GlobalObject*> global, 79 HandleObject debugCtor) { 80 return InitClass(cx, debugCtor, nullptr, nullptr, "Source", construct, 0, 81 properties_, methods_, nullptr, nullptr); 82 } 83 84 /* static */ 85 DebuggerSource* DebuggerSource::create(JSContext* cx, HandleObject proto, 86 Handle<DebuggerSourceReferent> referent, 87 Handle<NativeObject*> debugger) { 88 Rooted<DebuggerSource*> sourceObj( 89 cx, NewTenuredObjectWithGivenProto<DebuggerSource>(cx, proto)); 90 if (!sourceObj) { 91 return nullptr; 92 } 93 sourceObj->setReservedSlot(OWNER_SLOT, ObjectValue(*debugger)); 94 referent.get().match([&](auto sourceHandle) { 95 sourceObj->setReservedSlotGCThingAsPrivate(SOURCE_SLOT, sourceHandle); 96 }); 97 98 return sourceObj; 99 } 100 101 Debugger* DebuggerSource::owner() const { 102 JSObject* dbgobj = &getReservedSlot(OWNER_SLOT).toObject(); 103 return Debugger::fromJSObject(dbgobj); 104 } 105 106 // For internal use only. 107 NativeObject* DebuggerSource::getReferentRawObject() const { 108 return maybePtrFromReservedSlot<NativeObject>(SOURCE_SLOT); 109 } 110 111 DebuggerSourceReferent DebuggerSource::getReferent() const { 112 if (NativeObject* referent = getReferentRawObject()) { 113 if (referent->is<ScriptSourceObject>()) { 114 return AsVariant(&referent->as<ScriptSourceObject>()); 115 } 116 return AsVariant(&referent->as<WasmInstanceObject>()); 117 } 118 return AsVariant(static_cast<ScriptSourceObject*>(nullptr)); 119 } 120 121 void DebuggerSource::trace(JSTracer* trc) { 122 // There is a barrier on private pointers, so the Unbarriered marking 123 // is okay. 124 if (JSObject* referent = getReferentRawObject()) { 125 TraceManuallyBarrieredCrossCompartmentEdge(trc, this, &referent, 126 "Debugger.Source referent"); 127 if (referent != getReferentRawObject()) { 128 setReservedSlotGCThingAsPrivateUnbarriered(SOURCE_SLOT, referent); 129 } 130 } 131 } 132 133 /* static */ 134 bool DebuggerSource::construct(JSContext* cx, unsigned argc, Value* vp) { 135 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR, 136 "Debugger.Source"); 137 return false; 138 } 139 140 /* static */ 141 DebuggerSource* DebuggerSource::check(JSContext* cx, HandleValue thisv) { 142 JSObject* thisobj = RequireObject(cx, thisv); 143 if (!thisobj) { 144 return nullptr; 145 } 146 if (!thisobj->is<DebuggerSource>()) { 147 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 148 JSMSG_INCOMPATIBLE_PROTO, "Debugger.Source", 149 "method", thisobj->getClass()->name); 150 return nullptr; 151 } 152 153 return &thisobj->as<DebuggerSource>(); 154 } 155 156 struct MOZ_STACK_CLASS DebuggerSource::CallData { 157 JSContext* cx; 158 const CallArgs& args; 159 160 Handle<DebuggerSource*> obj; 161 Rooted<DebuggerSourceReferent> referent; 162 163 CallData(JSContext* cx, const CallArgs& args, Handle<DebuggerSource*> obj) 164 : cx(cx), args(args), obj(obj), referent(cx, obj->getReferent()) {} 165 166 bool getText(); 167 bool getBinary(); 168 bool getURL(); 169 bool getStartLine(); 170 bool getStartColumn(); 171 bool getId(); 172 bool getDisplayURL(); 173 bool getElementProperty(); 174 bool getIntroductionScript(); 175 bool getIntroductionOffset(); 176 bool getIntroductionType(); 177 bool setSourceMapURL(); 178 bool getSourceMapURL(); 179 bool reparse(); 180 181 using Method = bool (CallData::*)(); 182 183 template <Method MyMethod> 184 static bool ToNative(JSContext* cx, unsigned argc, Value* vp); 185 }; 186 187 template <DebuggerSource::CallData::Method MyMethod> 188 /* static */ 189 bool DebuggerSource::CallData::ToNative(JSContext* cx, unsigned argc, 190 Value* vp) { 191 CallArgs args = CallArgsFromVp(argc, vp); 192 193 Rooted<DebuggerSource*> obj(cx, DebuggerSource::check(cx, args.thisv())); 194 if (!obj) { 195 return false; 196 } 197 198 CallData data(cx, args, obj); 199 return (data.*MyMethod)(); 200 } 201 202 class DebuggerSourceGetTextMatcher { 203 JSContext* cx_; 204 205 public: 206 explicit DebuggerSourceGetTextMatcher(JSContext* cx) : cx_(cx) {} 207 208 using ReturnType = JSString*; 209 210 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 211 ScriptSource* ss = sourceObject->source(); 212 bool hasSourceText; 213 if (!ScriptSource::loadSource(cx_, ss, &hasSourceText)) { 214 return nullptr; 215 } 216 if (!hasSourceText) { 217 return NewStringCopyZ<CanGC>(cx_, "[no source]"); 218 } 219 220 if (ss->shouldUnwrapEventHandlerBody()) { 221 return ss->functionBodyString(cx_); 222 } 223 224 return ss->substring(cx_, 0, ss->length()); 225 } 226 227 ReturnType match(Handle<WasmInstanceObject*> instanceObj) { 228 wasm::Instance& instance = instanceObj->instance(); 229 const char* msg; 230 if (!instance.debugEnabled()) { 231 msg = "Restart with developer tools open to view WebAssembly source."; 232 } else { 233 msg = "[debugger missing wasm binary-to-text conversion]"; 234 } 235 return NewStringCopyZ<CanGC>(cx_, msg); 236 } 237 }; 238 239 bool DebuggerSource::CallData::getText() { 240 Value textv = obj->getReservedSlot(TEXT_SLOT); 241 if (!textv.isUndefined()) { 242 MOZ_ASSERT(textv.isString()); 243 args.rval().set(textv); 244 return true; 245 } 246 247 DebuggerSourceGetTextMatcher matcher(cx); 248 JSString* str = referent.match(matcher); 249 if (!str) { 250 return false; 251 } 252 253 args.rval().setString(str); 254 obj->setReservedSlot(TEXT_SLOT, args.rval()); 255 return true; 256 } 257 258 bool DebuggerSource::CallData::getBinary() { 259 if (!referent.is<WasmInstanceObject*>()) { 260 ReportValueError(cx, JSMSG_DEBUG_BAD_REFERENT, JSDVG_SEARCH_STACK, 261 args.thisv(), nullptr, "a wasm source"); 262 return false; 263 } 264 265 Rooted<WasmInstanceObject*> instanceObj(cx, 266 referent.as<WasmInstanceObject*>()); 267 wasm::Instance& instance = instanceObj->instance(); 268 269 if (!instance.debugEnabled()) { 270 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 271 JSMSG_DEBUG_NO_BINARY_SOURCE); 272 return false; 273 } 274 275 const wasm::BytecodeSource& bytecode = instance.debug().bytecode(); 276 RootedObject arr(cx, JS_NewUint8Array(cx, bytecode.length())); 277 if (!arr) { 278 return false; 279 } 280 281 bytecode.copyTo((uint8_t*)arr->as<TypedArrayObject>().dataPointerUnshared()); 282 283 args.rval().setObject(*arr); 284 return true; 285 } 286 287 class DebuggerSourceGetURLMatcher { 288 JSContext* cx_; 289 290 public: 291 explicit DebuggerSourceGetURLMatcher(JSContext* cx) : cx_(cx) {} 292 293 using ReturnType = Maybe<JSString*>; 294 295 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 296 ScriptSource* ss = sourceObject->source(); 297 MOZ_ASSERT(ss); 298 if (const char* filename = ss->filename()) { 299 JS::UTF8Chars utf8chars(filename, strlen(filename)); 300 JSString* str = NewStringCopyUTF8N(cx_, utf8chars); 301 return Some(str); 302 } 303 return Nothing(); 304 } 305 ReturnType match(Handle<WasmInstanceObject*> instanceObj) { 306 return Some(instanceObj->instance().createDisplayURL(cx_)); 307 } 308 }; 309 310 bool DebuggerSource::CallData::getURL() { 311 DebuggerSourceGetURLMatcher matcher(cx); 312 Maybe<JSString*> str = referent.match(matcher); 313 if (str.isSome()) { 314 if (!*str) { 315 return false; 316 } 317 args.rval().setString(*str); 318 } else { 319 args.rval().setNull(); 320 } 321 return true; 322 } 323 324 class DebuggerSourceGetStartLineMatcher { 325 public: 326 using ReturnType = uint32_t; 327 328 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 329 ScriptSource* ss = sourceObject->source(); 330 return ss->startLine(); 331 } 332 ReturnType match(Handle<WasmInstanceObject*> instanceObj) { return 0; } 333 }; 334 335 bool DebuggerSource::CallData::getStartLine() { 336 DebuggerSourceGetStartLineMatcher matcher; 337 uint32_t line = referent.match(matcher); 338 args.rval().setNumber(line); 339 return true; 340 } 341 342 class DebuggerSourceGetStartColumnMatcher { 343 public: 344 using ReturnType = JS::LimitedColumnNumberOneOrigin; 345 346 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 347 ScriptSource* ss = sourceObject->source(); 348 return ss->startColumn(); 349 } 350 ReturnType match(Handle<WasmInstanceObject*> instanceObj) { 351 return JS::LimitedColumnNumberOneOrigin( 352 JS::WasmFunctionIndex::DefaultBinarySourceColumnNumberOneOrigin); 353 } 354 }; 355 356 bool DebuggerSource::CallData::getStartColumn() { 357 DebuggerSourceGetStartColumnMatcher matcher; 358 JS::LimitedColumnNumberOneOrigin column = referent.match(matcher); 359 args.rval().setNumber(column.oneOriginValue()); 360 return true; 361 } 362 363 class DebuggerSourceGetIdMatcher { 364 public: 365 using ReturnType = uint32_t; 366 367 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 368 ScriptSource* ss = sourceObject->source(); 369 return ss->id(); 370 } 371 ReturnType match(Handle<WasmInstanceObject*> instanceObj) { return 0; } 372 }; 373 374 bool DebuggerSource::CallData::getId() { 375 DebuggerSourceGetIdMatcher matcher; 376 uint32_t id = referent.match(matcher); 377 args.rval().setNumber(id); 378 return true; 379 } 380 381 struct DebuggerSourceGetDisplayURLMatcher { 382 using ReturnType = const char16_t*; 383 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 384 ScriptSource* ss = sourceObject->source(); 385 MOZ_ASSERT(ss); 386 return ss->hasDisplayURL() ? ss->displayURL() : nullptr; 387 } 388 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { 389 return wasmInstance->instance().codeMetaForAsmJS() 390 ? wasmInstance->instance() 391 .codeMetaForAsmJS() 392 ->displayURL() // asm.js 393 : nullptr; // wasm 394 } 395 }; 396 397 bool DebuggerSource::CallData::getDisplayURL() { 398 DebuggerSourceGetDisplayURLMatcher matcher; 399 if (const char16_t* displayURL = referent.match(matcher)) { 400 JSString* str = JS_NewUCStringCopyZ(cx, displayURL); 401 if (!str) { 402 return false; 403 } 404 args.rval().setString(str); 405 } else { 406 args.rval().setNull(); 407 } 408 return true; 409 } 410 411 struct DebuggerSourceGetElementPropertyMatcher { 412 using ReturnType = Value; 413 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 414 return sourceObject->unwrappedElementAttributeName(); 415 } 416 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { 417 return UndefinedValue(); 418 } 419 }; 420 421 bool DebuggerSource::CallData::getElementProperty() { 422 DebuggerSourceGetElementPropertyMatcher matcher; 423 args.rval().set(referent.match(matcher)); 424 return obj->owner()->wrapDebuggeeValue(cx, args.rval()); 425 } 426 427 class DebuggerSourceGetIntroductionScriptMatcher { 428 JSContext* cx_; 429 Debugger* dbg_; 430 MutableHandleValue rval_; 431 432 public: 433 DebuggerSourceGetIntroductionScriptMatcher(JSContext* cx, Debugger* dbg, 434 MutableHandleValue rval) 435 : cx_(cx), dbg_(dbg), rval_(rval) {} 436 437 using ReturnType = bool; 438 439 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 440 Rooted<BaseScript*> script(cx_, 441 sourceObject->unwrappedIntroductionScript()); 442 if (script) { 443 RootedObject scriptDO(cx_, dbg_->wrapScript(cx_, script)); 444 if (!scriptDO) { 445 return false; 446 } 447 rval_.setObject(*scriptDO); 448 } else { 449 rval_.setUndefined(); 450 } 451 return true; 452 } 453 454 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { 455 RootedObject ds(cx_, dbg_->wrapWasmScript(cx_, wasmInstance)); 456 if (!ds) { 457 return false; 458 } 459 rval_.setObject(*ds); 460 return true; 461 } 462 }; 463 464 bool DebuggerSource::CallData::getIntroductionScript() { 465 Debugger* dbg = obj->owner(); 466 DebuggerSourceGetIntroductionScriptMatcher matcher(cx, dbg, args.rval()); 467 return referent.match(matcher); 468 } 469 470 struct DebuggerGetIntroductionOffsetMatcher { 471 using ReturnType = Value; 472 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 473 // Regardless of what's recorded in the ScriptSourceObject and 474 // ScriptSource, only hand out the introduction offset if we also have 475 // the script within which it applies. 476 ScriptSource* ss = sourceObject->source(); 477 if (ss->hasIntroductionOffset() && 478 sourceObject->unwrappedIntroductionScript()) { 479 return Int32Value(ss->introductionOffset()); 480 } 481 return UndefinedValue(); 482 } 483 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { 484 return UndefinedValue(); 485 } 486 }; 487 488 bool DebuggerSource::CallData::getIntroductionOffset() { 489 DebuggerGetIntroductionOffsetMatcher matcher; 490 args.rval().set(referent.match(matcher)); 491 return true; 492 } 493 494 struct DebuggerSourceGetIntroductionTypeMatcher { 495 using ReturnType = const char*; 496 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 497 ScriptSource* ss = sourceObject->source(); 498 MOZ_ASSERT(ss); 499 return ss->hasIntroductionType() ? ss->introductionType() : nullptr; 500 } 501 ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { return "wasm"; } 502 }; 503 504 bool DebuggerSource::CallData::getIntroductionType() { 505 DebuggerSourceGetIntroductionTypeMatcher matcher; 506 if (const char* introductionType = referent.match(matcher)) { 507 JSString* str = NewStringCopyZ<CanGC>(cx, introductionType); 508 if (!str) { 509 return false; 510 } 511 args.rval().setString(str); 512 } else { 513 args.rval().setUndefined(); 514 } 515 516 return true; 517 } 518 519 ScriptSourceObject* EnsureSourceObject(JSContext* cx, 520 Handle<DebuggerSource*> obj) { 521 if (!obj->getReferent().is<ScriptSourceObject*>()) { 522 RootedValue v(cx, ObjectValue(*obj)); 523 ReportValueError(cx, JSMSG_DEBUG_BAD_REFERENT, JSDVG_SEARCH_STACK, v, 524 nullptr, "a JS source"); 525 return nullptr; 526 } 527 return obj->getReferent().as<ScriptSourceObject*>(); 528 } 529 530 bool DebuggerSource::CallData::setSourceMapURL() { 531 Rooted<ScriptSourceObject*> sourceObject(cx, EnsureSourceObject(cx, obj)); 532 if (!sourceObject) { 533 return false; 534 } 535 ScriptSource* ss = sourceObject->source(); 536 MOZ_ASSERT(ss); 537 538 if (!args.requireAtLeast(cx, "set sourceMapURL", 1)) { 539 return false; 540 } 541 542 JSString* str = ToString<CanGC>(cx, args[0]); 543 if (!str) { 544 return false; 545 } 546 547 UniqueTwoByteChars chars = JS_CopyStringCharsZ(cx, str); 548 if (!chars) { 549 return false; 550 } 551 552 AutoReportFrontendContext fc(cx); 553 if (!ss->setSourceMapURL(&fc, std::move(chars))) { 554 return false; 555 } 556 557 args.rval().setUndefined(); 558 return true; 559 } 560 561 class DebuggerSourceGetSourceMapURLMatcher { 562 JSContext* cx_; 563 MutableHandleString result_; 564 565 public: 566 explicit DebuggerSourceGetSourceMapURLMatcher(JSContext* cx, 567 MutableHandleString result) 568 : cx_(cx), result_(result) {} 569 570 using ReturnType = bool; 571 ReturnType match(Handle<ScriptSourceObject*> sourceObject) { 572 ScriptSource* ss = sourceObject->source(); 573 MOZ_ASSERT(ss); 574 if (!ss->hasSourceMapURL()) { 575 result_.set(nullptr); 576 return true; 577 } 578 JSString* str = JS_NewUCStringCopyZ(cx_, ss->sourceMapURL()); 579 if (!str) { 580 return false; 581 } 582 result_.set(str); 583 return true; 584 } 585 ReturnType match(Handle<WasmInstanceObject*> instanceObj) { 586 wasm::Instance& instance = instanceObj->instance(); 587 if (!instance.debugEnabled()) { 588 result_.set(nullptr); 589 return true; 590 } 591 592 RootedString str(cx_); 593 if (!instance.debug().getSourceMappingURL(cx_, &str)) { 594 return false; 595 } 596 597 result_.set(str); 598 return true; 599 } 600 }; 601 602 bool DebuggerSource::CallData::getSourceMapURL() { 603 RootedString result(cx); 604 DebuggerSourceGetSourceMapURLMatcher matcher(cx, &result); 605 if (!referent.match(matcher)) { 606 return false; 607 } 608 if (result) { 609 args.rval().setString(result); 610 } else { 611 args.rval().setNull(); 612 } 613 return true; 614 } 615 616 template <typename Unit> 617 static JSScript* ReparseSource(JSContext* cx, Handle<ScriptSourceObject*> sso) { 618 AutoRealm ar(cx, sso); 619 ScriptSource* ss = sso->source(); 620 621 JS::CompileOptions options(cx); 622 options.setHideScriptFromDebugger(true); 623 options.setFileAndLine(ss->filename(), ss->startLine()); 624 options.setColumn(JS::ColumnNumberOneOrigin(ss->startColumn())); 625 626 UncompressedSourceCache::AutoHoldEntry holder; 627 628 ScriptSource::PinnedUnits<Unit> units(cx, ss, holder, 0, ss->length()); 629 if (!units.get()) { 630 return nullptr; 631 } 632 633 JS::SourceText<Unit> srcBuf; 634 if (!srcBuf.init(cx, units.get(), ss->length(), 635 JS::SourceOwnership::Borrowed)) { 636 return nullptr; 637 } 638 639 return JS::Compile(cx, options, srcBuf); 640 } 641 642 bool DebuggerSource::CallData::reparse() { 643 Rooted<ScriptSourceObject*> sourceObject(cx, EnsureSourceObject(cx, obj)); 644 if (!sourceObject) { 645 return false; 646 } 647 648 if (!sourceObject->source()->hasSourceText()) { 649 JS_ReportErrorASCII(cx, "Source object missing text"); 650 return false; 651 } 652 653 RootedScript script(cx); 654 if (sourceObject->source()->hasSourceType<mozilla::Utf8Unit>()) { 655 script = ReparseSource<mozilla::Utf8Unit>(cx, sourceObject); 656 } else { 657 script = ReparseSource<char16_t>(cx, sourceObject); 658 } 659 660 if (!script) { 661 return false; 662 } 663 664 Debugger* dbg = obj->owner(); 665 RootedObject scriptDO(cx, dbg->wrapScript(cx, script)); 666 if (!scriptDO) { 667 return false; 668 } 669 670 args.rval().setObject(*scriptDO); 671 return true; 672 } 673 674 const JSPropertySpec DebuggerSource::properties_[] = { 675 JS_DEBUG_PSG("text", getText), 676 JS_DEBUG_PSG("binary", getBinary), 677 JS_DEBUG_PSG("url", getURL), 678 JS_DEBUG_PSG("startLine", getStartLine), 679 JS_DEBUG_PSG("startColumn", getStartColumn), 680 JS_DEBUG_PSG("id", getId), 681 JS_DEBUG_PSG("displayURL", getDisplayURL), 682 JS_DEBUG_PSG("introductionScript", getIntroductionScript), 683 JS_DEBUG_PSG("introductionOffset", getIntroductionOffset), 684 JS_DEBUG_PSG("introductionType", getIntroductionType), 685 JS_DEBUG_PSG("elementAttributeName", getElementProperty), 686 JS_DEBUG_PSGS("sourceMapURL", getSourceMapURL, setSourceMapURL), 687 JS_PS_END, 688 }; 689 690 const JSFunctionSpec DebuggerSource::methods_[] = { 691 JS_DEBUG_FN("reparse", reparse, 0), 692 JS_FS_END, 693 };