/* -*- 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 #include #include #include #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 class SourceText; class TwoByteChars; using ValueVector = JS::GCVector; using IdVector = JS::GCVector; using ScriptVector = JS::GCVector; using StringVector = JS::GCVector; /** * Custom rooting behavior for internal and external clients. */ class MOZ_RAII JS_PUBLIC_API CustomAutoRooter : private AutoGCRooter { public: template 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 v); extern JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip); extern JS_PUBLIC_API JSType JS_TypeOfValue(JSContext* cx, JS::Handle 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)); 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 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 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 objp); extern JS_PUBLIC_API bool JS_GetClassPrototype( JSContext* cx, JSProtoKey key, JS::MutableHandle 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 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 ctor, JS::Handle proto); extern JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx, JS::Handle obj, const JSClass* clasp, JS::CallArgs* args); extern JS_PUBLIC_API bool JS_HasInstance(JSContext* cx, JS::Handle obj, JS::Handle 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 obj, const JSClass* clasp, JS::CallArgs* args); extern JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx, JS::Handle 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 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 obj); /** * Freezes an object; see ES5's Object.freeze(obj) method. */ extern JS_PUBLIC_API bool JS_FreezeObject(JSContext* cx, JS::Handle 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 desc); extern JS_PUBLIC_API bool JS_GetOwnPropertyDescriptor( JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandle desc); extern JS_PUBLIC_API bool JS_GetOwnUCPropertyDescriptor( JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::MutableHandle 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 desc); extern JS_PUBLIC_API bool JS_GetPropertyDescriptor( JSContext* cx, JS::HandleObject obj, const char* name, JS::MutableHandle desc); extern JS_PUBLIC_API bool JS_GetUCPropertyDescriptor( JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::MutableHandle 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 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 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 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 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. */ extern JS_PUBLIC_API bool JS_Enumerate(JSContext* cx, JS::HandleObject obj, JS::MutableHandle 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 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 obj, const JSFunctionSpec* fs); extern JS_PUBLIC_API JSFunction* JS_DefineFunction( JSContext* cx, JS::Handle obj, const char* name, JSNative call, unsigned nargs, unsigned attrs); extern JS_PUBLIC_API JSFunction* JS_DefineUCFunction( JSContext* cx, JS::Handle 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 obj, JS::Handle 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 script); extern JS_PUBLIC_API JSString* JS_DecompileFunction( JSContext* cx, JS::Handle 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; using UniqueOptimizedEncodingBytes = js::UniquePtr; 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 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 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 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(JSID_TO_STRING(id)); } static MOZ_ALWAYS_INLINE JSLinearString* JS_ASSERT_STRING_IS_LINEAR( JSString* str) { MOZ_ASSERT(JS_StringIsLinear(str)); return reinterpret_cast(str); } static MOZ_ALWAYS_INLINE JSString* JS_FORGET_STRING_LINEARNESS( JSLinearString* str) { return reinterpret_cast(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 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 > JS_EncodeStringToUTF8BufferPartial(JSContext* cx, JSString* str, mozilla::Span 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 filename_; AutoFilename(const AutoFilename&) = delete; AutoFilename& operator=(const AutoFilename&) = delete; public: AutoFilename() : ss_(nullptr), filename_(mozilla::AsVariant(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; /** * 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& 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 */