Object.cpp (82138B)
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/Object-inl.h" 8 9 #include "mozilla/Maybe.h" // for Maybe, Nothing, Some 10 #include "mozilla/Range.h" // for Range 11 #include "mozilla/Result.h" // for Result 12 #include "mozilla/Vector.h" // for Vector 13 14 #include <algorithm> 15 #include <string.h> // for size_t, strlen 16 #include <utility> // for move 17 18 #include "jsapi.h" // for CallArgs, RootedObject, Rooted 19 20 #include "builtin/Array.h" // for NewDenseCopiedArray 21 #include "builtin/Promise.h" // for PromiseReactionRecordBuilder 22 #include "debugger/Debugger.h" // for Completion, Debugger 23 #include "debugger/Frame.h" // for DebuggerFrame 24 #include "debugger/NoExecute.h" // for LeaveDebuggeeNoExecute 25 #include "debugger/Script.h" // for DebuggerScript 26 #include "debugger/Source.h" // for DebuggerSource 27 #include "gc/Tracer.h" // for TraceManuallyBarrieredCrossCompartmentEdge 28 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin 29 #include "js/CompilationAndEvaluation.h" // for Compile 30 #include "js/Conversions.h" // for ToObject 31 #include "js/experimental/JitInfo.h" // for JSJitInfo 32 #include "js/friend/ErrorMessages.h" // for GetErrorMessage, JSMSG_* 33 #include "js/friend/WindowProxy.h" // for IsWindow, IsWindowProxy, ToWindowIfWindowProxy 34 #include "js/HeapAPI.h" // for IsInsideNursery 35 #include "js/Promise.h" // for PromiseState 36 #include "js/PropertyAndElement.h" // for JS_GetProperty 37 #include "js/Proxy.h" // for PropertyDescriptor 38 #include "js/SourceText.h" // for SourceText 39 #include "js/StableStringChars.h" // for AutoStableStringChars 40 #include "js/String.h" // for JS::StringHasLatin1Chars 41 #include "proxy/ScriptedProxyHandler.h" // for ScriptedProxyHandler 42 #include "vm/ArgumentsObject.h" // for ARGS_LENGTH_MAX 43 #include "vm/ArrayObject.h" // for ArrayObject 44 #include "vm/AsyncFunction.h" // for AsyncGeneratorObject 45 #include "vm/AsyncIteration.h" // for AsyncFunctionGeneratorObject 46 #include "vm/BoundFunctionObject.h" // for BoundFunctionObject 47 #include "vm/BytecodeUtil.h" // for JSDVG_SEARCH_STACK 48 #include "vm/Compartment.h" // for Compartment 49 #include "vm/EnvironmentObject.h" // for GetDebugEnvironmentForFunction 50 #include "vm/ErrorObject.h" // for JSObject::is, ErrorObject 51 #include "vm/GeneratorObject.h" // for AbstractGeneratorObject 52 #include "vm/GlobalObject.h" // for JSObject::is, GlobalObject 53 #include "vm/Interpreter.h" // for Call 54 #include "vm/JSAtomUtils.h" // for Atomize, AtomizeString 55 #include "vm/JSContext.h" // for JSContext, ReportValueError 56 #include "vm/JSFunction.h" // for JSFunction 57 #include "vm/JSObject.h" // for GenericObject, NewObjectKind 58 #include "vm/JSScript.h" // for JSScript 59 #include "vm/NativeObject.h" // for NativeObject, JSObject::is 60 #include "vm/ObjectOperations.h" // for DefineProperty 61 #include "vm/PlainObject.h" // for js::PlainObject 62 #include "vm/PromiseObject.h" // for js::PromiseObject 63 #include "vm/Realm.h" // for AutoRealm, ErrorCopier, Realm 64 #include "vm/Runtime.h" // for JSAtomState 65 #include "vm/SavedFrame.h" // for SavedFrame 66 #include "vm/Scope.h" // for PositionalFormalParameterIter 67 #include "vm/SelfHosting.h" // for GetClonedSelfHostedFunctionName 68 #include "vm/Shape.h" // for Shape 69 #include "vm/Stack.h" // for InvokeArgs 70 #include "vm/StringType.h" // for JSAtom, PropertyName 71 #include "vm/WrapperObject.h" // for JSObject::is, WrapperObject 72 73 #include "gc/StableCellHasher-inl.h" 74 #include "vm/Compartment-inl.h" // for Compartment::wrap 75 #include "vm/JSObject-inl.h" // for GetObjectClassName, InitClass, NewObjectWithGivenProtoAndKind, ToPropertyKey 76 #include "vm/NativeObject-inl.h" // for NativeObject::global 77 #include "vm/ObjectOperations-inl.h" // for DeleteProperty, GetProperty 78 #include "vm/Realm-inl.h" // for AutoRealm::AutoRealm 79 80 using namespace js; 81 82 using JS::AutoStableStringChars; 83 using mozilla::Maybe; 84 using mozilla::Nothing; 85 using mozilla::Some; 86 87 const JSClassOps DebuggerObject::classOps_ = { 88 nullptr, // addProperty 89 nullptr, // delProperty 90 nullptr, // enumerate 91 nullptr, // newEnumerate 92 nullptr, // resolve 93 nullptr, // mayResolve 94 nullptr, // finalize 95 nullptr, // call 96 nullptr, // construct 97 CallTraceMethod<DebuggerObject>, // trace 98 }; 99 100 const JSClass DebuggerObject::class_ = { 101 "Object", 102 JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS), 103 &classOps_, 104 }; 105 106 void DebuggerObject::trace(JSTracer* trc) { 107 // There is a barrier on private pointers, so the Unbarriered marking 108 // is okay. 109 if (JSObject* referent = maybeReferent()) { 110 TraceManuallyBarrieredCrossCompartmentEdge(trc, this, &referent, 111 "Debugger.Object referent"); 112 if (referent != maybeReferent()) { 113 setReservedSlotGCThingAsPrivateUnbarriered(OBJECT_SLOT, referent); 114 } 115 } 116 } 117 118 static DebuggerObject* DebuggerObject_checkThis(JSContext* cx, 119 const CallArgs& args) { 120 JSObject* thisobj = RequireObject(cx, args.thisv()); 121 if (!thisobj) { 122 return nullptr; 123 } 124 if (!thisobj->is<DebuggerObject>()) { 125 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 126 JSMSG_INCOMPATIBLE_PROTO, "Debugger.Object", 127 "method", thisobj->getClass()->name); 128 return nullptr; 129 } 130 131 return &thisobj->as<DebuggerObject>(); 132 } 133 134 /* static */ 135 bool DebuggerObject::construct(JSContext* cx, unsigned argc, Value* vp) { 136 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR, 137 "Debugger.Object"); 138 return false; 139 } 140 141 struct MOZ_STACK_CLASS DebuggerObject::CallData { 142 JSContext* cx; 143 const CallArgs& args; 144 145 Handle<DebuggerObject*> object; 146 RootedObject referent; 147 148 CallData(JSContext* cx, const CallArgs& args, Handle<DebuggerObject*> obj) 149 : cx(cx), args(args), object(obj), referent(cx, obj->referent()) {} 150 151 // JSNative properties 152 bool callableGetter(); 153 bool isBoundFunctionGetter(); 154 bool isArrowFunctionGetter(); 155 bool isAsyncFunctionGetter(); 156 bool isClassConstructorGetter(); 157 bool isGeneratorFunctionGetter(); 158 bool protoGetter(); 159 bool classGetter(); 160 bool nameGetter(); 161 bool displayNameGetter(); 162 bool parameterNamesGetter(); 163 bool scriptGetter(); 164 bool environmentGetter(); 165 bool boundTargetFunctionGetter(); 166 bool boundThisGetter(); 167 bool boundArgumentsGetter(); 168 bool allocationSiteGetter(); 169 bool isErrorGetter(); 170 bool isMutedErrorGetter(); 171 bool errorMessageNameGetter(); 172 bool errorNotesGetter(); 173 bool errorLineNumberGetter(); 174 bool errorColumnNumberGetter(); 175 bool isProxyGetter(); 176 bool proxyTargetGetter(); 177 bool proxyHandlerGetter(); 178 bool isPromiseGetter(); 179 bool promiseStateGetter(); 180 bool promiseValueGetter(); 181 bool promiseReasonGetter(); 182 bool promiseLifetimeGetter(); 183 bool promiseTimeToResolutionGetter(); 184 bool promiseAllocationSiteGetter(); 185 bool promiseResolutionSiteGetter(); 186 bool promiseIDGetter(); 187 bool promiseDependentPromisesGetter(); 188 189 // JSNative methods 190 bool isExtensibleMethod(); 191 bool isSealedMethod(); 192 bool isFrozenMethod(); 193 bool getPropertyMethod(); 194 bool setPropertyMethod(); 195 bool getOwnPropertyNamesMethod(); 196 bool getOwnPropertyNamesLengthMethod(); 197 bool getOwnPropertySymbolsMethod(); 198 bool getOwnPrivatePropertiesMethod(); 199 bool getOwnPropertyDescriptorMethod(); 200 bool preventExtensionsMethod(); 201 bool sealMethod(); 202 bool freezeMethod(); 203 bool definePropertyMethod(); 204 bool definePropertiesMethod(); 205 bool deletePropertyMethod(); 206 bool callMethod(); 207 bool applyMethod(); 208 bool asEnvironmentMethod(); 209 bool forceLexicalInitializationByNameMethod(); 210 bool executeInGlobalMethod(); 211 bool executeInGlobalWithBindingsMethod(); 212 bool createSource(); 213 bool makeDebuggeeValueMethod(); 214 bool isSameNativeMethod(); 215 bool isSameNativeWithJitInfoMethod(); 216 bool isNativeGetterWithJitInfo(); 217 bool unsafeDereferenceMethod(); 218 bool unwrapMethod(); 219 bool getPromiseReactionsMethod(); 220 221 using Method = bool (CallData::*)(); 222 223 template <Method MyMethod> 224 static bool ToNative(JSContext* cx, unsigned argc, Value* vp); 225 }; 226 227 template <DebuggerObject::CallData::Method MyMethod> 228 /* static */ 229 bool DebuggerObject::CallData::ToNative(JSContext* cx, unsigned argc, 230 Value* vp) { 231 CallArgs args = CallArgsFromVp(argc, vp); 232 233 Rooted<DebuggerObject*> obj(cx, DebuggerObject_checkThis(cx, args)); 234 if (!obj) { 235 return false; 236 } 237 238 CallData data(cx, args, obj); 239 return (data.*MyMethod)(); 240 } 241 242 bool DebuggerObject::CallData::callableGetter() { 243 args.rval().setBoolean(object->isCallable()); 244 return true; 245 } 246 247 bool DebuggerObject::CallData::isBoundFunctionGetter() { 248 args.rval().setBoolean(object->isBoundFunction()); 249 return true; 250 } 251 252 bool DebuggerObject::CallData::isArrowFunctionGetter() { 253 if (!object->isDebuggeeFunction()) { 254 args.rval().setUndefined(); 255 return true; 256 } 257 258 args.rval().setBoolean(object->isArrowFunction()); 259 return true; 260 } 261 262 bool DebuggerObject::CallData::isAsyncFunctionGetter() { 263 if (!object->isDebuggeeFunction()) { 264 args.rval().setUndefined(); 265 return true; 266 } 267 268 args.rval().setBoolean(object->isAsyncFunction()); 269 return true; 270 } 271 272 bool DebuggerObject::CallData::isGeneratorFunctionGetter() { 273 if (!object->isDebuggeeFunction()) { 274 args.rval().setUndefined(); 275 return true; 276 } 277 278 args.rval().setBoolean(object->isGeneratorFunction()); 279 return true; 280 } 281 282 bool DebuggerObject::CallData::isClassConstructorGetter() { 283 if (!object->isDebuggeeFunction()) { 284 args.rval().setUndefined(); 285 return true; 286 } 287 288 args.rval().setBoolean(object->isClassConstructor()); 289 return true; 290 } 291 292 bool DebuggerObject::CallData::protoGetter() { 293 Rooted<DebuggerObject*> result(cx); 294 if (!DebuggerObject::getPrototypeOf(cx, object, &result)) { 295 return false; 296 } 297 298 args.rval().setObjectOrNull(result); 299 return true; 300 } 301 302 bool DebuggerObject::CallData::classGetter() { 303 RootedString result(cx); 304 if (!DebuggerObject::getClassName(cx, object, &result)) { 305 return false; 306 } 307 308 args.rval().setString(result); 309 return true; 310 } 311 312 bool DebuggerObject::CallData::nameGetter() { 313 if (!object->isFunction() && !object->isBoundFunction()) { 314 args.rval().setUndefined(); 315 return true; 316 } 317 318 JS::Rooted<JSAtom*> result(cx); 319 if (!object->name(cx, &result)) { 320 return false; 321 } 322 323 if (result) { 324 args.rval().setString(result); 325 } else { 326 args.rval().setUndefined(); 327 } 328 return true; 329 } 330 331 bool DebuggerObject::CallData::displayNameGetter() { 332 if (!object->isFunction() && !object->isBoundFunction()) { 333 args.rval().setUndefined(); 334 return true; 335 } 336 337 JS::Rooted<JSAtom*> result(cx); 338 if (!object->displayName(cx, &result)) { 339 return false; 340 } 341 if (result) { 342 args.rval().setString(result); 343 } else { 344 args.rval().setUndefined(); 345 } 346 return true; 347 } 348 349 bool DebuggerObject::CallData::parameterNamesGetter() { 350 if (!object->isDebuggeeFunction()) { 351 args.rval().setUndefined(); 352 return true; 353 } 354 355 RootedFunction referent(cx, &object->referent()->as<JSFunction>()); 356 357 ArrayObject* arr = GetFunctionParameterNamesArray(cx, referent); 358 if (!arr) { 359 return false; 360 } 361 362 args.rval().setObject(*arr); 363 return true; 364 } 365 366 bool DebuggerObject::CallData::scriptGetter() { 367 Debugger* dbg = object->owner(); 368 369 if (!referent->is<JSFunction>()) { 370 args.rval().setUndefined(); 371 return true; 372 } 373 374 RootedFunction fun(cx, &referent->as<JSFunction>()); 375 if (!IsInterpretedNonSelfHostedFunction(fun)) { 376 args.rval().setUndefined(); 377 return true; 378 } 379 380 RootedScript script(cx, GetOrCreateFunctionScript(cx, fun)); 381 if (!script) { 382 return false; 383 } 384 385 // Only hand out debuggee scripts. 386 if (!dbg->observesScript(script)) { 387 args.rval().setNull(); 388 return true; 389 } 390 391 Rooted<DebuggerScript*> scriptObject(cx, dbg->wrapScript(cx, script)); 392 if (!scriptObject) { 393 return false; 394 } 395 396 args.rval().setObject(*scriptObject); 397 return true; 398 } 399 400 bool DebuggerObject::CallData::environmentGetter() { 401 Debugger* dbg = object->owner(); 402 403 // Don't bother switching compartments just to check obj's type and get its 404 // env. 405 if (!referent->is<JSFunction>()) { 406 args.rval().setUndefined(); 407 return true; 408 } 409 410 RootedFunction fun(cx, &referent->as<JSFunction>()); 411 if (!IsInterpretedNonSelfHostedFunction(fun)) { 412 args.rval().setUndefined(); 413 return true; 414 } 415 416 // Only hand out environments of debuggee functions. 417 if (!dbg->observesGlobal(&fun->global())) { 418 args.rval().setNull(); 419 return true; 420 } 421 422 Rooted<Env*> env(cx); 423 { 424 AutoRealm ar(cx, fun); 425 env = GetDebugEnvironmentForFunction(cx, fun); 426 if (!env) { 427 return false; 428 } 429 } 430 431 return dbg->wrapEnvironment(cx, env, args.rval()); 432 } 433 434 bool DebuggerObject::CallData::boundTargetFunctionGetter() { 435 if (!object->isDebuggeeBoundFunction()) { 436 args.rval().setUndefined(); 437 return true; 438 } 439 440 Rooted<DebuggerObject*> result(cx); 441 if (!DebuggerObject::getBoundTargetFunction(cx, object, &result)) { 442 return false; 443 } 444 445 args.rval().setObject(*result); 446 return true; 447 } 448 449 bool DebuggerObject::CallData::boundThisGetter() { 450 if (!object->isDebuggeeBoundFunction()) { 451 args.rval().setUndefined(); 452 return true; 453 } 454 455 return DebuggerObject::getBoundThis(cx, object, args.rval()); 456 } 457 458 bool DebuggerObject::CallData::boundArgumentsGetter() { 459 if (!object->isDebuggeeBoundFunction()) { 460 args.rval().setUndefined(); 461 return true; 462 } 463 464 Rooted<ValueVector> result(cx, ValueVector(cx)); 465 if (!DebuggerObject::getBoundArguments(cx, object, &result)) { 466 return false; 467 } 468 469 RootedObject obj(cx, 470 NewDenseCopiedArray(cx, result.length(), result.begin())); 471 if (!obj) { 472 return false; 473 } 474 475 args.rval().setObject(*obj); 476 return true; 477 } 478 479 bool DebuggerObject::CallData::allocationSiteGetter() { 480 RootedObject result(cx); 481 if (!DebuggerObject::getAllocationSite(cx, object, &result)) { 482 return false; 483 } 484 485 args.rval().setObjectOrNull(result); 486 return true; 487 } 488 489 // Returns the "name" field (see js/public/friend/ErrorNumbers.msg), which may 490 // be used as a unique identifier, for any error object with a JSErrorReport or 491 // undefined if the object has no JSErrorReport. 492 bool DebuggerObject::CallData::errorMessageNameGetter() { 493 RootedString result(cx); 494 if (!DebuggerObject::getErrorMessageName(cx, object, &result)) { 495 return false; 496 } 497 498 if (result) { 499 args.rval().setString(result); 500 } else { 501 args.rval().setUndefined(); 502 } 503 return true; 504 } 505 506 bool DebuggerObject::CallData::isErrorGetter() { 507 args.rval().setBoolean(object->isError()); 508 return true; 509 } 510 511 bool DebuggerObject::CallData::isMutedErrorGetter() { 512 args.rval().setBoolean(object->isMutedError(cx)); 513 return true; 514 } 515 516 bool DebuggerObject::CallData::errorNotesGetter() { 517 return DebuggerObject::getErrorNotes(cx, object, args.rval()); 518 } 519 520 bool DebuggerObject::CallData::errorLineNumberGetter() { 521 return DebuggerObject::getErrorLineNumber(cx, object, args.rval()); 522 } 523 524 bool DebuggerObject::CallData::errorColumnNumberGetter() { 525 return DebuggerObject::getErrorColumnNumber(cx, object, args.rval()); 526 } 527 528 bool DebuggerObject::CallData::isProxyGetter() { 529 args.rval().setBoolean(object->isScriptedProxy()); 530 return true; 531 } 532 533 bool DebuggerObject::CallData::proxyTargetGetter() { 534 if (!object->isScriptedProxy()) { 535 args.rval().setUndefined(); 536 return true; 537 } 538 539 Rooted<DebuggerObject*> result(cx); 540 if (!DebuggerObject::getScriptedProxyTarget(cx, object, &result)) { 541 return false; 542 } 543 544 args.rval().setObjectOrNull(result); 545 return true; 546 } 547 548 bool DebuggerObject::CallData::proxyHandlerGetter() { 549 if (!object->isScriptedProxy()) { 550 args.rval().setUndefined(); 551 return true; 552 } 553 Rooted<DebuggerObject*> result(cx); 554 if (!DebuggerObject::getScriptedProxyHandler(cx, object, &result)) { 555 return false; 556 } 557 558 args.rval().setObjectOrNull(result); 559 return true; 560 } 561 562 bool DebuggerObject::CallData::isPromiseGetter() { 563 args.rval().setBoolean(object->isPromise()); 564 return true; 565 } 566 567 bool DebuggerObject::CallData::promiseStateGetter() { 568 if (!DebuggerObject::requirePromise(cx, object)) { 569 return false; 570 } 571 572 RootedValue result(cx); 573 switch (object->promiseState()) { 574 case JS::PromiseState::Pending: 575 result.setString(cx->names().pending); 576 break; 577 case JS::PromiseState::Fulfilled: 578 result.setString(cx->names().fulfilled); 579 break; 580 case JS::PromiseState::Rejected: 581 result.setString(cx->names().rejected); 582 break; 583 } 584 585 args.rval().set(result); 586 return true; 587 } 588 589 bool DebuggerObject::CallData::promiseValueGetter() { 590 if (!DebuggerObject::requirePromise(cx, object)) { 591 return false; 592 } 593 594 if (object->promiseState() != JS::PromiseState::Fulfilled) { 595 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 596 JSMSG_DEBUG_PROMISE_NOT_FULFILLED); 597 return false; 598 } 599 600 return DebuggerObject::getPromiseValue(cx, object, args.rval()); 601 ; 602 } 603 604 bool DebuggerObject::CallData::promiseReasonGetter() { 605 if (!DebuggerObject::requirePromise(cx, object)) { 606 return false; 607 } 608 609 if (object->promiseState() != JS::PromiseState::Rejected) { 610 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 611 JSMSG_DEBUG_PROMISE_NOT_REJECTED); 612 return false; 613 } 614 615 return DebuggerObject::getPromiseReason(cx, object, args.rval()); 616 } 617 618 bool DebuggerObject::CallData::promiseLifetimeGetter() { 619 if (!DebuggerObject::requirePromise(cx, object)) { 620 return false; 621 } 622 623 args.rval().setNumber(object->promiseLifetime()); 624 return true; 625 } 626 627 bool DebuggerObject::CallData::promiseTimeToResolutionGetter() { 628 if (!DebuggerObject::requirePromise(cx, object)) { 629 return false; 630 } 631 632 if (object->promiseState() == JS::PromiseState::Pending) { 633 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 634 JSMSG_DEBUG_PROMISE_NOT_RESOLVED); 635 return false; 636 } 637 638 args.rval().setNumber(object->promiseTimeToResolution()); 639 return true; 640 } 641 642 static PromiseObject* EnsurePromise(JSContext* cx, HandleObject referent) { 643 // We only care about promises, so CheckedUnwrapStatic is OK. 644 RootedObject obj(cx, CheckedUnwrapStatic(referent)); 645 if (!obj) { 646 ReportAccessDenied(cx); 647 return nullptr; 648 } 649 if (!obj->is<PromiseObject>()) { 650 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 651 JSMSG_NOT_EXPECTED_TYPE, "Debugger", "Promise", 652 obj->getClass()->name); 653 return nullptr; 654 } 655 return &obj->as<PromiseObject>(); 656 } 657 658 bool DebuggerObject::CallData::promiseAllocationSiteGetter() { 659 Rooted<PromiseObject*> promise(cx, EnsurePromise(cx, referent)); 660 if (!promise) { 661 return false; 662 } 663 664 RootedObject allocSite(cx, promise->allocationSite()); 665 if (!allocSite) { 666 args.rval().setNull(); 667 return true; 668 } 669 670 if (!cx->compartment()->wrap(cx, &allocSite)) { 671 return false; 672 } 673 args.rval().set(ObjectValue(*allocSite)); 674 return true; 675 } 676 677 bool DebuggerObject::CallData::promiseResolutionSiteGetter() { 678 Rooted<PromiseObject*> promise(cx, EnsurePromise(cx, referent)); 679 if (!promise) { 680 return false; 681 } 682 683 if (promise->state() == JS::PromiseState::Pending) { 684 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 685 JSMSG_DEBUG_PROMISE_NOT_RESOLVED); 686 return false; 687 } 688 689 RootedObject resolutionSite(cx, promise->resolutionSite()); 690 if (!resolutionSite) { 691 args.rval().setNull(); 692 return true; 693 } 694 695 if (!cx->compartment()->wrap(cx, &resolutionSite)) { 696 return false; 697 } 698 args.rval().set(ObjectValue(*resolutionSite)); 699 return true; 700 } 701 702 bool DebuggerObject::CallData::promiseIDGetter() { 703 Rooted<PromiseObject*> promise(cx, EnsurePromise(cx, referent)); 704 if (!promise) { 705 return false; 706 } 707 708 args.rval().setNumber(double(promise->getID())); 709 return true; 710 } 711 712 bool DebuggerObject::CallData::promiseDependentPromisesGetter() { 713 Debugger* dbg = object->owner(); 714 715 Rooted<PromiseObject*> promise(cx, EnsurePromise(cx, referent)); 716 if (!promise) { 717 return false; 718 } 719 720 Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx)); 721 { 722 JSAutoRealm ar(cx, promise); 723 if (!promise->dependentPromises(cx, &values)) { 724 return false; 725 } 726 } 727 for (size_t i = 0; i < values.length(); i++) { 728 if (!dbg->wrapDebuggeeValue(cx, values[i])) { 729 return false; 730 } 731 } 732 Rooted<ArrayObject*> promises(cx); 733 if (values.length() == 0) { 734 promises = NewDenseEmptyArray(cx); 735 } else { 736 promises = NewDenseCopiedArray(cx, values.length(), values[0].address()); 737 } 738 if (!promises) { 739 return false; 740 } 741 args.rval().setObject(*promises); 742 return true; 743 } 744 745 bool DebuggerObject::CallData::isExtensibleMethod() { 746 bool result; 747 if (!DebuggerObject::isExtensible(cx, object, result)) { 748 return false; 749 } 750 751 args.rval().setBoolean(result); 752 return true; 753 } 754 755 bool DebuggerObject::CallData::isSealedMethod() { 756 bool result; 757 if (!DebuggerObject::isSealed(cx, object, result)) { 758 return false; 759 } 760 761 args.rval().setBoolean(result); 762 return true; 763 } 764 765 bool DebuggerObject::CallData::isFrozenMethod() { 766 bool result; 767 if (!DebuggerObject::isFrozen(cx, object, result)) { 768 return false; 769 } 770 771 args.rval().setBoolean(result); 772 return true; 773 } 774 775 bool DebuggerObject::CallData::getOwnPropertyNamesMethod() { 776 RootedIdVector ids(cx); 777 if (!DebuggerObject::getOwnPropertyNames(cx, object, &ids)) { 778 return false; 779 } 780 781 JSObject* obj = IdVectorToArray(cx, ids); 782 if (!obj) { 783 return false; 784 } 785 786 args.rval().setObject(*obj); 787 return true; 788 } 789 790 bool DebuggerObject::CallData::getOwnPropertyNamesLengthMethod() { 791 size_t ownPropertiesLength; 792 if (!DebuggerObject::getOwnPropertyNamesLength(cx, object, 793 &ownPropertiesLength)) { 794 return false; 795 } 796 797 args.rval().setNumber(ownPropertiesLength); 798 return true; 799 } 800 801 bool DebuggerObject::CallData::getOwnPropertySymbolsMethod() { 802 RootedIdVector ids(cx); 803 if (!DebuggerObject::getOwnPropertySymbols(cx, object, &ids)) { 804 return false; 805 } 806 807 JSObject* obj = IdVectorToArray(cx, ids); 808 if (!obj) { 809 return false; 810 } 811 812 args.rval().setObject(*obj); 813 return true; 814 } 815 816 bool DebuggerObject::CallData::getOwnPrivatePropertiesMethod() { 817 RootedIdVector ids(cx); 818 if (!DebuggerObject::getOwnPrivateProperties(cx, object, &ids)) { 819 return false; 820 } 821 822 JSObject* obj = IdVectorToArray(cx, ids); 823 if (!obj) { 824 return false; 825 } 826 827 args.rval().setObject(*obj); 828 return true; 829 } 830 831 bool DebuggerObject::CallData::getOwnPropertyDescriptorMethod() { 832 RootedId id(cx); 833 if (!ToPropertyKey(cx, args.get(0), &id)) { 834 return false; 835 } 836 837 Rooted<Maybe<PropertyDescriptor>> desc(cx); 838 if (!DebuggerObject::getOwnPropertyDescriptor(cx, object, id, &desc)) { 839 return false; 840 } 841 842 return JS::FromPropertyDescriptor(cx, desc, args.rval()); 843 } 844 845 bool DebuggerObject::CallData::preventExtensionsMethod() { 846 if (!DebuggerObject::preventExtensions(cx, object)) { 847 return false; 848 } 849 850 args.rval().setUndefined(); 851 return true; 852 } 853 854 bool DebuggerObject::CallData::sealMethod() { 855 if (!DebuggerObject::seal(cx, object)) { 856 return false; 857 } 858 859 args.rval().setUndefined(); 860 return true; 861 } 862 863 bool DebuggerObject::CallData::freezeMethod() { 864 if (!DebuggerObject::freeze(cx, object)) { 865 return false; 866 } 867 868 args.rval().setUndefined(); 869 return true; 870 } 871 872 bool DebuggerObject::CallData::definePropertyMethod() { 873 if (!args.requireAtLeast(cx, "Debugger.Object.defineProperty", 2)) { 874 return false; 875 } 876 877 RootedId id(cx); 878 if (!ToPropertyKey(cx, args[0], &id)) { 879 return false; 880 } 881 882 Rooted<PropertyDescriptor> desc(cx); 883 if (!ToPropertyDescriptor(cx, args[1], false, &desc)) { 884 return false; 885 } 886 887 if (!DebuggerObject::defineProperty(cx, object, id, desc)) { 888 return false; 889 } 890 891 args.rval().setUndefined(); 892 return true; 893 } 894 895 bool DebuggerObject::CallData::definePropertiesMethod() { 896 if (!args.requireAtLeast(cx, "Debugger.Object.defineProperties", 1)) { 897 return false; 898 } 899 900 RootedValue arg(cx, args[0]); 901 RootedObject props(cx, ToObject(cx, arg)); 902 if (!props) { 903 return false; 904 } 905 RootedIdVector ids(cx); 906 Rooted<PropertyDescriptorVector> descs(cx, PropertyDescriptorVector(cx)); 907 if (!ReadPropertyDescriptors(cx, props, false, &ids, &descs)) { 908 return false; 909 } 910 Rooted<IdVector> ids2(cx, IdVector(cx)); 911 if (!ids2.append(ids.begin(), ids.end())) { 912 return false; 913 } 914 915 if (!DebuggerObject::defineProperties(cx, object, ids2, descs)) { 916 return false; 917 } 918 919 args.rval().setUndefined(); 920 return true; 921 } 922 923 /* 924 * This does a non-strict delete, as a matter of API design. The case where the 925 * property is non-configurable isn't necessarily exceptional here. 926 */ 927 bool DebuggerObject::CallData::deletePropertyMethod() { 928 RootedId id(cx); 929 if (!ToPropertyKey(cx, args.get(0), &id)) { 930 return false; 931 } 932 933 ObjectOpResult result; 934 if (!DebuggerObject::deleteProperty(cx, object, id, result)) { 935 return false; 936 } 937 938 args.rval().setBoolean(result.ok()); 939 return true; 940 } 941 942 bool DebuggerObject::CallData::callMethod() { 943 RootedValue thisv(cx, args.get(0)); 944 945 Rooted<ValueVector> nargs(cx, ValueVector(cx)); 946 if (args.length() >= 2) { 947 if (!nargs.growBy(args.length() - 1)) { 948 return false; 949 } 950 for (size_t i = 1; i < args.length(); ++i) { 951 nargs[i - 1].set(args[i]); 952 } 953 } 954 955 Rooted<Maybe<Completion>> completion( 956 cx, DebuggerObject::call(cx, object, thisv, nargs)); 957 if (!completion.get()) { 958 return false; 959 } 960 961 return completion->buildCompletionValue(cx, object->owner(), args.rval()); 962 } 963 964 bool DebuggerObject::CallData::getPropertyMethod() { 965 Debugger* dbg = object->owner(); 966 967 RootedId id(cx); 968 if (!ToPropertyKey(cx, args.get(0), &id)) { 969 return false; 970 } 971 972 RootedValue receiver(cx, 973 args.length() < 2 ? ObjectValue(*object) : args.get(1)); 974 975 Rooted<Completion> comp(cx); 976 JS_TRY_VAR_OR_RETURN_FALSE(cx, comp, getProperty(cx, object, id, receiver)); 977 return comp.get().buildCompletionValue(cx, dbg, args.rval()); 978 } 979 980 bool DebuggerObject::CallData::setPropertyMethod() { 981 Debugger* dbg = object->owner(); 982 983 RootedId id(cx); 984 if (!ToPropertyKey(cx, args.get(0), &id)) { 985 return false; 986 } 987 988 RootedValue value(cx, args.get(1)); 989 990 RootedValue receiver(cx, 991 args.length() < 3 ? ObjectValue(*object) : args.get(2)); 992 993 Rooted<Completion> comp(cx); 994 JS_TRY_VAR_OR_RETURN_FALSE(cx, comp, 995 setProperty(cx, object, id, value, receiver)); 996 return comp.get().buildCompletionValue(cx, dbg, args.rval()); 997 } 998 999 bool DebuggerObject::CallData::applyMethod() { 1000 RootedValue thisv(cx, args.get(0)); 1001 1002 Rooted<ValueVector> nargs(cx, ValueVector(cx)); 1003 if (args.length() >= 2 && !args[1].isNullOrUndefined()) { 1004 if (!args[1].isObject()) { 1005 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 1006 JSMSG_BAD_APPLY_ARGS, "apply"); 1007 return false; 1008 } 1009 1010 RootedObject argsobj(cx, &args[1].toObject()); 1011 1012 uint64_t argc = 0; 1013 if (!GetLengthProperty(cx, argsobj, &argc)) { 1014 return false; 1015 } 1016 argc = std::min(argc, uint64_t(ARGS_LENGTH_MAX)); 1017 1018 if (!nargs.growBy(argc) || !GetElements(cx, argsobj, argc, nargs.begin())) { 1019 return false; 1020 } 1021 } 1022 1023 Rooted<Maybe<Completion>> completion( 1024 cx, DebuggerObject::call(cx, object, thisv, nargs)); 1025 if (!completion.get()) { 1026 return false; 1027 } 1028 1029 return completion->buildCompletionValue(cx, object->owner(), args.rval()); 1030 } 1031 1032 static void EnterDebuggeeObjectRealm(JSContext* cx, Maybe<AutoRealm>& ar, 1033 JSObject* referent) { 1034 // |referent| may be a cross-compartment wrapper and CCWs normally 1035 // shouldn't be used with AutoRealm, but here we use an arbitrary realm for 1036 // now because we don't really have another option. 1037 ar.emplace(cx, referent->maybeCCWRealm()->maybeGlobal()); 1038 } 1039 1040 static bool RequireGlobalObject(JSContext* cx, HandleValue dbgobj, 1041 HandleObject referent) { 1042 RootedObject obj(cx, referent); 1043 1044 if (!obj->is<GlobalObject>()) { 1045 const char* isWrapper = ""; 1046 const char* isWindowProxy = ""; 1047 1048 // Help the poor programmer by pointing out wrappers around globals... 1049 if (obj->is<WrapperObject>()) { 1050 obj = js::UncheckedUnwrap(obj); 1051 isWrapper = "a wrapper around "; 1052 } 1053 1054 // ... and WindowProxies around Windows. 1055 if (IsWindowProxy(obj)) { 1056 obj = ToWindowIfWindowProxy(obj); 1057 isWindowProxy = "a WindowProxy referring to "; 1058 } 1059 1060 if (obj->is<GlobalObject>()) { 1061 ReportValueError(cx, JSMSG_DEBUG_WRAPPER_IN_WAY, JSDVG_SEARCH_STACK, 1062 dbgobj, nullptr, isWrapper, isWindowProxy); 1063 } else { 1064 ReportValueError(cx, JSMSG_DEBUG_BAD_REFERENT, JSDVG_SEARCH_STACK, dbgobj, 1065 nullptr, "a global object"); 1066 } 1067 return false; 1068 } 1069 1070 return true; 1071 } 1072 1073 bool DebuggerObject::CallData::asEnvironmentMethod() { 1074 Debugger* dbg = object->owner(); 1075 1076 if (!RequireGlobalObject(cx, args.thisv(), referent)) { 1077 return false; 1078 } 1079 1080 Rooted<Env*> env(cx); 1081 { 1082 AutoRealm ar(cx, referent); 1083 env = GetDebugEnvironmentForGlobalLexicalEnvironment(cx); 1084 if (!env) { 1085 return false; 1086 } 1087 } 1088 1089 return dbg->wrapEnvironment(cx, env, args.rval()); 1090 } 1091 1092 // Lookup a binding on the referent's global scope and change it to undefined 1093 // if it is an uninitialized lexical, otherwise do nothing. The method's 1094 // JavaScript return value is true _only_ when an uninitialized lexical has been 1095 // altered, otherwise it is false. 1096 bool DebuggerObject::CallData::forceLexicalInitializationByNameMethod() { 1097 if (!args.requireAtLeast( 1098 cx, "Debugger.Object.prototype.forceLexicalInitializationByName", 1099 1)) { 1100 return false; 1101 } 1102 1103 if (!DebuggerObject::requireGlobal(cx, object)) { 1104 return false; 1105 } 1106 1107 RootedId id(cx); 1108 if (!ValueToIdentifier(cx, args[0], &id)) { 1109 return false; 1110 } 1111 1112 bool result; 1113 if (!DebuggerObject::forceLexicalInitializationByName(cx, object, id, 1114 result)) { 1115 return false; 1116 } 1117 1118 args.rval().setBoolean(result); 1119 return true; 1120 } 1121 1122 bool DebuggerObject::CallData::executeInGlobalMethod() { 1123 if (!args.requireAtLeast(cx, "Debugger.Object.prototype.executeInGlobal", 1124 1)) { 1125 return false; 1126 } 1127 1128 if (!DebuggerObject::requireGlobal(cx, object)) { 1129 return false; 1130 } 1131 1132 AutoStableStringChars stableChars(cx); 1133 if (!ValueToStableChars(cx, "Debugger.Object.prototype.executeInGlobal", 1134 args[0], stableChars)) { 1135 return false; 1136 } 1137 mozilla::Range<const char16_t> chars = stableChars.twoByteRange(); 1138 1139 EvalOptions options(EvalOptions::EnvKind::Global); 1140 if (!ParseEvalOptions(cx, args.get(1), options)) { 1141 return false; 1142 } 1143 1144 Rooted<Completion> comp(cx); 1145 JS_TRY_VAR_OR_RETURN_FALSE( 1146 cx, comp, 1147 DebuggerObject::executeInGlobal(cx, object, chars, nullptr, options)); 1148 return comp.get().buildCompletionValue(cx, object->owner(), args.rval()); 1149 } 1150 1151 bool DebuggerObject::CallData::executeInGlobalWithBindingsMethod() { 1152 if (!args.requireAtLeast( 1153 cx, "Debugger.Object.prototype.executeInGlobalWithBindings", 2)) { 1154 return false; 1155 } 1156 1157 if (!DebuggerObject::requireGlobal(cx, object)) { 1158 return false; 1159 } 1160 1161 AutoStableStringChars stableChars(cx); 1162 if (!ValueToStableChars( 1163 cx, "Debugger.Object.prototype.executeInGlobalWithBindings", args[0], 1164 stableChars)) { 1165 return false; 1166 } 1167 mozilla::Range<const char16_t> chars = stableChars.twoByteRange(); 1168 1169 RootedObject bindings(cx, RequireObject(cx, args[1])); 1170 if (!bindings) { 1171 return false; 1172 } 1173 1174 EvalOptions options(EvalOptions::EnvKind::GlobalWithExtraOuterBindings); 1175 if (!ParseEvalOptions(cx, args.get(2), options)) { 1176 return false; 1177 } 1178 1179 Rooted<Completion> comp(cx); 1180 JS_TRY_VAR_OR_RETURN_FALSE( 1181 cx, comp, 1182 DebuggerObject::executeInGlobal(cx, object, chars, bindings, options)); 1183 return comp.get().buildCompletionValue(cx, object->owner(), args.rval()); 1184 } 1185 1186 // Copy a narrow or wide string to a vector, appending a null terminator. 1187 template <typename T> 1188 static bool CopyStringToVector(JSContext* cx, JSString* str, Vector<T>& chars) { 1189 JSLinearString* linear = str->ensureLinear(cx); 1190 if (!linear) { 1191 return false; 1192 } 1193 if (!chars.appendN(0, linear->length() + 1)) { 1194 return false; 1195 } 1196 CopyChars(chars.begin(), *linear); 1197 return true; 1198 } 1199 1200 bool DebuggerObject::CallData::createSource() { 1201 if (!args.requireAtLeast(cx, "Debugger.Object.prototype.createSource", 1)) { 1202 return false; 1203 } 1204 1205 if (!DebuggerObject::requireGlobal(cx, object)) { 1206 return false; 1207 } 1208 1209 Debugger* dbg = object->owner(); 1210 if (!dbg->isDebuggeeUnbarriered(referent->as<GlobalObject>().realm())) { 1211 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 1212 JSMSG_DEBUG_NOT_DEBUGGEE, "Debugger.Object", 1213 "global"); 1214 return false; 1215 } 1216 1217 RootedObject options(cx, ToObject(cx, args[0])); 1218 if (!options) { 1219 return false; 1220 } 1221 1222 RootedValue v(cx); 1223 if (!JS_GetProperty(cx, options, "text", &v)) { 1224 return false; 1225 } 1226 1227 RootedString text(cx, ToString<CanGC>(cx, v)); 1228 if (!text) { 1229 return false; 1230 } 1231 1232 if (!JS_GetProperty(cx, options, "url", &v)) { 1233 return false; 1234 } 1235 1236 RootedString url(cx, ToString<CanGC>(cx, v)); 1237 if (!url) { 1238 return false; 1239 } 1240 1241 if (!JS_GetProperty(cx, options, "startLine", &v)) { 1242 return false; 1243 } 1244 1245 uint32_t startLine; 1246 if (!ToUint32(cx, v, &startLine)) { 1247 return false; 1248 } 1249 1250 if (!JS_GetProperty(cx, options, "startColumn", &v)) { 1251 return false; 1252 } 1253 1254 uint32_t startColumn; 1255 if (!ToUint32(cx, v, &startColumn)) { 1256 return false; 1257 } 1258 if (startColumn == 0) { 1259 startColumn = 1; 1260 } 1261 1262 if (!JS_GetProperty(cx, options, "sourceMapURL", &v)) { 1263 return false; 1264 } 1265 1266 RootedString sourceMapURL(cx); 1267 if (!v.isUndefined()) { 1268 sourceMapURL = ToString<CanGC>(cx, v); 1269 if (!sourceMapURL) { 1270 return false; 1271 } 1272 } 1273 1274 if (!JS_GetProperty(cx, options, "isScriptElement", &v)) { 1275 return false; 1276 } 1277 1278 bool isScriptElement = ToBoolean(v); 1279 1280 if (!JS_GetProperty(cx, options, "forceEnableAsmJS", &v)) { 1281 return false; 1282 } 1283 1284 bool forceEnableAsmJS = ToBoolean(v); 1285 1286 RootedScript script(cx); 1287 { 1288 AutoRealm ar(cx, referent); 1289 1290 JS::CompileOptions compileOptions(cx); 1291 compileOptions.lineno = startLine; 1292 compileOptions.column = JS::ColumnNumberOneOrigin(startColumn); 1293 if (forceEnableAsmJS) { 1294 compileOptions.setAsmJSOption(JS::AsmJSOption::Enabled); 1295 } 1296 1297 if (!JS::StringHasLatin1Chars(url)) { 1298 JS_ReportErrorASCII(cx, "URL must be a narrow string"); 1299 return false; 1300 } 1301 1302 UniqueChars urlChars = JS_EncodeStringToUTF8(cx, url); 1303 if (!urlChars) { 1304 return false; 1305 } 1306 compileOptions.setFile(urlChars.get()); 1307 1308 Vector<char16_t> sourceMapURLChars(cx); 1309 if (sourceMapURL) { 1310 if (!CopyStringToVector(cx, sourceMapURL, sourceMapURLChars)) { 1311 return false; 1312 } 1313 compileOptions.setSourceMapURL(sourceMapURLChars.begin()); 1314 } 1315 1316 if (isScriptElement) { 1317 // The introduction type must be a statically allocated string. 1318 compileOptions.setIntroductionType("inlineScript"); 1319 } 1320 1321 AutoStableStringChars linearChars(cx); 1322 if (!linearChars.initTwoByte(cx, text)) { 1323 return false; 1324 } 1325 JS::SourceText<char16_t> srcBuf; 1326 if (!srcBuf.initMaybeBorrowed(cx, linearChars)) { 1327 return false; 1328 } 1329 1330 script = JS::Compile(cx, compileOptions, srcBuf); 1331 if (!script) { 1332 return false; 1333 } 1334 } 1335 1336 Rooted<ScriptSourceObject*> sso(cx, script->sourceObject()); 1337 RootedObject wrapped(cx, dbg->wrapSource(cx, sso)); 1338 if (!wrapped) { 1339 return false; 1340 } 1341 1342 args.rval().setObject(*wrapped); 1343 return true; 1344 } 1345 1346 bool DebuggerObject::CallData::makeDebuggeeValueMethod() { 1347 if (!args.requireAtLeast(cx, "Debugger.Object.prototype.makeDebuggeeValue", 1348 1)) { 1349 return false; 1350 } 1351 1352 return DebuggerObject::makeDebuggeeValue(cx, object, args[0], args.rval()); 1353 } 1354 1355 bool DebuggerObject::CallData::isSameNativeMethod() { 1356 if (!args.requireAtLeast(cx, "Debugger.Object.prototype.isSameNative", 1)) { 1357 return false; 1358 } 1359 1360 return DebuggerObject::isSameNative(cx, object, args[0], CheckJitInfo::No, 1361 args.rval()); 1362 } 1363 1364 bool DebuggerObject::CallData::isSameNativeWithJitInfoMethod() { 1365 if (!args.requireAtLeast( 1366 cx, "Debugger.Object.prototype.isSameNativeWithJitInfo", 1)) { 1367 return false; 1368 } 1369 1370 return DebuggerObject::isSameNative(cx, object, args[0], CheckJitInfo::Yes, 1371 args.rval()); 1372 } 1373 1374 bool DebuggerObject::CallData::isNativeGetterWithJitInfo() { 1375 return DebuggerObject::isNativeGetterWithJitInfo(cx, object, args.rval()); 1376 } 1377 1378 bool DebuggerObject::CallData::unsafeDereferenceMethod() { 1379 RootedObject result(cx); 1380 if (!DebuggerObject::unsafeDereference(cx, object, &result)) { 1381 return false; 1382 } 1383 1384 args.rval().setObject(*result); 1385 return true; 1386 } 1387 1388 bool DebuggerObject::CallData::unwrapMethod() { 1389 Rooted<DebuggerObject*> result(cx); 1390 if (!DebuggerObject::unwrap(cx, object, &result)) { 1391 return false; 1392 } 1393 1394 args.rval().setObjectOrNull(result); 1395 return true; 1396 } 1397 1398 struct DebuggerObject::PromiseReactionRecordBuilder 1399 : js::PromiseReactionRecordBuilder { 1400 Debugger* dbg; 1401 Handle<ArrayObject*> records; 1402 1403 PromiseReactionRecordBuilder(Debugger* dbg, Handle<ArrayObject*> records) 1404 : dbg(dbg), records(records) {} 1405 1406 bool then(JSContext* cx, HandleObject resolve, HandleObject reject, 1407 HandleObject result) override { 1408 Rooted<PlainObject*> record(cx, NewPlainObject(cx)); 1409 if (!record) { 1410 return false; 1411 } 1412 1413 if (!setIfNotNull(cx, record, cx->names().resolve, resolve) || 1414 !setIfNotNull(cx, record, cx->names().reject, reject) || 1415 !setIfNotNull(cx, record, cx->names().result, result)) { 1416 return false; 1417 } 1418 1419 return push(cx, record); 1420 } 1421 1422 bool direct(JSContext* cx, Handle<PromiseObject*> unwrappedPromise) override { 1423 RootedValue v(cx, ObjectValue(*unwrappedPromise)); 1424 return dbg->wrapDebuggeeValue(cx, &v) && push(cx, v); 1425 } 1426 1427 bool asyncFunction( 1428 JSContext* cx, 1429 Handle<AsyncFunctionGeneratorObject*> unwrappedGenerator) override { 1430 return maybePushGenerator(cx, unwrappedGenerator); 1431 } 1432 1433 bool asyncGenerator( 1434 JSContext* cx, 1435 Handle<AsyncGeneratorObject*> unwrappedGenerator) override { 1436 return maybePushGenerator(cx, unwrappedGenerator); 1437 } 1438 1439 private: 1440 bool push(JSContext* cx, HandleObject record) { 1441 RootedValue recordVal(cx, ObjectValue(*record)); 1442 return push(cx, recordVal); 1443 } 1444 1445 bool push(JSContext* cx, HandleValue recordVal) { 1446 return NewbornArrayPush(cx, records, recordVal); 1447 } 1448 1449 bool maybePushGenerator(JSContext* cx, 1450 Handle<AbstractGeneratorObject*> unwrappedGenerator) { 1451 Rooted<DebuggerFrame*> frame(cx); 1452 if (unwrappedGenerator->isClosed()) { 1453 // If the generator is closed, we can't generate a DebuggerFrame for it, 1454 // so we ignore it. 1455 return true; 1456 } 1457 if (!unwrappedGenerator->realm()->isDebuggee()) { 1458 // Caller can keep the reference to the debugger object even after 1459 // removing the realm from debuggee. Do nothing for this case. 1460 return true; 1461 } 1462 return dbg->getFrame(cx, unwrappedGenerator, &frame) && push(cx, frame); 1463 } 1464 1465 bool setIfNotNull(JSContext* cx, Handle<PlainObject*> obj, 1466 Handle<PropertyName*> name, HandleObject prop) { 1467 if (!prop) { 1468 return true; 1469 } 1470 1471 RootedValue v(cx, ObjectValue(*prop)); 1472 if (!dbg->wrapDebuggeeValue(cx, &v) || 1473 !DefineDataProperty(cx, obj, name, v)) { 1474 return false; 1475 } 1476 1477 return true; 1478 } 1479 }; 1480 1481 bool DebuggerObject::CallData::getPromiseReactionsMethod() { 1482 Debugger* dbg = object->owner(); 1483 1484 Rooted<PromiseObject*> unwrappedPromise(cx, EnsurePromise(cx, referent)); 1485 if (!unwrappedPromise) { 1486 return false; 1487 } 1488 1489 Rooted<ArrayObject*> holder(cx, NewDenseEmptyArray(cx)); 1490 if (!holder) { 1491 return false; 1492 } 1493 1494 PromiseReactionRecordBuilder builder(dbg, holder); 1495 if (!unwrappedPromise->forEachReactionRecord(cx, builder)) { 1496 return false; 1497 } 1498 1499 args.rval().setObject(*builder.records); 1500 return true; 1501 } 1502 1503 const JSPropertySpec DebuggerObject::properties_[] = { 1504 JS_DEBUG_PSG("callable", callableGetter), 1505 JS_DEBUG_PSG("isBoundFunction", isBoundFunctionGetter), 1506 JS_DEBUG_PSG("isArrowFunction", isArrowFunctionGetter), 1507 JS_DEBUG_PSG("isGeneratorFunction", isGeneratorFunctionGetter), 1508 JS_DEBUG_PSG("isAsyncFunction", isAsyncFunctionGetter), 1509 JS_DEBUG_PSG("isClassConstructor", isClassConstructorGetter), 1510 JS_DEBUG_PSG("proto", protoGetter), 1511 JS_DEBUG_PSG("class", classGetter), 1512 JS_DEBUG_PSG("name", nameGetter), 1513 JS_DEBUG_PSG("displayName", displayNameGetter), 1514 JS_DEBUG_PSG("parameterNames", parameterNamesGetter), 1515 JS_DEBUG_PSG("script", scriptGetter), 1516 JS_DEBUG_PSG("environment", environmentGetter), 1517 JS_DEBUG_PSG("boundTargetFunction", boundTargetFunctionGetter), 1518 JS_DEBUG_PSG("boundThis", boundThisGetter), 1519 JS_DEBUG_PSG("boundArguments", boundArgumentsGetter), 1520 JS_DEBUG_PSG("allocationSite", allocationSiteGetter), 1521 JS_DEBUG_PSG("isError", isErrorGetter), 1522 JS_DEBUG_PSG("isMutedError", isMutedErrorGetter), 1523 JS_DEBUG_PSG("errorMessageName", errorMessageNameGetter), 1524 JS_DEBUG_PSG("errorNotes", errorNotesGetter), 1525 JS_DEBUG_PSG("errorLineNumber", errorLineNumberGetter), 1526 JS_DEBUG_PSG("errorColumnNumber", errorColumnNumberGetter), 1527 JS_DEBUG_PSG("isProxy", isProxyGetter), 1528 JS_DEBUG_PSG("proxyTarget", proxyTargetGetter), 1529 JS_DEBUG_PSG("proxyHandler", proxyHandlerGetter), 1530 JS_PS_END, 1531 }; 1532 1533 const JSPropertySpec DebuggerObject::promiseProperties_[] = { 1534 JS_DEBUG_PSG("isPromise", isPromiseGetter), 1535 JS_DEBUG_PSG("promiseState", promiseStateGetter), 1536 JS_DEBUG_PSG("promiseValue", promiseValueGetter), 1537 JS_DEBUG_PSG("promiseReason", promiseReasonGetter), 1538 JS_DEBUG_PSG("promiseLifetime", promiseLifetimeGetter), 1539 JS_DEBUG_PSG("promiseTimeToResolution", promiseTimeToResolutionGetter), 1540 JS_DEBUG_PSG("promiseAllocationSite", promiseAllocationSiteGetter), 1541 JS_DEBUG_PSG("promiseResolutionSite", promiseResolutionSiteGetter), 1542 JS_DEBUG_PSG("promiseID", promiseIDGetter), 1543 JS_DEBUG_PSG("promiseDependentPromises", promiseDependentPromisesGetter), 1544 JS_PS_END, 1545 }; 1546 1547 const JSFunctionSpec DebuggerObject::methods_[] = { 1548 JS_DEBUG_FN("isExtensible", isExtensibleMethod, 0), 1549 JS_DEBUG_FN("isSealed", isSealedMethod, 0), 1550 JS_DEBUG_FN("isFrozen", isFrozenMethod, 0), 1551 JS_DEBUG_FN("getProperty", getPropertyMethod, 0), 1552 JS_DEBUG_FN("setProperty", setPropertyMethod, 0), 1553 JS_DEBUG_FN("getOwnPropertyNames", getOwnPropertyNamesMethod, 0), 1554 JS_DEBUG_FN("getOwnPropertyNamesLength", getOwnPropertyNamesLengthMethod, 1555 0), 1556 JS_DEBUG_FN("getOwnPropertySymbols", getOwnPropertySymbolsMethod, 0), 1557 JS_DEBUG_FN("getOwnPrivateProperties", getOwnPrivatePropertiesMethod, 0), 1558 JS_DEBUG_FN("getOwnPropertyDescriptor", getOwnPropertyDescriptorMethod, 1), 1559 JS_DEBUG_FN("preventExtensions", preventExtensionsMethod, 0), 1560 JS_DEBUG_FN("seal", sealMethod, 0), 1561 JS_DEBUG_FN("freeze", freezeMethod, 0), 1562 JS_DEBUG_FN("defineProperty", definePropertyMethod, 2), 1563 JS_DEBUG_FN("defineProperties", definePropertiesMethod, 1), 1564 JS_DEBUG_FN("deleteProperty", deletePropertyMethod, 1), 1565 JS_DEBUG_FN("call", callMethod, 0), 1566 JS_DEBUG_FN("apply", applyMethod, 0), 1567 JS_DEBUG_FN("asEnvironment", asEnvironmentMethod, 0), 1568 JS_DEBUG_FN("forceLexicalInitializationByName", 1569 forceLexicalInitializationByNameMethod, 1), 1570 JS_DEBUG_FN("executeInGlobal", executeInGlobalMethod, 1), 1571 JS_DEBUG_FN("executeInGlobalWithBindings", 1572 executeInGlobalWithBindingsMethod, 2), 1573 JS_DEBUG_FN("createSource", createSource, 1), 1574 JS_DEBUG_FN("makeDebuggeeValue", makeDebuggeeValueMethod, 1), 1575 JS_DEBUG_FN("isSameNative", isSameNativeMethod, 1), 1576 JS_DEBUG_FN("isSameNativeWithJitInfo", isSameNativeWithJitInfoMethod, 1), 1577 JS_DEBUG_FN("isNativeGetterWithJitInfo", isNativeGetterWithJitInfo, 1), 1578 JS_DEBUG_FN("unsafeDereference", unsafeDereferenceMethod, 0), 1579 JS_DEBUG_FN("unwrap", unwrapMethod, 0), 1580 JS_DEBUG_FN("getPromiseReactions", getPromiseReactionsMethod, 0), 1581 JS_FS_END, 1582 }; 1583 1584 /* static */ 1585 NativeObject* DebuggerObject::initClass(JSContext* cx, 1586 Handle<GlobalObject*> global, 1587 HandleObject debugCtor) { 1588 Rooted<NativeObject*> objectProto( 1589 cx, InitClass(cx, debugCtor, nullptr, nullptr, "Object", construct, 0, 1590 properties_, methods_, nullptr, nullptr)); 1591 1592 if (!objectProto) { 1593 return nullptr; 1594 } 1595 1596 if (!DefinePropertiesAndFunctions(cx, objectProto, promiseProperties_, 1597 nullptr)) { 1598 return nullptr; 1599 } 1600 1601 return objectProto; 1602 } 1603 1604 /* static */ 1605 DebuggerObject* DebuggerObject::create(JSContext* cx, HandleObject proto, 1606 HandleObject referent, 1607 Handle<NativeObject*> debugger) { 1608 DebuggerObject* obj = 1609 IsInsideNursery(referent) 1610 ? NewObjectWithGivenProto<DebuggerObject>(cx, proto) 1611 : NewTenuredObjectWithGivenProto<DebuggerObject>(cx, proto); 1612 if (!obj) { 1613 return nullptr; 1614 } 1615 1616 obj->setReservedSlotGCThingAsPrivate(OBJECT_SLOT, referent); 1617 obj->setReservedSlot(OWNER_SLOT, ObjectValue(*debugger)); 1618 1619 return obj; 1620 } 1621 1622 bool DebuggerObject::isCallable() const { return referent()->isCallable(); } 1623 1624 bool DebuggerObject::isFunction() const { return referent()->is<JSFunction>(); } 1625 1626 bool DebuggerObject::isDebuggeeFunction() const { 1627 return referent()->is<JSFunction>() && 1628 owner()->observesGlobal(&referent()->as<JSFunction>().global()); 1629 } 1630 1631 bool DebuggerObject::isBoundFunction() const { 1632 return referent()->is<BoundFunctionObject>(); 1633 } 1634 1635 bool DebuggerObject::isDebuggeeBoundFunction() const { 1636 return referent()->is<BoundFunctionObject>() && 1637 owner()->observesGlobal( 1638 &referent()->as<BoundFunctionObject>().global()); 1639 } 1640 1641 bool DebuggerObject::isArrowFunction() const { 1642 MOZ_ASSERT(isDebuggeeFunction()); 1643 1644 return referent()->as<JSFunction>().isArrow(); 1645 } 1646 1647 bool DebuggerObject::isAsyncFunction() const { 1648 MOZ_ASSERT(isDebuggeeFunction()); 1649 1650 return referent()->as<JSFunction>().isAsync(); 1651 } 1652 1653 bool DebuggerObject::isGeneratorFunction() const { 1654 MOZ_ASSERT(isDebuggeeFunction()); 1655 1656 return referent()->as<JSFunction>().isGenerator(); 1657 } 1658 1659 bool DebuggerObject::isClassConstructor() const { 1660 MOZ_ASSERT(isDebuggeeFunction()); 1661 1662 return referent()->as<JSFunction>().isClassConstructor(); 1663 } 1664 1665 bool DebuggerObject::isGlobal() const { return referent()->is<GlobalObject>(); } 1666 1667 bool DebuggerObject::isScriptedProxy() const { 1668 return js::IsScriptedProxy(referent()); 1669 } 1670 1671 bool DebuggerObject::isPromise() const { 1672 JSObject* referent = this->referent(); 1673 1674 if (IsCrossCompartmentWrapper(referent)) { 1675 // We only care about promises, so CheckedUnwrapStatic is OK. 1676 referent = CheckedUnwrapStatic(referent); 1677 if (!referent) { 1678 return false; 1679 } 1680 } 1681 1682 return referent->is<PromiseObject>(); 1683 } 1684 1685 bool DebuggerObject::isError() const { 1686 JSObject* referent = this->referent(); 1687 1688 if (IsCrossCompartmentWrapper(referent)) { 1689 // We only check for error classes, so CheckedUnwrapStatic is OK. 1690 referent = CheckedUnwrapStatic(referent); 1691 if (!referent) { 1692 return false; 1693 } 1694 } 1695 1696 return referent->is<ErrorObject>(); 1697 } 1698 1699 bool DebuggerObject::isMutedError(JSContext* cx) const { 1700 JS::Rooted<JSObject*> referent(cx, this->referent()); 1701 1702 if (IsCrossCompartmentWrapper(referent)) { 1703 // We only check for error classes, so CheckedUnwrapStatic is OK. 1704 referent = CheckedUnwrapStatic(referent); 1705 if (!referent) { 1706 return false; 1707 } 1708 } 1709 1710 if (!referent->is<ErrorObject>()) { 1711 return false; 1712 } 1713 1714 JSErrorReport* report = referent->as<ErrorObject>().getErrorReport(); 1715 if (!report) { 1716 // If the error report was missing, isMuted field can never be true, 1717 // and just returning false is OK. 1718 return false; 1719 } 1720 1721 return report->isMuted; 1722 } 1723 1724 /* static */ 1725 bool DebuggerObject::getClassName(JSContext* cx, Handle<DebuggerObject*> object, 1726 MutableHandleString result) { 1727 RootedObject referent(cx, object->referent()); 1728 1729 const char* className; 1730 { 1731 Maybe<AutoRealm> ar; 1732 EnterDebuggeeObjectRealm(cx, ar, referent); 1733 className = GetObjectClassName(cx, referent); 1734 } 1735 1736 JSAtom* str = Atomize(cx, className, strlen(className)); 1737 if (!str) { 1738 return false; 1739 } 1740 1741 result.set(str); 1742 return true; 1743 } 1744 1745 bool DebuggerObject::name(JSContext* cx, 1746 JS::MutableHandle<JSAtom*> result) const { 1747 if (isFunction()) { 1748 JSFunction* fun = &referent()->as<JSFunction>(); 1749 if (!fun->isAccessorWithLazyName()) { 1750 result.set(fun->fullExplicitName()); 1751 if (result) { 1752 cx->markAtom(result); 1753 } 1754 return true; 1755 } 1756 1757 { 1758 Maybe<AutoRealm> ar; 1759 EnterDebuggeeObjectRealm(cx, ar, fun); 1760 1761 result.set(fun->getAccessorNameForLazy(cx)); 1762 if (!result) { 1763 return false; 1764 } 1765 } 1766 cx->markAtom(result); 1767 return true; 1768 } 1769 1770 MOZ_ASSERT(isBoundFunction()); 1771 1772 // Bound functions have a configurable `name` data property and currently 1773 // don't store the original name. Try a pure lookup to get this name and if 1774 // this fails use "bound". 1775 Rooted<BoundFunctionObject*> bound(cx, 1776 &referent()->as<BoundFunctionObject>()); 1777 { 1778 Maybe<AutoRealm> ar; 1779 EnterDebuggeeObjectRealm(cx, ar, bound); 1780 1781 Value v; 1782 bool found; 1783 if (GetOwnPropertyPure(cx, bound, NameToId(cx->names().name), &v, &found) && 1784 found && v.isString()) { 1785 result.set(AtomizeString(cx, v.toString())); 1786 if (!result) { 1787 return false; 1788 } 1789 } else { 1790 result.set(cx->names().bound); 1791 } 1792 } 1793 1794 cx->markAtom(result); 1795 return true; 1796 } 1797 1798 bool DebuggerObject::displayName(JSContext* cx, 1799 JS::MutableHandle<JSAtom*> result) const { 1800 if (isFunction()) { 1801 { 1802 JS::Rooted<JSFunction*> fun(cx, &referent()->as<JSFunction>()); 1803 1804 Maybe<AutoRealm> ar; 1805 EnterDebuggeeObjectRealm(cx, ar, fun); 1806 1807 if (!fun->getDisplayAtom(cx, result)) { 1808 return false; 1809 } 1810 } 1811 if (result) { 1812 cx->markAtom(result); 1813 } 1814 return true; 1815 } 1816 1817 MOZ_ASSERT(isBoundFunction()); 1818 return name(cx, result); 1819 } 1820 1821 JS::PromiseState DebuggerObject::promiseState() const { 1822 return promise()->state(); 1823 } 1824 1825 double DebuggerObject::promiseLifetime() const { return promise()->lifetime(); } 1826 1827 double DebuggerObject::promiseTimeToResolution() const { 1828 MOZ_ASSERT(promiseState() != JS::PromiseState::Pending); 1829 1830 return promise()->timeToResolution(); 1831 } 1832 1833 /* static */ 1834 bool DebuggerObject::getBoundTargetFunction( 1835 JSContext* cx, Handle<DebuggerObject*> object, 1836 MutableHandle<DebuggerObject*> result) { 1837 MOZ_ASSERT(object->isBoundFunction()); 1838 1839 Rooted<BoundFunctionObject*> referent( 1840 cx, &object->referent()->as<BoundFunctionObject>()); 1841 Debugger* dbg = object->owner(); 1842 1843 RootedObject target(cx, referent->getTarget()); 1844 return dbg->wrapDebuggeeObject(cx, target, result); 1845 } 1846 1847 /* static */ 1848 bool DebuggerObject::getBoundThis(JSContext* cx, Handle<DebuggerObject*> object, 1849 MutableHandleValue result) { 1850 MOZ_ASSERT(object->isBoundFunction()); 1851 1852 Rooted<BoundFunctionObject*> referent( 1853 cx, &object->referent()->as<BoundFunctionObject>()); 1854 Debugger* dbg = object->owner(); 1855 1856 result.set(referent->getBoundThis()); 1857 return dbg->wrapDebuggeeValue(cx, result); 1858 } 1859 1860 /* static */ 1861 bool DebuggerObject::getBoundArguments(JSContext* cx, 1862 Handle<DebuggerObject*> object, 1863 MutableHandle<ValueVector> result) { 1864 MOZ_ASSERT(object->isBoundFunction()); 1865 1866 Rooted<BoundFunctionObject*> referent( 1867 cx, &object->referent()->as<BoundFunctionObject>()); 1868 Debugger* dbg = object->owner(); 1869 1870 size_t length = referent->numBoundArgs(); 1871 if (!result.resize(length)) { 1872 return false; 1873 } 1874 for (size_t i = 0; i < length; i++) { 1875 result[i].set(referent->getBoundArg(i)); 1876 if (!dbg->wrapDebuggeeValue(cx, result[i])) { 1877 return false; 1878 } 1879 } 1880 return true; 1881 } 1882 1883 /* static */ 1884 SavedFrame* Debugger::getObjectAllocationSite(JSObject& obj) { 1885 JSObject* metadata = GetAllocationMetadata(&obj); 1886 if (!metadata) { 1887 return nullptr; 1888 } 1889 1890 MOZ_ASSERT(!metadata->is<WrapperObject>()); 1891 return metadata->is<SavedFrame>() ? &metadata->as<SavedFrame>() : nullptr; 1892 } 1893 1894 /* static */ 1895 bool DebuggerObject::getAllocationSite(JSContext* cx, 1896 Handle<DebuggerObject*> object, 1897 MutableHandleObject result) { 1898 RootedObject referent(cx, object->referent()); 1899 1900 RootedObject allocSite(cx, Debugger::getObjectAllocationSite(*referent)); 1901 if (!cx->compartment()->wrap(cx, &allocSite)) { 1902 return false; 1903 } 1904 1905 result.set(allocSite); 1906 return true; 1907 } 1908 1909 /* static */ 1910 bool DebuggerObject::getErrorReport(JSContext* cx, HandleObject maybeError, 1911 JSErrorReport*& report) { 1912 JSObject* obj = maybeError; 1913 if (IsCrossCompartmentWrapper(obj)) { 1914 /* We only care about Error objects, so CheckedUnwrapStatic is OK. */ 1915 obj = CheckedUnwrapStatic(obj); 1916 } 1917 1918 if (!obj) { 1919 ReportAccessDenied(cx); 1920 return false; 1921 } 1922 1923 if (!obj->is<ErrorObject>()) { 1924 report = nullptr; 1925 return true; 1926 } 1927 1928 report = obj->as<ErrorObject>().getErrorReport(); 1929 return true; 1930 } 1931 1932 /* static */ 1933 bool DebuggerObject::getErrorMessageName(JSContext* cx, 1934 Handle<DebuggerObject*> object, 1935 MutableHandleString result) { 1936 RootedObject referent(cx, object->referent()); 1937 JSErrorReport* report; 1938 if (!getErrorReport(cx, referent, report)) { 1939 return false; 1940 } 1941 1942 if (!report || !report->errorMessageName) { 1943 result.set(nullptr); 1944 return true; 1945 } 1946 1947 RootedString str(cx, JS_NewStringCopyZ(cx, report->errorMessageName)); 1948 if (!str) { 1949 return false; 1950 } 1951 result.set(str); 1952 return true; 1953 } 1954 1955 /* static */ 1956 bool DebuggerObject::getErrorNotes(JSContext* cx, 1957 Handle<DebuggerObject*> object, 1958 MutableHandleValue result) { 1959 RootedObject referent(cx, object->referent()); 1960 JSErrorReport* report; 1961 if (!getErrorReport(cx, referent, report)) { 1962 return false; 1963 } 1964 1965 if (!report) { 1966 result.setUndefined(); 1967 return true; 1968 } 1969 1970 RootedObject errorNotesArray(cx, CreateErrorNotesArray(cx, report)); 1971 if (!errorNotesArray) { 1972 return false; 1973 } 1974 1975 if (!cx->compartment()->wrap(cx, &errorNotesArray)) { 1976 return false; 1977 } 1978 result.setObject(*errorNotesArray); 1979 return true; 1980 } 1981 1982 /* static */ 1983 bool DebuggerObject::getErrorLineNumber(JSContext* cx, 1984 Handle<DebuggerObject*> object, 1985 MutableHandleValue result) { 1986 RootedObject referent(cx, object->referent()); 1987 JSErrorReport* report; 1988 if (!getErrorReport(cx, referent, report)) { 1989 return false; 1990 } 1991 1992 if (!report) { 1993 result.setUndefined(); 1994 return true; 1995 } 1996 1997 result.setNumber(report->lineno); 1998 return true; 1999 } 2000 2001 /* static */ 2002 bool DebuggerObject::getErrorColumnNumber(JSContext* cx, 2003 Handle<DebuggerObject*> object, 2004 MutableHandleValue result) { 2005 RootedObject referent(cx, object->referent()); 2006 JSErrorReport* report; 2007 if (!getErrorReport(cx, referent, report)) { 2008 return false; 2009 } 2010 2011 if (!report) { 2012 result.setUndefined(); 2013 return true; 2014 } 2015 2016 result.setNumber(report->column.oneOriginValue()); 2017 return true; 2018 } 2019 2020 /* static */ 2021 bool DebuggerObject::getPromiseValue(JSContext* cx, 2022 Handle<DebuggerObject*> object, 2023 MutableHandleValue result) { 2024 MOZ_ASSERT(object->promiseState() == JS::PromiseState::Fulfilled); 2025 2026 result.set(object->promise()->value()); 2027 return object->owner()->wrapDebuggeeValue(cx, result); 2028 } 2029 2030 /* static */ 2031 bool DebuggerObject::getPromiseReason(JSContext* cx, 2032 Handle<DebuggerObject*> object, 2033 MutableHandleValue result) { 2034 MOZ_ASSERT(object->promiseState() == JS::PromiseState::Rejected); 2035 2036 result.set(object->promise()->reason()); 2037 return object->owner()->wrapDebuggeeValue(cx, result); 2038 } 2039 2040 /* static */ 2041 bool DebuggerObject::isExtensible(JSContext* cx, Handle<DebuggerObject*> object, 2042 bool& result) { 2043 RootedObject referent(cx, object->referent()); 2044 2045 Maybe<AutoRealm> ar; 2046 EnterDebuggeeObjectRealm(cx, ar, referent); 2047 2048 ErrorCopier ec(ar); 2049 return IsExtensible(cx, referent, &result); 2050 } 2051 2052 /* static */ 2053 bool DebuggerObject::isSealed(JSContext* cx, Handle<DebuggerObject*> object, 2054 bool& result) { 2055 RootedObject referent(cx, object->referent()); 2056 2057 Maybe<AutoRealm> ar; 2058 EnterDebuggeeObjectRealm(cx, ar, referent); 2059 2060 ErrorCopier ec(ar); 2061 return TestIntegrityLevel(cx, referent, IntegrityLevel::Sealed, &result); 2062 } 2063 2064 /* static */ 2065 bool DebuggerObject::isFrozen(JSContext* cx, Handle<DebuggerObject*> object, 2066 bool& result) { 2067 RootedObject referent(cx, object->referent()); 2068 2069 Maybe<AutoRealm> ar; 2070 EnterDebuggeeObjectRealm(cx, ar, referent); 2071 2072 ErrorCopier ec(ar); 2073 return TestIntegrityLevel(cx, referent, IntegrityLevel::Frozen, &result); 2074 } 2075 2076 /* static */ 2077 bool DebuggerObject::getPrototypeOf(JSContext* cx, 2078 Handle<DebuggerObject*> object, 2079 MutableHandle<DebuggerObject*> result) { 2080 RootedObject referent(cx, object->referent()); 2081 Debugger* dbg = object->owner(); 2082 2083 RootedObject proto(cx); 2084 { 2085 Maybe<AutoRealm> ar; 2086 EnterDebuggeeObjectRealm(cx, ar, referent); 2087 if (!GetPrototype(cx, referent, &proto)) { 2088 return false; 2089 } 2090 } 2091 2092 return dbg->wrapNullableDebuggeeObject(cx, proto, result); 2093 } 2094 2095 /* static */ 2096 bool DebuggerObject::getOwnPropertyNames(JSContext* cx, 2097 Handle<DebuggerObject*> object, 2098 MutableHandleIdVector result) { 2099 MOZ_ASSERT(result.empty()); 2100 2101 RootedObject referent(cx, object->referent()); 2102 { 2103 Maybe<AutoRealm> ar; 2104 EnterDebuggeeObjectRealm(cx, ar, referent); 2105 2106 ErrorCopier ec(ar); 2107 if (!GetPropertyKeys(cx, referent, JSITER_OWNONLY | JSITER_HIDDEN, 2108 result)) { 2109 return false; 2110 } 2111 } 2112 2113 for (size_t i = 0; i < result.length(); i++) { 2114 cx->markId(result[i]); 2115 } 2116 2117 return true; 2118 } 2119 2120 /* static */ 2121 bool DebuggerObject::getOwnPropertyNamesLength(JSContext* cx, 2122 Handle<DebuggerObject*> object, 2123 size_t* result) { 2124 RootedObject referent(cx, object->referent()); 2125 2126 RootedIdVector ids(cx); 2127 { 2128 Maybe<AutoRealm> ar; 2129 EnterDebuggeeObjectRealm(cx, ar, referent); 2130 2131 ErrorCopier ec(ar); 2132 if (!GetPropertyKeys(cx, referent, JSITER_OWNONLY | JSITER_HIDDEN, &ids)) { 2133 return false; 2134 } 2135 } 2136 2137 *result = ids.length(); 2138 return true; 2139 } 2140 2141 static bool GetSymbolPropertyKeys(JSContext* cx, Handle<DebuggerObject*> object, 2142 JS::MutableHandleIdVector props, 2143 bool includePrivate) { 2144 RootedObject referent(cx, object->referent()); 2145 2146 { 2147 Maybe<AutoRealm> ar; 2148 EnterDebuggeeObjectRealm(cx, ar, referent); 2149 2150 ErrorCopier ec(ar); 2151 2152 unsigned flags = 2153 JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY; 2154 if (includePrivate) { 2155 flags = flags | JSITER_PRIVATE; 2156 } 2157 if (!GetPropertyKeys(cx, referent, flags, props)) { 2158 return false; 2159 } 2160 } 2161 2162 return true; 2163 } 2164 2165 /* static */ 2166 bool DebuggerObject::getOwnPropertySymbols(JSContext* cx, 2167 Handle<DebuggerObject*> object, 2168 MutableHandleIdVector result) { 2169 MOZ_ASSERT(result.empty()); 2170 2171 if (!GetSymbolPropertyKeys(cx, object, result, false)) { 2172 return false; 2173 } 2174 2175 for (size_t i = 0; i < result.length(); i++) { 2176 cx->markAtom(result[i].toSymbol()); 2177 } 2178 2179 return true; 2180 } 2181 2182 /* static */ 2183 bool DebuggerObject::getOwnPrivateProperties(JSContext* cx, 2184 Handle<DebuggerObject*> object, 2185 MutableHandleIdVector result) { 2186 MOZ_ASSERT(result.empty()); 2187 2188 if (!GetSymbolPropertyKeys(cx, object, result, true)) { 2189 return false; 2190 } 2191 2192 result.eraseIf([](PropertyKey key) { 2193 if (!key.isPrivateName()) { 2194 return true; 2195 } 2196 // Private *methods* create a Private Brand, a special private name 2197 // stamped onto the symbol, to indicate it is possible to execute private 2198 // methods from the class on this object. We don't want to return such 2199 // items here, so we check if we're dealing with a private property, e.g. 2200 // the Symbol description starts with a "#" character. 2201 JSAtom* privateDescription = key.toSymbol()->description(); 2202 if (privateDescription->length() == 0) { 2203 return true; 2204 } 2205 char16_t firstChar = privateDescription->latin1OrTwoByteChar(0); 2206 return firstChar != '#'; 2207 }); 2208 2209 for (size_t i = 0; i < result.length(); i++) { 2210 cx->markAtom(result[i].toSymbol()); 2211 } 2212 2213 return true; 2214 } 2215 2216 /* static */ 2217 bool DebuggerObject::getOwnPropertyDescriptor( 2218 JSContext* cx, Handle<DebuggerObject*> object, HandleId id, 2219 MutableHandle<Maybe<PropertyDescriptor>> desc_) { 2220 RootedObject referent(cx, object->referent()); 2221 Debugger* dbg = object->owner(); 2222 2223 // Bug: This can cause the debuggee to run! 2224 { 2225 Maybe<AutoRealm> ar; 2226 EnterDebuggeeObjectRealm(cx, ar, referent); 2227 2228 cx->markId(id); 2229 2230 ErrorCopier ec(ar); 2231 if (!GetOwnPropertyDescriptor(cx, referent, id, desc_)) { 2232 return false; 2233 } 2234 } 2235 2236 if (desc_.isSome()) { 2237 Rooted<PropertyDescriptor> desc(cx, *desc_); 2238 2239 if (desc.hasValue()) { 2240 // Rewrap the debuggee values in desc for the debugger. 2241 if (!dbg->wrapDebuggeeValue(cx, desc.value())) { 2242 return false; 2243 } 2244 } 2245 if (desc.hasGetter()) { 2246 RootedValue get(cx, ObjectOrNullValue(desc.getter())); 2247 if (!dbg->wrapDebuggeeValue(cx, &get)) { 2248 return false; 2249 } 2250 desc.setGetter(get.toObjectOrNull()); 2251 } 2252 if (desc.hasSetter()) { 2253 RootedValue set(cx, ObjectOrNullValue(desc.setter())); 2254 if (!dbg->wrapDebuggeeValue(cx, &set)) { 2255 return false; 2256 } 2257 desc.setSetter(set.toObjectOrNull()); 2258 } 2259 2260 desc_.set(mozilla::Some(desc.get())); 2261 } 2262 2263 return true; 2264 } 2265 2266 /* static */ 2267 bool DebuggerObject::preventExtensions(JSContext* cx, 2268 Handle<DebuggerObject*> object) { 2269 RootedObject referent(cx, object->referent()); 2270 2271 Maybe<AutoRealm> ar; 2272 EnterDebuggeeObjectRealm(cx, ar, referent); 2273 2274 ErrorCopier ec(ar); 2275 return PreventExtensions(cx, referent); 2276 } 2277 2278 /* static */ 2279 bool DebuggerObject::seal(JSContext* cx, Handle<DebuggerObject*> object) { 2280 RootedObject referent(cx, object->referent()); 2281 2282 Maybe<AutoRealm> ar; 2283 EnterDebuggeeObjectRealm(cx, ar, referent); 2284 2285 ErrorCopier ec(ar); 2286 return SetIntegrityLevel(cx, referent, IntegrityLevel::Sealed); 2287 } 2288 2289 /* static */ 2290 bool DebuggerObject::freeze(JSContext* cx, Handle<DebuggerObject*> object) { 2291 RootedObject referent(cx, object->referent()); 2292 2293 Maybe<AutoRealm> ar; 2294 EnterDebuggeeObjectRealm(cx, ar, referent); 2295 2296 ErrorCopier ec(ar); 2297 return SetIntegrityLevel(cx, referent, IntegrityLevel::Frozen); 2298 } 2299 2300 /* static */ 2301 bool DebuggerObject::defineProperty(JSContext* cx, 2302 Handle<DebuggerObject*> object, HandleId id, 2303 Handle<PropertyDescriptor> desc_) { 2304 RootedObject referent(cx, object->referent()); 2305 Debugger* dbg = object->owner(); 2306 2307 Rooted<PropertyDescriptor> desc(cx, desc_); 2308 if (!dbg->unwrapPropertyDescriptor(cx, referent, &desc)) { 2309 return false; 2310 } 2311 JS_TRY_OR_RETURN_FALSE(cx, CheckPropertyDescriptorAccessors(cx, desc)); 2312 2313 Maybe<AutoRealm> ar; 2314 EnterDebuggeeObjectRealm(cx, ar, referent); 2315 2316 if (!cx->compartment()->wrap(cx, &desc)) { 2317 return false; 2318 } 2319 cx->markId(id); 2320 2321 ErrorCopier ec(ar); 2322 return DefineProperty(cx, referent, id, desc); 2323 } 2324 2325 /* static */ 2326 bool DebuggerObject::defineProperties(JSContext* cx, 2327 Handle<DebuggerObject*> object, 2328 Handle<IdVector> ids, 2329 Handle<PropertyDescriptorVector> descs_) { 2330 RootedObject referent(cx, object->referent()); 2331 Debugger* dbg = object->owner(); 2332 2333 Rooted<PropertyDescriptorVector> descs(cx, PropertyDescriptorVector(cx)); 2334 if (!descs.append(descs_.begin(), descs_.end())) { 2335 return false; 2336 } 2337 for (size_t i = 0; i < descs.length(); i++) { 2338 if (!dbg->unwrapPropertyDescriptor(cx, referent, descs[i])) { 2339 return false; 2340 } 2341 JS_TRY_OR_RETURN_FALSE(cx, CheckPropertyDescriptorAccessors(cx, descs[i])); 2342 } 2343 2344 Maybe<AutoRealm> ar; 2345 EnterDebuggeeObjectRealm(cx, ar, referent); 2346 2347 for (size_t i = 0; i < descs.length(); i++) { 2348 if (!cx->compartment()->wrap(cx, descs[i])) { 2349 return false; 2350 } 2351 cx->markId(ids[i]); 2352 } 2353 2354 ErrorCopier ec(ar); 2355 for (size_t i = 0; i < descs.length(); i++) { 2356 if (!DefineProperty(cx, referent, ids[i], descs[i])) { 2357 return false; 2358 } 2359 } 2360 2361 return true; 2362 } 2363 2364 /* static */ 2365 bool DebuggerObject::deleteProperty(JSContext* cx, 2366 Handle<DebuggerObject*> object, HandleId id, 2367 ObjectOpResult& result) { 2368 RootedObject referent(cx, object->referent()); 2369 2370 Maybe<AutoRealm> ar; 2371 EnterDebuggeeObjectRealm(cx, ar, referent); 2372 2373 cx->markId(id); 2374 2375 ErrorCopier ec(ar); 2376 return DeleteProperty(cx, referent, id, result); 2377 } 2378 2379 /* static */ 2380 Result<Completion> DebuggerObject::getProperty(JSContext* cx, 2381 Handle<DebuggerObject*> object, 2382 HandleId id, 2383 HandleValue receiver_) { 2384 RootedObject referent(cx, object->referent()); 2385 Debugger* dbg = object->owner(); 2386 2387 // Unwrap Debugger.Objects. This happens in the debugger's compartment since 2388 // that is where any exceptions must be reported. 2389 RootedValue receiver(cx, receiver_); 2390 if (!dbg->unwrapDebuggeeValue(cx, &receiver)) { 2391 return cx->alreadyReportedError(); 2392 } 2393 2394 // Enter the debuggee compartment and rewrap all input value for that 2395 // compartment. (Rewrapping always takes place in the destination 2396 // compartment.) 2397 Maybe<AutoRealm> ar; 2398 EnterDebuggeeObjectRealm(cx, ar, referent); 2399 if (!cx->compartment()->wrap(cx, &referent) || 2400 !cx->compartment()->wrap(cx, &receiver)) { 2401 return cx->alreadyReportedError(); 2402 } 2403 cx->markId(id); 2404 2405 LeaveDebuggeeNoExecute nnx(cx); 2406 2407 RootedValue result(cx); 2408 bool ok = GetProperty(cx, referent, receiver, id, &result); 2409 return Completion::fromJSResult(cx, ok, result); 2410 } 2411 2412 /* static */ 2413 Result<Completion> DebuggerObject::setProperty(JSContext* cx, 2414 Handle<DebuggerObject*> object, 2415 HandleId id, HandleValue value_, 2416 HandleValue receiver_) { 2417 RootedObject referent(cx, object->referent()); 2418 Debugger* dbg = object->owner(); 2419 2420 // Unwrap Debugger.Objects. This happens in the debugger's compartment since 2421 // that is where any exceptions must be reported. 2422 RootedValue value(cx, value_); 2423 RootedValue receiver(cx, receiver_); 2424 if (!dbg->unwrapDebuggeeValue(cx, &value) || 2425 !dbg->unwrapDebuggeeValue(cx, &receiver)) { 2426 return cx->alreadyReportedError(); 2427 } 2428 2429 // Enter the debuggee compartment and rewrap all input value for that 2430 // compartment. (Rewrapping always takes place in the destination 2431 // compartment.) 2432 Maybe<AutoRealm> ar; 2433 EnterDebuggeeObjectRealm(cx, ar, referent); 2434 if (!cx->compartment()->wrap(cx, &referent) || 2435 !cx->compartment()->wrap(cx, &value) || 2436 !cx->compartment()->wrap(cx, &receiver)) { 2437 return cx->alreadyReportedError(); 2438 } 2439 cx->markId(id); 2440 2441 LeaveDebuggeeNoExecute nnx(cx); 2442 2443 ObjectOpResult opResult; 2444 bool ok = SetProperty(cx, referent, id, value, receiver, opResult); 2445 2446 return Completion::fromJSResult(cx, ok, BooleanValue(ok && opResult.ok())); 2447 } 2448 2449 /* static */ 2450 Maybe<Completion> DebuggerObject::call(JSContext* cx, 2451 Handle<DebuggerObject*> object, 2452 HandleValue thisv_, 2453 Handle<ValueVector> args) { 2454 RootedObject referent(cx, object->referent()); 2455 Debugger* dbg = object->owner(); 2456 2457 if (!referent->isCallable()) { 2458 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 2459 JSMSG_INCOMPATIBLE_PROTO, "Debugger.Object", 2460 "call", referent->getClass()->name); 2461 return Nothing(); 2462 } 2463 2464 RootedValue calleev(cx, ObjectValue(*referent)); 2465 2466 // Unwrap Debugger.Objects. This happens in the debugger's compartment since 2467 // that is where any exceptions must be reported. 2468 RootedValue thisv(cx, thisv_); 2469 if (!dbg->unwrapDebuggeeValue(cx, &thisv)) { 2470 return Nothing(); 2471 } 2472 Rooted<ValueVector> args2(cx, ValueVector(cx)); 2473 if (!args2.append(args.begin(), args.end())) { 2474 return Nothing(); 2475 } 2476 for (size_t i = 0; i < args2.length(); ++i) { 2477 if (!dbg->unwrapDebuggeeValue(cx, args2[i])) { 2478 return Nothing(); 2479 } 2480 } 2481 2482 // Enter the debuggee compartment and rewrap all input value for that 2483 // compartment. (Rewrapping always takes place in the destination 2484 // compartment.) 2485 Maybe<AutoRealm> ar; 2486 EnterDebuggeeObjectRealm(cx, ar, referent); 2487 if (!cx->compartment()->wrap(cx, &calleev) || 2488 !cx->compartment()->wrap(cx, &thisv)) { 2489 return Nothing(); 2490 } 2491 for (size_t i = 0; i < args2.length(); ++i) { 2492 if (!cx->compartment()->wrap(cx, args2[i])) { 2493 return Nothing(); 2494 } 2495 } 2496 2497 // Note whether we are in an evaluation that might invoke the OnNativeCall 2498 // hook, so that the JITs will be disabled. 2499 Maybe<AutoNoteExclusiveDebuggerOnEval> noteEvaluation; 2500 if (dbg->isExclusiveDebuggerOnEval()) { 2501 noteEvaluation.emplace(cx, dbg); 2502 } 2503 2504 // Call the function. 2505 LeaveDebuggeeNoExecute nnx(cx); 2506 2507 RootedValue result(cx); 2508 bool ok; 2509 { 2510 InvokeArgs invokeArgs(cx); 2511 2512 ok = invokeArgs.init(cx, args2.length()); 2513 if (ok) { 2514 for (size_t i = 0; i < args2.length(); ++i) { 2515 invokeArgs[i].set(args2[i]); 2516 } 2517 2518 ok = js::Call(cx, calleev, thisv, invokeArgs, &result); 2519 } 2520 } 2521 2522 Rooted<Completion> completion(cx, Completion::fromJSResult(cx, ok, result)); 2523 ar.reset(); 2524 return Some(std::move(completion.get())); 2525 } 2526 2527 /* static */ 2528 bool DebuggerObject::forceLexicalInitializationByName( 2529 JSContext* cx, Handle<DebuggerObject*> object, HandleId id, bool& result) { 2530 if (!id.isString()) { 2531 JS_ReportErrorNumberASCII( 2532 cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE, 2533 "Debugger.Object.prototype.forceLexicalInitializationByName", "string", 2534 InformalValueTypeName(IdToValue(id))); 2535 return false; 2536 } 2537 2538 MOZ_ASSERT(object->isGlobal()); 2539 2540 Rooted<GlobalObject*> referent(cx, &object->referent()->as<GlobalObject>()); 2541 2542 // Shape::search can end up allocating a new BaseShape in Shape::cachify so 2543 // we need to be in the right compartment here. 2544 Maybe<AutoRealm> ar; 2545 EnterDebuggeeObjectRealm(cx, ar, referent); 2546 2547 RootedObject globalLexical(cx, &referent->lexicalEnvironment()); 2548 RootedObject pobj(cx); 2549 PropertyResult prop; 2550 if (!LookupProperty(cx, globalLexical, id, &pobj, &prop)) { 2551 return false; 2552 } 2553 2554 result = false; 2555 if (prop.isFound()) { 2556 MOZ_ASSERT(prop.isNativeProperty()); 2557 PropertyInfo propInfo = prop.propertyInfo(); 2558 Value v = globalLexical->as<NativeObject>().getSlot(propInfo.slot()); 2559 if (propInfo.isDataProperty() && v.isMagic() && 2560 v.whyMagic() == JS_UNINITIALIZED_LEXICAL) { 2561 globalLexical->as<NativeObject>().setSlot(propInfo.slot(), 2562 UndefinedValue()); 2563 result = true; 2564 } 2565 } 2566 2567 return true; 2568 } 2569 2570 /* static */ 2571 Result<Completion> DebuggerObject::executeInGlobal( 2572 JSContext* cx, Handle<DebuggerObject*> object, 2573 mozilla::Range<const char16_t> chars, HandleObject bindings, 2574 const EvalOptions& options) { 2575 MOZ_ASSERT(object->isGlobal()); 2576 2577 Rooted<GlobalObject*> referent(cx, &object->referent()->as<GlobalObject>()); 2578 Debugger* dbg = object->owner(); 2579 2580 RootedObject globalLexical(cx, &referent->lexicalEnvironment()); 2581 return DebuggerGenericEval(cx, chars, bindings, options, dbg, globalLexical, 2582 nullptr); 2583 } 2584 2585 /* static */ 2586 bool DebuggerObject::makeDebuggeeValue(JSContext* cx, 2587 Handle<DebuggerObject*> object, 2588 HandleValue value_, 2589 MutableHandleValue result) { 2590 RootedObject referent(cx, object->referent()); 2591 Debugger* dbg = object->owner(); 2592 2593 RootedValue value(cx, value_); 2594 2595 // Non-objects are already debuggee values. 2596 if (value.isObject()) { 2597 // Enter this Debugger.Object's referent's compartment, and wrap the 2598 // argument as appropriate for references from there. 2599 { 2600 Maybe<AutoRealm> ar; 2601 EnterDebuggeeObjectRealm(cx, ar, referent); 2602 if (!cx->compartment()->wrap(cx, &value)) { 2603 return false; 2604 } 2605 } 2606 2607 // Back in the debugger's compartment, produce a new Debugger.Object 2608 // instance referring to the wrapped argument. 2609 if (!dbg->wrapDebuggeeValue(cx, &value)) { 2610 return false; 2611 } 2612 } 2613 2614 result.set(value); 2615 return true; 2616 } 2617 2618 static JSFunction* EnsureNativeFunction(const Value& value) { 2619 if (!value.isObject() || !value.toObject().is<JSFunction>()) { 2620 return nullptr; 2621 } 2622 2623 JSFunction* fun = &value.toObject().as<JSFunction>(); 2624 if (!fun->isNativeFun()) { 2625 return nullptr; 2626 } 2627 2628 return fun; 2629 } 2630 2631 static JSAtom* MaybeGetSelfHostedFunctionName(const Value& v) { 2632 if (!v.isObject() || !v.toObject().is<JSFunction>()) { 2633 return nullptr; 2634 } 2635 2636 JSFunction* fun = &v.toObject().as<JSFunction>(); 2637 if (!fun->isSelfHostedBuiltin()) { 2638 return nullptr; 2639 } 2640 2641 return GetClonedSelfHostedFunctionName(fun); 2642 } 2643 2644 static bool IsSameNative(JSFunction* a, JSFunction* b, 2645 DebuggerObject::CheckJitInfo checkJitInfo) { 2646 if (a->native() != b->native()) { 2647 return false; 2648 } 2649 2650 if (checkJitInfo == DebuggerObject::CheckJitInfo::No) { 2651 return true; 2652 } 2653 2654 // Both function should agree with the existence of JitInfo. 2655 2656 if (a->hasJitInfo() != b->hasJitInfo()) { 2657 return false; 2658 } 2659 2660 if (!a->hasJitInfo()) { 2661 return true; 2662 } 2663 2664 if (a->jitInfo() == b->jitInfo()) { 2665 return true; 2666 } 2667 2668 return false; 2669 } 2670 2671 /* static */ 2672 bool DebuggerObject::isSameNative(JSContext* cx, Handle<DebuggerObject*> object, 2673 HandleValue value, CheckJitInfo checkJitInfo, 2674 MutableHandleValue result) { 2675 RootedValue referentValue(cx, ObjectValue(*object->referent())); 2676 2677 RootedValue nonCCWValue( 2678 cx, value.isObject() ? ObjectValue(*UncheckedUnwrap(&value.toObject())) 2679 : value); 2680 2681 RootedFunction fun(cx, EnsureNativeFunction(nonCCWValue)); 2682 if (!fun) { 2683 Rooted<JSAtom*> selfHostedName(cx, 2684 MaybeGetSelfHostedFunctionName(nonCCWValue)); 2685 if (!selfHostedName) { 2686 JS_ReportErrorASCII(cx, "Need native function"); 2687 return false; 2688 } 2689 2690 result.setBoolean(selfHostedName == 2691 MaybeGetSelfHostedFunctionName(referentValue)); 2692 return true; 2693 } 2694 2695 RootedFunction referentFun(cx, EnsureNativeFunction(referentValue)); 2696 2697 result.setBoolean(referentFun && 2698 IsSameNative(referentFun, fun, checkJitInfo)); 2699 return true; 2700 } 2701 2702 static bool IsNativeGetterWithJitInfo(JSFunction* fun) { 2703 return fun->isNativeFun() && fun->hasJitInfo() && 2704 fun->jitInfo()->type() == JSJitInfo::Getter; 2705 } 2706 2707 /* static */ 2708 bool DebuggerObject::isNativeGetterWithJitInfo(JSContext* cx, 2709 Handle<DebuggerObject*> object, 2710 MutableHandleValue result) { 2711 RootedValue referentValue(cx, ObjectValue(*object->referent())); 2712 RootedFunction referentFun(cx, EnsureNativeFunction(referentValue)); 2713 result.setBoolean(referentFun && IsNativeGetterWithJitInfo(referentFun)); 2714 return true; 2715 } 2716 2717 /* static */ 2718 bool DebuggerObject::unsafeDereference(JSContext* cx, 2719 Handle<DebuggerObject*> object, 2720 MutableHandleObject result) { 2721 RootedObject referent(cx, object->referent()); 2722 2723 if (!cx->compartment()->wrap(cx, &referent)) { 2724 return false; 2725 } 2726 2727 // Wrapping should return the WindowProxy. 2728 MOZ_ASSERT(!IsWindow(referent)); 2729 2730 result.set(referent); 2731 return true; 2732 } 2733 2734 /* static */ 2735 bool DebuggerObject::unwrap(JSContext* cx, Handle<DebuggerObject*> object, 2736 MutableHandle<DebuggerObject*> result) { 2737 RootedObject referent(cx, object->referent()); 2738 Debugger* dbg = object->owner(); 2739 2740 RootedObject unwrapped(cx, UnwrapOneCheckedStatic(referent)); 2741 2742 // Don't allow unwrapping to create a D.O whose referent is in an 2743 // invisible-to-Debugger compartment. (If our referent is a *wrapper* to such, 2744 // and the wrapper is in a visible compartment, that's fine.) 2745 if (unwrapped && unwrapped->compartment()->invisibleToDebugger()) { 2746 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 2747 JSMSG_DEBUG_INVISIBLE_COMPARTMENT); 2748 return false; 2749 } 2750 2751 return dbg->wrapNullableDebuggeeObject(cx, unwrapped, result); 2752 } 2753 2754 /* static */ 2755 bool DebuggerObject::requireGlobal(JSContext* cx, 2756 Handle<DebuggerObject*> object) { 2757 if (!object->isGlobal()) { 2758 RootedObject referent(cx, object->referent()); 2759 2760 const char* isWrapper = ""; 2761 const char* isWindowProxy = ""; 2762 2763 // Help the poor programmer by pointing out wrappers around globals... 2764 if (referent->is<WrapperObject>()) { 2765 referent = js::UncheckedUnwrap(referent); 2766 isWrapper = "a wrapper around "; 2767 } 2768 2769 // ... and WindowProxies around Windows. 2770 if (IsWindowProxy(referent)) { 2771 referent = ToWindowIfWindowProxy(referent); 2772 isWindowProxy = "a WindowProxy referring to "; 2773 } 2774 2775 RootedValue dbgobj(cx, ObjectValue(*object)); 2776 if (referent->is<GlobalObject>()) { 2777 ReportValueError(cx, JSMSG_DEBUG_WRAPPER_IN_WAY, JSDVG_SEARCH_STACK, 2778 dbgobj, nullptr, isWrapper, isWindowProxy); 2779 } else { 2780 ReportValueError(cx, JSMSG_DEBUG_BAD_REFERENT, JSDVG_SEARCH_STACK, dbgobj, 2781 nullptr, "a global object"); 2782 } 2783 return false; 2784 } 2785 2786 return true; 2787 } 2788 2789 /* static */ 2790 bool DebuggerObject::requirePromise(JSContext* cx, 2791 Handle<DebuggerObject*> object) { 2792 RootedObject referent(cx, object->referent()); 2793 2794 if (IsCrossCompartmentWrapper(referent)) { 2795 /* We only care about promises, so CheckedUnwrapStatic is OK. */ 2796 referent = CheckedUnwrapStatic(referent); 2797 if (!referent) { 2798 ReportAccessDenied(cx); 2799 return false; 2800 } 2801 } 2802 2803 if (!referent->is<PromiseObject>()) { 2804 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 2805 JSMSG_NOT_EXPECTED_TYPE, "Debugger", "Promise", 2806 object->getClass()->name); 2807 return false; 2808 } 2809 2810 return true; 2811 } 2812 2813 /* static */ 2814 bool DebuggerObject::getScriptedProxyTarget( 2815 JSContext* cx, Handle<DebuggerObject*> object, 2816 MutableHandle<DebuggerObject*> result) { 2817 MOZ_ASSERT(object->isScriptedProxy()); 2818 RootedObject referent(cx, object->referent()); 2819 Debugger* dbg = object->owner(); 2820 RootedObject unwrapped(cx, js::GetProxyTargetObject(referent)); 2821 2822 return dbg->wrapNullableDebuggeeObject(cx, unwrapped, result); 2823 } 2824 2825 /* static */ 2826 bool DebuggerObject::getScriptedProxyHandler( 2827 JSContext* cx, Handle<DebuggerObject*> object, 2828 MutableHandle<DebuggerObject*> result) { 2829 MOZ_ASSERT(object->isScriptedProxy()); 2830 RootedObject referent(cx, object->referent()); 2831 Debugger* dbg = object->owner(); 2832 RootedObject unwrapped(cx, ScriptedProxyHandler::handlerObject(referent)); 2833 return dbg->wrapNullableDebuggeeObject(cx, unwrapped, result); 2834 }