diff options
Diffstat (limited to 'js/src/jsapi.h')
-rw-r--r-- | js/src/jsapi.h | 3034 |
1 files changed, 3034 insertions, 0 deletions
diff --git a/js/src/jsapi.h b/js/src/jsapi.h new file mode 100644 index 0000000000..f959f36cf0 --- /dev/null +++ b/js/src/jsapi.h @@ -0,0 +1,3034 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* JavaScript API. */ + +#ifndef jsapi_h +#define jsapi_h + +#include "mozilla/AlreadyAddRefed.h" +#include "mozilla/FloatingPoint.h" +#include "mozilla/Maybe.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/Range.h" +#include "mozilla/RangedPtr.h" +#include "mozilla/RefPtr.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/Utf8.h" +#include "mozilla/Variant.h" + +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#include "jspubtd.h" + +#include "js/AllocPolicy.h" +#include "js/CallArgs.h" +#include "js/CharacterEncoding.h" +#include "js/Class.h" +#include "js/CompileOptions.h" +#include "js/ErrorReport.h" +#include "js/GCVector.h" +#include "js/HashTable.h" +#include "js/Id.h" +#include "js/MemoryFunctions.h" +#include "js/OffThreadScriptCompilation.h" +#include "js/Principals.h" +#include "js/PropertyDescriptor.h" +#include "js/PropertySpec.h" +#include "js/Realm.h" +#include "js/RealmOptions.h" +#include "js/RefCounted.h" +#include "js/RootingAPI.h" +#include "js/TracingAPI.h" +#include "js/Transcoding.h" +#include "js/UniquePtr.h" +#include "js/Utility.h" +#include "js/Value.h" +#include "js/ValueArray.h" +#include "js/Vector.h" + +/************************************************************************/ + +struct JSFunctionSpec; +struct JSPropertySpec; + +namespace JS { + +template <typename UnitT> +class SourceText; + +class TwoByteChars; + +using ValueVector = JS::GCVector<JS::Value>; +using IdVector = JS::GCVector<jsid>; +using ScriptVector = JS::GCVector<JSScript*>; +using StringVector = JS::GCVector<JSString*>; + +/** + * Custom rooting behavior for internal and external clients. + */ +class MOZ_RAII JS_PUBLIC_API CustomAutoRooter : private AutoGCRooter { + public: + template <typename CX> + explicit CustomAutoRooter(const CX& cx) + : AutoGCRooter(cx, AutoGCRooter::Kind::Custom) {} + + friend void AutoGCRooter::trace(JSTracer* trc); + + protected: + virtual ~CustomAutoRooter() = default; + + /** Supplied by derived class to trace roots. */ + virtual void trace(JSTracer* trc) = 0; + + private: +}; + +} /* namespace JS */ + +/* Callbacks and their arguments. */ + +/************************************************************************/ +using JSGetElementCallback = JSObject* (*)(JSContext* aCx, + JS::HandleValue privateValue); + +using JSInterruptCallback = bool (*)(JSContext*); + +/** + * Callback used to ask the embedding for the cross compartment wrapper handler + * that implements the desired prolicy for this kind of object in the + * destination compartment. |obj| is the object to be wrapped. If |existing| is + * non-nullptr, it will point to an existing wrapper object that should be + * re-used if possible. |existing| is guaranteed to be a cross-compartment + * wrapper with a lazily-defined prototype and the correct global. It is + * guaranteed not to wrap a function. + */ +using JSWrapObjectCallback = JSObject* (*)(JSContext*, JS::HandleObject, + JS::HandleObject); + +/** + * Callback used by the wrap hook to ask the embedding to prepare an object + * for wrapping in a context. This might include unwrapping other wrappers + * or even finding a more suitable object for the new compartment. If |origObj| + * is non-null, then it is the original object we are going to swap into during + * a transplant. + */ +using JSPreWrapCallback = void (*)(JSContext*, JS::HandleObject, + JS::HandleObject, JS::HandleObject, + JS::HandleObject, JS::MutableHandleObject); + +struct JSWrapObjectCallbacks { + JSWrapObjectCallback wrap; + JSPreWrapCallback preWrap; +}; + +using JSDestroyZoneCallback = void (*)(JSFreeOp*, JS::Zone*); + +using JSDestroyCompartmentCallback = void (*)(JSFreeOp*, JS::Compartment*); + +using JSSizeOfIncludingThisCompartmentCallback = + size_t (*)(mozilla::MallocSizeOf, JS::Compartment*); + +/** + * Callback used to intercept JavaScript errors. + */ +struct JSErrorInterceptor { + /** + * This method is called whenever an error has been raised from JS code. + * + * This method MUST be infallible. + */ + virtual void interceptError(JSContext* cx, JS::HandleValue error) = 0; +}; + +/************************************************************************/ + +static MOZ_ALWAYS_INLINE JS::Value JS_NumberValue(double d) { + int32_t i; + d = JS::CanonicalizeNaN(d); + if (mozilla::NumberIsInt32(d, &i)) { + return JS::Int32Value(i); + } + return JS::DoubleValue(d); +} + +/************************************************************************/ + +JS_PUBLIC_API bool JS_StringHasBeenPinned(JSContext* cx, JSString* str); + +/************************************************************************/ + +/** Microseconds since the epoch, midnight, January 1, 1970 UTC. */ +extern JS_PUBLIC_API int64_t JS_Now(void); + +/** Don't want to export data, so provide accessors for non-inline Values. */ +extern JS_PUBLIC_API JS::Value JS_GetEmptyStringValue(JSContext* cx); + +extern JS_PUBLIC_API JSString* JS_GetEmptyString(JSContext* cx); + +extern JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, JS::HandleValue v, + JS::MutableHandleObject objp); + +extern JS_PUBLIC_API JSFunction* JS_ValueToFunction(JSContext* cx, + JS::HandleValue v); + +extern JS_PUBLIC_API JSFunction* JS_ValueToConstructor(JSContext* cx, + JS::HandleValue v); + +extern JS_PUBLIC_API JSString* JS_ValueToSource(JSContext* cx, + JS::Handle<JS::Value> v); + +extern JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip); + +extern JS_PUBLIC_API JSType JS_TypeOfValue(JSContext* cx, + JS::Handle<JS::Value> v); + +namespace JS { + +extern JS_PUBLIC_API const char* InformalValueTypeName(const JS::Value& v); + +/** Timing information for telemetry purposes **/ +struct JSTimers { + mozilla::TimeDuration executionTime; // Total time spent executing + mozilla::TimeDuration delazificationTime; // Total time spent delazifying + mozilla::TimeDuration xdrEncodingTime; // Total time spent XDR encoding + mozilla::TimeDuration + baselineCompileTime; // Total time spent in baseline compiler +}; + +extern JS_PUBLIC_API JSTimers GetJSTimers(JSContext* cx); + +} /* namespace JS */ + +/** True iff fun is the global eval function. */ +extern JS_PUBLIC_API bool JS_IsBuiltinEvalFunction(JSFunction* fun); + +/** True iff fun is the Function constructor. */ +extern JS_PUBLIC_API bool JS_IsBuiltinFunctionConstructor(JSFunction* fun); + +/************************************************************************/ + +// [SMDOC] Data Structures (JSContext, JSRuntime, Realm, Compartment, Zone) +// +// SpiderMonkey uses some data structures that behave a lot like Russian dolls: +// runtimes contain zones, zones contain compartments, compartments contain +// realms. Each layer has its own purpose. +// +// Realm +// ----- +// Data associated with a global object. In the browser each frame has its +// own global/realm. +// +// Compartment +// ----------- +// Security membrane; when an object from compartment A is used in compartment +// B, a cross-compartment wrapper (a kind of proxy) is used. In the browser, +// same-origin realms can share a compartment. +// +// Zone +// ---- +// A Zone is a group of compartments that share GC resources (arenas, strings, +// etc) for memory usage and performance reasons. Zone is the GC unit: the GC +// can operate on one or more zones at a time. The browser uses roughly one zone +// per tab. +// +// Context +// ------- +// JSContext represents a thread: there must be exactly one JSContext for each +// thread running JS/Wasm. +// +// Internally, helper threads can also have a JSContext. They do not always have +// an active context, but one may be requested by AutoSetHelperThreadContext, +// which activates a pre-allocated JSContext for the duration of its lifetime. +// +// Runtime +// ------- +// JSRuntime is very similar to JSContext: each runtime belongs to one context +// (thread), but helper threads don't have their own runtimes (they're shared by +// all runtimes in the process and use the runtime of the task they're +// executing). + +/* + * Locking, contexts, and memory allocation. + * + * It is important that SpiderMonkey be initialized, and the first context + * be created, in a single-threaded fashion. Otherwise the behavior of the + * library is undefined. + * See: + * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference + */ + +// Create a new context (and runtime) for this thread. +extern JS_PUBLIC_API JSContext* JS_NewContext( + uint32_t maxbytes, JSRuntime* parentRuntime = nullptr); + +// Destroy a context allocated with JS_NewContext. Must be called on the thread +// that called JS_NewContext. +extern JS_PUBLIC_API void JS_DestroyContext(JSContext* cx); + +JS_PUBLIC_API void* JS_GetContextPrivate(JSContext* cx); + +JS_PUBLIC_API void JS_SetContextPrivate(JSContext* cx, void* data); + +extern JS_PUBLIC_API JSRuntime* JS_GetParentRuntime(JSContext* cx); + +extern JS_PUBLIC_API JSRuntime* JS_GetRuntime(JSContext* cx); + +extern JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx); + +namespace js { + +void AssertHeapIsIdle(); + +} /* namespace js */ + +namespace JS { + +/** + * Initialize the runtime's self-hosted code. Embeddings should call this + * exactly once per runtime/context, before the first JS_NewGlobalObject + * call. + * + * NOTE: This may not set a pending exception in the case of OOM since this + * runs very early in startup. + */ +JS_PUBLIC_API bool InitSelfHostedCode(JSContext* cx); + +/** + * Asserts (in debug and release builds) that `obj` belongs to the current + * thread's context. + */ +JS_PUBLIC_API void AssertObjectBelongsToCurrentThread(JSObject* obj); + +/** + * Install a process-wide callback to validate script filenames. The JS engine + * will invoke this callback for each JS script it parses or XDR decodes. + * + * If the callback returns |false|, an exception is thrown and parsing/decoding + * will be aborted. + * + * See also CompileOptions::setSkipFilenameValidation to opt-out of the callback + * for specific parse jobs. + */ +using FilenameValidationCallback = bool (*)(const char* filename, + bool isSystemRealm); +JS_PUBLIC_API void SetFilenameValidationCallback(FilenameValidationCallback cb); + +} /* namespace JS */ + +/** + * Set callback to send tasks to XPCOM thread pools + */ +JS_PUBLIC_API void SetHelperThreadTaskCallback( + bool (*callback)(js::UniquePtr<js::RunnableTask>)); + +extern JS_PUBLIC_API const char* JS_GetImplementationVersion(void); + +extern JS_PUBLIC_API void JS_SetDestroyZoneCallback( + JSContext* cx, JSDestroyZoneCallback callback); + +extern JS_PUBLIC_API void JS_SetDestroyCompartmentCallback( + JSContext* cx, JSDestroyCompartmentCallback callback); + +extern JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback( + JSContext* cx, JSSizeOfIncludingThisCompartmentCallback callback); + +extern JS_PUBLIC_API void JS_SetWrapObjectCallbacks( + JSContext* cx, const JSWrapObjectCallbacks* callbacks); + +// Set a callback that will be called whenever an error +// is thrown in this runtime. This is designed as a mechanism +// for logging errors. Note that the VM makes no attempt to sanitize +// the contents of the error (so it may contain private data) +// or to sort out among errors (so it may not be the error you +// are interested in or for the component in which you are +// interested). +// +// If the callback sets a new error, this new error +// will replace the original error. +// +// May be `nullptr`. +// This is a no-op if built without NIGHTLY_BUILD. +extern JS_PUBLIC_API void JS_SetErrorInterceptorCallback( + JSRuntime*, JSErrorInterceptor* callback); + +// This returns nullptr if built without NIGHTLY_BUILD. +extern JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback( + JSRuntime*); + +// Examine a value to determine if it is one of the built-in Error types. +// If so, return the error type. +extern JS_PUBLIC_API mozilla::Maybe<JSExnType> JS_GetErrorType( + const JS::Value& val); + +extern JS_PUBLIC_API void JS_SetCompartmentPrivate(JS::Compartment* compartment, + void* data); + +extern JS_PUBLIC_API void* JS_GetCompartmentPrivate( + JS::Compartment* compartment); + +extern JS_PUBLIC_API void JS_SetZoneUserData(JS::Zone* zone, void* data); + +extern JS_PUBLIC_API void* JS_GetZoneUserData(JS::Zone* zone); + +extern JS_PUBLIC_API bool JS_WrapObject(JSContext* cx, + JS::MutableHandleObject objp); + +extern JS_PUBLIC_API bool JS_WrapValue(JSContext* cx, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API JSObject* JS_TransplantObject(JSContext* cx, + JS::HandleObject origobj, + JS::HandleObject target); + +extern JS_PUBLIC_API bool JS_RefreshCrossCompartmentWrappers( + JSContext* cx, JS::Handle<JSObject*> obj); + +/* + * At any time, a JSContext has a current (possibly-nullptr) realm. + * Realms are described in: + * + * developer.mozilla.org/en-US/docs/SpiderMonkey/SpiderMonkey_compartments + * + * The current realm of a context may be changed. The preferred way to do + * this is with JSAutoRealm: + * + * void foo(JSContext* cx, JSObject* obj) { + * // in some realm 'r' + * { + * JSAutoRealm ar(cx, obj); // constructor enters + * // in the realm of 'obj' + * } // destructor leaves + * // back in realm 'r' + * } + * + * The object passed to JSAutoRealm must *not* be a cross-compartment wrapper, + * because CCWs are not associated with a single realm. + * + * For more complicated uses that don't neatly fit in a C++ stack frame, the + * realm can be entered and left using separate function calls: + * + * void foo(JSContext* cx, JSObject* obj) { + * // in 'oldRealm' + * JS::Realm* oldRealm = JS::EnterRealm(cx, obj); + * // in the realm of 'obj' + * JS::LeaveRealm(cx, oldRealm); + * // back in 'oldRealm' + * } + * + * Note: these calls must still execute in a LIFO manner w.r.t all other + * enter/leave calls on the context. Furthermore, only the return value of a + * JS::EnterRealm call may be passed as the 'oldRealm' argument of + * the corresponding JS::LeaveRealm call. + * + * Entering a realm roots the realm and its global object for the lifetime of + * the JSAutoRealm. + */ + +class MOZ_RAII JS_PUBLIC_API JSAutoRealm { + JSContext* cx_; + JS::Realm* oldRealm_; + + public: + JSAutoRealm(JSContext* cx, JSObject* target); + JSAutoRealm(JSContext* cx, JSScript* target); + ~JSAutoRealm(); +}; + +class MOZ_RAII JS_PUBLIC_API JSAutoNullableRealm { + JSContext* cx_; + JS::Realm* oldRealm_; + + public: + explicit JSAutoNullableRealm(JSContext* cx, JSObject* targetOrNull); + ~JSAutoNullableRealm(); +}; + +namespace JS { + +/** NB: This API is infallible; a nullptr return value does not indicate error. + * + * |target| must not be a cross-compartment wrapper because CCWs are not + * associated with a single realm. + * + * Entering a realm roots the realm and its global object until the matching + * JS::LeaveRealm() call. + */ +extern JS_PUBLIC_API JS::Realm* EnterRealm(JSContext* cx, JSObject* target); + +extern JS_PUBLIC_API void LeaveRealm(JSContext* cx, JS::Realm* oldRealm); + +using IterateRealmCallback = void (*)(JSContext* cx, void* data, Realm* realm, + const AutoRequireNoGC& nogc); + +/** + * This function calls |realmCallback| on every realm. Beware that there is no + * guarantee that the realm will survive after the callback returns. Also, + * barriers are disabled via the TraceSession. + */ +extern JS_PUBLIC_API void IterateRealms(JSContext* cx, void* data, + IterateRealmCallback realmCallback); + +/** + * Like IterateRealms, but only call the callback for realms using |principals|. + */ +extern JS_PUBLIC_API void IterateRealmsWithPrincipals( + JSContext* cx, JSPrincipals* principals, void* data, + IterateRealmCallback realmCallback); + +/** + * Like IterateRealms, but only iterates realms in |compartment|. + */ +extern JS_PUBLIC_API void IterateRealmsInCompartment( + JSContext* cx, JS::Compartment* compartment, void* data, + IterateRealmCallback realmCallback); + +} // namespace JS + +/** + * An enum that JSIterateCompartmentCallback can return to indicate + * whether to keep iterating. + */ +namespace JS { +enum class CompartmentIterResult { KeepGoing, Stop }; +} // namespace JS + +using JSIterateCompartmentCallback = + JS::CompartmentIterResult (*)(JSContext*, void*, JS::Compartment*); + +/** + * This function calls |compartmentCallback| on every compartment until either + * all compartments have been iterated or CompartmentIterResult::Stop is + * returned. Beware that there is no guarantee that the compartment will survive + * after the callback returns. Also, barriers are disabled via the TraceSession. + */ +extern JS_PUBLIC_API void JS_IterateCompartments( + JSContext* cx, void* data, + JSIterateCompartmentCallback compartmentCallback); + +/** + * This function calls |compartmentCallback| on every compartment in the given + * zone until either all compartments have been iterated or + * CompartmentIterResult::Stop is returned. Beware that there is no guarantee + * that the compartment will survive after the callback returns. Also, barriers + * are disabled via the TraceSession. + */ +extern JS_PUBLIC_API void JS_IterateCompartmentsInZone( + JSContext* cx, JS::Zone* zone, void* data, + JSIterateCompartmentCallback compartmentCallback); + +/** + * Mark a jsid after entering a new compartment. Different zones separately + * mark the ids in a runtime, and this must be used any time an id is obtained + * from one compartment and then used in another compartment, unless the two + * compartments are guaranteed to be in the same zone. + */ +extern JS_PUBLIC_API void JS_MarkCrossZoneId(JSContext* cx, jsid id); + +/** + * If value stores a jsid (an atomized string or symbol), mark that id as for + * JS_MarkCrossZoneId. + */ +extern JS_PUBLIC_API void JS_MarkCrossZoneIdValue(JSContext* cx, + const JS::Value& value); + +/** + * Resolve id, which must contain either a string or an int, to a standard + * class name in obj if possible, defining the class's constructor and/or + * prototype and storing true in *resolved. If id does not name a standard + * class or a top-level property induced by initializing a standard class, + * store false in *resolved and just return true. Return false on error, + * as usual for bool result-typed API entry points. + * + * This API can be called directly from a global object class's resolve op, + * to define standard classes lazily. The class should either have an enumerate + * hook that calls JS_EnumerateStandardClasses, or a newEnumerate hook that + * calls JS_NewEnumerateStandardClasses. newEnumerate is preferred because it's + * faster (does not define all standard classes). + */ +extern JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + bool* resolved); + +extern JS_PUBLIC_API bool JS_MayResolveStandardClass(const JSAtomState& names, + jsid id, + JSObject* maybeObj); + +extern JS_PUBLIC_API bool JS_EnumerateStandardClasses(JSContext* cx, + JS::HandleObject obj); + +/** + * Fill "properties" with a list of standard class names that have not yet been + * resolved on "obj". This can be used as (part of) a newEnumerate class hook + * on a global. Already-resolved things are excluded because they might have + * been deleted by script after being resolved and enumeration considers + * already-defined properties anyway. + */ +extern JS_PUBLIC_API bool JS_NewEnumerateStandardClasses( + JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties, + bool enumerableOnly); + +/** + * Fill "properties" with a list of standard class names. This can be used for + * proxies that want to define behavior that looks like enumerating a global + * without touching the global itself. + */ +extern JS_PUBLIC_API bool JS_NewEnumerateStandardClassesIncludingResolved( + JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties, + bool enumerableOnly); + +extern JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key, + JS::MutableHandle<JSObject*> objp); + +extern JS_PUBLIC_API bool JS_GetClassPrototype( + JSContext* cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp); + +namespace JS { + +/* + * Determine if the given object is an instance/prototype/constructor for a + * standard class. If so, return the associated JSProtoKey. If not, return + * JSProto_Null. + */ + +extern JS_PUBLIC_API JSProtoKey IdentifyStandardInstance(JSObject* obj); + +extern JS_PUBLIC_API JSProtoKey IdentifyStandardPrototype(JSObject* obj); + +extern JS_PUBLIC_API JSProtoKey +IdentifyStandardInstanceOrPrototype(JSObject* obj); + +extern JS_PUBLIC_API JSProtoKey IdentifyStandardConstructor(JSObject* obj); + +extern JS_PUBLIC_API void ProtoKeyToId(JSContext* cx, JSProtoKey key, + JS::MutableHandleId idp); + +} /* namespace JS */ + +extern JS_PUBLIC_API JSProtoKey JS_IdToProtoKey(JSContext* cx, JS::HandleId id); + +extern JS_PUBLIC_API bool JS_IsGlobalObject(JSObject* obj); + +extern JS_PUBLIC_API JSObject* JS_GlobalLexicalEnvironment(JSObject* obj); + +extern JS_PUBLIC_API bool JS_HasExtensibleLexicalEnvironment(JSObject* obj); + +extern JS_PUBLIC_API JSObject* JS_ExtensibleLexicalEnvironment(JSObject* obj); + +namespace JS { + +/** + * Get the current realm's global. Returns nullptr if no realm has been + * entered. + */ +extern JS_PUBLIC_API JSObject* CurrentGlobalOrNull(JSContext* cx); + +/** + * Get the global object associated with an object's realm. The object must not + * be a cross-compartment wrapper (because CCWs are shared by all realms in the + * compartment). + */ +extern JS_PUBLIC_API JSObject* GetNonCCWObjectGlobal(JSObject* obj); + +} // namespace JS + +/** + * Add 'Reflect.parse', a SpiderMonkey extension, to the Reflect object on the + * given global. + */ +extern JS_PUBLIC_API bool JS_InitReflectParse(JSContext* cx, + JS::HandleObject global); + +/** + * Add various profiling-related functions as properties of the given object. + * Defined in builtin/Profilers.cpp. + */ +extern JS_PUBLIC_API bool JS_DefineProfilingFunctions(JSContext* cx, + JS::HandleObject obj); + +/* Defined in vm/Debugger.cpp. */ +extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx, + JS::HandleObject obj); + +namespace JS { + +/** + * Tell JS engine whether Profile Timeline Recording is enabled or not. + * If Profile Timeline Recording is enabled, data shown there like stack won't + * be optimized out. + * This is global state and not associated with specific runtime or context. + */ +extern JS_PUBLIC_API void SetProfileTimelineRecordingEnabled(bool enabled); + +extern JS_PUBLIC_API bool IsProfileTimelineRecordingEnabled(); + +} // namespace JS + +/** + * Set the size of the native stack that should not be exceed. To disable + * stack size checking pass 0. + * + * SpiderMonkey allows for a distinction between system code (such as GCs, which + * may incidentally be triggered by script but are not strictly performed on + * behalf of such script), trusted script (as determined by + * JS_SetTrustedPrincipals), and untrusted script. Each kind of code may have a + * different stack quota, allowing embedders to keep higher-priority machinery + * running in the face of scripted stack exhaustion by something else. + * + * The stack quotas for each kind of code should be monotonically descending, + * and may be specified with this function. If 0 is passed for a given kind + * of code, it defaults to the value of the next-highest-priority kind. + * + * This function may only be called immediately after the runtime is initialized + * and before any code is executed and/or interrupts requested. + */ +extern JS_PUBLIC_API void JS_SetNativeStackQuota( + JSContext* cx, size_t systemCodeStackSize, + size_t trustedScriptStackSize = 0, size_t untrustedScriptStackSize = 0); + +/************************************************************************/ + +extern JS_PUBLIC_API bool JS_ValueToId(JSContext* cx, JS::HandleValue v, + JS::MutableHandleId idp); + +extern JS_PUBLIC_API bool JS_StringToId(JSContext* cx, JS::HandleString s, + JS::MutableHandleId idp); + +extern JS_PUBLIC_API bool JS_IdToValue(JSContext* cx, jsid id, + JS::MutableHandle<JS::Value> vp); + +namespace JS { + +/** + * Convert obj to a primitive value. On success, store the result in vp and + * return true. + * + * The hint argument must be JSTYPE_STRING, JSTYPE_NUMBER, or + * JSTYPE_UNDEFINED (no hint). + * + * Implements: ES6 7.1.1 ToPrimitive(input, [PreferredType]). + */ +extern JS_PUBLIC_API bool ToPrimitive(JSContext* cx, JS::HandleObject obj, + JSType hint, JS::MutableHandleValue vp); + +/** + * If args.get(0) is one of the strings "string", "number", or "default", set + * result to JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_UNDEFINED accordingly and + * return true. Otherwise, return false with a TypeError pending. + * + * This can be useful in implementing a @@toPrimitive method. + */ +extern JS_PUBLIC_API bool GetFirstArgumentAsTypeHint(JSContext* cx, + CallArgs args, + JSType* result); + +} /* namespace JS */ + +extern JS_PUBLIC_API JSObject* JS_InitClass( + JSContext* cx, JS::HandleObject obj, JS::HandleObject parent_proto, + const JSClass* clasp, JSNative constructor, unsigned nargs, + const JSPropertySpec* ps, const JSFunctionSpec* fs, + const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs); + +/** + * Set up ctor.prototype = proto and proto.constructor = ctor with the + * right property flags. + */ +extern JS_PUBLIC_API bool JS_LinkConstructorAndPrototype( + JSContext* cx, JS::Handle<JSObject*> ctor, JS::Handle<JSObject*> proto); + +extern JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx, + JS::Handle<JSObject*> obj, + const JSClass* clasp, + JS::CallArgs* args); + +extern JS_PUBLIC_API bool JS_HasInstance(JSContext* cx, + JS::Handle<JSObject*> obj, + JS::Handle<JS::Value> v, bool* bp); + +namespace JS { + +// Implementation of +// http://www.ecma-international.org/ecma-262/6.0/#sec-ordinaryhasinstance. If +// you're looking for the equivalent of "instanceof", you want JS_HasInstance, +// not this function. +extern JS_PUBLIC_API bool OrdinaryHasInstance(JSContext* cx, + HandleObject objArg, + HandleValue v, bool* bp); + +// Implementation of +// https://www.ecma-international.org/ecma-262/6.0/#sec-instanceofoperator +// This is almost identical to JS_HasInstance, except the latter may call a +// custom hasInstance class op instead of InstanceofOperator. +extern JS_PUBLIC_API bool InstanceofOperator(JSContext* cx, HandleObject obj, + HandleValue v, bool* bp); + +} // namespace JS + +extern JS_PUBLIC_API void JS_InitPrivate(JSObject* obj, void* data, + size_t nbytes, JS::MemoryUse use); + +extern JS_PUBLIC_API void* JS_GetInstancePrivate(JSContext* cx, + JS::Handle<JSObject*> obj, + const JSClass* clasp, + JS::CallArgs* args); + +extern JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx, + JS::Handle<JSObject*> proto); + +namespace JS { + +/** + * During global creation, we fire notifications to callbacks registered + * via the Debugger API. These callbacks are arbitrary script, and can touch + * the global in arbitrary ways. When that happens, the global should not be + * in a half-baked state. But this creates a problem for consumers that need + * to set slots on the global to put it in a consistent state. + * + * This API provides a way for consumers to set slots atomically (immediately + * after the global is created), before any debugger hooks are fired. It's + * unfortunately on the clunky side, but that's the way the cookie crumbles. + * + * If callers have no additional state on the global to set up, they may pass + * |FireOnNewGlobalHook| to JS_NewGlobalObject, which causes that function to + * fire the hook as its final act before returning. Otherwise, callers should + * pass |DontFireOnNewGlobalHook|, which means that they are responsible for + * invoking JS_FireOnNewGlobalObject upon successfully creating the global. If + * an error occurs and the operation aborts, callers should skip firing the + * hook. But otherwise, callers must take care to fire the hook exactly once + * before compiling any script in the global's scope (we have assertions in + * place to enforce this). This lets us be sure that debugger clients never miss + * breakpoints. + */ +enum OnNewGlobalHookOption { FireOnNewGlobalHook, DontFireOnNewGlobalHook }; + +} /* namespace JS */ + +extern JS_PUBLIC_API JSObject* JS_NewGlobalObject( + JSContext* cx, const JSClass* clasp, JSPrincipals* principals, + JS::OnNewGlobalHookOption hookOption, const JS::RealmOptions& options); +/** + * Spidermonkey does not have a good way of keeping track of what compartments + * should be marked on their own. We can mark the roots unconditionally, but + * marking GC things only relevant in live compartments is hard. To mitigate + * this, we create a static trace hook, installed on each global object, from + * which we can be sure the compartment is relevant, and mark it. + * + * It is still possible to specify custom trace hooks for global object classes. + * They can be provided via the RealmOptions passed to JS_NewGlobalObject. + */ +extern JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc, + JSObject* global); + +namespace JS { + +/** + * This allows easily constructing a global object without having to deal with + * JSClassOps, forgetting to add JS_GlobalObjectTraceHook, or forgetting to call + * JS::InitRealmStandardClasses(). Example: + * + * const JSClass globalClass = { "MyGlobal", JSCLASS_GLOBAL_FLAGS, + * &JS::DefaultGlobalClassOps }; + * JS_NewGlobalObject(cx, &globalClass, ...); + */ +extern JS_PUBLIC_DATA const JSClassOps DefaultGlobalClassOps; + +} // namespace JS + +extern JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx, + JS::HandleObject global); + +extern JS_PUBLIC_API JSObject* JS_NewObject(JSContext* cx, + const JSClass* clasp); + +extern JS_PUBLIC_API bool JS_IsNative(JSObject* obj); + +/** + * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default + * proto. If proto is nullptr, the JS object will have `null` as [[Prototype]]. + */ +extern JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProto( + JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto); + +/** + * Creates a new plain object, like `new Object()`, with Object.prototype as + * [[Prototype]]. + */ +extern JS_PUBLIC_API JSObject* JS_NewPlainObject(JSContext* cx); + +/** + * Freeze obj, and all objects it refers to, recursively. This will not recurse + * through non-extensible objects, on the assumption that those are already + * deep-frozen. + */ +extern JS_PUBLIC_API bool JS_DeepFreezeObject(JSContext* cx, + JS::Handle<JSObject*> obj); + +/** + * Freezes an object; see ES5's Object.freeze(obj) method. + */ +extern JS_PUBLIC_API bool JS_FreezeObject(JSContext* cx, + JS::Handle<JSObject*> obj); + +/*** Standard internal methods ********************************************** + * + * The functions below are the fundamental operations on objects. + * + * ES6 specifies 14 internal methods that define how objects behave. The + * standard is actually quite good on this topic, though you may have to read + * it a few times. See ES6 sections 6.1.7.2 and 6.1.7.3. + * + * When 'obj' is an ordinary object, these functions have boring standard + * behavior as specified by ES6 section 9.1; see the section about internal + * methods in js/src/vm/NativeObject.h. + * + * Proxies override the behavior of internal methods. So when 'obj' is a proxy, + * any one of the functions below could do just about anything. See + * js/public/Proxy.h. + */ + +/** + * Get the prototype of |obj|, storing it in |proto|. + * + * Implements: ES6 [[GetPrototypeOf]] internal method. + */ +extern JS_PUBLIC_API bool JS_GetPrototype(JSContext* cx, JS::HandleObject obj, + JS::MutableHandleObject result); + +/** + * If |obj| (underneath any functionally-transparent wrapper proxies) has as + * its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined + * for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype + * in |result|. Otherwise set |*isOrdinary = false|. In case of error, both + * outparams have unspecified value. + */ +extern JS_PUBLIC_API bool JS_GetPrototypeIfOrdinary( + JSContext* cx, JS::HandleObject obj, bool* isOrdinary, + JS::MutableHandleObject result); + +/** + * Change the prototype of obj. + * + * Implements: ES6 [[SetPrototypeOf]] internal method. + * + * In cases where ES6 [[SetPrototypeOf]] returns false without an exception, + * JS_SetPrototype throws a TypeError and returns false. + * + * Performance warning: JS_SetPrototype is very bad for performance. It may + * cause compiled jit-code to be invalidated. It also causes not only obj but + * all other objects in the same "group" as obj to be permanently deoptimized. + * It's better to create the object with the right prototype from the start. + */ +extern JS_PUBLIC_API bool JS_SetPrototype(JSContext* cx, JS::HandleObject obj, + JS::HandleObject proto); + +/** + * Determine whether obj is extensible. Extensible objects can have new + * properties defined on them. Inextensible objects can't, and their + * [[Prototype]] slot is fixed as well. + * + * Implements: ES6 [[IsExtensible]] internal method. + */ +extern JS_PUBLIC_API bool JS_IsExtensible(JSContext* cx, JS::HandleObject obj, + bool* extensible); + +/** + * Attempt to make |obj| non-extensible. + * + * Not all failures are treated as errors. See the comment on + * JS::ObjectOpResult in js/public/Class.h. + * + * Implements: ES6 [[PreventExtensions]] internal method. + */ +extern JS_PUBLIC_API bool JS_PreventExtensions(JSContext* cx, + JS::HandleObject obj, + JS::ObjectOpResult& result); + +/** + * Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt + * to modify it will fail. If an error occurs during the attempt, return false + * (with a pending exception set, depending upon the nature of the error). If + * no error occurs, return true with |*succeeded| set to indicate whether the + * attempt successfully made the [[Prototype]] immutable. + * + * This is a nonstandard internal method. + */ +extern JS_PUBLIC_API bool JS_SetImmutablePrototype(JSContext* cx, + JS::HandleObject obj, + bool* succeeded); + +/** + * Get a description of one of obj's own properties. If no such property exists + * on obj, return true with desc.object() set to null. + * + * Implements: ES6 [[GetOwnProperty]] internal method. + */ +extern JS_PUBLIC_API bool JS_GetOwnPropertyDescriptorById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandle<JS::PropertyDescriptor> desc); + +extern JS_PUBLIC_API bool JS_GetOwnPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char* name, + JS::MutableHandle<JS::PropertyDescriptor> desc); + +extern JS_PUBLIC_API bool JS_GetOwnUCPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::MutableHandle<JS::PropertyDescriptor> desc); + +/** + * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain + * if no own property is found directly on obj. The object on which the + * property is found is returned in desc.object(). If the property is not found + * on the prototype chain, this returns true with desc.object() set to null. + */ +extern JS_PUBLIC_API bool JS_GetPropertyDescriptorById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::MutableHandle<JS::PropertyDescriptor> desc); + +extern JS_PUBLIC_API bool JS_GetPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char* name, + JS::MutableHandle<JS::PropertyDescriptor> desc); + +extern JS_PUBLIC_API bool JS_GetUCPropertyDescriptor( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::MutableHandle<JS::PropertyDescriptor> desc); + +/** + * Define a property on obj. + * + * This function uses JS::ObjectOpResult to indicate conditions that ES6 + * specifies as non-error failures. This is inconvenient at best, so use this + * function only if you are implementing a proxy handler's defineProperty() + * method. For all other purposes, use one of the many DefineProperty functions + * below that throw an exception in all failure cases. + * + * Implements: ES6 [[DefineOwnProperty]] internal method. + */ +extern JS_PUBLIC_API bool JS_DefinePropertyById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result); + +/** + * Define a property on obj, throwing a TypeError if the attempt fails. + * This is the C++ equivalent of `Object.defineProperty(obj, id, desc)`. + */ +extern JS_PUBLIC_API bool JS_DefinePropertyById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::Handle<JS::PropertyDescriptor> desc); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleValue value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, JSNative getter, + JSNative setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, + JS::HandleObject getter, JS::HandleObject setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleObject value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleString value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefinePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, double value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::HandleValue value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, JSNative getter, + JSNative setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::HandleObject getter, + JS::HandleObject setter, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::HandleObject value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::HandleString value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineProperty(JSContext* cx, JS::HandleObject obj, + const char* name, double value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& result); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::Handle<JS::PropertyDescriptor> desc); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleValue value, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleObject getter, JS::HandleObject setter, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleObject value, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty( + JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, + JS::HandleString value, unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, double value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::HandleValue value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::HandleObject getter, + JS::HandleObject setter, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::HandleObject value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::HandleString value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, int32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, uint32_t value, + unsigned attrs); + +extern JS_PUBLIC_API bool JS_DefineElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, double value, + unsigned attrs); + +/** + * Compute the expression `id in obj`. + * + * If obj has an own or inherited property obj[id], set *foundp = true and + * return true. If not, set *foundp = false and return true. On error, return + * false with an exception pending. + * + * Implements: ES6 [[Has]] internal method. + */ +extern JS_PUBLIC_API bool JS_HasPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, bool* foundp); + +extern JS_PUBLIC_API bool JS_HasProperty(JSContext* cx, JS::HandleObject obj, + const char* name, bool* foundp); + +extern JS_PUBLIC_API bool JS_HasUCProperty(JSContext* cx, JS::HandleObject obj, + const char16_t* name, size_t namelen, + bool* vp); + +extern JS_PUBLIC_API bool JS_HasElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, bool* foundp); + +/** + * Determine whether obj has an own property with the key `id`. + * + * Implements: ES6 7.3.11 HasOwnProperty(O, P). + */ +extern JS_PUBLIC_API bool JS_HasOwnPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, bool* foundp); + +extern JS_PUBLIC_API bool JS_HasOwnProperty(JSContext* cx, JS::HandleObject obj, + const char* name, bool* foundp); + +/** + * Get the value of the property `obj[id]`, or undefined if no such property + * exists. This is the C++ equivalent of `vp = Reflect.get(obj, id, receiver)`. + * + * Most callers don't need the `receiver` argument. Consider using + * JS_GetProperty instead. (But if you're implementing a proxy handler's set() + * method, it's often correct to call this function and pass the receiver + * through.) + * + * Implements: ES6 [[Get]] internal method. + */ +extern JS_PUBLIC_API bool JS_ForwardGetPropertyTo(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleValue receiver, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_ForwardGetElementTo(JSContext* cx, + JS::HandleObject obj, + uint32_t index, + JS::HandleObject receiver, + JS::MutableHandleValue vp); + +/** + * Get the value of the property `obj[id]`, or undefined if no such property + * exists. The result is stored in vp. + * + * Implements: ES6 7.3.1 Get(O, P). + */ +extern JS_PUBLIC_API bool JS_GetPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_GetProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_GetUCProperty(JSContext* cx, JS::HandleObject obj, + const char16_t* name, size_t namelen, + JS::MutableHandleValue vp); + +extern JS_PUBLIC_API bool JS_GetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::MutableHandleValue vp); + +/** + * Perform the same property assignment as `Reflect.set(obj, id, v, receiver)`. + * + * This function has a `receiver` argument that most callers don't need. + * Consider using JS_SetProperty instead. + * + * Implements: ES6 [[Set]] internal method. + */ +extern JS_PUBLIC_API bool JS_ForwardSetPropertyTo( + JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, + JS::HandleValue receiver, JS::ObjectOpResult& result); + +/** + * Perform the assignment `obj[id] = v`. + * + * This function performs non-strict assignment, so if the property is + * read-only, nothing happens and no error is thrown. + */ +extern JS_PUBLIC_API bool JS_SetPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::HandleValue v); + +extern JS_PUBLIC_API bool JS_SetProperty(JSContext* cx, JS::HandleObject obj, + const char* name, JS::HandleValue v); + +extern JS_PUBLIC_API bool JS_SetUCProperty(JSContext* cx, JS::HandleObject obj, + const char16_t* name, size_t namelen, + JS::HandleValue v); + +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JS::HandleValue v); + +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JS::HandleObject v); + +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, JS::HandleString v); + +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, int32_t v); + +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, uint32_t v); + +extern JS_PUBLIC_API bool JS_SetElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, double v); + +/** + * Delete a property. This is the C++ equivalent of + * `result = Reflect.deleteProperty(obj, id)`. + * + * This function has a `result` out parameter that most callers don't need. + * Unless you can pass through an ObjectOpResult provided by your caller, it's + * probably best to use the JS_DeletePropertyById signature with just 3 + * arguments. + * + * Implements: ES6 [[Delete]] internal method. + */ +extern JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, + const char* name, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API bool JS_DeleteUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, + JS::ObjectOpResult& result); + +extern JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::HandleObject obj, + uint32_t index, + JS::ObjectOpResult& result); + +/** + * Delete a property, ignoring strict failures. This is the C++ equivalent of + * the JS `delete obj[id]` in non-strict mode code. + */ +extern JS_PUBLIC_API bool JS_DeletePropertyById(JSContext* cx, + JS::HandleObject obj, jsid id); + +extern JS_PUBLIC_API bool JS_DeleteProperty(JSContext* cx, JS::HandleObject obj, + const char* name); + +extern JS_PUBLIC_API bool JS_DeleteElement(JSContext* cx, JS::HandleObject obj, + uint32_t index); + +/** + * Get an array of the non-symbol enumerable properties of obj. + * This function is roughly equivalent to: + * + * var result = []; + * for (key in obj) { + * result.push(key); + * } + * return result; + * + * This is the closest thing we currently have to the ES6 [[Enumerate]] + * internal method. + * + * The array of ids returned by JS_Enumerate must be rooted to protect its + * contents from garbage collection. Use JS::Rooted<JS::IdVector>. + */ +extern JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, JS::HandleObject obj, + JS::MutableHandle<JS::IdVector> props); + +/** + * Equivalent to `Object.assign(target, src)`: Copies the properties from the + * `src` object (which must not be null) to `target` (which also must not be + * null). + */ +extern JS_PUBLIC_API bool JS_AssignObject(JSContext* cx, + JS::HandleObject target, + JS::HandleObject src); + +/* + * API for determining callability and constructability. [[Call]] and + * [[Construct]] are internal methods that aren't present on all objects, so it + * is useful to ask if they are there or not. The standard itself asks these + * questions routinely. + */ +namespace JS { + +/** + * Return true if the given object is callable. In ES6 terms, an object is + * callable if it has a [[Call]] internal method. + * + * Implements: ES6 7.2.3 IsCallable(argument). + * + * Functions are callable. A scripted proxy or wrapper is callable if its + * target is callable. Most other objects aren't callable. + */ +extern JS_PUBLIC_API bool IsCallable(JSObject* obj); + +/** + * Return true if the given object is a constructor. In ES6 terms, an object is + * a constructor if it has a [[Construct]] internal method. The expression + * `new obj()` throws a TypeError if obj is not a constructor. + * + * Implements: ES6 7.2.4 IsConstructor(argument). + * + * JS functions and classes are constructors. Arrow functions and most builtin + * functions are not. A scripted proxy or wrapper is a constructor if its + * target is a constructor. + */ +extern JS_PUBLIC_API bool IsConstructor(JSObject* obj); + +} /* namespace JS */ + +/** + * Call a function, passing a this-value and arguments. This is the C++ + * equivalent of `rval = Reflect.apply(fun, obj, args)`. + * + * Implements: ES6 7.3.12 Call(F, V, [argumentsList]). + * Use this function to invoke the [[Call]] internal method. + */ +extern JS_PUBLIC_API bool JS_CallFunctionValue(JSContext* cx, + JS::HandleObject obj, + JS::HandleValue fval, + const JS::HandleValueArray& args, + JS::MutableHandleValue rval); + +extern JS_PUBLIC_API bool JS_CallFunction(JSContext* cx, JS::HandleObject obj, + JS::HandleFunction fun, + const JS::HandleValueArray& args, + JS::MutableHandleValue rval); + +/** + * Perform the method call `rval = obj[name](args)`. + */ +extern JS_PUBLIC_API bool JS_CallFunctionName(JSContext* cx, + JS::HandleObject obj, + const char* name, + const JS::HandleValueArray& args, + JS::MutableHandleValue rval); + +namespace JS { + +static inline bool Call(JSContext* cx, JS::HandleObject thisObj, + JS::HandleFunction fun, + const JS::HandleValueArray& args, + MutableHandleValue rval) { + return !!JS_CallFunction(cx, thisObj, fun, args, rval); +} + +static inline bool Call(JSContext* cx, JS::HandleObject thisObj, + JS::HandleValue fun, const JS::HandleValueArray& args, + MutableHandleValue rval) { + return !!JS_CallFunctionValue(cx, thisObj, fun, args, rval); +} + +static inline bool Call(JSContext* cx, JS::HandleObject thisObj, + const char* name, const JS::HandleValueArray& args, + MutableHandleValue rval) { + return !!JS_CallFunctionName(cx, thisObj, name, args, rval); +} + +extern JS_PUBLIC_API bool Call(JSContext* cx, JS::HandleValue thisv, + JS::HandleValue fun, + const JS::HandleValueArray& args, + MutableHandleValue rval); + +static inline bool Call(JSContext* cx, JS::HandleValue thisv, + JS::HandleObject funObj, + const JS::HandleValueArray& args, + MutableHandleValue rval) { + MOZ_ASSERT(funObj); + JS::RootedValue fun(cx, JS::ObjectValue(*funObj)); + return Call(cx, thisv, fun, args, rval); +} + +/** + * Invoke a constructor. This is the C++ equivalent of + * `rval = Reflect.construct(fun, args, newTarget)`. + * + * JS::Construct() takes a `newTarget` argument that most callers don't need. + * Consider using the four-argument Construct signature instead. (But if you're + * implementing a subclass or a proxy handler's construct() method, this is the + * right function to call.) + * + * Implements: ES6 7.3.13 Construct(F, [argumentsList], [newTarget]). + * Use this function to invoke the [[Construct]] internal method. + */ +extern JS_PUBLIC_API bool Construct(JSContext* cx, JS::HandleValue fun, + HandleObject newTarget, + const JS::HandleValueArray& args, + MutableHandleObject objp); + +/** + * Invoke a constructor. This is the C++ equivalent of + * `rval = new fun(...args)`. + * + * Implements: ES6 7.3.13 Construct(F, [argumentsList], [newTarget]), when + * newTarget is omitted. + */ +extern JS_PUBLIC_API bool Construct(JSContext* cx, JS::HandleValue fun, + const JS::HandleValueArray& args, + MutableHandleObject objp); + +} /* namespace JS */ + +/** + * Invoke a constructor, like the JS expression `new ctor(...args)`. Returns + * the new object, or null on error. + */ +extern JS_PUBLIC_API JSObject* JS_New(JSContext* cx, JS::HandleObject ctor, + const JS::HandleValueArray& args); + +/*** Other property-defining functions **************************************/ + +extern JS_PUBLIC_API JSObject* JS_DefineObject(JSContext* cx, + JS::HandleObject obj, + const char* name, + const JSClass* clasp = nullptr, + unsigned attrs = 0); + +extern JS_PUBLIC_API bool JS_DefineProperties(JSContext* cx, + JS::HandleObject obj, + const JSPropertySpec* ps); + +/* * */ + +extern JS_PUBLIC_API bool JS_AlreadyHasOwnPropertyById(JSContext* cx, + JS::HandleObject obj, + JS::HandleId id, + bool* foundp); + +extern JS_PUBLIC_API bool JS_AlreadyHasOwnProperty(JSContext* cx, + JS::HandleObject obj, + const char* name, + bool* foundp); + +extern JS_PUBLIC_API bool JS_AlreadyHasOwnUCProperty(JSContext* cx, + JS::HandleObject obj, + const char16_t* name, + size_t namelen, + bool* foundp); + +extern JS_PUBLIC_API bool JS_AlreadyHasOwnElement(JSContext* cx, + JS::HandleObject obj, + uint32_t index, bool* foundp); + +namespace JS { + +/** + * On success, returns true, setting |*isMap| to true if |obj| is a Map object + * or a wrapper around one, or to false if not. Returns false on failure. + * + * This method returns true with |*isMap == false| when passed an ES6 proxy + * whose target is a Map, or when passed a revoked proxy. + */ +extern JS_PUBLIC_API bool IsMapObject(JSContext* cx, JS::HandleObject obj, + bool* isMap); + +/** + * On success, returns true, setting |*isSet| to true if |obj| is a Set object + * or a wrapper around one, or to false if not. Returns false on failure. + * + * This method returns true with |*isSet == false| when passed an ES6 proxy + * whose target is a Set, or when passed a revoked proxy. + */ +extern JS_PUBLIC_API bool IsSetObject(JSContext* cx, JS::HandleObject obj, + bool* isSet); + +} /* namespace JS */ + +/** + * Assign 'undefined' to all of the object's non-reserved slots. Note: this is + * done for all slots, regardless of the associated property descriptor. + */ +JS_PUBLIC_API void JS_SetAllNonReservedSlotsToUndefined(JS::HandleObject obj); + +extern JS_PUBLIC_API void JS_SetReservedSlot(JSObject* obj, uint32_t index, + const JS::Value& v); + +extern JS_PUBLIC_API void JS_InitReservedSlot(JSObject* obj, uint32_t index, + void* ptr, size_t nbytes, + JS::MemoryUse use); + +template <typename T> +void JS_InitReservedSlot(JSObject* obj, uint32_t index, T* ptr, + JS::MemoryUse use) { + JS_InitReservedSlot(obj, index, ptr, sizeof(T), use); +} + +extern JS_PUBLIC_API void JS_InitPrivate(JSObject* obj, void* data, + size_t nbytes, JS::MemoryUse use); + +/************************************************************************/ + +/* native that can be called as a ctor */ +static constexpr unsigned JSFUN_CONSTRUCTOR = 0x400; + +/* | of all the JSFUN_* flags */ +static constexpr unsigned JSFUN_FLAGS_MASK = 0x400; + +static_assert((JSPROP_FLAGS_MASK & JSFUN_FLAGS_MASK) == 0, + "JSFUN_* flags do not overlap JSPROP_* flags, because bits from " + "the two flag-sets appear in the same flag in some APIs"); + +/* + * Functions and scripts. + */ +extern JS_PUBLIC_API JSFunction* JS_NewFunction(JSContext* cx, JSNative call, + unsigned nargs, unsigned flags, + const char* name); + +namespace JS { + +extern JS_PUBLIC_API JSFunction* GetSelfHostedFunction( + JSContext* cx, const char* selfHostedName, HandleId id, unsigned nargs); + +/** + * Create a new function based on the given JSFunctionSpec, *fs. + * id is the result of a successful call to + * `PropertySpecNameToId(cx, fs->name, &id)` or + `PropertySpecNameToPermanentId(cx, fs->name, &id)`. + * + * Unlike JS_DefineFunctions, this does not treat fs as an array. + * *fs must not be JS_FS_END. + */ +extern JS_PUBLIC_API JSFunction* NewFunctionFromSpec(JSContext* cx, + const JSFunctionSpec* fs, + HandleId id); + +/** + * Same as above, but without an id arg, for callers who don't have + * the id already. + */ +extern JS_PUBLIC_API JSFunction* NewFunctionFromSpec(JSContext* cx, + const JSFunctionSpec* fs); + +} /* namespace JS */ + +extern JS_PUBLIC_API JSObject* JS_GetFunctionObject(JSFunction* fun); + +/** + * Return the function's identifier as a JSString, or null if fun is unnamed. + * The returned string lives as long as fun, so you don't need to root a saved + * reference to it if fun is well-connected or rooted, and provided you bound + * the use of the saved reference by fun's lifetime. + */ +extern JS_PUBLIC_API JSString* JS_GetFunctionId(JSFunction* fun); + +/** + * Return a function's display name. This is the defined name if one was given + * where the function was defined, or it could be an inferred name by the JS + * engine in the case that the function was defined to be anonymous. This can + * still return nullptr if a useful display name could not be inferred. The + * same restrictions on rooting as those in JS_GetFunctionId apply. + */ +extern JS_PUBLIC_API JSString* JS_GetFunctionDisplayId(JSFunction* fun); + +/* + * Return the arity of fun, which includes default parameters and rest + * parameter. This can be used as `nargs` parameter for other functions. + */ +extern JS_PUBLIC_API uint16_t JS_GetFunctionArity(JSFunction* fun); + +/* + * Return the length of fun, which is the original value of .length property. + */ +JS_PUBLIC_API bool JS_GetFunctionLength(JSContext* cx, JS::HandleFunction fun, + uint16_t* length); + +/** + * Infallible predicate to test whether obj is a function object (faster than + * comparing obj's class name to "Function", but equivalent unless someone has + * overwritten the "Function" identifier with a different constructor and then + * created instances using that constructor that might be passed in as obj). + */ +extern JS_PUBLIC_API bool JS_ObjectIsFunction(JSObject* obj); + +extern JS_PUBLIC_API bool JS_IsNativeFunction(JSObject* funobj, JSNative call); + +/** Return whether the given function is a valid constructor. */ +extern JS_PUBLIC_API bool JS_IsConstructor(JSFunction* fun); + +extern JS_PUBLIC_API bool JS_DefineFunctions(JSContext* cx, + JS::Handle<JSObject*> obj, + const JSFunctionSpec* fs); + +extern JS_PUBLIC_API JSFunction* JS_DefineFunction( + JSContext* cx, JS::Handle<JSObject*> obj, const char* name, JSNative call, + unsigned nargs, unsigned attrs); + +extern JS_PUBLIC_API JSFunction* JS_DefineUCFunction( + JSContext* cx, JS::Handle<JSObject*> obj, const char16_t* name, + size_t namelen, JSNative call, unsigned nargs, unsigned attrs); + +extern JS_PUBLIC_API JSFunction* JS_DefineFunctionById( + JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, + JSNative call, unsigned nargs, unsigned attrs); + +extern JS_PUBLIC_API bool JS_IsFunctionBound(JSFunction* fun); + +extern JS_PUBLIC_API JSObject* JS_GetBoundFunctionTarget(JSFunction* fun); + +extern JS_PUBLIC_API JSObject* JS_GetGlobalFromScript(JSScript* script); + +extern JS_PUBLIC_API const char* JS_GetScriptFilename(JSScript* script); + +extern JS_PUBLIC_API unsigned JS_GetScriptBaseLineNumber(JSContext* cx, + JSScript* script); + +extern JS_PUBLIC_API JSScript* JS_GetFunctionScript(JSContext* cx, + JS::HandleFunction fun); + +extern JS_PUBLIC_API JSString* JS_DecompileScript(JSContext* cx, + JS::Handle<JSScript*> script); + +extern JS_PUBLIC_API JSString* JS_DecompileFunction( + JSContext* cx, JS::Handle<JSFunction*> fun); + +namespace JS { + +/** + * Set a private value associated with a script. Note that this value is shared + * by all nested scripts compiled from a single source file. + */ +extern JS_PUBLIC_API void SetScriptPrivate(JSScript* script, + const JS::Value& value); + +/** + * Get the private value associated with a script. Note that this value is + * shared by all nested scripts compiled from a single source file. + */ +extern JS_PUBLIC_API JS::Value GetScriptPrivate(JSScript* script); + +/* + * Return the private value associated with currently executing script or + * module, or undefined if there is no such script. + */ +extern JS_PUBLIC_API JS::Value GetScriptedCallerPrivate(JSContext* cx); + +/** + * Hooks called when references to a script private value are created or + * destroyed. This allows use of a reference counted object as the + * script private. + */ +using ScriptPrivateReferenceHook = void (*)(const JS::Value&); + +/** + * Set the script private finalize hook for the runtime to the given function. + */ +extern JS_PUBLIC_API void SetScriptPrivateReferenceHooks( + JSRuntime* rt, ScriptPrivateReferenceHook addRefHook, + ScriptPrivateReferenceHook releaseHook); + +} /* namespace JS */ + +extern JS_PUBLIC_API bool JS_CheckForInterrupt(JSContext* cx); + +/* + * These functions allow setting an interrupt callback that will be called + * from the JS thread some time after any thread triggered the callback using + * JS_RequestInterruptCallback(cx). + * + * To schedule the GC and for other activities the engine internally triggers + * interrupt callbacks. The embedding should thus not rely on callbacks being + * triggered through the external API only. + * + * Important note: Additional callbacks can occur inside the callback handler + * if it re-enters the JS engine. The embedding must ensure that the callback + * is disconnected before attempting such re-entry. + */ +extern JS_PUBLIC_API bool JS_AddInterruptCallback(JSContext* cx, + JSInterruptCallback callback); + +extern JS_PUBLIC_API bool JS_DisableInterruptCallback(JSContext* cx); + +extern JS_PUBLIC_API void JS_ResetInterruptCallback(JSContext* cx, bool enable); + +extern JS_PUBLIC_API void JS_RequestInterruptCallback(JSContext* cx); + +extern JS_PUBLIC_API void JS_RequestInterruptCallbackCanWait(JSContext* cx); + +namespace JS { + +/** + * The ConsumeStreamCallback is called from an active JSContext, passing a + * StreamConsumer that wishes to consume the given host object as a stream of + * bytes with the given MIME type. On failure, the embedding must report the + * appropriate error on 'cx'. On success, the embedding must call + * consumer->consumeChunk() repeatedly on any thread until exactly one of: + * - consumeChunk() returns false + * - the embedding calls consumer->streamEnd() + * - the embedding calls consumer->streamError() + * before JS_DestroyContext(cx) or JS::ShutdownAsyncTasks(cx) is called. + * + * Note: consumeChunk(), streamEnd() and streamError() may be called + * synchronously by ConsumeStreamCallback. + * + * When streamEnd() is called, the embedding may optionally pass an + * OptimizedEncodingListener*, indicating that there is a cache entry associated + * with this stream that can store an optimized encoding of the bytes that were + * just streamed at some point in the future by having SpiderMonkey call + * storeOptimizedEncoding(). Until the optimized encoding is ready, SpiderMonkey + * will hold an outstanding refcount to keep the listener alive. + * + * After storeOptimizedEncoding() is called, on cache hit, the embedding + * may call consumeOptimizedEncoding() instead of consumeChunk()/streamEnd(). + * The embedding must ensure that the GetOptimizedEncodingBuildId() (see + * js/BuildId.h) at the time when an optimized encoding is created is the same + * as when it is later consumed. + */ + +using OptimizedEncodingBytes = js::Vector<uint8_t, 0, js::SystemAllocPolicy>; +using UniqueOptimizedEncodingBytes = js::UniquePtr<OptimizedEncodingBytes>; + +class OptimizedEncodingListener { + protected: + virtual ~OptimizedEncodingListener() = default; + + public: + // SpiderMonkey will hold an outstanding reference count as long as it holds + // a pointer to OptimizedEncodingListener. + virtual MozExternalRefCountType MOZ_XPCOM_ABI AddRef() = 0; + virtual MozExternalRefCountType MOZ_XPCOM_ABI Release() = 0; + + // SpiderMonkey may optionally call storeOptimizedEncoding() after it has + // finished processing a streamed resource. + virtual void storeOptimizedEncoding(UniqueOptimizedEncodingBytes bytes) = 0; +}; + +class JS_PUBLIC_API StreamConsumer { + protected: + // AsyncStreamConsumers are created and destroyed by SpiderMonkey. + StreamConsumer() = default; + virtual ~StreamConsumer() = default; + + public: + // Called by the embedding as each chunk of bytes becomes available. + // If this function returns 'false', the stream must drop all pointers to + // this StreamConsumer. + virtual bool consumeChunk(const uint8_t* begin, size_t length) = 0; + + // Called by the embedding when the stream reaches end-of-file, passing the + // listener described above. + virtual void streamEnd(OptimizedEncodingListener* listener = nullptr) = 0; + + // Called by the embedding when there is an error during streaming. The + // given error code should be passed to the ReportStreamErrorCallback on the + // main thread to produce the semantically-correct rejection value. + virtual void streamError(size_t errorCode) = 0; + + // Called by the embedding *instead of* consumeChunk()/streamEnd() if an + // optimized encoding is available from a previous streaming of the same + // contents with the same optimized build id. + virtual void consumeOptimizedEncoding(const uint8_t* begin, + size_t length) = 0; + + // Provides optional stream attributes such as base or source mapping URLs. + // Necessarily called before consumeChunk(), streamEnd(), streamError() or + // consumeOptimizedEncoding(). The caller retains ownership of the strings. + virtual void noteResponseURLs(const char* maybeUrl, + const char* maybeSourceMapUrl) = 0; +}; + +enum class MimeType { Wasm }; + +using ConsumeStreamCallback = bool (*)(JSContext*, JS::HandleObject, MimeType, + StreamConsumer*); + +using ReportStreamErrorCallback = void (*)(JSContext*, size_t); + +extern JS_PUBLIC_API void InitConsumeStreamCallback( + JSContext* cx, ConsumeStreamCallback consume, + ReportStreamErrorCallback report); + +/** + * Supply an alternative stack to incorporate into captured SavedFrame + * backtraces as the imputed caller of asynchronous JavaScript calls, like async + * function resumptions and DOM callbacks. + * + * When one async function awaits the result of another, it's natural to think + * of that as a sort of function call: just as execution resumes from an + * ordinary call expression when the callee returns, with the return value + * providing the value of the call expression, execution resumes from an 'await' + * expression after the awaited asynchronous function call returns, passing the + * return value along. + * + * Call the two async functions in such a situation the 'awaiter' and the + * 'awaitee'. + * + * As an async function, the awaitee contains 'await' expressions of its own. + * Whenever it executes after its first 'await', there are never any actual + * frames on the JavaScript stack under it; its awaiter is certainly not there. + * An await expression's continuation is invoked as a promise callback, and + * those are always called directly from the event loop in their own microtick. + * (Ignore unusual cases like nested event loops.) + * + * But because await expressions bear such a strong resemblance to calls (and + * deliberately so!), it would be unhelpful for stacks captured within the + * awaitee to be empty; instead, they should present the awaiter as the caller. + * + * The AutoSetAsyncStackForNewCalls RAII class supplies a SavedFrame stack to + * treat as the caller of any JavaScript invocations that occur within its + * lifetime. Any SavedFrame stack captured during such an invocation uses the + * SavedFrame passed to the constructor's 'stack' parameter as the 'asyncParent' + * property of the SavedFrame for the invocation's oldest frame. Its 'parent' + * property will be null, so stack-walking code can distinguish this + * awaiter/awaitee transition from an ordinary caller/callee transition. + * + * The constructor's 'asyncCause' parameter supplies a string explaining what + * sort of asynchronous call caused 'stack' to be spliced into the backtrace; + * for example, async function resumptions use the string "async". This appears + * as the 'asyncCause' property of the 'asyncParent' SavedFrame. + * + * Async callers are distinguished in the string form of a SavedFrame chain by + * including the 'asyncCause' string in the frame. It appears before the + * function name, with the two separated by a '*'. + * + * Note that, as each compartment has its own set of SavedFrames, the + * 'asyncParent' may actually point to a copy of 'stack', rather than the exact + * SavedFrame object passed. + * + * The youngest frame of 'stack' is not mutated to take the asyncCause string as + * its 'asyncCause' property; SavedFrame objects are immutable. Rather, a fresh + * clone of the frame is created with the needed 'asyncCause' property. + * + * The 'kind' argument specifies how aggressively 'stack' supplants any + * JavaScript frames older than this AutoSetAsyncStackForNewCalls object. If + * 'kind' is 'EXPLICIT', then all captured SavedFrame chains take on 'stack' as + * their 'asyncParent' where the chain crosses this object's scope. If 'kind' is + * 'IMPLICIT', then 'stack' is only included in captured chains if there are no + * other JavaScript frames on the stack --- that is, only if the stack would + * otherwise end at that point. + * + * AutoSetAsyncStackForNewCalls affects only SavedFrame chains; it does not + * affect Debugger.Frame or js::FrameIter. SavedFrame chains are used for + * Error.stack, allocation profiling, Promise debugging, and so on. + * + * See also `js/src/doc/SavedFrame/SavedFrame.md` for documentation on async + * stack frames. + */ +class MOZ_STACK_CLASS JS_PUBLIC_API AutoSetAsyncStackForNewCalls { + JSContext* cx; + RootedObject oldAsyncStack; + const char* oldAsyncCause; + bool oldAsyncCallIsExplicit; + + public: + enum class AsyncCallKind { + // The ordinary kind of call, where we may apply an async + // parent if there is no ordinary parent. + IMPLICIT, + // An explicit async parent, e.g., callFunctionWithAsyncStack, + // where we always want to override any ordinary parent. + EXPLICIT + }; + + // The stack parameter cannot be null by design, because it would be + // ambiguous whether that would clear any scheduled async stack and make the + // normal stack reappear in the new call, or just keep the async stack + // already scheduled for the new call, if any. + // + // asyncCause is owned by the caller and its lifetime must outlive the + // lifetime of the AutoSetAsyncStackForNewCalls object. It is strongly + // encouraged that asyncCause be a string constant or similar statically + // allocated string. + AutoSetAsyncStackForNewCalls(JSContext* cx, HandleObject stack, + const char* asyncCause, + AsyncCallKind kind = AsyncCallKind::IMPLICIT); + ~AutoSetAsyncStackForNewCalls(); +}; + +} // namespace JS + +/************************************************************************/ + +/* + * Strings. + * + * NB: JS_NewUCString takes ownership of bytes on success, avoiding a copy; + * but on error (signified by null return), it leaves chars owned by the + * caller. So the caller must free bytes in the error case, if it has no use + * for them. In contrast, all the JS_New*StringCopy* functions do not take + * ownership of the character memory passed to them -- they copy it. + */ +extern JS_PUBLIC_API JSString* JS_NewStringCopyN(JSContext* cx, const char* s, + size_t n); + +extern JS_PUBLIC_API JSString* JS_NewStringCopyZ(JSContext* cx, const char* s); + +extern JS_PUBLIC_API JSString* JS_NewStringCopyUTF8Z( + JSContext* cx, const JS::ConstUTF8CharsZ s); + +extern JS_PUBLIC_API JSString* JS_NewStringCopyUTF8N(JSContext* cx, + const JS::UTF8Chars s); + +extern JS_PUBLIC_API JSString* JS_AtomizeAndPinJSString(JSContext* cx, + JS::HandleString str); + +extern JS_PUBLIC_API JSString* JS_AtomizeStringN(JSContext* cx, const char* s, + size_t length); + +extern JS_PUBLIC_API JSString* JS_AtomizeString(JSContext* cx, const char* s); + +extern JS_PUBLIC_API JSString* JS_AtomizeAndPinStringN(JSContext* cx, + const char* s, + size_t length); + +extern JS_PUBLIC_API JSString* JS_AtomizeAndPinString(JSContext* cx, + const char* s); + +extern JS_PUBLIC_API JSString* JS_NewLatin1String( + JSContext* cx, js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> chars, + size_t length); + +extern JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx, + JS::UniqueTwoByteChars chars, + size_t length); + +extern JS_PUBLIC_API JSString* JS_NewUCStringDontDeflate( + JSContext* cx, JS::UniqueTwoByteChars chars, size_t length); + +extern JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx, + const char16_t* s, size_t n); + +extern JS_PUBLIC_API JSString* JS_NewUCStringCopyZ(JSContext* cx, + const char16_t* s); + +extern JS_PUBLIC_API JSString* JS_AtomizeUCStringN(JSContext* cx, + const char16_t* s, + size_t length); + +extern JS_PUBLIC_API JSString* JS_AtomizeUCString(JSContext* cx, + const char16_t* s); + +extern JS_PUBLIC_API JSString* JS_AtomizeAndPinUCStringN(JSContext* cx, + const char16_t* s, + size_t length); + +extern JS_PUBLIC_API JSString* JS_AtomizeAndPinUCString(JSContext* cx, + const char16_t* s); + +extern JS_PUBLIC_API bool JS_CompareStrings(JSContext* cx, JSString* str1, + JSString* str2, int32_t* result); + +extern JS_PUBLIC_API MOZ_MUST_USE bool JS_StringEqualsAscii( + JSContext* cx, JSString* str, const char* asciiBytes, bool* match); + +// Same as above, but when the length of asciiBytes (excluding the +// trailing null, if any) is known. +extern JS_PUBLIC_API MOZ_MUST_USE bool JS_StringEqualsAscii( + JSContext* cx, JSString* str, const char* asciiBytes, size_t length, + bool* match); + +template <size_t N> +MOZ_MUST_USE bool JS_StringEqualsLiteral(JSContext* cx, JSString* str, + const char (&asciiBytes)[N], + bool* match) { + MOZ_ASSERT(asciiBytes[N - 1] == '\0'); + return JS_StringEqualsAscii(cx, str, asciiBytes, N - 1, match); +} + +extern JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer, + size_t size, JSString* str, + char quote); + +/* + * Extracting string characters and length. + * + * While getting the length of a string is infallible, getting the chars can + * fail. As indicated by the lack of a JSContext parameter, there are two + * special cases where getting the chars is infallible: + * + * The first case is for strings that have been atomized, e.g. directly by + * JS_AtomizeAndPinString or implicitly because it is stored in a jsid. + * + * The second case is "linear" strings that have been explicitly prepared in a + * fallible context by JS_EnsureLinearString. To catch errors, a separate opaque + * JSLinearString type is returned by JS_EnsureLinearString and expected by + * JS_Get{Latin1,TwoByte}StringCharsAndLength. Note, though, that this is purely + * a syntactic distinction: the input and output of JS_EnsureLinearString are + * the same actual GC-thing. If a JSString is known to be linear, + * JS_ASSERT_STRING_IS_LINEAR can be used to make a debug-checked cast. Example: + * + * // In a fallible context. + * JSLinearString* lstr = JS_EnsureLinearString(cx, str); + * if (!lstr) { + * return false; + * } + * MOZ_ASSERT(lstr == JS_ASSERT_STRING_IS_LINEAR(str)); + * + * // In an infallible context, for the same 'str'. + * AutoCheckCannotGC nogc; + * const char16_t* chars = JS::GetTwoByteLinearStringChars(nogc, lstr) + * MOZ_ASSERT(chars); + * + * Note: JS strings (including linear strings and atoms) are not + * null-terminated! + * + * Additionally, string characters are stored as either Latin1Char (8-bit) + * or char16_t (16-bit). Clients can use JS::StringHasLatin1Chars and can then + * call either the Latin1* or TwoByte* functions. Some functions like + * JS_CopyStringChars and JS_GetStringCharAt accept both Latin1 and TwoByte + * strings. + */ + +extern JS_PUBLIC_API size_t JS_GetStringLength(JSString* str); + +extern JS_PUBLIC_API bool JS_StringIsLinear(JSString* str); + +extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength( + JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, + size_t* length); + +extern JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength( + JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, + size_t* length); + +extern JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str, + size_t index, char16_t* res); + +extern JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars( + JSString* str); + +extern JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx, + mozilla::Range<char16_t> dest, + JSString* str); + +/** + * Copies the string's characters to a null-terminated char16_t buffer. + * + * Returns nullptr on OOM. + */ +extern JS_PUBLIC_API JS::UniqueTwoByteChars JS_CopyStringCharsZ(JSContext* cx, + JSString* str); + +extern JS_PUBLIC_API JSLinearString* JS_EnsureLinearString(JSContext* cx, + JSString* str); + +static MOZ_ALWAYS_INLINE JSLinearString* JSID_TO_LINEAR_STRING(jsid id) { + MOZ_ASSERT(JSID_IS_STRING(id)); + return reinterpret_cast<JSLinearString*>(JSID_TO_STRING(id)); +} + +static MOZ_ALWAYS_INLINE JSLinearString* JS_ASSERT_STRING_IS_LINEAR( + JSString* str) { + MOZ_ASSERT(JS_StringIsLinear(str)); + return reinterpret_cast<JSLinearString*>(str); +} + +static MOZ_ALWAYS_INLINE JSString* JS_FORGET_STRING_LINEARNESS( + JSLinearString* str) { + return reinterpret_cast<JSString*>(str); +} + +/* + * Additional APIs that avoid fallibility when given a linear string. + */ + +extern JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str, + const char* asciiBytes); +extern JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str, + const char* asciiBytes, + size_t length); + +template <size_t N> +bool JS_LinearStringEqualsLiteral(JSLinearString* str, + const char (&asciiBytes)[N]) { + MOZ_ASSERT(asciiBytes[N - 1] == '\0'); + return JS_LinearStringEqualsAscii(str, asciiBytes, N - 1); +} + +extern JS_PUBLIC_API size_t JS_PutEscapedLinearString(char* buffer, size_t size, + JSLinearString* str, + char quote); + +/** + * Create a dependent string, i.e., a string that owns no character storage, + * but that refers to a slice of another string's chars. Dependent strings + * are mutable by definition, so the thread safety comments above apply. + */ +extern JS_PUBLIC_API JSString* JS_NewDependentString(JSContext* cx, + JS::HandleString str, + size_t start, + size_t length); + +/** + * Concatenate two strings, possibly resulting in a rope. + * See above for thread safety comments. + */ +extern JS_PUBLIC_API JSString* JS_ConcatStrings(JSContext* cx, + JS::HandleString left, + JS::HandleString right); + +/** + * For JS_DecodeBytes, set *dstlenp to the size of the destination buffer before + * the call; on return, *dstlenp contains the number of characters actually + * stored. To determine the necessary destination buffer size, make a sizing + * call that passes nullptr for dst. + * + * On errors, the functions report the error. In that case, *dstlenp contains + * the number of characters or bytes transferred so far. If cx is nullptr, no + * error is reported on failure, and the functions simply return false. + * + * NB: This function does not store an additional zero byte or char16_t after + * the transcoded string. + */ +JS_PUBLIC_API bool JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen, + char16_t* dst, size_t* dstlenp); + +/** + * Get number of bytes in the string encoding (without accounting for a + * terminating zero bytes. The function returns (size_t) -1 if the string + * can not be encoded into bytes and reports an error using cx accordingly. + */ +JS_PUBLIC_API size_t JS_GetStringEncodingLength(JSContext* cx, JSString* str); + +/** + * Encode string into a buffer. The function does not stores an additional + * zero byte. The function returns (size_t) -1 if the string can not be + * encoded into bytes with no error reported. Otherwise it returns the number + * of bytes that are necessary to encode the string. If that exceeds the + * length parameter, the string will be cut and only length bytes will be + * written into the buffer. + */ +MOZ_MUST_USE JS_PUBLIC_API bool JS_EncodeStringToBuffer(JSContext* cx, + JSString* str, + char* buffer, + size_t length); + +/** + * Encode as many scalar values of the string as UTF-8 as can fit + * into the caller-provided buffer replacing unpaired surrogates + * with the REPLACEMENT CHARACTER. + * + * If JS::StringHasLatin1Chars(str) returns true, the function + * is guaranteed to convert the entire string if + * buffer.Length() >= 2 * JS_GetStringLength(str). Otherwise, + * the function is guaranteed to convert the entire string if + * buffer.Length() >= 3 * JS_GetStringLength(str). + * + * This function does not alter the representation of |str| or + * any |JSString*| substring that is a constituent part of it. + * Returns mozilla::Nothing() on OOM, without reporting an error; + * some data may have been written to |buffer| when this happens. + * + * If there's no OOM, returns the number of code units read and + * the number of code units written. + * + * The semantics of this method match the semantics of + * TextEncoder.encodeInto(). + * + * The function does not store an additional zero byte. + */ +JS_PUBLIC_API mozilla::Maybe<mozilla::Tuple<size_t, size_t> > +JS_EncodeStringToUTF8BufferPartial(JSContext* cx, JSString* str, + mozilla::Span<char> buffer); + +namespace JS { + +JS_PUBLIC_API bool PropertySpecNameEqualsId(JSPropertySpec::Name name, + HandleId id); + +/** + * Create a jsid that does not need to be marked for GC. + * + * 'name' is a JSPropertySpec::name or JSFunctionSpec::name value. The + * resulting jsid, on success, is either an interned string or a well-known + * symbol; either way it is immune to GC so there is no need to visit *idp + * during GC marking. + */ +JS_PUBLIC_API bool PropertySpecNameToPermanentId(JSContext* cx, + JSPropertySpec::Name name, + jsid* idp); + +} /* namespace JS */ + +/************************************************************************/ + +/* + * Error reporting. + * + * There are four encoding variants for the error reporting API: + * UTF-8 + * JSAPI's default encoding for error handling. Use this when the encoding + * of the error message, format string, and arguments is UTF-8. + * ASCII + * Equivalent to UTF-8, but also asserts that the error message, format + * string, and arguments are all ASCII. Because ASCII is a subset of UTF-8, + * any use of this encoding variant *could* be replaced with use of the + * UTF-8 variant. This variant exists solely to double-check the + * developer's assumption that all these strings truly are ASCII, given that + * UTF-8 and ASCII strings regrettably have the same C++ type. + * UC = UTF-16 + * Use this when arguments are UTF-16. The format string must be UTF-8. + * Latin1 (planned to be removed) + * In this variant, all strings are interpreted byte-for-byte as the + * corresponding Unicode codepoint. This encoding may *safely* be used on + * any null-terminated string, regardless of its encoding. (You shouldn't + * *actually* be uncertain, but in the real world, a string's encoding -- if + * promised at all -- may be more...aspirational...than reality.) This + * encoding variant will eventually be removed -- work to convert your uses + * to UTF-8 as you're able. + */ + +namespace JS { +const uint16_t MaxNumErrorArguments = 10; +}; + +/** + * Report an exception represented by the sprintf-like conversion of format + * and its arguments. + */ +extern JS_PUBLIC_API void JS_ReportErrorASCII(JSContext* cx, const char* format, + ...) MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API void JS_ReportErrorLatin1(JSContext* cx, + const char* format, ...) + MOZ_FORMAT_PRINTF(2, 3); + +extern JS_PUBLIC_API void JS_ReportErrorUTF8(JSContext* cx, const char* format, + ...) MOZ_FORMAT_PRINTF(2, 3); + +/* + * Use an errorNumber to retrieve the format string, args are char* + */ +extern JS_PUBLIC_API void JS_ReportErrorNumberASCII( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + +extern JS_PUBLIC_API void JS_ReportErrorNumberASCIIVA( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, va_list ap); + +extern JS_PUBLIC_API void JS_ReportErrorNumberLatin1( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + +#ifdef va_start +extern JS_PUBLIC_API void JS_ReportErrorNumberLatin1VA( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, va_list ap); +#endif + +extern JS_PUBLIC_API void JS_ReportErrorNumberUTF8( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + +#ifdef va_start +extern JS_PUBLIC_API void JS_ReportErrorNumberUTF8VA( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, va_list ap); +#endif + +/* + * args is null-terminated. That is, a null char* means there are no + * more args. The number of args must match the number expected for + * errorNumber for the given JSErrorCallback. + */ +extern JS_PUBLIC_API void JS_ReportErrorNumberUTF8Array( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, const char** args); + +/* + * Use an errorNumber to retrieve the format string, args are char16_t* + */ +extern JS_PUBLIC_API void JS_ReportErrorNumberUC(JSContext* cx, + JSErrorCallback errorCallback, + void* userRef, + const unsigned errorNumber, + ...); + +extern JS_PUBLIC_API void JS_ReportErrorNumberUCArray( + JSContext* cx, JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, const char16_t** args); + +/** + * Complain when out of memory. + */ +extern MOZ_COLD JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx); + +extern JS_PUBLIC_API bool JS_ExpandErrorArgumentsASCII( + JSContext* cx, JSErrorCallback errorCallback, const unsigned errorNumber, + JSErrorReport* reportp, ...); + +/** + * Complain when an allocation size overflows the maximum supported limit. + */ +extern JS_PUBLIC_API void JS_ReportAllocationOverflow(JSContext* cx); + +namespace JS { + +extern JS_PUBLIC_API bool CreateError( + JSContext* cx, JSExnType type, HandleObject stack, HandleString fileName, + uint32_t lineNumber, uint32_t columnNumber, JSErrorReport* report, + HandleString message, MutableHandleValue rval); + +/************************************************************************/ + +/* + * Weak Maps. + */ + +extern JS_PUBLIC_API JSObject* NewWeakMapObject(JSContext* cx); + +extern JS_PUBLIC_API bool IsWeakMapObject(JSObject* obj); + +extern JS_PUBLIC_API bool GetWeakMapEntry(JSContext* cx, + JS::HandleObject mapObj, + JS::HandleObject key, + JS::MutableHandleValue val); + +extern JS_PUBLIC_API bool SetWeakMapEntry(JSContext* cx, + JS::HandleObject mapObj, + JS::HandleObject key, + JS::HandleValue val); + +/* + * Map + */ +extern JS_PUBLIC_API JSObject* NewMapObject(JSContext* cx); + +extern JS_PUBLIC_API uint32_t MapSize(JSContext* cx, HandleObject obj); + +extern JS_PUBLIC_API bool MapGet(JSContext* cx, HandleObject obj, + HandleValue key, MutableHandleValue rval); + +extern JS_PUBLIC_API bool MapHas(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); + +extern JS_PUBLIC_API bool MapSet(JSContext* cx, HandleObject obj, + HandleValue key, HandleValue val); + +extern JS_PUBLIC_API bool MapDelete(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); + +extern JS_PUBLIC_API bool MapClear(JSContext* cx, HandleObject obj); + +extern JS_PUBLIC_API bool MapKeys(JSContext* cx, HandleObject obj, + MutableHandleValue rval); + +extern JS_PUBLIC_API bool MapValues(JSContext* cx, HandleObject obj, + MutableHandleValue rval); + +extern JS_PUBLIC_API bool MapEntries(JSContext* cx, HandleObject obj, + MutableHandleValue rval); + +extern JS_PUBLIC_API bool MapForEach(JSContext* cx, HandleObject obj, + HandleValue callbackFn, + HandleValue thisVal); + +/* + * Set + */ +extern JS_PUBLIC_API JSObject* NewSetObject(JSContext* cx); + +extern JS_PUBLIC_API uint32_t SetSize(JSContext* cx, HandleObject obj); + +extern JS_PUBLIC_API bool SetHas(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); + +extern JS_PUBLIC_API bool SetDelete(JSContext* cx, HandleObject obj, + HandleValue key, bool* rval); + +extern JS_PUBLIC_API bool SetAdd(JSContext* cx, HandleObject obj, + HandleValue key); + +extern JS_PUBLIC_API bool SetClear(JSContext* cx, HandleObject obj); + +extern JS_PUBLIC_API bool SetKeys(JSContext* cx, HandleObject obj, + MutableHandleValue rval); + +extern JS_PUBLIC_API bool SetValues(JSContext* cx, HandleObject obj, + MutableHandleValue rval); + +extern JS_PUBLIC_API bool SetEntries(JSContext* cx, HandleObject obj, + MutableHandleValue rval); + +extern JS_PUBLIC_API bool SetForEach(JSContext* cx, HandleObject obj, + HandleValue callbackFn, + HandleValue thisVal); + +} /* namespace JS */ + +/************************************************************************/ + +extern JS_PUBLIC_API bool JS_IsExceptionPending(JSContext* cx); + +extern JS_PUBLIC_API bool JS_IsThrowingOutOfMemory(JSContext* cx); + +extern JS_PUBLIC_API bool JS_GetPendingException(JSContext* cx, + JS::MutableHandleValue vp); + +namespace JS { + +enum class ExceptionStackBehavior : bool { + // Do not capture any stack. + DoNotCapture, + + // Capture the current JS stack when setting the exception. It may be + // retrieved by JS::GetPendingExceptionStack. + Capture +}; + +} // namespace JS + +extern JS_PUBLIC_API void JS_SetPendingException( + JSContext* cx, JS::HandleValue v, + JS::ExceptionStackBehavior behavior = JS::ExceptionStackBehavior::Capture); + +extern JS_PUBLIC_API void JS_ClearPendingException(JSContext* cx); + +namespace JS { + +/** + * Save and later restore the current exception state of a given JSContext. + * This is useful for implementing behavior in C++ that's like try/catch + * or try/finally in JS. + * + * Typical usage: + * + * bool ok = JS::Evaluate(cx, ...); + * AutoSaveExceptionState savedExc(cx); + * ... cleanup that might re-enter JS ... + * return ok; + */ +class JS_PUBLIC_API AutoSaveExceptionState { + private: + JSContext* context; + bool wasPropagatingForcedReturn; + bool wasOverRecursed; + bool wasThrowing; + RootedValue exceptionValue; + RootedObject exceptionStack; + + public: + /* + * Take a snapshot of cx's current exception state. Then clear any current + * pending exception in cx. + */ + explicit AutoSaveExceptionState(JSContext* cx); + + /* + * If neither drop() nor restore() was called, restore the exception + * state only if no exception is currently pending on cx. + */ + ~AutoSaveExceptionState(); + + /* + * Discard any stored exception state. + * If this is called, the destructor is a no-op. + */ + void drop(); + + /* + * Replace cx's exception state with the stored exception state. Then + * discard the stored exception state. If this is called, the + * destructor is a no-op. + */ + void restore(); +}; + +} /* namespace JS */ + +/** + * If the given object is an exception object, the exception will have (or be + * able to lazily create) an error report struct, and this function will return + * the address of that struct. Otherwise, it returns nullptr. The lifetime + * of the error report struct that might be returned is the same as the + * lifetime of the exception object. + */ +extern JS_PUBLIC_API JSErrorReport* JS_ErrorFromException(JSContext* cx, + JS::HandleObject obj); + +namespace JS { +/** + * If the given object is an exception object (or an unwrappable + * cross-compartment wrapper for one), return the stack for that exception, if + * any. Will return null if the given object is not an exception object + * (including if it's null or a security wrapper that can't be unwrapped) or if + * the exception has no stack. + */ +extern JS_PUBLIC_API JSObject* ExceptionStackOrNull(JS::HandleObject obj); + +} /* namespace JS */ + +/** + * A JS context always has an "owner thread". The owner thread is set when the + * context is created (to the current thread) and practically all entry points + * into the JS engine check that a context (or anything contained in the + * context: runtime, compartment, object, etc) is only touched by its owner + * thread. Embeddings may check this invariant outside the JS engine by calling + * JS_AbortIfWrongThread (which will abort if not on the owner thread, even for + * non-debug builds). + */ + +extern JS_PUBLIC_API void JS_AbortIfWrongThread(JSContext* cx); + +/************************************************************************/ + +/** + * A constructor can request that the JS engine create a default new 'this' + * object of the given class, using the callee to determine parentage and + * [[Prototype]]. + */ +extern JS_PUBLIC_API JSObject* JS_NewObjectForConstructor( + JSContext* cx, const JSClass* clasp, const JS::CallArgs& args); + +/************************************************************************/ + +#ifdef JS_GC_ZEAL +# define JS_DEFAULT_ZEAL_FREQ 100 + +extern JS_PUBLIC_API void JS_GetGCZealBits(JSContext* cx, uint32_t* zealBits, + uint32_t* frequency, + uint32_t* nextScheduled); + +extern JS_PUBLIC_API void JS_SetGCZeal(JSContext* cx, uint8_t zeal, + uint32_t frequency); + +extern JS_PUBLIC_API void JS_UnsetGCZeal(JSContext* cx, uint8_t zeal); + +extern JS_PUBLIC_API void JS_ScheduleGC(JSContext* cx, uint32_t count); +#endif + +extern JS_PUBLIC_API void JS_SetParallelParsingEnabled(JSContext* cx, + bool enabled); + +extern JS_PUBLIC_API void JS_SetOffthreadIonCompilationEnabled(JSContext* cx, + bool enabled); + +// clang-format off +#define JIT_COMPILER_OPTIONS(Register) \ + Register(BASELINE_INTERPRETER_WARMUP_TRIGGER, "blinterp.warmup.trigger") \ + Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ + Register(ION_NORMAL_WARMUP_TRIGGER, "ion.warmup.trigger") \ + Register(ION_GVN_ENABLE, "ion.gvn.enable") \ + Register(ION_FORCE_IC, "ion.forceinlineCaches") \ + Register(ION_ENABLE, "ion.enable") \ + Register(JIT_TRUSTEDPRINCIPALS_ENABLE, "jit_trustedprincipals.enable") \ + Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \ + Register(ION_FREQUENT_BAILOUT_THRESHOLD, "ion.frequent-bailout-threshold") \ + Register(BASELINE_INTERPRETER_ENABLE, "blinterp.enable") \ + Register(BASELINE_ENABLE, "baseline.enable") \ + Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ + Register(FULL_DEBUG_CHECKS, "jit.full-debug-checks") \ + Register(JUMP_THRESHOLD, "jump-threshold") \ + Register(NATIVE_REGEXP_ENABLE, "native_regexp.enable") \ + Register(SIMULATOR_ALWAYS_INTERRUPT, "simulator.always-interrupt") \ + Register(SPECTRE_INDEX_MASKING, "spectre.index-masking") \ + Register(SPECTRE_OBJECT_MITIGATIONS_BARRIERS, "spectre.object-mitigations.barriers") \ + Register(SPECTRE_OBJECT_MITIGATIONS_MISC, "spectre.object-mitigations.misc") \ + Register(SPECTRE_STRING_MITIGATIONS, "spectre.string-mitigations") \ + Register(SPECTRE_VALUE_MASKING, "spectre.value-masking") \ + Register(SPECTRE_JIT_TO_CXX_CALLS, "spectre.jit-to-C++-calls") \ + Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") \ + Register(WASM_DELAY_TIER2, "wasm.delay-tier2") \ + Register(WASM_JIT_BASELINE, "wasm.baseline") \ + Register(WASM_JIT_OPTIMIZING, "wasm.optimizing") \ +// clang-format on + +typedef enum JSJitCompilerOption { +#define JIT_COMPILER_DECLARE(key, str) JSJITCOMPILER_##key, + + JIT_COMPILER_OPTIONS(JIT_COMPILER_DECLARE) +#undef JIT_COMPILER_DECLARE + + JSJITCOMPILER_NOT_AN_OPTION +} JSJitCompilerOption; + +extern JS_PUBLIC_API void JS_SetGlobalJitCompilerOption(JSContext* cx, + JSJitCompilerOption opt, + uint32_t value); +extern JS_PUBLIC_API bool JS_GetGlobalJitCompilerOption(JSContext* cx, + JSJitCompilerOption opt, + uint32_t* valueOut); + +/** + * Convert a uint32_t index into a jsid. + */ +extern JS_PUBLIC_API bool JS_IndexToId(JSContext* cx, uint32_t index, + JS::MutableHandleId); + +/** + * Convert chars into a jsid. + * + * |chars| may not be an index. + */ +extern JS_PUBLIC_API bool JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, + JS::MutableHandleId); + +/** + * Test if the given string is a valid ECMAScript identifier + */ +extern JS_PUBLIC_API bool JS_IsIdentifier(JSContext* cx, JS::HandleString str, + bool* isIdentifier); + +/** + * Test whether the given chars + length are a valid ECMAScript identifier. + * This version is infallible, so just returns whether the chars are an + * identifier. + */ +extern JS_PUBLIC_API bool JS_IsIdentifier(const char16_t* chars, size_t length); + +namespace js { +class ScriptSource; +} // namespace js + +namespace JS { + +class MOZ_RAII JS_PUBLIC_API AutoFilename { + private: + js::ScriptSource* ss_; + mozilla::Variant<const char*, UniqueChars> filename_; + + AutoFilename(const AutoFilename&) = delete; + AutoFilename& operator=(const AutoFilename&) = delete; + + public: + AutoFilename() + : ss_(nullptr), filename_(mozilla::AsVariant<const char*>(nullptr)) {} + + ~AutoFilename() { reset(); } + + void reset(); + + void setOwned(UniqueChars&& filename); + void setUnowned(const char* filename); + void setScriptSource(js::ScriptSource* ss); + + const char* get() const; +}; + +/** + * Return the current filename, line number and column number of the most + * currently running frame. Returns true if a scripted frame was found, false + * otherwise. + * + * If a the embedding has hidden the scripted caller for the topmost activation + * record, this will also return false. + */ +extern JS_PUBLIC_API bool DescribeScriptedCaller( + JSContext* cx, AutoFilename* filename = nullptr, unsigned* lineno = nullptr, + unsigned* column = nullptr); + +extern JS_PUBLIC_API JSObject* GetScriptedCallerGlobal(JSContext* cx); + +/** + * Informs the JS engine that the scripted caller should be hidden. This can be + * used by the embedding to maintain an override of the scripted caller in its + * calculations, by hiding the scripted caller in the JS engine and pushing data + * onto a separate stack, which it inspects when DescribeScriptedCaller returns + * null. + * + * We maintain a counter on each activation record. Add() increments the counter + * of the topmost activation, and Remove() decrements it. The count may never + * drop below zero, and must always be exactly zero when the activation is + * popped from the stack. + */ +extern JS_PUBLIC_API void HideScriptedCaller(JSContext* cx); + +extern JS_PUBLIC_API void UnhideScriptedCaller(JSContext* cx); + +class MOZ_RAII AutoHideScriptedCaller { + public: + explicit AutoHideScriptedCaller(JSContext* cx) : mContext(cx) { + HideScriptedCaller(mContext); + } + ~AutoHideScriptedCaller() { UnhideScriptedCaller(mContext); } + + protected: + JSContext* mContext; +}; + +} /* namespace JS */ + +namespace js { + +enum class StackFormat { SpiderMonkey, V8, Default }; + +/* + * Sets the format used for stringifying Error stacks. + * + * The default format is StackFormat::SpiderMonkey. Use StackFormat::V8 + * in order to emulate V8's stack formatting. StackFormat::Default can't be + * used here. + */ +extern JS_PUBLIC_API void SetStackFormat(JSContext* cx, StackFormat format); + +extern JS_PUBLIC_API StackFormat GetStackFormat(JSContext* cx); + +} // namespace js + +namespace JS { + +/** + * Attempt to disable Wasm's usage of reserving a large virtual memory + * allocation to avoid bounds checking overhead. This must be called before any + * Wasm module or memory is created in this process, or else this function will + * fail. + */ +extern JS_PUBLIC_API MOZ_MUST_USE bool DisableWasmHugeMemory(); + +/** + * If a large allocation fails when calling pod_{calloc,realloc}CanGC, the JS + * engine may call the large-allocation-failure callback, if set, to allow the + * embedding to flush caches, possibly perform shrinking GCs, etc. to make some + * room. The allocation will then be retried (and may still fail.) This callback + * can be called on any thread and must be set at most once in a process. + */ + +using LargeAllocationFailureCallback = void (*)(); + +extern JS_PUBLIC_API void SetProcessLargeAllocationFailureCallback( + LargeAllocationFailureCallback afc); + +/** + * Unlike the error reporter, which is only called if the exception for an OOM + * bubbles up and is not caught, the OutOfMemoryCallback is called immediately + * at the OOM site to allow the embedding to capture the current state of heap + * allocation before anything is freed. If the large-allocation-failure callback + * is called at all (not all allocation sites call the large-allocation-failure + * callback on failure), it is called before the out-of-memory callback; the + * out-of-memory callback is only called if the allocation still fails after the + * large-allocation-failure callback has returned. + */ + +using OutOfMemoryCallback = void (*)(JSContext*, void*); + +extern JS_PUBLIC_API void SetOutOfMemoryCallback(JSContext* cx, + OutOfMemoryCallback cb, + void* data); + +/** + * When the JSRuntime is about to block in an Atomics.wait() JS call or in a + * `wait` instruction in WebAssembly, it can notify the host by means of a call + * to BeforeWaitCallback. After the wait, it can notify the host by means of a + * call to AfterWaitCallback. Both callbacks must be null, or neither. + * + * (If you change the callbacks from null to not-null or vice versa while some + * thread on the runtime is in a wait, you will be sorry.) + * + * The argument to the BeforeWaitCallback is a pointer to uninitialized + * stack-allocated working memory of size WAIT_CALLBACK_CLIENT_MAXMEM bytes. + * The caller of SetWaitCallback() must pass the amount of memory it will need, + * and this amount will be checked against that limit and the process will crash + * reliably if the check fails. + * + * The value returned by the BeforeWaitCallback will be passed to the + * AfterWaitCallback. + * + * The AfterWaitCallback will be called even if the wakeup is spurious and the + * thread goes right back to waiting again. Of course the thread will call the + * BeforeWaitCallback once more before it goes to sleep in this situation. + */ + +static constexpr size_t WAIT_CALLBACK_CLIENT_MAXMEM = 32; + +using BeforeWaitCallback = void* (*)(uint8_t* memory); +using AfterWaitCallback = void (*)(void* cookie); + +extern JS_PUBLIC_API void SetWaitCallback(JSRuntime* rt, + BeforeWaitCallback beforeWait, + AfterWaitCallback afterWait, + size_t requiredMemory); + +/** + * Capture all frames. + */ +struct AllFrames {}; + +/** + * Capture at most this many frames. + */ +struct MaxFrames { + uint32_t maxFrames; + + explicit MaxFrames(uint32_t max) : maxFrames(max) { MOZ_ASSERT(max > 0); } +}; + +/** + * Capture the first frame with the given principals. By default, do not + * consider self-hosted frames with the given principals as satisfying the stack + * capture. + */ +struct JS_PUBLIC_API FirstSubsumedFrame { + JSContext* cx; + JSPrincipals* principals; + bool ignoreSelfHosted; + + /** + * Use the cx's current compartment's principals. + */ + explicit FirstSubsumedFrame(JSContext* cx, + bool ignoreSelfHostedFrames = true); + + explicit FirstSubsumedFrame(JSContext* ctx, JSPrincipals* p, + bool ignoreSelfHostedFrames = true) + : cx(ctx), principals(p), ignoreSelfHosted(ignoreSelfHostedFrames) { + if (principals) { + JS_HoldPrincipals(principals); + } + } + + // No copying because we want to avoid holding and dropping principals + // unnecessarily. + FirstSubsumedFrame(const FirstSubsumedFrame&) = delete; + FirstSubsumedFrame& operator=(const FirstSubsumedFrame&) = delete; + + FirstSubsumedFrame(FirstSubsumedFrame&& rhs) + : principals(rhs.principals), ignoreSelfHosted(rhs.ignoreSelfHosted) { + MOZ_ASSERT(this != &rhs, "self move disallowed"); + rhs.principals = nullptr; + } + + FirstSubsumedFrame& operator=(FirstSubsumedFrame&& rhs) { + new (this) FirstSubsumedFrame(std::move(rhs)); + return *this; + } + + ~FirstSubsumedFrame() { + if (principals) { + JS_DropPrincipals(cx, principals); + } + } +}; + +using StackCapture = mozilla::Variant<AllFrames, MaxFrames, FirstSubsumedFrame>; + +/** + * Capture the current call stack as a chain of SavedFrame JSObjects, and set + * |stackp| to the SavedFrame for the youngest stack frame, or nullptr if there + * are no JS frames on the stack. + * + * The |capture| parameter describes the portion of the JS stack to capture: + * + * * |JS::AllFrames|: Capture all frames on the stack. + * + * * |JS::MaxFrames|: Capture no more than |JS::MaxFrames::maxFrames| from the + * stack. + * + * * |JS::FirstSubsumedFrame|: Capture the first frame whose principals are + * subsumed by |JS::FirstSubsumedFrame::principals|. By default, do not + * consider self-hosted frames; this can be controlled via the + * |JS::FirstSubsumedFrame::ignoreSelfHosted| flag. Do not capture any async + * stack. + */ +extern JS_PUBLIC_API bool CaptureCurrentStack( + JSContext* cx, MutableHandleObject stackp, + StackCapture&& capture = StackCapture(AllFrames())); + +/** + * Returns true if capturing stack trace data to associate with an asynchronous + * operation is currently enabled for the current context realm. + * + * Users should check this state before capturing a stack that will be passed + * back to AutoSetAsyncStackForNewCalls later, in order to avoid capturing a + * stack for async use when we don't actually want to capture it. + */ +extern JS_PUBLIC_API bool IsAsyncStackCaptureEnabledForRealm(JSContext* cx); + +/* + * This is a utility function for preparing an async stack to be used + * by some other object. This may be used when you need to treat a + * given stack trace as an async parent. If you just need to capture + * the current stack, async parents and all, use CaptureCurrentStack + * instead. + * + * Here |asyncStack| is the async stack to prepare. It is copied into + * |cx|'s current compartment, and the newest frame is given + * |asyncCause| as its asynchronous cause. If |maxFrameCount| is + * |Some(n)|, capture at most the youngest |n| frames. The + * new stack object is written to |stackp|. Returns true on success, + * or sets an exception and returns |false| on error. + */ +extern JS_PUBLIC_API bool CopyAsyncStack( + JSContext* cx, HandleObject asyncStack, HandleString asyncCause, + MutableHandleObject stackp, const mozilla::Maybe<size_t>& maxFrameCount); + +/** + * Given a SavedFrame JSObject stack, stringify it in the same format as + * Error.prototype.stack. The stringified stack out parameter is placed in the + * cx's compartment. Defaults to the empty string. + * + * The same notes above about SavedFrame accessors applies here as well: cx + * doesn't need to be in stack's compartment, and stack can be null, a + * SavedFrame object, or a wrapper (CCW or Xray) around a SavedFrame object. + * SavedFrames not subsumed by |principals| are skipped. + * + * Optional indent parameter specifies the number of white spaces to indent + * each line. + */ +extern JS_PUBLIC_API bool BuildStackString( + JSContext* cx, JSPrincipals* principals, HandleObject stack, + MutableHandleString stringp, size_t indent = 0, + js::StackFormat stackFormat = js::StackFormat::Default); + +/** + * Return true iff the given object is either a SavedFrame object or wrapper + * around a SavedFrame object, and it is not the SavedFrame.prototype object. + */ +extern JS_PUBLIC_API bool IsMaybeWrappedSavedFrame(JSObject* obj); + +/** + * Return true iff the given object is a SavedFrame object and not the + * SavedFrame.prototype object. + */ +extern JS_PUBLIC_API bool IsUnwrappedSavedFrame(JSObject* obj); + +} /* namespace JS */ + +namespace js { + +/** + * Hint that we expect a crash. Currently, the only thing that cares is the + * breakpad injector, which (if loaded) will suppress minidump generation. + */ +extern JS_PUBLIC_API void NoteIntentionalCrash(); + +} /* namespace js */ + +namespace js { + +enum class CompletionKind { Normal, Return, Throw }; + +} /* namespace js */ + +#ifdef DEBUG +namespace JS { + +extern JS_PUBLIC_API void SetSupportDifferentialTesting(bool value); + +} +#endif /* DEBUG */ + +#endif /* jsapi_h */ |