Source code

Revision control

Other Tools

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 <type_traits> // for remove_reference<>::type
17
#include <utility> // for move
18
19
#include "jsapi.h" // for CallArgs, RootedObject, Rooted
20
#include "jsfriendapi.h" // for GetErrorMessage
21
22
#include "builtin/Array.h" // for NewDenseCopiedArray
23
#include "debugger/Debugger.h" // for Completion, Debugger
24
#include "debugger/NoExecute.h" // for LeaveDebuggeeNoExecute
25
#include "debugger/Script.h" // for DebuggerScript
26
#include "debugger/Source.h" // for DebuggerSource
27
#include "gc/Barrier.h" // for ImmutablePropertyNamePtr
28
#include "gc/Rooting.h" // for RootedDebuggerObject
29
#include "gc/Tracer.h" // for TraceManuallyBarrieredCrossCompartmentEdge
30
#include "js/CompilationAndEvaluation.h" // for Compile
31
#include "js/Conversions.h" // for ToObject
32
#include "js/HeapAPI.h" // for IsInsideNursery
33
#include "js/Promise.h" // for PromiseState
34
#include "js/Proxy.h" // for PropertyDescriptor
35
#include "js/StableStringChars.h" // for AutoStableStringChars
36
#include "proxy/ScriptedProxyHandler.h" // for ScriptedProxyHandler
37
#include "vm/ArgumentsObject.h" // for ARGS_LENGTH_MAX
38
#include "vm/ArrayObject.h" // for ArrayObject
39
#include "vm/BytecodeUtil.h" // for JSDVG_SEARCH_STACK
40
#include "vm/Compartment.h" // for Compartment
41
#include "vm/EnvironmentObject.h" // for GetDebugEnvironmentForFunction
42
#include "vm/ErrorObject.h" // for JSObject::is, ErrorObject
43
#include "vm/GlobalObject.h" // for JSObject::is, GlobalObject
44
#include "vm/Instrumentation.h" // for RealmInstrumentation
45
#include "vm/Interpreter.h" // for Call
46
#include "vm/JSAtom.h" // for Atomize, js_apply_str
47
#include "vm/JSContext.h" // for JSContext, ReportValueError
48
#include "vm/JSFunction.h" // for JSFunction
49
#include "vm/JSScript.h" // for JSScript
50
#include "vm/NativeObject.h" // for NativeObject, JSObject::is
51
#include "vm/ObjectGroup.h" // for GenericObject, NewObjectKind
52
#include "vm/ObjectOperations.h" // for DefineProperty
53
#include "vm/Realm.h" // for AutoRealm, ErrorCopier, Realm
54
#include "vm/Runtime.h" // for JSAtomState
55
#include "vm/SavedFrame.h" // for SavedFrame
56
#include "vm/Scope.h" // for PositionalFormalParameterIter
57
#include "vm/SelfHosting.h" // for GetClonedSelfHostedFunctionName
58
#include "vm/Shape.h" // for Shape
59
#include "vm/Stack.h" // for InvokeArgs
60
#include "vm/StringType.h" // for JSAtom, PropertyName
61
#include "vm/WrapperObject.h" // for JSObject::is, WrapperObject
62
63
#include "vm/Compartment-inl.h" // for Compartment::wrap
64
#include "vm/JSAtom-inl.h" // for ValueToId
65
#include "vm/JSObject-inl.h" // for GetObjectClassName, InitClass
66
#include "vm/NativeObject-inl.h" // for NativeObject::global
67
#include "vm/ObjectOperations-inl.h" // for DeleteProperty, GetProperty
68
#include "vm/Realm-inl.h" // for AutoRealm::AutoRealm
69
70
using namespace js;
71
72
using JS::AutoStableStringChars;
73
using mozilla::Maybe;
74
using mozilla::Nothing;
75
using mozilla::Some;
76
77
const JSClassOps DebuggerObject::classOps_ = {
78
nullptr, /* addProperty */
79
nullptr, /* delProperty */
80
nullptr, /* enumerate */
81
nullptr, /* newEnumerate */
82
nullptr, /* resolve */
83
nullptr, /* mayResolve */
84
nullptr, /* finalize */
85
nullptr, /* call */
86
nullptr, /* hasInstance */
87
nullptr, /* construct */
88
CallTraceMethod<DebuggerObject>, /* trace */
89
};
90
91
const JSClass DebuggerObject::class_ = {
92
"Object", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
93
&classOps_};
94
95
void DebuggerObject::trace(JSTracer* trc) {
96
// There is a barrier on private pointers, so the Unbarriered marking
97
// is okay.
98
if (JSObject* referent = (JSObject*)getPrivate()) {
99
TraceManuallyBarrieredCrossCompartmentEdge(
100
trc, static_cast<JSObject*>(this), &referent,
101
"Debugger.Object referent");
102
setPrivateUnbarriered(referent);
103
}
104
}
105
106
static DebuggerObject* DebuggerObject_checkThis(JSContext* cx,
107
const CallArgs& args) {
108
JSObject* thisobj = RequireObject(cx, args.thisv());
109
if (!thisobj) {
110
return nullptr;
111
}
112
if (thisobj->getClass() != &DebuggerObject::class_) {
113
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
114
JSMSG_INCOMPATIBLE_PROTO, "Debugger.Object",
115
"method", thisobj->getClass()->name);
116
return nullptr;
117
}
118
119
// Forbid Debugger.Object.prototype, which is of class DebuggerObject::class_
120
// but isn't a real working Debugger.Object. The prototype object is
121
// distinguished by having no referent.
122
DebuggerObject* nthisobj = &thisobj->as<DebuggerObject>();
123
if (!nthisobj->getPrivate()) {
124
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
125
JSMSG_INCOMPATIBLE_PROTO, "Debugger.Object",
126
"method", "prototype object");
127
return nullptr;
128
}
129
return nthisobj;
130
}
131
132
/* static */
133
bool DebuggerObject::construct(JSContext* cx, unsigned argc, Value* vp) {
134
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
135
"Debugger.Object");
136
return false;
137
}
138
139
struct MOZ_STACK_CLASS DebuggerObject::CallData {
140
JSContext* cx;
141
const CallArgs& args;
142
143
HandleDebuggerObject object;
144
RootedObject referent;
145
146
CallData(JSContext* cx, const CallArgs& args, HandleDebuggerObject obj)
147
: cx(cx), args(args), object(obj), referent(cx, obj->referent()) {}
148
149
// JSNative properties
150
bool callableGetter();
151
bool isBoundFunctionGetter();
152
bool isArrowFunctionGetter();
153
bool isAsyncFunctionGetter();
154
bool isClassConstructorGetter();
155
bool isGeneratorFunctionGetter();
156
bool protoGetter();
157
bool classGetter();
158
bool nameGetter();
159
bool displayNameGetter();
160
bool parameterNamesGetter();
161
bool scriptGetter();
162
bool environmentGetter();
163
bool boundTargetFunctionGetter();
164
bool boundThisGetter();
165
bool boundArgumentsGetter();
166
bool allocationSiteGetter();
167
bool errorMessageNameGetter();
168
bool errorNotesGetter();
169
bool errorLineNumberGetter();
170
bool errorColumnNumberGetter();
171
bool isProxyGetter();
172
bool proxyTargetGetter();
173
bool proxyHandlerGetter();
174
bool isPromiseGetter();
175
bool promiseStateGetter();
176
bool promiseValueGetter();
177
bool promiseReasonGetter();
178
bool promiseLifetimeGetter();
179
bool promiseTimeToResolutionGetter();
180
bool promiseAllocationSiteGetter();
181
bool promiseResolutionSiteGetter();
182
bool promiseIDGetter();
183
bool promiseDependentPromisesGetter();
184
185
// JSNative methods
186
bool isExtensibleMethod();
187
bool isSealedMethod();
188
bool isFrozenMethod();
189
bool getPropertyMethod();
190
bool setPropertyMethod();
191
bool getOwnPropertyNamesMethod();
192
bool getOwnPropertySymbolsMethod();
193
bool getOwnPropertyDescriptorMethod();
194
bool preventExtensionsMethod();
195
bool sealMethod();
196
bool freezeMethod();
197
bool definePropertyMethod();
198
bool definePropertiesMethod();
199
bool deletePropertyMethod();
200
bool callMethod();
201
bool applyMethod();
202
bool asEnvironmentMethod();
203
bool forceLexicalInitializationByNameMethod();
204
bool executeInGlobalMethod();
205
bool executeInGlobalWithBindingsMethod();
206
bool createSource();
207
bool makeDebuggeeValueMethod();
208
bool makeDebuggeeNativeFunctionMethod();
209
bool isSameNativeMethod();
210
bool unsafeDereferenceMethod();
211
bool unwrapMethod();
212
bool setInstrumentationMethod();
213
bool setInstrumentationActiveMethod();
214
215
using Method = bool (CallData::*)();
216
217
template <Method MyMethod>
218
static bool ToNative(JSContext* cx, unsigned argc, Value* vp);
219
};
220
221
template <DebuggerObject::CallData::Method MyMethod>
222
/* static */
223
bool DebuggerObject::CallData::ToNative(JSContext* cx, unsigned argc,
224
Value* vp) {
225
CallArgs args = CallArgsFromVp(argc, vp);
226
227
RootedDebuggerObject obj(cx, DebuggerObject_checkThis(cx, args));
228
if (!obj) {
229
return false;
230
}
231
232
CallData data(cx, args, obj);
233
return (data.*MyMethod)();
234
}
235
236
bool DebuggerObject::CallData::callableGetter() {
237
args.rval().setBoolean(object->isCallable());
238
return true;
239
}
240
241
bool DebuggerObject::CallData::isBoundFunctionGetter() {
242
if (!object->isDebuggeeFunction()) {
243
args.rval().setUndefined();
244
return true;
245
}
246
247
args.rval().setBoolean(object->isBoundFunction());
248
return true;
249
}
250
251
bool DebuggerObject::CallData::isArrowFunctionGetter() {
252
if (!object->isDebuggeeFunction()) {
253
args.rval().setUndefined();
254
return true;
255
}
256
257
args.rval().setBoolean(object->isArrowFunction());
258
return true;
259
}
260
261
bool DebuggerObject::CallData::isAsyncFunctionGetter() {
262
if (!object->isDebuggeeFunction()) {
263
args.rval().setUndefined();
264
return true;
265
}
266
267
args.rval().setBoolean(object->isAsyncFunction());
268
return true;
269
}
270
271
bool DebuggerObject::CallData::isGeneratorFunctionGetter() {
272
if (!object->isDebuggeeFunction()) {
273
args.rval().setUndefined();
274
return true;
275
}
276
277
args.rval().setBoolean(object->isGeneratorFunction());
278
return true;
279
}
280
281
bool DebuggerObject::CallData::isClassConstructorGetter() {
282
if (!object->isDebuggeeFunction()) {
283
args.rval().setUndefined();
284
return true;
285
}
286
287
args.rval().setBoolean(object->isClassConstructor());
288
return true;
289
}
290
291
bool DebuggerObject::CallData::protoGetter() {
292
RootedDebuggerObject result(cx);
293
if (!DebuggerObject::getPrototypeOf(cx, object, &result)) {
294
return false;
295
}
296
297
args.rval().setObjectOrNull(result);
298
return true;
299
}
300
301
bool DebuggerObject::CallData::classGetter() {
302
RootedString result(cx);
303
if (!DebuggerObject::getClassName(cx, object, &result)) {
304
return false;
305
}
306
307
args.rval().setString(result);
308
return true;
309
}
310
311
bool DebuggerObject::CallData::nameGetter() {
312
if (!object->isFunction()) {
313
args.rval().setUndefined();
314
return true;
315
}
316
317
RootedString result(cx, object->name(cx));
318
if (result) {
319
args.rval().setString(result);
320
} else {
321
args.rval().setUndefined();
322
}
323
return true;
324
}
325
326
bool DebuggerObject::CallData::displayNameGetter() {
327
if (!object->isFunction()) {
328
args.rval().setUndefined();
329
return true;
330
}
331
332
RootedString result(cx, object->displayName(cx));
333
if (result) {
334
args.rval().setString(result);
335
} else {
336
args.rval().setUndefined();
337
}
338
return true;
339
}
340
341
bool DebuggerObject::CallData::parameterNamesGetter() {
342
if (!object->isDebuggeeFunction()) {
343
args.rval().setUndefined();
344
return true;
345
}
346
347
Rooted<StringVector> names(cx, StringVector(cx));
348
if (!DebuggerObject::getParameterNames(cx, object, &names)) {
349
return false;
350
}
351
352
RootedArrayObject obj(cx, NewDenseFullyAllocatedArray(cx, names.length()));
353
if (!obj) {
354
return false;
355
}
356
357
obj->ensureDenseInitializedLength(cx, 0, names.length());
358
for (size_t i = 0; i < names.length(); ++i) {
359
Value v;
360
if (names[i]) {
361
v = StringValue(names[i]);
362
} else {
363
v = UndefinedValue();
364
}
365
obj->setDenseElement(i, v);
366
}
367
368
args.rval().setObject(*obj);
369
return true;
370
}
371
372
bool DebuggerObject::CallData::scriptGetter() {
373
Debugger* dbg = Debugger::fromChildJSObject(object);
374
375
if (!referent->is<JSFunction>()) {
376
args.rval().setUndefined();
377
return true;
378
}
379
380
RootedFunction fun(cx, &referent->as<JSFunction>());
381
if (!IsInterpretedNonSelfHostedFunction(fun)) {
382
args.rval().setUndefined();
383
return true;
384
}
385
386
RootedScript script(cx, GetOrCreateFunctionScript(cx, fun));
387
if (!script) {
388
return false;
389
}
390
391
// Only hand out debuggee scripts.
392
if (!dbg->observesScript(script)) {
393
args.rval().setNull();
394
return true;
395
}
396
397
RootedDebuggerScript scriptObject(cx, dbg->wrapScript(cx, script));
398
if (!scriptObject) {
399
return false;
400
}
401
402
args.rval().setObject(*scriptObject);
403
return true;
404
}
405
406
bool DebuggerObject::CallData::environmentGetter() {
407
Debugger* dbg = Debugger::fromChildJSObject(object);
408
409
// Don't bother switching compartments just to check obj's type and get its
410
// env.
411
if (!referent->is<JSFunction>()) {
412
args.rval().setUndefined();
413
return true;
414
}
415
416
RootedFunction fun(cx, &referent->as<JSFunction>());
417
if (!IsInterpretedNonSelfHostedFunction(fun)) {
418
args.rval().setUndefined();
419
return true;
420
}
421
422
// Only hand out environments of debuggee functions.
423
if (!dbg->observesGlobal(&fun->global())) {
424
args.rval().setNull();
425
return true;
426
}
427
428
Rooted<Env*> env(cx);
429
{
430
AutoRealm ar(cx, fun);
431
env = GetDebugEnvironmentForFunction(cx, fun);
432
if (!env) {
433
return false;
434
}
435
}
436
437
return dbg->wrapEnvironment(cx, env, args.rval());
438
}
439
440
bool DebuggerObject::CallData::boundTargetFunctionGetter() {
441
if (!object->isDebuggeeFunction() || !object->isBoundFunction()) {
442
args.rval().setUndefined();
443
return true;
444
}
445
446
RootedDebuggerObject result(cx);
447
if (!DebuggerObject::getBoundTargetFunction(cx, object, &result)) {
448
return false;
449
}
450
451
args.rval().setObject(*result);
452
return true;
453
}
454
455
bool DebuggerObject::CallData::boundThisGetter() {
456
if (!object->isDebuggeeFunction() || !object->isBoundFunction()) {
457
args.rval().setUndefined();
458
return true;
459
}
460
461
return DebuggerObject::getBoundThis(cx, object, args.rval());
462
}
463
464
bool DebuggerObject::CallData::boundArgumentsGetter() {
465
if (!object->isDebuggeeFunction() || !object->isBoundFunction()) {
466
args.rval().setUndefined();
467
return true;
468
}
469
470
Rooted<ValueVector> result(cx, ValueVector(cx));
471
if (!DebuggerObject::getBoundArguments(cx, object, &result)) {
472
return false;
473
}
474
475
RootedObject obj(cx,
476
NewDenseCopiedArray(cx, result.length(), result.begin()));
477
if (!obj) {
478
return false;
479
}
480
481
args.rval().setObject(*obj);
482
return true;
483
}
484
485
bool DebuggerObject::CallData::allocationSiteGetter() {
486
RootedObject result(cx);
487
if (!DebuggerObject::getAllocationSite(cx, object, &result)) {
488
return false;
489
}
490
491
args.rval().setObjectOrNull(result);
492
return true;
493
}
494
495
// Returns the "name" field (see js.msg), which may be used as a unique
496
// identifier, for any error object with a JSErrorReport or undefined
497
// if the object has no JSErrorReport.
498
bool DebuggerObject::CallData::errorMessageNameGetter() {
499
RootedString result(cx);
500
if (!DebuggerObject::getErrorMessageName(cx, object, &result)) {
501
return false;
502
}
503
504
if (result) {
505
args.rval().setString(result);
506
} else {
507
args.rval().setUndefined();
508
}
509
return true;
510
}
511
512
bool DebuggerObject::CallData::errorNotesGetter() {
513
return DebuggerObject::getErrorNotes(cx, object, args.rval());
514
}
515
516
bool DebuggerObject::CallData::errorLineNumberGetter() {
517
return DebuggerObject::getErrorLineNumber(cx, object, args.rval());
518
}
519
520
bool DebuggerObject::CallData::errorColumnNumberGetter() {
521
return DebuggerObject::getErrorColumnNumber(cx, object, args.rval());
522
}
523
524
bool DebuggerObject::CallData::isProxyGetter() {
525
args.rval().setBoolean(object->isScriptedProxy());
526
return true;
527
}
528
529
bool DebuggerObject::CallData::proxyTargetGetter() {
530
if (!object->isScriptedProxy()) {
531
args.rval().setUndefined();
532
return true;
533
}
534
535
Rooted<DebuggerObject*> result(cx);
536
if (!DebuggerObject::getScriptedProxyTarget(cx, object, &result)) {
537
return false;
538
}
539
540
args.rval().setObjectOrNull(result);
541
return true;
542
}
543
544
bool DebuggerObject::CallData::proxyHandlerGetter() {
545
if (!object->isScriptedProxy()) {
546
args.rval().setUndefined();
547
return true;
548
}
549
Rooted<DebuggerObject*> result(cx);
550
if (!DebuggerObject::getScriptedProxyHandler(cx, object, &result)) {
551
return false;
552
}
553
554
args.rval().setObjectOrNull(result);
555
return true;
556
}
557
558
bool DebuggerObject::CallData::isPromiseGetter() {
559
args.rval().setBoolean(object->isPromise());
560
return true;
561
}
562
563
bool DebuggerObject::CallData::promiseStateGetter() {
564
if (!DebuggerObject::requirePromise(cx, object)) {
565
return false;
566
}
567
568
RootedValue result(cx);
569
switch (object->promiseState()) {
570
case JS::PromiseState::Pending:
571
result.setString(cx->names().pending);
572
break;
573
case JS::PromiseState::Fulfilled:
574
result.setString(cx->names().fulfilled);
575
break;
576
case JS::PromiseState::Rejected:
577
result.setString(cx->names().rejected);
578
break;
579
}
580
581
args.rval().set(result);
582
return true;
583
}
584
585
bool DebuggerObject::CallData::promiseValueGetter() {
586
if (!DebuggerObject::requirePromise(cx, object)) {
587
return false;
588
}
589
590
if (object->promiseState() != JS::PromiseState::Fulfilled) {
591
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
592
JSMSG_DEBUG_PROMISE_NOT_FULFILLED);
593
return false;
594
}
595
596
return DebuggerObject::getPromiseValue(cx, object, args.rval());
597
;
598
}
599
600
bool DebuggerObject::CallData::promiseReasonGetter() {
601
if (!DebuggerObject::requirePromise(cx, object)) {
602
return false;
603
}
604
605
if (object->promiseState() != JS::PromiseState::Rejected) {
606
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
607
JSMSG_DEBUG_PROMISE_NOT_REJECTED);
608
return false;
609
}
610
611
return DebuggerObject::getPromiseReason(cx, object, args.rval());
612
}
613
614
bool DebuggerObject::CallData::promiseLifetimeGetter() {
615
if (!DebuggerObject::requirePromise(cx, object)) {
616
return false;
617
}
618
619
args.rval().setNumber(object->promiseLifetime());
620
return true;
621
}
622
623
bool DebuggerObject::CallData::promiseTimeToResolutionGetter() {
624
if (!DebuggerObject::requirePromise(cx, object)) {
625
return false;
626
}
627
628
if (object->promiseState() == JS::PromiseState::Pending) {
629
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
630
JSMSG_DEBUG_PROMISE_NOT_RESOLVED);
631
return false;
632
}
633
634
args.rval().setNumber(object->promiseTimeToResolution());
635
return true;
636
}
637
638
static PromiseObject* EnsurePromise(JSContext* cx, HandleObject referent) {
639
// We only care about promises, so CheckedUnwrapStatic is OK.
640
RootedObject obj(cx, CheckedUnwrapStatic(referent));
641
if (!obj) {
642
ReportAccessDenied(cx);
643
return nullptr;
644
}
645
if (!obj->is<PromiseObject>()) {
646
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
647
JSMSG_NOT_EXPECTED_TYPE, "Debugger", "Promise",
648
obj->getClass()->name);
649
return nullptr;
650
}
651
return &obj->as<PromiseObject>();
652
}
653
654
bool DebuggerObject::CallData::promiseAllocationSiteGetter() {
655
Rooted<PromiseObject*> promise(cx, EnsurePromise(cx, referent));
656
if (!promise) {
657
return false;
658
}
659
660
RootedObject allocSite(cx, promise->allocationSite());
661
if (!allocSite) {
662
args.rval().setNull();
663
return true;
664
}
665
666
if (!cx->compartment()->wrap(cx, &allocSite)) {
667
return false;
668
}
669
args.rval().set(ObjectValue(*allocSite));
670
return true;
671
}
672
673
bool DebuggerObject::CallData::promiseResolutionSiteGetter() {
674
Rooted<PromiseObject*> promise(cx, EnsurePromise(cx, referent));
675
if (!promise) {
676
return false;
677
}
678
679
if (promise->state() == JS::PromiseState::Pending) {
680
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
681
JSMSG_DEBUG_PROMISE_NOT_RESOLVED);
682
return false;
683
}
684
685
RootedObject resolutionSite(cx, promise->resolutionSite());
686
if (!resolutionSite) {
687
args.rval().setNull();
688
return true;
689
}
690
691
if (!cx->compartment()->wrap(cx, &resolutionSite)) {
692
return false;
693
}
694
args.rval().set(ObjectValue(*resolutionSite));
695
return true;
696
}
697
698
bool DebuggerObject::CallData::promiseIDGetter() {
699
Rooted<PromiseObject*> promise(cx, EnsurePromise(cx, referent));
700
if (!promise) {
701
return false;
702
}
703
704
args.rval().setNumber(double(promise->getID()));
705
return true;
706
}
707
708
bool DebuggerObject::CallData::promiseDependentPromisesGetter() {
709
Debugger* dbg = Debugger::fromChildJSObject(object);
710
711
Rooted<PromiseObject*> promise(cx, EnsurePromise(cx, referent));
712
if (!promise) {
713
return false;
714
}
715
716
Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
717
{
718
JSAutoRealm ar(cx, promise);
719
if (!promise->dependentPromises(cx, &values)) {
720
return false;
721
}
722
}
723
for (size_t i = 0; i < values.length(); i++) {
724
if (!dbg->wrapDebuggeeValue(cx, values[i])) {
725
return false;
726
}
727
}
728
RootedArrayObject promises(cx);
729
if (values.length() == 0) {
730
promises = NewDenseEmptyArray(cx);
731
} else {
732
promises = NewDenseCopiedArray(cx, values.length(), values[0].address());
733
}
734
if (!promises) {
735
return false;
736
}
737
args.rval().setObject(*promises);
738
return true;
739
}
740
741
bool DebuggerObject::CallData::isExtensibleMethod() {
742
bool result;
743
if (!DebuggerObject::isExtensible(cx, object, result)) {
744
return false;
745
}
746
747
args.rval().setBoolean(result);
748
return true;
749
}
750
751
bool DebuggerObject::CallData::isSealedMethod() {
752
bool result;
753
if (!DebuggerObject::isSealed(cx, object, result)) {
754
return false;
755
}
756
757
args.rval().setBoolean(result);
758
return true;
759
}
760
761
bool DebuggerObject::CallData::isFrozenMethod() {
762
bool result;
763
if (!DebuggerObject::isFrozen(cx, object, result)) {
764
return false;
765
}
766
767
args.rval().setBoolean(result);
768
return true;
769
}
770
771
bool DebuggerObject::CallData::getOwnPropertyNamesMethod() {
772
Rooted<IdVector> ids(cx, IdVector(cx));
773
if (!DebuggerObject::getOwnPropertyNames(cx, object, &ids)) {
774
return false;
775
}
776
777
RootedObject obj(cx, IdVectorToArray(cx, ids));
778
if (!obj) {
779
return false;
780
}
781
782
args.rval().setObject(*obj);
783
return true;
784
}
785
786
bool DebuggerObject::CallData::getOwnPropertySymbolsMethod() {
787
Rooted<IdVector> ids(cx, IdVector(cx));
788
if (!DebuggerObject::getOwnPropertySymbols(cx, object, &ids)) {
789
return false;
790
}
791
792
RootedObject obj(cx, IdVectorToArray(cx, ids));
793
if (!obj) {
794
return false;
795
}
796
797
args.rval().setObject(*obj);
798
return true;
799
}
800
801
bool DebuggerObject::CallData::getOwnPropertyDescriptorMethod() {
802
RootedId id(cx);
803
if (!ValueToId<CanGC>(cx, args.get(0), &id)) {
804
return false;
805
}
806
807
Rooted<PropertyDescriptor> desc(cx);
808
if (!DebuggerObject::getOwnPropertyDescriptor(cx, object, id, &desc)) {
809
return false;
810
}
811
812
return JS::FromPropertyDescriptor(cx, desc, args.rval());
813
}
814
815
bool DebuggerObject::CallData::preventExtensionsMethod() {
816
if (!DebuggerObject::preventExtensions(cx, object)) {
817
return false;
818
}
819
820
args.rval().setUndefined();
821
return true;
822
}
823
824
bool DebuggerObject::CallData::sealMethod() {
825
if (!DebuggerObject::seal(cx, object)) {
826
return false;
827
}
828
829
args.rval().setUndefined();
830
return true;
831
}
832
833
bool DebuggerObject::CallData::freezeMethod() {
834
if (!DebuggerObject::freeze(cx, object)) {
835
return false;
836
}
837
838
args.rval().setUndefined();
839
return true;
840
}
841
842
bool DebuggerObject::CallData::definePropertyMethod() {
843
if (!args.requireAtLeast(cx, "Debugger.Object.defineProperty", 2)) {
844
return false;
845
}
846
847
RootedId id(cx);
848
if (!ValueToId<CanGC>(cx, args[0], &id)) {
849
return false;
850
}
851
852
Rooted<PropertyDescriptor> desc(cx);
853
if (!ToPropertyDescriptor(cx, args[1], false, &desc)) {
854
return false;
855
}
856
857
if (!DebuggerObject::defineProperty(cx, object, id, desc)) {
858
return false;
859
}
860
861
args.rval().setUndefined();
862
return true;
863
}
864
865
bool DebuggerObject::CallData::definePropertiesMethod() {
866
if (!args.requireAtLeast(cx, "Debugger.Object.defineProperties", 1)) {
867
return false;
868
}
869
870
RootedValue arg(cx, args[0]);
871
RootedObject props(cx, ToObject(cx, arg));
872
if (!props) {
873
return false;
874
}
875
RootedIdVector ids(cx);
876
Rooted<PropertyDescriptorVector> descs(cx, PropertyDescriptorVector(cx));
877
if (!ReadPropertyDescriptors(cx, props, false, &ids, &descs)) {
878
return false;
879
}
880
Rooted<IdVector> ids2(cx, IdVector(cx));
881
if (!ids2.append(ids.begin(), ids.end())) {
882
return false;
883
}
884
885
if (!DebuggerObject::defineProperties(cx, object, ids2, descs)) {
886
return false;
887
}
888
889
args.rval().setUndefined();
890
return true;
891
}
892
893
/*
894
* This does a non-strict delete, as a matter of API design. The case where the
895
* property is non-configurable isn't necessarily exceptional here.
896
*/
897
bool DebuggerObject::CallData::deletePropertyMethod() {
898
RootedId id(cx);
899
if (!ValueToId<CanGC>(cx, args.get(0), &id)) {
900
return false;
901
}
902
903
ObjectOpResult result;
904
if (!DebuggerObject::deleteProperty(cx, object, id, result)) {
905
return false;
906
}
907
908
args.rval().setBoolean(result.ok());
909
return true;
910
}
911
912
bool DebuggerObject::CallData::callMethod() {
913
RootedValue thisv(cx, args.get(0));
914
915
Rooted<ValueVector> nargs(cx, ValueVector(cx));
916
if (args.length() >= 2) {
917
if (!nargs.growBy(args.length() - 1)) {
918
return false;
919
}
920
for (size_t i = 1; i < args.length(); ++i) {
921
nargs[i - 1].set(args[i]);
922
}
923
}
924
925
Rooted<Maybe<Completion>> completion(
926
cx, DebuggerObject::call(cx, object, thisv, nargs));
927
if (!completion.get()) {
928
return false;
929
}
930
931
return completion->buildCompletionValue(cx, object->owner(), args.rval());
932
}
933
934
bool DebuggerObject::CallData::getPropertyMethod() {
935
Debugger* dbg = Debugger::fromChildJSObject(object);
936
937
RootedId id(cx);
938
if (!ValueToId<CanGC>(cx, args.get(0), &id)) {
939
return false;
940
}
941
942
RootedValue receiver(cx,
943
args.length() < 2 ? ObjectValue(*object) : args.get(1));
944
945
Rooted<Completion> comp(cx);
946
JS_TRY_VAR_OR_RETURN_FALSE(cx, comp, getProperty(cx, object, id, receiver));
947
return comp.get().buildCompletionValue(cx, dbg, args.rval());
948
}
949
950
bool DebuggerObject::CallData::setPropertyMethod() {
951
Debugger* dbg = Debugger::fromChildJSObject(object);
952
953
RootedId id(cx);
954
if (!ValueToId<CanGC>(cx, args.get(0), &id)) {
955
return false;
956
}
957
958
RootedValue value(cx, args.get(1));
959
960
RootedValue receiver(cx,
961
args.length() < 3 ? ObjectValue(*object) : args.get(2));
962
963
Rooted<Completion> comp(cx);
964
JS_TRY_VAR_OR_RETURN_FALSE(cx, comp,
965
setProperty(cx, object, id, value, receiver));
966
return comp.get().buildCompletionValue(cx, dbg, args.rval());
967
}
968
969
bool DebuggerObject::CallData::applyMethod() {
970
RootedValue thisv(cx, args.get(0));
971
972
Rooted<ValueVector> nargs(cx, ValueVector(cx));
973
if (args.length() >= 2 && !args[1].isNullOrUndefined()) {
974
if (!args[1].isObject()) {
975
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
976
JSMSG_BAD_APPLY_ARGS, js_apply_str);
977
return false;
978
}
979
980
RootedObject argsobj(cx, &args[1].toObject());
981
982
unsigned argc = 0;
983
if (!GetLengthProperty(cx, argsobj, &argc)) {
984
return false;
985
}
986
argc = unsigned(std::min(argc, ARGS_LENGTH_MAX));
987
988
if (!nargs.growBy(argc) || !GetElements(cx, argsobj, argc, nargs.begin())) {
989
return false;
990
}
991
}
992
993
Rooted<Maybe<Completion>> completion(
994
cx, DebuggerObject::call(cx, object, thisv, nargs));
995
if (!completion.get()) {
996
return false;
997
}
998
999
return completion->buildCompletionValue(cx, object->owner(), args.rval());
1000
}
1001
1002
static void EnterDebuggeeObjectRealm(JSContext* cx, Maybe<AutoRealm>& ar,
1003
JSObject* referent) {
1004
// |referent| may be a cross-compartment wrapper and CCWs normally
1005
// shouldn't be used with AutoRealm, but here we use an arbitrary realm for
1006
// now because we don't really have another option.
1007
ar.emplace(cx, referent->maybeCCWRealm()->maybeGlobal());
1008
}
1009
1010
static bool RequireGlobalObject(JSContext* cx, HandleValue dbgobj,
1011
HandleObject referent) {
1012
RootedObject obj(cx, referent);
1013
1014
if (!obj->is<GlobalObject>()) {
1015
const char* isWrapper = "";
1016
const char* isWindowProxy = "";
1017
1018
// Help the poor programmer by pointing out wrappers around globals...
1019
if (obj->is<WrapperObject>()) {
1020
obj = js::UncheckedUnwrap(obj);
1021
isWrapper = "a wrapper around ";
1022
}
1023
1024
// ... and WindowProxies around Windows.
1025
if (IsWindowProxy(obj)) {
1026
obj = ToWindowIfWindowProxy(obj);
1027
isWindowProxy = "a WindowProxy referring to ";
1028
}
1029
1030
if (obj->is<GlobalObject>()) {
1031
ReportValueError(cx, JSMSG_DEBUG_WRAPPER_IN_WAY, JSDVG_SEARCH_STACK,
1032
dbgobj, nullptr, isWrapper, isWindowProxy);
1033
} else {
1034
ReportValueError(cx, JSMSG_DEBUG_BAD_REFERENT, JSDVG_SEARCH_STACK, dbgobj,
1035
nullptr, "a global object");
1036
}
1037
return false;
1038
}
1039
1040
return true;
1041
}
1042
1043
bool DebuggerObject::CallData::asEnvironmentMethod() {
1044
Debugger* dbg = Debugger::fromChildJSObject(object);
1045
1046
if (!RequireGlobalObject(cx, args.thisv(), referent)) {
1047
return false;
1048
}
1049
1050
Rooted<Env*> env(cx);
1051
{
1052
AutoRealm ar(cx, referent);
1053
env = GetDebugEnvironmentForGlobalLexicalEnvironment(cx);
1054
if (!env) {
1055
return false;
1056
}
1057
}
1058
1059
return dbg->wrapEnvironment(cx, env, args.rval());
1060
}
1061
1062
// Lookup a binding on the referent's global scope and change it to undefined
1063
// if it is an uninitialized lexical, otherwise do nothing. The method's
1064
// JavaScript return value is true _only_ when an uninitialized lexical has been
1065
// altered, otherwise it is false.
1066
bool DebuggerObject::CallData::forceLexicalInitializationByNameMethod() {
1067
if (!args.requireAtLeast(
1068
cx, "Debugger.Object.prototype.forceLexicalInitializationByName",
1069
1)) {
1070
return false;
1071
}
1072
1073
if (!DebuggerObject::requireGlobal(cx, object)) {
1074
return false;
1075
}
1076
1077
RootedId id(cx);
1078
if (!ValueToIdentifier(cx, args[0], &id)) {
1079
return false;
1080
}
1081
1082
bool result;
1083
if (!DebuggerObject::forceLexicalInitializationByName(cx, object, id,
1084
result)) {
1085
return false;
1086
}
1087
1088
args.rval().setBoolean(result);
1089
return true;
1090
}
1091
1092
bool DebuggerObject::CallData::executeInGlobalMethod() {
1093
if (!args.requireAtLeast(cx, "Debugger.Object.prototype.executeInGlobal",
1094
1)) {
1095
return false;
1096
}
1097
1098
if (!DebuggerObject::requireGlobal(cx, object)) {
1099
return false;
1100
}
1101
1102
AutoStableStringChars stableChars(cx);
1103
if (!ValueToStableChars(cx, "Debugger.Object.prototype.executeInGlobal",
1104
args[0], stableChars)) {
1105
return false;
1106
}
1107
mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
1108
1109
EvalOptions options;
1110
if (!ParseEvalOptions(cx, args.get(1), options)) {
1111
return false;
1112
}
1113
1114
Rooted<Completion> comp(cx);
1115
JS_TRY_VAR_OR_RETURN_FALSE(
1116
cx, comp,
1117
DebuggerObject::executeInGlobal(cx, object, chars, nullptr, options));
1118
return comp.get().buildCompletionValue(cx, object->owner(), args.rval());
1119
}
1120
1121
bool DebuggerObject::CallData::executeInGlobalWithBindingsMethod() {
1122
if (!args.requireAtLeast(
1123
cx, "Debugger.Object.prototype.executeInGlobalWithBindings", 2)) {
1124
return false;
1125
}
1126
1127
if (!DebuggerObject::requireGlobal(cx, object)) {
1128
return false;
1129
}
1130
1131
AutoStableStringChars stableChars(cx);
1132
if (!ValueToStableChars(
1133
cx, "Debugger.Object.prototype.executeInGlobalWithBindings", args[0],
1134
stableChars)) {
1135
return false;
1136
}
1137
mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
1138
1139
RootedObject bindings(cx, RequireObject(cx, args[1]));
1140
if (!bindings) {
1141
return false;
1142
}
1143
1144
EvalOptions options;
1145
if (!ParseEvalOptions(cx, args.get(2), options)) {
1146
return false;
1147
}
1148
1149
Rooted<Completion> comp(cx);
1150
JS_TRY_VAR_OR_RETURN_FALSE(
1151
cx, comp,
1152
DebuggerObject::executeInGlobal(cx, object, chars, bindings, options));
1153
return comp.get().buildCompletionValue(cx, object->owner(), args.rval());
1154
}
1155
1156
// Copy a narrow or wide string to a vector, appending a null terminator.
1157
template <typename T>
1158
static bool CopyStringToVector(JSContext* cx, JSString* str, Vector<T>& chars) {
1159
JSLinearString* linear = str->ensureLinear(cx);
1160
if (!linear) {
1161
return false;
1162
}
1163
if (!chars.appendN(0, linear->length() + 1)) {
1164
return false;
1165
}
1166
CopyChars(chars.begin(), *linear);
1167
return true;
1168
}
1169
1170
bool DebuggerObject::CallData::createSource() {
1171
if (!args.requireAtLeast(cx, "Debugger.Object.prototype.createSource", 1)) {
1172
return false;
1173
}
1174
1175
if (!DebuggerObject::requireGlobal(cx, object)) {
1176
return false;
1177
}
1178
1179
RootedObject options(cx, ToObject(cx, args[0]));
1180
if (!options) {
1181
return false;
1182
}
1183
1184
RootedValue v(cx);
1185
if (!JS_GetProperty(cx, options, "text", &v)) {
1186
return false;
1187
}
1188
1189
RootedString text(cx, ToString<CanGC>(cx, v));
1190
if (!text) {
1191
return false;
1192
}
1193
1194
if (!JS_GetProperty(cx, options, "url", &v)) {
1195
return false;
1196
}
1197
1198
RootedString url(cx, ToString<CanGC>(cx, v));
1199
if (!url) {
1200
return false;
1201
}
1202
1203
if (!JS_GetProperty(cx, options, "startLine", &v)) {
1204
return false;
1205
}
1206
1207
uint32_t startLine;
1208
if (!ToUint32(cx, v, &startLine)) {
1209
return false;
1210
}
1211
1212
if (!JS_GetProperty(cx, options, "sourceMapURL", &v)) {
1213
return false;
1214
}
1215
1216
RootedString sourceMapURL(cx);
1217
if (!v.isUndefined()) {
1218
sourceMapURL = ToString<CanGC>(cx, v);
1219
if (!sourceMapURL) {
1220
return false;
1221
}
1222
}
1223
1224
if (!JS_GetProperty(cx, options, "isScriptElement", &v)) {
1225
return false;
1226
}
1227
1228
bool isScriptElement = ToBoolean(v);
1229
1230
JS::CompileOptions compileOptions(cx);
1231
compileOptions.lineno = startLine;
1232
1233
if (!JS_StringHasLatin1Chars(url)) {
1234
JS_ReportErrorASCII(cx, "URL must be a narrow string");
1235
return false;
1236
}
1237
1238
Vector<Latin1Char> urlChars(cx);
1239
if (!CopyStringToVector(cx, url, urlChars)) {
1240
return false;
1241
}
1242
compileOptions.setFile((const char*)urlChars.begin());
1243
1244
Vector<char16_t> sourceMapURLChars(cx);
1245
if (sourceMapURL) {
1246
if (!CopyStringToVector(cx, sourceMapURL, sourceMapURLChars)) {
1247
return false;
1248
}
1249
compileOptions.setSourceMapURL(sourceMapURLChars.begin());
1250
}
1251
1252
if (isScriptElement) {
1253
// The introduction type must be a statically allocated string.
1254
compileOptions.setIntroductionType("scriptElement");
1255
}
1256
1257
Vector<char16_t> textChars(cx);
1258
if (!CopyStringToVector(cx, text, textChars)) {
1259
return false;
1260
}
1261
1262
JS::SourceText<char16_t> srcBuf;
1263
if (!srcBuf.init(cx, textChars.begin(), text->length(),
1264
JS::SourceOwnership::Borrowed)) {
1265
return false;
1266
}
1267
1268
RootedScript script(cx);
1269
{
1270
AutoRealm ar(cx, object->referent());
1271
script = JS::Compile(cx, compileOptions, srcBuf);
1272
if (!script) {
1273
return false;
1274
}
1275
}
1276
1277
RootedScriptSourceObject sso(cx, script->sourceObject());
1278
RootedObject wrapped(cx, object->owner()->wrapSource(cx, sso));
1279
if (!wrapped) {
1280
return false;
1281
}
1282
1283
args.rval().setObject(*wrapped);
1284
return true;
1285
}
1286
1287
bool DebuggerObject::CallData::makeDebuggeeValueMethod() {
1288
if (!args.requireAtLeast(cx, "Debugger.Object.prototype.makeDebuggeeValue",
1289
1)) {
1290
return false;
1291
}
1292
1293
return DebuggerObject::makeDebuggeeValue(cx, object, args[0], args.rval());
1294
}
1295
1296
bool DebuggerObject::CallData::makeDebuggeeNativeFunctionMethod() {
1297
if (!args.requireAtLeast(
1298
cx, "Debugger.Object.prototype.makeDebuggeeNativeFunction", 1)) {
1299
return false;
1300
}
1301
1302
return DebuggerObject::makeDebuggeeNativeFunction(cx, object, args[0],
1303
args.rval());
1304
}
1305
1306
bool DebuggerObject::CallData::isSameNativeMethod() {
1307
if (!args.requireAtLeast(cx, "Debugger.Object.prototype.isSameNative", 1)) {
1308
return false;
1309
}
1310
1311
return DebuggerObject::isSameNative(cx, object, args[0], args.rval());
1312
}
1313
1314
bool DebuggerObject::CallData::unsafeDereferenceMethod() {
1315
RootedObject result(cx);
1316
if (!DebuggerObject::unsafeDereference(cx, object, &result)) {
1317
return false;
1318
}
1319
1320
args.rval().setObject(*result);
1321
return true;
1322
}
1323
1324
bool DebuggerObject::CallData::unwrapMethod() {
1325
RootedDebuggerObject result(cx);
1326
if (!DebuggerObject::unwrap(cx, object, &result)) {
1327
return false;
1328
}
1329
1330
args.rval().setObjectOrNull(result);
1331
return true;
1332
}
1333
1334
bool DebuggerObject::CallData::setInstrumentationMethod() {
1335
if (!args.requireAtLeast(cx, "Debugger.Object.prototype.setInstrumentation",
1336
2)) {
1337
return false;
1338
}
1339
1340
if (!DebuggerObject::requireGlobal(cx, object)) {
1341
return false;
1342
}
1343
RootedGlobalObject global(cx, &object->referent()->as<GlobalObject>());
1344
1345
RootedValue v(cx, args[0]);
1346
if (!object->owner()->unwrapDebuggeeValue(cx, &v)) {
1347
return false;
1348
}
1349
if (!v.isObject()) {
1350
JS_ReportErrorASCII(cx, "Instrumentation callback must be an object");
1351
return false;
1352
}
1353
RootedObject callback(cx, &v.toObject());
1354
1355
if (!args[1].isObject()) {
1356
JS_ReportErrorASCII(cx, "Instrumentation kinds must be an object");
1357
return false;
1358
}
1359
RootedObject kindsObj(cx, &args[1].toObject());
1360
1361
unsigned length = 0;
1362
if (!GetLengthProperty(cx, kindsObj, &length)) {
1363
return false;
1364
}
1365
1366
Rooted<ValueVector> values(cx, ValueVector(cx));
1367
if (!values.growBy(length) ||
1368
!GetElements(cx, kindsObj, length, values.begin())) {
1369
return false;
1370
}
1371
1372
Rooted<StringVector> kinds(cx, StringVector(cx));
1373
for (size_t i = 0; i < values.length(); i++) {
1374
if (!values[i].isString()) {
1375
JS_ReportErrorASCII(cx, "Instrumentation kind must be a string");
1376
return false;
1377
}
1378
if (!kinds.append(values[i].toString())) {
1379
return false;
1380
}
1381
}
1382
1383
{
1384
AutoRealm ar(cx, global);
1385
RootedObject dbgObject(cx, object->owner()->toJSObject());
1386
if (!RealmInstrumentation::install(cx, global, callback, dbgObject,
1387
kinds)) {
1388
return false;
1389
}
1390
}
1391
1392
args.rval().setUndefined();
1393
return true;
1394
}
1395
1396
bool DebuggerObject::CallData::setInstrumentationActiveMethod() {
1397
if (!DebuggerObject::requireGlobal(cx, object)) {
1398
return false;
1399
}
1400
1401
if (!args.requireAtLeast(
1402
cx, "Debugger.Object.prototype.setInstrumentationActive", 1)) {
1403
return false;
1404
}
1405
1406
RootedGlobalObject global(cx, &object->referent()->as<GlobalObject>());
1407
bool active = ToBoolean(args[0]);
1408
1409
{
1410
AutoRealm ar(cx, global);
1411
if (!RealmInstrumentation::setActive(cx, global, object->owner(), active)) {
1412
return false;
1413
}
1414
}
1415
1416
args.rval().setUndefined();
1417
return true;
1418
}
1419
1420
const JSPropertySpec DebuggerObject::properties_[] = {
1421
JS_DEBUG_PSG("callable", callableGetter),
1422
JS_DEBUG_PSG("isBoundFunction", isBoundFunctionGetter),
1423
JS_DEBUG_PSG("isArrowFunction", isArrowFunctionGetter),
1424
JS_DEBUG_PSG("isGeneratorFunction", isGeneratorFunctionGetter),
1425
JS_DEBUG_PSG("isAsyncFunction", isAsyncFunctionGetter),
1426
JS_DEBUG_PSG("isClassConstructor", isClassConstructorGetter),
1427
JS_DEBUG_PSG("proto", protoGetter),
1428
JS_DEBUG_PSG("class", classGetter),
1429
JS_DEBUG_PSG("name", nameGetter),
1430
JS_DEBUG_PSG("displayName", displayNameGetter),
1431
JS_DEBUG_PSG("parameterNames", parameterNamesGetter),
1432
JS_DEBUG_PSG("script", scriptGetter),
1433
JS_DEBUG_PSG("environment", environmentGetter),
1434
JS_DEBUG_PSG("boundTargetFunction", boundTargetFunctionGetter),
1435
JS_DEBUG_PSG("boundThis", boundThisGetter),
1436
JS_DEBUG_PSG("boundArguments", boundArgumentsGetter),
1437
JS_DEBUG_PSG("allocationSite", allocationSiteGetter),
1438
JS_DEBUG_PSG("errorMessageName", errorMessageNameGetter),
1439
JS_DEBUG_PSG("errorNotes", errorNotesGetter),
1440
JS_DEBUG_PSG("errorLineNumber", errorLineNumberGetter),
1441
JS_DEBUG_PSG("errorColumnNumber", errorColumnNumberGetter),
1442
JS_DEBUG_PSG("isProxy", isProxyGetter),
1443
JS_DEBUG_PSG("proxyTarget", proxyTargetGetter),
1444
JS_DEBUG_PSG("proxyHandler", proxyHandlerGetter),
1445
JS_PS_END};
1446
1447
const JSPropertySpec DebuggerObject::promiseProperties_[] = {
1448
JS_DEBUG_PSG("isPromise", isPromiseGetter),
1449
JS_DEBUG_PSG("promiseState", promiseStateGetter),
1450
JS_DEBUG_PSG("promiseValue", promiseValueGetter),
1451
JS_DEBUG_PSG("promiseReason", promiseReasonGetter),
1452
JS_DEBUG_PSG("promiseLifetime", promiseLifetimeGetter),
1453
JS_DEBUG_PSG("promiseTimeToResolution", promiseTimeToResolutionGetter),
1454
JS_DEBUG_PSG("promiseAllocationSite", promiseAllocationSiteGetter),
1455
JS_DEBUG_PSG("promiseResolutionSite", promiseResolutionSiteGetter),
1456
JS_DEBUG_PSG("promiseID", promiseIDGetter),
1457
JS_DEBUG_PSG("promiseDependentPromises", promiseDependentPromisesGetter),
1458
JS_PS_END};
1459
1460
const JSFunctionSpec DebuggerObject::methods_[] = {
1461
JS_DEBUG_FN("isExtensible", isExtensibleMethod, 0),
1462
JS_DEBUG_FN("isSealed", isSealedMethod, 0),
1463
JS_DEBUG_FN("isFrozen", isFrozenMethod, 0),
1464
JS_DEBUG_FN("getProperty", getPropertyMethod, 0),
1465
JS_DEBUG_FN("setProperty", setPropertyMethod, 0),
1466
JS_DEBUG_FN("getOwnPropertyNames", getOwnPropertyNamesMethod, 0),
1467
JS_DEBUG_FN("getOwnPropertySymbols", getOwnPropertySymbolsMethod, 0),
1468
JS_DEBUG_FN("getOwnPropertyDescriptor", getOwnPropertyDescriptorMethod, 1),
1469
JS_DEBUG_FN("preventExtensions", preventExtensionsMethod, 0),
1470
JS_DEBUG_FN("seal", sealMethod, 0),
1471
JS_DEBUG_FN("freeze", freezeMethod, 0),
1472
JS_DEBUG_FN("defineProperty", definePropertyMethod, 2),
1473
JS_DEBUG_FN("defineProperties", definePropertiesMethod, 1),
1474
JS_DEBUG_FN("deleteProperty", deletePropertyMethod, 1),
1475
JS_DEBUG_FN("call", callMethod, 0),
1476
JS_DEBUG_FN("apply", applyMethod, 0),
1477
JS_DEBUG_FN("asEnvironment", asEnvironmentMethod, 0),
1478
JS_DEBUG_FN("forceLexicalInitializationByName",
1479
forceLexicalInitializationByNameMethod, 1),
1480
JS_DEBUG_FN("executeInGlobal", executeInGlobalMethod, 1),
1481
JS_DEBUG_FN("executeInGlobalWithBindings",
1482
executeInGlobalWithBindingsMethod, 2),
1483
JS_DEBUG_FN("createSource", createSource, 1),
1484
JS_DEBUG_FN("makeDebuggeeValue", makeDebuggeeValueMethod, 1),
1485
JS_DEBUG_FN("makeDebuggeeNativeFunction", makeDebuggeeNativeFunctionMethod,
1486
1),
1487
JS_DEBUG_FN("isSameNative", isSameNativeMethod, 1),
1488
JS_DEBUG_FN("unsafeDereference", unsafeDereferenceMethod, 0),
1489
JS_DEBUG_FN("unwrap", unwrapMethod, 0),
1490
JS_DEBUG_FN("setInstrumentation", setInstrumentationMethod, 2),
1491
JS_DEBUG_FN("setInstrumentationActive", setInstrumentationActiveMethod, 1),
1492
JS_FS_END};
1493
1494
/* static */
1495
NativeObject* DebuggerObject::initClass(JSContext* cx,
1496
Handle<GlobalObject*> global,
1497
HandleObject debugCtor) {
1498
RootedNativeObject objectProto(
1499
cx, InitClass(cx, debugCtor, nullptr, &class_, construct, 0, properties_,
1500
methods_, nullptr, nullptr));
1501
1502
if (!objectProto) {
1503
return nullptr;
1504
}
1505
1506
if (!DefinePropertiesAndFunctions(cx, objectProto, promiseProperties_,
1507
nullptr)) {
1508
return nullptr;
1509
}
1510
1511
return objectProto;
1512
}
1513
1514
/* static */
1515
DebuggerObject* DebuggerObject::create(JSContext* cx, HandleObject proto,
1516
HandleObject referent,
1517
HandleNativeObject debugger) {
1518
NewObjectKind newKind =
1519
IsInsideNursery(referent) ? GenericObject : TenuredObject;
1520
DebuggerObject* obj =
1521
NewObjectWithGivenProto<DebuggerObject>(cx, proto, newKind);
1522
if (!obj) {
1523
return nullptr;
1524
}
1525
1526
obj->setPrivateGCThing(referent);
1527
obj->setReservedSlot(JSSLOT_DEBUGOBJECT_OWNER, ObjectValue(*debugger));
1528
1529
return obj;
1530
}
1531
1532
bool DebuggerObject::isCallable() const { return referent()->isCallable(); }
1533
1534
bool DebuggerObject::isFunction() const { return referent()->is<JSFunction>(); }
1535
1536
bool DebuggerObject::isDebuggeeFunction() const {
1537
return referent()->is<JSFunction>() &&
1538
owner()->observesGlobal(&referent()->as<JSFunction>().global());
1539
}
1540
1541
bool DebuggerObject::isBoundFunction() const {
1542
MOZ_ASSERT(isDebuggeeFunction());
1543
1544
return referent()->isBoundFunction();
1545
}
1546
1547
bool DebuggerObject::isArrowFunction() const {
1548
MOZ_ASSERT(isDebuggeeFunction());
1549
1550
return referent()->as<JSFunction>().isArrow();
1551
}
1552
1553
bool DebuggerObject::isAsyncFunction() const {
1554
MOZ_ASSERT(isDebuggeeFunction());
1555
1556
return referent()->as<JSFunction>().isAsync();
1557
}
1558
1559
bool DebuggerObject::isGeneratorFunction() const {
1560
MOZ_ASSERT(isDebuggeeFunction());
1561
1562
return referent()->as<JSFunction>().isGenerator();
1563
}
1564
1565
bool DebuggerObject::isClassConstructor() const {
1566
MOZ_ASSERT(isDebuggeeFunction());
1567
1568
return referent()->as<JSFunction>().isClassConstructor();
1569
}
1570
1571
bool DebuggerObject::isGlobal() const { return referent()->is<GlobalObject>(); }
1572
1573
bool DebuggerObject::isScriptedProxy() const {
1574
return js::IsScriptedProxy(referent());
1575
}
1576
1577
bool DebuggerObject::isPromise() const {
1578
JSObject* referent = this->referent();
1579
1580
if (IsCrossCompartmentWrapper(referent)) {
1581
/* We only care about promises, so CheckedUnwrapStatic is OK. */
1582
referent = CheckedUnwrapStatic(referent);
1583
if (!referent) {
1584
return false;
1585
}
1586
}
1587
1588
return referent->is<PromiseObject>();
1589
}
1590
1591
/* static */
1592
bool DebuggerObject::getClassName(JSContext* cx, HandleDebuggerObject object,
1593
MutableHandleString result) {
1594
RootedObject referent(cx, object->referent());
1595
1596
const char* className;
1597
{
1598
Maybe<AutoRealm> ar;
1599
EnterDebuggeeObjectRealm(cx, ar, referent);
1600
className = GetObjectClassName(cx, referent);
1601
}
1602
1603
JSAtom* str = Atomize(cx, className, strlen(className));
1604
if (!str) {
1605
return false;
1606
}
1607
1608
result.set(str);
1609
return true;
1610
}
1611
1612
JSAtom* DebuggerObject::name(JSContext* cx) const {
1613
MOZ_ASSERT(isFunction());
1614
1615
JSAtom* atom = referent()->as<JSFunction>().explicitName();
1616
if (atom) {
1617
cx->markAtom(atom);
1618
}
1619
return atom;
1620
}
1621
1622
JSAtom* DebuggerObject::displayName(JSContext* cx) const {
1623
MOZ_ASSERT(isFunction());
1624
1625
JSAtom* atom = referent()->as<JSFunction>().displayAtom();
1626
if (atom) {
1627
cx->markAtom(atom);
1628
}
1629
return atom;
1630
}
1631
1632
JS::PromiseState DebuggerObject::promiseState() const {
1633
return promise()->state();
1634
}
1635
1636
double DebuggerObject::promiseLifetime() const { return promise()->lifetime(); }
1637
1638
double DebuggerObject::promiseTimeToResolution() const {
1639
MOZ_ASSERT(promiseState() != JS::PromiseState::Pending);
1640
1641
return promise()->timeToResolution();
1642
}
1643
1644
/* static */
1645
bool DebuggerObject::getParameterNames(JSContext* cx,
1646
HandleDebuggerObject object,
1647
MutableHandle<StringVector> result) {
1648
MOZ_ASSERT(object->isDebuggeeFunction());
1649
1650
RootedFunction referent(cx, &object->referent()->as<JSFunction>());
1651
1652
if (!result.growBy(referent->nargs())) {
1653
return false;
1654
}
1655
if (IsInterpretedNonSelfHostedFunction(referent)) {
1656
RootedScript script(cx, GetOrCreateFunctionScript(cx, referent));
1657
if (!script) {
1658
return false;
1659
}
1660
1661
MOZ_ASSERT(referent->nargs() == script->numArgs());
1662
1663
if (referent->nargs() > 0) {
1664
PositionalFormalParameterIter fi(script);
1665
for (size_t i = 0; i < referent->nargs(); i++, fi++) {
1666
MOZ_ASSERT(fi.argumentSlot() == i);
1667
JSAtom* atom = fi.name();
1668
if (atom) {
1669
cx->markAtom(atom);
1670
}
1671
result[i].set(atom);
1672
}
1673
}
1674
} else {
1675
for (size_t i = 0; i < referent->nargs(); i++) {
1676
result[i].set(nullptr);
1677
}
1678
}
1679
1680
return true;
1681
}
1682
1683
/* static */
1684
bool DebuggerObject::getBoundTargetFunction(
1685
JSContext* cx, HandleDebuggerObject object,
1686
MutableHandleDebuggerObject result) {
1687
MOZ_ASSERT(object->isBoundFunction());
1688
1689
RootedFunction referent(cx, &object->referent()->as<JSFunction>());
1690
Debugger* dbg = object->owner();
1691
1692
RootedObject target(cx, referent->getBoundFunctionTarget());
1693
return dbg->wrapDebuggeeObject(cx, target, result);
1694
}
1695
1696
/* static */
1697
bool DebuggerObject::getBoundThis(JSContext* cx, HandleDebuggerObject object,
1698
MutableHandleValue result) {
1699
MOZ_ASSERT(object->isBoundFunction());
1700
1701
RootedFunction referent(cx, &object->referent()->as<JSFunction>());
1702
Debugger* dbg = object->owner();
1703
1704
result.set(referent->getBoundFunctionThis());
1705
return dbg->wrapDebuggeeValue(cx, result);
1706
}
1707
1708
/* static */
1709
bool DebuggerObject::getBoundArguments(JSContext* cx,
1710
HandleDebuggerObject object,
1711
MutableHandle<ValueVector> result) {
1712
MOZ_ASSERT(object->isBoundFunction());
1713
1714
RootedFunction referent(cx, &object->referent()->as<JSFunction>());
1715
Debugger* dbg = object->owner();
1716
1717
size_t length = referent->getBoundFunctionArgumentCount();
1718
if (!result.resize(length)) {
1719
return false;
1720
}
1721
for (size_t i = 0; i < length; i++) {
1722
result[i].set(referent->getBoundFunctionArgument(i));
1723
if (!dbg->wrapDebuggeeValue(cx, result[i])) {
1724
return false;
1725
}
1726
}
1727
return true;
1728
}
1729
1730
/* static */
1731
SavedFrame* Debugger::getObjectAllocationSite(JSObject& obj) {
1732
JSObject* metadata = GetAllocationMetadata(&obj);
1733
if (!metadata) {
1734
return nullptr;
1735
}
1736
1737
MOZ_ASSERT(!metadata->is<WrapperObject>());
1738
return metadata->is<SavedFrame>() ? &metadata->as<SavedFrame>() : nullptr;
1739
}
1740
1741
/* static */
1742
bool DebuggerObject::getAllocationSite(JSContext* cx,
1743
HandleDebuggerObject object,
1744
MutableHandleObject result) {
1745
RootedObject referent(cx, object->referent());
1746
1747
RootedObject allocSite(cx, Debugger::getObjectAllocationSite(*referent));
1748
if (!cx->compartment()->wrap(cx, &allocSite)) {
1749
return false;
1750
}
1751
1752
result.set(allocSite);
1753
return true;
1754
}
1755
1756
/* static */
1757
bool DebuggerObject::getErrorReport(JSContext* cx, HandleObject maybeError,
1758
JSErrorReport*& report) {
1759
JSObject* obj = maybeError;
1760
if (IsCrossCompartmentWrapper(obj)) {
1761
/* We only care about Error objects, so CheckedUnwrapStatic is OK. */
1762
obj = CheckedUnwrapStatic(obj);
1763
}
1764
1765
if (!obj) {
1766
ReportAccessDenied(cx);
1767
return false;
1768
}
1769
1770
if (!obj->is<ErrorObject>()) {
1771
report = nullptr;
1772
return true;