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/. */
7 #include "debugger/Object-inl.h"
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
15 #include <string.h> // for size_t, strlen
16 #include <type_traits> // for remove_reference<>::type
17 #include <utility> // for move
19 #include "jsapi.h" // for CallArgs, RootedObject, Rooted
21 #include "builtin/Array.h" // for NewDenseCopiedArray
22 #include "builtin/Promise.h" // for PromiseReactionRecordBuilder
23 #include "debugger/Debugger.h" // for Completion, Debugger
24 #include "debugger/Frame.h" // for DebuggerFrame
25 #include "debugger/NoExecute.h" // for LeaveDebuggeeNoExecute
26 #include "debugger/Script.h" // for DebuggerScript
27 #include "debugger/Source.h" // for DebuggerSource
28 #include "gc/Tracer.h" // for TraceManuallyBarrieredCrossCompartmentEdge
29 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
30 #include "js/CompilationAndEvaluation.h" // for Compile
31 #include "js/Conversions.h" // for ToObject
32 #include "js/experimental/JitInfo.h" // for JSJitInfo
33 #include "js/friend/ErrorMessages.h" // for GetErrorMessage, JSMSG_*
34 #include "js/friend/WindowProxy.h" // for IsWindow, IsWindowProxy, ToWindowIfWindowProxy
35 #include "js/HeapAPI.h" // for IsInsideNursery
36 #include "js/Promise.h" // for PromiseState
37 #include "js/PropertyAndElement.h" // for JS_GetProperty
38 #include "js/Proxy.h" // for PropertyDescriptor
39 #include "js/SourceText.h" // for SourceText
40 #include "js/StableStringChars.h" // for AutoStableStringChars
41 #include "js/String.h" // for JS::StringHasLatin1Chars
42 #include "proxy/ScriptedProxyHandler.h" // for ScriptedProxyHandler
43 #include "vm/ArgumentsObject.h" // for ARGS_LENGTH_MAX
44 #include "vm/ArrayObject.h" // for ArrayObject
45 #include "vm/AsyncFunction.h" // for AsyncGeneratorObject
46 #include "vm/AsyncIteration.h" // for AsyncFunctionGeneratorObject
47 #include "vm/BoundFunctionObject.h" // for BoundFunctionObject
48 #include "vm/BytecodeUtil.h" // for JSDVG_SEARCH_STACK
49 #include "vm/Compartment.h" // for Compartment
50 #include "vm/EnvironmentObject.h" // for GetDebugEnvironmentForFunction
51 #include "vm/ErrorObject.h" // for JSObject::is, ErrorObject
52 #include "vm/GeneratorObject.h" // for AbstractGeneratorObject
53 #include "vm/GlobalObject.h" // for JSObject::is, GlobalObject
54 #include "vm/Interpreter.h" // for Call
55 #include "vm/JSAtomUtils.h" // for Atomize, AtomizeString
56 #include "vm/JSContext.h" // for JSContext, ReportValueError
57 #include "vm/JSFunction.h" // for JSFunction
58 #include "vm/JSObject.h" // for GenericObject, NewObjectKind
59 #include "vm/JSScript.h" // for JSScript
60 #include "vm/NativeObject.h" // for NativeObject, JSObject::is
61 #include "vm/ObjectOperations.h" // for DefineProperty
62 #include "vm/PlainObject.h" // for js::PlainObject
63 #include "vm/PromiseObject.h" // for js::PromiseObject
64 #include "vm/Realm.h" // for AutoRealm, ErrorCopier, Realm
65 #include "vm/Runtime.h" // for JSAtomState
66 #include "vm/SavedFrame.h" // for SavedFrame
67 #include "vm/Scope.h" // for PositionalFormalParameterIter
68 #include "vm/SelfHosting.h" // for GetClonedSelfHostedFunctionName
69 #include "vm/Shape.h" // for Shape
70 #include "vm/Stack.h" // for InvokeArgs
71 #include "vm/StringType.h" // for JSAtom, PropertyName
72 #include "vm/WrapperObject.h" // for JSObject::is, WrapperObject
74 #include "gc/StableCellHasher-inl.h"
75 #include "vm/Compartment-inl.h" // for Compartment::wrap
76 #include "vm/JSObject-inl.h" // for GetObjectClassName, InitClass, NewObjectWithGivenProtoAndKind, ToPropertyKey
77 #include "vm/NativeObject-inl.h" // for NativeObject::global
78 #include "vm/ObjectOperations-inl.h" // for DeleteProperty, GetProperty
79 #include "vm/Realm-inl.h" // for AutoRealm::AutoRealm
83 using JS::AutoStableStringChars
;
85 using mozilla::Nothing
;
88 const JSClassOps
DebuggerObject::classOps_
= {
89 nullptr, // addProperty
90 nullptr, // delProperty
92 nullptr, // newEnumerate
94 nullptr, // mayResolve
98 CallTraceMethod
<DebuggerObject
>, // trace
101 const JSClass
DebuggerObject::class_
= {
102 "Object", JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS
), &classOps_
};
104 void DebuggerObject::trace(JSTracer
* trc
) {
105 // There is a barrier on private pointers, so the Unbarriered marking
107 if (JSObject
* referent
= maybeReferent()) {
108 TraceManuallyBarrieredCrossCompartmentEdge(trc
, this, &referent
,
109 "Debugger.Object referent");
110 if (referent
!= maybeReferent()) {
111 setReservedSlotGCThingAsPrivateUnbarriered(OBJECT_SLOT
, referent
);
116 static DebuggerObject
* DebuggerObject_checkThis(JSContext
* cx
,
117 const CallArgs
& args
) {
118 JSObject
* thisobj
= RequireObject(cx
, args
.thisv());
122 if (!thisobj
->is
<DebuggerObject
>()) {
123 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
124 JSMSG_INCOMPATIBLE_PROTO
, "Debugger.Object",
125 "method", thisobj
->getClass()->name
);
129 return &thisobj
->as
<DebuggerObject
>();
133 bool DebuggerObject::construct(JSContext
* cx
, unsigned argc
, Value
* vp
) {
134 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr, JSMSG_NO_CONSTRUCTOR
,
139 struct MOZ_STACK_CLASS
DebuggerObject::CallData
{
141 const CallArgs
& args
;
143 Handle
<DebuggerObject
*> object
;
144 RootedObject referent
;
146 CallData(JSContext
* cx
, const CallArgs
& args
, Handle
<DebuggerObject
*> obj
)
147 : cx(cx
), args(args
), object(obj
), referent(cx
, obj
->referent()) {}
149 // JSNative properties
150 bool callableGetter();
151 bool isBoundFunctionGetter();
152 bool isArrowFunctionGetter();
153 bool isAsyncFunctionGetter();
154 bool isClassConstructorGetter();
155 bool isGeneratorFunctionGetter();
159 bool displayNameGetter();
160 bool parameterNamesGetter();
162 bool environmentGetter();
163 bool boundTargetFunctionGetter();
164 bool boundThisGetter();
165 bool boundArgumentsGetter();
166 bool allocationSiteGetter();
167 bool isErrorGetter();
168 bool errorMessageNameGetter();
169 bool errorNotesGetter();
170 bool errorLineNumberGetter();
171 bool errorColumnNumberGetter();
172 bool isProxyGetter();
173 bool proxyTargetGetter();
174 bool proxyHandlerGetter();
175 bool isPromiseGetter();
176 bool promiseStateGetter();
177 bool promiseValueGetter();
178 bool promiseReasonGetter();
179 bool promiseLifetimeGetter();
180 bool promiseTimeToResolutionGetter();
181 bool promiseAllocationSiteGetter();
182 bool promiseResolutionSiteGetter();
183 bool promiseIDGetter();
184 bool promiseDependentPromisesGetter();
187 bool isExtensibleMethod();
188 bool isSealedMethod();
189 bool isFrozenMethod();
190 bool getPropertyMethod();
191 bool setPropertyMethod();
192 bool getOwnPropertyNamesMethod();
193 bool getOwnPropertyNamesLengthMethod();
194 bool getOwnPropertySymbolsMethod();
195 bool getOwnPrivatePropertiesMethod();
196 bool getOwnPropertyDescriptorMethod();
197 bool preventExtensionsMethod();
200 bool definePropertyMethod();
201 bool definePropertiesMethod();
202 bool deletePropertyMethod();
205 bool asEnvironmentMethod();
206 bool forceLexicalInitializationByNameMethod();
207 bool executeInGlobalMethod();
208 bool executeInGlobalWithBindingsMethod();
210 bool makeDebuggeeValueMethod();
211 bool isSameNativeMethod();
212 bool isSameNativeWithJitInfoMethod();
213 bool isNativeGetterWithJitInfo();
214 bool unsafeDereferenceMethod();
216 bool getPromiseReactionsMethod();
218 using Method
= bool (CallData::*)();
220 template <Method MyMethod
>
221 static bool ToNative(JSContext
* cx
, unsigned argc
, Value
* vp
);
224 template <DebuggerObject::CallData::Method MyMethod
>
226 bool DebuggerObject::CallData::ToNative(JSContext
* cx
, unsigned argc
,
228 CallArgs args
= CallArgsFromVp(argc
, vp
);
230 Rooted
<DebuggerObject
*> obj(cx
, DebuggerObject_checkThis(cx
, args
));
235 CallData
data(cx
, args
, obj
);
236 return (data
.*MyMethod
)();
239 bool DebuggerObject::CallData::callableGetter() {
240 args
.rval().setBoolean(object
->isCallable());
244 bool DebuggerObject::CallData::isBoundFunctionGetter() {
245 args
.rval().setBoolean(object
->isBoundFunction());
249 bool DebuggerObject::CallData::isArrowFunctionGetter() {
250 if (!object
->isDebuggeeFunction()) {
251 args
.rval().setUndefined();
255 args
.rval().setBoolean(object
->isArrowFunction());
259 bool DebuggerObject::CallData::isAsyncFunctionGetter() {
260 if (!object
->isDebuggeeFunction()) {
261 args
.rval().setUndefined();
265 args
.rval().setBoolean(object
->isAsyncFunction());
269 bool DebuggerObject::CallData::isGeneratorFunctionGetter() {
270 if (!object
->isDebuggeeFunction()) {
271 args
.rval().setUndefined();
275 args
.rval().setBoolean(object
->isGeneratorFunction());
279 bool DebuggerObject::CallData::isClassConstructorGetter() {
280 if (!object
->isDebuggeeFunction()) {
281 args
.rval().setUndefined();
285 args
.rval().setBoolean(object
->isClassConstructor());
289 bool DebuggerObject::CallData::protoGetter() {
290 Rooted
<DebuggerObject
*> result(cx
);
291 if (!DebuggerObject::getPrototypeOf(cx
, object
, &result
)) {
295 args
.rval().setObjectOrNull(result
);
299 bool DebuggerObject::CallData::classGetter() {
300 RootedString
result(cx
);
301 if (!DebuggerObject::getClassName(cx
, object
, &result
)) {
305 args
.rval().setString(result
);
309 bool DebuggerObject::CallData::nameGetter() {
310 if (!object
->isFunction() && !object
->isBoundFunction()) {
311 args
.rval().setUndefined();
315 JS::Rooted
<JSAtom
*> result(cx
);
316 if (!object
->name(cx
, &result
)) {
321 args
.rval().setString(result
);
323 args
.rval().setUndefined();
328 bool DebuggerObject::CallData::displayNameGetter() {
329 if (!object
->isFunction() && !object
->isBoundFunction()) {
330 args
.rval().setUndefined();
334 JS::Rooted
<JSAtom
*> result(cx
);
335 if (!object
->displayName(cx
, &result
)) {
339 args
.rval().setString(result
);
341 args
.rval().setUndefined();
346 bool DebuggerObject::CallData::parameterNamesGetter() {
347 if (!object
->isDebuggeeFunction()) {
348 args
.rval().setUndefined();
352 RootedFunction
referent(cx
, &object
->referent()->as
<JSFunction
>());
354 ArrayObject
* arr
= GetFunctionParameterNamesArray(cx
, referent
);
359 args
.rval().setObject(*arr
);
363 bool DebuggerObject::CallData::scriptGetter() {
364 Debugger
* dbg
= object
->owner();
366 if (!referent
->is
<JSFunction
>()) {
367 args
.rval().setUndefined();
371 RootedFunction
fun(cx
, &referent
->as
<JSFunction
>());
372 if (!IsInterpretedNonSelfHostedFunction(fun
)) {
373 args
.rval().setUndefined();
377 RootedScript
script(cx
, GetOrCreateFunctionScript(cx
, fun
));
382 // Only hand out debuggee scripts.
383 if (!dbg
->observesScript(script
)) {
384 args
.rval().setNull();
388 Rooted
<DebuggerScript
*> scriptObject(cx
, dbg
->wrapScript(cx
, script
));
393 args
.rval().setObject(*scriptObject
);
397 bool DebuggerObject::CallData::environmentGetter() {
398 Debugger
* dbg
= object
->owner();
400 // Don't bother switching compartments just to check obj's type and get its
402 if (!referent
->is
<JSFunction
>()) {
403 args
.rval().setUndefined();
407 RootedFunction
fun(cx
, &referent
->as
<JSFunction
>());
408 if (!IsInterpretedNonSelfHostedFunction(fun
)) {
409 args
.rval().setUndefined();
413 // Only hand out environments of debuggee functions.
414 if (!dbg
->observesGlobal(&fun
->global())) {
415 args
.rval().setNull();
419 Rooted
<Env
*> env(cx
);
421 AutoRealm
ar(cx
, fun
);
422 env
= GetDebugEnvironmentForFunction(cx
, fun
);
428 return dbg
->wrapEnvironment(cx
, env
, args
.rval());
431 bool DebuggerObject::CallData::boundTargetFunctionGetter() {
432 if (!object
->isDebuggeeBoundFunction()) {
433 args
.rval().setUndefined();
437 Rooted
<DebuggerObject
*> result(cx
);
438 if (!DebuggerObject::getBoundTargetFunction(cx
, object
, &result
)) {
442 args
.rval().setObject(*result
);
446 bool DebuggerObject::CallData::boundThisGetter() {
447 if (!object
->isDebuggeeBoundFunction()) {
448 args
.rval().setUndefined();
452 return DebuggerObject::getBoundThis(cx
, object
, args
.rval());
455 bool DebuggerObject::CallData::boundArgumentsGetter() {
456 if (!object
->isDebuggeeBoundFunction()) {
457 args
.rval().setUndefined();
461 Rooted
<ValueVector
> result(cx
, ValueVector(cx
));
462 if (!DebuggerObject::getBoundArguments(cx
, object
, &result
)) {
467 NewDenseCopiedArray(cx
, result
.length(), result
.begin()));
472 args
.rval().setObject(*obj
);
476 bool DebuggerObject::CallData::allocationSiteGetter() {
477 RootedObject
result(cx
);
478 if (!DebuggerObject::getAllocationSite(cx
, object
, &result
)) {
482 args
.rval().setObjectOrNull(result
);
486 // Returns the "name" field (see js/public/friend/ErrorNumbers.msg), which may
487 // be used as a unique identifier, for any error object with a JSErrorReport or
488 // undefined if the object has no JSErrorReport.
489 bool DebuggerObject::CallData::errorMessageNameGetter() {
490 RootedString
result(cx
);
491 if (!DebuggerObject::getErrorMessageName(cx
, object
, &result
)) {
496 args
.rval().setString(result
);
498 args
.rval().setUndefined();
503 bool DebuggerObject::CallData::isErrorGetter() {
504 args
.rval().setBoolean(object
->isError());
508 bool DebuggerObject::CallData::errorNotesGetter() {
509 return DebuggerObject::getErrorNotes(cx
, object
, args
.rval());
512 bool DebuggerObject::CallData::errorLineNumberGetter() {
513 return DebuggerObject::getErrorLineNumber(cx
, object
, args
.rval());
516 bool DebuggerObject::CallData::errorColumnNumberGetter() {
517 return DebuggerObject::getErrorColumnNumber(cx
, object
, args
.rval());
520 bool DebuggerObject::CallData::isProxyGetter() {
521 args
.rval().setBoolean(object
->isScriptedProxy());
525 bool DebuggerObject::CallData::proxyTargetGetter() {
526 if (!object
->isScriptedProxy()) {
527 args
.rval().setUndefined();
531 Rooted
<DebuggerObject
*> result(cx
);
532 if (!DebuggerObject::getScriptedProxyTarget(cx
, object
, &result
)) {
536 args
.rval().setObjectOrNull(result
);
540 bool DebuggerObject::CallData::proxyHandlerGetter() {
541 if (!object
->isScriptedProxy()) {
542 args
.rval().setUndefined();
545 Rooted
<DebuggerObject
*> result(cx
);
546 if (!DebuggerObject::getScriptedProxyHandler(cx
, object
, &result
)) {
550 args
.rval().setObjectOrNull(result
);
554 bool DebuggerObject::CallData::isPromiseGetter() {
555 args
.rval().setBoolean(object
->isPromise());
559 bool DebuggerObject::CallData::promiseStateGetter() {
560 if (!DebuggerObject::requirePromise(cx
, object
)) {
564 RootedValue
result(cx
);
565 switch (object
->promiseState()) {
566 case JS::PromiseState::Pending
:
567 result
.setString(cx
->names().pending
);
569 case JS::PromiseState::Fulfilled
:
570 result
.setString(cx
->names().fulfilled
);
572 case JS::PromiseState::Rejected
:
573 result
.setString(cx
->names().rejected
);
577 args
.rval().set(result
);
581 bool DebuggerObject::CallData::promiseValueGetter() {
582 if (!DebuggerObject::requirePromise(cx
, object
)) {
586 if (object
->promiseState() != JS::PromiseState::Fulfilled
) {
587 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
588 JSMSG_DEBUG_PROMISE_NOT_FULFILLED
);
592 return DebuggerObject::getPromiseValue(cx
, object
, args
.rval());
596 bool DebuggerObject::CallData::promiseReasonGetter() {
597 if (!DebuggerObject::requirePromise(cx
, object
)) {
601 if (object
->promiseState() != JS::PromiseState::Rejected
) {
602 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
603 JSMSG_DEBUG_PROMISE_NOT_REJECTED
);
607 return DebuggerObject::getPromiseReason(cx
, object
, args
.rval());
610 bool DebuggerObject::CallData::promiseLifetimeGetter() {
611 if (!DebuggerObject::requirePromise(cx
, object
)) {
615 args
.rval().setNumber(object
->promiseLifetime());
619 bool DebuggerObject::CallData::promiseTimeToResolutionGetter() {
620 if (!DebuggerObject::requirePromise(cx
, object
)) {
624 if (object
->promiseState() == JS::PromiseState::Pending
) {
625 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
626 JSMSG_DEBUG_PROMISE_NOT_RESOLVED
);
630 args
.rval().setNumber(object
->promiseTimeToResolution());
634 static PromiseObject
* EnsurePromise(JSContext
* cx
, HandleObject referent
) {
635 // We only care about promises, so CheckedUnwrapStatic is OK.
636 RootedObject
obj(cx
, CheckedUnwrapStatic(referent
));
638 ReportAccessDenied(cx
);
641 if (!obj
->is
<PromiseObject
>()) {
642 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
643 JSMSG_NOT_EXPECTED_TYPE
, "Debugger", "Promise",
644 obj
->getClass()->name
);
647 return &obj
->as
<PromiseObject
>();
650 bool DebuggerObject::CallData::promiseAllocationSiteGetter() {
651 Rooted
<PromiseObject
*> promise(cx
, EnsurePromise(cx
, referent
));
656 RootedObject
allocSite(cx
, promise
->allocationSite());
658 args
.rval().setNull();
662 if (!cx
->compartment()->wrap(cx
, &allocSite
)) {
665 args
.rval().set(ObjectValue(*allocSite
));
669 bool DebuggerObject::CallData::promiseResolutionSiteGetter() {
670 Rooted
<PromiseObject
*> promise(cx
, EnsurePromise(cx
, referent
));
675 if (promise
->state() == JS::PromiseState::Pending
) {
676 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
677 JSMSG_DEBUG_PROMISE_NOT_RESOLVED
);
681 RootedObject
resolutionSite(cx
, promise
->resolutionSite());
682 if (!resolutionSite
) {
683 args
.rval().setNull();
687 if (!cx
->compartment()->wrap(cx
, &resolutionSite
)) {
690 args
.rval().set(ObjectValue(*resolutionSite
));
694 bool DebuggerObject::CallData::promiseIDGetter() {
695 Rooted
<PromiseObject
*> promise(cx
, EnsurePromise(cx
, referent
));
700 args
.rval().setNumber(double(promise
->getID()));
704 bool DebuggerObject::CallData::promiseDependentPromisesGetter() {
705 Debugger
* dbg
= object
->owner();
707 Rooted
<PromiseObject
*> promise(cx
, EnsurePromise(cx
, referent
));
712 Rooted
<GCVector
<Value
>> values(cx
, GCVector
<Value
>(cx
));
714 JSAutoRealm
ar(cx
, promise
);
715 if (!promise
->dependentPromises(cx
, &values
)) {
719 for (size_t i
= 0; i
< values
.length(); i
++) {
720 if (!dbg
->wrapDebuggeeValue(cx
, values
[i
])) {
724 Rooted
<ArrayObject
*> promises(cx
);
725 if (values
.length() == 0) {
726 promises
= NewDenseEmptyArray(cx
);
728 promises
= NewDenseCopiedArray(cx
, values
.length(), values
[0].address());
733 args
.rval().setObject(*promises
);
737 bool DebuggerObject::CallData::isExtensibleMethod() {
739 if (!DebuggerObject::isExtensible(cx
, object
, result
)) {
743 args
.rval().setBoolean(result
);
747 bool DebuggerObject::CallData::isSealedMethod() {
749 if (!DebuggerObject::isSealed(cx
, object
, result
)) {
753 args
.rval().setBoolean(result
);
757 bool DebuggerObject::CallData::isFrozenMethod() {
759 if (!DebuggerObject::isFrozen(cx
, object
, result
)) {
763 args
.rval().setBoolean(result
);
767 bool DebuggerObject::CallData::getOwnPropertyNamesMethod() {
768 RootedIdVector
ids(cx
);
769 if (!DebuggerObject::getOwnPropertyNames(cx
, object
, &ids
)) {
773 JSObject
* obj
= IdVectorToArray(cx
, ids
);
778 args
.rval().setObject(*obj
);
782 bool DebuggerObject::CallData::getOwnPropertyNamesLengthMethod() {
783 size_t ownPropertiesLength
;
784 if (!DebuggerObject::getOwnPropertyNamesLength(cx
, object
,
785 &ownPropertiesLength
)) {
789 args
.rval().setNumber(ownPropertiesLength
);
793 bool DebuggerObject::CallData::getOwnPropertySymbolsMethod() {
794 RootedIdVector
ids(cx
);
795 if (!DebuggerObject::getOwnPropertySymbols(cx
, object
, &ids
)) {
799 JSObject
* obj
= IdVectorToArray(cx
, ids
);
804 args
.rval().setObject(*obj
);
808 bool DebuggerObject::CallData::getOwnPrivatePropertiesMethod() {
809 RootedIdVector
ids(cx
);
810 if (!DebuggerObject::getOwnPrivateProperties(cx
, object
, &ids
)) {
814 JSObject
* obj
= IdVectorToArray(cx
, ids
);
819 args
.rval().setObject(*obj
);
823 bool DebuggerObject::CallData::getOwnPropertyDescriptorMethod() {
825 if (!ToPropertyKey(cx
, args
.get(0), &id
)) {
829 Rooted
<Maybe
<PropertyDescriptor
>> desc(cx
);
830 if (!DebuggerObject::getOwnPropertyDescriptor(cx
, object
, id
, &desc
)) {
834 return JS::FromPropertyDescriptor(cx
, desc
, args
.rval());
837 bool DebuggerObject::CallData::preventExtensionsMethod() {
838 if (!DebuggerObject::preventExtensions(cx
, object
)) {
842 args
.rval().setUndefined();
846 bool DebuggerObject::CallData::sealMethod() {
847 if (!DebuggerObject::seal(cx
, object
)) {
851 args
.rval().setUndefined();
855 bool DebuggerObject::CallData::freezeMethod() {
856 if (!DebuggerObject::freeze(cx
, object
)) {
860 args
.rval().setUndefined();
864 bool DebuggerObject::CallData::definePropertyMethod() {
865 if (!args
.requireAtLeast(cx
, "Debugger.Object.defineProperty", 2)) {
870 if (!ToPropertyKey(cx
, args
[0], &id
)) {
874 Rooted
<PropertyDescriptor
> desc(cx
);
875 if (!ToPropertyDescriptor(cx
, args
[1], false, &desc
)) {
879 if (!DebuggerObject::defineProperty(cx
, object
, id
, desc
)) {
883 args
.rval().setUndefined();
887 bool DebuggerObject::CallData::definePropertiesMethod() {
888 if (!args
.requireAtLeast(cx
, "Debugger.Object.defineProperties", 1)) {
892 RootedValue
arg(cx
, args
[0]);
893 RootedObject
props(cx
, ToObject(cx
, arg
));
897 RootedIdVector
ids(cx
);
898 Rooted
<PropertyDescriptorVector
> descs(cx
, PropertyDescriptorVector(cx
));
899 if (!ReadPropertyDescriptors(cx
, props
, false, &ids
, &descs
)) {
902 Rooted
<IdVector
> ids2(cx
, IdVector(cx
));
903 if (!ids2
.append(ids
.begin(), ids
.end())) {
907 if (!DebuggerObject::defineProperties(cx
, object
, ids2
, descs
)) {
911 args
.rval().setUndefined();
916 * This does a non-strict delete, as a matter of API design. The case where the
917 * property is non-configurable isn't necessarily exceptional here.
919 bool DebuggerObject::CallData::deletePropertyMethod() {
921 if (!ToPropertyKey(cx
, args
.get(0), &id
)) {
925 ObjectOpResult result
;
926 if (!DebuggerObject::deleteProperty(cx
, object
, id
, result
)) {
930 args
.rval().setBoolean(result
.ok());
934 bool DebuggerObject::CallData::callMethod() {
935 RootedValue
thisv(cx
, args
.get(0));
937 Rooted
<ValueVector
> nargs(cx
, ValueVector(cx
));
938 if (args
.length() >= 2) {
939 if (!nargs
.growBy(args
.length() - 1)) {
942 for (size_t i
= 1; i
< args
.length(); ++i
) {
943 nargs
[i
- 1].set(args
[i
]);
947 Rooted
<Maybe
<Completion
>> completion(
948 cx
, DebuggerObject::call(cx
, object
, thisv
, nargs
));
949 if (!completion
.get()) {
953 return completion
->buildCompletionValue(cx
, object
->owner(), args
.rval());
956 bool DebuggerObject::CallData::getPropertyMethod() {
957 Debugger
* dbg
= object
->owner();
960 if (!ToPropertyKey(cx
, args
.get(0), &id
)) {
964 RootedValue
receiver(cx
,
965 args
.length() < 2 ? ObjectValue(*object
) : args
.get(1));
967 Rooted
<Completion
> comp(cx
);
968 JS_TRY_VAR_OR_RETURN_FALSE(cx
, comp
, getProperty(cx
, object
, id
, receiver
));
969 return comp
.get().buildCompletionValue(cx
, dbg
, args
.rval());
972 bool DebuggerObject::CallData::setPropertyMethod() {
973 Debugger
* dbg
= object
->owner();
976 if (!ToPropertyKey(cx
, args
.get(0), &id
)) {
980 RootedValue
value(cx
, args
.get(1));
982 RootedValue
receiver(cx
,
983 args
.length() < 3 ? ObjectValue(*object
) : args
.get(2));
985 Rooted
<Completion
> comp(cx
);
986 JS_TRY_VAR_OR_RETURN_FALSE(cx
, comp
,
987 setProperty(cx
, object
, id
, value
, receiver
));
988 return comp
.get().buildCompletionValue(cx
, dbg
, args
.rval());
991 bool DebuggerObject::CallData::applyMethod() {
992 RootedValue
thisv(cx
, args
.get(0));
994 Rooted
<ValueVector
> nargs(cx
, ValueVector(cx
));
995 if (args
.length() >= 2 && !args
[1].isNullOrUndefined()) {
996 if (!args
[1].isObject()) {
997 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
998 JSMSG_BAD_APPLY_ARGS
, "apply");
1002 RootedObject
argsobj(cx
, &args
[1].toObject());
1005 if (!GetLengthProperty(cx
, argsobj
, &argc
)) {
1008 argc
= std::min(argc
, uint64_t(ARGS_LENGTH_MAX
));
1010 if (!nargs
.growBy(argc
) || !GetElements(cx
, argsobj
, argc
, nargs
.begin())) {
1015 Rooted
<Maybe
<Completion
>> completion(
1016 cx
, DebuggerObject::call(cx
, object
, thisv
, nargs
));
1017 if (!completion
.get()) {
1021 return completion
->buildCompletionValue(cx
, object
->owner(), args
.rval());
1024 static void EnterDebuggeeObjectRealm(JSContext
* cx
, Maybe
<AutoRealm
>& ar
,
1025 JSObject
* referent
) {
1026 // |referent| may be a cross-compartment wrapper and CCWs normally
1027 // shouldn't be used with AutoRealm, but here we use an arbitrary realm for
1028 // now because we don't really have another option.
1029 ar
.emplace(cx
, referent
->maybeCCWRealm()->maybeGlobal());
1032 static bool RequireGlobalObject(JSContext
* cx
, HandleValue dbgobj
,
1033 HandleObject referent
) {
1034 RootedObject
obj(cx
, referent
);
1036 if (!obj
->is
<GlobalObject
>()) {
1037 const char* isWrapper
= "";
1038 const char* isWindowProxy
= "";
1040 // Help the poor programmer by pointing out wrappers around globals...
1041 if (obj
->is
<WrapperObject
>()) {
1042 obj
= js::UncheckedUnwrap(obj
);
1043 isWrapper
= "a wrapper around ";
1046 // ... and WindowProxies around Windows.
1047 if (IsWindowProxy(obj
)) {
1048 obj
= ToWindowIfWindowProxy(obj
);
1049 isWindowProxy
= "a WindowProxy referring to ";
1052 if (obj
->is
<GlobalObject
>()) {
1053 ReportValueError(cx
, JSMSG_DEBUG_WRAPPER_IN_WAY
, JSDVG_SEARCH_STACK
,
1054 dbgobj
, nullptr, isWrapper
, isWindowProxy
);
1056 ReportValueError(cx
, JSMSG_DEBUG_BAD_REFERENT
, JSDVG_SEARCH_STACK
, dbgobj
,
1057 nullptr, "a global object");
1065 bool DebuggerObject::CallData::asEnvironmentMethod() {
1066 Debugger
* dbg
= object
->owner();
1068 if (!RequireGlobalObject(cx
, args
.thisv(), referent
)) {
1072 Rooted
<Env
*> env(cx
);
1074 AutoRealm
ar(cx
, referent
);
1075 env
= GetDebugEnvironmentForGlobalLexicalEnvironment(cx
);
1081 return dbg
->wrapEnvironment(cx
, env
, args
.rval());
1084 // Lookup a binding on the referent's global scope and change it to undefined
1085 // if it is an uninitialized lexical, otherwise do nothing. The method's
1086 // JavaScript return value is true _only_ when an uninitialized lexical has been
1087 // altered, otherwise it is false.
1088 bool DebuggerObject::CallData::forceLexicalInitializationByNameMethod() {
1089 if (!args
.requireAtLeast(
1090 cx
, "Debugger.Object.prototype.forceLexicalInitializationByName",
1095 if (!DebuggerObject::requireGlobal(cx
, object
)) {
1100 if (!ValueToIdentifier(cx
, args
[0], &id
)) {
1105 if (!DebuggerObject::forceLexicalInitializationByName(cx
, object
, id
,
1110 args
.rval().setBoolean(result
);
1114 bool DebuggerObject::CallData::executeInGlobalMethod() {
1115 if (!args
.requireAtLeast(cx
, "Debugger.Object.prototype.executeInGlobal",
1120 if (!DebuggerObject::requireGlobal(cx
, object
)) {
1124 AutoStableStringChars
stableChars(cx
);
1125 if (!ValueToStableChars(cx
, "Debugger.Object.prototype.executeInGlobal",
1126 args
[0], stableChars
)) {
1129 mozilla::Range
<const char16_t
> chars
= stableChars
.twoByteRange();
1131 EvalOptions
options(EvalOptions::EnvKind::Global
);
1132 if (!ParseEvalOptions(cx
, args
.get(1), options
)) {
1136 Rooted
<Completion
> comp(cx
);
1137 JS_TRY_VAR_OR_RETURN_FALSE(
1139 DebuggerObject::executeInGlobal(cx
, object
, chars
, nullptr, options
));
1140 return comp
.get().buildCompletionValue(cx
, object
->owner(), args
.rval());
1143 bool DebuggerObject::CallData::executeInGlobalWithBindingsMethod() {
1144 if (!args
.requireAtLeast(
1145 cx
, "Debugger.Object.prototype.executeInGlobalWithBindings", 2)) {
1149 if (!DebuggerObject::requireGlobal(cx
, object
)) {
1153 AutoStableStringChars
stableChars(cx
);
1154 if (!ValueToStableChars(
1155 cx
, "Debugger.Object.prototype.executeInGlobalWithBindings", args
[0],
1159 mozilla::Range
<const char16_t
> chars
= stableChars
.twoByteRange();
1161 RootedObject
bindings(cx
, RequireObject(cx
, args
[1]));
1166 EvalOptions
options(EvalOptions::EnvKind::GlobalWithExtraOuterBindings
);
1167 if (!ParseEvalOptions(cx
, args
.get(2), options
)) {
1171 Rooted
<Completion
> comp(cx
);
1172 JS_TRY_VAR_OR_RETURN_FALSE(
1174 DebuggerObject::executeInGlobal(cx
, object
, chars
, bindings
, options
));
1175 return comp
.get().buildCompletionValue(cx
, object
->owner(), args
.rval());
1178 // Copy a narrow or wide string to a vector, appending a null terminator.
1179 template <typename T
>
1180 static bool CopyStringToVector(JSContext
* cx
, JSString
* str
, Vector
<T
>& chars
) {
1181 JSLinearString
* linear
= str
->ensureLinear(cx
);
1185 if (!chars
.appendN(0, linear
->length() + 1)) {
1188 CopyChars(chars
.begin(), *linear
);
1192 bool DebuggerObject::CallData::createSource() {
1193 if (!args
.requireAtLeast(cx
, "Debugger.Object.prototype.createSource", 1)) {
1197 if (!DebuggerObject::requireGlobal(cx
, object
)) {
1201 Debugger
* dbg
= object
->owner();
1202 if (!dbg
->isDebuggeeUnbarriered(referent
->as
<GlobalObject
>().realm())) {
1203 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
1204 JSMSG_DEBUG_NOT_DEBUGGEE
, "Debugger.Object",
1209 RootedObject
options(cx
, ToObject(cx
, args
[0]));
1215 if (!JS_GetProperty(cx
, options
, "text", &v
)) {
1219 RootedString
text(cx
, ToString
<CanGC
>(cx
, v
));
1224 if (!JS_GetProperty(cx
, options
, "url", &v
)) {
1228 RootedString
url(cx
, ToString
<CanGC
>(cx
, v
));
1233 if (!JS_GetProperty(cx
, options
, "startLine", &v
)) {
1238 if (!ToUint32(cx
, v
, &startLine
)) {
1242 if (!JS_GetProperty(cx
, options
, "startColumn", &v
)) {
1246 uint32_t startColumn
;
1247 if (!ToUint32(cx
, v
, &startColumn
)) {
1250 if (startColumn
== 0) {
1254 if (!JS_GetProperty(cx
, options
, "sourceMapURL", &v
)) {
1258 RootedString
sourceMapURL(cx
);
1259 if (!v
.isUndefined()) {
1260 sourceMapURL
= ToString
<CanGC
>(cx
, v
);
1261 if (!sourceMapURL
) {
1266 if (!JS_GetProperty(cx
, options
, "isScriptElement", &v
)) {
1270 bool isScriptElement
= ToBoolean(v
);
1272 JS::CompileOptions
compileOptions(cx
);
1273 compileOptions
.lineno
= startLine
;
1274 compileOptions
.column
= JS::ColumnNumberOneOrigin(startColumn
);
1276 if (!JS::StringHasLatin1Chars(url
)) {
1277 JS_ReportErrorASCII(cx
, "URL must be a narrow string");
1281 Vector
<Latin1Char
> urlChars(cx
);
1282 if (!CopyStringToVector(cx
, url
, urlChars
)) {
1285 compileOptions
.setFile((const char*)urlChars
.begin());
1287 Vector
<char16_t
> sourceMapURLChars(cx
);
1289 if (!CopyStringToVector(cx
, sourceMapURL
, sourceMapURLChars
)) {
1292 compileOptions
.setSourceMapURL(sourceMapURLChars
.begin());
1295 if (isScriptElement
) {
1296 // The introduction type must be a statically allocated string.
1297 compileOptions
.setIntroductionType("inlineScript");
1300 AutoStableStringChars
linearChars(cx
);
1301 if (!linearChars
.initTwoByte(cx
, text
)) {
1304 JS::SourceText
<char16_t
> srcBuf
;
1305 if (!srcBuf
.initMaybeBorrowed(cx
, linearChars
)) {
1309 RootedScript
script(cx
);
1311 AutoRealm
ar(cx
, referent
);
1312 script
= JS::Compile(cx
, compileOptions
, srcBuf
);
1318 Rooted
<ScriptSourceObject
*> sso(cx
, script
->sourceObject());
1319 RootedObject
wrapped(cx
, dbg
->wrapSource(cx
, sso
));
1324 args
.rval().setObject(*wrapped
);
1328 bool DebuggerObject::CallData::makeDebuggeeValueMethod() {
1329 if (!args
.requireAtLeast(cx
, "Debugger.Object.prototype.makeDebuggeeValue",
1334 return DebuggerObject::makeDebuggeeValue(cx
, object
, args
[0], args
.rval());
1337 bool DebuggerObject::CallData::isSameNativeMethod() {
1338 if (!args
.requireAtLeast(cx
, "Debugger.Object.prototype.isSameNative", 1)) {
1342 return DebuggerObject::isSameNative(cx
, object
, args
[0], CheckJitInfo::No
,
1346 bool DebuggerObject::CallData::isSameNativeWithJitInfoMethod() {
1347 if (!args
.requireAtLeast(
1348 cx
, "Debugger.Object.prototype.isSameNativeWithJitInfo", 1)) {
1352 return DebuggerObject::isSameNative(cx
, object
, args
[0], CheckJitInfo::Yes
,
1356 bool DebuggerObject::CallData::isNativeGetterWithJitInfo() {
1357 return DebuggerObject::isNativeGetterWithJitInfo(cx
, object
, args
.rval());
1360 bool DebuggerObject::CallData::unsafeDereferenceMethod() {
1361 RootedObject
result(cx
);
1362 if (!DebuggerObject::unsafeDereference(cx
, object
, &result
)) {
1366 args
.rval().setObject(*result
);
1370 bool DebuggerObject::CallData::unwrapMethod() {
1371 Rooted
<DebuggerObject
*> result(cx
);
1372 if (!DebuggerObject::unwrap(cx
, object
, &result
)) {
1376 args
.rval().setObjectOrNull(result
);
1380 struct DebuggerObject::PromiseReactionRecordBuilder
1381 : js::PromiseReactionRecordBuilder
{
1383 Handle
<ArrayObject
*> records
;
1385 PromiseReactionRecordBuilder(Debugger
* dbg
, Handle
<ArrayObject
*> records
)
1386 : dbg(dbg
), records(records
) {}
1388 bool then(JSContext
* cx
, HandleObject resolve
, HandleObject reject
,
1389 HandleObject result
) override
{
1390 Rooted
<PlainObject
*> record(cx
, NewPlainObject(cx
));
1395 if (!setIfNotNull(cx
, record
, cx
->names().resolve
, resolve
) ||
1396 !setIfNotNull(cx
, record
, cx
->names().reject
, reject
) ||
1397 !setIfNotNull(cx
, record
, cx
->names().result
, result
)) {
1401 return push(cx
, record
);
1404 bool direct(JSContext
* cx
, Handle
<PromiseObject
*> unwrappedPromise
) override
{
1405 RootedValue
v(cx
, ObjectValue(*unwrappedPromise
));
1406 return dbg
->wrapDebuggeeValue(cx
, &v
) && push(cx
, v
);
1411 Handle
<AsyncFunctionGeneratorObject
*> unwrappedGenerator
) override
{
1412 return maybePushGenerator(cx
, unwrappedGenerator
);
1415 bool asyncGenerator(
1417 Handle
<AsyncGeneratorObject
*> unwrappedGenerator
) override
{
1418 return maybePushGenerator(cx
, unwrappedGenerator
);
1422 bool push(JSContext
* cx
, HandleObject record
) {
1423 RootedValue
recordVal(cx
, ObjectValue(*record
));
1424 return push(cx
, recordVal
);
1427 bool push(JSContext
* cx
, HandleValue recordVal
) {
1428 return NewbornArrayPush(cx
, records
, recordVal
);
1431 bool maybePushGenerator(JSContext
* cx
,
1432 Handle
<AbstractGeneratorObject
*> unwrappedGenerator
) {
1433 Rooted
<DebuggerFrame
*> frame(cx
);
1434 if (unwrappedGenerator
->isClosed()) {
1435 // If the generator is closed, we can't generate a DebuggerFrame for it,
1439 if (!unwrappedGenerator
->realm()->isDebuggee()) {
1440 // Caller can keep the reference to the debugger object even after
1441 // removing the realm from debuggee. Do nothing for this case.
1444 return dbg
->getFrame(cx
, unwrappedGenerator
, &frame
) && push(cx
, frame
);
1447 bool setIfNotNull(JSContext
* cx
, Handle
<PlainObject
*> obj
,
1448 Handle
<PropertyName
*> name
, HandleObject prop
) {
1453 RootedValue
v(cx
, ObjectValue(*prop
));
1454 if (!dbg
->wrapDebuggeeValue(cx
, &v
) ||
1455 !DefineDataProperty(cx
, obj
, name
, v
)) {
1463 bool DebuggerObject::CallData::getPromiseReactionsMethod() {
1464 Debugger
* dbg
= object
->owner();
1466 Rooted
<PromiseObject
*> unwrappedPromise(cx
, EnsurePromise(cx
, referent
));
1467 if (!unwrappedPromise
) {
1471 Rooted
<ArrayObject
*> holder(cx
, NewDenseEmptyArray(cx
));
1476 PromiseReactionRecordBuilder
builder(dbg
, holder
);
1477 if (!unwrappedPromise
->forEachReactionRecord(cx
, builder
)) {
1481 args
.rval().setObject(*builder
.records
);
1485 const JSPropertySpec
DebuggerObject::properties_
[] = {
1486 JS_DEBUG_PSG("callable", callableGetter
),
1487 JS_DEBUG_PSG("isBoundFunction", isBoundFunctionGetter
),
1488 JS_DEBUG_PSG("isArrowFunction", isArrowFunctionGetter
),
1489 JS_DEBUG_PSG("isGeneratorFunction", isGeneratorFunctionGetter
),
1490 JS_DEBUG_PSG("isAsyncFunction", isAsyncFunctionGetter
),
1491 JS_DEBUG_PSG("isClassConstructor", isClassConstructorGetter
),
1492 JS_DEBUG_PSG("proto", protoGetter
),
1493 JS_DEBUG_PSG("class", classGetter
),
1494 JS_DEBUG_PSG("name", nameGetter
),
1495 JS_DEBUG_PSG("displayName", displayNameGetter
),
1496 JS_DEBUG_PSG("parameterNames", parameterNamesGetter
),
1497 JS_DEBUG_PSG("script", scriptGetter
),
1498 JS_DEBUG_PSG("environment", environmentGetter
),
1499 JS_DEBUG_PSG("boundTargetFunction", boundTargetFunctionGetter
),
1500 JS_DEBUG_PSG("boundThis", boundThisGetter
),
1501 JS_DEBUG_PSG("boundArguments", boundArgumentsGetter
),
1502 JS_DEBUG_PSG("allocationSite", allocationSiteGetter
),
1503 JS_DEBUG_PSG("isError", isErrorGetter
),
1504 JS_DEBUG_PSG("errorMessageName", errorMessageNameGetter
),
1505 JS_DEBUG_PSG("errorNotes", errorNotesGetter
),
1506 JS_DEBUG_PSG("errorLineNumber", errorLineNumberGetter
),
1507 JS_DEBUG_PSG("errorColumnNumber", errorColumnNumberGetter
),
1508 JS_DEBUG_PSG("isProxy", isProxyGetter
),
1509 JS_DEBUG_PSG("proxyTarget", proxyTargetGetter
),
1510 JS_DEBUG_PSG("proxyHandler", proxyHandlerGetter
),
1513 const JSPropertySpec
DebuggerObject::promiseProperties_
[] = {
1514 JS_DEBUG_PSG("isPromise", isPromiseGetter
),
1515 JS_DEBUG_PSG("promiseState", promiseStateGetter
),
1516 JS_DEBUG_PSG("promiseValue", promiseValueGetter
),
1517 JS_DEBUG_PSG("promiseReason", promiseReasonGetter
),
1518 JS_DEBUG_PSG("promiseLifetime", promiseLifetimeGetter
),
1519 JS_DEBUG_PSG("promiseTimeToResolution", promiseTimeToResolutionGetter
),
1520 JS_DEBUG_PSG("promiseAllocationSite", promiseAllocationSiteGetter
),
1521 JS_DEBUG_PSG("promiseResolutionSite", promiseResolutionSiteGetter
),
1522 JS_DEBUG_PSG("promiseID", promiseIDGetter
),
1523 JS_DEBUG_PSG("promiseDependentPromises", promiseDependentPromisesGetter
),
1526 const JSFunctionSpec
DebuggerObject::methods_
[] = {
1527 JS_DEBUG_FN("isExtensible", isExtensibleMethod
, 0),
1528 JS_DEBUG_FN("isSealed", isSealedMethod
, 0),
1529 JS_DEBUG_FN("isFrozen", isFrozenMethod
, 0),
1530 JS_DEBUG_FN("getProperty", getPropertyMethod
, 0),
1531 JS_DEBUG_FN("setProperty", setPropertyMethod
, 0),
1532 JS_DEBUG_FN("getOwnPropertyNames", getOwnPropertyNamesMethod
, 0),
1533 JS_DEBUG_FN("getOwnPropertyNamesLength", getOwnPropertyNamesLengthMethod
,
1535 JS_DEBUG_FN("getOwnPropertySymbols", getOwnPropertySymbolsMethod
, 0),
1536 JS_DEBUG_FN("getOwnPrivateProperties", getOwnPrivatePropertiesMethod
, 0),
1537 JS_DEBUG_FN("getOwnPropertyDescriptor", getOwnPropertyDescriptorMethod
, 1),
1538 JS_DEBUG_FN("preventExtensions", preventExtensionsMethod
, 0),
1539 JS_DEBUG_FN("seal", sealMethod
, 0),
1540 JS_DEBUG_FN("freeze", freezeMethod
, 0),
1541 JS_DEBUG_FN("defineProperty", definePropertyMethod
, 2),
1542 JS_DEBUG_FN("defineProperties", definePropertiesMethod
, 1),
1543 JS_DEBUG_FN("deleteProperty", deletePropertyMethod
, 1),
1544 JS_DEBUG_FN("call", callMethod
, 0),
1545 JS_DEBUG_FN("apply", applyMethod
, 0),
1546 JS_DEBUG_FN("asEnvironment", asEnvironmentMethod
, 0),
1547 JS_DEBUG_FN("forceLexicalInitializationByName",
1548 forceLexicalInitializationByNameMethod
, 1),
1549 JS_DEBUG_FN("executeInGlobal", executeInGlobalMethod
, 1),
1550 JS_DEBUG_FN("executeInGlobalWithBindings",
1551 executeInGlobalWithBindingsMethod
, 2),
1552 JS_DEBUG_FN("createSource", createSource
, 1),
1553 JS_DEBUG_FN("makeDebuggeeValue", makeDebuggeeValueMethod
, 1),
1554 JS_DEBUG_FN("isSameNative", isSameNativeMethod
, 1),
1555 JS_DEBUG_FN("isSameNativeWithJitInfo", isSameNativeWithJitInfoMethod
, 1),
1556 JS_DEBUG_FN("isNativeGetterWithJitInfo", isNativeGetterWithJitInfo
, 1),
1557 JS_DEBUG_FN("unsafeDereference", unsafeDereferenceMethod
, 0),
1558 JS_DEBUG_FN("unwrap", unwrapMethod
, 0),
1559 JS_DEBUG_FN("getPromiseReactions", getPromiseReactionsMethod
, 0),
1563 NativeObject
* DebuggerObject::initClass(JSContext
* cx
,
1564 Handle
<GlobalObject
*> global
,
1565 HandleObject debugCtor
) {
1566 Rooted
<NativeObject
*> objectProto(
1567 cx
, InitClass(cx
, debugCtor
, nullptr, nullptr, "Object", construct
, 0,
1568 properties_
, methods_
, nullptr, nullptr));
1574 if (!DefinePropertiesAndFunctions(cx
, objectProto
, promiseProperties_
,
1583 DebuggerObject
* DebuggerObject::create(JSContext
* cx
, HandleObject proto
,
1584 HandleObject referent
,
1585 Handle
<NativeObject
*> debugger
) {
1586 DebuggerObject
* obj
=
1587 IsInsideNursery(referent
)
1588 ? NewObjectWithGivenProto
<DebuggerObject
>(cx
, proto
)
1589 : NewTenuredObjectWithGivenProto
<DebuggerObject
>(cx
, proto
);
1594 obj
->setReservedSlotGCThingAsPrivate(OBJECT_SLOT
, referent
);
1595 obj
->setReservedSlot(OWNER_SLOT
, ObjectValue(*debugger
));
1600 bool DebuggerObject::isCallable() const { return referent()->isCallable(); }
1602 bool DebuggerObject::isFunction() const { return referent()->is
<JSFunction
>(); }
1604 bool DebuggerObject::isDebuggeeFunction() const {
1605 return referent()->is
<JSFunction
>() &&
1606 owner()->observesGlobal(&referent()->as
<JSFunction
>().global());
1609 bool DebuggerObject::isBoundFunction() const {
1610 return referent()->is
<BoundFunctionObject
>();
1613 bool DebuggerObject::isDebuggeeBoundFunction() const {
1614 return referent()->is
<BoundFunctionObject
>() &&
1615 owner()->observesGlobal(
1616 &referent()->as
<BoundFunctionObject
>().global());
1619 bool DebuggerObject::isArrowFunction() const {
1620 MOZ_ASSERT(isDebuggeeFunction());
1622 return referent()->as
<JSFunction
>().isArrow();
1625 bool DebuggerObject::isAsyncFunction() const {
1626 MOZ_ASSERT(isDebuggeeFunction());
1628 return referent()->as
<JSFunction
>().isAsync();
1631 bool DebuggerObject::isGeneratorFunction() const {
1632 MOZ_ASSERT(isDebuggeeFunction());
1634 return referent()->as
<JSFunction
>().isGenerator();
1637 bool DebuggerObject::isClassConstructor() const {
1638 MOZ_ASSERT(isDebuggeeFunction());
1640 return referent()->as
<JSFunction
>().isClassConstructor();
1643 bool DebuggerObject::isGlobal() const { return referent()->is
<GlobalObject
>(); }
1645 bool DebuggerObject::isScriptedProxy() const {
1646 return js::IsScriptedProxy(referent());
1649 bool DebuggerObject::isPromise() const {
1650 JSObject
* referent
= this->referent();
1652 if (IsCrossCompartmentWrapper(referent
)) {
1653 // We only care about promises, so CheckedUnwrapStatic is OK.
1654 referent
= CheckedUnwrapStatic(referent
);
1660 return referent
->is
<PromiseObject
>();
1663 bool DebuggerObject::isError() const {
1664 JSObject
* referent
= this->referent();
1666 if (IsCrossCompartmentWrapper(referent
)) {
1667 // We only check for error classes, so CheckedUnwrapStatic is OK.
1668 referent
= CheckedUnwrapStatic(referent
);
1674 return referent
->is
<ErrorObject
>();
1678 bool DebuggerObject::getClassName(JSContext
* cx
, Handle
<DebuggerObject
*> object
,
1679 MutableHandleString result
) {
1680 RootedObject
referent(cx
, object
->referent());
1682 const char* className
;
1684 Maybe
<AutoRealm
> ar
;
1685 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
1686 className
= GetObjectClassName(cx
, referent
);
1689 JSAtom
* str
= Atomize(cx
, className
, strlen(className
));
1698 bool DebuggerObject::name(JSContext
* cx
,
1699 JS::MutableHandle
<JSAtom
*> result
) const {
1701 JSFunction
* fun
= &referent()->as
<JSFunction
>();
1702 if (!fun
->isAccessorWithLazyName()) {
1703 result
.set(fun
->fullExplicitName());
1705 cx
->markAtom(result
);
1711 Maybe
<AutoRealm
> ar
;
1712 EnterDebuggeeObjectRealm(cx
, ar
, fun
);
1714 result
.set(fun
->getAccessorNameForLazy(cx
));
1719 cx
->markAtom(result
);
1723 MOZ_ASSERT(isBoundFunction());
1725 // Bound functions have a configurable `name` data property and currently
1726 // don't store the original name. Try a pure lookup to get this name and if
1727 // this fails use "bound".
1728 Rooted
<BoundFunctionObject
*> bound(cx
,
1729 &referent()->as
<BoundFunctionObject
>());
1731 Maybe
<AutoRealm
> ar
;
1732 EnterDebuggeeObjectRealm(cx
, ar
, bound
);
1736 if (GetOwnPropertyPure(cx
, bound
, NameToId(cx
->names().name
), &v
, &found
) &&
1737 found
&& v
.isString()) {
1738 result
.set(AtomizeString(cx
, v
.toString()));
1743 result
.set(cx
->names().bound
);
1747 cx
->markAtom(result
);
1751 bool DebuggerObject::displayName(JSContext
* cx
,
1752 JS::MutableHandle
<JSAtom
*> result
) const {
1755 JS::Rooted
<JSFunction
*> fun(cx
, &referent()->as
<JSFunction
>());
1757 Maybe
<AutoRealm
> ar
;
1758 EnterDebuggeeObjectRealm(cx
, ar
, fun
);
1760 if (!fun
->getDisplayAtom(cx
, result
)) {
1765 cx
->markAtom(result
);
1770 MOZ_ASSERT(isBoundFunction());
1771 return name(cx
, result
);
1774 JS::PromiseState
DebuggerObject::promiseState() const {
1775 return promise()->state();
1778 double DebuggerObject::promiseLifetime() const { return promise()->lifetime(); }
1780 double DebuggerObject::promiseTimeToResolution() const {
1781 MOZ_ASSERT(promiseState() != JS::PromiseState::Pending
);
1783 return promise()->timeToResolution();
1787 bool DebuggerObject::getBoundTargetFunction(
1788 JSContext
* cx
, Handle
<DebuggerObject
*> object
,
1789 MutableHandle
<DebuggerObject
*> result
) {
1790 MOZ_ASSERT(object
->isBoundFunction());
1792 Rooted
<BoundFunctionObject
*> referent(
1793 cx
, &object
->referent()->as
<BoundFunctionObject
>());
1794 Debugger
* dbg
= object
->owner();
1796 RootedObject
target(cx
, referent
->getTarget());
1797 return dbg
->wrapDebuggeeObject(cx
, target
, result
);
1801 bool DebuggerObject::getBoundThis(JSContext
* cx
, Handle
<DebuggerObject
*> object
,
1802 MutableHandleValue result
) {
1803 MOZ_ASSERT(object
->isBoundFunction());
1805 Rooted
<BoundFunctionObject
*> referent(
1806 cx
, &object
->referent()->as
<BoundFunctionObject
>());
1807 Debugger
* dbg
= object
->owner();
1809 result
.set(referent
->getBoundThis());
1810 return dbg
->wrapDebuggeeValue(cx
, result
);
1814 bool DebuggerObject::getBoundArguments(JSContext
* cx
,
1815 Handle
<DebuggerObject
*> object
,
1816 MutableHandle
<ValueVector
> result
) {
1817 MOZ_ASSERT(object
->isBoundFunction());
1819 Rooted
<BoundFunctionObject
*> referent(
1820 cx
, &object
->referent()->as
<BoundFunctionObject
>());
1821 Debugger
* dbg
= object
->owner();
1823 size_t length
= referent
->numBoundArgs();
1824 if (!result
.resize(length
)) {
1827 for (size_t i
= 0; i
< length
; i
++) {
1828 result
[i
].set(referent
->getBoundArg(i
));
1829 if (!dbg
->wrapDebuggeeValue(cx
, result
[i
])) {
1837 SavedFrame
* Debugger::getObjectAllocationSite(JSObject
& obj
) {
1838 JSObject
* metadata
= GetAllocationMetadata(&obj
);
1843 MOZ_ASSERT(!metadata
->is
<WrapperObject
>());
1844 return metadata
->is
<SavedFrame
>() ? &metadata
->as
<SavedFrame
>() : nullptr;
1848 bool DebuggerObject::getAllocationSite(JSContext
* cx
,
1849 Handle
<DebuggerObject
*> object
,
1850 MutableHandleObject result
) {
1851 RootedObject
referent(cx
, object
->referent());
1853 RootedObject
allocSite(cx
, Debugger::getObjectAllocationSite(*referent
));
1854 if (!cx
->compartment()->wrap(cx
, &allocSite
)) {
1858 result
.set(allocSite
);
1863 bool DebuggerObject::getErrorReport(JSContext
* cx
, HandleObject maybeError
,
1864 JSErrorReport
*& report
) {
1865 JSObject
* obj
= maybeError
;
1866 if (IsCrossCompartmentWrapper(obj
)) {
1867 /* We only care about Error objects, so CheckedUnwrapStatic is OK. */
1868 obj
= CheckedUnwrapStatic(obj
);
1872 ReportAccessDenied(cx
);
1876 if (!obj
->is
<ErrorObject
>()) {
1881 report
= obj
->as
<ErrorObject
>().getErrorReport();
1886 bool DebuggerObject::getErrorMessageName(JSContext
* cx
,
1887 Handle
<DebuggerObject
*> object
,
1888 MutableHandleString result
) {
1889 RootedObject
referent(cx
, object
->referent());
1890 JSErrorReport
* report
;
1891 if (!getErrorReport(cx
, referent
, report
)) {
1895 if (!report
|| !report
->errorMessageName
) {
1896 result
.set(nullptr);
1900 RootedString
str(cx
, JS_NewStringCopyZ(cx
, report
->errorMessageName
));
1909 bool DebuggerObject::getErrorNotes(JSContext
* cx
,
1910 Handle
<DebuggerObject
*> object
,
1911 MutableHandleValue result
) {
1912 RootedObject
referent(cx
, object
->referent());
1913 JSErrorReport
* report
;
1914 if (!getErrorReport(cx
, referent
, report
)) {
1919 result
.setUndefined();
1923 RootedObject
errorNotesArray(cx
, CreateErrorNotesArray(cx
, report
));
1924 if (!errorNotesArray
) {
1928 if (!cx
->compartment()->wrap(cx
, &errorNotesArray
)) {
1931 result
.setObject(*errorNotesArray
);
1936 bool DebuggerObject::getErrorLineNumber(JSContext
* cx
,
1937 Handle
<DebuggerObject
*> object
,
1938 MutableHandleValue result
) {
1939 RootedObject
referent(cx
, object
->referent());
1940 JSErrorReport
* report
;
1941 if (!getErrorReport(cx
, referent
, report
)) {
1946 result
.setUndefined();
1950 result
.setNumber(report
->lineno
);
1955 bool DebuggerObject::getErrorColumnNumber(JSContext
* cx
,
1956 Handle
<DebuggerObject
*> object
,
1957 MutableHandleValue result
) {
1958 RootedObject
referent(cx
, object
->referent());
1959 JSErrorReport
* report
;
1960 if (!getErrorReport(cx
, referent
, report
)) {
1965 result
.setUndefined();
1969 result
.setNumber(report
->column
.oneOriginValue());
1974 bool DebuggerObject::getPromiseValue(JSContext
* cx
,
1975 Handle
<DebuggerObject
*> object
,
1976 MutableHandleValue result
) {
1977 MOZ_ASSERT(object
->promiseState() == JS::PromiseState::Fulfilled
);
1979 result
.set(object
->promise()->value());
1980 return object
->owner()->wrapDebuggeeValue(cx
, result
);
1984 bool DebuggerObject::getPromiseReason(JSContext
* cx
,
1985 Handle
<DebuggerObject
*> object
,
1986 MutableHandleValue result
) {
1987 MOZ_ASSERT(object
->promiseState() == JS::PromiseState::Rejected
);
1989 result
.set(object
->promise()->reason());
1990 return object
->owner()->wrapDebuggeeValue(cx
, result
);
1994 bool DebuggerObject::isExtensible(JSContext
* cx
, Handle
<DebuggerObject
*> object
,
1996 RootedObject
referent(cx
, object
->referent());
1998 Maybe
<AutoRealm
> ar
;
1999 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2002 return IsExtensible(cx
, referent
, &result
);
2006 bool DebuggerObject::isSealed(JSContext
* cx
, Handle
<DebuggerObject
*> object
,
2008 RootedObject
referent(cx
, object
->referent());
2010 Maybe
<AutoRealm
> ar
;
2011 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2014 return TestIntegrityLevel(cx
, referent
, IntegrityLevel::Sealed
, &result
);
2018 bool DebuggerObject::isFrozen(JSContext
* cx
, Handle
<DebuggerObject
*> object
,
2020 RootedObject
referent(cx
, object
->referent());
2022 Maybe
<AutoRealm
> ar
;
2023 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2026 return TestIntegrityLevel(cx
, referent
, IntegrityLevel::Frozen
, &result
);
2030 bool DebuggerObject::getPrototypeOf(JSContext
* cx
,
2031 Handle
<DebuggerObject
*> object
,
2032 MutableHandle
<DebuggerObject
*> result
) {
2033 RootedObject
referent(cx
, object
->referent());
2034 Debugger
* dbg
= object
->owner();
2036 RootedObject
proto(cx
);
2038 Maybe
<AutoRealm
> ar
;
2039 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2040 if (!GetPrototype(cx
, referent
, &proto
)) {
2045 return dbg
->wrapNullableDebuggeeObject(cx
, proto
, result
);
2049 bool DebuggerObject::getOwnPropertyNames(JSContext
* cx
,
2050 Handle
<DebuggerObject
*> object
,
2051 MutableHandleIdVector result
) {
2052 MOZ_ASSERT(result
.empty());
2054 RootedObject
referent(cx
, object
->referent());
2056 Maybe
<AutoRealm
> ar
;
2057 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2060 if (!GetPropertyKeys(cx
, referent
, JSITER_OWNONLY
| JSITER_HIDDEN
,
2066 for (size_t i
= 0; i
< result
.length(); i
++) {
2067 cx
->markId(result
[i
]);
2074 bool DebuggerObject::getOwnPropertyNamesLength(JSContext
* cx
,
2075 Handle
<DebuggerObject
*> object
,
2077 RootedObject
referent(cx
, object
->referent());
2079 RootedIdVector
ids(cx
);
2081 Maybe
<AutoRealm
> ar
;
2082 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2085 if (!GetPropertyKeys(cx
, referent
, JSITER_OWNONLY
| JSITER_HIDDEN
, &ids
)) {
2090 *result
= ids
.length();
2094 static bool GetSymbolPropertyKeys(JSContext
* cx
, Handle
<DebuggerObject
*> object
,
2095 JS::MutableHandleIdVector props
,
2096 bool includePrivate
) {
2097 RootedObject
referent(cx
, object
->referent());
2100 Maybe
<AutoRealm
> ar
;
2101 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2106 JSITER_OWNONLY
| JSITER_HIDDEN
| JSITER_SYMBOLS
| JSITER_SYMBOLSONLY
;
2107 if (includePrivate
) {
2108 flags
= flags
| JSITER_PRIVATE
;
2110 if (!GetPropertyKeys(cx
, referent
, flags
, props
)) {
2119 bool DebuggerObject::getOwnPropertySymbols(JSContext
* cx
,
2120 Handle
<DebuggerObject
*> object
,
2121 MutableHandleIdVector result
) {
2122 MOZ_ASSERT(result
.empty());
2124 if (!GetSymbolPropertyKeys(cx
, object
, result
, false)) {
2128 for (size_t i
= 0; i
< result
.length(); i
++) {
2129 cx
->markAtom(result
[i
].toSymbol());
2136 bool DebuggerObject::getOwnPrivateProperties(JSContext
* cx
,
2137 Handle
<DebuggerObject
*> object
,
2138 MutableHandleIdVector result
) {
2139 MOZ_ASSERT(result
.empty());
2141 if (!GetSymbolPropertyKeys(cx
, object
, result
, true)) {
2145 result
.eraseIf([](PropertyKey key
) {
2146 if (!key
.isPrivateName()) {
2149 // Private *methods* create a Private Brand, a special private name
2150 // stamped onto the symbol, to indicate it is possible to execute private
2151 // methods from the class on this object. We don't want to return such
2152 // items here, so we check if we're dealing with a private property, e.g.
2153 // the Symbol description starts with a "#" character.
2154 JSAtom
* privateDescription
= key
.toSymbol()->description();
2155 if (privateDescription
->length() == 0) {
2158 char16_t firstChar
= privateDescription
->latin1OrTwoByteChar(0);
2159 return firstChar
!= '#';
2162 for (size_t i
= 0; i
< result
.length(); i
++) {
2163 cx
->markAtom(result
[i
].toSymbol());
2170 bool DebuggerObject::getOwnPropertyDescriptor(
2171 JSContext
* cx
, Handle
<DebuggerObject
*> object
, HandleId id
,
2172 MutableHandle
<Maybe
<PropertyDescriptor
>> desc_
) {
2173 RootedObject
referent(cx
, object
->referent());
2174 Debugger
* dbg
= object
->owner();
2176 // Bug: This can cause the debuggee to run!
2178 Maybe
<AutoRealm
> ar
;
2179 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2184 if (!GetOwnPropertyDescriptor(cx
, referent
, id
, desc_
)) {
2189 if (desc_
.isSome()) {
2190 Rooted
<PropertyDescriptor
> desc(cx
, *desc_
);
2192 if (desc
.hasValue()) {
2193 // Rewrap the debuggee values in desc for the debugger.
2194 if (!dbg
->wrapDebuggeeValue(cx
, desc
.value())) {
2198 if (desc
.hasGetter()) {
2199 RootedValue
get(cx
, ObjectOrNullValue(desc
.getter()));
2200 if (!dbg
->wrapDebuggeeValue(cx
, &get
)) {
2203 desc
.setGetter(get
.toObjectOrNull());
2205 if (desc
.hasSetter()) {
2206 RootedValue
set(cx
, ObjectOrNullValue(desc
.setter()));
2207 if (!dbg
->wrapDebuggeeValue(cx
, &set
)) {
2210 desc
.setSetter(set
.toObjectOrNull());
2213 desc_
.set(mozilla::Some(desc
.get()));
2220 bool DebuggerObject::preventExtensions(JSContext
* cx
,
2221 Handle
<DebuggerObject
*> object
) {
2222 RootedObject
referent(cx
, object
->referent());
2224 Maybe
<AutoRealm
> ar
;
2225 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2228 return PreventExtensions(cx
, referent
);
2232 bool DebuggerObject::seal(JSContext
* cx
, Handle
<DebuggerObject
*> object
) {
2233 RootedObject
referent(cx
, object
->referent());
2235 Maybe
<AutoRealm
> ar
;
2236 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2239 return SetIntegrityLevel(cx
, referent
, IntegrityLevel::Sealed
);
2243 bool DebuggerObject::freeze(JSContext
* cx
, Handle
<DebuggerObject
*> object
) {
2244 RootedObject
referent(cx
, object
->referent());
2246 Maybe
<AutoRealm
> ar
;
2247 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2250 return SetIntegrityLevel(cx
, referent
, IntegrityLevel::Frozen
);
2254 bool DebuggerObject::defineProperty(JSContext
* cx
,
2255 Handle
<DebuggerObject
*> object
, HandleId id
,
2256 Handle
<PropertyDescriptor
> desc_
) {
2257 RootedObject
referent(cx
, object
->referent());
2258 Debugger
* dbg
= object
->owner();
2260 Rooted
<PropertyDescriptor
> desc(cx
, desc_
);
2261 if (!dbg
->unwrapPropertyDescriptor(cx
, referent
, &desc
)) {
2264 JS_TRY_OR_RETURN_FALSE(cx
, CheckPropertyDescriptorAccessors(cx
, desc
));
2266 Maybe
<AutoRealm
> ar
;
2267 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2269 if (!cx
->compartment()->wrap(cx
, &desc
)) {
2275 return DefineProperty(cx
, referent
, id
, desc
);
2279 bool DebuggerObject::defineProperties(JSContext
* cx
,
2280 Handle
<DebuggerObject
*> object
,
2281 Handle
<IdVector
> ids
,
2282 Handle
<PropertyDescriptorVector
> descs_
) {
2283 RootedObject
referent(cx
, object
->referent());
2284 Debugger
* dbg
= object
->owner();
2286 Rooted
<PropertyDescriptorVector
> descs(cx
, PropertyDescriptorVector(cx
));
2287 if (!descs
.append(descs_
.begin(), descs_
.end())) {
2290 for (size_t i
= 0; i
< descs
.length(); i
++) {
2291 if (!dbg
->unwrapPropertyDescriptor(cx
, referent
, descs
[i
])) {
2294 JS_TRY_OR_RETURN_FALSE(cx
, CheckPropertyDescriptorAccessors(cx
, descs
[i
]));
2297 Maybe
<AutoRealm
> ar
;
2298 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2300 for (size_t i
= 0; i
< descs
.length(); i
++) {
2301 if (!cx
->compartment()->wrap(cx
, descs
[i
])) {
2308 for (size_t i
= 0; i
< descs
.length(); i
++) {
2309 if (!DefineProperty(cx
, referent
, ids
[i
], descs
[i
])) {
2318 bool DebuggerObject::deleteProperty(JSContext
* cx
,
2319 Handle
<DebuggerObject
*> object
, HandleId id
,
2320 ObjectOpResult
& result
) {
2321 RootedObject
referent(cx
, object
->referent());
2323 Maybe
<AutoRealm
> ar
;
2324 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2329 return DeleteProperty(cx
, referent
, id
, result
);
2333 Result
<Completion
> DebuggerObject::getProperty(JSContext
* cx
,
2334 Handle
<DebuggerObject
*> object
,
2336 HandleValue receiver_
) {
2337 RootedObject
referent(cx
, object
->referent());
2338 Debugger
* dbg
= object
->owner();
2340 // Unwrap Debugger.Objects. This happens in the debugger's compartment since
2341 // that is where any exceptions must be reported.
2342 RootedValue
receiver(cx
, receiver_
);
2343 if (!dbg
->unwrapDebuggeeValue(cx
, &receiver
)) {
2344 return cx
->alreadyReportedError();
2347 // Enter the debuggee compartment and rewrap all input value for that
2348 // compartment. (Rewrapping always takes place in the destination
2350 Maybe
<AutoRealm
> ar
;
2351 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2352 if (!cx
->compartment()->wrap(cx
, &referent
) ||
2353 !cx
->compartment()->wrap(cx
, &receiver
)) {
2354 return cx
->alreadyReportedError();
2358 LeaveDebuggeeNoExecute
nnx(cx
);
2360 RootedValue
result(cx
);
2361 bool ok
= GetProperty(cx
, referent
, receiver
, id
, &result
);
2362 return Completion::fromJSResult(cx
, ok
, result
);
2366 Result
<Completion
> DebuggerObject::setProperty(JSContext
* cx
,
2367 Handle
<DebuggerObject
*> object
,
2368 HandleId id
, HandleValue value_
,
2369 HandleValue receiver_
) {
2370 RootedObject
referent(cx
, object
->referent());
2371 Debugger
* dbg
= object
->owner();
2373 // Unwrap Debugger.Objects. This happens in the debugger's compartment since
2374 // that is where any exceptions must be reported.
2375 RootedValue
value(cx
, value_
);
2376 RootedValue
receiver(cx
, receiver_
);
2377 if (!dbg
->unwrapDebuggeeValue(cx
, &value
) ||
2378 !dbg
->unwrapDebuggeeValue(cx
, &receiver
)) {
2379 return cx
->alreadyReportedError();
2382 // Enter the debuggee compartment and rewrap all input value for that
2383 // compartment. (Rewrapping always takes place in the destination
2385 Maybe
<AutoRealm
> ar
;
2386 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2387 if (!cx
->compartment()->wrap(cx
, &referent
) ||
2388 !cx
->compartment()->wrap(cx
, &value
) ||
2389 !cx
->compartment()->wrap(cx
, &receiver
)) {
2390 return cx
->alreadyReportedError();
2394 LeaveDebuggeeNoExecute
nnx(cx
);
2396 ObjectOpResult opResult
;
2397 bool ok
= SetProperty(cx
, referent
, id
, value
, receiver
, opResult
);
2399 return Completion::fromJSResult(cx
, ok
, BooleanValue(ok
&& opResult
.ok()));
2403 Maybe
<Completion
> DebuggerObject::call(JSContext
* cx
,
2404 Handle
<DebuggerObject
*> object
,
2406 Handle
<ValueVector
> args
) {
2407 RootedObject
referent(cx
, object
->referent());
2408 Debugger
* dbg
= object
->owner();
2410 if (!referent
->isCallable()) {
2411 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
2412 JSMSG_INCOMPATIBLE_PROTO
, "Debugger.Object",
2413 "call", referent
->getClass()->name
);
2417 RootedValue
calleev(cx
, ObjectValue(*referent
));
2419 // Unwrap Debugger.Objects. This happens in the debugger's compartment since
2420 // that is where any exceptions must be reported.
2421 RootedValue
thisv(cx
, thisv_
);
2422 if (!dbg
->unwrapDebuggeeValue(cx
, &thisv
)) {
2425 Rooted
<ValueVector
> args2(cx
, ValueVector(cx
));
2426 if (!args2
.append(args
.begin(), args
.end())) {
2429 for (size_t i
= 0; i
< args2
.length(); ++i
) {
2430 if (!dbg
->unwrapDebuggeeValue(cx
, args2
[i
])) {
2435 // Enter the debuggee compartment and rewrap all input value for that
2436 // compartment. (Rewrapping always takes place in the destination
2438 Maybe
<AutoRealm
> ar
;
2439 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2440 if (!cx
->compartment()->wrap(cx
, &calleev
) ||
2441 !cx
->compartment()->wrap(cx
, &thisv
)) {
2444 for (size_t i
= 0; i
< args2
.length(); ++i
) {
2445 if (!cx
->compartment()->wrap(cx
, args2
[i
])) {
2450 // Note whether we are in an evaluation that might invoke the OnNativeCall
2451 // hook, so that the JITs will be disabled.
2452 Maybe
<AutoNoteExclusiveDebuggerOnEval
> noteEvaluation
;
2453 if (dbg
->isExclusiveDebuggerOnEval()) {
2454 noteEvaluation
.emplace(cx
, dbg
);
2457 // Call the function.
2458 LeaveDebuggeeNoExecute
nnx(cx
);
2460 RootedValue
result(cx
);
2463 InvokeArgs
invokeArgs(cx
);
2465 ok
= invokeArgs
.init(cx
, args2
.length());
2467 for (size_t i
= 0; i
< args2
.length(); ++i
) {
2468 invokeArgs
[i
].set(args2
[i
]);
2471 ok
= js::Call(cx
, calleev
, thisv
, invokeArgs
, &result
);
2475 Rooted
<Completion
> completion(cx
, Completion::fromJSResult(cx
, ok
, result
));
2477 return Some(std::move(completion
.get()));
2481 bool DebuggerObject::forceLexicalInitializationByName(
2482 JSContext
* cx
, Handle
<DebuggerObject
*> object
, HandleId id
, bool& result
) {
2483 if (!id
.isString()) {
2484 JS_ReportErrorNumberASCII(
2485 cx
, GetErrorMessage
, nullptr, JSMSG_NOT_EXPECTED_TYPE
,
2486 "Debugger.Object.prototype.forceLexicalInitializationByName", "string",
2487 InformalValueTypeName(IdToValue(id
)));
2491 MOZ_ASSERT(object
->isGlobal());
2493 Rooted
<GlobalObject
*> referent(cx
, &object
->referent()->as
<GlobalObject
>());
2495 // Shape::search can end up allocating a new BaseShape in Shape::cachify so
2496 // we need to be in the right compartment here.
2497 Maybe
<AutoRealm
> ar
;
2498 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2500 RootedObject
globalLexical(cx
, &referent
->lexicalEnvironment());
2501 RootedObject
pobj(cx
);
2502 PropertyResult prop
;
2503 if (!LookupProperty(cx
, globalLexical
, id
, &pobj
, &prop
)) {
2508 if (prop
.isFound()) {
2509 MOZ_ASSERT(prop
.isNativeProperty());
2510 PropertyInfo propInfo
= prop
.propertyInfo();
2511 Value v
= globalLexical
->as
<NativeObject
>().getSlot(propInfo
.slot());
2512 if (propInfo
.isDataProperty() && v
.isMagic() &&
2513 v
.whyMagic() == JS_UNINITIALIZED_LEXICAL
) {
2514 globalLexical
->as
<NativeObject
>().setSlot(propInfo
.slot(),
2524 Result
<Completion
> DebuggerObject::executeInGlobal(
2525 JSContext
* cx
, Handle
<DebuggerObject
*> object
,
2526 mozilla::Range
<const char16_t
> chars
, HandleObject bindings
,
2527 const EvalOptions
& options
) {
2528 MOZ_ASSERT(object
->isGlobal());
2530 Rooted
<GlobalObject
*> referent(cx
, &object
->referent()->as
<GlobalObject
>());
2531 Debugger
* dbg
= object
->owner();
2533 RootedObject
globalLexical(cx
, &referent
->lexicalEnvironment());
2534 return DebuggerGenericEval(cx
, chars
, bindings
, options
, dbg
, globalLexical
,
2539 bool DebuggerObject::makeDebuggeeValue(JSContext
* cx
,
2540 Handle
<DebuggerObject
*> object
,
2542 MutableHandleValue result
) {
2543 RootedObject
referent(cx
, object
->referent());
2544 Debugger
* dbg
= object
->owner();
2546 RootedValue
value(cx
, value_
);
2548 // Non-objects are already debuggee values.
2549 if (value
.isObject()) {
2550 // Enter this Debugger.Object's referent's compartment, and wrap the
2551 // argument as appropriate for references from there.
2553 Maybe
<AutoRealm
> ar
;
2554 EnterDebuggeeObjectRealm(cx
, ar
, referent
);
2555 if (!cx
->compartment()->wrap(cx
, &value
)) {
2560 // Back in the debugger's compartment, produce a new Debugger.Object
2561 // instance referring to the wrapped argument.
2562 if (!dbg
->wrapDebuggeeValue(cx
, &value
)) {
2571 static JSFunction
* EnsureNativeFunction(const Value
& value
) {
2572 if (!value
.isObject() || !value
.toObject().is
<JSFunction
>()) {
2576 JSFunction
* fun
= &value
.toObject().as
<JSFunction
>();
2577 if (!fun
->isNativeFun()) {
2584 static JSAtom
* MaybeGetSelfHostedFunctionName(const Value
& v
) {
2585 if (!v
.isObject() || !v
.toObject().is
<JSFunction
>()) {
2589 JSFunction
* fun
= &v
.toObject().as
<JSFunction
>();
2590 if (!fun
->isSelfHostedBuiltin()) {
2594 return GetClonedSelfHostedFunctionName(fun
);
2597 static bool IsSameNative(JSFunction
* a
, JSFunction
* b
,
2598 DebuggerObject::CheckJitInfo checkJitInfo
) {
2599 if (a
->native() != b
->native()) {
2603 if (checkJitInfo
== DebuggerObject::CheckJitInfo::No
) {
2607 // Both function should agree with the existence of JitInfo.
2609 if (a
->hasJitInfo() != b
->hasJitInfo()) {
2613 if (!a
->hasJitInfo()) {
2617 if (a
->jitInfo() == b
->jitInfo()) {
2625 bool DebuggerObject::isSameNative(JSContext
* cx
, Handle
<DebuggerObject
*> object
,
2626 HandleValue value
, CheckJitInfo checkJitInfo
,
2627 MutableHandleValue result
) {
2628 RootedValue
referentValue(cx
, ObjectValue(*object
->referent()));
2630 RootedValue
nonCCWValue(
2631 cx
, value
.isObject() ? ObjectValue(*UncheckedUnwrap(&value
.toObject()))
2634 RootedFunction
fun(cx
, EnsureNativeFunction(nonCCWValue
));
2636 Rooted
<JSAtom
*> selfHostedName(cx
,
2637 MaybeGetSelfHostedFunctionName(nonCCWValue
));
2638 if (!selfHostedName
) {
2639 JS_ReportErrorASCII(cx
, "Need native function");
2643 result
.setBoolean(selfHostedName
==
2644 MaybeGetSelfHostedFunctionName(referentValue
));
2648 RootedFunction
referentFun(cx
, EnsureNativeFunction(referentValue
));
2650 result
.setBoolean(referentFun
&&
2651 IsSameNative(referentFun
, fun
, checkJitInfo
));
2655 static bool IsNativeGetterWithJitInfo(JSFunction
* fun
) {
2656 return fun
->isNativeFun() && fun
->hasJitInfo() &&
2657 fun
->jitInfo()->type() == JSJitInfo::Getter
;
2661 bool DebuggerObject::isNativeGetterWithJitInfo(JSContext
* cx
,
2662 Handle
<DebuggerObject
*> object
,
2663 MutableHandleValue result
) {
2664 RootedValue
referentValue(cx
, ObjectValue(*object
->referent()));
2665 RootedFunction
referentFun(cx
, EnsureNativeFunction(referentValue
));
2666 result
.setBoolean(referentFun
&& IsNativeGetterWithJitInfo(referentFun
));
2671 bool DebuggerObject::unsafeDereference(JSContext
* cx
,
2672 Handle
<DebuggerObject
*> object
,
2673 MutableHandleObject result
) {
2674 RootedObject
referent(cx
, object
->referent());
2676 if (!cx
->compartment()->wrap(cx
, &referent
)) {
2680 // Wrapping should return the WindowProxy.
2681 MOZ_ASSERT(!IsWindow(referent
));
2683 result
.set(referent
);
2688 bool DebuggerObject::unwrap(JSContext
* cx
, Handle
<DebuggerObject
*> object
,
2689 MutableHandle
<DebuggerObject
*> result
) {
2690 RootedObject
referent(cx
, object
->referent());
2691 Debugger
* dbg
= object
->owner();
2693 RootedObject
unwrapped(cx
, UnwrapOneCheckedStatic(referent
));
2695 // Don't allow unwrapping to create a D.O whose referent is in an
2696 // invisible-to-Debugger compartment. (If our referent is a *wrapper* to such,
2697 // and the wrapper is in a visible compartment, that's fine.)
2698 if (unwrapped
&& unwrapped
->compartment()->invisibleToDebugger()) {
2699 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
2700 JSMSG_DEBUG_INVISIBLE_COMPARTMENT
);
2704 return dbg
->wrapNullableDebuggeeObject(cx
, unwrapped
, result
);
2708 bool DebuggerObject::requireGlobal(JSContext
* cx
,
2709 Handle
<DebuggerObject
*> object
) {
2710 if (!object
->isGlobal()) {
2711 RootedObject
referent(cx
, object
->referent());
2713 const char* isWrapper
= "";
2714 const char* isWindowProxy
= "";
2716 // Help the poor programmer by pointing out wrappers around globals...
2717 if (referent
->is
<WrapperObject
>()) {
2718 referent
= js::UncheckedUnwrap(referent
);
2719 isWrapper
= "a wrapper around ";
2722 // ... and WindowProxies around Windows.
2723 if (IsWindowProxy(referent
)) {
2724 referent
= ToWindowIfWindowProxy(referent
);
2725 isWindowProxy
= "a WindowProxy referring to ";
2728 RootedValue
dbgobj(cx
, ObjectValue(*object
));
2729 if (referent
->is
<GlobalObject
>()) {
2730 ReportValueError(cx
, JSMSG_DEBUG_WRAPPER_IN_WAY
, JSDVG_SEARCH_STACK
,
2731 dbgobj
, nullptr, isWrapper
, isWindowProxy
);
2733 ReportValueError(cx
, JSMSG_DEBUG_BAD_REFERENT
, JSDVG_SEARCH_STACK
, dbgobj
,
2734 nullptr, "a global object");
2743 bool DebuggerObject::requirePromise(JSContext
* cx
,
2744 Handle
<DebuggerObject
*> object
) {
2745 RootedObject
referent(cx
, object
->referent());
2747 if (IsCrossCompartmentWrapper(referent
)) {
2748 /* We only care about promises, so CheckedUnwrapStatic is OK. */
2749 referent
= CheckedUnwrapStatic(referent
);
2751 ReportAccessDenied(cx
);
2756 if (!referent
->is
<PromiseObject
>()) {
2757 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
2758 JSMSG_NOT_EXPECTED_TYPE
, "Debugger", "Promise",
2759 object
->getClass()->name
);
2767 bool DebuggerObject::getScriptedProxyTarget(
2768 JSContext
* cx
, Handle
<DebuggerObject
*> object
,
2769 MutableHandle
<DebuggerObject
*> result
) {
2770 MOZ_ASSERT(object
->isScriptedProxy());
2771 RootedObject
referent(cx
, object
->referent());
2772 Debugger
* dbg
= object
->owner();
2773 RootedObject
unwrapped(cx
, js::GetProxyTargetObject(referent
));
2775 return dbg
->wrapNullableDebuggeeObject(cx
, unwrapped
, result
);
2779 bool DebuggerObject::getScriptedProxyHandler(
2780 JSContext
* cx
, Handle
<DebuggerObject
*> object
,
2781 MutableHandle
<DebuggerObject
*> result
) {
2782 MOZ_ASSERT(object
->isScriptedProxy());
2783 RootedObject
referent(cx
, object
->referent());
2784 Debugger
* dbg
= object
->owner();
2785 RootedObject
unwrapped(cx
, ScriptedProxyHandler::handlerObject(referent
));
2786 return dbg
->wrapNullableDebuggeeObject(cx
, unwrapped
, result
);