Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / js / src / jsfriendapi.cpp
blob574e61248eb8d892a814ebc6b37ae6378698220a
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 JSFunction* js::NewFunctionByIdWithReservedAndProto(
424 JSContext* cx, JSNative native, HandleObject proto, unsigned nargs,
425 unsigned flags, jsid id) {
426 MOZ_ASSERT(id.isAtom());
427 MOZ_ASSERT(!cx->zone()->isAtomsZone());
428 MOZ_ASSERT(native);
429 CHECK_THREAD(cx);
430 cx->check(id);
432 Rooted<JSAtom*> atom(cx, id.toAtom());
433 FunctionFlags funflags = (flags & JSFUN_CONSTRUCTOR)
434 ? FunctionFlags::NATIVE_CTOR
435 : FunctionFlags::NATIVE_FUN;
436 return NewFunctionWithProto(cx, native, nargs, funflags, nullptr, atom, proto,
437 gc::AllocKind::FUNCTION_EXTENDED, TenuredObject);
440 JS_PUBLIC_API const Value& js::GetFunctionNativeReserved(JSObject* fun,
441 size_t which) {
442 MOZ_ASSERT(fun->as<JSFunction>().isNativeFun());
443 return fun->as<JSFunction>().getExtendedSlot(which);
446 JS_PUBLIC_API void js::SetFunctionNativeReserved(JSObject* fun, size_t which,
447 const Value& val) {
448 MOZ_ASSERT(fun->as<JSFunction>().isNativeFun());
449 MOZ_ASSERT_IF(val.isObject(),
450 val.toObject().compartment() == fun->compartment());
451 fun->as<JSFunction>().setExtendedSlot(which, val);
454 JS_PUBLIC_API bool js::FunctionHasNativeReserved(JSObject* fun) {
455 MOZ_ASSERT(fun->as<JSFunction>().isNativeFun());
456 return fun->as<JSFunction>().isExtended();
459 bool js::GetObjectProto(JSContext* cx, JS::Handle<JSObject*> obj,
460 JS::MutableHandle<JSObject*> proto) {
461 cx->check(obj);
463 if (obj->is<ProxyObject>()) {
464 return JS_GetPrototype(cx, obj, proto);
467 proto.set(obj->staticPrototype());
468 return true;
471 JS_PUBLIC_API JSObject* js::GetStaticPrototype(JSObject* obj) {
472 MOZ_ASSERT(obj->hasStaticPrototype());
473 return obj->staticPrototype();
476 JS_PUBLIC_API bool js::GetRealmOriginalEval(JSContext* cx,
477 MutableHandleObject eval) {
478 eval.set(&cx->global()->getEvalFunction());
479 return true;
482 void JS::detail::SetReservedSlotWithBarrier(JSObject* obj, size_t slot,
483 const Value& value) {
484 if (obj->is<ProxyObject>()) {
485 obj->as<ProxyObject>().setReservedSlot(slot, value);
486 } else {
487 // Note: We do not currently support watching reserved object slots for
488 // property modification.
489 obj->as<NativeObject>().setSlot(slot, value);
493 void js::SetPreserveWrapperCallbacks(
494 JSContext* cx, PreserveWrapperCallback preserveWrapper,
495 HasReleasedWrapperCallback hasReleasedWrapper) {
496 cx->runtime()->preserveWrapperCallback = preserveWrapper;
497 cx->runtime()->hasReleasedWrapperCallback = hasReleasedWrapper;
500 JS_PUBLIC_API unsigned JS_PCToLineNumber(
501 JSScript* script, jsbytecode* pc,
502 JS::LimitedColumnNumberOneOrigin* columnp) {
503 return PCToLineNumber(script, pc, columnp);
506 JS_PUBLIC_API bool JS_IsDeadWrapper(JSObject* obj) {
507 return IsDeadProxyObject(obj);
510 JS_PUBLIC_API JSObject* JS_NewDeadWrapper(JSContext* cx, JSObject* origObj) {
511 return NewDeadProxyObject(cx, origObj);
514 void js::TraceWeakMaps(WeakMapTracer* trc) {
515 WeakMapBase::traceAllMappings(trc);
518 extern JS_PUBLIC_API bool js::AreGCGrayBitsValid(JSRuntime* rt) {
519 return rt->gc.areGrayBitsValid();
522 JS_PUBLIC_API bool js::ZoneGlobalsAreAllGray(JS::Zone* zone) {
523 for (RealmsInZoneIter realm(zone); !realm.done(); realm.next()) {
524 JSObject* obj = realm->unsafeUnbarrieredMaybeGlobal();
525 if (!obj || !JS::ObjectIsMarkedGray(obj)) {
526 return false;
529 return true;
532 JS_PUBLIC_API bool js::IsCompartmentZoneSweepingOrCompacting(
533 JS::Compartment* comp) {
534 MOZ_ASSERT(comp);
535 return comp->zone()->isGCSweepingOrCompacting();
538 JS_PUBLIC_API void js::TraceGrayWrapperTargets(JSTracer* trc, Zone* zone) {
539 JS::AutoSuppressGCAnalysis nogc;
541 for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
542 for (Compartment::ObjectWrapperEnum e(comp); !e.empty(); e.popFront()) {
543 JSObject* target = e.front().key();
544 if (target->isMarkedGray()) {
545 TraceManuallyBarrieredEdge(trc, &target, "gray CCW target");
546 MOZ_ASSERT(target == e.front().key());
552 JSLinearString* JS::detail::StringToLinearStringSlow(JSContext* cx,
553 JSString* str) {
554 return str->ensureLinear(cx);
557 static bool CopyProxyObject(JSContext* cx, Handle<ProxyObject*> from,
558 Handle<ProxyObject*> to) {
559 MOZ_ASSERT(from->getClass() == to->getClass());
561 if (from->is<WrapperObject>() &&
562 (Wrapper::wrapperHandler(from)->flags() & Wrapper::CROSS_COMPARTMENT)) {
563 to->setCrossCompartmentPrivate(GetProxyPrivate(from));
564 } else {
565 RootedValue v(cx, GetProxyPrivate(from));
566 if (!cx->compartment()->wrap(cx, &v)) {
567 return false;
569 to->setSameCompartmentPrivate(v);
572 MOZ_ASSERT(from->numReservedSlots() == to->numReservedSlots());
574 RootedValue v(cx);
575 for (size_t n = 0; n < from->numReservedSlots(); n++) {
576 v = GetProxyReservedSlot(from, n);
577 if (!cx->compartment()->wrap(cx, &v)) {
578 return false;
580 SetProxyReservedSlot(to, n, v);
583 return true;
586 JS_PUBLIC_API JSObject* JS_CloneObject(JSContext* cx, HandleObject obj,
587 HandleObject proto) {
588 // |obj| might be in a different compartment.
589 cx->check(proto);
591 if (!obj->is<NativeObject>() && !obj->is<ProxyObject>()) {
592 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
593 JSMSG_CANT_CLONE_OBJECT);
594 return nullptr;
597 RootedObject clone(cx);
598 if (obj->is<NativeObject>()) {
599 clone = NewObjectWithGivenProto(cx, obj->getClass(), proto);
600 if (!clone) {
601 return nullptr;
604 if (clone->is<JSFunction>() && obj->compartment() != clone->compartment()) {
605 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
606 JSMSG_CANT_CLONE_OBJECT);
607 return nullptr;
609 } else {
610 auto* handler = GetProxyHandler(obj);
611 clone = ProxyObject::New(cx, handler, JS::NullHandleValue,
612 AsTaggedProto(proto), obj->getClass());
613 if (!clone) {
614 return nullptr;
617 if (!CopyProxyObject(cx, obj.as<ProxyObject>(), clone.as<ProxyObject>())) {
618 return nullptr;
622 return clone;
625 extern JS_PUBLIC_API bool JS::ForceLexicalInitialization(JSContext* cx,
626 HandleObject obj) {
627 AssertHeapIsIdle();
628 CHECK_THREAD(cx);
629 cx->check(obj);
631 bool initializedAny = false;
632 NativeObject* nobj = &obj->as<NativeObject>();
634 for (ShapePropertyIter<NoGC> iter(nobj->shape()); !iter.done(); iter++) {
635 Value v = nobj->getSlot(iter->slot());
636 if (iter->isDataProperty() && v.isMagic() &&
637 v.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
638 nobj->setSlot(iter->slot(), UndefinedValue());
639 initializedAny = true;
642 return initializedAny;
645 extern JS_PUBLIC_API int JS::IsGCPoisoning() {
646 #ifdef JS_GC_ALLOW_EXTRA_POISONING
647 return js::gExtraPoisoningEnabled;
648 #else
649 return false;
650 #endif
653 JS_PUBLIC_API void JS::NotifyGCRootsRemoved(JSContext* cx) {
654 cx->runtime()->gc.notifyRootsRemoved();
657 JS_PUBLIC_API JS::Realm* js::GetAnyRealmInZone(JS::Zone* zone) {
658 if (zone->isAtomsZone()) {
659 return nullptr;
662 RealmsInZoneIter realm(zone);
663 MOZ_ASSERT(!realm.done());
664 return realm.get();
667 JS_PUBLIC_API bool js::IsSharableCompartment(JS::Compartment* comp) {
668 // If this compartment has nuked outgoing wrappers (because all its globals
669 // got nuked), we won't be able to create any useful CCWs out of it in the
670 // future, and so we shouldn't use it for any new globals.
671 if (comp->nukedOutgoingWrappers) {
672 return false;
675 // If this compartment has no live globals, it might be in the middle of being
676 // GCed. Don't create any new Realms inside. There's no point to doing that
677 // anyway, since the idea would be to avoid CCWs from existing Realms in the
678 // compartment to the new Realm, and there are no existing Realms.
679 if (!CompartmentHasLiveGlobal(comp)) {
680 return false;
683 // Good to go.
684 return true;
687 JS_PUBLIC_API JSObject* js::GetTestingFunctions(JSContext* cx) {
688 RootedObject obj(cx, JS_NewPlainObject(cx));
689 if (!obj) {
690 return nullptr;
693 if (!DefineTestingFunctions(cx, obj, false, false)) {
694 return nullptr;
697 return obj;
700 JS_PUBLIC_API void js::SetDOMCallbacks(JSContext* cx,
701 const DOMCallbacks* callbacks) {
702 cx->runtime()->DOMcallbacks = callbacks;
705 JS_PUBLIC_API const DOMCallbacks* js::GetDOMCallbacks(JSContext* cx) {
706 return cx->runtime()->DOMcallbacks;
709 JS_PUBLIC_API void js::PrepareScriptEnvironmentAndInvoke(
710 JSContext* cx, HandleObject global,
711 ScriptEnvironmentPreparer::Closure& closure) {
712 MOZ_ASSERT(!cx->isExceptionPending());
713 MOZ_ASSERT(global->is<GlobalObject>());
715 MOZ_RELEASE_ASSERT(
716 cx->runtime()->scriptEnvironmentPreparer,
717 "Embedding needs to set a scriptEnvironmentPreparer callback");
719 cx->runtime()->scriptEnvironmentPreparer->invoke(global, closure);
722 JS_PUBLIC_API void js::SetScriptEnvironmentPreparer(
723 JSContext* cx, ScriptEnvironmentPreparer* preparer) {
724 cx->runtime()->scriptEnvironmentPreparer = preparer;
727 JS_PUBLIC_API void JS::SetCTypesActivityCallback(JSContext* cx,
728 CTypesActivityCallback cb) {
729 cx->runtime()->ctypesActivityCallback = cb;
732 JS::AutoCTypesActivityCallback::AutoCTypesActivityCallback(
733 JSContext* cx, CTypesActivityType beginType, CTypesActivityType endType)
734 : cx(cx),
735 callback(cx->runtime()->ctypesActivityCallback),
736 endType(endType) {
737 if (callback) {
738 callback(cx, beginType);
742 JS_PUBLIC_API void js::SetAllocationMetadataBuilder(
743 JSContext* cx, const AllocationMetadataBuilder* callback) {
744 cx->realm()->setAllocationMetadataBuilder(callback);
747 JS_PUBLIC_API JSObject* js::GetAllocationMetadata(JSObject* obj) {
748 ObjectWeakMap* map = ObjectRealm::get(obj).objectMetadataTable.get();
749 if (map) {
750 return map->lookup(obj);
752 return nullptr;
755 JS_PUBLIC_API bool js::ReportIsNotFunction(JSContext* cx, HandleValue v) {
756 cx->check(v);
757 return ReportIsNotFunction(cx, v, -1);
760 #ifdef DEBUG
761 bool js::HasObjectMovedOp(JSObject* obj) {
762 return !!JS::GetClass(obj)->extObjectMovedOp();
764 #endif
766 JS_PUBLIC_API bool js::ForwardToNative(JSContext* cx, JSNative native,
767 const CallArgs& args) {
768 return native(cx, args.length(), args.base());
771 AutoAssertNoContentJS::AutoAssertNoContentJS(JSContext* cx)
772 : context_(cx), prevAllowContentJS_(cx->runtime()->allowContentJS_) {
773 cx->runtime()->allowContentJS_ = false;
776 AutoAssertNoContentJS::~AutoAssertNoContentJS() {
777 context_->runtime()->allowContentJS_ = prevAllowContentJS_;
780 JS_PUBLIC_API void js::EnableCodeCoverage() { js::coverage::EnableLCov(); }
782 JS_PUBLIC_API JS::Value js::MaybeGetScriptPrivate(JSObject* object) {
783 if (!object->is<ScriptSourceObject>()) {
784 return UndefinedValue();
787 return object->as<ScriptSourceObject>().getPrivate();
790 JS_PUBLIC_API uint64_t js::GetMemoryUsageForZone(Zone* zone) {
791 // We do not include zone->sharedMemoryUseCounts since that's already included
792 // in zone->mallocHeapSize.
793 return zone->gcHeapSize.bytes() + zone->mallocHeapSize.bytes() +
794 zone->jitHeapSize.bytes();
797 JS_PUBLIC_API const gc::SharedMemoryMap& js::GetSharedMemoryUsageForZone(
798 Zone* zone) {
799 return zone->sharedMemoryUseCounts;
802 JS_PUBLIC_API uint64_t js::GetGCHeapUsage(JSContext* cx) {
803 mozilla::CheckedInt<uint64_t> sum = 0;
804 using SharedSet = js::HashSet<void*, PointerHasher<void*>, SystemAllocPolicy>;
805 SharedSet sharedVisited;
807 for (ZonesIter zone(cx->runtime(), WithAtoms); !zone.done(); zone.next()) {
808 sum += GetMemoryUsageForZone(zone);
810 const gc::SharedMemoryMap& shared = GetSharedMemoryUsageForZone(zone);
811 for (auto iter = shared.iter(); !iter.done(); iter.next()) {
812 void* sharedMem = iter.get().key();
813 SharedSet::AddPtr addShared = sharedVisited.lookupForAdd(sharedMem);
814 if (addShared) {
815 // We *have* seen this shared memory before.
817 // Because shared memory is already included in
818 // GetMemoryUsageForZone() above, and we've seen it for a
819 // previous zone, we subtract it here so it's not counted more
820 // than once.
821 sum -= iter.get().value().nbytes;
822 } else if (!sharedVisited.add(addShared, sharedMem)) {
823 // OOM, abort counting (usually causing an over-estimate).
824 break;
829 MOZ_ASSERT(sum.isValid(), "Memory calculation under/over flowed");
830 return sum.value();
833 #ifdef DEBUG
834 JS_PUBLIC_API bool js::RuntimeIsBeingDestroyed() {
835 JSRuntime* runtime = TlsContext.get()->runtime();
836 MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime));
837 return runtime->isBeingDestroyed();
839 #endif
841 // No-op implementations of public API that would depend on --with-intl-api
843 #ifndef JS_HAS_INTL_API
845 static bool IntlNotEnabled(JSContext* cx) {
846 JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr,
847 JSMSG_SUPPORT_NOT_ENABLED, "Intl");
848 return false;
851 bool JS::AddMozDateTimeFormatConstructor(JSContext* cx, JS::HandleObject intl) {
852 return IntlNotEnabled(cx);
855 bool JS::AddMozDisplayNamesConstructor(JSContext* cx, JS::HandleObject intl) {
856 return IntlNotEnabled(cx);
859 #endif // !JS_HAS_INTL_API
861 JS_PUBLIC_API JS::Zone* js::GetObjectZoneFromAnyThread(const JSObject* obj) {
862 return MaybeForwarded(obj)->zoneFromAnyThread();