Bug 1880704 - Crop more PDF rendering and wait differently for rendering r=mboldan
[gecko.git] / js / src / jsfriendapi.cpp
blob694058f6c98c02f93dd9673d9179bfcb98f54138
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jsfriendapi.h"
9 #include "mozilla/Maybe.h"
10 #include "mozilla/PodOperations.h"
11 #include "mozilla/TimeStamp.h"
13 #include <stdint.h>
15 #include "builtin/BigInt.h"
16 #include "builtin/MapObject.h"
17 #include "builtin/TestingFunctions.h"
18 #include "frontend/FrontendContext.h" // FrontendContext
19 #include "gc/PublicIterators.h"
20 #include "gc/WeakMap.h"
21 #include "js/ColumnNumber.h" // JS::LimitedColumnNumberOneOrigin
22 #include "js/experimental/CodeCoverage.h"
23 #include "js/experimental/CTypes.h" // JS::AutoCTypesActivityCallback, JS::SetCTypesActivityCallback
24 #include "js/experimental/Intl.h" // JS::AddMoz{DateTimeFormat,DisplayNames}Constructor
25 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
26 #include "js/friend/StackLimits.h" // JS_STACK_GROWTH_DIRECTION
27 #include "js/friend/WindowProxy.h" // js::ToWindowIfWindowProxy
28 #include "js/HashTable.h"
29 #include "js/Object.h" // JS::GetClass
30 #include "js/PropertyAndElement.h" // JS_DefineProperty
31 #include "js/Proxy.h"
32 #include "js/Stack.h" // JS::NativeStackLimitMax
33 #include "js/String.h" // JS::detail::StringToLinearStringSlow
34 #include "js/Wrapper.h"
35 #include "proxy/DeadObjectProxy.h"
36 #include "util/Poison.h"
37 #include "vm/ArgumentsObject.h"
38 #include "vm/BooleanObject.h"
39 #include "vm/DateObject.h"
40 #include "vm/ErrorObject.h"
41 #include "vm/Interpreter.h"
42 #include "vm/JSContext.h"
43 #include "vm/JSObject.h"
44 #include "vm/NumberObject.h"
45 #include "vm/PlainObject.h" // js::PlainObject
46 #include "vm/PromiseObject.h" // js::PromiseObject
47 #include "vm/Realm.h"
48 #include "vm/StringObject.h"
49 #include "vm/Watchtower.h"
50 #include "vm/WrapperObject.h"
51 #ifdef ENABLE_RECORD_TUPLE
52 # include "vm/RecordType.h"
53 # include "vm/TupleType.h"
54 #endif
56 #include "gc/Marking-inl.h"
57 #include "vm/Compartment-inl.h" // JS::Compartment::wrap
58 #include "vm/JSObject-inl.h"
59 #include "vm/JSScript-inl.h"
60 #include "vm/Realm-inl.h"
62 using namespace js;
64 using mozilla::PodArrayZero;
66 JS::RootingContext::RootingContext(js::Nursery* nursery)
67 : nursery_(nursery), zone_(nullptr), realm_(nullptr) {
68 for (auto& listHead : stackRoots_) {
69 listHead = nullptr;
71 for (auto& listHead : autoGCRooters_) {
72 listHead = nullptr;
75 #if JS_STACK_GROWTH_DIRECTION > 0
76 for (int i = 0; i < StackKindCount; i++) {
77 nativeStackLimit[i] = JS::NativeStackLimitMax;
79 #else
80 static_assert(JS::NativeStackLimitMax == 0);
81 PodArrayZero(nativeStackLimit);
82 #endif
85 JS_PUBLIC_API void JS_SetGrayGCRootsTracer(JSContext* cx,
86 JSGrayRootsTracer traceOp,
87 void* data) {
88 cx->runtime()->gc.setGrayRootsTracer(traceOp, data);
91 JS_PUBLIC_API JSObject* JS_FindCompilationScope(JSContext* cx,
92 HandleObject objArg) {
93 cx->check(objArg);
95 RootedObject obj(cx, objArg);
98 * We unwrap wrappers here. This is a little weird, but it's what's being
99 * asked of us.
101 if (obj->is<WrapperObject>()) {
102 obj = UncheckedUnwrap(obj);
106 * Get the Window if `obj` is a WindowProxy so that we compile in the
107 * correct (global) scope.
109 return ToWindowIfWindowProxy(obj);
112 JS_PUBLIC_API JSFunction* JS_GetObjectFunction(JSObject* obj) {
113 if (obj->is<JSFunction>()) {
114 return &obj->as<JSFunction>();
116 return nullptr;
119 JS_PUBLIC_API JSObject* JS_NewObjectWithoutMetadata(
120 JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto) {
121 cx->check(proto);
122 AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
123 return JS_NewObjectWithGivenProto(cx, clasp, proto);
126 JS_PUBLIC_API bool JS::GetIsSecureContext(JS::Realm* realm) {
127 return realm->creationOptions().secureContext();
130 JS_PUBLIC_API JSPrincipals* JS::GetRealmPrincipals(JS::Realm* realm) {
131 return realm->principals();
134 JS_PUBLIC_API bool JS::GetDebuggerObservesWasm(JS::Realm* realm) {
135 return realm->debuggerObservesAsmJS();
138 JS_PUBLIC_API void JS::SetRealmPrincipals(JS::Realm* realm,
139 JSPrincipals* principals) {
140 // Short circuit if there's no change.
141 if (principals == realm->principals()) {
142 return;
145 // We'd like to assert that our new principals is always same-origin
146 // with the old one, but JSPrincipals doesn't give us a way to do that.
147 // But we can at least assert that we're not switching between system
148 // and non-system.
149 const JSPrincipals* trusted =
150 realm->runtimeFromMainThread()->trustedPrincipals();
151 bool isSystem = principals && principals == trusted;
152 MOZ_RELEASE_ASSERT(realm->isSystem() == isSystem);
154 // Clear out the old principals, if any.
155 if (realm->principals()) {
156 JS_DropPrincipals(TlsContext.get(), realm->principals());
157 realm->setPrincipals(nullptr);
160 // Set up the new principals.
161 if (principals) {
162 JS_HoldPrincipals(principals);
163 realm->setPrincipals(principals);
167 JS_PUBLIC_API JSPrincipals* JS_GetScriptPrincipals(JSScript* script) {
168 return script->principals();
171 JS_PUBLIC_API bool JS_ScriptHasMutedErrors(JSScript* script) {
172 return script->mutedErrors();
175 JS_PUBLIC_API bool JS_WrapPropertyDescriptor(
176 JSContext* cx, JS::MutableHandle<JS::PropertyDescriptor> desc) {
177 return cx->compartment()->wrap(cx, desc);
180 JS_PUBLIC_API bool JS_WrapPropertyDescriptor(
181 JSContext* cx,
182 JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc) {
183 return cx->compartment()->wrap(cx, desc);
186 JS_PUBLIC_API void JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc,
187 JS::GCCellPtr shape) {
188 MOZ_ASSERT(shape.is<Shape>());
189 TraceCycleCollectorChildren(trc, &shape.as<Shape>());
192 static bool DefineHelpProperty(JSContext* cx, HandleObject obj,
193 const char* prop, const char* value) {
194 Rooted<JSAtom*> atom(cx, Atomize(cx, value, strlen(value)));
195 if (!atom) {
196 return false;
198 return JS_DefineProperty(cx, obj, prop, atom,
199 JSPROP_READONLY | JSPROP_PERMANENT);
202 JS_PUBLIC_API bool JS_DefineFunctionsWithHelp(
203 JSContext* cx, HandleObject obj, const JSFunctionSpecWithHelp* fs) {
204 MOZ_ASSERT(!cx->zone()->isAtomsZone());
206 CHECK_THREAD(cx);
207 cx->check(obj);
208 for (; fs->name; fs++) {
209 JSAtom* atom = Atomize(cx, fs->name, strlen(fs->name));
210 if (!atom) {
211 return false;
214 Rooted<jsid> id(cx, AtomToId(atom));
215 RootedFunction fun(cx, DefineFunction(cx, obj, id, fs->call, fs->nargs,
216 fs->flags | JSPROP_RESOLVING));
217 if (!fun) {
218 return false;
221 if (fs->jitInfo) {
222 fun->setJitInfo(fs->jitInfo);
225 if (fs->usage) {
226 if (!DefineHelpProperty(cx, fun, "usage", fs->usage)) {
227 return false;
231 if (fs->help) {
232 if (!DefineHelpProperty(cx, fun, "help", fs->help)) {
233 return false;
238 return true;
241 JS_PUBLIC_API bool JS::GetBuiltinClass(JSContext* cx, HandleObject obj,
242 js::ESClass* cls) {
243 if (MOZ_UNLIKELY(obj->is<ProxyObject>())) {
244 return Proxy::getBuiltinClass(cx, obj, cls);
247 if (obj->is<PlainObject>()) {
248 *cls = ESClass::Object;
249 } else if (obj->is<ArrayObject>()) {
250 *cls = ESClass::Array;
251 } else if (obj->is<NumberObject>()) {
252 *cls = ESClass::Number;
253 } else if (obj->is<StringObject>()) {
254 *cls = ESClass::String;
255 } else if (obj->is<BooleanObject>()) {
256 *cls = ESClass::Boolean;
257 } else if (obj->is<RegExpObject>()) {
258 *cls = ESClass::RegExp;
259 } else if (obj->is<ArrayBufferObject>()) {
260 *cls = ESClass::ArrayBuffer;
261 } else if (obj->is<SharedArrayBufferObject>()) {
262 *cls = ESClass::SharedArrayBuffer;
263 } else if (obj->is<DateObject>()) {
264 *cls = ESClass::Date;
265 } else if (obj->is<SetObject>()) {
266 *cls = ESClass::Set;
267 } else if (obj->is<MapObject>()) {
268 *cls = ESClass::Map;
269 } else if (obj->is<PromiseObject>()) {
270 *cls = ESClass::Promise;
271 } else if (obj->is<MapIteratorObject>()) {
272 *cls = ESClass::MapIterator;
273 } else if (obj->is<SetIteratorObject>()) {
274 *cls = ESClass::SetIterator;
275 } else if (obj->is<ArgumentsObject>()) {
276 *cls = ESClass::Arguments;
277 } else if (obj->is<ErrorObject>()) {
278 *cls = ESClass::Error;
279 } else if (obj->is<BigIntObject>()) {
280 *cls = ESClass::BigInt;
281 #ifdef ENABLE_RECORD_TUPLE
282 } else if (obj->is<RecordType>()) {
283 *cls = ESClass::Record;
284 } else if (obj->is<TupleType>()) {
285 *cls = ESClass::Tuple;
286 #endif
287 } else if (obj->is<JSFunction>()) {
288 *cls = ESClass::Function;
289 } else {
290 *cls = ESClass::Other;
293 return true;
296 JS_PUBLIC_API bool js::IsArgumentsObject(HandleObject obj) {
297 return obj->is<ArgumentsObject>();
300 JS_PUBLIC_API JS::Zone* js::GetRealmZone(JS::Realm* realm) {
301 return realm->zone();
304 JS_PUBLIC_API bool js::IsSystemCompartment(JS::Compartment* comp) {
305 // Realms in the same compartment must either all be system realms or
306 // non-system realms. We assert this in NewRealm and SetRealmPrincipals,
307 // but do an extra sanity check here.
308 MOZ_ASSERT(comp->realms()[0]->isSystem() ==
309 comp->realms().back()->isSystem());
310 return comp->realms()[0]->isSystem();
313 JS_PUBLIC_API bool js::IsSystemRealm(JS::Realm* realm) {
314 return realm->isSystem();
317 JS_PUBLIC_API bool js::IsSystemZone(Zone* zone) { return zone->isSystemZone(); }
319 JS_PUBLIC_API bool js::IsFunctionObject(JSObject* obj) {
320 return obj->is<JSFunction>();
323 JS_PUBLIC_API bool js::IsSavedFrame(JSObject* obj) {
324 return obj->is<SavedFrame>();
327 JS_PUBLIC_API bool js::UninlinedIsCrossCompartmentWrapper(const JSObject* obj) {
328 return js::IsCrossCompartmentWrapper(obj);
331 JS_PUBLIC_API void js::AssertSameCompartment(JSContext* cx, JSObject* obj) {
332 cx->check(obj);
335 JS_PUBLIC_API void js::AssertSameCompartment(JSContext* cx, JS::HandleValue v) {
336 cx->check(v);
339 #ifdef DEBUG
340 JS_PUBLIC_API void js::AssertSameCompartment(JSObject* objA, JSObject* objB) {
341 MOZ_ASSERT(objA->compartment() == objB->compartment());
343 #endif
345 JS_PUBLIC_API void js::NotifyAnimationActivity(JSObject* obj) {
346 MOZ_ASSERT(obj->is<GlobalObject>());
348 auto timeNow = mozilla::TimeStamp::Now();
349 obj->as<GlobalObject>().realm()->lastAnimationTime = timeNow;
350 obj->runtimeFromMainThread()->lastAnimationTime = timeNow;
353 JS_PUBLIC_API bool js::IsObjectInContextCompartment(JSObject* obj,
354 const JSContext* cx) {
355 return obj->compartment() == cx->compartment();
358 JS_PUBLIC_API JS::StackKind
359 js::AutoCheckRecursionLimit::stackKindForCurrentPrincipal(JSContext* cx) const {
360 return cx->stackKindForCurrentPrincipal();
363 JS::NativeStackLimit AutoCheckRecursionLimit::getStackLimit(
364 FrontendContext* fc) const {
365 return fc->stackLimit();
368 JS_PUBLIC_API JSFunction* js::DefineFunctionWithReserved(
369 JSContext* cx, JSObject* objArg, const char* name, JSNative call,
370 unsigned nargs, unsigned attrs) {
371 RootedObject obj(cx, objArg);
372 MOZ_ASSERT(!cx->zone()->isAtomsZone());
373 CHECK_THREAD(cx);
374 cx->check(obj);
375 JSAtom* atom = Atomize(cx, name, strlen(name));
376 if (!atom) {
377 return nullptr;
379 Rooted<jsid> id(cx, AtomToId(atom));
380 return DefineFunction(cx, obj, id, call, nargs, attrs,
381 gc::AllocKind::FUNCTION_EXTENDED);
384 JS_PUBLIC_API JSFunction* js::NewFunctionWithReserved(JSContext* cx,
385 JSNative native,
386 unsigned nargs,
387 unsigned flags,
388 const char* name) {
389 MOZ_ASSERT(!cx->zone()->isAtomsZone());
391 CHECK_THREAD(cx);
393 Rooted<JSAtom*> atom(cx);
394 if (name) {
395 atom = Atomize(cx, name, strlen(name));
396 if (!atom) {
397 return nullptr;
401 return (flags & JSFUN_CONSTRUCTOR)
402 ? NewNativeConstructor(cx, native, nargs, atom,
403 gc::AllocKind::FUNCTION_EXTENDED)
404 : NewNativeFunction(cx, native, nargs, atom,
405 gc::AllocKind::FUNCTION_EXTENDED);
408 JS_PUBLIC_API JSFunction* js::NewFunctionByIdWithReserved(
409 JSContext* cx, JSNative native, unsigned nargs, unsigned flags, jsid id) {
410 MOZ_ASSERT(id.isAtom());
411 MOZ_ASSERT(!cx->zone()->isAtomsZone());
412 CHECK_THREAD(cx);
413 cx->check(id);
415 Rooted<JSAtom*> atom(cx, id.toAtom());
416 return (flags & JSFUN_CONSTRUCTOR)
417 ? NewNativeConstructor(cx, native, nargs, atom,
418 gc::AllocKind::FUNCTION_EXTENDED)
419 : NewNativeFunction(cx, native, nargs, atom,
420 gc::AllocKind::FUNCTION_EXTENDED);
423 JS_PUBLIC_API const Value& js::GetFunctionNativeReserved(JSObject* fun,
424 size_t which) {
425 MOZ_ASSERT(fun->as<JSFunction>().isNativeFun());
426 return fun->as<JSFunction>().getExtendedSlot(which);
429 JS_PUBLIC_API void js::SetFunctionNativeReserved(JSObject* fun, size_t which,
430 const Value& val) {
431 MOZ_ASSERT(fun->as<JSFunction>().isNativeFun());
432 MOZ_ASSERT_IF(val.isObject(),
433 val.toObject().compartment() == fun->compartment());
434 fun->as<JSFunction>().setExtendedSlot(which, val);
437 JS_PUBLIC_API bool js::FunctionHasNativeReserved(JSObject* fun) {
438 MOZ_ASSERT(fun->as<JSFunction>().isNativeFun());
439 return fun->as<JSFunction>().isExtended();
442 bool js::GetObjectProto(JSContext* cx, JS::Handle<JSObject*> obj,
443 JS::MutableHandle<JSObject*> proto) {
444 cx->check(obj);
446 if (obj->is<ProxyObject>()) {
447 return JS_GetPrototype(cx, obj, proto);
450 proto.set(obj->staticPrototype());
451 return true;
454 JS_PUBLIC_API JSObject* js::GetStaticPrototype(JSObject* obj) {
455 MOZ_ASSERT(obj->hasStaticPrototype());
456 return obj->staticPrototype();
459 JS_PUBLIC_API bool js::GetRealmOriginalEval(JSContext* cx,
460 MutableHandleObject eval) {
461 eval.set(&cx->global()->getEvalFunction());
462 return true;
465 void JS::detail::SetReservedSlotWithBarrier(JSObject* obj, size_t slot,
466 const Value& value) {
467 if (obj->is<ProxyObject>()) {
468 obj->as<ProxyObject>().setReservedSlot(slot, value);
469 } else {
470 // Note: We do not currently support watching reserved object slots for
471 // property modification.
472 obj->as<NativeObject>().setSlot(slot, value);
476 void js::SetPreserveWrapperCallbacks(
477 JSContext* cx, PreserveWrapperCallback preserveWrapper,
478 HasReleasedWrapperCallback hasReleasedWrapper) {
479 cx->runtime()->preserveWrapperCallback = preserveWrapper;
480 cx->runtime()->hasReleasedWrapperCallback = hasReleasedWrapper;
483 JS_PUBLIC_API unsigned JS_PCToLineNumber(
484 JSScript* script, jsbytecode* pc,
485 JS::LimitedColumnNumberOneOrigin* columnp) {
486 return PCToLineNumber(script, pc, columnp);
489 JS_PUBLIC_API bool JS_IsDeadWrapper(JSObject* obj) {
490 return IsDeadProxyObject(obj);
493 JS_PUBLIC_API JSObject* JS_NewDeadWrapper(JSContext* cx, JSObject* origObj) {
494 return NewDeadProxyObject(cx, origObj);
497 void js::TraceWeakMaps(WeakMapTracer* trc) {
498 WeakMapBase::traceAllMappings(trc);
501 extern JS_PUBLIC_API bool js::AreGCGrayBitsValid(JSRuntime* rt) {
502 return rt->gc.areGrayBitsValid();
505 JS_PUBLIC_API bool js::ZoneGlobalsAreAllGray(JS::Zone* zone) {
506 for (RealmsInZoneIter realm(zone); !realm.done(); realm.next()) {
507 JSObject* obj = realm->unsafeUnbarrieredMaybeGlobal();
508 if (!obj || !JS::ObjectIsMarkedGray(obj)) {
509 return false;
512 return true;
515 JS_PUBLIC_API bool js::IsCompartmentZoneSweepingOrCompacting(
516 JS::Compartment* comp) {
517 MOZ_ASSERT(comp);
518 return comp->zone()->isGCSweepingOrCompacting();
521 JS_PUBLIC_API void js::TraceGrayWrapperTargets(JSTracer* trc, Zone* zone) {
522 JS::AutoSuppressGCAnalysis nogc;
524 for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
525 for (Compartment::ObjectWrapperEnum e(comp); !e.empty(); e.popFront()) {
526 JSObject* target = e.front().key();
527 if (target->isMarkedGray()) {
528 TraceManuallyBarrieredEdge(trc, &target, "gray CCW target");
529 MOZ_ASSERT(target == e.front().key());
535 JSLinearString* JS::detail::StringToLinearStringSlow(JSContext* cx,
536 JSString* str) {
537 return str->ensureLinear(cx);
540 static bool CopyProxyObject(JSContext* cx, Handle<ProxyObject*> from,
541 Handle<ProxyObject*> to) {
542 MOZ_ASSERT(from->getClass() == to->getClass());
544 if (from->is<WrapperObject>() &&
545 (Wrapper::wrapperHandler(from)->flags() & Wrapper::CROSS_COMPARTMENT)) {
546 to->setCrossCompartmentPrivate(GetProxyPrivate(from));
547 } else {
548 RootedValue v(cx, GetProxyPrivate(from));
549 if (!cx->compartment()->wrap(cx, &v)) {
550 return false;
552 to->setSameCompartmentPrivate(v);
555 MOZ_ASSERT(from->numReservedSlots() == to->numReservedSlots());
557 RootedValue v(cx);
558 for (size_t n = 0; n < from->numReservedSlots(); n++) {
559 v = GetProxyReservedSlot(from, n);
560 if (!cx->compartment()->wrap(cx, &v)) {
561 return false;
563 SetProxyReservedSlot(to, n, v);
566 return true;
569 JS_PUBLIC_API JSObject* JS_CloneObject(JSContext* cx, HandleObject obj,
570 HandleObject proto) {
571 // |obj| might be in a different compartment.
572 cx->check(proto);
574 if (!obj->is<NativeObject>() && !obj->is<ProxyObject>()) {
575 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
576 JSMSG_CANT_CLONE_OBJECT);
577 return nullptr;
580 RootedObject clone(cx);
581 if (obj->is<NativeObject>()) {
582 clone = NewObjectWithGivenProto(cx, obj->getClass(), proto);
583 if (!clone) {
584 return nullptr;
587 if (clone->is<JSFunction>() && obj->compartment() != clone->compartment()) {
588 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
589 JSMSG_CANT_CLONE_OBJECT);
590 return nullptr;
592 } else {
593 auto* handler = GetProxyHandler(obj);
594 clone = ProxyObject::New(cx, handler, JS::NullHandleValue,
595 AsTaggedProto(proto), obj->getClass());
596 if (!clone) {
597 return nullptr;
600 if (!CopyProxyObject(cx, obj.as<ProxyObject>(), clone.as<ProxyObject>())) {
601 return nullptr;
605 return clone;
608 extern JS_PUBLIC_API bool JS::ForceLexicalInitialization(JSContext* cx,
609 HandleObject obj) {
610 AssertHeapIsIdle();
611 CHECK_THREAD(cx);
612 cx->check(obj);
614 bool initializedAny = false;
615 NativeObject* nobj = &obj->as<NativeObject>();
617 for (ShapePropertyIter<NoGC> iter(nobj->shape()); !iter.done(); iter++) {
618 Value v = nobj->getSlot(iter->slot());
619 if (iter->isDataProperty() && v.isMagic() &&
620 v.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
621 nobj->setSlot(iter->slot(), UndefinedValue());
622 initializedAny = true;
625 return initializedAny;
628 extern JS_PUBLIC_API int JS::IsGCPoisoning() {
629 #ifdef JS_GC_ALLOW_EXTRA_POISONING
630 return js::gExtraPoisoningEnabled;
631 #else
632 return false;
633 #endif
636 JS_PUBLIC_API void JS::NotifyGCRootsRemoved(JSContext* cx) {
637 cx->runtime()->gc.notifyRootsRemoved();
640 JS_PUBLIC_API JS::Realm* js::GetAnyRealmInZone(JS::Zone* zone) {
641 if (zone->isAtomsZone()) {
642 return nullptr;
645 RealmsInZoneIter realm(zone);
646 MOZ_ASSERT(!realm.done());
647 return realm.get();
650 JS_PUBLIC_API bool js::IsSharableCompartment(JS::Compartment* comp) {
651 // If this compartment has nuked outgoing wrappers (because all its globals
652 // got nuked), we won't be able to create any useful CCWs out of it in the
653 // future, and so we shouldn't use it for any new globals.
654 if (comp->nukedOutgoingWrappers) {
655 return false;
658 // If this compartment has no live globals, it might be in the middle of being
659 // GCed. Don't create any new Realms inside. There's no point to doing that
660 // anyway, since the idea would be to avoid CCWs from existing Realms in the
661 // compartment to the new Realm, and there are no existing Realms.
662 if (!CompartmentHasLiveGlobal(comp)) {
663 return false;
666 // Good to go.
667 return true;
670 JS_PUBLIC_API JSObject* js::GetTestingFunctions(JSContext* cx) {
671 RootedObject obj(cx, JS_NewPlainObject(cx));
672 if (!obj) {
673 return nullptr;
676 if (!DefineTestingFunctions(cx, obj, false, false)) {
677 return nullptr;
680 return obj;
683 JS_PUBLIC_API void js::SetDOMCallbacks(JSContext* cx,
684 const DOMCallbacks* callbacks) {
685 cx->runtime()->DOMcallbacks = callbacks;
688 JS_PUBLIC_API const DOMCallbacks* js::GetDOMCallbacks(JSContext* cx) {
689 return cx->runtime()->DOMcallbacks;
692 JS_PUBLIC_API void js::PrepareScriptEnvironmentAndInvoke(
693 JSContext* cx, HandleObject global,
694 ScriptEnvironmentPreparer::Closure& closure) {
695 MOZ_ASSERT(!cx->isExceptionPending());
696 MOZ_ASSERT(global->is<GlobalObject>());
698 MOZ_RELEASE_ASSERT(
699 cx->runtime()->scriptEnvironmentPreparer,
700 "Embedding needs to set a scriptEnvironmentPreparer callback");
702 cx->runtime()->scriptEnvironmentPreparer->invoke(global, closure);
705 JS_PUBLIC_API void js::SetScriptEnvironmentPreparer(
706 JSContext* cx, ScriptEnvironmentPreparer* preparer) {
707 cx->runtime()->scriptEnvironmentPreparer = preparer;
710 JS_PUBLIC_API void JS::SetCTypesActivityCallback(JSContext* cx,
711 CTypesActivityCallback cb) {
712 cx->runtime()->ctypesActivityCallback = cb;
715 JS::AutoCTypesActivityCallback::AutoCTypesActivityCallback(
716 JSContext* cx, CTypesActivityType beginType, CTypesActivityType endType)
717 : cx(cx),
718 callback(cx->runtime()->ctypesActivityCallback),
719 endType(endType) {
720 if (callback) {
721 callback(cx, beginType);
725 JS_PUBLIC_API void js::SetAllocationMetadataBuilder(
726 JSContext* cx, const AllocationMetadataBuilder* callback) {
727 cx->realm()->setAllocationMetadataBuilder(callback);
730 JS_PUBLIC_API JSObject* js::GetAllocationMetadata(JSObject* obj) {
731 ObjectWeakMap* map = ObjectRealm::get(obj).objectMetadataTable.get();
732 if (map) {
733 return map->lookup(obj);
735 return nullptr;
738 JS_PUBLIC_API bool js::ReportIsNotFunction(JSContext* cx, HandleValue v) {
739 cx->check(v);
740 return ReportIsNotFunction(cx, v, -1);
743 #ifdef DEBUG
744 bool js::HasObjectMovedOp(JSObject* obj) {
745 return !!JS::GetClass(obj)->extObjectMovedOp();
747 #endif
749 JS_PUBLIC_API bool js::ForwardToNative(JSContext* cx, JSNative native,
750 const CallArgs& args) {
751 return native(cx, args.length(), args.base());
754 AutoAssertNoContentJS::AutoAssertNoContentJS(JSContext* cx)
755 : context_(cx), prevAllowContentJS_(cx->runtime()->allowContentJS_) {
756 cx->runtime()->allowContentJS_ = false;
759 AutoAssertNoContentJS::~AutoAssertNoContentJS() {
760 context_->runtime()->allowContentJS_ = prevAllowContentJS_;
763 JS_PUBLIC_API void js::EnableCodeCoverage() { js::coverage::EnableLCov(); }
765 JS_PUBLIC_API JS::Value js::MaybeGetScriptPrivate(JSObject* object) {
766 if (!object->is<ScriptSourceObject>()) {
767 return UndefinedValue();
770 return object->as<ScriptSourceObject>().getPrivate();
773 JS_PUBLIC_API uint64_t js::GetMemoryUsageForZone(Zone* zone) {
774 // We do not include zone->sharedMemoryUseCounts since that's already included
775 // in zone->mallocHeapSize.
776 return zone->gcHeapSize.bytes() + zone->mallocHeapSize.bytes() +
777 zone->jitHeapSize.bytes();
780 JS_PUBLIC_API const gc::SharedMemoryMap& js::GetSharedMemoryUsageForZone(
781 Zone* zone) {
782 return zone->sharedMemoryUseCounts;
785 JS_PUBLIC_API uint64_t js::GetGCHeapUsage(JSContext* cx) {
786 mozilla::CheckedInt<uint64_t> sum = 0;
787 using SharedSet = js::HashSet<void*, PointerHasher<void*>, SystemAllocPolicy>;
788 SharedSet sharedVisited;
790 for (ZonesIter zone(cx->runtime(), WithAtoms); !zone.done(); zone.next()) {
791 sum += GetMemoryUsageForZone(zone);
793 const gc::SharedMemoryMap& shared = GetSharedMemoryUsageForZone(zone);
794 for (auto iter = shared.iter(); !iter.done(); iter.next()) {
795 void* sharedMem = iter.get().key();
796 SharedSet::AddPtr addShared = sharedVisited.lookupForAdd(sharedMem);
797 if (addShared) {
798 // We *have* seen this shared memory before.
800 // Because shared memory is already included in
801 // GetMemoryUsageForZone() above, and we've seen it for a
802 // previous zone, we subtract it here so it's not counted more
803 // than once.
804 sum -= iter.get().value().nbytes;
805 } else if (!sharedVisited.add(addShared, sharedMem)) {
806 // OOM, abort counting (usually causing an over-estimate).
807 break;
812 MOZ_ASSERT(sum.isValid(), "Memory calculation under/over flowed");
813 return sum.value();
816 #ifdef DEBUG
817 JS_PUBLIC_API bool js::RuntimeIsBeingDestroyed() {
818 JSRuntime* runtime = TlsContext.get()->runtime();
819 MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime));
820 return runtime->isBeingDestroyed();
822 #endif
824 // No-op implementations of public API that would depend on --with-intl-api
826 #ifndef JS_HAS_INTL_API
828 static bool IntlNotEnabled(JSContext* cx) {
829 JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr,
830 JSMSG_SUPPORT_NOT_ENABLED, "Intl");
831 return false;
834 bool JS::AddMozDateTimeFormatConstructor(JSContext* cx, JS::HandleObject intl) {
835 return IntlNotEnabled(cx);
838 bool JS::AddMozDisplayNamesConstructor(JSContext* cx, JS::HandleObject intl) {
839 return IntlNotEnabled(cx);
842 #endif // !JS_HAS_INTL_API
844 JS_PUBLIC_API JS::Zone* js::GetObjectZoneFromAnyThread(const JSObject* obj) {
845 return MaybeForwarded(obj)->zoneFromAnyThread();