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
/*
8
* JavaScript API.
9
*/
10
11
#include "jsapi.h"
12
13
#include "mozilla/FloatingPoint.h"
14
#include "mozilla/Maybe.h"
15
#include "mozilla/PodOperations.h"
16
#include "mozilla/Sprintf.h"
17
18
#include <algorithm>
19
#ifdef __linux__
20
# include <dlfcn.h>
21
#endif
22
#include <stdarg.h>
23
#include <string.h>
24
25
#include "jsdate.h"
26
#include "jsexn.h"
27
#include "jsfriendapi.h"
28
#include "jsmath.h"
29
#include "jsnum.h"
30
#include "jstypes.h"
31
32
#include "builtin/Array.h"
33
#include "builtin/AtomicsObject.h"
34
#include "builtin/Boolean.h"
35
#include "builtin/Eval.h"
36
#include "builtin/FinalizationGroupObject.h"
37
#include "builtin/JSON.h"
38
#include "builtin/MapObject.h"
39
#include "builtin/Promise.h"
40
#include "builtin/Stream.h"
41
#include "builtin/Symbol.h"
42
#ifdef ENABLE_TYPED_OBJECTS
43
# include "builtin/TypedObject.h"
44
#endif
45
#include "frontend/BytecodeCompiler.h"
46
#include "gc/FreeOp.h"
47
#include "gc/Marking.h"
48
#include "gc/Policy.h"
49
#include "gc/PublicIterators.h"
50
#include "gc/WeakMap.h"
51
#include "jit/JitCommon.h"
52
#include "jit/JitSpewer.h"
53
#include "js/CharacterEncoding.h"
54
#include "js/CompilationAndEvaluation.h"
55
#include "js/CompileOptions.h"
56
#include "js/ContextOptions.h" // JS::ContextOptions{,Ref}
57
#include "js/Conversions.h"
58
#include "js/Date.h"
59
#include "js/Initialization.h"
60
#include "js/JSON.h"
61
#include "js/LocaleSensitive.h"
62
#include "js/MemoryFunctions.h"
63
#include "js/PropertySpec.h"
64
#include "js/Proxy.h"
65
#include "js/SliceBudget.h"
66
#include "js/SourceText.h"
67
#include "js/StableStringChars.h"
68
#include "js/StructuredClone.h"
69
#include "js/Symbol.h"
70
#include "js/Utility.h"
71
#include "js/Wrapper.h"
72
#include "util/CompleteFile.h"
73
#include "util/StringBuffer.h"
74
#include "util/Text.h"
75
#include "vm/AsyncFunction.h"
76
#include "vm/AsyncIteration.h"
77
#include "vm/DateObject.h"
78
#include "vm/EnvironmentObject.h"
79
#include "vm/ErrorObject.h"
80
#include "vm/HelperThreads.h"
81
#include "vm/Instrumentation.h"
82
#include "vm/Interpreter.h"
83
#include "vm/Iteration.h"
84
#include "vm/JSAtom.h"
85
#include "vm/JSContext.h"
86
#include "vm/JSFunction.h"
87
#include "vm/JSObject.h"
88
#include "vm/JSScript.h"
89
#include "vm/Runtime.h"
90
#include "vm/SavedStacks.h"
91
#include "vm/SelfHosting.h"
92
#include "vm/Shape.h"
93
#include "vm/StringType.h"
94
#include "vm/SymbolType.h"
95
#include "vm/WrapperObject.h"
96
#include "vm/Xdr.h"
97
#include "wasm/WasmModule.h"
98
#include "wasm/WasmProcess.h"
99
100
#include "debugger/DebugAPI-inl.h"
101
#include "vm/Compartment-inl.h"
102
#include "vm/Interpreter-inl.h"
103
#include "vm/JSAtom-inl.h"
104
#include "vm/JSFunction-inl.h"
105
#include "vm/JSScript-inl.h"
106
#include "vm/NativeObject-inl.h"
107
#include "vm/SavedStacks-inl.h"
108
#include "vm/StringType-inl.h"
109
110
using namespace js;
111
112
using mozilla::Maybe;
113
using mozilla::PodCopy;
114
using mozilla::Some;
115
116
using JS::AutoStableStringChars;
117
using JS::CompileOptions;
118
using JS::ReadOnlyCompileOptions;
119
using JS::SourceText;
120
121
#ifdef HAVE_VA_LIST_AS_ARRAY
122
# define JS_ADDRESSOF_VA_LIST(ap) ((va_list*)(ap))
123
#else
124
# define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
125
#endif
126
127
JS_PUBLIC_API void JS::CallArgs::reportMoreArgsNeeded(JSContext* cx,
128
const char* fnname,
129
unsigned required,
130
unsigned actual) {
131
char requiredArgsStr[40];
132
SprintfLiteral(requiredArgsStr, "%u", required);
133
char actualArgsStr[40];
134
SprintfLiteral(actualArgsStr, "%u", actual);
135
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
136
JSMSG_MORE_ARGS_NEEDED, fnname, requiredArgsStr,
137
required == 1 ? "" : "s", actualArgsStr);
138
}
139
140
static bool ErrorTakesArguments(unsigned msg) {
141
MOZ_ASSERT(msg < JSErr_Limit);
142
unsigned argCount = js_ErrorFormatString[msg].argCount;
143
MOZ_ASSERT(argCount <= 2);
144
return argCount == 1 || argCount == 2;
145
}
146
147
static bool ErrorTakesObjectArgument(unsigned msg) {
148
MOZ_ASSERT(msg < JSErr_Limit);
149
unsigned argCount = js_ErrorFormatString[msg].argCount;
150
MOZ_ASSERT(argCount <= 2);
151
return argCount == 2;
152
}
153
154
JS_PUBLIC_API bool JS::ObjectOpResult::reportStrictErrorOrWarning(
155
JSContext* cx, HandleObject obj, HandleId id, bool strict) {
156
static_assert(unsigned(OkCode) == unsigned(JSMSG_NOT_AN_ERROR),
157
"unsigned value of OkCode must not be an error code");
158
MOZ_ASSERT(code_ != Uninitialized);
159
MOZ_ASSERT(!ok());
160
cx->check(obj);
161
162
unsigned flags =
163
strict ? JSREPORT_ERROR : (JSREPORT_WARNING | JSREPORT_STRICT);
164
if (code_ == JSMSG_OBJECT_NOT_EXTENSIBLE) {
165
RootedValue val(cx, ObjectValue(*obj));
166
return ReportValueErrorFlags(cx, flags, code_, JSDVG_IGNORE_STACK, val,
167
nullptr, nullptr, nullptr);
168
}
169
170
if (ErrorTakesArguments(code_)) {
171
UniqueChars propName =
172
IdToPrintableUTF8(cx, id, IdToPrintableBehavior::IdIsPropertyKey);
173
if (!propName) {
174
return false;
175
}
176
177
if (code_ == JSMSG_SET_NON_OBJECT_RECEIVER) {
178
// We know that the original receiver was a primitive, so unbox it.
179
RootedValue val(cx, ObjectValue(*obj));
180
if (!obj->is<ProxyObject>()) {
181
if (!Unbox(cx, obj, &val)) {
182
return false;
183
}
184
}
185
return ReportValueErrorFlags(cx, flags, code_, JSDVG_IGNORE_STACK, val,
186
nullptr, propName.get(), nullptr);
187
}
188
189
if (ErrorTakesObjectArgument(code_)) {
190
return JS_ReportErrorFlagsAndNumberUTF8(
191
cx, flags, GetErrorMessage, nullptr, code_, obj->getClass()->name,
192
propName.get());
193
}
194
195
return JS_ReportErrorFlagsAndNumberUTF8(cx, flags, GetErrorMessage, nullptr,
196
code_, propName.get());
197
}
198
return JS_ReportErrorFlagsAndNumberASCII(cx, flags, GetErrorMessage, nullptr,
199
code_);
200
}
201
202
JS_PUBLIC_API bool JS::ObjectOpResult::reportStrictErrorOrWarning(
203
JSContext* cx, HandleObject obj, bool strict) {
204
MOZ_ASSERT(code_ != Uninitialized);
205
MOZ_ASSERT(!ok());
206
MOZ_ASSERT(!ErrorTakesArguments(code_));
207
cx->check(obj);
208
209
unsigned flags =
210
strict ? JSREPORT_ERROR : (JSREPORT_WARNING | JSREPORT_STRICT);
211
return JS_ReportErrorFlagsAndNumberASCII(cx, flags, GetErrorMessage, nullptr,
212
code_);
213
}
214
215
JS_PUBLIC_API bool JS::ObjectOpResult::failCantRedefineProp() {
216
return fail(JSMSG_CANT_REDEFINE_PROP);
217
}
218
219
JS_PUBLIC_API bool JS::ObjectOpResult::failReadOnly() {
220
return fail(JSMSG_READ_ONLY);
221
}
222
223
JS_PUBLIC_API bool JS::ObjectOpResult::failGetterOnly() {
224
return fail(JSMSG_GETTER_ONLY);
225
}
226
227
JS_PUBLIC_API bool JS::ObjectOpResult::failCantDelete() {
228
return fail(JSMSG_CANT_DELETE);
229
}
230
231
JS_PUBLIC_API bool JS::ObjectOpResult::failCantSetInterposed() {
232
return fail(JSMSG_CANT_SET_INTERPOSED);
233
}
234
235
JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowElement() {
236
return fail(JSMSG_CANT_DEFINE_WINDOW_ELEMENT);
237
}
238
239
JS_PUBLIC_API bool JS::ObjectOpResult::failCantDeleteWindowElement() {
240
return fail(JSMSG_CANT_DELETE_WINDOW_ELEMENT);
241
}
242
243
JS_PUBLIC_API bool JS::ObjectOpResult::failCantDeleteWindowNamedProperty() {
244
return fail(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY);
245
}
246
247
JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowNonConfigurable() {
248
return fail(JSMSG_CANT_DEFINE_WINDOW_NC);
249
}
250
251
JS_PUBLIC_API bool JS::ObjectOpResult::failCantPreventExtensions() {
252
return fail(JSMSG_CANT_PREVENT_EXTENSIONS);
253
}
254
255
JS_PUBLIC_API bool JS::ObjectOpResult::failCantSetProto() {
256
return fail(JSMSG_CANT_SET_PROTO);
257
}
258
259
JS_PUBLIC_API bool JS::ObjectOpResult::failNoNamedSetter() {
260
return fail(JSMSG_NO_NAMED_SETTER);
261
}
262
263
JS_PUBLIC_API bool JS::ObjectOpResult::failNoIndexedSetter() {
264
return fail(JSMSG_NO_INDEXED_SETTER);
265
}
266
267
JS_PUBLIC_API bool JS::ObjectOpResult::failNotDataDescriptor() {
268
return fail(JSMSG_NOT_DATA_DESCRIPTOR);
269
}
270
271
JS_PUBLIC_API int64_t JS_Now() { return PRMJ_Now(); }
272
273
JS_PUBLIC_API Value JS_GetEmptyStringValue(JSContext* cx) {
274
return StringValue(cx->runtime()->emptyString);
275
}
276
277
JS_PUBLIC_API JSString* JS_GetEmptyString(JSContext* cx) {
278
MOZ_ASSERT(cx->emptyString());
279
return cx->emptyString();
280
}
281
282
namespace js {
283
284
void AssertHeapIsIdle() { MOZ_ASSERT(!JS::RuntimeHeapIsBusy()); }
285
286
} // namespace js
287
288
static void AssertHeapIsIdleOrIterating() {
289
MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
290
}
291
292
JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, HandleValue value,
293
MutableHandleObject objp) {
294
AssertHeapIsIdle();
295
CHECK_THREAD(cx);
296
cx->check(value);
297
if (value.isNullOrUndefined()) {
298
objp.set(nullptr);
299
return true;
300
}
301
JSObject* obj = ToObject(cx, value);
302
if (!obj) {
303
return false;
304
}
305
objp.set(obj);
306
return true;
307
}
308
309
JS_PUBLIC_API JSFunction* JS_ValueToFunction(JSContext* cx, HandleValue value) {
310
AssertHeapIsIdle();
311
CHECK_THREAD(cx);
312
cx->check(value);
313
return ReportIfNotFunction(cx, value);
314
}
315
316
JS_PUBLIC_API JSFunction* JS_ValueToConstructor(JSContext* cx,
317
HandleValue value) {
318
AssertHeapIsIdle();
319
CHECK_THREAD(cx);
320
cx->check(value);
321
return ReportIfNotFunction(cx, value);
322
}
323
324
JS_PUBLIC_API JSString* JS_ValueToSource(JSContext* cx, HandleValue value) {
325
AssertHeapIsIdle();
326
CHECK_THREAD(cx);
327
cx->check(value);
328
return ValueToSource(cx, value);
329
}
330
331
JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip) {
332
return mozilla::NumberIsInt32(d, ip);
333
}
334
335
JS_PUBLIC_API JSType JS_TypeOfValue(JSContext* cx, HandleValue value) {
336
AssertHeapIsIdle();
337
CHECK_THREAD(cx);
338
cx->check(value);
339
return TypeOfValue(value);
340
}
341
342
JS_PUBLIC_API bool JS_IsBuiltinEvalFunction(JSFunction* fun) {
343
return IsAnyBuiltinEval(fun);
344
}
345
346
JS_PUBLIC_API bool JS_IsBuiltinFunctionConstructor(JSFunction* fun) {
347
return fun->isBuiltinFunctionConstructor();
348
}
349
350
JS_PUBLIC_API bool JS_IsFunctionBound(JSFunction* fun) {
351
return fun->isBoundFunction();
352
}
353
354
JS_PUBLIC_API JSObject* JS_GetBoundFunctionTarget(JSFunction* fun) {
355
return fun->isBoundFunction() ? fun->getBoundFunctionTarget() : nullptr;
356
}
357
358
/************************************************************************/
359
360
JS_PUBLIC_API JSContext* JS_NewContext(uint32_t maxbytes,
361
JSRuntime* parentRuntime) {
362
MOZ_ASSERT(JS::detail::libraryInitState == JS::detail::InitState::Running,
363
"must call JS_Init prior to creating any JSContexts");
364
365
// Make sure that all parent runtimes are the topmost parent.
366
while (parentRuntime && parentRuntime->parentRuntime) {
367
parentRuntime = parentRuntime->parentRuntime;
368
}
369
370
return NewContext(maxbytes, parentRuntime);
371
}
372
373
JS_PUBLIC_API void JS_DestroyContext(JSContext* cx) { DestroyContext(cx); }
374
375
JS_PUBLIC_API void* JS_GetContextPrivate(JSContext* cx) { return cx->data; }
376
377
JS_PUBLIC_API void JS_SetContextPrivate(JSContext* cx, void* data) {
378
cx->data = data;
379
}
380
381
JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx) {
382
cx->fx.setCanWait(true);
383
}
384
385
JS_PUBLIC_API JSRuntime* JS_GetParentRuntime(JSContext* cx) {
386
return cx->runtime()->parentRuntime ? cx->runtime()->parentRuntime
387
: cx->runtime();
388
}
389
390
JS_PUBLIC_API JSRuntime* JS_GetRuntime(JSContext* cx) { return cx->runtime(); }
391
392
JS_PUBLIC_API JS::ContextOptions& JS::ContextOptionsRef(JSContext* cx) {
393
return cx->options();
394
}
395
396
JS_PUBLIC_API bool JS::InitSelfHostedCode(JSContext* cx) {
397
MOZ_RELEASE_ASSERT(!cx->runtime()->hasInitializedSelfHosting(),
398
"JS::InitSelfHostedCode() called more than once");
399
400
AutoNoteSingleThreadedRegion anstr;
401
402
JSRuntime* rt = cx->runtime();
403
404
if (!rt->initializeAtoms(cx)) {
405
return false;
406
}
407
408
#ifndef JS_CODEGEN_NONE
409
if (!rt->createJitRuntime(cx)) {
410
return false;
411
}
412
#endif
413
414
if (!rt->initSelfHosting(cx)) {
415
return false;
416
}
417
418
if (!rt->parentRuntime && !rt->initMainAtomsTables(cx)) {
419
return false;
420
}
421
422
return true;
423
}
424
425
JS_PUBLIC_API const char* JS_GetImplementationVersion(void) {
426
return "JavaScript-C" MOZILLA_VERSION;
427
}
428
429
JS_PUBLIC_API void JS_SetDestroyCompartmentCallback(
430
JSContext* cx, JSDestroyCompartmentCallback callback) {
431
cx->runtime()->destroyCompartmentCallback = callback;
432
}
433
434
JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback(
435
JSContext* cx, JSSizeOfIncludingThisCompartmentCallback callback) {
436
cx->runtime()->sizeOfIncludingThisCompartmentCallback = callback;
437
}
438
439
#if defined(NIGHTLY_BUILD)
440
JS_PUBLIC_API void JS_SetErrorInterceptorCallback(
441
JSRuntime* rt, JSErrorInterceptor* callback) {
442
rt->errorInterception.interceptor = callback;
443
}
444
445
JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback(
446
JSRuntime* rt) {
447
return rt->errorInterception.interceptor;
448
}
449
450
JS_PUBLIC_API Maybe<JSExnType> JS_GetErrorType(const JS::Value& val) {
451
// All errors are objects.
452
if (!val.isObject()) {
453
return mozilla::Nothing();
454
}
455
456
const JSObject& obj = val.toObject();
457
458
// All errors are `ErrorObject`.
459
if (!obj.is<js::ErrorObject>()) {
460
// Not one of the primitive errors.
461
return mozilla::Nothing();
462
}
463
464
const js::ErrorObject& err = obj.as<js::ErrorObject>();
465
return mozilla::Some(err.type());
466
}
467
468
#endif // defined(NIGHTLY_BUILD)
469
470
JS_PUBLIC_API void JS_SetWrapObjectCallbacks(
471
JSContext* cx, const JSWrapObjectCallbacks* callbacks) {
472
cx->runtime()->wrapObjectCallbacks = callbacks;
473
}
474
475
JS_PUBLIC_API Realm* JS::EnterRealm(JSContext* cx, JSObject* target) {
476
AssertHeapIsIdle();
477
CHECK_THREAD(cx);
478
479
MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(target));
480
481
Realm* oldRealm = cx->realm();
482
cx->enterRealmOf(target);
483
return oldRealm;
484
}
485
486
JS_PUBLIC_API void JS::LeaveRealm(JSContext* cx, JS::Realm* oldRealm) {
487
AssertHeapIsIdle();
488
CHECK_THREAD(cx);
489
cx->leaveRealm(oldRealm);
490
}
491
492
JSAutoRealm::JSAutoRealm(
493
JSContext* cx, JSObject* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
494
: cx_(cx), oldRealm_(cx->realm()) {
495
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
496
MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(target));
497
AssertHeapIsIdleOrIterating();
498
cx_->enterRealmOf(target);
499
}
500
501
JSAutoRealm::JSAutoRealm(
502
JSContext* cx, JSScript* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
503
: cx_(cx), oldRealm_(cx->realm()) {
504
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
505
AssertHeapIsIdleOrIterating();
506
cx_->enterRealmOf(target);
507
}
508
509
JSAutoRealm::~JSAutoRealm() { cx_->leaveRealm(oldRealm_); }
510
511
JSAutoNullableRealm::JSAutoNullableRealm(
512
JSContext* cx,
513
JSObject* targetOrNull MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
514
: cx_(cx), oldRealm_(cx->realm()) {
515
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
516
AssertHeapIsIdleOrIterating();
517
if (targetOrNull) {
518
MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(targetOrNull));
519
cx_->enterRealmOf(targetOrNull);
520
} else {
521
cx_->enterNullRealm();
522
}
523
}
524
525
JSAutoNullableRealm::~JSAutoNullableRealm() { cx_->leaveRealm(oldRealm_); }
526
527
JS_PUBLIC_API void JS_SetCompartmentPrivate(JS::Compartment* compartment,
528
void* data) {
529
compartment->data = data;
530
}
531
532
JS_PUBLIC_API void* JS_GetCompartmentPrivate(JS::Compartment* compartment) {
533
return compartment->data;
534
}
535
536
JS_PUBLIC_API void JS_MarkCrossZoneId(JSContext* cx, jsid id) {
537
cx->markId(id);
538
}
539
540
JS_PUBLIC_API void JS_MarkCrossZoneIdValue(JSContext* cx, const Value& value) {
541
cx->markAtomValue(value);
542
}
543
544
JS_PUBLIC_API void JS_SetZoneUserData(JS::Zone* zone, void* data) {
545
zone->data = data;
546
}
547
548
JS_PUBLIC_API void* JS_GetZoneUserData(JS::Zone* zone) { return zone->data; }
549
550
JS_PUBLIC_API bool JS_WrapObject(JSContext* cx, MutableHandleObject objp) {
551
AssertHeapIsIdle();
552
CHECK_THREAD(cx);
553
if (objp) {
554
JS::ExposeObjectToActiveJS(objp);
555
}
556
return cx->compartment()->wrap(cx, objp);
557
}
558
559
JS_PUBLIC_API bool JS_WrapValue(JSContext* cx, MutableHandleValue vp) {
560
AssertHeapIsIdle();
561
CHECK_THREAD(cx);
562
JS::ExposeValueToActiveJS(vp);
563
return cx->compartment()->wrap(cx, vp);
564
}
565
566
static void ReleaseAssertObjectHasNoWrappers(JSContext* cx,
567
HandleObject target) {
568
for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
569
if (c->lookupWrapper(target)) {
570
MOZ_CRASH("wrapper found for target object");
571
}
572
}
573
}
574
575
/*
576
* [SMDOC] Brain transplants.
577
*
578
* Not for beginners or the squeamish.
579
*
580
* Sometimes a web spec requires us to transplant an object from one
581
* compartment to another, like when a DOM node is inserted into a document in
582
* another window and thus gets "adopted". We cannot literally change the
583
* `.compartment()` of a `JSObject`; that would break the compartment
584
* invariants. However, as usual, we have a workaround using wrappers.
585
*
586
* Of all the wrapper-based workarounds we do, it's safe to say this is the
587
* most spectacular and questionable.
588
*
589
* `JS_TransplantObject(cx, origobj, target)` changes `origobj` into a
590
* simulacrum of `target`, using highly esoteric means. To JS code, the effect
591
* is as if `origobj` magically "became" `target`, but most often what actually
592
* happens is that `origobj` gets turned into a cross-compartment wrapper for
593
* `target`. The old behavior and contents of `origobj` are overwritten or
594
* discarded.
595
*
596
* Thus, to "transplant" an object from one compartment to another:
597
*
598
* 1. Let `origobj` be the object that you want to move. First, create a
599
* clone of it, `target`, in the destination compartment.
600
*
601
* In our DOM adoption example, `target` will be a Node of the same type as
602
* `origobj`, same content, but in the adopting document. We're not done
603
* yet: the spec for DOM adoption requires that `origobj.ownerDocument`
604
* actually change. All we've done so far is make a copy.
605
*
606
* 2. Call `JS_TransplantObject(cx, origobj, target)`. This typically turns
607
* `origobj` into a wrapper for `target`, so that any JS code that has a
608
* reference to `origobj` will observe it to have the behavior of `target`
609
* going forward. In addition, all existing wrappers for `origobj` are
610
* changed into wrappers for `target`, extending the illusion to those
611
* compartments as well.
612
*
613
* During navigation, we use the above technique to transplant the WindowProxy
614
* into the new Window's compartment.
615
*
616
* A few rules:
617
*
618
* - `origobj` and `target` must be two distinct objects of the same
619
* `JSClass`. Some classes may not support transplantation; WindowProxy
620
* objects and DOM nodes are OK.
621
*
622
* - `target` should be created specifically to be passed to this function.
623
* There must be no existing cross-compartment wrappers for it; ideally
624
* there shouldn't be any pointers to it at all, except the one passed in.
625
*
626
* - `target` shouldn't be used afterwards. Instead, `JS_TransplantObject`
627
* returns a pointer to the transplanted object, which might be `target`
628
* but might be some other object in the same compartment. Use that.
629
*
630
* The reason for this last rule is that JS_TransplantObject does very strange
631
* things in some cases, like swapping `target`'s brain with that of another
632
* object. Leaving `target` behaving like its former self is not a goal.
633
*
634
* We don't have a good way to recover from failure in this function, so
635
* we intentionally crash instead.
636
*/
637
638
static void CheckTransplantObject(JSObject* obj) {
639
#ifdef DEBUG
640
MOZ_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
641
JS::AssertCellIsNotGray(obj);
642
#endif
643
}
644
645
JS_PUBLIC_API JSObject* JS_TransplantObject(JSContext* cx, HandleObject origobj,
646
HandleObject target) {
647
AssertHeapIsIdle();
648
MOZ_ASSERT(origobj != target);
649
CheckTransplantObject(origobj);
650
CheckTransplantObject(target);
651
ReleaseAssertObjectHasNoWrappers(cx, target);
652
653
RootedObject newIdentity(cx);
654
655
// Don't allow a compacting GC to observe any intermediate state.
656
AutoDisableCompactingGC nocgc(cx);
657
658
AutoDisableProxyCheck adpc;
659
660
JS::Compartment* destination = target->compartment();
661
662
if (origobj->compartment() == destination) {
663
// If the original object is in the same compartment as the
664
// destination, then we know that we won't find a wrapper in the
665
// destination's cross compartment map and that the same
666
// object will continue to work.
667
AutoRealm ar(cx, origobj);
668
JSObject::swap(cx, origobj, target);
669
newIdentity = origobj;
670
} else if (ObjectWrapperMap::Ptr p = destination->lookupWrapper(origobj)) {
671
// There might already be a wrapper for the original object in
672
// the new compartment. If there is, we use its identity and swap
673
// in the contents of |target|.
674
newIdentity = p->value().get();
675
676
// When we remove origv from the wrapper map, its wrapper, newIdentity,
677
// must immediately cease to be a cross-compartment wrapper. Nuke it.
678
destination->removeWrapper(p);
679
NukeCrossCompartmentWrapper(cx, newIdentity);
680
681
AutoRealm ar(cx, newIdentity);
682
JSObject::swap(cx, newIdentity, target);
683
} else {
684
// Otherwise, we use |target| for the new identity object.
685
newIdentity = target;
686
}
687
688
// Now, iterate through other scopes looking for references to the old
689
// object, and update the relevant cross-compartment wrappers. We do this
690
// even if origobj is in the same compartment as target and thus
691
// `newIdentity == origobj`, because this process also clears out any
692
// cached wrapper state.
693
if (!RemapAllWrappersForObject(cx, origobj, newIdentity)) {
694
MOZ_CRASH();
695
}
696
697
// Lastly, update the original object to point to the new one.
698
if (origobj->compartment() != destination) {
699
RootedObject newIdentityWrapper(cx, newIdentity);
700
AutoRealm ar(cx, origobj);
701
if (!JS_WrapObject(cx, &newIdentityWrapper)) {
702
MOZ_CRASH();
703
}
704
MOZ_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
705
JSObject::swap(cx, origobj, newIdentityWrapper);
706
if (origobj->compartment()->lookupWrapper(newIdentity)) {
707
MOZ_ASSERT(origobj->is<CrossCompartmentWrapperObject>());
708
if (!origobj->compartment()->putWrapper(cx, newIdentity, origobj)) {
709
MOZ_CRASH();
710
}
711
}
712
}
713
714
// The new identity object might be one of several things. Return it to avoid
715
// ambiguity.
716
JS::AssertCellIsNotGray(newIdentity);
717
return newIdentity;
718
}
719
720
JS_FRIEND_API void js::RemapRemoteWindowProxies(
721
JSContext* cx, CompartmentTransplantCallback* callback,
722
MutableHandleObject target) {
723
AssertHeapIsIdle();
724
CheckTransplantObject(target);
725
ReleaseAssertObjectHasNoWrappers(cx, target);
726
727
// |target| can't be a remote proxy, because we expect it to get a CCW when
728
// wrapped across compartments.
729
MOZ_ASSERT(!js::IsDOMRemoteProxyObject(target));
730
731
// Don't allow a compacting GC to observe any intermediate state.
732
AutoDisableCompactingGC nocgc(cx);
733
734
AutoDisableProxyCheck adpc;
735
736
AutoEnterOOMUnsafeRegion oomUnsafe;
737
if (!CheckSystemRecursionLimit(cx)) {
738
oomUnsafe.crash("js::RemapRemoteWindowProxies");
739
}
740
741
RootedObject targetCompartmentProxy(cx);
742
JS::RootedVector<JSObject*> otherProxies(cx);
743
744
// Use the callback to find remote proxies in all compartments that match
745
// whatever criteria callback uses.
746
for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
747
RootedObject remoteProxy(cx, callback->getObjectToTransplant(c));
748
if (!remoteProxy) {
749
continue;
750
}
751
// The object the callback returns should be a DOM remote proxy object in
752
// the compartment c. We rely on it being a DOM remote proxy because that
753
// means that it won't have any cross-compartment wrappers.
754
MOZ_ASSERT(js::IsDOMRemoteProxyObject(remoteProxy));
755
MOZ_ASSERT(remoteProxy->compartment() == c);
756
CheckTransplantObject(remoteProxy);
757
758
// Immediately turn the DOM remote proxy object into a dead proxy object
759
// so we don't have to worry about anything weird going on with it.
760
js::NukeNonCCWProxy(cx, remoteProxy);
761
762
if (remoteProxy->compartment() == target->compartment()) {
763
targetCompartmentProxy = remoteProxy;
764
} else if (!otherProxies.append(remoteProxy)) {
765
oomUnsafe.crash("js::RemapRemoteWindowProxies");
766
}
767
}
768
769
// If there was a remote proxy in |target|'s compartment, we need to use it
770
// instead of |target|, in case it had any references, so swap it. Do this
771
// before any other compartment so that the target object will be set up
772
// correctly before we start wrapping it into other compartments.
773
if (targetCompartmentProxy) {
774
AutoRealm ar(cx, targetCompartmentProxy);
775
JSObject::swap(cx, targetCompartmentProxy, target);
776
target.set(targetCompartmentProxy);
777
}
778
779
for (JSObject*& obj : otherProxies) {
780
RootedObject deadWrapper(cx, obj);
781
js::RemapDeadWrapper(cx, deadWrapper, target);
782
}
783
}
784
785
/*
786
* Recompute all cross-compartment wrappers for an object, resetting state.
787
* Gecko uses this to clear Xray wrappers when doing a navigation that reuses
788
* the inner window and global object.
789
*/
790
JS_PUBLIC_API bool JS_RefreshCrossCompartmentWrappers(JSContext* cx,
791
HandleObject obj) {
792
return RemapAllWrappersForObject(cx, obj, obj);
793
}
794
795
typedef struct JSStdName {
796
size_t atomOffset; /* offset of atom pointer in JSAtomState */
797
JSProtoKey key;
798
bool isDummy() const { return key == JSProto_Null; }
799
bool isSentinel() const { return key == JSProto_LIMIT; }
800
} JSStdName;
801
802
static const JSStdName* LookupStdName(const JSAtomState& names, JSAtom* name,
803
const JSStdName* table) {
804
for (unsigned i = 0; !table[i].isSentinel(); i++) {
805
if (table[i].isDummy()) {
806
continue;
807
}
808
JSAtom* atom = AtomStateOffsetToName(names, table[i].atomOffset);
809
MOZ_ASSERT(atom);
810
if (name == atom) {
811
return &table[i];
812
}
813
}
814
815
return nullptr;
816
}
817
818
/*
819
* Table of standard classes, indexed by JSProtoKey. For entries where the
820
* JSProtoKey does not correspond to a class with a meaningful constructor, we
821
* insert a null entry into the table.
822
*/
823
#define STD_NAME_ENTRY(name, init, clasp) {NAME_OFFSET(name), JSProto_##name},
824
#define STD_DUMMY_ENTRY(name, init, dummy) {0, JSProto_Null},
825
static const JSStdName standard_class_names[] = {
826
JS_FOR_PROTOTYPES(STD_NAME_ENTRY, STD_DUMMY_ENTRY){0, JSProto_LIMIT}};
827
828
/*
829
* Table of top-level function and constant names and the JSProtoKey of the
830
* standard class that initializes them.
831
*/
832
static const JSStdName builtin_property_names[] = {
833
{NAME_OFFSET(eval), JSProto_Object},
834
835
/* Global properties and functions defined by the Number class. */
836
{NAME_OFFSET(NaN), JSProto_Number},
837
{NAME_OFFSET(Infinity), JSProto_Number},
838
{NAME_OFFSET(isNaN), JSProto_Number},
839
{NAME_OFFSET(isFinite), JSProto_Number},
840
{NAME_OFFSET(parseFloat), JSProto_Number},
841
{NAME_OFFSET(parseInt), JSProto_Number},
842
843
/* String global functions. */
844
{NAME_OFFSET(escape), JSProto_String},
845
{NAME_OFFSET(unescape), JSProto_String},
846
{NAME_OFFSET(decodeURI), JSProto_String},
847
{NAME_OFFSET(encodeURI), JSProto_String},
848
{NAME_OFFSET(decodeURIComponent), JSProto_String},
849
{NAME_OFFSET(encodeURIComponent), JSProto_String},
850
{NAME_OFFSET(uneval), JSProto_String},
851
852
{0, JSProto_LIMIT}};
853
854
JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx, HandleObject obj,
855
HandleId id, bool* resolved) {
856
const JSStdName* stdnm;
857
858
AssertHeapIsIdle();
859
CHECK_THREAD(cx);
860
cx->check(obj, id);
861
862
Handle<GlobalObject*> global = obj.as<GlobalObject>();
863
*resolved = false;
864
865
if (!JSID_IS_ATOM(id)) {
866
return true;
867
}
868
869
/* Check whether we're resolving 'undefined', and define it if so. */
870
JSAtom* idAtom = JSID_TO_ATOM(id);
871
if (idAtom == cx->names().undefined) {
872
*resolved = true;
873
return DefineDataProperty(
874
cx, global, id, UndefinedHandleValue,
875
JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING);
876
}
877
878
// Resolve a "globalThis" self-referential property if necessary.
879
if (idAtom == cx->names().globalThis) {
880
return GlobalObject::maybeResolveGlobalThis(cx, global, resolved);
881
}
882
883
/* Try for class constructors/prototypes named by well-known atoms. */
884
stdnm = LookupStdName(cx->names(), idAtom, standard_class_names);
885
886
/* Try less frequently used top-level functions and constants. */
887
if (!stdnm) {
888
stdnm = LookupStdName(cx->names(), idAtom, builtin_property_names);
889
}
890
891
if (stdnm && GlobalObject::skipDeselectedConstructor(cx, stdnm->key)) {
892
stdnm = nullptr;
893
}
894
895
// If this class is anonymous, then it doesn't exist as a global
896
// property, so we won't resolve anything.
897
JSProtoKey key = stdnm ? stdnm->key : JSProto_Null;
898
if (key != JSProto_Null && key != JSProto_AsyncFunction &&
899
key != JSProto_GeneratorFunction &&
900
key != JSProto_AsyncGeneratorFunction) {
901
const JSClass* clasp = ProtoKeyToClass(key);
902
if (!clasp || clasp->specShouldDefineConstructor()) {
903
if (!GlobalObject::ensureConstructor(cx, global, key)) {
904
return false;
905
}
906
907
*resolved = true;
908
return true;
909
}
910
}
911
912
// There is no such property to resolve. An ordinary resolve hook would
913
// just return true at this point. But the global object is special in one
914
// more way: its prototype chain is lazily initialized. That is,
915
// global->getProto() might be null right now because we haven't created
916
// Object.prototype yet. Force it now.
917
return GlobalObject::getOrCreateObjectPrototype(cx, global);
918
}
919
920
JS_PUBLIC_API bool JS_MayResolveStandardClass(const JSAtomState& names, jsid id,
921
JSObject* maybeObj) {
922
MOZ_ASSERT_IF(maybeObj, maybeObj->is<GlobalObject>());
923
924
// The global object's resolve hook is special: JS_ResolveStandardClass
925
// initializes the prototype chain lazily. Only attempt to optimize here
926
// if we know the prototype chain has been initialized.
927
if (!maybeObj || !maybeObj->staticPrototype()) {
928
return true;
929
}
930
931
if (!JSID_IS_ATOM(id)) {
932
return false;
933
}
934
935
JSAtom* atom = JSID_TO_ATOM(id);
936
937
// This will return true even for deselected constructors. (To do
938
// better, we need a JSContext here; it's fine as it is.)
939
940
return atom == names.undefined || atom == names.globalThis ||
941
LookupStdName(names, atom, standard_class_names) ||
942
LookupStdName(names, atom, builtin_property_names);
943
}
944
945
JS_PUBLIC_API bool JS_EnumerateStandardClasses(JSContext* cx,
946
HandleObject obj) {
947
AssertHeapIsIdle();
948
CHECK_THREAD(cx);
949
cx->check(obj);
950
Handle<GlobalObject*> global = obj.as<GlobalObject>();
951
return GlobalObject::initStandardClasses(cx, global);
952
}
953
954
static bool EnumerateStandardClassesInTable(JSContext* cx,
955
Handle<GlobalObject*> global,
956
MutableHandleIdVector properties,
957
const JSStdName* table,
958
bool includeResolved) {
959
for (unsigned i = 0; !table[i].isSentinel(); i++) {
960
if (table[i].isDummy()) {
961
continue;
962
}
963
964
JSProtoKey key = table[i].key;
965
966
// If the standard class has been resolved, the properties have been
967
// defined on the global so we don't need to add them here.
968
if (!includeResolved && global->isStandardClassResolved(key)) {
969
continue;
970
}
971
972
if (GlobalObject::skipDeselectedConstructor(cx, key)) {
973
continue;
974
}
975
976
// Async(Function|Generator) and Generator don't yet use ClassSpec.
977
if (key == JSProto_AsyncFunction || key == JSProto_GeneratorFunction ||
978
key == JSProto_AsyncGeneratorFunction) {
979
continue;
980
}
981
982
if (const JSClass* clasp = ProtoKeyToClass(key)) {
983
if (!clasp->specShouldDefineConstructor()) {
984
continue;
985
}
986
}
987
988
jsid id = NameToId(AtomStateOffsetToName(cx->names(), table[i].atomOffset));
989
if (!properties.append(id)) {
990
return false;
991
}
992
}
993
994
return true;
995
}
996
997
static bool EnumerateStandardClasses(JSContext* cx, JS::HandleObject obj,
998
JS::MutableHandleIdVector properties,
999
bool enumerableOnly,
1000
bool includeResolved) {
1001
if (enumerableOnly) {
1002
// There are no enumerable standard classes and "undefined" is
1003
// not enumerable.
1004
return true;
1005
}
1006
1007
Handle<GlobalObject*> global = obj.as<GlobalObject>();
1008
1009
// It's fine to always append |undefined| here, it's non-configurable and
1010
// the enumeration code filters duplicates.
1011
if (!properties.append(NameToId(cx->names().undefined))) {
1012
return false;
1013
}
1014
1015
bool resolved = false;
1016
if (!GlobalObject::maybeResolveGlobalThis(cx, global, &resolved)) {
1017
return false;
1018
}
1019
if (resolved || includeResolved) {
1020
if (!properties.append(NameToId(cx->names().globalThis))) {
1021
return false;
1022
}
1023
}
1024
1025
if (!EnumerateStandardClassesInTable(cx, global, properties,
1026
standard_class_names, includeResolved)) {
1027
return false;
1028
}
1029
if (!EnumerateStandardClassesInTable(
1030
cx, global, properties, builtin_property_names, includeResolved)) {
1031
return false;
1032
}
1033
1034
return true;
1035
}
1036
1037
JS_PUBLIC_API bool JS_NewEnumerateStandardClasses(
1038
JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
1039
bool enumerableOnly) {
1040
return EnumerateStandardClasses(cx, obj, properties, enumerableOnly, false);
1041
}
1042
1043
JS_PUBLIC_API bool JS_NewEnumerateStandardClassesIncludingResolved(
1044
JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
1045
bool enumerableOnly) {
1046
return EnumerateStandardClasses(cx, obj, properties, enumerableOnly, true);
1047
}
1048
1049
JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key,
1050
MutableHandleObject objp) {
1051
AssertHeapIsIdle();
1052
CHECK_THREAD(cx);
1053
JSObject* obj = GlobalObject::getOrCreateConstructor(cx, key);
1054
if (!obj) {
1055
return false;
1056
}
1057
objp.set(obj);
1058
return true;
1059
}
1060
1061
JS_PUBLIC_API bool JS_GetClassPrototype(JSContext* cx, JSProtoKey key,
1062
MutableHandleObject objp) {
1063
AssertHeapIsIdle();
1064
CHECK_THREAD(cx);
1065
JSObject* proto = GlobalObject::getOrCreatePrototype(cx, key);
1066
if (!proto) {
1067
return false;
1068
}
1069
objp.set(proto);
1070
return true;
1071
}
1072
1073
namespace JS {
1074
1075
JS_PUBLIC_API void ProtoKeyToId(JSContext* cx, JSProtoKey key,
1076
MutableHandleId idp) {
1077
idp.set(NameToId(ClassName(key, cx)));
1078
}
1079
1080
} /* namespace JS */
1081
1082
JS_PUBLIC_API JSProtoKey JS_IdToProtoKey(JSContext* cx, HandleId id) {
1083
AssertHeapIsIdle();
1084
CHECK_THREAD(cx);
1085
cx->check(id);
1086
1087
if (!JSID_IS_ATOM(id)) {
1088
return JSProto_Null;
1089
}
1090
1091
JSAtom* atom = JSID_TO_ATOM(id);
1092
const JSStdName* stdnm =
1093
LookupStdName(cx->names(), atom, standard_class_names);
1094
if (!stdnm) {
1095
return JSProto_Null;
1096
}
1097
1098
if (GlobalObject::skipDeselectedConstructor(cx, stdnm->key)) {
1099
return JSProto_Null;
1100
}
1101
1102
MOZ_ASSERT(MOZ_ARRAY_LENGTH(standard_class_names) == JSProto_LIMIT + 1);
1103
return static_cast<JSProtoKey>(stdnm - standard_class_names);
1104
}
1105
1106
extern JS_PUBLIC_API bool JS_IsGlobalObject(JSObject* obj) {
1107
return obj->is<GlobalObject>();
1108
}
1109
1110
extern JS_PUBLIC_API JSObject* JS_GlobalLexicalEnvironment(JSObject* obj) {
1111
return &obj->as<GlobalObject>().lexicalEnvironment();
1112
}
1113
1114
extern JS_PUBLIC_API bool JS_HasExtensibleLexicalEnvironment(JSObject* obj) {
1115
return obj->is<GlobalObject>() ||
1116
ObjectRealm::get(obj).getNonSyntacticLexicalEnvironment(obj);
1117
}
1118
1119
extern JS_PUBLIC_API JSObject* JS_ExtensibleLexicalEnvironment(JSObject* obj) {
1120
JSObject* lexical = nullptr;
1121
if (obj->is<GlobalObject>()) {
1122
lexical = JS_GlobalLexicalEnvironment(obj);
1123
} else {
1124
lexical = ObjectRealm::get(obj).getNonSyntacticLexicalEnvironment(obj);
1125
}
1126
MOZ_ASSERT(lexical);
1127
return lexical;
1128
}
1129
1130
JS_PUBLIC_API JSObject* JS::CurrentGlobalOrNull(JSContext* cx) {
1131
AssertHeapIsIdleOrIterating();
1132
CHECK_THREAD(cx);
1133
if (!cx->realm()) {
1134
return nullptr;
1135
}
1136
return cx->global();
1137
}
1138
1139
JS_PUBLIC_API JSObject* JS::GetNonCCWObjectGlobal(JSObject* obj) {
1140
AssertHeapIsIdleOrIterating();
1141
MOZ_DIAGNOSTIC_ASSERT(!IsCrossCompartmentWrapper(obj));
1142
return &obj->nonCCWGlobal();
1143
}
1144
1145
JS_PUBLIC_API bool JS::detail::ComputeThis(JSContext* cx, Value* vp,
1146
MutableHandleObject thisObject) {
1147
AssertHeapIsIdle();
1148
cx->check(vp[0], vp[1]);
1149
1150
MutableHandleValue thisv = MutableHandleValue::fromMarkedLocation(&vp[1]);
1151
if (!BoxNonStrictThis(cx, thisv, thisv)) {
1152
return false;
1153
}
1154
1155
thisObject.set(&thisv.toObject());
1156
return true;
1157
}
1158
1159
static bool gProfileTimelineRecordingEnabled = false;
1160
1161
JS_PUBLIC_API void JS::SetProfileTimelineRecordingEnabled(bool enabled) {
1162
gProfileTimelineRecordingEnabled = enabled;
1163
}
1164
1165
JS_PUBLIC_API bool JS::IsProfileTimelineRecordingEnabled() {
1166
return gProfileTimelineRecordingEnabled;
1167
}
1168
1169
JS_PUBLIC_API void* JS_malloc(JSContext* cx, size_t nbytes) {
1170
AssertHeapIsIdle();
1171
CHECK_THREAD(cx);
1172
return static_cast<void*>(cx->maybe_pod_malloc<uint8_t>(nbytes));
1173
}
1174
1175
JS_PUBLIC_API void* JS_realloc(JSContext* cx, void* p, size_t oldBytes,
1176
size_t newBytes) {
1177
AssertHeapIsIdle();
1178
CHECK_THREAD(cx);
1179
return static_cast<void*>(cx->maybe_pod_realloc<uint8_t>(
1180
static_cast<uint8_t*>(p), oldBytes, newBytes));
1181
}
1182
1183
JS_PUBLIC_API void JS_free(JSContext* cx, void* p) { return js_free(p); }
1184
1185
JS_PUBLIC_API void* JS_string_malloc(JSContext* cx, size_t nbytes) {
1186
AssertHeapIsIdle();
1187
CHECK_THREAD(cx);
1188
return static_cast<void*>(
1189
cx->maybe_pod_arena_malloc<uint8_t>(js::StringBufferArena, nbytes));
1190
}
1191
1192
JS_PUBLIC_API void* JS_string_realloc(JSContext* cx, void* p, size_t oldBytes,
1193
size_t newBytes) {
1194
AssertHeapIsIdle();
1195
CHECK_THREAD(cx);
1196
return static_cast<void*>(cx->maybe_pod_arena_realloc<uint8_t>(
1197
js::StringBufferArena, static_cast<uint8_t*>(p), oldBytes, newBytes));
1198
}
1199
1200
JS_PUBLIC_API void JS_string_free(JSContext* cx, void* p) { return js_free(p); }
1201
1202
JS_PUBLIC_API void JS_freeop(JSFreeOp* fop, void* p) {
1203
return fop->freeUntracked(p);
1204
}
1205
1206
JS_PUBLIC_API void JS::AddAssociatedMemory(JSObject* obj, size_t nbytes,
1207
JS::MemoryUse use) {
1208
MOZ_ASSERT(obj);
1209
if (!nbytes) {
1210
return;
1211
}
1212
1213
Zone* zone = obj->zone();
1214
zone->addCellMemory(obj, nbytes, js::MemoryUse(use));
1215
zone->maybeMallocTriggerZoneGC();
1216
}
1217
1218
JS_PUBLIC_API void JS::RemoveAssociatedMemory(JSObject* obj, size_t nbytes,
1219
JS::MemoryUse use) {
1220
MOZ_ASSERT(obj);
1221
if (!nbytes) {
1222
return;
1223
}
1224
1225
JSRuntime* rt = obj->runtimeFromAnyThread();
1226
rt->defaultFreeOp()->removeCellMemory(obj, nbytes, js::MemoryUse(use));
1227
}
1228
1229
#undef JS_AddRoot
1230
1231
JS_PUBLIC_API bool JS_AddExtraGCRootsTracer(JSContext* cx,
1232
JSTraceDataOp traceOp, void* data) {
1233
return cx->runtime()->gc.addBlackRootsTracer(traceOp, data);
1234
}
1235
1236
JS_PUBLIC_API void JS_RemoveExtraGCRootsTracer(JSContext* cx,
1237
JSTraceDataOp traceOp,
1238
void* data) {
1239
return cx->runtime()->gc.removeBlackRootsTracer(traceOp, data);
1240
}
1241
1242
JS_PUBLIC_API bool JS::IsIdleGCTaskNeeded(JSRuntime* rt) {
1243
// Currently, we only collect nursery during idle time.
1244
return rt->gc.nursery().shouldCollect();
1245
}
1246
1247
JS_PUBLIC_API void JS::RunIdleTimeGCTask(JSRuntime* rt) {
1248
gc::GCRuntime& gc = rt->gc;
1249
if (gc.nursery().shouldCollect()) {
1250
gc.minorGC(JS::GCReason::IDLE_TIME_COLLECTION);
1251
}
1252
}
1253
1254
JS_PUBLIC_API void JS_GC(JSContext* cx, JS::GCReason reason) {
1255
AssertHeapIsIdle();
1256
JS::PrepareForFullGC(cx);
1257
cx->runtime()->gc.gc(GC_NORMAL, reason);
1258
}
1259
1260
JS_PUBLIC_API void JS_MaybeGC(JSContext* cx) {
1261
AssertHeapIsIdle();
1262
cx->runtime()->gc.maybeGC();
1263
}
1264
1265
JS_PUBLIC_API void JS_SetGCCallback(JSContext* cx, JSGCCallback cb,
1266
void* data) {
1267
AssertHeapIsIdle();
1268
cx->runtime()->gc.setGCCallback(cb, data);
1269
}
1270
1271
JS_PUBLIC_API void JS_SetObjectsTenuredCallback(JSContext* cx,
1272
JSObjectsTenuredCallback cb,
1273
void* data) {
1274
AssertHeapIsIdle();
1275
cx->runtime()->gc.setObjectsTenuredCallback(cb, data);
1276
}
1277
1278
JS_PUBLIC_API bool JS_AddFinalizeCallback(JSContext* cx, JSFinalizeCallback cb,
1279
void* data) {
1280
AssertHeapIsIdle();
1281
return cx->runtime()->gc.addFinalizeCallback(cb, data);
1282
}
1283
1284
JS_PUBLIC_API void JS_RemoveFinalizeCallback(JSContext* cx,
1285
JSFinalizeCallback cb) {
1286
cx->runtime()->gc.removeFinalizeCallback(cb);
1287
}
1288
1289
JS_PUBLIC_API void JS::SetHostCleanupFinalizationGroupCallback(
1290
JSContext* cx, JSHostCleanupFinalizationGroupCallback cb, void* data) {
1291
AssertHeapIsIdle();
1292
cx->runtime()->gc.setHostCleanupFinalizationGroupCallback(cb, data);
1293
}
1294
1295
JS_PUBLIC_API bool JS::CleanupQueuedFinalizationGroup(JSContext* cx,
1296
HandleObject group) {
1297
AssertHeapIsIdle();
1298
CHECK_THREAD(cx);
1299
cx->check(group);
1300
return cx->runtime()->gc.cleanupQueuedFinalizationGroup(
1301
cx, group.as<FinalizationGroupObject>());
1302
}
1303
1304
JS_PUBLIC_API bool JS_AddWeakPointerZonesCallback(JSContext* cx,
1305
JSWeakPointerZonesCallback cb,
1306
void* data) {
1307
AssertHeapIsIdle();
1308
return cx->runtime()->gc.addWeakPointerZonesCallback(cb, data);
1309
}
1310
1311
JS_PUBLIC_API void JS_RemoveWeakPointerZonesCallback(
1312
JSContext* cx, JSWeakPointerZonesCallback cb) {
1313
cx->runtime()->gc.removeWeakPointerZonesCallback(cb);
1314
}
1315
1316
JS_PUBLIC_API bool JS_AddWeakPointerCompartmentCallback(
1317
JSContext* cx, JSWeakPointerCompartmentCallback cb, void* data) {
1318
AssertHeapIsIdle();
1319
return cx->runtime()->gc.addWeakPointerCompartmentCallback(cb, data);
1320
}
1321
1322
JS_PUBLIC_API void JS_RemoveWeakPointerCompartmentCallback(
1323
JSContext* cx, JSWeakPointerCompartmentCallback cb) {
1324
cx->runtime()->gc.removeWeakPointerCompartmentCallback(cb);
1325
}
1326
1327
JS_PUBLIC_API void JS_UpdateWeakPointerAfterGC(JS::Heap<JSObject*>* objp) {
1328
JS_UpdateWeakPointerAfterGCUnbarriered(objp->unsafeGet());
1329
}
1330
1331
JS_PUBLIC_API void JS_UpdateWeakPointerAfterGCUnbarriered(JSObject** objp) {
1332
if (IsAboutToBeFinalizedUnbarriered(objp)) {
1333
*objp = nullptr;
1334
}
1335
}
1336
1337
JS_PUBLIC_API void JS_SetGCParameter(JSContext* cx, JSGCParamKey key,
1338
uint32_t value) {
1339
MOZ_ALWAYS_TRUE(cx->runtime()->gc.setParameter(key, value));
1340
}
1341
1342
JS_PUBLIC_API void JS_ResetGCParameter(JSContext* cx, JSGCParamKey key) {
1343
cx->runtime()->gc.resetParameter(key);
1344
}
1345
1346
JS_PUBLIC_API uint32_t JS_GetGCParameter(JSContext* cx, JSGCParamKey key) {
1347
return cx->runtime()->gc.getParameter(key);
1348
}
1349
1350
JS_PUBLIC_API void JS_SetGCParametersBasedOnAvailableMemory(JSContext* cx,
1351
uint32_t availMem) {
1352
struct JSGCConfig {
1353
JSGCParamKey key;
1354
uint32_t value;
1355
};
1356
1357
static const JSGCConfig minimal[] = {
1358
{JSGC_SLICE_TIME_BUDGET_MS, 30},
1359
{JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1360
{JSGC_HIGH_FREQUENCY_HIGH_LIMIT, 40},
1361
{JSGC_HIGH_FREQUENCY_LOW_LIMIT, 0},
1362
{JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, 300},
1363
{JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, 120},
1364
{JSGC_LOW_FREQUENCY_HEAP_GROWTH, 120},
1365
{JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1366
{JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1367
{JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1368
{JSGC_ALLOCATION_THRESHOLD, 1},
1369
{JSGC_MODE, JSGC_MODE_ZONE_INCREMENTAL}};
1370
1371
static const JSGCConfig nominal[] = {
1372
{JSGC_SLICE_TIME_BUDGET_MS, 30},
1373
{JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1000},
1374
{JSGC_HIGH_FREQUENCY_HIGH_LIMIT, 500},
1375
{JSGC_HIGH_FREQUENCY_LOW_LIMIT, 100},
1376
{JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, 300},
1377
{JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, 150},
1378
{JSGC_LOW_FREQUENCY_HEAP_GROWTH, 150},
1379
{JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1380
{JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1381
{JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1382
{JSGC_ALLOCATION_THRESHOLD, 30},
1383
{JSGC_MODE, JSGC_MODE_ZONE}};
1384
1385
const auto& configSet = availMem > 512 ? nominal : minimal;
1386
for (const auto& config : configSet) {
1387
JS_SetGCParameter(cx, config.key, config.value);
1388
}
1389
}
1390
1391
JS_PUBLIC_API JSString* JS_NewExternalString(
1392
JSContext* cx, const char16_t* chars, size_t length,
1393
const JSExternalStringCallbacks* callbacks) {
1394
AssertHeapIsIdle();
1395
CHECK_THREAD(cx);
1396
return JSExternalString::new_(cx, chars, length, callbacks);
1397
}
1398
1399
JS_PUBLIC_API JSString* JS_NewMaybeExternalString(
1400
JSContext* cx, const char16_t* chars, size_t length,
1401
const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) {
1402
AssertHeapIsIdle();
1403
CHECK_THREAD(cx);
1404
return NewMaybeExternalString(cx, chars, length, callbacks,
1405
allocatedExternal);
1406
}
1407
1408
extern JS_PUBLIC_API bool JS_IsExternalString(JSString* str) {
1409
return str->isExternal();
1410
}
1411
1412
extern JS_PUBLIC_API const JSExternalStringCallbacks*
1413
JS_GetExternalStringCallbacks(JSString* str) {
1414
return str->asExternal().callbacks();
1415
}
1416
1417
static void SetNativeStackLimit(JSContext* cx, JS::StackKind kind,
1418
size_t stackSize) {
1419
#if JS_STACK_GROWTH_DIRECTION > 0
1420
if (stackSize == 0) {
1421
cx->nativeStackLimit[kind] = UINTPTR_MAX;
1422
} else {
1423
MOZ_ASSERT(cx->nativeStackBase <= size_t(-1) - stackSize);
1424
cx->nativeStackLimit[kind] = cx->nativeStackBase + stackSize - 1;
1425
}
1426
#else
1427
if (stackSize == 0) {
1428
cx->nativeStackLimit[kind] = 0;
1429
} else {
1430
MOZ_ASSERT(cx->nativeStackBase >= stackSize);
1431
cx->nativeStackLimit[kind] = cx->nativeStackBase - (stackSize - 1);
1432
}
1433
#endif
1434
}
1435
1436
JS_PUBLIC_API void JS_SetNativeStackQuota(JSContext* cx,
1437
size_t systemCodeStackSize,
1438
size_t trustedScriptStackSize,
1439
size_t untrustedScriptStackSize) {
1440
MOZ_ASSERT(!cx->activation());
1441
1442
if (!trustedScriptStackSize) {
1443
trustedScriptStackSize = systemCodeStackSize;
1444
} else {
1445
MOZ_ASSERT(trustedScriptStackSize < systemCodeStackSize);
1446
}
1447
1448
if (!untrustedScriptStackSize) {
1449
untrustedScriptStackSize = trustedScriptStackSize;
1450
} else {
1451
MOZ_ASSERT(untrustedScriptStackSize < trustedScriptStackSize);
1452
}
1453
1454
SetNativeStackLimit(cx, JS::StackForSystemCode, systemCodeStackSize);
1455
SetNativeStackLimit(cx, JS::StackForTrustedScript, trustedScriptStackSize);
1456
SetNativeStackLimit(cx, JS::StackForUntrustedScript,
1457
untrustedScriptStackSize);
1458
1459
if (cx->isMainThreadContext()) {
1460
cx->initJitStackLimit();
1461
}
1462
}
1463
1464
/************************************************************************/
1465
1466
JS_PUBLIC_API bool JS_ValueToId(JSContext* cx, HandleValue value,
1467
MutableHandleId idp) {
1468
AssertHeapIsIdle();
1469
CHECK_THREAD(cx);
1470
cx->check(value);
1471
return ValueToId<CanGC>(cx, value, idp);
1472
}
1473
1474
JS_PUBLIC_API bool JS_StringToId(JSContext* cx, HandleString string,
1475
MutableHandleId idp) {
1476
AssertHeapIsIdle();
1477
CHECK_THREAD(cx);
1478
cx->check(string);
1479
RootedValue value(cx, StringValue(string));
1480
return ValueToId<CanGC>(cx, value, idp);
1481
}
1482
1483
JS_PUBLIC_API bool JS_IdToValue(JSContext* cx, jsid id, MutableHandleValue vp) {
1484
AssertHeapIsIdle();
1485
CHECK_THREAD(cx);
1486
cx->check(id);
1487
vp.set(IdToValue(id));
1488
cx->check(vp);
1489
return true;
1490
}
1491
1492
JS_PUBLIC_API bool JS::ToPrimitive(JSContext* cx, HandleObject obj, JSType hint,
1493
MutableHandleValue vp) {
1494
AssertHeapIsIdle();
1495
CHECK_THREAD(cx);
1496
cx->check(obj);
1497
MOZ_ASSERT(obj != nullptr);
1498
MOZ_ASSERT(hint == JSTYPE_UNDEFINED || hint == JSTYPE_STRING ||
1499
hint == JSTYPE_NUMBER);
1500
vp.setObject(*obj);
1501
return ToPrimitiveSlow(cx, hint, vp);
1502
}
1503
1504
JS_PUBLIC_API bool JS::GetFirstArgumentAsTypeHint(JSContext* cx, CallArgs args,
1505
JSType* result) {
1506
if (!args.get(0).isString()) {
1507
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1508
JSMSG_NOT_EXPECTED_TYPE, "Symbol.toPrimitive",
1509
"\"string\", \"number\", or \"default\"",
1510
InformalValueTypeName(args.get(0)));
1511
return false;
1512
}
1513
1514
RootedString str(cx, args.get(0).toString());
1515
bool match;
1516
1517
if (!EqualStrings(cx, str, cx->names().default_, &match)) {
1518
return false;
1519
}
1520
if (match) {
1521
*result = JSTYPE_UNDEFINED;
1522
return true;
1523
}
1524
1525
if (!EqualStrings(cx, str, cx->names().string, &match)) {
1526
return false;
1527
}
1528
if (match) {
1529
*result = JSTYPE_STRING;
1530
return true;
1531
}
1532
1533
if (!EqualStrings(cx, str, cx->names().number, &match)) {
1534
return false;
1535
}
1536
if (match) {
1537
*result = JSTYPE_NUMBER;
1538
return true;
1539
}
1540
1541
UniqueChars bytes;
1542
const char* source = ValueToSourceForError(cx, args.get(0), bytes);
1543
if (!source) {
1544
ReportOutOfMemory(cx);
1545
return false;
1546
}
1547
1548
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
1549
JSMSG_NOT_EXPECTED_TYPE, "Symbol.toPrimitive",
1550
"\"string\", \"number\", or \"default\"", source);
1551
return false;
1552
}
1553
1554
JS_PUBLIC_API JSObject* JS_InitClass(JSContext* cx, HandleObject obj,
1555
HandleObject parent_proto,
1556
const JSClass* clasp, JSNative constructor,
1557
unsigned nargs, const JSPropertySpec* ps,
1558
const JSFunctionSpec* fs,
1559
const JSPropertySpec* static_ps,
1560
const JSFunctionSpec* static_fs) {
1561
AssertHeapIsIdle();
1562
CHECK_THREAD(cx);
1563
cx->check(obj, parent_proto);
1564
return InitClass(cx, obj, parent_proto, clasp, constructor, nargs, ps, fs,
1565
static_ps, static_fs);
1566
}
1567
1568
JS_PUBLIC_API bool JS_LinkConstructorAndPrototype(JSContext* cx,
1569
HandleObject ctor,
1570
HandleObject proto) {
1571
return LinkConstructorAndPrototype(cx, ctor, proto);
1572
}
1573
1574
JS_PUBLIC_API const JSClass* JS_GetClass(JSObject* obj) {
1575
return obj->getClass();
1576
}
1577
1578
JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx, HandleObject obj,
1579
const JSClass* clasp, CallArgs* args) {
1580
AssertHeapIsIdle();
1581
CHECK_THREAD(cx);
1582
#ifdef DEBUG
1583
if (args) {
1584
cx->check(obj);
1585
cx->check(args->thisv(), args->calleev());
1586
}
1587
#endif
1588
if (!obj || obj->getClass() != clasp) {
1589
if (args) {
1590
ReportIncompatibleMethod(cx, *args, clasp);
1591
}
1592
return false;
1593
}
1594
return true;
1595
}
1596
1597
JS_PUBLIC_API bool JS_HasInstance(JSContext* cx, HandleObject obj,
1598
HandleValue value, bool* bp) {
1599
AssertHeapIsIdle();
1600
cx->check(obj, value);
1601
return HasInstance(cx, obj, value, bp);
1602
}
1603
1604
JS_PUBLIC_API void* JS_GetPrivate(JSObject* obj) {
1605
/* This function can be called by a finalizer. */
1606
return obj->as<NativeObject>().getPrivate();
1607
}
1608
1609
JS_PUBLIC_API void JS_SetPrivate(JSObject* obj, void* data) {
1610
/* This function can be called by a finalizer. */
1611
obj->as<NativeObject>().setPrivate(data);
1612
}
1613
1614
JS_PUBLIC_API void* JS_GetInstancePrivate(JSContext* cx, HandleObject obj,
1615
const JSClass* clasp,
1616
CallArgs* args) {
1617
if (!JS_InstanceOf(cx, obj, clasp, args)) {
1618
return nullptr;
1619
}
1620
return obj->as<NativeObject>().getPrivate();
1621
}
1622
1623
JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx, HandleObject proto) {
1624
AssertHeapIsIdle();
1625
CHECK_THREAD(cx);
1626
cx->check(proto);
1627
1628
RootedValue cval(cx);
1629
if (!GetProperty(cx, proto, proto, cx->names().constructor, &cval)) {
1630
return nullptr;
1631
}
1632
if (!IsFunctionObject(cval)) {
1633
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1634
JSMSG_NO_CONSTRUCTOR, proto->getClass()->name);
1635
return nullptr;
1636
}
1637
return &cval.toObject();
1638
}
1639
1640
bool JS::RealmBehaviors::extraWarnings(JSContext* cx) const {
1641
return extraWarningsOverride_.get(cx->options().extraWarnings());
1642
}
1643
1644
JS::RealmCreationOptions&
1645
JS::RealmCreationOptions::setNewCompartmentInSystemZone() {
1646
compSpec_ = CompartmentSpecifier::NewCompartmentInSystemZone;
1647
comp_ = nullptr;
1648
return *this;
1649
}
1650
1651
JS::RealmCreationOptions&
1652
JS::RealmCreationOptions::setNewCompartmentInExistingZone(JSObject* obj) {
1653
compSpec_ = CompartmentSpecifier::NewCompartmentInExistingZone;
1654
zone_ = obj->zone();
1655
return *this;
1656
}
1657
1658
JS::RealmCreationOptions& JS::RealmCreationOptions::setExistingCompartment(
1659
JSObject* obj) {
1660
compSpec_ = CompartmentSpecifier::ExistingCompartment;
1661
comp_ = obj->compartment();
1662
return *this;
1663
}
1664
1665
JS::RealmCreationOptions& JS::RealmCreationOptions::setExistingCompartment(
1666
JS::Compartment* compartment) {
1667
compSpec_ = CompartmentSpecifier::ExistingCompartment;
1668
comp_ = compartment;
1669
return *this;
1670
}
1671
1672
JS::RealmCreationOptions& JS::RealmCreationOptions::setNewCompartmentAndZone() {
1673
compSpec_ = CompartmentSpecifier::NewCompartmentAndZone;
1674
comp_ = nullptr;
1675
return *this;
1676
}
1677
1678
const JS::RealmCreationOptions& JS::RealmCreationOptionsRef(Realm* realm) {
1679
return realm->creationOptions();
1680
}
1681
1682
const JS::RealmCreationOptions& JS::RealmCreationOptionsRef(JSContext* cx) {
1683
return cx->realm()->creationOptions();
1684
}
1685
1686
bool JS::RealmCreationOptions::getSharedMemoryAndAtomicsEnabled() const {
1687
return sharedMemoryAndAtomics_;
1688
}
1689
1690
JS::RealmCreationOptions&
1691
JS::RealmCreationOptions::setSharedMemoryAndAtomicsEnabled(bool flag) {
1692
sharedMemoryAndAtomics_ = flag;
1693
return *this;
1694
}
1695
1696
JS::RealmBehaviors& JS::RealmBehaviorsRef(JS::Realm* realm) {
1697
return realm->behaviors();
1698
}
1699
1700
JS::RealmBehaviors& JS::RealmBehaviorsRef(JSContext* cx) {
1701
return cx->realm()->behaviors();
1702
}
1703
1704
JS_PUBLIC_API JSObject* JS_NewGlobalObject(JSContext* cx, const JSClass* clasp,
1705
JSPrincipals* principals,
1706
JS::OnNewGlobalHookOption hookOption,
1707
const JS::RealmOptions& options) {
1708
MOZ_RELEASE_ASSERT(
1709
cx->runtime()->hasInitializedSelfHosting(),
1710
"Must call JS::InitSelfHostedCode() before creating a global");
1711
1712
AssertHeapIsIdle();
1713
CHECK_THREAD(cx);
1714
1715
return GlobalObject::new_(cx, clasp, principals, hookOption, options);
1716
}
1717
1718
JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global) {
1719
GlobalObject* globalObj = &global->as<GlobalObject>();
1720
Realm* globalRealm = globalObj->realm();
1721
1722
// Off thread parsing and compilation tasks create a dummy global which is
1723
// then merged back into the host realm. Since it used to be a global, it
1724
// will still have this trace hook, but it does not have a meaning relative
1725
// to its new realm. We can safely skip it.
1726
//
1727
// Similarly, if we GC when creating the global, we may not have set that
1728
// global's realm's global pointer yet. In this case, the realm will not yet
1729
// contain anything that needs to be traced.
1730
if (globalRealm->unsafeUnbarrieredMaybeGlobal() != globalObj) {
1731
return;
1732
}
1733
1734
// Trace the realm for any GC things that should only stick around if we
1735
// know the global is live.
1736
globalRealm->traceGlobal(trc);
1737
1738
if (JSTraceOp trace = globalRealm->creationOptions().getTrace()) {
1739
trace(trc, global);
1740
}
1741
}
1742
1743
const JSClassOps JS::DefaultGlobalClassOps = {nullptr, // addProperty
1744
nullptr, // deleteProperty
1745
nullptr, // enumerate
1746
JS_NewEnumerateStandardClasses,
1747
JS_ResolveStandardClass,
1748
JS_MayResolveStandardClass,
1749
nullptr, // finalize
1750
nullptr, // call
1751
nullptr, // hasInstance
1752
nullptr, // construct
1753
JS_GlobalObjectTraceHook};
1754
1755
JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx,
1756
JS::HandleObject global) {
1757
// This hook is infallible, because we don't really want arbitrary script
1758
// to be able to throw errors during delicate global creation routines.
1759
// This infallibility will eat OOM and slow script, but if that happens
1760
// we'll likely run up into them again soon in a fallible context.
1761
cx->check(global);
1762
Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>());
1763
DebugAPI::onNewGlobalObject(cx, globalObject);
1764
cx->runtime()->ensureRealmIsRecordingAllocations(globalObject);
1765
}
1766
1767
JS_PUBLIC_API JSObject* JS_NewObject(JSContext* cx, const JSClass* clasp) {
1768
MOZ_ASSERT(!cx->zone()->isAtomsZone());
1769
AssertHeapIsIdle();
1770
CHECK_THREAD(cx);
1771