no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / js / src / jsapi.cpp
bloba4d0c15074994f05f01a7f4fe69bebf3f3c55dcd
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 /*
8 * JavaScript API.
9 */
11 #include "jsapi.h"
13 #include "mozilla/FloatingPoint.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/PodOperations.h"
16 #include "mozilla/Sprintf.h"
18 #include <algorithm>
19 #include <cstdarg>
20 #ifdef __linux__
21 # include <dlfcn.h>
22 #endif
23 #include <iterator>
24 #include <stdarg.h>
25 #include <string.h>
27 #include "jsexn.h"
28 #include "jsfriendapi.h"
29 #include "jsmath.h"
30 #include "jstypes.h"
32 #include "builtin/AtomicsObject.h"
33 #include "builtin/Eval.h"
34 #include "builtin/JSON.h"
35 #include "builtin/Promise.h"
36 #include "builtin/Symbol.h"
37 #include "frontend/FrontendContext.h" // AutoReportFrontendContext
38 #include "gc/GC.h"
39 #include "gc/GCContext.h"
40 #include "gc/Marking.h"
41 #include "gc/PublicIterators.h"
42 #include "jit/JitSpewer.h"
43 #include "js/CallAndConstruct.h" // JS::IsCallable
44 #include "js/CharacterEncoding.h"
45 #include "js/ColumnNumber.h" // JS::TaggedColumnNumberOneOrigin, JS::ColumnNumberOneOrigin
46 #include "js/CompileOptions.h"
47 #include "js/ContextOptions.h" // JS::ContextOptions{,Ref}
48 #include "js/Conversions.h"
49 #include "js/Date.h" // JS::GetReduceMicrosecondTimePrecisionCallback
50 #include "js/ErrorInterceptor.h"
51 #include "js/ErrorReport.h" // JSErrorBase
52 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
53 #include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
54 #include "js/GlobalObject.h"
55 #include "js/Initialization.h"
56 #include "js/Interrupt.h"
57 #include "js/JSON.h"
58 #include "js/LocaleSensitive.h"
59 #include "js/MemoryCallbacks.h"
60 #include "js/MemoryFunctions.h"
61 #include "js/Prefs.h"
62 #include "js/PropertySpec.h"
63 #include "js/Proxy.h"
64 #include "js/ScriptPrivate.h"
65 #include "js/StableStringChars.h"
66 #include "js/Stack.h" // JS::NativeStackSize, JS::NativeStackLimitMax, JS::GetNativeStackLimit
67 #include "js/StreamConsumer.h"
68 #include "js/String.h" // JS::MaxStringLength
69 #include "js/Symbol.h"
70 #include "js/TelemetryTimers.h"
71 #include "js/Utility.h"
72 #include "js/WaitCallbacks.h"
73 #include "js/WasmModule.h"
74 #include "js/Wrapper.h"
75 #include "js/WrapperCallbacks.h"
76 #include "proxy/DOMProxy.h"
77 #include "util/Identifier.h" // IsIdentifier
78 #include "util/StringBuffer.h"
79 #include "util/Text.h"
80 #include "vm/BoundFunctionObject.h"
81 #include "vm/EnvironmentObject.h"
82 #include "vm/ErrorObject.h"
83 #include "vm/ErrorReporting.h"
84 #include "vm/FunctionPrefixKind.h"
85 #include "vm/Interpreter.h"
86 #include "vm/JSAtomState.h"
87 #include "vm/JSAtomUtils.h" // Atomize, AtomizeWithoutActiveZone, AtomizeChars, PinAtom, ClassName
88 #include "vm/JSContext.h"
89 #include "vm/JSFunction.h"
90 #include "vm/JSObject.h"
91 #include "vm/JSScript.h"
92 #include "vm/PlainObject.h" // js::PlainObject
93 #include "vm/PromiseObject.h" // js::PromiseObject
94 #include "vm/Runtime.h"
95 #include "vm/SavedStacks.h"
96 #include "vm/StringType.h"
97 #include "vm/Time.h"
98 #include "vm/ToSource.h"
99 #include "vm/Watchtower.h"
100 #include "vm/WrapperObject.h"
101 #include "wasm/WasmModule.h"
102 #include "wasm/WasmProcess.h"
104 #include "builtin/Promise-inl.h"
105 #include "debugger/DebugAPI-inl.h"
106 #include "vm/Compartment-inl.h"
107 #include "vm/Interpreter-inl.h"
108 #include "vm/IsGivenTypeObject-inl.h" // js::IsGivenTypeObject
109 #include "vm/JSAtomUtils-inl.h" // AtomToId, PrimitiveValueToId, IndexToId, ClassName
110 #include "vm/JSFunction-inl.h"
111 #include "vm/JSScript-inl.h"
112 #include "vm/NativeObject-inl.h"
113 #include "vm/SavedStacks-inl.h"
114 #include "vm/StringType-inl.h"
116 using namespace js;
118 using mozilla::Maybe;
119 using mozilla::PodCopy;
120 using mozilla::Some;
122 using JS::AutoStableStringChars;
123 using JS::CompileOptions;
124 using JS::ReadOnlyCompileOptions;
125 using JS::SourceText;
127 // See preprocessor definition of JS_BITS_PER_WORD in jstypes.h; make sure
128 // JS_64BIT (used internally) agrees with it
129 #ifdef JS_64BIT
130 static_assert(JS_BITS_PER_WORD == 64, "values must be in sync");
131 #else
132 static_assert(JS_BITS_PER_WORD == 32, "values must be in sync");
133 #endif
135 JS_PUBLIC_API void JS::CallArgs::reportMoreArgsNeeded(JSContext* cx,
136 const char* fnname,
137 unsigned required,
138 unsigned actual) {
139 char requiredArgsStr[40];
140 SprintfLiteral(requiredArgsStr, "%u", required);
141 char actualArgsStr[40];
142 SprintfLiteral(actualArgsStr, "%u", actual);
143 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
144 JSMSG_MORE_ARGS_NEEDED, fnname, requiredArgsStr,
145 required == 1 ? "" : "s", actualArgsStr);
148 static bool ErrorTakesArguments(unsigned msg) {
149 MOZ_ASSERT(msg < JSErr_Limit);
150 unsigned argCount = js_ErrorFormatString[msg].argCount;
151 MOZ_ASSERT(argCount <= 2);
152 return argCount == 1 || argCount == 2;
155 static bool ErrorTakesObjectArgument(unsigned msg) {
156 MOZ_ASSERT(msg < JSErr_Limit);
157 unsigned argCount = js_ErrorFormatString[msg].argCount;
158 MOZ_ASSERT(argCount <= 2);
159 return argCount == 2;
162 bool JS::ObjectOpResult::reportError(JSContext* cx, HandleObject obj,
163 HandleId id) {
164 static_assert(unsigned(OkCode) == unsigned(JSMSG_NOT_AN_ERROR),
165 "unsigned value of OkCode must not be an error code");
166 MOZ_ASSERT(code_ != Uninitialized);
167 MOZ_ASSERT(!ok());
168 cx->check(obj);
170 if (code_ == JSMSG_OBJECT_NOT_EXTENSIBLE) {
171 RootedValue val(cx, ObjectValue(*obj));
172 return ReportValueError(cx, code_, JSDVG_IGNORE_STACK, val, nullptr);
175 if (ErrorTakesArguments(code_)) {
176 UniqueChars propName =
177 IdToPrintableUTF8(cx, id, IdToPrintableBehavior::IdIsPropertyKey);
178 if (!propName) {
179 return false;
182 if (code_ == JSMSG_SET_NON_OBJECT_RECEIVER) {
183 // We know that the original receiver was a primitive, so unbox it.
184 RootedValue val(cx, ObjectValue(*obj));
185 if (!obj->is<ProxyObject>()) {
186 if (!Unbox(cx, obj, &val)) {
187 return false;
190 return ReportValueError(cx, code_, JSDVG_IGNORE_STACK, val, nullptr,
191 propName.get());
194 if (ErrorTakesObjectArgument(code_)) {
195 JSObject* unwrapped = js::CheckedUnwrapStatic(obj);
196 const char* name = unwrapped ? unwrapped->getClass()->name : "Object";
197 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, code_, name,
198 propName.get());
199 return false;
202 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, code_,
203 propName.get());
204 return false;
206 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, code_);
207 return false;
210 bool JS::ObjectOpResult::reportError(JSContext* cx, HandleObject obj) {
211 MOZ_ASSERT(code_ != Uninitialized);
212 MOZ_ASSERT(!ok());
213 MOZ_ASSERT(!ErrorTakesArguments(code_));
214 cx->check(obj);
216 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, code_);
217 return false;
220 JS_PUBLIC_API bool JS::ObjectOpResult::failCantRedefineProp() {
221 return fail(JSMSG_CANT_REDEFINE_PROP);
224 JS_PUBLIC_API bool JS::ObjectOpResult::failReadOnly() {
225 return fail(JSMSG_READ_ONLY);
228 JS_PUBLIC_API bool JS::ObjectOpResult::failGetterOnly() {
229 return fail(JSMSG_GETTER_ONLY);
232 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDelete() {
233 return fail(JSMSG_CANT_DELETE);
236 JS_PUBLIC_API bool JS::ObjectOpResult::failCantSetInterposed() {
237 return fail(JSMSG_CANT_SET_INTERPOSED);
240 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowElement() {
241 return fail(JSMSG_CANT_DEFINE_WINDOW_ELEMENT);
244 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDeleteWindowElement() {
245 return fail(JSMSG_CANT_DELETE_WINDOW_ELEMENT);
248 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowNamedProperty() {
249 return fail(JSMSG_CANT_DEFINE_WINDOW_NAMED_PROPERTY);
252 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDeleteWindowNamedProperty() {
253 return fail(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY);
256 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowNonConfigurable() {
257 return fail(JSMSG_CANT_DEFINE_WINDOW_NC);
260 JS_PUBLIC_API bool JS::ObjectOpResult::failCantPreventExtensions() {
261 return fail(JSMSG_CANT_PREVENT_EXTENSIONS);
264 JS_PUBLIC_API bool JS::ObjectOpResult::failCantSetProto() {
265 return fail(JSMSG_CANT_SET_PROTO);
268 JS_PUBLIC_API bool JS::ObjectOpResult::failNoNamedSetter() {
269 return fail(JSMSG_NO_NAMED_SETTER);
272 JS_PUBLIC_API bool JS::ObjectOpResult::failNoIndexedSetter() {
273 return fail(JSMSG_NO_INDEXED_SETTER);
276 JS_PUBLIC_API bool JS::ObjectOpResult::failNotDataDescriptor() {
277 return fail(JSMSG_NOT_DATA_DESCRIPTOR);
280 JS_PUBLIC_API bool JS::ObjectOpResult::failInvalidDescriptor() {
281 return fail(JSMSG_INVALID_DESCRIPTOR);
284 JS_PUBLIC_API bool JS::ObjectOpResult::failBadArrayLength() {
285 return fail(JSMSG_BAD_ARRAY_LENGTH);
288 JS_PUBLIC_API bool JS::ObjectOpResult::failBadIndex() {
289 return fail(JSMSG_BAD_INDEX);
292 JS_PUBLIC_API int64_t JS_Now() { return PRMJ_Now(); }
294 JS_PUBLIC_API Value JS_GetEmptyStringValue(JSContext* cx) {
295 return StringValue(cx->runtime()->emptyString);
298 JS_PUBLIC_API JSString* JS_GetEmptyString(JSContext* cx) {
299 MOZ_ASSERT(cx->emptyString());
300 return cx->emptyString();
303 namespace js {
305 void AssertHeapIsIdle() { MOZ_ASSERT(!JS::RuntimeHeapIsBusy()); }
307 } // namespace js
309 static void AssertHeapIsIdleOrIterating() {
310 MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
313 JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, HandleValue value,
314 MutableHandleObject objp) {
315 AssertHeapIsIdle();
316 CHECK_THREAD(cx);
317 cx->check(value);
318 if (value.isNullOrUndefined()) {
319 objp.set(nullptr);
320 return true;
322 JSObject* obj = ToObject(cx, value);
323 if (!obj) {
324 return false;
326 objp.set(obj);
327 return true;
330 JS_PUBLIC_API JSFunction* JS_ValueToFunction(JSContext* cx, HandleValue value) {
331 AssertHeapIsIdle();
332 CHECK_THREAD(cx);
333 cx->check(value);
334 return ReportIfNotFunction(cx, value);
337 JS_PUBLIC_API JSFunction* JS_ValueToConstructor(JSContext* cx,
338 HandleValue value) {
339 AssertHeapIsIdle();
340 CHECK_THREAD(cx);
341 cx->check(value);
342 return ReportIfNotFunction(cx, value);
345 JS_PUBLIC_API JSString* JS_ValueToSource(JSContext* cx, HandleValue value) {
346 AssertHeapIsIdle();
347 CHECK_THREAD(cx);
348 cx->check(value);
349 return ValueToSource(cx, value);
352 JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip) {
353 return mozilla::NumberIsInt32(d, ip);
356 JS_PUBLIC_API JSType JS_TypeOfValue(JSContext* cx, HandleValue value) {
357 AssertHeapIsIdle();
358 CHECK_THREAD(cx);
359 cx->check(value);
360 return TypeOfValue(value);
363 JS_PUBLIC_API bool JS_IsBuiltinEvalFunction(JSFunction* fun) {
364 return IsAnyBuiltinEval(fun);
367 JS_PUBLIC_API bool JS_IsBuiltinFunctionConstructor(JSFunction* fun) {
368 return fun->isBuiltinFunctionConstructor();
371 JS_PUBLIC_API bool JS_ObjectIsBoundFunction(JSObject* obj) {
372 return obj->is<BoundFunctionObject>();
375 JS_PUBLIC_API JSObject* JS_GetBoundFunctionTarget(JSObject* obj) {
376 return obj->is<BoundFunctionObject>()
377 ? obj->as<BoundFunctionObject>().getTarget()
378 : nullptr;
381 /************************************************************************/
383 // Prevent functions from being discarded by linker, so that they are callable
384 // when debugging.
385 static void PreventDiscardingFunctions() {
386 if (reinterpret_cast<uintptr_t>(&PreventDiscardingFunctions) == 1) {
387 // Never executed.
388 memset((void*)&js::debug::GetMarkInfo, 0, 1);
389 memset((void*)&js::debug::GetMarkWordAddress, 0, 1);
390 memset((void*)&js::debug::GetMarkMask, 0, 1);
394 JS_PUBLIC_API JSContext* JS_NewContext(uint32_t maxbytes,
395 JSRuntime* parentRuntime) {
396 MOZ_ASSERT(JS::detail::libraryInitState == JS::detail::InitState::Running,
397 "must call JS_Init prior to creating any JSContexts");
399 // Prevent linker from discarding unused debug functions.
400 PreventDiscardingFunctions();
402 // Make sure that all parent runtimes are the topmost parent.
403 while (parentRuntime && parentRuntime->parentRuntime) {
404 parentRuntime = parentRuntime->parentRuntime;
407 return NewContext(maxbytes, parentRuntime);
410 JS_PUBLIC_API void JS_DestroyContext(JSContext* cx) { DestroyContext(cx); }
412 JS_PUBLIC_API void* JS_GetContextPrivate(JSContext* cx) { return cx->data; }
414 JS_PUBLIC_API void JS_SetContextPrivate(JSContext* cx, void* data) {
415 cx->data = data;
418 JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx) {
419 cx->fx.setCanWait(true);
422 JS_PUBLIC_API JSRuntime* JS_GetParentRuntime(JSContext* cx) {
423 return cx->runtime()->parentRuntime ? cx->runtime()->parentRuntime
424 : cx->runtime();
427 JS_PUBLIC_API JSRuntime* JS_GetRuntime(JSContext* cx) { return cx->runtime(); }
429 JS_PUBLIC_API JS::ContextOptions& JS::ContextOptionsRef(JSContext* cx) {
430 return cx->options();
433 JS::ContextOptions& JS::ContextOptions::setFuzzing(bool flag) {
434 #ifdef FUZZING
435 fuzzing_ = flag;
436 #endif
437 return *this;
440 JS_PUBLIC_API const char* JS_GetImplementationVersion(void) {
441 return "JavaScript-C" MOZILLA_VERSION;
444 JS_PUBLIC_API void JS_SetDestroyZoneCallback(JSContext* cx,
445 JSDestroyZoneCallback callback) {
446 cx->runtime()->destroyZoneCallback = callback;
449 JS_PUBLIC_API void JS_SetDestroyCompartmentCallback(
450 JSContext* cx, JSDestroyCompartmentCallback callback) {
451 cx->runtime()->destroyCompartmentCallback = callback;
454 JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback(
455 JSContext* cx, JSSizeOfIncludingThisCompartmentCallback callback) {
456 cx->runtime()->sizeOfIncludingThisCompartmentCallback = callback;
459 JS_PUBLIC_API void JS_SetErrorInterceptorCallback(
460 JSRuntime* rt, JSErrorInterceptor* callback) {
461 #if defined(NIGHTLY_BUILD)
462 rt->errorInterception.interceptor = callback;
463 #endif // defined(NIGHTLY_BUILD)
466 JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback(
467 JSRuntime* rt) {
468 #if defined(NIGHTLY_BUILD)
469 return rt->errorInterception.interceptor;
470 #else // !NIGHTLY_BUILD
471 return nullptr;
472 #endif // defined(NIGHTLY_BUILD)
475 JS_PUBLIC_API Maybe<JSExnType> JS_GetErrorType(const JS::Value& val) {
476 // All errors are objects.
477 if (!val.isObject()) {
478 return mozilla::Nothing();
481 const JSObject& obj = val.toObject();
483 // All errors are `ErrorObject`.
484 if (!obj.is<js::ErrorObject>()) {
485 // Not one of the primitive errors.
486 return mozilla::Nothing();
489 const js::ErrorObject& err = obj.as<js::ErrorObject>();
490 return mozilla::Some(err.type());
493 JS_PUBLIC_API void JS_SetWrapObjectCallbacks(
494 JSContext* cx, const JSWrapObjectCallbacks* callbacks) {
495 cx->runtime()->wrapObjectCallbacks = callbacks;
498 JS_PUBLIC_API Realm* JS::EnterRealm(JSContext* cx, JSObject* target) {
499 AssertHeapIsIdle();
500 CHECK_THREAD(cx);
502 MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(target));
504 Realm* oldRealm = cx->realm();
505 cx->enterRealmOf(target);
506 return oldRealm;
509 JS_PUBLIC_API void JS::LeaveRealm(JSContext* cx, JS::Realm* oldRealm) {
510 AssertHeapIsIdle();
511 CHECK_THREAD(cx);
512 cx->leaveRealm(oldRealm);
515 JSAutoRealm::JSAutoRealm(JSContext* cx, JSObject* target)
516 : cx_(cx), oldRealm_(cx->realm()) {
517 MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(target));
518 AssertHeapIsIdleOrIterating();
519 cx_->enterRealmOf(target);
522 JSAutoRealm::JSAutoRealm(JSContext* cx, JSScript* target)
523 : cx_(cx), oldRealm_(cx->realm()) {
524 AssertHeapIsIdleOrIterating();
525 cx_->enterRealmOf(target);
528 JSAutoRealm::~JSAutoRealm() { cx_->leaveRealm(oldRealm_); }
530 JSAutoNullableRealm::JSAutoNullableRealm(JSContext* cx, JSObject* targetOrNull)
531 : cx_(cx), oldRealm_(cx->realm()) {
532 AssertHeapIsIdleOrIterating();
533 if (targetOrNull) {
534 MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(targetOrNull));
535 cx_->enterRealmOf(targetOrNull);
536 } else {
537 cx_->enterNullRealm();
541 JSAutoNullableRealm::~JSAutoNullableRealm() { cx_->leaveRealm(oldRealm_); }
543 JS_PUBLIC_API void JS_SetCompartmentPrivate(JS::Compartment* compartment,
544 void* data) {
545 compartment->data = data;
548 JS_PUBLIC_API void* JS_GetCompartmentPrivate(JS::Compartment* compartment) {
549 return compartment->data;
552 JS_PUBLIC_API void JS_MarkCrossZoneId(JSContext* cx, jsid id) {
553 cx->markId(id);
556 JS_PUBLIC_API void JS_MarkCrossZoneIdValue(JSContext* cx, const Value& value) {
557 cx->markAtomValue(value);
560 JS_PUBLIC_API void JS_SetZoneUserData(JS::Zone* zone, void* data) {
561 zone->data = data;
564 JS_PUBLIC_API void* JS_GetZoneUserData(JS::Zone* zone) { return zone->data; }
566 JS_PUBLIC_API bool JS_WrapObject(JSContext* cx, MutableHandleObject objp) {
567 AssertHeapIsIdle();
568 CHECK_THREAD(cx);
569 if (objp) {
570 JS::ExposeObjectToActiveJS(objp);
572 return cx->compartment()->wrap(cx, objp);
575 JS_PUBLIC_API bool JS_WrapValue(JSContext* cx, MutableHandleValue vp) {
576 AssertHeapIsIdle();
577 CHECK_THREAD(cx);
578 JS::ExposeValueToActiveJS(vp);
579 return cx->compartment()->wrap(cx, vp);
582 static void ReleaseAssertObjectHasNoWrappers(JSContext* cx,
583 HandleObject target) {
584 for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
585 if (c->lookupWrapper(target)) {
586 MOZ_CRASH("wrapper found for target object");
592 * [SMDOC] Brain transplants.
594 * Not for beginners or the squeamish.
596 * Sometimes a web spec requires us to transplant an object from one
597 * compartment to another, like when a DOM node is inserted into a document in
598 * another window and thus gets "adopted". We cannot literally change the
599 * `.compartment()` of a `JSObject`; that would break the compartment
600 * invariants. However, as usual, we have a workaround using wrappers.
602 * Of all the wrapper-based workarounds we do, it's safe to say this is the
603 * most spectacular and questionable.
605 * `JS_TransplantObject(cx, origobj, target)` changes `origobj` into a
606 * simulacrum of `target`, using highly esoteric means. To JS code, the effect
607 * is as if `origobj` magically "became" `target`, but most often what actually
608 * happens is that `origobj` gets turned into a cross-compartment wrapper for
609 * `target`. The old behavior and contents of `origobj` are overwritten or
610 * discarded.
612 * Thus, to "transplant" an object from one compartment to another:
614 * 1. Let `origobj` be the object that you want to move. First, create a
615 * clone of it, `target`, in the destination compartment.
617 * In our DOM adoption example, `target` will be a Node of the same type as
618 * `origobj`, same content, but in the adopting document. We're not done
619 * yet: the spec for DOM adoption requires that `origobj.ownerDocument`
620 * actually change. All we've done so far is make a copy.
622 * 2. Call `JS_TransplantObject(cx, origobj, target)`. This typically turns
623 * `origobj` into a wrapper for `target`, so that any JS code that has a
624 * reference to `origobj` will observe it to have the behavior of `target`
625 * going forward. In addition, all existing wrappers for `origobj` are
626 * changed into wrappers for `target`, extending the illusion to those
627 * compartments as well.
629 * During navigation, we use the above technique to transplant the WindowProxy
630 * into the new Window's compartment.
632 * A few rules:
634 * - `origobj` and `target` must be two distinct objects of the same
635 * `JSClass`. Some classes may not support transplantation; WindowProxy
636 * objects and DOM nodes are OK.
638 * - `target` should be created specifically to be passed to this function.
639 * There must be no existing cross-compartment wrappers for it; ideally
640 * there shouldn't be any pointers to it at all, except the one passed in.
642 * - `target` shouldn't be used afterwards. Instead, `JS_TransplantObject`
643 * returns a pointer to the transplanted object, which might be `target`
644 * but might be some other object in the same compartment. Use that.
646 * The reason for this last rule is that JS_TransplantObject does very strange
647 * things in some cases, like swapping `target`'s brain with that of another
648 * object. Leaving `target` behaving like its former self is not a goal.
650 * We don't have a good way to recover from failure in this function, so
651 * we intentionally crash instead.
654 static void CheckTransplantObject(JSObject* obj) {
655 #ifdef DEBUG
656 MOZ_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
657 JS::AssertCellIsNotGray(obj);
658 #endif
661 JS_PUBLIC_API JSObject* JS_TransplantObject(JSContext* cx, HandleObject origobj,
662 HandleObject target) {
663 AssertHeapIsIdle();
664 MOZ_ASSERT(origobj != target);
665 CheckTransplantObject(origobj);
666 CheckTransplantObject(target);
667 ReleaseAssertObjectHasNoWrappers(cx, target);
669 RootedObject newIdentity(cx);
671 // Don't allow a compacting GC to observe any intermediate state.
672 AutoDisableCompactingGC nocgc(cx);
674 AutoDisableProxyCheck adpc;
676 AutoEnterOOMUnsafeRegion oomUnsafe;
678 JS::Compartment* destination = target->compartment();
680 if (origobj->compartment() == destination) {
681 // If the original object is in the same compartment as the
682 // destination, then we know that we won't find a wrapper in the
683 // destination's cross compartment map and that the same
684 // object will continue to work.
685 AutoRealm ar(cx, origobj);
686 JSObject::swap(cx, origobj, target, oomUnsafe);
687 newIdentity = origobj;
688 } else if (ObjectWrapperMap::Ptr p = destination->lookupWrapper(origobj)) {
689 // There might already be a wrapper for the original object in
690 // the new compartment. If there is, we use its identity and swap
691 // in the contents of |target|.
692 newIdentity = p->value().get();
694 // When we remove origv from the wrapper map, its wrapper, newIdentity,
695 // must immediately cease to be a cross-compartment wrapper. Nuke it.
696 destination->removeWrapper(p);
697 NukeCrossCompartmentWrapper(cx, newIdentity);
699 AutoRealm ar(cx, newIdentity);
700 JSObject::swap(cx, newIdentity, target, oomUnsafe);
701 } else {
702 // Otherwise, we use |target| for the new identity object.
703 newIdentity = target;
706 // Now, iterate through other scopes looking for references to the old
707 // object, and update the relevant cross-compartment wrappers. We do this
708 // even if origobj is in the same compartment as target and thus
709 // `newIdentity == origobj`, because this process also clears out any
710 // cached wrapper state.
711 if (!RemapAllWrappersForObject(cx, origobj, newIdentity)) {
712 oomUnsafe.crash("JS_TransplantObject");
715 // Lastly, update the original object to point to the new one.
716 if (origobj->compartment() != destination) {
717 RootedObject newIdentityWrapper(cx, newIdentity);
718 AutoRealm ar(cx, origobj);
719 if (!JS_WrapObject(cx, &newIdentityWrapper)) {
720 MOZ_RELEASE_ASSERT(cx->isThrowingOutOfMemory() ||
721 cx->isThrowingOverRecursed());
722 oomUnsafe.crash("JS_TransplantObject");
724 MOZ_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
725 JSObject::swap(cx, origobj, newIdentityWrapper, oomUnsafe);
726 if (origobj->compartment()->lookupWrapper(newIdentity)) {
727 MOZ_ASSERT(origobj->is<CrossCompartmentWrapperObject>());
728 if (!origobj->compartment()->putWrapper(cx, newIdentity, origobj)) {
729 oomUnsafe.crash("JS_TransplantObject");
734 // The new identity object might be one of several things. Return it to avoid
735 // ambiguity.
736 JS::AssertCellIsNotGray(newIdentity);
737 return newIdentity;
740 JS_PUBLIC_API void js::RemapRemoteWindowProxies(
741 JSContext* cx, CompartmentTransplantCallback* callback,
742 MutableHandleObject target) {
743 AssertHeapIsIdle();
744 CheckTransplantObject(target);
745 ReleaseAssertObjectHasNoWrappers(cx, target);
747 // |target| can't be a remote proxy, because we expect it to get a CCW when
748 // wrapped across compartments.
749 MOZ_ASSERT(!js::IsDOMRemoteProxyObject(target));
751 // Don't allow a compacting GC to observe any intermediate state.
752 AutoDisableCompactingGC nocgc(cx);
754 AutoDisableProxyCheck adpc;
756 AutoEnterOOMUnsafeRegion oomUnsafe;
758 AutoCheckRecursionLimit recursion(cx);
759 if (!recursion.checkSystem(cx)) {
760 oomUnsafe.crash("js::RemapRemoteWindowProxies");
763 RootedObject targetCompartmentProxy(cx);
764 JS::RootedVector<JSObject*> otherProxies(cx);
766 // Use the callback to find remote proxies in all compartments that match
767 // whatever criteria callback uses.
768 for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
769 RootedObject remoteProxy(cx, callback->getObjectToTransplant(c));
770 if (!remoteProxy) {
771 continue;
773 // The object the callback returns should be a DOM remote proxy object in
774 // the compartment c. We rely on it being a DOM remote proxy because that
775 // means that it won't have any cross-compartment wrappers.
776 MOZ_ASSERT(js::IsDOMRemoteProxyObject(remoteProxy));
777 MOZ_ASSERT(remoteProxy->compartment() == c);
778 CheckTransplantObject(remoteProxy);
780 // Immediately turn the DOM remote proxy object into a dead proxy object
781 // so we don't have to worry about anything weird going on with it.
782 js::NukeNonCCWProxy(cx, remoteProxy);
784 if (remoteProxy->compartment() == target->compartment()) {
785 targetCompartmentProxy = remoteProxy;
786 } else if (!otherProxies.append(remoteProxy)) {
787 oomUnsafe.crash("js::RemapRemoteWindowProxies");
791 // If there was a remote proxy in |target|'s compartment, we need to use it
792 // instead of |target|, in case it had any references, so swap it. Do this
793 // before any other compartment so that the target object will be set up
794 // correctly before we start wrapping it into other compartments.
795 if (targetCompartmentProxy) {
796 AutoRealm ar(cx, targetCompartmentProxy);
797 JSObject::swap(cx, targetCompartmentProxy, target, oomUnsafe);
798 target.set(targetCompartmentProxy);
801 for (JSObject*& obj : otherProxies) {
802 RootedObject deadWrapper(cx, obj);
803 js::RemapDeadWrapper(cx, deadWrapper, target);
808 * Recompute all cross-compartment wrappers for an object, resetting state.
809 * Gecko uses this to clear Xray wrappers when doing a navigation that reuses
810 * the inner window and global object.
812 JS_PUBLIC_API bool JS_RefreshCrossCompartmentWrappers(JSContext* cx,
813 HandleObject obj) {
814 return RemapAllWrappersForObject(cx, obj, obj);
817 typedef struct JSStdName {
818 size_t atomOffset; /* offset of atom pointer in JSAtomState */
819 JSProtoKey key;
820 bool isDummy() const { return key == JSProto_Null; }
821 bool isSentinel() const { return key == JSProto_LIMIT; }
822 } JSStdName;
824 static const JSStdName* LookupStdName(const JSAtomState& names, JSAtom* name,
825 const JSStdName* table) {
826 for (unsigned i = 0; !table[i].isSentinel(); i++) {
827 if (table[i].isDummy()) {
828 continue;
830 JSAtom* atom = AtomStateOffsetToName(names, table[i].atomOffset);
831 MOZ_ASSERT(atom);
832 if (name == atom) {
833 return &table[i];
837 return nullptr;
841 * Table of standard classes, indexed by JSProtoKey. For entries where the
842 * JSProtoKey does not correspond to a class with a meaningful constructor, we
843 * insert a null entry into the table.
845 #define STD_NAME_ENTRY(name, clasp) {NAME_OFFSET(name), JSProto_##name},
846 #define STD_DUMMY_ENTRY(name, dummy) {0, JSProto_Null},
847 static const JSStdName standard_class_names[] = {
848 JS_FOR_PROTOTYPES(STD_NAME_ENTRY, STD_DUMMY_ENTRY){0, JSProto_LIMIT}};
851 * Table of top-level function and constant names and the JSProtoKey of the
852 * standard class that initializes them.
854 static const JSStdName builtin_property_names[] = {
855 {NAME_OFFSET(eval), JSProto_Object},
857 /* Global properties and functions defined by the Number class. */
858 {NAME_OFFSET(NaN), JSProto_Number},
859 {NAME_OFFSET(Infinity), JSProto_Number},
860 {NAME_OFFSET(isNaN), JSProto_Number},
861 {NAME_OFFSET(isFinite), JSProto_Number},
862 {NAME_OFFSET(parseFloat), JSProto_Number},
863 {NAME_OFFSET(parseInt), JSProto_Number},
865 /* String global functions. */
866 {NAME_OFFSET(escape), JSProto_String},
867 {NAME_OFFSET(unescape), JSProto_String},
868 {NAME_OFFSET(decodeURI), JSProto_String},
869 {NAME_OFFSET(encodeURI), JSProto_String},
870 {NAME_OFFSET(decodeURIComponent), JSProto_String},
871 {NAME_OFFSET(encodeURIComponent), JSProto_String},
872 {NAME_OFFSET(uneval), JSProto_String},
874 {0, JSProto_LIMIT}};
876 static bool SkipUneval(jsid id, JSContext* cx) {
877 return !cx->realm()->creationOptions().getToSourceEnabled() &&
878 id == NameToId(cx->names().uneval);
881 static bool SkipSharedArrayBufferConstructor(JSProtoKey key,
882 GlobalObject* global) {
883 if (key != JSProto_SharedArrayBuffer) {
884 return false;
887 const JS::RealmCreationOptions& options = global->realm()->creationOptions();
888 MOZ_ASSERT(options.getSharedMemoryAndAtomicsEnabled(),
889 "shouldn't contemplate defining SharedArrayBuffer if shared "
890 "memory is disabled");
892 // On the web, it isn't presently possible to expose the global
893 // "SharedArrayBuffer" property unless the page is cross-site-isolated. Only
894 // define this constructor if an option on the realm indicates that it should
895 // be defined.
896 return !options.defineSharedArrayBufferConstructor();
899 JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx, HandleObject obj,
900 HandleId id, bool* resolved) {
901 AssertHeapIsIdle();
902 CHECK_THREAD(cx);
903 cx->check(obj, id);
905 Handle<GlobalObject*> global = obj.as<GlobalObject>();
906 *resolved = false;
908 if (!id.isAtom()) {
909 return true;
912 /* Check whether we're resolving 'undefined', and define it if so. */
913 JSAtom* idAtom = id.toAtom();
914 if (idAtom == cx->names().undefined) {
915 *resolved = true;
916 return js::DefineDataProperty(
917 cx, global, id, UndefinedHandleValue,
918 JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING);
921 // Resolve a "globalThis" self-referential property if necessary.
922 if (idAtom == cx->names().globalThis) {
923 return GlobalObject::maybeResolveGlobalThis(cx, global, resolved);
926 // Try for class constructors/prototypes named by well-known atoms.
927 const JSStdName* stdnm =
928 LookupStdName(cx->names(), idAtom, standard_class_names);
929 if (!stdnm) {
930 // Try less frequently used top-level functions and constants.
931 stdnm = LookupStdName(cx->names(), idAtom, builtin_property_names);
932 if (!stdnm) {
933 return true;
937 JSProtoKey key = stdnm->key;
938 if (key == JSProto_Null || GlobalObject::skipDeselectedConstructor(cx, key) ||
939 SkipUneval(id, cx)) {
940 return true;
943 // If this class is anonymous (or it's "SharedArrayBuffer" but that global
944 // constructor isn't supposed to be defined), then it doesn't exist as a
945 // global property, so we won't resolve anything.
946 const JSClass* clasp = ProtoKeyToClass(key);
947 if (clasp && !clasp->specShouldDefineConstructor()) {
948 return true;
950 if (SkipSharedArrayBufferConstructor(key, global)) {
951 return true;
954 if (!GlobalObject::ensureConstructor(cx, global, key)) {
955 return false;
957 *resolved = true;
958 return true;
961 JS_PUBLIC_API bool JS_MayResolveStandardClass(const JSAtomState& names, jsid id,
962 JSObject* maybeObj) {
963 MOZ_ASSERT_IF(maybeObj, maybeObj->is<GlobalObject>());
965 // The global object's resolve hook is special: JS_ResolveStandardClass
966 // initializes the prototype chain lazily. Only attempt to optimize here
967 // if we know the prototype chain has been initialized.
968 if (!maybeObj || !maybeObj->staticPrototype()) {
969 return true;
972 if (!id.isAtom()) {
973 return false;
976 JSAtom* atom = id.toAtom();
978 // This will return true even for deselected constructors. (To do
979 // better, we need a JSContext here; it's fine as it is.)
981 return atom == names.undefined || atom == names.globalThis ||
982 LookupStdName(names, atom, standard_class_names) ||
983 LookupStdName(names, atom, builtin_property_names);
986 JS_PUBLIC_API bool JS_EnumerateStandardClasses(JSContext* cx,
987 HandleObject obj) {
988 AssertHeapIsIdle();
989 CHECK_THREAD(cx);
990 cx->check(obj);
991 Handle<GlobalObject*> global = obj.as<GlobalObject>();
992 return GlobalObject::initStandardClasses(cx, global);
995 static bool EnumerateStandardClassesInTable(JSContext* cx,
996 Handle<GlobalObject*> global,
997 MutableHandleIdVector properties,
998 const JSStdName* table,
999 bool includeResolved) {
1000 for (unsigned i = 0; !table[i].isSentinel(); i++) {
1001 if (table[i].isDummy()) {
1002 continue;
1005 JSProtoKey key = table[i].key;
1007 // If the standard class has been resolved, the properties have been
1008 // defined on the global so we don't need to add them here.
1009 if (!includeResolved && global->isStandardClassResolved(key)) {
1010 continue;
1013 if (GlobalObject::skipDeselectedConstructor(cx, key)) {
1014 continue;
1017 if (const JSClass* clasp = ProtoKeyToClass(key)) {
1018 if (!clasp->specShouldDefineConstructor() ||
1019 SkipSharedArrayBufferConstructor(key, global)) {
1020 continue;
1024 jsid id = NameToId(AtomStateOffsetToName(cx->names(), table[i].atomOffset));
1026 if (SkipUneval(id, cx)) {
1027 continue;
1030 if (!properties.append(id)) {
1031 return false;
1035 return true;
1038 static bool EnumerateStandardClasses(JSContext* cx, JS::HandleObject obj,
1039 JS::MutableHandleIdVector properties,
1040 bool enumerableOnly,
1041 bool includeResolved) {
1042 if (enumerableOnly) {
1043 // There are no enumerable standard classes and "undefined" is
1044 // not enumerable.
1045 return true;
1048 Handle<GlobalObject*> global = obj.as<GlobalObject>();
1050 // It's fine to always append |undefined| here, it's non-configurable and
1051 // the enumeration code filters duplicates.
1052 if (!properties.append(NameToId(cx->names().undefined))) {
1053 return false;
1056 bool resolved = false;
1057 if (!GlobalObject::maybeResolveGlobalThis(cx, global, &resolved)) {
1058 return false;
1060 if (resolved || includeResolved) {
1061 if (!properties.append(NameToId(cx->names().globalThis))) {
1062 return false;
1066 if (!EnumerateStandardClassesInTable(cx, global, properties,
1067 standard_class_names, includeResolved)) {
1068 return false;
1070 if (!EnumerateStandardClassesInTable(
1071 cx, global, properties, builtin_property_names, includeResolved)) {
1072 return false;
1075 return true;
1078 JS_PUBLIC_API bool JS_NewEnumerateStandardClasses(
1079 JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
1080 bool enumerableOnly) {
1081 return EnumerateStandardClasses(cx, obj, properties, enumerableOnly, false);
1084 JS_PUBLIC_API bool JS_NewEnumerateStandardClassesIncludingResolved(
1085 JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
1086 bool enumerableOnly) {
1087 return EnumerateStandardClasses(cx, obj, properties, enumerableOnly, true);
1090 JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key,
1091 MutableHandleObject objp) {
1092 AssertHeapIsIdle();
1093 CHECK_THREAD(cx);
1094 JSObject* obj = GlobalObject::getOrCreateConstructor(cx, key);
1095 if (!obj) {
1096 return false;
1098 objp.set(obj);
1099 return true;
1102 JS_PUBLIC_API bool JS_GetClassPrototype(JSContext* cx, JSProtoKey key,
1103 MutableHandleObject objp) {
1104 AssertHeapIsIdle();
1105 CHECK_THREAD(cx);
1107 // Bound functions don't have their own prototype object: they reuse the
1108 // prototype of the target object. This is typically Function.prototype so we
1109 // use that here.
1110 if (key == JSProto_BoundFunction) {
1111 key = JSProto_Function;
1114 JSObject* proto = GlobalObject::getOrCreatePrototype(cx, key);
1115 if (!proto) {
1116 return false;
1118 objp.set(proto);
1119 return true;
1122 namespace JS {
1124 JS_PUBLIC_API void ProtoKeyToId(JSContext* cx, JSProtoKey key,
1125 MutableHandleId idp) {
1126 idp.set(NameToId(ClassName(key, cx)));
1129 } /* namespace JS */
1131 JS_PUBLIC_API JSProtoKey JS_IdToProtoKey(JSContext* cx, HandleId id) {
1132 AssertHeapIsIdle();
1133 CHECK_THREAD(cx);
1134 cx->check(id);
1136 if (!id.isAtom()) {
1137 return JSProto_Null;
1140 JSAtom* atom = id.toAtom();
1141 const JSStdName* stdnm =
1142 LookupStdName(cx->names(), atom, standard_class_names);
1143 if (!stdnm) {
1144 return JSProto_Null;
1147 if (GlobalObject::skipDeselectedConstructor(cx, stdnm->key)) {
1148 return JSProto_Null;
1151 if (SkipSharedArrayBufferConstructor(stdnm->key, cx->global())) {
1152 MOZ_ASSERT(id == NameToId(cx->names().SharedArrayBuffer));
1153 return JSProto_Null;
1156 if (SkipUneval(id, cx)) {
1157 return JSProto_Null;
1160 static_assert(std::size(standard_class_names) == JSProto_LIMIT + 1);
1161 return static_cast<JSProtoKey>(stdnm - standard_class_names);
1164 extern JS_PUBLIC_API bool JS_IsGlobalObject(JSObject* obj) {
1165 return obj->is<GlobalObject>();
1168 extern JS_PUBLIC_API JSObject* JS_GlobalLexicalEnvironment(JSObject* obj) {
1169 return &obj->as<GlobalObject>().lexicalEnvironment();
1172 extern JS_PUBLIC_API bool JS_HasExtensibleLexicalEnvironment(JSObject* obj) {
1173 return obj->is<GlobalObject>() ||
1174 ObjectRealm::get(obj).getNonSyntacticLexicalEnvironment(obj);
1177 extern JS_PUBLIC_API JSObject* JS_ExtensibleLexicalEnvironment(JSObject* obj) {
1178 return ExtensibleLexicalEnvironmentObject::forVarEnvironment(obj);
1181 JS_PUBLIC_API JSObject* JS::CurrentGlobalOrNull(JSContext* cx) {
1182 AssertHeapIsIdleOrIterating();
1183 CHECK_THREAD(cx);
1184 if (!cx->realm()) {
1185 return nullptr;
1187 return cx->global();
1190 JS_PUBLIC_API JSObject* JS::GetNonCCWObjectGlobal(JSObject* obj) {
1191 AssertHeapIsIdleOrIterating();
1192 MOZ_DIAGNOSTIC_ASSERT(!IsCrossCompartmentWrapper(obj));
1193 return &obj->nonCCWGlobal();
1196 JS_PUBLIC_API bool JS::detail::ComputeThis(JSContext* cx, Value* vp,
1197 MutableHandleObject thisObject) {
1198 AssertHeapIsIdle();
1199 cx->check(vp[0], vp[1]);
1201 MutableHandleValue thisv = MutableHandleValue::fromMarkedLocation(&vp[1]);
1202 JSObject* obj = BoxNonStrictThis(cx, thisv);
1203 if (!obj) {
1204 return false;
1207 thisObject.set(obj);
1208 return true;
1211 static bool gProfileTimelineRecordingEnabled = false;
1213 JS_PUBLIC_API void JS::SetProfileTimelineRecordingEnabled(bool enabled) {
1214 gProfileTimelineRecordingEnabled = enabled;
1217 JS_PUBLIC_API bool JS::IsProfileTimelineRecordingEnabled() {
1218 return gProfileTimelineRecordingEnabled;
1221 JS_PUBLIC_API void* JS_malloc(JSContext* cx, size_t nbytes) {
1222 AssertHeapIsIdle();
1223 CHECK_THREAD(cx);
1224 return static_cast<void*>(cx->maybe_pod_malloc<uint8_t>(nbytes));
1227 JS_PUBLIC_API void* JS_realloc(JSContext* cx, void* p, size_t oldBytes,
1228 size_t newBytes) {
1229 AssertHeapIsIdle();
1230 CHECK_THREAD(cx);
1231 return static_cast<void*>(cx->maybe_pod_realloc<uint8_t>(
1232 static_cast<uint8_t*>(p), oldBytes, newBytes));
1235 JS_PUBLIC_API void JS_free(JSContext* cx, void* p) { return js_free(p); }
1237 JS_PUBLIC_API void* JS_string_malloc(JSContext* cx, size_t nbytes) {
1238 AssertHeapIsIdle();
1239 CHECK_THREAD(cx);
1240 return static_cast<void*>(
1241 cx->maybe_pod_arena_malloc<uint8_t>(js::StringBufferArena, nbytes));
1244 JS_PUBLIC_API void* JS_string_realloc(JSContext* cx, void* p, size_t oldBytes,
1245 size_t newBytes) {
1246 AssertHeapIsIdle();
1247 CHECK_THREAD(cx);
1248 return static_cast<void*>(cx->maybe_pod_arena_realloc<uint8_t>(
1249 js::StringBufferArena, static_cast<uint8_t*>(p), oldBytes, newBytes));
1252 JS_PUBLIC_API void JS_string_free(JSContext* cx, void* p) { return js_free(p); }
1254 JS_PUBLIC_API void JS::AddAssociatedMemory(JSObject* obj, size_t nbytes,
1255 JS::MemoryUse use) {
1256 MOZ_ASSERT(obj);
1257 if (!nbytes) {
1258 return;
1261 Zone* zone = obj->zone();
1262 MOZ_ASSERT(!IsInsideNursery(obj));
1263 zone->addCellMemory(obj, nbytes, js::MemoryUse(use));
1264 zone->maybeTriggerGCOnMalloc();
1267 JS_PUBLIC_API void JS::RemoveAssociatedMemory(JSObject* obj, size_t nbytes,
1268 JS::MemoryUse use) {
1269 MOZ_ASSERT(obj);
1270 if (!nbytes) {
1271 return;
1274 GCContext* gcx = obj->runtimeFromMainThread()->gcContext();
1275 gcx->removeCellMemory(obj, nbytes, js::MemoryUse(use));
1278 #undef JS_AddRoot
1280 JS_PUBLIC_API bool JS_AddExtraGCRootsTracer(JSContext* cx,
1281 JSTraceDataOp traceOp, void* data) {
1282 return cx->runtime()->gc.addBlackRootsTracer(traceOp, data);
1285 JS_PUBLIC_API void JS_RemoveExtraGCRootsTracer(JSContext* cx,
1286 JSTraceDataOp traceOp,
1287 void* data) {
1288 return cx->runtime()->gc.removeBlackRootsTracer(traceOp, data);
1291 JS_PUBLIC_API JS::GCReason JS::WantEagerMinorGC(JSRuntime* rt) {
1292 if (rt->gc.nursery().wantEagerCollection()) {
1293 return JS::GCReason::EAGER_NURSERY_COLLECTION;
1295 return JS::GCReason::NO_REASON;
1298 JS_PUBLIC_API JS::GCReason JS::WantEagerMajorGC(JSRuntime* rt) {
1299 return rt->gc.wantMajorGC(true);
1302 JS_PUBLIC_API void JS::MaybeRunNurseryCollection(JSRuntime* rt,
1303 JS::GCReason reason) {
1304 gc::GCRuntime& gc = rt->gc;
1305 if (gc.nursery().wantEagerCollection()) {
1306 gc.minorGC(reason);
1310 JS_PUBLIC_API void JS::RunNurseryCollection(
1311 JSRuntime* rt, JS::GCReason reason,
1312 mozilla::TimeDuration aSinceLastMinorGC) {
1313 gc::GCRuntime& gc = rt->gc;
1314 if (!gc.nursery().lastCollectionEndTime() ||
1315 (mozilla::TimeStamp::Now() - gc.nursery().lastCollectionEndTime() >
1316 aSinceLastMinorGC)) {
1317 gc.minorGC(reason);
1321 JS_PUBLIC_API void JS_GC(JSContext* cx, JS::GCReason reason) {
1322 AssertHeapIsIdle();
1323 JS::PrepareForFullGC(cx);
1324 cx->runtime()->gc.gc(JS::GCOptions::Normal, reason);
1327 JS_PUBLIC_API void JS_MaybeGC(JSContext* cx) {
1328 AssertHeapIsIdle();
1329 cx->runtime()->gc.maybeGC();
1332 JS_PUBLIC_API void JS_SetGCCallback(JSContext* cx, JSGCCallback cb,
1333 void* data) {
1334 AssertHeapIsIdle();
1335 cx->runtime()->gc.setGCCallback(cb, data);
1338 JS_PUBLIC_API void JS_SetObjectsTenuredCallback(JSContext* cx,
1339 JSObjectsTenuredCallback cb,
1340 void* data) {
1341 AssertHeapIsIdle();
1342 cx->runtime()->gc.setObjectsTenuredCallback(cb, data);
1345 JS_PUBLIC_API bool JS_AddFinalizeCallback(JSContext* cx, JSFinalizeCallback cb,
1346 void* data) {
1347 AssertHeapIsIdle();
1348 return cx->runtime()->gc.addFinalizeCallback(cb, data);
1351 JS_PUBLIC_API void JS_RemoveFinalizeCallback(JSContext* cx,
1352 JSFinalizeCallback cb) {
1353 cx->runtime()->gc.removeFinalizeCallback(cb);
1356 JS_PUBLIC_API void JS::SetHostCleanupFinalizationRegistryCallback(
1357 JSContext* cx, JSHostCleanupFinalizationRegistryCallback cb, void* data) {
1358 AssertHeapIsIdle();
1359 cx->runtime()->gc.setHostCleanupFinalizationRegistryCallback(cb, data);
1362 JS_PUBLIC_API void JS::ClearKeptObjects(JSContext* cx) {
1363 gc::GCRuntime* gc = &cx->runtime()->gc;
1365 for (ZonesIter zone(gc, ZoneSelector::WithAtoms); !zone.done(); zone.next()) {
1366 zone->clearKeptObjects();
1370 JS_PUBLIC_API bool JS::AtomsZoneIsCollecting(JSRuntime* runtime) {
1371 return runtime->activeGCInAtomsZone();
1374 JS_PUBLIC_API bool JS::IsAtomsZone(JS::Zone* zone) {
1375 return zone->isAtomsZone();
1378 JS_PUBLIC_API bool JS_AddWeakPointerZonesCallback(JSContext* cx,
1379 JSWeakPointerZonesCallback cb,
1380 void* data) {
1381 AssertHeapIsIdle();
1382 return cx->runtime()->gc.addWeakPointerZonesCallback(cb, data);
1385 JS_PUBLIC_API void JS_RemoveWeakPointerZonesCallback(
1386 JSContext* cx, JSWeakPointerZonesCallback cb) {
1387 cx->runtime()->gc.removeWeakPointerZonesCallback(cb);
1390 JS_PUBLIC_API bool JS_AddWeakPointerCompartmentCallback(
1391 JSContext* cx, JSWeakPointerCompartmentCallback cb, void* data) {
1392 AssertHeapIsIdle();
1393 return cx->runtime()->gc.addWeakPointerCompartmentCallback(cb, data);
1396 JS_PUBLIC_API void JS_RemoveWeakPointerCompartmentCallback(
1397 JSContext* cx, JSWeakPointerCompartmentCallback cb) {
1398 cx->runtime()->gc.removeWeakPointerCompartmentCallback(cb);
1401 JS_PUBLIC_API bool JS_UpdateWeakPointerAfterGC(JSTracer* trc,
1402 JS::Heap<JSObject*>* objp) {
1403 return TraceWeakEdge(trc, objp);
1406 JS_PUBLIC_API bool JS_UpdateWeakPointerAfterGCUnbarriered(JSTracer* trc,
1407 JSObject** objp) {
1408 return TraceManuallyBarrieredWeakEdge(trc, objp, "External weak pointer");
1411 JS_PUBLIC_API void JS_SetGCParameter(JSContext* cx, JSGCParamKey key,
1412 uint32_t value) {
1413 // Bug 1742118: JS_SetGCParameter has no way to return an error
1414 // The GC ignores invalid values internally but this is not reported to the
1415 // caller.
1416 (void)cx->runtime()->gc.setParameter(cx, key, value);
1419 JS_PUBLIC_API void JS_ResetGCParameter(JSContext* cx, JSGCParamKey key) {
1420 cx->runtime()->gc.resetParameter(cx, key);
1423 JS_PUBLIC_API uint32_t JS_GetGCParameter(JSContext* cx, JSGCParamKey key) {
1424 return cx->runtime()->gc.getParameter(key);
1427 JS_PUBLIC_API void JS_SetGCParametersBasedOnAvailableMemory(
1428 JSContext* cx, uint32_t availMemMB) {
1429 struct JSGCConfig {
1430 JSGCParamKey key;
1431 uint32_t value;
1434 static const JSGCConfig minimal[] = {
1435 {JSGC_SLICE_TIME_BUDGET_MS, 5},
1436 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
1437 {JSGC_LARGE_HEAP_SIZE_MIN, 250},
1438 {JSGC_SMALL_HEAP_SIZE_MAX, 50},
1439 {JSGC_HIGH_FREQUENCY_SMALL_HEAP_GROWTH, 300},
1440 {JSGC_HIGH_FREQUENCY_LARGE_HEAP_GROWTH, 120},
1441 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 120},
1442 {JSGC_ALLOCATION_THRESHOLD, 15},
1443 {JSGC_MALLOC_THRESHOLD_BASE, 20},
1444 {JSGC_SMALL_HEAP_INCREMENTAL_LIMIT, 200},
1445 {JSGC_LARGE_HEAP_INCREMENTAL_LIMIT, 110},
1446 {JSGC_URGENT_THRESHOLD_MB, 8}};
1448 static const JSGCConfig nominal[] = {
1449 {JSGC_SLICE_TIME_BUDGET_MS, 5},
1450 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1000},
1451 {JSGC_LARGE_HEAP_SIZE_MIN, 500},
1452 {JSGC_SMALL_HEAP_SIZE_MAX, 100},
1453 {JSGC_HIGH_FREQUENCY_SMALL_HEAP_GROWTH, 300},
1454 {JSGC_HIGH_FREQUENCY_LARGE_HEAP_GROWTH, 150},
1455 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 150},
1456 {JSGC_ALLOCATION_THRESHOLD, 27},
1457 {JSGC_MALLOC_THRESHOLD_BASE, 38},
1458 {JSGC_SMALL_HEAP_INCREMENTAL_LIMIT, 150},
1459 {JSGC_LARGE_HEAP_INCREMENTAL_LIMIT, 110},
1460 {JSGC_URGENT_THRESHOLD_MB, 16}};
1462 const auto& configSet = availMemMB > 512 ? nominal : minimal;
1463 for (const auto& config : configSet) {
1464 JS_SetGCParameter(cx, config.key, config.value);
1468 JS_PUBLIC_API JSString* JS_NewExternalStringLatin1(
1469 JSContext* cx, const Latin1Char* chars, size_t length,
1470 const JSExternalStringCallbacks* callbacks) {
1471 AssertHeapIsIdle();
1472 CHECK_THREAD(cx);
1473 return JSExternalString::new_(cx, chars, length, callbacks);
1476 JS_PUBLIC_API JSString* JS_NewExternalUCString(
1477 JSContext* cx, const char16_t* chars, size_t length,
1478 const JSExternalStringCallbacks* callbacks) {
1479 AssertHeapIsIdle();
1480 CHECK_THREAD(cx);
1481 return JSExternalString::new_(cx, chars, length, callbacks);
1484 JS_PUBLIC_API JSString* JS_NewMaybeExternalStringLatin1(
1485 JSContext* cx, const JS::Latin1Char* chars, size_t length,
1486 const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) {
1487 AssertHeapIsIdle();
1488 CHECK_THREAD(cx);
1489 return NewMaybeExternalString(cx, chars, length, callbacks,
1490 allocatedExternal);
1493 JS_PUBLIC_API JSString* JS_NewMaybeExternalStringUTF8(
1494 JSContext* cx, const JS::UTF8Chars& utf8,
1495 const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) {
1496 AssertHeapIsIdle();
1497 CHECK_THREAD(cx);
1499 JS::SmallestEncoding encoding = JS::FindSmallestEncoding(utf8);
1500 if (encoding == JS::SmallestEncoding::ASCII) {
1501 // ASCII case can use the external buffer as Latin1 buffer.
1502 return NewMaybeExternalString(
1503 cx, reinterpret_cast<JS::Latin1Char*>(utf8.begin().get()),
1504 utf8.length(), callbacks, allocatedExternal);
1507 // Non-ASCII case cannot use the external buffer.
1508 *allocatedExternal = false;
1509 return NewStringCopyUTF8N(cx, utf8, encoding);
1512 JS_PUBLIC_API JSString* JS_NewMaybeExternalUCString(
1513 JSContext* cx, const char16_t* chars, size_t length,
1514 const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) {
1515 AssertHeapIsIdle();
1516 CHECK_THREAD(cx);
1517 return NewMaybeExternalString(cx, chars, length, callbacks,
1518 allocatedExternal);
1521 extern JS_PUBLIC_API const JSExternalStringCallbacks*
1522 JS_GetExternalStringCallbacks(JSString* str) {
1523 return str->asExternal().callbacks();
1526 static void SetNativeStackSize(JSContext* cx, JS::StackKind kind,
1527 JS::NativeStackSize stackSize) {
1528 #ifdef __wasi__
1529 cx->nativeStackLimit[kind] = JS::WASINativeStackLimit;
1530 #else // __wasi__
1531 if (stackSize == 0) {
1532 cx->nativeStackLimit[kind] = JS::NativeStackLimitMax;
1533 } else {
1534 cx->nativeStackLimit[kind] =
1535 JS::GetNativeStackLimit(cx->nativeStackBase(), stackSize - 1);
1537 #endif // !__wasi__
1540 JS_PUBLIC_API void JS_SetNativeStackQuota(
1541 JSContext* cx, JS::NativeStackSize systemCodeStackSize,
1542 JS::NativeStackSize trustedScriptStackSize,
1543 JS::NativeStackSize untrustedScriptStackSize) {
1544 MOZ_ASSERT(!cx->activation());
1546 if (!trustedScriptStackSize) {
1547 trustedScriptStackSize = systemCodeStackSize;
1548 } else {
1549 MOZ_ASSERT(trustedScriptStackSize < systemCodeStackSize);
1552 if (!untrustedScriptStackSize) {
1553 untrustedScriptStackSize = trustedScriptStackSize;
1554 } else {
1555 MOZ_ASSERT(untrustedScriptStackSize < trustedScriptStackSize);
1558 SetNativeStackSize(cx, JS::StackForSystemCode, systemCodeStackSize);
1559 SetNativeStackSize(cx, JS::StackForTrustedScript, trustedScriptStackSize);
1560 SetNativeStackSize(cx, JS::StackForUntrustedScript, untrustedScriptStackSize);
1562 cx->initJitStackLimit();
1565 /************************************************************************/
1567 JS_PUBLIC_API bool JS_ValueToId(JSContext* cx, HandleValue value,
1568 MutableHandleId idp) {
1569 AssertHeapIsIdle();
1570 CHECK_THREAD(cx);
1571 cx->check(value);
1572 return ToPropertyKey(cx, value, idp);
1575 JS_PUBLIC_API bool JS_StringToId(JSContext* cx, HandleString string,
1576 MutableHandleId idp) {
1577 AssertHeapIsIdle();
1578 CHECK_THREAD(cx);
1579 cx->check(string);
1580 RootedValue value(cx, StringValue(string));
1581 return PrimitiveValueToId<CanGC>(cx, value, idp);
1584 JS_PUBLIC_API bool JS_IdToValue(JSContext* cx, jsid id, MutableHandleValue vp) {
1585 AssertHeapIsIdle();
1586 CHECK_THREAD(cx);
1587 cx->check(id);
1588 vp.set(IdToValue(id));
1589 cx->check(vp);
1590 return true;
1593 JS_PUBLIC_API bool JS::ToPrimitive(JSContext* cx, HandleObject obj, JSType hint,
1594 MutableHandleValue vp) {
1595 AssertHeapIsIdle();
1596 CHECK_THREAD(cx);
1597 cx->check(obj);
1598 MOZ_ASSERT(obj != nullptr);
1599 MOZ_ASSERT(hint == JSTYPE_UNDEFINED || hint == JSTYPE_STRING ||
1600 hint == JSTYPE_NUMBER);
1601 vp.setObject(*obj);
1602 return ToPrimitiveSlow(cx, hint, vp);
1605 JS_PUBLIC_API bool JS::GetFirstArgumentAsTypeHint(JSContext* cx,
1606 const CallArgs& args,
1607 JSType* result) {
1608 if (!args.get(0).isString()) {
1609 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1610 JSMSG_NOT_EXPECTED_TYPE, "Symbol.toPrimitive",
1611 "\"string\", \"number\", or \"default\"",
1612 InformalValueTypeName(args.get(0)));
1613 return false;
1616 RootedString str(cx, args.get(0).toString());
1617 bool match;
1619 if (!EqualStrings(cx, str, cx->names().default_, &match)) {
1620 return false;
1622 if (match) {
1623 *result = JSTYPE_UNDEFINED;
1624 return true;
1627 if (!EqualStrings(cx, str, cx->names().string, &match)) {
1628 return false;
1630 if (match) {
1631 *result = JSTYPE_STRING;
1632 return true;
1635 if (!EqualStrings(cx, str, cx->names().number, &match)) {
1636 return false;
1638 if (match) {
1639 *result = JSTYPE_NUMBER;
1640 return true;
1643 UniqueChars bytes;
1644 const char* source = ValueToSourceForError(cx, args.get(0), bytes);
1645 if (!source) {
1646 ReportOutOfMemory(cx);
1647 return false;
1650 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
1651 JSMSG_NOT_EXPECTED_TYPE, "Symbol.toPrimitive",
1652 "\"string\", \"number\", or \"default\"", source);
1653 return false;
1656 JS_PUBLIC_API JSObject* JS_InitClass(
1657 JSContext* cx, HandleObject obj, const JSClass* protoClass,
1658 HandleObject protoProto, const char* name, JSNative constructor,
1659 unsigned nargs, const JSPropertySpec* ps, const JSFunctionSpec* fs,
1660 const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs) {
1661 AssertHeapIsIdle();
1662 CHECK_THREAD(cx);
1663 cx->check(obj, protoProto);
1664 return InitClass(cx, obj, protoClass, protoProto, name, constructor, nargs,
1665 ps, fs, static_ps, static_fs);
1668 JS_PUBLIC_API bool JS_LinkConstructorAndPrototype(JSContext* cx,
1669 HandleObject ctor,
1670 HandleObject proto) {
1671 return LinkConstructorAndPrototype(cx, ctor, proto);
1674 JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx, HandleObject obj,
1675 const JSClass* clasp, CallArgs* args) {
1676 AssertHeapIsIdle();
1677 CHECK_THREAD(cx);
1678 #ifdef DEBUG
1679 if (args) {
1680 cx->check(obj);
1681 cx->check(args->thisv(), args->calleev());
1683 #endif
1684 if (!obj || obj->getClass() != clasp) {
1685 if (args) {
1686 ReportIncompatibleMethod(cx, *args, clasp);
1688 return false;
1690 return true;
1693 JS_PUBLIC_API bool JS_HasInstance(JSContext* cx, HandleObject obj,
1694 HandleValue value, bool* bp) {
1695 AssertHeapIsIdle();
1696 cx->check(obj, value);
1697 return InstanceofOperator(cx, obj, value, bp);
1700 JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx, HandleObject proto) {
1701 AssertHeapIsIdle();
1702 CHECK_THREAD(cx);
1703 cx->check(proto);
1705 RootedValue cval(cx);
1706 if (!GetProperty(cx, proto, proto, cx->names().constructor, &cval)) {
1707 return nullptr;
1709 if (!IsFunctionObject(cval)) {
1710 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
1711 JSMSG_NO_CONSTRUCTOR, proto->getClass()->name);
1712 return nullptr;
1714 return &cval.toObject();
1717 JS::RealmCreationOptions&
1718 JS::RealmCreationOptions::setNewCompartmentInSystemZone() {
1719 compSpec_ = CompartmentSpecifier::NewCompartmentInSystemZone;
1720 comp_ = nullptr;
1721 return *this;
1724 JS::RealmCreationOptions&
1725 JS::RealmCreationOptions::setNewCompartmentInExistingZone(JSObject* obj) {
1726 compSpec_ = CompartmentSpecifier::NewCompartmentInExistingZone;
1727 zone_ = obj->zone();
1728 return *this;
1731 JS::RealmCreationOptions& JS::RealmCreationOptions::setExistingCompartment(
1732 JSObject* obj) {
1733 compSpec_ = CompartmentSpecifier::ExistingCompartment;
1734 comp_ = obj->compartment();
1735 return *this;
1738 JS::RealmCreationOptions& JS::RealmCreationOptions::setExistingCompartment(
1739 JS::Compartment* compartment) {
1740 compSpec_ = CompartmentSpecifier::ExistingCompartment;
1741 comp_ = compartment;
1742 return *this;
1745 JS::RealmCreationOptions& JS::RealmCreationOptions::setNewCompartmentAndZone() {
1746 compSpec_ = CompartmentSpecifier::NewCompartmentAndZone;
1747 comp_ = nullptr;
1748 return *this;
1751 const JS::RealmCreationOptions& JS::RealmCreationOptionsRef(Realm* realm) {
1752 return realm->creationOptions();
1755 const JS::RealmCreationOptions& JS::RealmCreationOptionsRef(JSContext* cx) {
1756 return cx->realm()->creationOptions();
1759 bool JS::RealmCreationOptions::getSharedMemoryAndAtomicsEnabled() const {
1760 return sharedMemoryAndAtomics_;
1763 JS::RealmCreationOptions&
1764 JS::RealmCreationOptions::setSharedMemoryAndAtomicsEnabled(bool flag) {
1765 sharedMemoryAndAtomics_ = flag;
1766 return *this;
1769 bool JS::RealmCreationOptions::getCoopAndCoepEnabled() const {
1770 return coopAndCoep_;
1773 JS::RealmCreationOptions& JS::RealmCreationOptions::setCoopAndCoepEnabled(
1774 bool flag) {
1775 coopAndCoep_ = flag;
1776 return *this;
1779 JS::RealmCreationOptions& JS::RealmCreationOptions::setLocaleCopyZ(
1780 const char* locale) {
1781 const size_t size = strlen(locale) + 1;
1783 AutoEnterOOMUnsafeRegion oomUnsafe;
1784 char* memoryPtr = js_pod_malloc<char>(sizeof(LocaleString) + size);
1785 if (!memoryPtr) {
1786 oomUnsafe.crash("RealmCreationOptions::setLocaleCopyZ");
1789 char* localePtr = memoryPtr + sizeof(LocaleString);
1790 memcpy(localePtr, locale, size);
1792 locale_ = new (memoryPtr) LocaleString(localePtr);
1794 return *this;
1797 const JS::RealmBehaviors& JS::RealmBehaviorsRef(JS::Realm* realm) {
1798 return realm->behaviors();
1801 const JS::RealmBehaviors& JS::RealmBehaviorsRef(JSContext* cx) {
1802 return cx->realm()->behaviors();
1805 void JS::SetRealmNonLive(Realm* realm) { realm->setNonLive(); }
1807 void JS::SetRealmReduceTimerPrecisionCallerType(Realm* realm,
1808 JS::RTPCallerTypeToken type) {
1809 realm->setReduceTimerPrecisionCallerType(type);
1812 JS_PUBLIC_API JSObject* JS_NewGlobalObject(JSContext* cx, const JSClass* clasp,
1813 JSPrincipals* principals,
1814 JS::OnNewGlobalHookOption hookOption,
1815 const JS::RealmOptions& options) {
1816 MOZ_RELEASE_ASSERT(
1817 cx->runtime()->hasInitializedSelfHosting(),
1818 "Must call JS::InitSelfHostedCode() before creating a global");
1820 AssertHeapIsIdle();
1821 CHECK_THREAD(cx);
1823 return GlobalObject::new_(cx, clasp, principals, hookOption, options);
1826 JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global) {
1827 GlobalObject* globalObj = &global->as<GlobalObject>();
1828 Realm* globalRealm = globalObj->realm();
1830 // If we GC when creating the global, we may not have set that global's
1831 // realm's global pointer yet. In this case, the realm will not yet contain
1832 // anything that needs to be traced.
1833 if (globalRealm->unsafeUnbarrieredMaybeGlobal() != globalObj) {
1834 return;
1837 // Trace the realm for any GC things that should only stick around if we
1838 // know the global is live.
1839 globalRealm->traceGlobalData(trc);
1841 globalObj->traceData(trc, globalObj);
1843 if (JSTraceOp trace = globalRealm->creationOptions().getTrace()) {
1844 trace(trc, global);
1848 const JSClassOps JS::DefaultGlobalClassOps = {
1849 nullptr, // addProperty
1850 nullptr, // delProperty
1851 nullptr, // enumerate
1852 JS_NewEnumerateStandardClasses, // newEnumerate
1853 JS_ResolveStandardClass, // resolve
1854 JS_MayResolveStandardClass, // mayResolve
1855 nullptr, // finalize
1856 nullptr, // call
1857 nullptr, // construct
1858 JS_GlobalObjectTraceHook, // trace
1861 JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx,
1862 JS::HandleObject global) {
1863 // This hook is infallible, because we don't really want arbitrary script
1864 // to be able to throw errors during delicate global creation routines.
1865 // This infallibility will eat OOM and slow script, but if that happens
1866 // we'll likely run up into them again soon in a fallible context.
1867 cx->check(global);
1869 Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>());
1870 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1871 if (JS::GetReduceMicrosecondTimePrecisionCallback()) {
1872 MOZ_DIAGNOSTIC_ASSERT(globalObject->realm()
1873 ->behaviors()
1874 .reduceTimerPrecisionCallerType()
1875 .isSome(),
1876 "Trying to create a global without setting an "
1877 "explicit RTPCallerType!");
1879 #endif
1880 DebugAPI::onNewGlobalObject(cx, globalObject);
1881 cx->runtime()->ensureRealmIsRecordingAllocations(globalObject);
1884 JS_PUBLIC_API JSObject* JS_NewObject(JSContext* cx, const JSClass* clasp) {
1885 MOZ_ASSERT(!cx->zone()->isAtomsZone());
1886 AssertHeapIsIdle();
1887 CHECK_THREAD(cx);
1889 if (!clasp) {
1890 // Default class is Object.
1891 return NewPlainObject(cx);
1894 MOZ_ASSERT(!clasp->isJSFunction());
1895 MOZ_ASSERT(clasp != &PlainObject::class_);
1896 MOZ_ASSERT(clasp != &ArrayObject::class_);
1897 MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
1899 return NewBuiltinClassInstance(cx, clasp);
1902 JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProto(JSContext* cx,
1903 const JSClass* clasp,
1904 HandleObject proto) {
1905 MOZ_ASSERT(!cx->zone()->isAtomsZone());
1906 AssertHeapIsIdle();
1907 CHECK_THREAD(cx);
1908 cx->check(proto);
1910 if (!clasp) {
1911 // Default class is Object.
1912 return NewPlainObjectWithProto(cx, proto);
1915 MOZ_ASSERT(!clasp->isJSFunction());
1916 MOZ_ASSERT(clasp != &PlainObject::class_);
1917 MOZ_ASSERT(clasp != &ArrayObject::class_);
1918 MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
1920 return NewObjectWithGivenProto(cx, clasp, proto);
1923 JS_PUBLIC_API JSObject* JS_NewPlainObject(JSContext* cx) {
1924 MOZ_ASSERT(!cx->zone()->isAtomsZone());
1925 AssertHeapIsIdle();
1926 CHECK_THREAD(cx);
1928 return NewPlainObject(cx);
1931 JS_PUBLIC_API JSObject* JS_NewObjectForConstructor(JSContext* cx,
1932 const JSClass* clasp,
1933 const CallArgs& args) {
1934 AssertHeapIsIdle();
1935 CHECK_THREAD(cx);
1937 MOZ_ASSERT(!clasp->isJSFunction());
1938 MOZ_ASSERT(clasp != &PlainObject::class_);
1939 MOZ_ASSERT(clasp != &ArrayObject::class_);
1940 MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
1942 if (!ThrowIfNotConstructing(cx, args, clasp->name)) {
1943 return nullptr;
1946 RootedObject newTarget(cx, &args.newTarget().toObject());
1947 cx->check(newTarget);
1949 RootedObject proto(cx);
1950 if (!GetPrototypeFromConstructor(cx, newTarget,
1951 JSCLASS_CACHED_PROTO_KEY(clasp), &proto)) {
1952 return nullptr;
1955 return NewObjectWithClassProto(cx, clasp, proto);
1958 JS_PUBLIC_API bool JS_IsNative(JSObject* obj) {
1959 return obj->is<NativeObject>();
1962 JS_PUBLIC_API void JS::AssertObjectBelongsToCurrentThread(JSObject* obj) {
1963 JSRuntime* rt = obj->compartment()->runtimeFromAnyThread();
1964 MOZ_RELEASE_ASSERT(CurrentThreadCanAccessRuntime(rt));
1967 JS_PUBLIC_API void JS::SetFilenameValidationCallback(
1968 JS::FilenameValidationCallback cb) {
1969 js::gFilenameValidationCallback = cb;
1972 JS_PUBLIC_API void JS::SetHostEnsureCanAddPrivateElementHook(
1973 JSContext* cx, JS::EnsureCanAddPrivateElementOp op) {
1974 cx->runtime()->canAddPrivateElement = op;
1977 /*** Standard internal methods **********************************************/
1979 JS_PUBLIC_API bool JS_GetPrototype(JSContext* cx, HandleObject obj,
1980 MutableHandleObject result) {
1981 cx->check(obj);
1982 return GetPrototype(cx, obj, result);
1985 JS_PUBLIC_API bool JS_SetPrototype(JSContext* cx, HandleObject obj,
1986 HandleObject proto) {
1987 AssertHeapIsIdle();
1988 CHECK_THREAD(cx);
1989 cx->check(obj, proto);
1991 return SetPrototype(cx, obj, proto);
1994 JS_PUBLIC_API bool JS_GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj,
1995 bool* isOrdinary,
1996 MutableHandleObject result) {
1997 cx->check(obj);
1998 return GetPrototypeIfOrdinary(cx, obj, isOrdinary, result);
2001 JS_PUBLIC_API bool JS_IsExtensible(JSContext* cx, HandleObject obj,
2002 bool* extensible) {
2003 cx->check(obj);
2004 return IsExtensible(cx, obj, extensible);
2007 JS_PUBLIC_API bool JS_PreventExtensions(JSContext* cx, JS::HandleObject obj,
2008 ObjectOpResult& result) {
2009 cx->check(obj);
2010 return PreventExtensions(cx, obj, result);
2013 JS_PUBLIC_API bool JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj,
2014 bool* succeeded) {
2015 cx->check(obj);
2016 return SetImmutablePrototype(cx, obj, succeeded);
2019 /* * */
2021 JS_PUBLIC_API bool JS_FreezeObject(JSContext* cx, HandleObject obj) {
2022 AssertHeapIsIdle();
2023 CHECK_THREAD(cx);
2024 cx->check(obj);
2025 return FreezeObject(cx, obj);
2028 static bool DeepFreezeSlot(JSContext* cx, const Value& v) {
2029 if (v.isPrimitive()) {
2030 return true;
2032 RootedObject obj(cx, &v.toObject());
2033 return JS_DeepFreezeObject(cx, obj);
2036 JS_PUBLIC_API bool JS_DeepFreezeObject(JSContext* cx, HandleObject obj) {
2037 AssertHeapIsIdle();
2038 CHECK_THREAD(cx);
2039 cx->check(obj);
2041 // Assume that non-extensible objects are already deep-frozen, to avoid
2042 // divergence.
2043 bool extensible;
2044 if (!IsExtensible(cx, obj, &extensible)) {
2045 return false;
2047 if (!extensible) {
2048 return true;
2051 if (!FreezeObject(cx, obj)) {
2052 return false;
2055 // Walk slots in obj and if any value is a non-null object, seal it.
2056 if (obj->is<NativeObject>()) {
2057 Rooted<NativeObject*> nobj(cx, &obj->as<NativeObject>());
2058 for (uint32_t i = 0, n = nobj->slotSpan(); i < n; ++i) {
2059 if (!DeepFreezeSlot(cx, nobj->getSlot(i))) {
2060 return false;
2063 for (uint32_t i = 0, n = nobj->getDenseInitializedLength(); i < n; ++i) {
2064 if (!DeepFreezeSlot(cx, nobj->getDenseElement(i))) {
2065 return false;
2070 return true;
2073 JS_PUBLIC_API bool JSPropertySpec::getValue(JSContext* cx,
2074 MutableHandleValue vp) const {
2075 MOZ_ASSERT(!isAccessor());
2077 switch (u.value.type) {
2078 case ValueWrapper::Type::String: {
2079 Rooted<JSAtom*> atom(cx,
2080 Atomize(cx, u.value.string, strlen(u.value.string)));
2081 if (!atom) {
2082 return false;
2084 vp.setString(atom);
2085 return true;
2088 case ValueWrapper::Type::Int32:
2089 vp.setInt32(u.value.int32);
2090 return true;
2092 case ValueWrapper::Type::Double:
2093 vp.setDouble(u.value.double_);
2094 return true;
2097 MOZ_CRASH("Unexpected type");
2100 bool PropertySpecNameToId(JSContext* cx, JSPropertySpec::Name name,
2101 MutableHandleId id) {
2102 if (name.isSymbol()) {
2103 id.set(PropertyKey::Symbol(cx->wellKnownSymbols().get(name.symbol())));
2104 } else {
2105 JSAtom* atom = Atomize(cx, name.string(), strlen(name.string()));
2106 if (!atom) {
2107 return false;
2109 id.set(AtomToId(atom));
2111 return true;
2114 JS_PUBLIC_API bool JS::PropertySpecNameToPermanentId(JSContext* cx,
2115 JSPropertySpec::Name name,
2116 jsid* idp) {
2117 // We are calling fromMarkedLocation(idp) even though idp points to a
2118 // location that will never be marked. This is OK because the whole point
2119 // of this API is to populate *idp with a jsid that does not need to be
2120 // marked.
2121 MutableHandleId id = MutableHandleId::fromMarkedLocation(idp);
2122 if (!PropertySpecNameToId(cx, name, id)) {
2123 return false;
2126 if (id.isString() && !PinAtom(cx, &id.toString()->asAtom())) {
2127 return false;
2130 return true;
2133 JS_PUBLIC_API bool JS::ToCompletePropertyDescriptor(
2134 JSContext* cx, HandleValue descriptor,
2135 MutableHandle<PropertyDescriptor> desc) {
2136 AssertHeapIsIdle();
2137 CHECK_THREAD(cx);
2138 cx->check(descriptor);
2139 if (!ToPropertyDescriptor(cx, descriptor, /* checkAccessors */ true, desc)) {
2140 return false;
2142 CompletePropertyDescriptor(desc);
2143 return true;
2146 JS_PUBLIC_API void JS_SetAllNonReservedSlotsToUndefined(JS::HandleObject obj) {
2147 if (!obj->is<NativeObject>()) {
2148 return;
2151 NativeObject& nobj = obj->as<NativeObject>();
2152 MOZ_RELEASE_ASSERT(!Watchtower::watchesPropertyModification(&nobj));
2153 const JSClass* clasp = obj->getClass();
2154 unsigned numReserved = JSCLASS_RESERVED_SLOTS(clasp);
2155 unsigned numSlots = nobj.slotSpan();
2156 for (unsigned i = numReserved; i < numSlots; i++) {
2157 obj->as<NativeObject>().setSlot(i, UndefinedValue());
2161 JS_PUBLIC_API void JS_SetReservedSlot(JSObject* obj, uint32_t index,
2162 const Value& value) {
2163 // Note: we don't use setReservedSlot so that this also works on swappable DOM
2164 // objects. See NativeObject::getReservedSlotRef comment.
2165 NativeObject& nobj = obj->as<NativeObject>();
2166 MOZ_ASSERT(index < JSCLASS_RESERVED_SLOTS(obj->getClass()));
2167 MOZ_ASSERT(!Watchtower::watchesPropertyModification(&nobj));
2168 nobj.setSlot(index, value);
2171 JS_PUBLIC_API void JS_InitReservedSlot(JSObject* obj, uint32_t index, void* ptr,
2172 size_t nbytes, JS::MemoryUse use) {
2173 // Note: we don't use InitReservedSlot so that this also works on swappable
2174 // DOM objects. See NativeObject::getReservedSlotRef comment.
2175 MOZ_ASSERT(index < JSCLASS_RESERVED_SLOTS(obj->getClass()));
2176 AddCellMemory(obj, nbytes, js::MemoryUse(use));
2177 obj->as<NativeObject>().initSlot(index, PrivateValue(ptr));
2180 JS_PUBLIC_API bool JS::IsMapObject(JSContext* cx, JS::HandleObject obj,
2181 bool* isMap) {
2182 return IsGivenTypeObject(cx, obj, ESClass::Map, isMap);
2185 JS_PUBLIC_API bool JS::IsSetObject(JSContext* cx, JS::HandleObject obj,
2186 bool* isSet) {
2187 return IsGivenTypeObject(cx, obj, ESClass::Set, isSet);
2190 JS_PUBLIC_API void JS_HoldPrincipals(JSPrincipals* principals) {
2191 ++principals->refcount;
2194 JS_PUBLIC_API void JS_DropPrincipals(JSContext* cx, JSPrincipals* principals) {
2195 int rc = --principals->refcount;
2196 if (rc == 0) {
2197 JS::AutoSuppressGCAnalysis nogc;
2198 cx->runtime()->destroyPrincipals(principals);
2202 JS_PUBLIC_API void JS_SetSecurityCallbacks(JSContext* cx,
2203 const JSSecurityCallbacks* scb) {
2204 MOZ_ASSERT(scb != &NullSecurityCallbacks);
2205 cx->runtime()->securityCallbacks = scb ? scb : &NullSecurityCallbacks;
2208 JS_PUBLIC_API const JSSecurityCallbacks* JS_GetSecurityCallbacks(
2209 JSContext* cx) {
2210 return (cx->runtime()->securityCallbacks != &NullSecurityCallbacks)
2211 ? cx->runtime()->securityCallbacks.ref()
2212 : nullptr;
2215 JS_PUBLIC_API void JS_SetTrustedPrincipals(JSContext* cx, JSPrincipals* prin) {
2216 cx->runtime()->setTrustedPrincipals(prin);
2219 extern JS_PUBLIC_API void JS_InitDestroyPrincipalsCallback(
2220 JSContext* cx, JSDestroyPrincipalsOp destroyPrincipals) {
2221 MOZ_ASSERT(destroyPrincipals);
2222 MOZ_ASSERT(!cx->runtime()->destroyPrincipals);
2223 cx->runtime()->destroyPrincipals = destroyPrincipals;
2226 extern JS_PUBLIC_API void JS_InitReadPrincipalsCallback(
2227 JSContext* cx, JSReadPrincipalsOp read) {
2228 MOZ_ASSERT(read);
2229 MOZ_ASSERT(!cx->runtime()->readPrincipals);
2230 cx->runtime()->readPrincipals = read;
2233 JS_PUBLIC_API JSFunction* JS_NewFunction(JSContext* cx, JSNative native,
2234 unsigned nargs, unsigned flags,
2235 const char* name) {
2236 MOZ_ASSERT(!cx->zone()->isAtomsZone());
2238 AssertHeapIsIdle();
2239 CHECK_THREAD(cx);
2241 Rooted<JSAtom*> atom(cx);
2242 if (name) {
2243 atom = Atomize(cx, name, strlen(name));
2244 if (!atom) {
2245 return nullptr;
2249 return (flags & JSFUN_CONSTRUCTOR)
2250 ? NewNativeConstructor(cx, native, nargs, atom)
2251 : NewNativeFunction(cx, native, nargs, atom);
2254 JS_PUBLIC_API JSFunction* JS::GetSelfHostedFunction(JSContext* cx,
2255 const char* selfHostedName,
2256 HandleId id,
2257 unsigned nargs) {
2258 MOZ_ASSERT(!cx->zone()->isAtomsZone());
2259 AssertHeapIsIdle();
2260 CHECK_THREAD(cx);
2261 cx->check(id);
2263 Rooted<JSAtom*> name(cx, IdToFunctionName(cx, id));
2264 if (!name) {
2265 return nullptr;
2268 JSAtom* shAtom = Atomize(cx, selfHostedName, strlen(selfHostedName));
2269 if (!shAtom) {
2270 return nullptr;
2272 Rooted<PropertyName*> shName(cx, shAtom->asPropertyName());
2273 RootedValue funVal(cx);
2274 if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name,
2275 nargs, &funVal)) {
2276 return nullptr;
2278 return &funVal.toObject().as<JSFunction>();
2281 JS_PUBLIC_API JSFunction* JS::NewFunctionFromSpec(JSContext* cx,
2282 const JSFunctionSpec* fs,
2283 HandleId id) {
2284 cx->check(id);
2286 #ifdef DEBUG
2287 if (fs->name.isSymbol()) {
2288 JS::Symbol* sym = cx->wellKnownSymbols().get(fs->name.symbol());
2289 MOZ_ASSERT(PropertyKey::Symbol(sym) == id);
2290 } else {
2291 MOZ_ASSERT(id.isString() &&
2292 StringEqualsAscii(id.toLinearString(), fs->name.string()));
2294 #endif
2296 // Delay cloning self-hosted functions until they are called. This is
2297 // achieved by passing DefineFunction a nullptr JSNative which produces an
2298 // interpreted JSFunction where !hasScript. Interpreted call paths then
2299 // call InitializeLazyFunctionScript if !hasScript.
2300 if (fs->selfHostedName) {
2301 MOZ_ASSERT(!fs->call.op);
2302 MOZ_ASSERT(!fs->call.info);
2304 JSAtom* shAtom =
2305 Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName));
2306 if (!shAtom) {
2307 return nullptr;
2309 Rooted<PropertyName*> shName(cx, shAtom->asPropertyName());
2310 Rooted<JSAtom*> name(cx, IdToFunctionName(cx, id));
2311 if (!name) {
2312 return nullptr;
2314 RootedValue funVal(cx);
2315 if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name,
2316 fs->nargs, &funVal)) {
2317 return nullptr;
2319 return &funVal.toObject().as<JSFunction>();
2322 Rooted<JSAtom*> atom(cx, IdToFunctionName(cx, id));
2323 if (!atom) {
2324 return nullptr;
2327 MOZ_ASSERT(fs->call.op);
2329 JSFunction* fun;
2330 if (fs->flags & JSFUN_CONSTRUCTOR) {
2331 fun = NewNativeConstructor(cx, fs->call.op, fs->nargs, atom);
2332 } else {
2333 fun = NewNativeFunction(cx, fs->call.op, fs->nargs, atom);
2335 if (!fun) {
2336 return nullptr;
2339 if (fs->call.info) {
2340 fun->setJitInfo(fs->call.info);
2342 return fun;
2345 JS_PUBLIC_API JSFunction* JS::NewFunctionFromSpec(JSContext* cx,
2346 const JSFunctionSpec* fs) {
2347 RootedId id(cx);
2348 if (!PropertySpecNameToId(cx, fs->name, &id)) {
2349 return nullptr;
2352 return NewFunctionFromSpec(cx, fs, id);
2355 JS_PUBLIC_API JSObject* JS_GetFunctionObject(JSFunction* fun) { return fun; }
2357 JS_PUBLIC_API bool JS_GetFunctionId(JSContext* cx, JS::Handle<JSFunction*> fun,
2358 JS::MutableHandle<JSString*> name) {
2359 JS::Rooted<JSAtom*> atom(cx);
2360 if (!fun->getExplicitName(cx, &atom)) {
2361 return false;
2363 name.set(atom);
2364 return true;
2367 JS_PUBLIC_API JSString* JS_GetMaybePartialFunctionId(JSFunction* fun) {
2368 return fun->maybePartialExplicitName();
2371 JS_PUBLIC_API bool JS_GetFunctionDisplayId(JSContext* cx,
2372 JS::Handle<JSFunction*> fun,
2373 JS::MutableHandle<JSString*> name) {
2374 JS::Rooted<JSAtom*> atom(cx);
2375 if (!fun->getDisplayAtom(cx, &atom)) {
2376 return false;
2378 name.set(atom);
2379 return true;
2382 JS_PUBLIC_API JSString* JS_GetMaybePartialFunctionDisplayId(JSFunction* fun) {
2383 return fun->maybePartialDisplayAtom();
2386 JS_PUBLIC_API uint16_t JS_GetFunctionArity(JSFunction* fun) {
2387 return fun->nargs();
2390 JS_PUBLIC_API bool JS_GetFunctionLength(JSContext* cx, HandleFunction fun,
2391 uint16_t* length) {
2392 cx->check(fun);
2393 return JSFunction::getLength(cx, fun, length);
2396 JS_PUBLIC_API bool JS_ObjectIsFunction(JSObject* obj) {
2397 return obj->is<JSFunction>();
2400 JS_PUBLIC_API bool JS_IsNativeFunction(JSObject* funobj, JSNative call) {
2401 if (!funobj->is<JSFunction>()) {
2402 return false;
2404 JSFunction* fun = &funobj->as<JSFunction>();
2405 return fun->isNativeFun() && fun->native() == call;
2408 extern JS_PUBLIC_API bool JS_IsConstructor(JSFunction* fun) {
2409 return fun->isConstructor();
2412 void JS::TransitiveCompileOptions::copyPODTransitiveOptions(
2413 const TransitiveCompileOptions& rhs) {
2414 // filename_, introducerFilename_, sourceMapURL_ should be handled in caller.
2416 mutedErrors_ = rhs.mutedErrors_;
2417 forceStrictMode_ = rhs.forceStrictMode_;
2418 alwaysUseFdlibm_ = rhs.alwaysUseFdlibm_;
2419 skipFilenameValidation_ = rhs.skipFilenameValidation_;
2420 hideScriptFromDebugger_ = rhs.hideScriptFromDebugger_;
2421 deferDebugMetadata_ = rhs.deferDebugMetadata_;
2422 eagerDelazificationStrategy_ = rhs.eagerDelazificationStrategy_;
2424 selfHostingMode = rhs.selfHostingMode;
2425 discardSource = rhs.discardSource;
2426 sourceIsLazy = rhs.sourceIsLazy;
2427 allowHTMLComments = rhs.allowHTMLComments;
2428 nonSyntacticScope = rhs.nonSyntacticScope;
2430 topLevelAwait = rhs.topLevelAwait;
2432 borrowBuffer = rhs.borrowBuffer;
2433 usePinnedBytecode = rhs.usePinnedBytecode;
2434 deoptimizeModuleGlobalVars = rhs.deoptimizeModuleGlobalVars;
2436 prefableOptions_ = rhs.prefableOptions_;
2438 introductionType = rhs.introductionType;
2439 introductionLineno = rhs.introductionLineno;
2440 introductionOffset = rhs.introductionOffset;
2441 hasIntroductionInfo = rhs.hasIntroductionInfo;
2444 void JS::ReadOnlyCompileOptions::copyPODNonTransitiveOptions(
2445 const ReadOnlyCompileOptions& rhs) {
2446 lineno = rhs.lineno;
2447 column = rhs.column;
2448 scriptSourceOffset = rhs.scriptSourceOffset;
2449 isRunOnce = rhs.isRunOnce;
2450 noScriptRval = rhs.noScriptRval;
2453 JS::OwningCompileOptions::OwningCompileOptions(JSContext* cx) {}
2455 void JS::OwningCompileOptions::release() {
2456 // OwningCompileOptions always owns these, so these casts are okay.
2457 js_free(const_cast<char*>(filename_.c_str()));
2458 js_free(const_cast<char16_t*>(sourceMapURL_));
2459 js_free(const_cast<char*>(introducerFilename_.c_str()));
2461 filename_ = JS::ConstUTF8CharsZ();
2462 sourceMapURL_ = nullptr;
2463 introducerFilename_ = JS::ConstUTF8CharsZ();
2466 JS::OwningCompileOptions::~OwningCompileOptions() { release(); }
2468 size_t JS::OwningCompileOptions::sizeOfExcludingThis(
2469 mozilla::MallocSizeOf mallocSizeOf) const {
2470 return mallocSizeOf(filename_.c_str()) + mallocSizeOf(sourceMapURL_) +
2471 mallocSizeOf(introducerFilename_.c_str());
2474 void JS::OwningCompileOptions::steal(JS::OwningCompileOptions&& rhs) {
2475 // Release existing string allocations.
2476 release();
2478 copyPODNonTransitiveOptions(rhs);
2479 copyPODTransitiveOptions(rhs);
2481 filename_ = rhs.filename_;
2482 rhs.filename_ = JS::ConstUTF8CharsZ();
2483 introducerFilename_ = rhs.introducerFilename_;
2484 rhs.introducerFilename_ = JS::ConstUTF8CharsZ();
2485 sourceMapURL_ = rhs.sourceMapURL_;
2486 rhs.sourceMapURL_ = nullptr;
2489 void JS::OwningCompileOptions::steal(JS::OwningDecodeOptions&& rhs) {
2490 // Release existing string allocations.
2491 release();
2493 rhs.copyPODOptionsTo(*this);
2495 introducerFilename_ = rhs.introducerFilename_;
2496 rhs.introducerFilename_ = JS::ConstUTF8CharsZ();
2499 template <typename ContextT>
2500 bool JS::OwningCompileOptions::copyImpl(ContextT* cx,
2501 const ReadOnlyCompileOptions& rhs) {
2502 // Release existing string allocations.
2503 release();
2505 copyPODNonTransitiveOptions(rhs);
2506 copyPODTransitiveOptions(rhs);
2508 if (rhs.filename()) {
2509 const char* str = DuplicateString(cx, rhs.filename().c_str()).release();
2510 if (!str) {
2511 return false;
2513 filename_ = JS::ConstUTF8CharsZ(str);
2516 if (rhs.sourceMapURL()) {
2517 sourceMapURL_ = DuplicateString(cx, rhs.sourceMapURL()).release();
2518 if (!sourceMapURL_) {
2519 return false;
2523 if (rhs.introducerFilename()) {
2524 const char* str =
2525 DuplicateString(cx, rhs.introducerFilename().c_str()).release();
2526 if (!str) {
2527 return false;
2529 introducerFilename_ = JS::ConstUTF8CharsZ(str);
2532 return true;
2535 bool JS::OwningCompileOptions::copy(JSContext* cx,
2536 const ReadOnlyCompileOptions& rhs) {
2537 return copyImpl(cx, rhs);
2540 bool JS::OwningCompileOptions::copy(JS::FrontendContext* fc,
2541 const ReadOnlyCompileOptions& rhs) {
2542 return copyImpl(fc, rhs);
2545 JS::CompileOptions::CompileOptions(JSContext* cx) {
2546 prefableOptions_ = cx->options().compileOptions();
2548 if (cx->options().asmJSOption() == AsmJSOption::Enabled) {
2549 if (!js::IsAsmJSCompilationAvailable(cx)) {
2550 prefableOptions_.setAsmJSOption(AsmJSOption::DisabledByNoWasmCompiler);
2551 } else if (cx->realm() && (cx->realm()->debuggerObservesWasm() ||
2552 cx->realm()->debuggerObservesAsmJS())) {
2553 prefableOptions_.setAsmJSOption(AsmJSOption::DisabledByDebugger);
2557 // Certain modes of operation disallow syntax parsing in general.
2558 if (coverage::IsLCovEnabled()) {
2559 eagerDelazificationStrategy_ = DelazificationOption::ParseEverythingEagerly;
2562 // Note: If we parse outside of a specific realm, we do not inherit any realm
2563 // behaviours. These can still be set manually on the options though.
2564 if (Realm* realm = cx->realm()) {
2565 alwaysUseFdlibm_ = realm->creationOptions().alwaysUseFdlibm();
2566 discardSource = realm->behaviors().discardSource();
2570 CompileOptions& CompileOptions::setIntroductionInfoToCaller(
2571 JSContext* cx, const char* introductionType,
2572 MutableHandle<JSScript*> introductionScript) {
2573 RootedScript maybeScript(cx);
2574 const char* filename;
2575 uint32_t lineno;
2576 uint32_t pcOffset;
2577 bool mutedErrors;
2578 DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno,
2579 &pcOffset, &mutedErrors);
2580 if (filename) {
2581 introductionScript.set(maybeScript);
2582 return setIntroductionInfo(filename, introductionType, lineno, pcOffset);
2584 return setIntroductionType(introductionType);
2587 JS::OwningDecodeOptions::~OwningDecodeOptions() { release(); }
2589 void JS::OwningDecodeOptions::release() {
2590 js_free(const_cast<char*>(introducerFilename_.c_str()));
2592 introducerFilename_ = JS::ConstUTF8CharsZ();
2595 bool JS::OwningDecodeOptions::copy(JS::FrontendContext* maybeFc,
2596 const JS::ReadOnlyDecodeOptions& rhs) {
2597 copyPODOptionsFrom(rhs);
2599 if (rhs.introducerFilename()) {
2600 MOZ_ASSERT(maybeFc);
2601 const char* str =
2602 DuplicateString(maybeFc, rhs.introducerFilename().c_str()).release();
2603 if (!str) {
2604 return false;
2606 introducerFilename_ = JS::ConstUTF8CharsZ(str);
2609 return true;
2612 void JS::OwningDecodeOptions::infallibleCopy(
2613 const JS::ReadOnlyDecodeOptions& rhs) {
2614 copyPODOptionsFrom(rhs);
2616 MOZ_ASSERT(!rhs.introducerFilename());
2619 size_t JS::OwningDecodeOptions::sizeOfExcludingThis(
2620 mozilla::MallocSizeOf mallocSizeOf) const {
2621 return mallocSizeOf(introducerFilename_.c_str());
2624 JS_PUBLIC_API JSObject* JS_GetGlobalFromScript(JSScript* script) {
2625 return &script->global();
2628 JS_PUBLIC_API const char* JS_GetScriptFilename(JSScript* script) {
2629 // This is called from ThreadStackHelper which can be called from another
2630 // thread or inside a signal hander, so we need to be careful in case a
2631 // copmacting GC is currently moving things around.
2632 return script->maybeForwardedFilename();
2635 JS_PUBLIC_API unsigned JS_GetScriptBaseLineNumber(JSContext* cx,
2636 JSScript* script) {
2637 return script->lineno();
2640 JS_PUBLIC_API JSScript* JS_GetFunctionScript(JSContext* cx,
2641 HandleFunction fun) {
2642 if (fun->isNativeFun()) {
2643 return nullptr;
2646 if (fun->hasBytecode()) {
2647 return fun->nonLazyScript();
2650 AutoRealm ar(cx, fun);
2651 JSScript* script = JSFunction::getOrCreateScript(cx, fun);
2652 if (!script) {
2653 MOZ_CRASH();
2655 return script;
2658 JS_PUBLIC_API JSString* JS_DecompileScript(JSContext* cx, HandleScript script) {
2659 MOZ_ASSERT(!cx->zone()->isAtomsZone());
2661 AssertHeapIsIdle();
2662 CHECK_THREAD(cx);
2663 RootedFunction fun(cx, script->function());
2664 if (fun) {
2665 return JS_DecompileFunction(cx, fun);
2667 bool haveSource;
2668 if (!ScriptSource::loadSource(cx, script->scriptSource(), &haveSource)) {
2669 return nullptr;
2671 return haveSource ? JSScript::sourceData(cx, script)
2672 : NewStringCopyZ<CanGC>(cx, "[no source]");
2675 JS_PUBLIC_API JSString* JS_DecompileFunction(JSContext* cx,
2676 HandleFunction fun) {
2677 MOZ_ASSERT(!cx->zone()->isAtomsZone());
2678 AssertHeapIsIdle();
2679 CHECK_THREAD(cx);
2680 cx->check(fun);
2681 return FunctionToString(cx, fun, /* isToSource = */ false);
2684 JS_PUBLIC_API void JS::SetScriptPrivate(JSScript* script,
2685 const JS::Value& value) {
2686 JSRuntime* rt = script->zone()->runtimeFromMainThread();
2687 script->sourceObject()->setPrivate(rt, value);
2690 JS_PUBLIC_API JS::Value JS::GetScriptPrivate(JSScript* script) {
2691 return script->sourceObject()->getPrivate();
2694 JS_PUBLIC_API JS::Value JS::GetScriptedCallerPrivate(JSContext* cx) {
2695 AssertHeapIsIdle();
2696 CHECK_THREAD(cx);
2698 NonBuiltinFrameIter iter(cx, cx->realm()->principals());
2699 if (iter.done() || !iter.hasScript()) {
2700 return UndefinedValue();
2703 return iter.script()->sourceObject()->getPrivate();
2706 JS_PUBLIC_API void JS::SetScriptPrivateReferenceHooks(
2707 JSRuntime* rt, JS::ScriptPrivateReferenceHook addRefHook,
2708 JS::ScriptPrivateReferenceHook releaseHook) {
2709 AssertHeapIsIdle();
2710 rt->scriptPrivateAddRefHook = addRefHook;
2711 rt->scriptPrivateReleaseHook = releaseHook;
2714 JS_PUBLIC_API void JS::SetWaitCallback(JSRuntime* rt,
2715 BeforeWaitCallback beforeWait,
2716 AfterWaitCallback afterWait,
2717 size_t requiredMemory) {
2718 MOZ_RELEASE_ASSERT(requiredMemory <= WAIT_CALLBACK_CLIENT_MAXMEM);
2719 MOZ_RELEASE_ASSERT((beforeWait == nullptr) == (afterWait == nullptr));
2720 rt->beforeWaitCallback = beforeWait;
2721 rt->afterWaitCallback = afterWait;
2724 JS_PUBLIC_API bool JS_CheckForInterrupt(JSContext* cx) {
2725 return js::CheckForInterrupt(cx);
2728 JS_PUBLIC_API bool JS_AddInterruptCallback(JSContext* cx,
2729 JSInterruptCallback callback) {
2730 return cx->interruptCallbacks().append(callback);
2733 JS_PUBLIC_API bool JS_DisableInterruptCallback(JSContext* cx) {
2734 bool result = cx->interruptCallbackDisabled;
2735 cx->interruptCallbackDisabled = true;
2736 return result;
2739 JS_PUBLIC_API void JS_ResetInterruptCallback(JSContext* cx, bool enable) {
2740 cx->interruptCallbackDisabled = enable;
2743 /************************************************************************/
2746 * Promises.
2748 JS_PUBLIC_API void JS::SetJobQueue(JSContext* cx, JobQueue* queue) {
2749 cx->jobQueue = queue;
2752 extern JS_PUBLIC_API void JS::SetPromiseRejectionTrackerCallback(
2753 JSContext* cx, PromiseRejectionTrackerCallback callback,
2754 void* data /* = nullptr */) {
2755 cx->promiseRejectionTrackerCallback = callback;
2756 cx->promiseRejectionTrackerCallbackData = data;
2759 extern JS_PUBLIC_API void JS::JobQueueIsEmpty(JSContext* cx) {
2760 cx->canSkipEnqueuingJobs = true;
2763 extern JS_PUBLIC_API void JS::JobQueueMayNotBeEmpty(JSContext* cx) {
2764 cx->canSkipEnqueuingJobs = false;
2767 JS_PUBLIC_API JSObject* JS::NewPromiseObject(JSContext* cx,
2768 HandleObject executor) {
2769 MOZ_ASSERT(!cx->zone()->isAtomsZone());
2770 AssertHeapIsIdle();
2771 CHECK_THREAD(cx);
2772 cx->check(executor);
2774 if (!executor) {
2775 return PromiseObject::createSkippingExecutor(cx);
2778 MOZ_ASSERT(IsCallable(executor));
2779 return PromiseObject::create(cx, executor);
2782 JS_PUBLIC_API bool JS::IsPromiseObject(JS::HandleObject obj) {
2783 return obj->is<PromiseObject>();
2786 JS_PUBLIC_API JSObject* JS::GetPromiseConstructor(JSContext* cx) {
2787 CHECK_THREAD(cx);
2788 Rooted<GlobalObject*> global(cx, cx->global());
2789 return GlobalObject::getOrCreatePromiseConstructor(cx, global);
2792 JS_PUBLIC_API JSObject* JS::GetPromisePrototype(JSContext* cx) {
2793 CHECK_THREAD(cx);
2794 Rooted<GlobalObject*> global(cx, cx->global());
2795 return GlobalObject::getOrCreatePromisePrototype(cx, global);
2798 JS_PUBLIC_API JS::PromiseState JS::GetPromiseState(JS::HandleObject promise) {
2799 PromiseObject* promiseObj = promise->maybeUnwrapIf<PromiseObject>();
2800 if (!promiseObj) {
2801 return JS::PromiseState::Pending;
2804 return promiseObj->state();
2807 JS_PUBLIC_API uint64_t JS::GetPromiseID(JS::HandleObject promise) {
2808 return promise->as<PromiseObject>().getID();
2811 JS_PUBLIC_API JS::Value JS::GetPromiseResult(JS::HandleObject promiseObj) {
2812 PromiseObject* promise = &promiseObj->as<PromiseObject>();
2813 MOZ_ASSERT(promise->state() != JS::PromiseState::Pending);
2814 return promise->state() == JS::PromiseState::Fulfilled ? promise->value()
2815 : promise->reason();
2818 JS_PUBLIC_API bool JS::GetPromiseIsHandled(JS::HandleObject promise) {
2819 PromiseObject* promiseObj = &promise->as<PromiseObject>();
2820 return !promiseObj->isUnhandled();
2823 static PromiseObject* UnwrapPromise(JSContext* cx, JS::HandleObject promise,
2824 mozilla::Maybe<AutoRealm>& ar) {
2825 AssertHeapIsIdle();
2826 CHECK_THREAD(cx);
2827 cx->check(promise);
2829 PromiseObject* promiseObj;
2830 if (IsWrapper(promise)) {
2831 promiseObj = promise->maybeUnwrapAs<PromiseObject>();
2832 if (!promiseObj) {
2833 ReportAccessDenied(cx);
2834 return nullptr;
2836 ar.emplace(cx, promiseObj);
2837 } else {
2838 promiseObj = promise.as<PromiseObject>();
2840 return promiseObj;
2843 JS_PUBLIC_API bool JS::SetSettledPromiseIsHandled(JSContext* cx,
2844 JS::HandleObject promise) {
2845 mozilla::Maybe<AutoRealm> ar;
2846 Rooted<PromiseObject*> promiseObj(cx, UnwrapPromise(cx, promise, ar));
2847 if (!promiseObj) {
2848 return false;
2850 js::SetSettledPromiseIsHandled(cx, promiseObj);
2851 return true;
2854 JS_PUBLIC_API bool JS::SetAnyPromiseIsHandled(JSContext* cx,
2855 JS::HandleObject promise) {
2856 mozilla::Maybe<AutoRealm> ar;
2857 Rooted<PromiseObject*> promiseObj(cx, UnwrapPromise(cx, promise, ar));
2858 if (!promiseObj) {
2859 return false;
2861 js::SetAnyPromiseIsHandled(cx, promiseObj);
2862 return true;
2865 JS_PUBLIC_API JSObject* JS::GetPromiseAllocationSite(JS::HandleObject promise) {
2866 return promise->as<PromiseObject>().allocationSite();
2869 JS_PUBLIC_API JSObject* JS::GetPromiseResolutionSite(JS::HandleObject promise) {
2870 return promise->as<PromiseObject>().resolutionSite();
2873 #ifdef DEBUG
2874 JS_PUBLIC_API void JS::DumpPromiseAllocationSite(JSContext* cx,
2875 JS::HandleObject promise) {
2876 RootedObject stack(cx, promise->as<PromiseObject>().allocationSite());
2877 JSPrincipals* principals = cx->realm()->principals();
2878 UniqueChars stackStr = BuildUTF8StackString(cx, principals, stack);
2879 if (stackStr) {
2880 fputs(stackStr.get(), stderr);
2884 JS_PUBLIC_API void JS::DumpPromiseResolutionSite(JSContext* cx,
2885 JS::HandleObject promise) {
2886 RootedObject stack(cx, promise->as<PromiseObject>().resolutionSite());
2887 JSPrincipals* principals = cx->realm()->principals();
2888 UniqueChars stackStr = BuildUTF8StackString(cx, principals, stack);
2889 if (stackStr) {
2890 fputs(stackStr.get(), stderr);
2893 #endif
2895 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseResolve(
2896 JSContext* cx, JS::HandleValue resolutionValue) {
2897 AssertHeapIsIdle();
2898 CHECK_THREAD(cx);
2899 cx->check(resolutionValue);
2901 RootedObject promise(cx,
2902 PromiseObject::unforgeableResolve(cx, resolutionValue));
2903 MOZ_ASSERT_IF(promise, promise->canUnwrapAs<PromiseObject>());
2904 return promise;
2907 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseReject(
2908 JSContext* cx, JS::HandleValue rejectionValue) {
2909 AssertHeapIsIdle();
2910 CHECK_THREAD(cx);
2911 cx->check(rejectionValue);
2913 RootedObject promise(cx,
2914 PromiseObject::unforgeableReject(cx, rejectionValue));
2915 MOZ_ASSERT_IF(promise, promise->canUnwrapAs<PromiseObject>());
2916 return promise;
2919 static bool ResolveOrRejectPromise(JSContext* cx, JS::HandleObject promiseObj,
2920 JS::HandleValue resultOrReason_,
2921 bool reject) {
2922 AssertHeapIsIdle();
2923 CHECK_THREAD(cx);
2924 cx->check(promiseObj, resultOrReason_);
2926 mozilla::Maybe<AutoRealm> ar;
2927 Rooted<PromiseObject*> promise(cx);
2928 RootedValue resultOrReason(cx, resultOrReason_);
2929 if (IsWrapper(promiseObj)) {
2930 promise = promiseObj->maybeUnwrapAs<PromiseObject>();
2931 if (!promise) {
2932 ReportAccessDenied(cx);
2933 return false;
2935 ar.emplace(cx, promise);
2936 if (!cx->compartment()->wrap(cx, &resultOrReason)) {
2937 return false;
2939 } else {
2940 promise = promiseObj.as<PromiseObject>();
2943 return reject ? PromiseObject::reject(cx, promise, resultOrReason)
2944 : PromiseObject::resolve(cx, promise, resultOrReason);
2947 JS_PUBLIC_API bool JS::ResolvePromise(JSContext* cx,
2948 JS::HandleObject promiseObj,
2949 JS::HandleValue resolutionValue) {
2950 return ResolveOrRejectPromise(cx, promiseObj, resolutionValue, false);
2953 JS_PUBLIC_API bool JS::RejectPromise(JSContext* cx, JS::HandleObject promiseObj,
2954 JS::HandleValue rejectionValue) {
2955 return ResolveOrRejectPromise(cx, promiseObj, rejectionValue, true);
2958 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseThen(
2959 JSContext* cx, JS::HandleObject promiseObj, JS::HandleObject onFulfilled,
2960 JS::HandleObject onRejected) {
2961 AssertHeapIsIdle();
2962 CHECK_THREAD(cx);
2963 cx->check(promiseObj, onFulfilled, onRejected);
2965 MOZ_ASSERT_IF(onFulfilled, IsCallable(onFulfilled));
2966 MOZ_ASSERT_IF(onRejected, IsCallable(onRejected));
2968 return OriginalPromiseThen(cx, promiseObj, onFulfilled, onRejected);
2971 [[nodiscard]] static bool ReactToPromise(JSContext* cx,
2972 JS::Handle<JSObject*> promiseObj,
2973 JS::Handle<JSObject*> onFulfilled,
2974 JS::Handle<JSObject*> onRejected,
2975 UnhandledRejectionBehavior behavior) {
2976 AssertHeapIsIdle();
2977 CHECK_THREAD(cx);
2978 cx->check(promiseObj, onFulfilled, onRejected);
2980 MOZ_ASSERT_IF(onFulfilled, IsCallable(onFulfilled));
2981 MOZ_ASSERT_IF(onRejected, IsCallable(onRejected));
2983 Rooted<PromiseObject*> unwrappedPromise(cx);
2985 RootedValue promiseVal(cx, ObjectValue(*promiseObj));
2986 unwrappedPromise = UnwrapAndTypeCheckValue<PromiseObject>(
2987 cx, promiseVal, [cx, promiseObj] {
2988 JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
2989 JSMSG_INCOMPATIBLE_PROTO, "Promise",
2990 "then", promiseObj->getClass()->name);
2992 if (!unwrappedPromise) {
2993 return false;
2997 return ReactToUnwrappedPromise(cx, unwrappedPromise, onFulfilled, onRejected,
2998 behavior);
3001 JS_PUBLIC_API bool JS::AddPromiseReactions(JSContext* cx,
3002 JS::HandleObject promiseObj,
3003 JS::HandleObject onFulfilled,
3004 JS::HandleObject onRejected) {
3005 return ReactToPromise(cx, promiseObj, onFulfilled, onRejected,
3006 UnhandledRejectionBehavior::Report);
3009 JS_PUBLIC_API bool JS::AddPromiseReactionsIgnoringUnhandledRejection(
3010 JSContext* cx, JS::HandleObject promiseObj, JS::HandleObject onFulfilled,
3011 JS::HandleObject onRejected) {
3012 return ReactToPromise(cx, promiseObj, onFulfilled, onRejected,
3013 UnhandledRejectionBehavior::Ignore);
3016 JS_PUBLIC_API JS::PromiseUserInputEventHandlingState
3017 JS::GetPromiseUserInputEventHandlingState(JS::HandleObject promiseObj_) {
3018 PromiseObject* promise = promiseObj_->maybeUnwrapIf<PromiseObject>();
3019 if (!promise) {
3020 return JS::PromiseUserInputEventHandlingState::DontCare;
3023 if (!promise->requiresUserInteractionHandling()) {
3024 return JS::PromiseUserInputEventHandlingState::DontCare;
3026 if (promise->hadUserInteractionUponCreation()) {
3027 return JS::PromiseUserInputEventHandlingState::HadUserInteractionAtCreation;
3029 return JS::PromiseUserInputEventHandlingState::
3030 DidntHaveUserInteractionAtCreation;
3033 JS_PUBLIC_API bool JS::SetPromiseUserInputEventHandlingState(
3034 JS::HandleObject promiseObj_,
3035 JS::PromiseUserInputEventHandlingState state) {
3036 PromiseObject* promise = promiseObj_->maybeUnwrapIf<PromiseObject>();
3037 if (!promise) {
3038 return false;
3041 switch (state) {
3042 case JS::PromiseUserInputEventHandlingState::DontCare:
3043 promise->setRequiresUserInteractionHandling(false);
3044 break;
3045 case JS::PromiseUserInputEventHandlingState::HadUserInteractionAtCreation:
3046 promise->setRequiresUserInteractionHandling(true);
3047 promise->setHadUserInteractionUponCreation(true);
3048 break;
3049 case JS::PromiseUserInputEventHandlingState::
3050 DidntHaveUserInteractionAtCreation:
3051 promise->setRequiresUserInteractionHandling(true);
3052 promise->setHadUserInteractionUponCreation(false);
3053 break;
3054 default:
3055 MOZ_ASSERT_UNREACHABLE(
3056 "Invalid PromiseUserInputEventHandlingState enum value");
3057 return false;
3059 return true;
3063 * Unforgeable version of Promise.all for internal use.
3065 * Takes a dense array of Promise objects and returns a promise that's
3066 * resolved with an array of resolution values when all those promises ahve
3067 * been resolved, or rejected with the rejection value of the first rejected
3068 * promise.
3070 * Asserts that the array is dense and all entries are Promise objects.
3072 JS_PUBLIC_API JSObject* JS::GetWaitForAllPromise(
3073 JSContext* cx, JS::HandleObjectVector promises) {
3074 AssertHeapIsIdle();
3075 CHECK_THREAD(cx);
3077 return js::GetWaitForAllPromise(cx, promises);
3080 JS_PUBLIC_API void JS::InitDispatchToEventLoop(
3081 JSContext* cx, JS::DispatchToEventLoopCallback callback, void* closure) {
3082 cx->runtime()->offThreadPromiseState.ref().init(callback, closure);
3085 JS_PUBLIC_API void JS::ShutdownAsyncTasks(JSContext* cx) {
3086 cx->runtime()->offThreadPromiseState.ref().shutdown(cx);
3089 JS_PUBLIC_API void JS::InitConsumeStreamCallback(
3090 JSContext* cx, ConsumeStreamCallback consume,
3091 ReportStreamErrorCallback report) {
3092 cx->runtime()->consumeStreamCallback = consume;
3093 cx->runtime()->reportStreamErrorCallback = report;
3096 JS_PUBLIC_API void JS_RequestInterruptCallback(JSContext* cx) {
3097 cx->requestInterrupt(InterruptReason::CallbackUrgent);
3100 JS_PUBLIC_API void JS_RequestInterruptCallbackCanWait(JSContext* cx) {
3101 cx->requestInterrupt(InterruptReason::CallbackCanWait);
3104 JS::AutoSetAsyncStackForNewCalls::AutoSetAsyncStackForNewCalls(
3105 JSContext* cx, HandleObject stack, const char* asyncCause,
3106 JS::AutoSetAsyncStackForNewCalls::AsyncCallKind kind)
3107 : cx(cx),
3108 oldAsyncStack(cx, cx->asyncStackForNewActivations()),
3109 oldAsyncCause(cx->asyncCauseForNewActivations),
3110 oldAsyncCallIsExplicit(cx->asyncCallIsExplicit) {
3111 CHECK_THREAD(cx);
3113 // The option determines whether we actually use the new values at this
3114 // point. It will not affect restoring the previous values when the object
3115 // is destroyed, so if the option changes it won't cause consistency issues.
3116 if (!cx->options().asyncStack()) {
3117 return;
3120 SavedFrame* asyncStack = &stack->as<SavedFrame>();
3122 cx->asyncStackForNewActivations() = asyncStack;
3123 cx->asyncCauseForNewActivations = asyncCause;
3124 cx->asyncCallIsExplicit = kind == AsyncCallKind::EXPLICIT;
3127 JS::AutoSetAsyncStackForNewCalls::~AutoSetAsyncStackForNewCalls() {
3128 cx->asyncCauseForNewActivations = oldAsyncCause;
3129 cx->asyncStackForNewActivations() =
3130 oldAsyncStack ? &oldAsyncStack->as<SavedFrame>() : nullptr;
3131 cx->asyncCallIsExplicit = oldAsyncCallIsExplicit;
3134 /************************************************************************/
3135 JS_PUBLIC_API JSString* JS_NewStringCopyN(JSContext* cx, const char* s,
3136 size_t n) {
3137 AssertHeapIsIdle();
3138 CHECK_THREAD(cx);
3139 return NewStringCopyN<CanGC>(cx, s, n);
3142 JS_PUBLIC_API JSString* JS_NewStringCopyZ(JSContext* cx, const char* s) {
3143 AssertHeapIsIdle();
3144 CHECK_THREAD(cx);
3145 if (!s) {
3146 return cx->runtime()->emptyString;
3148 return NewStringCopyZ<CanGC>(cx, s);
3151 JS_PUBLIC_API JSString* JS_NewStringCopyUTF8Z(JSContext* cx,
3152 const JS::ConstUTF8CharsZ s) {
3153 AssertHeapIsIdle();
3154 CHECK_THREAD(cx);
3155 return NewStringCopyUTF8Z(cx, s);
3158 JS_PUBLIC_API JSString* JS_NewStringCopyUTF8N(JSContext* cx,
3159 const JS::UTF8Chars& s) {
3160 AssertHeapIsIdle();
3161 CHECK_THREAD(cx);
3162 return NewStringCopyUTF8N(cx, s);
3165 JS_PUBLIC_API bool JS_StringHasBeenPinned(JSContext* cx, JSString* str) {
3166 AssertHeapIsIdle();
3167 CHECK_THREAD(cx);
3169 if (!str->isAtom()) {
3170 return false;
3173 return AtomIsPinned(cx, &str->asAtom());
3176 JS_PUBLIC_API JSString* JS_AtomizeString(JSContext* cx, const char* s) {
3177 return JS_AtomizeStringN(cx, s, strlen(s));
3180 JS_PUBLIC_API JSString* JS_AtomizeStringN(JSContext* cx, const char* s,
3181 size_t length) {
3182 AssertHeapIsIdle();
3183 CHECK_THREAD(cx);
3184 return Atomize(cx, s, length);
3187 JS_PUBLIC_API JSString* JS_AtomizeAndPinString(JSContext* cx, const char* s) {
3188 return JS_AtomizeAndPinStringN(cx, s, strlen(s));
3191 JS_PUBLIC_API JSString* JS_AtomizeAndPinStringN(JSContext* cx, const char* s,
3192 size_t length) {
3193 AssertHeapIsIdle();
3194 CHECK_THREAD(cx);
3196 JSAtom* atom = cx->zone() ? Atomize(cx, s, length)
3197 : AtomizeWithoutActiveZone(cx, s, length);
3198 if (!atom || !PinAtom(cx, atom)) {
3199 return nullptr;
3202 MOZ_ASSERT(JS_StringHasBeenPinned(cx, atom));
3203 return atom;
3206 JS_PUBLIC_API JSString* JS_NewLatin1String(
3207 JSContext* cx, js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> chars,
3208 size_t length) {
3209 AssertHeapIsIdle();
3210 CHECK_THREAD(cx);
3211 return NewString<CanGC>(cx, std::move(chars), length);
3214 JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx,
3215 JS::UniqueTwoByteChars chars,
3216 size_t length) {
3217 AssertHeapIsIdle();
3218 CHECK_THREAD(cx);
3219 return NewString<CanGC>(cx, std::move(chars), length);
3222 JS_PUBLIC_API JSString* JS_NewUCStringDontDeflate(JSContext* cx,
3223 JS::UniqueTwoByteChars chars,
3224 size_t length) {
3225 AssertHeapIsIdle();
3226 CHECK_THREAD(cx);
3227 return NewStringDontDeflate<CanGC>(cx, std::move(chars), length);
3230 JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx, const char16_t* s,
3231 size_t n) {
3232 AssertHeapIsIdle();
3233 CHECK_THREAD(cx);
3234 if (!n) {
3235 return cx->names().empty_;
3237 return NewStringCopyN<CanGC>(cx, s, n);
3240 JS_PUBLIC_API JSString* JS_NewUCStringCopyZ(JSContext* cx, const char16_t* s) {
3241 AssertHeapIsIdle();
3242 CHECK_THREAD(cx);
3243 if (!s) {
3244 return cx->runtime()->emptyString;
3246 return NewStringCopyZ<CanGC>(cx, s);
3249 JS_PUBLIC_API JSString* JS_AtomizeUCString(JSContext* cx, const char16_t* s) {
3250 return JS_AtomizeUCStringN(cx, s, js_strlen(s));
3253 JS_PUBLIC_API JSString* JS_AtomizeUCStringN(JSContext* cx, const char16_t* s,
3254 size_t length) {
3255 AssertHeapIsIdle();
3256 CHECK_THREAD(cx);
3257 return AtomizeChars(cx, s, length);
3260 JS_PUBLIC_API size_t JS_GetStringLength(JSString* str) { return str->length(); }
3262 JS_PUBLIC_API bool JS_StringIsLinear(JSString* str) { return str->isLinear(); }
3264 JS_PUBLIC_API bool JS_DeprecatedStringHasLatin1Chars(JSString* str) {
3265 return str->hasLatin1Chars();
3268 JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength(
3269 JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str,
3270 size_t* plength) {
3271 MOZ_ASSERT(plength);
3272 AssertHeapIsIdle();
3273 CHECK_THREAD(cx);
3274 cx->check(str);
3275 JSLinearString* linear = str->ensureLinear(cx);
3276 if (!linear) {
3277 return nullptr;
3279 *plength = linear->length();
3280 return linear->latin1Chars(nogc);
3283 JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength(
3284 JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str,
3285 size_t* plength) {
3286 MOZ_ASSERT(plength);
3287 AssertHeapIsIdle();
3288 CHECK_THREAD(cx);
3289 cx->check(str);
3290 JSLinearString* linear = str->ensureLinear(cx);
3291 if (!linear) {
3292 return nullptr;
3294 *plength = linear->length();
3295 return linear->twoByteChars(nogc);
3298 JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars(JSString* str) {
3299 return str->asExternal().twoByteChars();
3302 JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str,
3303 size_t index, char16_t* res) {
3304 AssertHeapIsIdle();
3305 CHECK_THREAD(cx);
3306 cx->check(str);
3308 JSLinearString* linear = str->ensureLinear(cx);
3309 if (!linear) {
3310 return false;
3313 *res = linear->latin1OrTwoByteChar(index);
3314 return true;
3317 JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx,
3318 const mozilla::Range<char16_t>& dest,
3319 JSString* str) {
3320 AssertHeapIsIdle();
3321 CHECK_THREAD(cx);
3322 cx->check(str);
3324 JSLinearString* linear = str->ensureLinear(cx);
3325 if (!linear) {
3326 return false;
3329 MOZ_ASSERT(linear->length() <= dest.length());
3330 CopyChars(dest.begin().get(), *linear);
3331 return true;
3334 extern JS_PUBLIC_API JS::UniqueTwoByteChars JS_CopyStringCharsZ(JSContext* cx,
3335 JSString* str) {
3336 AssertHeapIsIdle();
3337 CHECK_THREAD(cx);
3339 JSLinearString* linear = str->ensureLinear(cx);
3340 if (!linear) {
3341 return nullptr;
3344 size_t len = linear->length();
3346 static_assert(JS::MaxStringLength < UINT32_MAX,
3347 "len + 1 must not overflow on 32-bit platforms");
3349 UniqueTwoByteChars chars(cx->pod_malloc<char16_t>(len + 1));
3350 if (!chars) {
3351 return nullptr;
3354 CopyChars(chars.get(), *linear);
3355 chars[len] = '\0';
3357 return chars;
3360 extern JS_PUBLIC_API JSLinearString* JS_EnsureLinearString(JSContext* cx,
3361 JSString* str) {
3362 AssertHeapIsIdle();
3363 CHECK_THREAD(cx);
3364 cx->check(str);
3365 return str->ensureLinear(cx);
3368 JS_PUBLIC_API bool JS_CompareStrings(JSContext* cx, JSString* str1,
3369 JSString* str2, int32_t* result) {
3370 AssertHeapIsIdle();
3371 CHECK_THREAD(cx);
3373 return CompareStrings(cx, str1, str2, result);
3376 JS_PUBLIC_API bool JS_StringEqualsAscii(JSContext* cx, JSString* str,
3377 const char* asciiBytes, bool* match) {
3378 AssertHeapIsIdle();
3379 CHECK_THREAD(cx);
3381 JSLinearString* linearStr = str->ensureLinear(cx);
3382 if (!linearStr) {
3383 return false;
3385 *match = StringEqualsAscii(linearStr, asciiBytes);
3386 return true;
3389 JS_PUBLIC_API bool JS_StringEqualsAscii(JSContext* cx, JSString* str,
3390 const char* asciiBytes, size_t length,
3391 bool* match) {
3392 AssertHeapIsIdle();
3393 CHECK_THREAD(cx);
3395 JSLinearString* linearStr = str->ensureLinear(cx);
3396 if (!linearStr) {
3397 return false;
3399 *match = StringEqualsAscii(linearStr, asciiBytes, length);
3400 return true;
3403 JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str,
3404 const char* asciiBytes) {
3405 return StringEqualsAscii(str, asciiBytes);
3408 JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str,
3409 const char* asciiBytes,
3410 size_t length) {
3411 return StringEqualsAscii(str, asciiBytes, length);
3414 JS_PUBLIC_API size_t JS_PutEscapedLinearString(char* buffer, size_t size,
3415 JSLinearString* str,
3416 char quote) {
3417 return PutEscapedString(buffer, size, str, quote);
3420 JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer,
3421 size_t size, JSString* str,
3422 char quote) {
3423 AssertHeapIsIdle();
3424 JSLinearString* linearStr = str->ensureLinear(cx);
3425 if (!linearStr) {
3426 return size_t(-1);
3428 return PutEscapedString(buffer, size, linearStr, quote);
3431 JS_PUBLIC_API JSString* JS_NewDependentString(JSContext* cx, HandleString str,
3432 size_t start, size_t length) {
3433 AssertHeapIsIdle();
3434 CHECK_THREAD(cx);
3435 return NewDependentString(cx, str, start, length);
3438 JS_PUBLIC_API JSString* JS_ConcatStrings(JSContext* cx, HandleString left,
3439 HandleString right) {
3440 AssertHeapIsIdle();
3441 CHECK_THREAD(cx);
3442 return ConcatStrings<CanGC>(cx, left, right);
3445 JS_PUBLIC_API bool JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen,
3446 char16_t* dst, size_t* dstlenp) {
3447 AssertHeapIsIdle();
3448 CHECK_THREAD(cx);
3450 if (!dst) {
3451 *dstlenp = srclen;
3452 return true;
3455 size_t dstlen = *dstlenp;
3457 if (srclen > dstlen) {
3458 CopyAndInflateChars(dst, src, dstlen);
3460 gc::AutoSuppressGC suppress(cx);
3461 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
3462 JSMSG_BUFFER_TOO_SMALL);
3463 return false;
3466 CopyAndInflateChars(dst, src, srclen);
3467 *dstlenp = srclen;
3468 return true;
3471 JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToASCII(JSContext* cx,
3472 JSString* str) {
3473 AssertHeapIsIdle();
3474 CHECK_THREAD(cx);
3476 return js::EncodeAscii(cx, str);
3479 JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToLatin1(JSContext* cx,
3480 JSString* str) {
3481 AssertHeapIsIdle();
3482 CHECK_THREAD(cx);
3484 return js::EncodeLatin1(cx, str);
3487 JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToUTF8(JSContext* cx,
3488 HandleString str) {
3489 AssertHeapIsIdle();
3490 CHECK_THREAD(cx);
3492 return StringToNewUTF8CharsZ(cx, *str);
3495 JS_PUBLIC_API size_t JS_GetStringEncodingLength(JSContext* cx, JSString* str) {
3496 AssertHeapIsIdle();
3497 CHECK_THREAD(cx);
3499 if (!str->ensureLinear(cx)) {
3500 return size_t(-1);
3502 return str->length();
3505 JS_PUBLIC_API bool JS_EncodeStringToBuffer(JSContext* cx, JSString* str,
3506 char* buffer, size_t length) {
3507 AssertHeapIsIdle();
3508 CHECK_THREAD(cx);
3510 JSLinearString* linear = str->ensureLinear(cx);
3511 if (!linear) {
3512 return false;
3515 JS::AutoCheckCannotGC nogc;
3516 size_t writeLength = std::min(linear->length(), length);
3517 if (linear->hasLatin1Chars()) {
3518 mozilla::PodCopy(reinterpret_cast<Latin1Char*>(buffer),
3519 linear->latin1Chars(nogc), writeLength);
3520 } else {
3521 const char16_t* src = linear->twoByteChars(nogc);
3522 for (size_t i = 0; i < writeLength; i++) {
3523 buffer[i] = char(src[i]);
3526 return true;
3529 JS_PUBLIC_API mozilla::Maybe<std::tuple<size_t, size_t>>
3530 JS_EncodeStringToUTF8BufferPartial(JSContext* cx, JSString* str,
3531 mozilla::Span<char> buffer) {
3532 AssertHeapIsIdle();
3533 CHECK_THREAD(cx);
3534 JS::AutoCheckCannotGC nogc;
3535 return str->encodeUTF8Partial(nogc, buffer);
3538 JS_PUBLIC_API JS::Symbol* JS::NewSymbol(JSContext* cx,
3539 HandleString description) {
3540 AssertHeapIsIdle();
3541 CHECK_THREAD(cx);
3542 if (description) {
3543 cx->check(description);
3546 return Symbol::new_(cx, SymbolCode::UniqueSymbol, description);
3549 JS_PUBLIC_API JS::Symbol* JS::GetSymbolFor(JSContext* cx, HandleString key) {
3550 AssertHeapIsIdle();
3551 CHECK_THREAD(cx);
3552 cx->check(key);
3554 return Symbol::for_(cx, key);
3557 JS_PUBLIC_API JSString* JS::GetSymbolDescription(HandleSymbol symbol) {
3558 return symbol->description();
3561 JS_PUBLIC_API JS::SymbolCode JS::GetSymbolCode(Handle<Symbol*> symbol) {
3562 return symbol->code();
3565 JS_PUBLIC_API JS::Symbol* JS::GetWellKnownSymbol(JSContext* cx,
3566 JS::SymbolCode which) {
3567 return cx->wellKnownSymbols().get(which);
3570 JS_PUBLIC_API JS::PropertyKey JS::GetWellKnownSymbolKey(JSContext* cx,
3571 JS::SymbolCode which) {
3572 return PropertyKey::Symbol(cx->wellKnownSymbols().get(which));
3575 static bool AddPrefix(JSContext* cx, JS::Handle<JS::PropertyKey> id,
3576 FunctionPrefixKind prefixKind,
3577 JS::MutableHandle<JS::PropertyKey> out) {
3578 JS::Rooted<JSAtom*> atom(cx, js::IdToFunctionName(cx, id, prefixKind));
3579 if (!atom) {
3580 return false;
3583 out.set(JS::PropertyKey::NonIntAtom(atom));
3584 return true;
3587 JS_PUBLIC_API bool JS::ToGetterId(JSContext* cx, JS::Handle<JS::PropertyKey> id,
3588 JS::MutableHandle<JS::PropertyKey> getterId) {
3589 return AddPrefix(cx, id, FunctionPrefixKind::Get, getterId);
3592 JS_PUBLIC_API bool JS::ToSetterId(JSContext* cx, JS::Handle<JS::PropertyKey> id,
3593 JS::MutableHandle<JS::PropertyKey> setterId) {
3594 return AddPrefix(cx, id, FunctionPrefixKind::Set, setterId);
3597 #ifdef DEBUG
3598 static bool PropertySpecNameIsDigits(JSPropertySpec::Name name) {
3599 if (name.isSymbol()) {
3600 return false;
3602 const char* s = name.string();
3603 if (!*s) {
3604 return false;
3606 for (; *s; s++) {
3607 if (*s < '0' || *s > '9') {
3608 return false;
3611 return true;
3613 #endif // DEBUG
3615 JS_PUBLIC_API bool JS::PropertySpecNameEqualsId(JSPropertySpec::Name name,
3616 HandleId id) {
3617 if (name.isSymbol()) {
3618 return id.isWellKnownSymbol(name.symbol());
3621 MOZ_ASSERT(!PropertySpecNameIsDigits(name));
3622 return id.isAtom() && JS_LinearStringEqualsAscii(id.toAtom(), name.string());
3625 JS_PUBLIC_API bool JS_Stringify(JSContext* cx, MutableHandleValue vp,
3626 HandleObject replacer, HandleValue space,
3627 JSONWriteCallback callback, void* data) {
3628 AssertHeapIsIdle();
3629 CHECK_THREAD(cx);
3630 cx->check(replacer, space);
3631 StringBuffer sb(cx);
3632 if (!sb.ensureTwoByteChars()) {
3633 return false;
3635 if (!Stringify(cx, vp, replacer, space, sb, StringifyBehavior::Normal)) {
3636 return false;
3638 if (sb.empty() && !sb.append(cx->names().null)) {
3639 return false;
3641 return callback(sb.rawTwoByteBegin(), sb.length(), data);
3644 JS_PUBLIC_API bool JS::ToJSON(JSContext* cx, HandleValue value,
3645 HandleObject replacer, HandleValue space,
3646 JSONWriteCallback callback, void* data) {
3647 AssertHeapIsIdle();
3648 CHECK_THREAD(cx);
3649 cx->check(replacer, space);
3650 StringBuffer sb(cx);
3651 if (!sb.ensureTwoByteChars()) {
3652 return false;
3654 RootedValue v(cx, value);
3655 if (!Stringify(cx, &v, replacer, space, sb, StringifyBehavior::Normal)) {
3656 return false;
3658 if (sb.empty()) {
3659 return true;
3661 return callback(sb.rawTwoByteBegin(), sb.length(), data);
3664 JS_PUBLIC_API bool JS::ToJSONMaybeSafely(JSContext* cx, JS::HandleObject input,
3665 JSONWriteCallback callback,
3666 void* data) {
3667 AssertHeapIsIdle();
3668 CHECK_THREAD(cx);
3669 cx->check(input);
3671 StringBuffer sb(cx);
3672 if (!sb.ensureTwoByteChars()) {
3673 return false;
3676 RootedValue inputValue(cx, ObjectValue(*input));
3677 if (!Stringify(cx, &inputValue, nullptr, NullHandleValue, sb,
3678 StringifyBehavior::RestrictedSafe))
3679 return false;
3681 if (sb.empty() && !sb.append(cx->names().null)) {
3682 return false;
3685 return callback(sb.rawTwoByteBegin(), sb.length(), data);
3688 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, const char16_t* chars,
3689 uint32_t len, MutableHandleValue vp) {
3690 AssertHeapIsIdle();
3691 CHECK_THREAD(cx);
3692 return ParseJSONWithReviver(cx, mozilla::Range<const char16_t>(chars, len),
3693 NullHandleValue, vp);
3696 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, HandleString str,
3697 MutableHandleValue vp) {
3698 return JS_ParseJSONWithReviver(cx, str, NullHandleValue, vp);
3701 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, const Latin1Char* chars,
3702 uint32_t len, MutableHandleValue vp) {
3703 AssertHeapIsIdle();
3704 CHECK_THREAD(cx);
3705 return ParseJSONWithReviver(cx, mozilla::Range<const Latin1Char>(chars, len),
3706 NullHandleValue, vp);
3709 JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, const char16_t* chars,
3710 uint32_t len, HandleValue reviver,
3711 MutableHandleValue vp) {
3712 AssertHeapIsIdle();
3713 CHECK_THREAD(cx);
3714 return ParseJSONWithReviver(cx, mozilla::Range<const char16_t>(chars, len),
3715 reviver, vp);
3718 JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, HandleString str,
3719 HandleValue reviver,
3720 MutableHandleValue vp) {
3721 AssertHeapIsIdle();
3722 CHECK_THREAD(cx);
3723 cx->check(str);
3725 AutoStableStringChars stableChars(cx);
3726 if (!stableChars.init(cx, str)) {
3727 return false;
3730 return stableChars.isLatin1()
3731 ? ParseJSONWithReviver(cx, stableChars.latin1Range(), reviver, vp)
3732 : ParseJSONWithReviver(cx, stableChars.twoByteRange(), reviver,
3733 vp);
3736 /************************************************************************/
3738 JS_PUBLIC_API void JS_ReportErrorASCII(JSContext* cx, const char* format, ...) {
3739 va_list ap;
3741 AssertHeapIsIdle();
3742 va_start(ap, format);
3743 ReportErrorVA(cx, IsWarning::No, format, ArgumentsAreASCII, ap);
3744 va_end(ap);
3747 JS_PUBLIC_API void JS_ReportErrorLatin1(JSContext* cx, const char* format,
3748 ...) {
3749 va_list ap;
3751 AssertHeapIsIdle();
3752 va_start(ap, format);
3753 ReportErrorVA(cx, IsWarning::No, format, ArgumentsAreLatin1, ap);
3754 va_end(ap);
3757 JS_PUBLIC_API void JS_ReportErrorUTF8(JSContext* cx, const char* format, ...) {
3758 va_list ap;
3760 AssertHeapIsIdle();
3761 va_start(ap, format);
3762 ReportErrorVA(cx, IsWarning::No, format, ArgumentsAreUTF8, ap);
3763 va_end(ap);
3766 JS_PUBLIC_API void JS_ReportErrorNumberASCII(JSContext* cx,
3767 JSErrorCallback errorCallback,
3768 void* userRef,
3769 const unsigned errorNumber, ...) {
3770 va_list ap;
3771 va_start(ap, errorNumber);
3772 JS_ReportErrorNumberASCIIVA(cx, errorCallback, userRef, errorNumber, ap);
3773 va_end(ap);
3776 JS_PUBLIC_API void JS_ReportErrorNumberASCIIVA(JSContext* cx,
3777 JSErrorCallback errorCallback,
3778 void* userRef,
3779 const unsigned errorNumber,
3780 va_list ap) {
3781 AssertHeapIsIdle();
3782 ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber,
3783 ArgumentsAreASCII, ap);
3786 JS_PUBLIC_API void JS_ReportErrorNumberLatin1(JSContext* cx,
3787 JSErrorCallback errorCallback,
3788 void* userRef,
3789 const unsigned errorNumber, ...) {
3790 va_list ap;
3791 va_start(ap, errorNumber);
3792 JS_ReportErrorNumberLatin1VA(cx, errorCallback, userRef, errorNumber, ap);
3793 va_end(ap);
3796 JS_PUBLIC_API void JS_ReportErrorNumberLatin1VA(JSContext* cx,
3797 JSErrorCallback errorCallback,
3798 void* userRef,
3799 const unsigned errorNumber,
3800 va_list ap) {
3801 AssertHeapIsIdle();
3802 ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber,
3803 ArgumentsAreLatin1, ap);
3806 JS_PUBLIC_API void JS_ReportErrorNumberUTF8(JSContext* cx,
3807 JSErrorCallback errorCallback,
3808 void* userRef,
3809 const unsigned errorNumber, ...) {
3810 va_list ap;
3811 va_start(ap, errorNumber);
3812 JS_ReportErrorNumberUTF8VA(cx, errorCallback, userRef, errorNumber, ap);
3813 va_end(ap);
3816 JS_PUBLIC_API void JS_ReportErrorNumberUTF8VA(JSContext* cx,
3817 JSErrorCallback errorCallback,
3818 void* userRef,
3819 const unsigned errorNumber,
3820 va_list ap) {
3821 AssertHeapIsIdle();
3822 ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber,
3823 ArgumentsAreUTF8, ap);
3826 JS_PUBLIC_API void JS_ReportErrorNumberUTF8Array(JSContext* cx,
3827 JSErrorCallback errorCallback,
3828 void* userRef,
3829 const unsigned errorNumber,
3830 const char** args) {
3831 AssertHeapIsIdle();
3832 ReportErrorNumberUTF8Array(cx, IsWarning::No, errorCallback, userRef,
3833 errorNumber, args);
3836 JS_PUBLIC_API void JS_ReportErrorNumberUC(JSContext* cx,
3837 JSErrorCallback errorCallback,
3838 void* userRef,
3839 const unsigned errorNumber, ...) {
3840 va_list ap;
3842 AssertHeapIsIdle();
3843 va_start(ap, errorNumber);
3844 ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber,
3845 ArgumentsAreUnicode, ap);
3846 va_end(ap);
3849 JS_PUBLIC_API void JS_ReportErrorNumberUCArray(JSContext* cx,
3850 JSErrorCallback errorCallback,
3851 void* userRef,
3852 const unsigned errorNumber,
3853 const char16_t** args) {
3854 AssertHeapIsIdle();
3855 ReportErrorNumberUCArray(cx, IsWarning::No, errorCallback, userRef,
3856 errorNumber, args);
3859 JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx) {
3860 ReportOutOfMemory(cx);
3863 JS_PUBLIC_API void JS_ReportAllocationOverflow(JSContext* cx) {
3864 ReportAllocationOverflow(cx);
3867 JS_PUBLIC_API bool JS_ExpandErrorArgumentsASCII(JSContext* cx,
3868 JSErrorCallback errorCallback,
3869 const unsigned errorNumber,
3870 JSErrorReport* reportp, ...) {
3871 va_list ap;
3872 bool ok;
3874 AssertHeapIsIdle();
3875 va_start(ap, reportp);
3876 AutoReportFrontendContext fc(cx);
3877 ok = ExpandErrorArgumentsVA(&fc, errorCallback, nullptr, errorNumber,
3878 ArgumentsAreASCII, reportp, ap);
3879 va_end(ap);
3880 return ok;
3882 /************************************************************************/
3884 JS_PUBLIC_API bool JS_SetDefaultLocale(JSRuntime* rt, const char* locale) {
3885 AssertHeapIsIdle();
3886 return rt->setDefaultLocale(locale);
3889 JS_PUBLIC_API UniqueChars JS_GetDefaultLocale(JSContext* cx) {
3890 AssertHeapIsIdle();
3891 if (const char* locale = cx->runtime()->getDefaultLocale()) {
3892 return DuplicateString(cx, locale);
3895 return nullptr;
3898 JS_PUBLIC_API void JS_ResetDefaultLocale(JSRuntime* rt) {
3899 AssertHeapIsIdle();
3900 rt->resetDefaultLocale();
3903 JS_PUBLIC_API void JS_SetLocaleCallbacks(JSRuntime* rt,
3904 const JSLocaleCallbacks* callbacks) {
3905 AssertHeapIsIdle();
3906 rt->localeCallbacks = callbacks;
3909 JS_PUBLIC_API const JSLocaleCallbacks* JS_GetLocaleCallbacks(JSRuntime* rt) {
3910 /* This function can be called by a finalizer. */
3911 return rt->localeCallbacks;
3914 /************************************************************************/
3916 JS_PUBLIC_API bool JS_IsExceptionPending(JSContext* cx) {
3917 /* This function can be called by a finalizer. */
3918 return (bool)cx->isExceptionPending();
3921 JS_PUBLIC_API bool JS_IsThrowingOutOfMemory(JSContext* cx) {
3922 return cx->isThrowingOutOfMemory();
3925 JS_PUBLIC_API bool JS_GetPendingException(JSContext* cx,
3926 MutableHandleValue vp) {
3927 AssertHeapIsIdle();
3928 CHECK_THREAD(cx);
3929 if (!cx->isExceptionPending()) {
3930 return false;
3932 return cx->getPendingException(vp);
3935 JS_PUBLIC_API void JS_SetPendingException(JSContext* cx, HandleValue value,
3936 JS::ExceptionStackBehavior behavior) {
3937 AssertHeapIsIdle();
3938 CHECK_THREAD(cx);
3939 // We don't check the compartment of `value` here, because we're not
3940 // doing anything with it other than storing it, and stored
3941 // exception values can be in an abitrary compartment.
3943 if (behavior == JS::ExceptionStackBehavior::Capture) {
3944 cx->setPendingException(value, ShouldCaptureStack::Always);
3945 } else {
3946 cx->setPendingException(value, nullptr);
3950 JS_PUBLIC_API void JS_ClearPendingException(JSContext* cx) {
3951 AssertHeapIsIdle();
3952 cx->clearPendingException();
3955 JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext* cx)
3956 : context(cx), status(cx->status), exceptionValue(cx), exceptionStack(cx) {
3957 AssertHeapIsIdle();
3958 CHECK_THREAD(cx);
3959 if (IsCatchableExceptionStatus(status)) {
3960 exceptionValue = cx->unwrappedException();
3961 exceptionStack = cx->unwrappedExceptionStack();
3963 cx->clearPendingException();
3966 void JS::AutoSaveExceptionState::drop() {
3967 status = JS::ExceptionStatus::None;
3968 exceptionValue.setUndefined();
3969 exceptionStack = nullptr;
3972 void JS::AutoSaveExceptionState::restore() {
3973 context->status = status;
3974 context->unwrappedException() = exceptionValue;
3975 if (exceptionStack) {
3976 context->unwrappedExceptionStack() = &exceptionStack->as<SavedFrame>();
3978 drop();
3981 JS::AutoSaveExceptionState::~AutoSaveExceptionState() {
3982 // NOTE: An interrupt/uncatchable exception or a debugger-forced-return may be
3983 // clobbered here by the saved exception. If that is not desired, this
3984 // state should be dropped before the destructor fires.
3985 if (!context->isExceptionPending()) {
3986 if (status != JS::ExceptionStatus::None) {
3987 context->status = status;
3989 if (IsCatchableExceptionStatus(status)) {
3990 context->unwrappedException() = exceptionValue;
3991 if (exceptionStack) {
3992 context->unwrappedExceptionStack() = &exceptionStack->as<SavedFrame>();
3998 JS_PUBLIC_API JSErrorReport* JS_ErrorFromException(JSContext* cx,
3999 HandleObject obj) {
4000 AssertHeapIsIdle();
4001 CHECK_THREAD(cx);
4002 cx->check(obj);
4003 return ErrorFromException(cx, obj);
4006 void JSErrorReport::initBorrowedLinebuf(const char16_t* linebufArg,
4007 size_t linebufLengthArg,
4008 size_t tokenOffsetArg) {
4009 MOZ_ASSERT(linebufArg);
4010 MOZ_ASSERT(tokenOffsetArg <= linebufLengthArg);
4011 MOZ_ASSERT(linebufArg[linebufLengthArg] == '\0');
4013 linebuf_ = linebufArg;
4014 linebufLength_ = linebufLengthArg;
4015 tokenOffset_ = tokenOffsetArg;
4018 void JSErrorReport::freeLinebuf() {
4019 if (ownsLinebuf_ && linebuf_) {
4020 js_free((void*)linebuf_);
4021 ownsLinebuf_ = false;
4023 linebuf_ = nullptr;
4026 JSString* JSErrorBase::newMessageString(JSContext* cx) {
4027 if (!message_) {
4028 return cx->runtime()->emptyString;
4031 return JS_NewStringCopyUTF8Z(cx, message_);
4034 void JSErrorBase::freeMessage() {
4035 if (ownsMessage_) {
4036 js_free((void*)message_.get());
4037 ownsMessage_ = false;
4039 message_ = JS::ConstUTF8CharsZ();
4042 JSErrorNotes::JSErrorNotes() = default;
4044 JSErrorNotes::~JSErrorNotes() = default;
4046 static UniquePtr<JSErrorNotes::Note> CreateErrorNoteVA(
4047 FrontendContext* fc, const char* filename, unsigned sourceId,
4048 uint32_t lineno, JS::ColumnNumberOneOrigin column,
4049 JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber,
4050 ErrorArgumentsType argumentsType, va_list ap) {
4051 auto note = MakeUnique<JSErrorNotes::Note>();
4052 if (!note) {
4053 ReportOutOfMemory(fc);
4054 return nullptr;
4057 note->errorNumber = errorNumber;
4058 note->filename = JS::ConstUTF8CharsZ(filename);
4059 note->sourceId = sourceId;
4060 note->lineno = lineno;
4061 note->column = column;
4063 if (!ExpandErrorArgumentsVA(fc, errorCallback, userRef, errorNumber, nullptr,
4064 argumentsType, note.get(), ap)) {
4065 return nullptr;
4068 return note;
4071 bool JSErrorNotes::addNoteVA(FrontendContext* fc, const char* filename,
4072 unsigned sourceId, uint32_t lineno,
4073 JS::ColumnNumberOneOrigin column,
4074 JSErrorCallback errorCallback, void* userRef,
4075 const unsigned errorNumber,
4076 ErrorArgumentsType argumentsType, va_list ap) {
4077 auto note =
4078 CreateErrorNoteVA(fc, filename, sourceId, lineno, column, errorCallback,
4079 userRef, errorNumber, argumentsType, ap);
4081 if (!note) {
4082 return false;
4084 if (!notes_.append(std::move(note))) {
4085 ReportOutOfMemory(fc);
4086 return false;
4088 return true;
4091 bool JSErrorNotes::addNoteASCII(JSContext* cx, const char* filename,
4092 unsigned sourceId, uint32_t lineno,
4093 JS::ColumnNumberOneOrigin column,
4094 JSErrorCallback errorCallback, void* userRef,
4095 const unsigned errorNumber, ...) {
4096 AutoReportFrontendContext fc(cx);
4097 va_list ap;
4098 va_start(ap, errorNumber);
4099 bool ok = addNoteVA(&fc, filename, sourceId, lineno, column, errorCallback,
4100 userRef, errorNumber, ArgumentsAreASCII, ap);
4101 va_end(ap);
4102 return ok;
4105 bool JSErrorNotes::addNoteASCII(FrontendContext* fc, const char* filename,
4106 unsigned sourceId, uint32_t lineno,
4107 JS::ColumnNumberOneOrigin column,
4108 JSErrorCallback errorCallback, void* userRef,
4109 const unsigned errorNumber, ...) {
4110 va_list ap;
4111 va_start(ap, errorNumber);
4112 bool ok = addNoteVA(fc, filename, sourceId, lineno, column, errorCallback,
4113 userRef, errorNumber, ArgumentsAreASCII, ap);
4114 va_end(ap);
4115 return ok;
4118 bool JSErrorNotes::addNoteLatin1(JSContext* cx, const char* filename,
4119 unsigned sourceId, uint32_t lineno,
4120 JS::ColumnNumberOneOrigin column,
4121 JSErrorCallback errorCallback, void* userRef,
4122 const unsigned errorNumber, ...) {
4123 AutoReportFrontendContext fc(cx);
4124 va_list ap;
4125 va_start(ap, errorNumber);
4126 bool ok = addNoteVA(&fc, filename, sourceId, lineno, column, errorCallback,
4127 userRef, errorNumber, ArgumentsAreLatin1, ap);
4128 va_end(ap);
4129 return ok;
4132 bool JSErrorNotes::addNoteLatin1(FrontendContext* fc, const char* filename,
4133 unsigned sourceId, uint32_t lineno,
4134 JS::ColumnNumberOneOrigin column,
4135 JSErrorCallback errorCallback, void* userRef,
4136 const unsigned errorNumber, ...) {
4137 va_list ap;
4138 va_start(ap, errorNumber);
4139 bool ok = addNoteVA(fc, filename, sourceId, lineno, column, errorCallback,
4140 userRef, errorNumber, ArgumentsAreLatin1, ap);
4141 va_end(ap);
4142 return ok;
4145 bool JSErrorNotes::addNoteUTF8(JSContext* cx, const char* filename,
4146 unsigned sourceId, uint32_t lineno,
4147 JS::ColumnNumberOneOrigin column,
4148 JSErrorCallback errorCallback, void* userRef,
4149 const unsigned errorNumber, ...) {
4150 AutoReportFrontendContext fc(cx);
4151 va_list ap;
4152 va_start(ap, errorNumber);
4153 bool ok = addNoteVA(&fc, filename, sourceId, lineno, column, errorCallback,
4154 userRef, errorNumber, ArgumentsAreUTF8, ap);
4155 va_end(ap);
4156 return ok;
4159 bool JSErrorNotes::addNoteUTF8(FrontendContext* fc, const char* filename,
4160 unsigned sourceId, uint32_t lineno,
4161 JS::ColumnNumberOneOrigin column,
4162 JSErrorCallback errorCallback, void* userRef,
4163 const unsigned errorNumber, ...) {
4164 va_list ap;
4165 va_start(ap, errorNumber);
4166 bool ok = addNoteVA(fc, filename, sourceId, lineno, column, errorCallback,
4167 userRef, errorNumber, ArgumentsAreUTF8, ap);
4168 va_end(ap);
4169 return ok;
4172 JS_PUBLIC_API size_t JSErrorNotes::length() { return notes_.length(); }
4174 UniquePtr<JSErrorNotes> JSErrorNotes::copy(JSContext* cx) {
4175 auto copiedNotes = MakeUnique<JSErrorNotes>();
4176 if (!copiedNotes) {
4177 ReportOutOfMemory(cx);
4178 return nullptr;
4181 for (auto&& note : *this) {
4182 UniquePtr<JSErrorNotes::Note> copied = CopyErrorNote(cx, note.get());
4183 if (!copied) {
4184 return nullptr;
4187 if (!copiedNotes->notes_.append(std::move(copied))) {
4188 return nullptr;
4192 return copiedNotes;
4195 JS_PUBLIC_API JSErrorNotes::iterator JSErrorNotes::begin() {
4196 return iterator(notes_.begin());
4199 JS_PUBLIC_API JSErrorNotes::iterator JSErrorNotes::end() {
4200 return iterator(notes_.end());
4203 extern MOZ_NEVER_INLINE JS_PUBLIC_API void JS_AbortIfWrongThread(
4204 JSContext* cx) {
4205 if (!CurrentThreadCanAccessRuntime(cx->runtime())) {
4206 MOZ_CRASH();
4208 if (TlsContext.get() != cx) {
4209 MOZ_CRASH();
4213 #ifdef JS_GC_ZEAL
4214 JS_PUBLIC_API void JS_GetGCZealBits(JSContext* cx, uint32_t* zealBits,
4215 uint32_t* frequency,
4216 uint32_t* nextScheduled) {
4217 cx->runtime()->gc.getZealBits(zealBits, frequency, nextScheduled);
4220 JS_PUBLIC_API void JS_SetGCZeal(JSContext* cx, uint8_t zeal,
4221 uint32_t frequency) {
4222 cx->runtime()->gc.setZeal(zeal, frequency);
4225 JS_PUBLIC_API void JS_UnsetGCZeal(JSContext* cx, uint8_t zeal) {
4226 cx->runtime()->gc.unsetZeal(zeal);
4229 JS_PUBLIC_API void JS_ScheduleGC(JSContext* cx, uint32_t count) {
4230 cx->runtime()->gc.setNextScheduled(count);
4232 #endif
4234 JS_PUBLIC_API void JS_SetParallelParsingEnabled(JSContext* cx, bool enabled) {
4235 cx->runtime()->setParallelParsingEnabled(enabled);
4238 JS_PUBLIC_API void JS_SetOffthreadIonCompilationEnabled(JSContext* cx,
4239 bool enabled) {
4240 cx->runtime()->setOffthreadIonCompilationEnabled(enabled);
4243 JS_PUBLIC_API void JS_SetGlobalJitCompilerOption(JSContext* cx,
4244 JSJitCompilerOption opt,
4245 uint32_t value) {
4246 JSRuntime* rt = cx->runtime();
4247 switch (opt) {
4248 #ifdef ENABLE_PORTABLE_BASELINE_INTERP
4249 case JSJITCOMPILER_PORTABLE_BASELINE_ENABLE:
4250 if (value == 1) {
4251 jit::JitOptions.portableBaselineInterpreter = true;
4252 } else if (value == 0) {
4253 jit::JitOptions.portableBaselineInterpreter = false;
4255 break;
4256 case JSJITCOMPILER_PORTABLE_BASELINE_WARMUP_THRESHOLD:
4257 if (value == uint32_t(-1)) {
4258 jit::DefaultJitOptions defaultValues;
4259 value = defaultValues.portableBaselineInterpreterWarmUpThreshold;
4261 jit::JitOptions.portableBaselineInterpreterWarmUpThreshold = value;
4262 break;
4263 #endif
4264 case JSJITCOMPILER_BASELINE_INTERPRETER_WARMUP_TRIGGER:
4265 if (value == uint32_t(-1)) {
4266 jit::DefaultJitOptions defaultValues;
4267 value = defaultValues.baselineInterpreterWarmUpThreshold;
4269 jit::JitOptions.baselineInterpreterWarmUpThreshold = value;
4270 break;
4271 case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER:
4272 if (value == uint32_t(-1)) {
4273 jit::DefaultJitOptions defaultValues;
4274 value = defaultValues.baselineJitWarmUpThreshold;
4276 jit::JitOptions.baselineJitWarmUpThreshold = value;
4277 break;
4278 case JSJITCOMPILER_IC_FORCE_MEGAMORPHIC:
4279 jit::JitOptions.forceMegamorphicICs = !!value;
4280 break;
4281 case JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER:
4282 if (value == uint32_t(-1)) {
4283 jit::JitOptions.resetNormalIonWarmUpThreshold();
4284 break;
4286 jit::JitOptions.setNormalIonWarmUpThreshold(value);
4287 break;
4288 case JSJITCOMPILER_ION_GVN_ENABLE:
4289 if (value == 0) {
4290 jit::JitOptions.enableGvn(false);
4291 JitSpew(js::jit::JitSpew_IonScripts, "Disable ion's GVN");
4292 } else {
4293 jit::JitOptions.enableGvn(true);
4294 JitSpew(js::jit::JitSpew_IonScripts, "Enable ion's GVN");
4296 break;
4297 case JSJITCOMPILER_ION_FORCE_IC:
4298 if (value == 0) {
4299 jit::JitOptions.forceInlineCaches = false;
4300 JitSpew(js::jit::JitSpew_IonScripts,
4301 "Ion: Enable non-IC optimizations.");
4302 } else {
4303 jit::JitOptions.forceInlineCaches = true;
4304 JitSpew(js::jit::JitSpew_IonScripts,
4305 "Ion: Disable non-IC optimizations.");
4307 break;
4308 case JSJITCOMPILER_ION_CHECK_RANGE_ANALYSIS:
4309 if (value == 0) {
4310 jit::JitOptions.checkRangeAnalysis = false;
4311 JitSpew(js::jit::JitSpew_IonScripts,
4312 "Ion: Enable range analysis checks.");
4313 } else {
4314 jit::JitOptions.checkRangeAnalysis = true;
4315 JitSpew(js::jit::JitSpew_IonScripts,
4316 "Ion: Disable range analysis checks.");
4318 break;
4319 case JSJITCOMPILER_ION_ENABLE:
4320 if (value == 1) {
4321 jit::JitOptions.ion = true;
4322 JitSpew(js::jit::JitSpew_IonScripts, "Enable ion");
4323 } else if (value == 0) {
4324 jit::JitOptions.ion = false;
4325 JitSpew(js::jit::JitSpew_IonScripts, "Disable ion");
4327 break;
4328 case JSJITCOMPILER_JIT_TRUSTEDPRINCIPALS_ENABLE:
4329 if (value == 1) {
4330 jit::JitOptions.jitForTrustedPrincipals = true;
4331 JitSpew(js::jit::JitSpew_IonScripts,
4332 "Enable ion and baselinejit for trusted principals");
4333 } else if (value == 0) {
4334 jit::JitOptions.jitForTrustedPrincipals = false;
4335 JitSpew(js::jit::JitSpew_IonScripts,
4336 "Disable ion and baselinejit for trusted principals");
4338 break;
4339 case JSJITCOMPILER_ION_FREQUENT_BAILOUT_THRESHOLD:
4340 if (value == uint32_t(-1)) {
4341 jit::DefaultJitOptions defaultValues;
4342 value = defaultValues.frequentBailoutThreshold;
4344 jit::JitOptions.frequentBailoutThreshold = value;
4345 break;
4346 case JSJITCOMPILER_BASE_REG_FOR_LOCALS:
4347 if (value == 0) {
4348 jit::JitOptions.baseRegForLocals = jit::BaseRegForAddress::SP;
4349 } else if (value == 1) {
4350 jit::JitOptions.baseRegForLocals = jit::BaseRegForAddress::FP;
4351 } else {
4352 jit::DefaultJitOptions defaultValues;
4353 jit::JitOptions.baseRegForLocals = defaultValues.baseRegForLocals;
4355 break;
4356 case JSJITCOMPILER_BASELINE_INTERPRETER_ENABLE:
4357 if (value == 1) {
4358 jit::JitOptions.baselineInterpreter = true;
4359 } else if (value == 0) {
4360 ReleaseAllJITCode(rt->gcContext());
4361 jit::JitOptions.baselineInterpreter = false;
4363 break;
4364 case JSJITCOMPILER_BASELINE_ENABLE:
4365 if (value == 1) {
4366 jit::JitOptions.baselineJit = true;
4367 ReleaseAllJITCode(rt->gcContext());
4368 JitSpew(js::jit::JitSpew_BaselineScripts, "Enable baseline");
4369 } else if (value == 0) {
4370 jit::JitOptions.baselineJit = false;
4371 ReleaseAllJITCode(rt->gcContext());
4372 JitSpew(js::jit::JitSpew_BaselineScripts, "Disable baseline");
4374 break;
4375 case JSJITCOMPILER_NATIVE_REGEXP_ENABLE:
4376 jit::JitOptions.nativeRegExp = !!value;
4377 break;
4378 case JSJITCOMPILER_JIT_HINTS_ENABLE:
4379 jit::JitOptions.disableJitHints = !value;
4380 break;
4381 case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE:
4382 if (value == 1) {
4383 rt->setOffthreadIonCompilationEnabled(true);
4384 JitSpew(js::jit::JitSpew_IonScripts, "Enable offthread compilation");
4385 } else if (value == 0) {
4386 rt->setOffthreadIonCompilationEnabled(false);
4387 JitSpew(js::jit::JitSpew_IonScripts, "Disable offthread compilation");
4389 break;
4390 case JSJITCOMPILER_INLINING_BYTECODE_MAX_LENGTH:
4391 if (value == uint32_t(-1)) {
4392 jit::DefaultJitOptions defaultValues;
4393 value = defaultValues.smallFunctionMaxBytecodeLength;
4395 jit::JitOptions.smallFunctionMaxBytecodeLength = value;
4396 break;
4397 case JSJITCOMPILER_JUMP_THRESHOLD:
4398 if (value == uint32_t(-1)) {
4399 jit::DefaultJitOptions defaultValues;
4400 value = defaultValues.jumpThreshold;
4402 jit::JitOptions.jumpThreshold = value;
4403 break;
4404 case JSJITCOMPILER_SPECTRE_INDEX_MASKING:
4405 jit::JitOptions.spectreIndexMasking = !!value;
4406 break;
4407 case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS:
4408 jit::JitOptions.spectreObjectMitigations = !!value;
4409 break;
4410 case JSJITCOMPILER_SPECTRE_STRING_MITIGATIONS:
4411 jit::JitOptions.spectreStringMitigations = !!value;
4412 break;
4413 case JSJITCOMPILER_SPECTRE_VALUE_MASKING:
4414 jit::JitOptions.spectreValueMasking = !!value;
4415 break;
4416 case JSJITCOMPILER_SPECTRE_JIT_TO_CXX_CALLS:
4417 jit::JitOptions.spectreJitToCxxCalls = !!value;
4418 break;
4419 case JSJITCOMPILER_WRITE_PROTECT_CODE:
4420 jit::JitOptions.maybeSetWriteProtectCode(!!value);
4421 break;
4422 case JSJITCOMPILER_WASM_FOLD_OFFSETS:
4423 jit::JitOptions.wasmFoldOffsets = !!value;
4424 break;
4425 case JSJITCOMPILER_WASM_DELAY_TIER2:
4426 jit::JitOptions.wasmDelayTier2 = !!value;
4427 break;
4428 case JSJITCOMPILER_WASM_JIT_BASELINE:
4429 JS::ContextOptionsRef(cx).setWasmBaseline(!!value);
4430 break;
4431 case JSJITCOMPILER_WASM_JIT_OPTIMIZING:
4432 JS::ContextOptionsRef(cx).setWasmIon(!!value);
4433 break;
4435 #ifdef DEBUG
4436 case JSJITCOMPILER_FULL_DEBUG_CHECKS:
4437 jit::JitOptions.fullDebugChecks = !!value;
4438 break;
4439 #endif
4440 default:
4441 break;
4445 JS_PUBLIC_API bool JS_GetGlobalJitCompilerOption(JSContext* cx,
4446 JSJitCompilerOption opt,
4447 uint32_t* valueOut) {
4448 MOZ_ASSERT(valueOut);
4449 #ifndef JS_CODEGEN_NONE
4450 JSRuntime* rt = cx->runtime();
4451 switch (opt) {
4452 case JSJITCOMPILER_BASELINE_INTERPRETER_WARMUP_TRIGGER:
4453 *valueOut = jit::JitOptions.baselineInterpreterWarmUpThreshold;
4454 break;
4455 case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER:
4456 *valueOut = jit::JitOptions.baselineJitWarmUpThreshold;
4457 break;
4458 case JSJITCOMPILER_IC_FORCE_MEGAMORPHIC:
4459 *valueOut = jit::JitOptions.forceMegamorphicICs;
4460 break;
4461 case JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER:
4462 *valueOut = jit::JitOptions.normalIonWarmUpThreshold;
4463 break;
4464 case JSJITCOMPILER_ION_FORCE_IC:
4465 *valueOut = jit::JitOptions.forceInlineCaches;
4466 break;
4467 case JSJITCOMPILER_ION_CHECK_RANGE_ANALYSIS:
4468 *valueOut = jit::JitOptions.checkRangeAnalysis;
4469 break;
4470 case JSJITCOMPILER_ION_ENABLE:
4471 *valueOut = jit::JitOptions.ion;
4472 break;
4473 case JSJITCOMPILER_ION_FREQUENT_BAILOUT_THRESHOLD:
4474 *valueOut = jit::JitOptions.frequentBailoutThreshold;
4475 break;
4476 case JSJITCOMPILER_BASE_REG_FOR_LOCALS:
4477 *valueOut = uint32_t(jit::JitOptions.baseRegForLocals);
4478 break;
4479 case JSJITCOMPILER_INLINING_BYTECODE_MAX_LENGTH:
4480 *valueOut = jit::JitOptions.smallFunctionMaxBytecodeLength;
4481 break;
4482 case JSJITCOMPILER_BASELINE_INTERPRETER_ENABLE:
4483 *valueOut = jit::JitOptions.baselineInterpreter;
4484 break;
4485 case JSJITCOMPILER_BASELINE_ENABLE:
4486 *valueOut = jit::JitOptions.baselineJit;
4487 break;
4488 case JSJITCOMPILER_NATIVE_REGEXP_ENABLE:
4489 *valueOut = jit::JitOptions.nativeRegExp;
4490 break;
4491 case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE:
4492 *valueOut = rt->canUseOffthreadIonCompilation();
4493 break;
4494 case JSJITCOMPILER_SPECTRE_INDEX_MASKING:
4495 *valueOut = jit::JitOptions.spectreIndexMasking ? 1 : 0;
4496 break;
4497 case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS:
4498 *valueOut = jit::JitOptions.spectreObjectMitigations ? 1 : 0;
4499 break;
4500 case JSJITCOMPILER_SPECTRE_STRING_MITIGATIONS:
4501 *valueOut = jit::JitOptions.spectreStringMitigations ? 1 : 0;
4502 break;
4503 case JSJITCOMPILER_SPECTRE_VALUE_MASKING:
4504 *valueOut = jit::JitOptions.spectreValueMasking ? 1 : 0;
4505 break;
4506 case JSJITCOMPILER_SPECTRE_JIT_TO_CXX_CALLS:
4507 *valueOut = jit::JitOptions.spectreJitToCxxCalls ? 1 : 0;
4508 break;
4509 case JSJITCOMPILER_WRITE_PROTECT_CODE:
4510 *valueOut = jit::JitOptions.writeProtectCode ? 1 : 0;
4511 break;
4512 case JSJITCOMPILER_WASM_FOLD_OFFSETS:
4513 *valueOut = jit::JitOptions.wasmFoldOffsets ? 1 : 0;
4514 break;
4515 case JSJITCOMPILER_WASM_JIT_BASELINE:
4516 *valueOut = JS::ContextOptionsRef(cx).wasmBaseline() ? 1 : 0;
4517 break;
4518 case JSJITCOMPILER_WASM_JIT_OPTIMIZING:
4519 *valueOut = JS::ContextOptionsRef(cx).wasmIon() ? 1 : 0;
4520 break;
4521 # ifdef DEBUG
4522 case JSJITCOMPILER_FULL_DEBUG_CHECKS:
4523 *valueOut = jit::JitOptions.fullDebugChecks ? 1 : 0;
4524 break;
4525 # endif
4526 default:
4527 return false;
4529 #else
4530 switch (opt) {
4531 # ifdef ENABLE_PORTABLE_BASELINE_INTERP
4532 case JSJITCOMPILER_PORTABLE_BASELINE_ENABLE:
4533 *valueOut = jit::JitOptions.portableBaselineInterpreter;
4534 break;
4535 case JSJITCOMPILER_PORTABLE_BASELINE_WARMUP_THRESHOLD:
4536 *valueOut = jit::JitOptions.portableBaselineInterpreterWarmUpThreshold;
4537 break;
4538 # endif
4539 default:
4540 *valueOut = 0;
4542 #endif
4543 return true;
4546 JS_PUBLIC_API void JS::DisableSpectreMitigationsAfterInit() {
4547 // This is used to turn off Spectre mitigations in pre-allocated child
4548 // processes used for isolated web content. Assert there's a single runtime
4549 // and cancel off-thread compilations, to ensure we're not racing with any
4550 // compilations.
4551 JSContext* cx = TlsContext.get();
4552 MOZ_RELEASE_ASSERT(cx);
4553 MOZ_RELEASE_ASSERT(JSRuntime::hasSingleLiveRuntime());
4554 MOZ_RELEASE_ASSERT(cx->runtime()->wasmInstances.lock()->empty());
4556 CancelOffThreadIonCompile(cx->runtime());
4558 jit::JitOptions.spectreIndexMasking = false;
4559 jit::JitOptions.spectreObjectMitigations = false;
4560 jit::JitOptions.spectreStringMitigations = false;
4561 jit::JitOptions.spectreValueMasking = false;
4562 jit::JitOptions.spectreJitToCxxCalls = false;
4565 /************************************************************************/
4567 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && \
4568 defined(XP_WIN) && (defined(MOZ_MEMORY) || !defined(JS_STANDALONE))
4570 # include "util/WindowsWrapper.h"
4573 * Initialization routine for the JS DLL.
4575 BOOL WINAPI DllMain(HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) {
4576 return TRUE;
4579 #endif
4581 JS_PUBLIC_API bool JS_IndexToId(JSContext* cx, uint32_t index,
4582 MutableHandleId id) {
4583 return IndexToId(cx, index, id);
4586 JS_PUBLIC_API bool JS_CharsToId(JSContext* cx, JS::TwoByteChars chars,
4587 MutableHandleId idp) {
4588 Rooted<JSAtom*> atom(cx,
4589 AtomizeChars(cx, chars.begin().get(), chars.length()));
4590 if (!atom) {
4591 return false;
4593 #ifdef DEBUG
4594 MOZ_ASSERT(!atom->isIndex(), "API misuse: |chars| must not encode an index");
4595 #endif
4596 idp.set(AtomToId(atom));
4597 return true;
4600 JS_PUBLIC_API bool JS_IsIdentifier(JSContext* cx, HandleString str,
4601 bool* isIdentifier) {
4602 cx->check(str);
4604 JSLinearString* linearStr = str->ensureLinear(cx);
4605 if (!linearStr) {
4606 return false;
4609 *isIdentifier = IsIdentifier(linearStr);
4610 return true;
4613 JS_PUBLIC_API bool JS_IsIdentifier(const char16_t* chars, size_t length) {
4614 return IsIdentifier(chars, length);
4617 namespace JS {
4619 void AutoFilename::reset() {
4620 if (ss_) {
4621 ss_->Release();
4622 ss_ = nullptr;
4624 if (filename_.is<const char*>()) {
4625 filename_.as<const char*>() = nullptr;
4626 } else {
4627 filename_.as<UniqueChars>().reset();
4631 void AutoFilename::setScriptSource(js::ScriptSource* p) {
4632 MOZ_ASSERT(!ss_);
4633 MOZ_ASSERT(!get());
4634 ss_ = p;
4635 if (p) {
4636 p->AddRef();
4637 setUnowned(p->filename());
4641 void AutoFilename::setUnowned(const char* filename) {
4642 MOZ_ASSERT(!get());
4643 filename_.as<const char*>() = filename ? filename : "";
4646 void AutoFilename::setOwned(UniqueChars&& filename) {
4647 MOZ_ASSERT(!get());
4648 filename_ = AsVariant(std::move(filename));
4651 const char* AutoFilename::get() const {
4652 if (filename_.is<const char*>()) {
4653 return filename_.as<const char*>();
4655 return filename_.as<UniqueChars>().get();
4658 JS_PUBLIC_API bool DescribeScriptedCaller(JSContext* cx, AutoFilename* filename,
4659 uint32_t* lineno,
4660 JS::ColumnNumberOneOrigin* column) {
4661 if (filename) {
4662 filename->reset();
4664 if (lineno) {
4665 *lineno = 0;
4667 if (column) {
4668 *column = JS::ColumnNumberOneOrigin();
4671 if (!cx->compartment()) {
4672 return false;
4675 NonBuiltinFrameIter i(cx, cx->realm()->principals());
4676 if (i.done()) {
4677 return false;
4680 // If the caller is hidden, the embedding wants us to return false here so
4681 // that it can check its own stack (see HideScriptedCaller).
4682 if (i.activation()->scriptedCallerIsHidden()) {
4683 return false;
4686 if (filename) {
4687 if (i.isWasm()) {
4688 // For Wasm, copy out the filename, there is no script source.
4689 UniqueChars copy = DuplicateString(i.filename() ? i.filename() : "");
4690 if (!copy) {
4691 filename->setUnowned("out of memory");
4692 } else {
4693 filename->setOwned(std::move(copy));
4695 } else {
4696 // All other frames have a script source to read the filename from.
4697 filename->setScriptSource(i.scriptSource());
4701 if (lineno) {
4702 JS::TaggedColumnNumberOneOrigin columnNumber;
4703 *lineno = i.computeLine(&columnNumber);
4704 if (column) {
4705 *column = JS::ColumnNumberOneOrigin(columnNumber.oneOriginValue());
4707 } else if (column) {
4708 JS::TaggedColumnNumberOneOrigin columnNumber;
4709 i.computeLine(&columnNumber);
4710 *column = JS::ColumnNumberOneOrigin(columnNumber.oneOriginValue());
4713 return true;
4716 // Fast path to get the activation and realm to use for GetScriptedCallerGlobal.
4717 // If this returns false, the fast path didn't work out and the caller has to
4718 // use the (much slower) NonBuiltinFrameIter path.
4720 // The optimization here is that we skip Ion-inlined frames and only look at
4721 // 'outer' frames. That's fine because Ion doesn't inline cross-realm calls.
4722 // However, GetScriptedCallerGlobal has to skip self-hosted frames and Ion
4723 // can inline self-hosted scripts, so we have to be careful:
4725 // * When we see a non-self-hosted outer script, it's possible we inlined
4726 // self-hosted scripts into it but that doesn't matter because these scripts
4727 // all have the same realm/global anyway.
4729 // * When we see a self-hosted outer script, it's possible we inlined
4730 // non-self-hosted scripts into it, so we have to give up because in this
4731 // case, whether or not to skip the self-hosted frame (to the possibly
4732 // different-realm caller) requires the slow path to handle inlining. Baseline
4733 // and the interpreter don't inline so this only affects Ion.
4734 static bool GetScriptedCallerActivationRealmFast(JSContext* cx,
4735 Activation** activation,
4736 Realm** realm) {
4737 ActivationIterator activationIter(cx);
4739 if (activationIter.done()) {
4740 *activation = nullptr;
4741 *realm = nullptr;
4742 return true;
4745 if (activationIter->isJit()) {
4746 jit::JitActivation* act = activationIter->asJit();
4747 JitFrameIter iter(act);
4748 while (true) {
4749 iter.skipNonScriptedJSFrames();
4750 if (iter.done()) {
4751 break;
4754 if (!iter.isSelfHostedIgnoringInlining()) {
4755 *activation = act;
4756 *realm = iter.realm();
4757 return true;
4760 if (iter.isJSJit() && iter.asJSJit().isIonScripted()) {
4761 // Ion might have inlined non-self-hosted scripts in this
4762 // self-hosted script.
4763 return false;
4766 ++iter;
4768 } else if (activationIter->isInterpreter()) {
4769 InterpreterActivation* act = activationIter->asInterpreter();
4770 for (InterpreterFrameIterator iter(act); !iter.done(); ++iter) {
4771 if (!iter.frame()->script()->selfHosted()) {
4772 *activation = act;
4773 *realm = iter.frame()->script()->realm();
4774 return true;
4779 return false;
4782 JS_PUBLIC_API JSObject* GetScriptedCallerGlobal(JSContext* cx) {
4783 Activation* activation;
4784 Realm* realm;
4785 if (GetScriptedCallerActivationRealmFast(cx, &activation, &realm)) {
4786 if (!activation) {
4787 return nullptr;
4789 } else {
4790 NonBuiltinFrameIter i(cx);
4791 if (i.done()) {
4792 return nullptr;
4794 activation = i.activation();
4795 realm = i.realm();
4798 MOZ_ASSERT(realm->compartment() == activation->compartment());
4800 // If the caller is hidden, the embedding wants us to return null here so
4801 // that it can check its own stack (see HideScriptedCaller).
4802 if (activation->scriptedCallerIsHidden()) {
4803 return nullptr;
4806 GlobalObject* global = realm->maybeGlobal();
4808 // No one should be running code in a realm without any live objects, so
4809 // there should definitely be a live global.
4810 MOZ_ASSERT(global);
4812 return global;
4815 JS_PUBLIC_API void HideScriptedCaller(JSContext* cx) {
4816 MOZ_ASSERT(cx);
4818 // If there's no accessible activation on the stack, we'll return null from
4819 // DescribeScriptedCaller anyway, so there's no need to annotate anything.
4820 Activation* act = cx->activation();
4821 if (!act) {
4822 return;
4824 act->hideScriptedCaller();
4827 JS_PUBLIC_API void UnhideScriptedCaller(JSContext* cx) {
4828 Activation* act = cx->activation();
4829 if (!act) {
4830 return;
4832 act->unhideScriptedCaller();
4835 } /* namespace JS */
4837 #ifdef JS_DEBUG
4838 JS_PUBLIC_API void JS::detail::AssertArgumentsAreSane(JSContext* cx,
4839 HandleValue value) {
4840 AssertHeapIsIdle();
4841 CHECK_THREAD(cx);
4842 cx->check(value);
4844 #endif /* JS_DEBUG */
4846 JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx,
4847 JS::HandleScript script,
4848 TranscodeBuffer& buffer) {
4849 if (!script) {
4850 return false;
4852 if (!script->scriptSource()->xdrFinalizeEncoder(cx, buffer)) {
4853 return false;
4855 return true;
4858 JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx,
4859 JS::Handle<JSObject*> module,
4860 TranscodeBuffer& buffer) {
4861 if (!module->as<ModuleObject>()
4862 .scriptSourceObject()
4863 ->source()
4864 ->xdrFinalizeEncoder(cx, buffer)) {
4865 return false;
4867 return true;
4870 JS_PUBLIC_API void JS::AbortIncrementalEncoding(JS::HandleScript script) {
4871 if (!script) {
4872 return;
4874 script->scriptSource()->xdrAbortEncoder();
4877 JS_PUBLIC_API void JS::AbortIncrementalEncoding(JS::Handle<JSObject*> module) {
4878 module->as<ModuleObject>().scriptSourceObject()->source()->xdrAbortEncoder();
4881 bool JS::IsWasmModuleObject(HandleObject obj) {
4882 return obj->canUnwrapAs<WasmModuleObject>();
4885 JS_PUBLIC_API RefPtr<JS::WasmModule> JS::GetWasmModule(HandleObject obj) {
4886 MOZ_ASSERT(JS::IsWasmModuleObject(obj));
4887 WasmModuleObject& mobj = obj->unwrapAs<WasmModuleObject>();
4888 return const_cast<wasm::Module*>(&mobj.module());
4891 bool JS::DisableWasmHugeMemory() { return wasm::DisableHugeMemory(); }
4893 JS_PUBLIC_API void JS::SetProcessLargeAllocationFailureCallback(
4894 JS::LargeAllocationFailureCallback lafc) {
4895 MOZ_ASSERT(!OnLargeAllocationFailure);
4896 OnLargeAllocationFailure = lafc;
4899 JS_PUBLIC_API void JS::SetOutOfMemoryCallback(JSContext* cx,
4900 OutOfMemoryCallback cb,
4901 void* data) {
4902 cx->runtime()->oomCallback = cb;
4903 cx->runtime()->oomCallbackData = data;
4906 JS_PUBLIC_API void JS::SetShadowRealmInitializeGlobalCallback(
4907 JSContext* cx, JS::GlobalInitializeCallback callback) {
4908 cx->runtime()->shadowRealmInitializeGlobalCallback = callback;
4911 JS_PUBLIC_API void JS::SetShadowRealmGlobalCreationCallback(
4912 JSContext* cx, JS::GlobalCreationCallback callback) {
4913 cx->runtime()->shadowRealmGlobalCreationCallback = callback;
4916 JS::FirstSubsumedFrame::FirstSubsumedFrame(
4917 JSContext* cx, bool ignoreSelfHostedFrames /* = true */)
4918 : JS::FirstSubsumedFrame(cx, cx->realm()->principals(),
4919 ignoreSelfHostedFrames) {}
4921 JS_PUBLIC_API bool JS::CaptureCurrentStack(
4922 JSContext* cx, JS::MutableHandleObject stackp,
4923 JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */) {
4924 AssertHeapIsIdle();
4925 CHECK_THREAD(cx);
4926 MOZ_RELEASE_ASSERT(cx->realm());
4928 Realm* realm = cx->realm();
4929 Rooted<SavedFrame*> frame(cx);
4930 if (!realm->savedStacks().saveCurrentStack(cx, &frame, std::move(capture))) {
4931 return false;
4933 stackp.set(frame.get());
4934 return true;
4937 JS_PUBLIC_API bool JS::IsAsyncStackCaptureEnabledForRealm(JSContext* cx) {
4938 if (!cx->options().asyncStack()) {
4939 return false;
4942 if (!cx->options().asyncStackCaptureDebuggeeOnly() ||
4943 cx->realm()->isDebuggee()) {
4944 return true;
4947 return cx->realm()->isAsyncStackCapturingEnabled;
4950 JS_PUBLIC_API bool JS::CopyAsyncStack(JSContext* cx,
4951 JS::HandleObject asyncStack,
4952 JS::HandleString asyncCause,
4953 JS::MutableHandleObject stackp,
4954 const Maybe<size_t>& maxFrameCount) {
4955 AssertHeapIsIdle();
4956 CHECK_THREAD(cx);
4957 MOZ_RELEASE_ASSERT(cx->realm());
4959 js::AssertObjectIsSavedFrameOrWrapper(cx, asyncStack);
4960 Realm* realm = cx->realm();
4961 Rooted<SavedFrame*> frame(cx);
4962 if (!realm->savedStacks().copyAsyncStack(cx, asyncStack, asyncCause, &frame,
4963 maxFrameCount)) {
4964 return false;
4966 stackp.set(frame.get());
4967 return true;
4970 JS_PUBLIC_API Zone* JS::GetObjectZone(JSObject* obj) {
4971 Zone* zone = obj->zone();
4973 // Check zone pointer is valid and not a poison value. See bug 1878421.
4974 MOZ_RELEASE_ASSERT(zone->runtimeFromMainThread());
4976 return zone;
4979 JS_PUBLIC_API Zone* JS::GetTenuredGCThingZone(GCCellPtr thing) {
4980 js::gc::Cell* cell = thing.asCell();
4981 MOZ_ASSERT(!js::gc::IsInsideNursery(cell));
4982 Zone* zone = js::gc::detail::GetTenuredGCThingZone(cell);
4984 // Check zone pointer is valid and not a poison value. See bug 1878421.
4985 MOZ_RELEASE_ASSERT(zone->runtimeFromMainThread());
4987 return zone;
4990 JS_PUBLIC_API Zone* JS::GetNurseryCellZone(gc::Cell* cell) {
4991 return cell->nurseryZone();
4994 JS_PUBLIC_API JS::TraceKind JS::GCThingTraceKind(void* thing) {
4995 MOZ_ASSERT(thing);
4996 return static_cast<js::gc::Cell*>(thing)->getTraceKind();
4999 JS_PUBLIC_API void js::SetStackFormat(JSContext* cx, js::StackFormat format) {
5000 cx->runtime()->setStackFormat(format);
5003 JS_PUBLIC_API js::StackFormat js::GetStackFormat(JSContext* cx) {
5004 return cx->runtime()->stackFormat();
5007 JS_PUBLIC_API JS::JSTimers JS::GetJSTimers(JSContext* cx) {
5008 return cx->realm()->timers;
5011 namespace js {
5013 JS_PUBLIC_API void NoteIntentionalCrash() {
5014 #ifdef __linux__
5015 static bool* addr =
5016 reinterpret_cast<bool*>(dlsym(RTLD_DEFAULT, "gBreakpadInjectorEnabled"));
5017 if (addr) {
5018 *addr = false;
5020 #endif
5023 #ifdef DEBUG
5024 bool gSupportDifferentialTesting = false;
5025 #endif // DEBUG
5027 } // namespace js
5029 #ifdef DEBUG
5031 JS_PUBLIC_API void JS::SetSupportDifferentialTesting(bool value) {
5032 js::gSupportDifferentialTesting = value;
5035 #endif // DEBUG