Source code

Revision control

Other Tools

/* -*- 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/RangedPtr.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Utf8.h"
#include "mozilla/Variant.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "jspubtd.h"
#include "js/AllocPolicy.h"
#include "js/CallAndConstruct.h" // JS::Call, JS_CallFunction, JS_CallFunctionName, JS_CallFunctionValue
#include "js/CallArgs.h"
#include "js/CharacterEncoding.h"
#include "js/Class.h"
#include "js/CompileOptions.h"
#include "js/Context.h"
#include "js/ErrorReport.h"
#include "js/Exception.h"
#include "js/GCAPI.h"
#include "js/GCVector.h"
#include "js/HashTable.h"
#include "js/Id.h"
#include "js/MapAndSet.h"
#include "js/MemoryFunctions.h"
#include "js/OffThreadScriptCompilation.h"
#include "js/Principals.h"
#include "js/PropertyAndElement.h" // JS_Enumerate
#include "js/PropertyDescriptor.h"
#include "js/PropertySpec.h"
#include "js/Realm.h"
#include "js/RealmIterators.h"
#include "js/RealmOptions.h"
#include "js/RefCounted.h"
#include "js/RootingAPI.h"
#include "js/String.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"
#include "js/WeakMap.h"
#include "js/Zone.h"
/************************************************************************/
struct JSFunctionSpec;
struct JSPropertySpec;
namespace JS {
template <typename UnitT>
class SourceText;
class TwoByteChars;
using ValueVector = JS::GCVector<JS::Value>;
using IdVector = JS::GCVector<jsid>;
using ScriptVector = JS::GCVector<JSScript*>;
using StringVector = JS::GCVector<JSString*>;
} /* namespace JS */
/* Callbacks and their arguments. */
/************************************************************************/
// Callback for the embedding to map from a ScriptSourceObject private-value to
// an object that is exposed as the source "element" in debugger API. This hook
// must be infallible, but can return nullptr if no such element exists.
using JSSourceElementCallback = JSObject* (*)(JSContext*, JS::HandleValue);
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;
};
/**
* 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);
extern JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, JS::HandleValue v,
JS::MutableHandleObject objp);
extern JS_PUBLIC_API JSFunction* JS_ValueToFunction(JSContext* cx,
JS::HandleValue v);
extern JS_PUBLIC_API JSFunction* JS_ValueToConstructor(JSContext* cx,
JS::HandleValue v);
extern JS_PUBLIC_API JSString* JS_ValueToSource(JSContext* cx,
JS::Handle<JS::Value> v);
extern JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip);
extern JS_PUBLIC_API JSType JS_TypeOfValue(JSContext* cx,
JS::Handle<JS::Value> v);
namespace JS {
extern JS_PUBLIC_API const char* InformalValueTypeName(const JS::Value& v);
/** Timing information for telemetry purposes **/
struct JSTimers {
mozilla::TimeDuration executionTime; // Total time spent executing
mozilla::TimeDuration delazificationTime; // Total time spent delazifying
mozilla::TimeDuration xdrEncodingTime; // Total time spent XDR encoding
mozilla::TimeDuration gcTime; // Total time spent in GC
mozilla::TimeDuration
protectTime; // Total time spent protecting JIT executable memory
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);
extern JS_PUBLIC_API const char* JS_GetImplementationVersion(void);
extern JS_PUBLIC_API void JS_SetWrapObjectCallbacks(
JSContext* cx, const JSWrapObjectCallbacks* callbacks);
// Set a callback that will be called whenever an error
// is thrown in this runtime. This is designed as a mechanism
// for logging errors. Note that the VM makes no attempt to sanitize
// the contents of the error (so it may contain private data)
// or to sort out among errors (so it may not be the error you
// are interested in or for the component in which you are
// interested).
//
// If the callback sets a new error, this new error
// will replace the original error.
//
// May be `nullptr`.
// This is a no-op if built without NIGHTLY_BUILD.
extern JS_PUBLIC_API void JS_SetErrorInterceptorCallback(
JSRuntime*, JSErrorInterceptor* callback);
// This returns nullptr if built without NIGHTLY_BUILD.
extern JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback(
JSRuntime*);
// Examine a value to determine if it is one of the built-in Error types.
// If so, return the error type.
extern JS_PUBLIC_API mozilla::Maybe<JSExnType> JS_GetErrorType(
const JS::Value& val);
extern JS_PUBLIC_API 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);
/**
* Resolve id, which must contain either a string or an int, to a standard
* class name in obj if possible, defining the class's constructor and/or
* prototype and storing true in *resolved. If id does not name a standard
* class or a top-level property induced by initializing a standard class,
* store false in *resolved and just return true. Return false on error,
* as usual for bool result-typed API entry points.
*
* This API can be called directly from a global object class's resolve op,
* to define standard classes lazily. The class should either have an enumerate
* hook that calls JS_EnumerateStandardClasses, or a newEnumerate hook that
* calls JS_NewEnumerateStandardClasses. newEnumerate is preferred because it's
* faster (does not define all standard classes).
*/
extern JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx,
JS::HandleObject obj,
JS::HandleId id,
bool* resolved);
extern JS_PUBLIC_API bool JS_MayResolveStandardClass(const JSAtomState& names,
jsid id,
JSObject* maybeObj);
extern JS_PUBLIC_API bool JS_EnumerateStandardClasses(JSContext* cx,
JS::HandleObject obj);
/**
* Fill "properties" with a list of standard class names that have not yet been
* resolved on "obj". This can be used as (part of) a newEnumerate class hook
* on a global. Already-resolved things are excluded because they might have
* been deleted by script after being resolved and enumeration considers
* already-defined properties anyway.
*/
extern JS_PUBLIC_API bool JS_NewEnumerateStandardClasses(
JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
bool enumerableOnly);
/**
* Fill "properties" with a list of standard class names. This can be used for
* proxies that want to define behavior that looks like enumerating a global
* without touching the global itself.
*/
extern JS_PUBLIC_API bool JS_NewEnumerateStandardClassesIncludingResolved(
JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties,
bool enumerableOnly);
extern JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key,
JS::MutableHandle<JSObject*> objp);
extern JS_PUBLIC_API bool JS_GetClassPrototype(
JSContext* cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp);
namespace JS {
/*
* Determine if the given object is an instance/prototype/constructor for a
* standard class. If so, return the associated JSProtoKey. If not, return
* JSProto_Null.
*/
extern JS_PUBLIC_API JSProtoKey IdentifyStandardInstance(JSObject* obj);
extern JS_PUBLIC_API JSProtoKey IdentifyStandardPrototype(JSObject* obj);
extern JS_PUBLIC_API JSProtoKey
IdentifyStandardInstanceOrPrototype(JSObject* obj);
extern JS_PUBLIC_API JSProtoKey IdentifyStandardConstructor(JSObject* obj);
extern JS_PUBLIC_API void ProtoKeyToId(JSContext* cx, JSProtoKey key,
JS::MutableHandleId idp);
} /* namespace JS */
extern JS_PUBLIC_API JSProtoKey JS_IdToProtoKey(JSContext* cx, JS::HandleId id);
extern JS_PUBLIC_API bool JS_IsGlobalObject(JSObject* obj);
extern JS_PUBLIC_API JSObject* JS_GlobalLexicalEnvironment(JSObject* obj);
extern JS_PUBLIC_API bool JS_HasExtensibleLexicalEnvironment(JSObject* obj);
extern JS_PUBLIC_API JSObject* JS_ExtensibleLexicalEnvironment(JSObject* obj);
namespace JS {
/**
* Get the current realm's global. Returns nullptr if no realm has been
* entered.
*/
extern JS_PUBLIC_API JSObject* CurrentGlobalOrNull(JSContext* cx);
/**
* Get the global object associated with an object's realm. The object must not
* be a cross-compartment wrapper (because CCWs are shared by all realms in the
* compartment).
*/
extern JS_PUBLIC_API JSObject* GetNonCCWObjectGlobal(JSObject* obj);
} // namespace JS
/**
* Add 'Reflect.parse', a SpiderMonkey extension, to the Reflect object on the
* given global.
*/
extern JS_PUBLIC_API bool JS_InitReflectParse(JSContext* cx,
JS::HandleObject global);
/**
* Add various profiling-related functions as properties of the given object.
* Defined in builtin/Profilers.cpp.
*/
extern JS_PUBLIC_API bool JS_DefineProfilingFunctions(JSContext* cx,
JS::HandleObject obj);
/* Defined in vm/Debugger.cpp. */
extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx,
JS::HandleObject obj);
namespace JS {
/**
* Tell JS engine whether Profile Timeline Recording is enabled or not.
* If Profile Timeline Recording is enabled, data shown there like stack won't
* be optimized out.
* This is global state and not associated with specific runtime or context.
*/
extern JS_PUBLIC_API void SetProfileTimelineRecordingEnabled(bool enabled);
extern JS_PUBLIC_API bool IsProfileTimelineRecordingEnabled();
} // namespace JS
/**
* Set the size of the native stack that should not be exceed. To disable
* stack size checking pass 0.
*
* SpiderMonkey allows for a distinction between system code (such as GCs, which
* may incidentally be triggered by script but are not strictly performed on
* behalf of such script), trusted script (as determined by
* JS_SetTrustedPrincipals), and untrusted script. Each kind of code may have a
* different stack quota, allowing embedders to keep higher-priority machinery
* running in the face of scripted stack exhaustion by something else.
*
* The stack quotas for each kind of code should be monotonically descending,
* and may be specified with this function. If 0 is passed for a given kind
* of code, it defaults to the value of the next-highest-priority kind.
*
* This function may only be called immediately after the runtime is initialized
* and before any code is executed and/or interrupts requested.
*/
extern JS_PUBLIC_API void JS_SetNativeStackQuota(
JSContext* cx, size_t systemCodeStackSize,
size_t trustedScriptStackSize = 0, size_t untrustedScriptStackSize = 0);
/************************************************************************/
extern JS_PUBLIC_API bool JS_ValueToId(JSContext* cx, JS::HandleValue v,
JS::MutableHandleId idp);
extern JS_PUBLIC_API bool JS_StringToId(JSContext* cx, JS::HandleString s,
JS::MutableHandleId idp);
extern JS_PUBLIC_API bool JS_IdToValue(JSContext* cx, jsid id,
JS::MutableHandle<JS::Value> vp);
namespace JS {
/**
* Convert obj to a primitive value. On success, store the result in vp and
* return true.
*
* The hint argument must be JSTYPE_STRING, JSTYPE_NUMBER, or
* JSTYPE_UNDEFINED (no hint).
*
* Implements: ES6 7.1.1 ToPrimitive(input, [PreferredType]).
*/
extern JS_PUBLIC_API bool ToPrimitive(JSContext* cx, JS::HandleObject obj,
JSType hint, JS::MutableHandleValue vp);
/**
* If args.get(0) is one of the strings "string", "number", or "default", set
* result to JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_UNDEFINED accordingly and
* return true. Otherwise, return false with a TypeError pending.
*
* This can be useful in implementing a @@toPrimitive method.
*/
extern JS_PUBLIC_API bool GetFirstArgumentAsTypeHint(JSContext* cx,
CallArgs args,
JSType* result);
} /* namespace JS */
extern JS_PUBLIC_API JSObject* JS_InitClass(
JSContext* cx, JS::HandleObject obj, JS::HandleObject parent_proto,
const JSClass* clasp, JSNative constructor, unsigned nargs,
const JSPropertySpec* ps, const JSFunctionSpec* fs,
const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs);
/**
* Set up ctor.prototype = proto and proto.constructor = ctor with the
* right property flags.
*/
extern JS_PUBLIC_API bool JS_LinkConstructorAndPrototype(
JSContext* cx, JS::Handle<JSObject*> ctor, JS::Handle<JSObject*> proto);
extern JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx,
JS::Handle<JSObject*> obj,
const JSClass* clasp,
JS::CallArgs* args);
extern JS_PUBLIC_API bool JS_HasInstance(JSContext* cx,
JS::Handle<JSObject*> obj,
JS::Handle<JS::Value> v, bool* bp);
namespace JS {
// Implementation of
// 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
// This is almost identical to JS_HasInstance, except the latter may call a
// custom hasInstance class op instead of InstanceofOperator.
extern JS_PUBLIC_API bool InstanceofOperator(JSContext* cx, HandleObject obj,
HandleValue v, bool* bp);
} // namespace JS
extern JS_PUBLIC_API void JS_InitPrivate(JSObject* obj, void* data,
size_t nbytes, JS::MemoryUse use);
extern JS_PUBLIC_API void* JS_GetInstancePrivate(JSContext* cx,
JS::Handle<JSObject*> obj,
const JSClass* clasp,
JS::CallArgs* args);
extern JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx,
JS::Handle<JSObject*> proto);
namespace JS {
/**
* During global creation, we fire notifications to callbacks registered
* via the Debugger API. These callbacks are arbitrary script, and can touch
* the global in arbitrary ways. When that happens, the global should not be
* in a half-baked state. But this creates a problem for consumers that need
* to set slots on the global to put it in a consistent state.
*
* This API provides a way for consumers to set slots atomically (immediately
* after the global is created), before any debugger hooks are fired. It's
* unfortunately on the clunky side, but that's the way the cookie crumbles.
*
* If callers have no additional state on the global to set up, they may pass
* |FireOnNewGlobalHook| to JS_NewGlobalObject, which causes that function to
* fire the hook as its final act before returning. Otherwise, callers should
* pass |DontFireOnNewGlobalHook|, which means that they are responsible for
* invoking JS_FireOnNewGlobalObject upon successfully creating the global. If
* an error occurs and the operation aborts, callers should skip firing the
* hook. But otherwise, callers must take care to fire the hook exactly once
* before compiling any script in the global's scope (we have assertions in
* place to enforce this). This lets us be sure that debugger clients never miss
* breakpoints.
*/
enum OnNewGlobalHookOption { FireOnNewGlobalHook, DontFireOnNewGlobalHook };
} /* namespace JS */
extern JS_PUBLIC_API JSObject* JS_NewGlobalObject(
JSContext* cx, const JSClass* clasp, JSPrincipals* principals,
JS::OnNewGlobalHookOption hookOption, const JS::RealmOptions& options);
/**
* Spidermonkey does not have a good way of keeping track of what compartments
* should be marked on their own. We can mark the roots unconditionally, but
* marking GC things only relevant in live compartments is hard. To mitigate
* this, we create a static trace hook, installed on each global object, from
* which we can be sure the compartment is relevant, and mark it.
*
* It is still possible to specify custom trace hooks for global object classes.
* They can be provided via the RealmOptions passed to JS_NewGlobalObject.
*/
extern JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc,
JSObject* global);
namespace JS {
/**
* This allows easily constructing a global object without having to deal with
* JSClassOps, forgetting to add JS_GlobalObjectTraceHook, or forgetting to call
* JS::InitRealmStandardClasses(). Example:
*
* const JSClass globalClass = { "MyGlobal", JSCLASS_GLOBAL_FLAGS,
* &JS::DefaultGlobalClassOps };
* JS_NewGlobalObject(cx, &globalClass, ...);
*/
extern JS_PUBLIC_DATA const JSClassOps DefaultGlobalClassOps;
} // namespace JS
extern JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx,
JS::HandleObject global);
extern JS_PUBLIC_API JSObject* JS_NewObject(JSContext* cx,
const JSClass* clasp);
extern JS_PUBLIC_API bool JS_IsNative(JSObject* obj);
/**
* Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default
* proto. If proto is nullptr, the JS object will have `null` as [[Prototype]].
*/
extern JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProto(
JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto);
/**
* Creates a new plain object, like `new Object()`, with Object.prototype as
* [[Prototype]].
*/
extern JS_PUBLIC_API JSObject* JS_NewPlainObject(JSContext* cx);
/**
* Freeze obj, and all objects it refers to, recursively. This will not recurse
* through non-extensible objects, on the assumption that those are already
* deep-frozen.
*/
extern JS_PUBLIC_API bool JS_DeepFreezeObject(JSContext* cx,
JS::Handle<JSObject*> obj);
/**
* Freezes an object; see ES5's Object.freeze(obj) method.
*/
extern JS_PUBLIC_API bool JS_FreezeObject(JSContext* cx,
JS::Handle<JSObject*> obj);
/*** Standard internal methods **********************************************
*
* The functions below are the fundamental operations on objects.
*
* ES6 specifies 14 internal methods that define how objects behave. The
* standard is actually quite good on this topic, though you may have to read
* it a few times. See ES6 sections 6.1.7.2 and 6.1.7.3.
*
* When 'obj' is an ordinary object, these functions have boring standard
* behavior as specified by ES6 section 9.1; see the section about internal
* methods in js/src/vm/NativeObject.h.
*
* Proxies override the behavior of internal methods. So when 'obj' is a proxy,
* any one of the functions below could do just about anything. See
* js/public/Proxy.h.
*/
/**
* Get the prototype of |obj|, storing it in |proto|.
*
* Implements: ES6 [[GetPrototypeOf]] internal method.
*/
extern JS_PUBLIC_API bool JS_GetPrototype(JSContext* cx, JS::HandleObject obj,
JS::MutableHandleObject result);
/**
* If |obj| (underneath any functionally-transparent wrapper proxies) has as
* its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined
* for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype
* in |result|. Otherwise set |*isOrdinary = false|. In case of error, both
* outparams have unspecified value.
*/
extern JS_PUBLIC_API bool JS_GetPrototypeIfOrdinary(
JSContext* cx, JS::HandleObject obj, bool* isOrdinary,
JS::MutableHandleObject result);
/**
* Change the prototype of obj.
*
* Implements: ES6 [[SetPrototypeOf]] internal method.
*
* In cases where ES6 [[SetPrototypeOf]] returns false without an exception,
* JS_SetPrototype throws a TypeError and returns false.
*
* Performance warning: JS_SetPrototype is very bad for performance. It may
* cause compiled jit-code to be invalidated. It also causes not only obj but
* all other objects in the same "group" as obj to be permanently deoptimized.
* It's better to create the object with the right prototype from the start.
*/
extern JS_PUBLIC_API bool JS_SetPrototype(JSContext* cx, JS::HandleObject obj,
JS::HandleObject proto);
/**
* Determine whether obj is extensible. Extensible objects can have new
* properties defined on them. Inextensible objects can't, and their
* [[Prototype]] slot is fixed as well.
*
* Implements: ES6 [[IsExtensible]] internal method.
*/
extern JS_PUBLIC_API bool JS_IsExtensible(JSContext* cx, JS::HandleObject obj,
bool* extensible);
/**
* Attempt to make |obj| non-extensible.
*
* Not all failures are treated as errors. See the comment on
* JS::ObjectOpResult in js/public/Class.h.
*
* Implements: ES6 [[PreventExtensions]] internal method.
*/
extern JS_PUBLIC_API bool JS_PreventExtensions(JSContext* cx,
JS::HandleObject obj,
JS::ObjectOpResult& result);
/**
* Attempt to make the [[Prototype]] of |obj| immutable, such that any attempt
* to modify it will fail. If an error occurs during the attempt, return false
* (with a pending exception set, depending upon the nature of the error). If
* no error occurs, return true with |*succeeded| set to indicate whether the
* attempt successfully made the [[Prototype]] immutable.
*
* This is a nonstandard internal method.
*/
extern JS_PUBLIC_API bool JS_SetImmutablePrototype(JSContext* cx,
JS::HandleObject obj,
bool* succeeded);
/**
* 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);
namespace JS {
/**
* On success, returns true, setting |*isMap| to true if |obj| is a Map object
* or a wrapper around one, or to false if not. Returns false on failure.
*
* This method returns true with |*isMap == false| when passed an ES6 proxy
* whose target is a Map, or when passed a revoked proxy.
*/
extern JS_PUBLIC_API bool IsMapObject(JSContext* cx, JS::HandleObject obj,
bool* isMap);
/**
* On success, returns true, setting |*isSet| to true if |obj| is a Set object
* or a wrapper around one, or to false if not. Returns false on failure.
*
* This method returns true with |*isSet == false| when passed an ES6 proxy
* whose target is a Set, or when passed a revoked proxy.
*/
extern JS_PUBLIC_API bool IsSetObject(JSContext* cx, JS::HandleObject obj,
bool* isSet);
} /* namespace JS */
/**
* Assign 'undefined' to all of the object's non-reserved slots. Note: this is
* done for all slots, regardless of the associated property descriptor.
*/
JS_PUBLIC_API void JS_SetAllNonReservedSlotsToUndefined(JS::HandleObject obj);
extern JS_PUBLIC_API void JS_SetReservedSlot(JSObject* obj, uint32_t index,
const JS::Value& v);
extern JS_PUBLIC_API void JS_InitReservedSlot(JSObject* obj, uint32_t index,
void* ptr, size_t nbytes,
JS::MemoryUse use);
template <typename T>
void JS_InitReservedSlot(JSObject* obj, uint32_t index, T* ptr,
JS::MemoryUse use) {
JS_InitReservedSlot(obj, index, ptr, sizeof(T), use);
}
extern JS_PUBLIC_API void JS_InitPrivate(JSObject* obj, void* data,
size_t nbytes, JS::MemoryUse use);
/************************************************************************/
/* native that can be called as a ctor */
static constexpr unsigned JSFUN_CONSTRUCTOR = 0x400;
/* | of all the JSFUN_* flags */
static constexpr unsigned JSFUN_FLAGS_MASK = 0x400;
static_assert((JSPROP_FLAGS_MASK & JSFUN_FLAGS_MASK) == 0,
"JSFUN_* flags do not overlap JSPROP_* flags, because bits from "
"the two flag-sets appear in the same flag in some APIs");
/*
* Functions and scripts.
*/
extern JS_PUBLIC_API JSFunction* JS_NewFunction(JSContext* cx, JSNative call,
unsigned nargs, unsigned flags,
const char* name);
namespace JS {
extern JS_PUBLIC_API JSFunction* GetSelfHostedFunction(
JSContext* cx, const char* selfHostedName, HandleId id, unsigned nargs);
/**
* Create a new function based on the given JSFunctionSpec, *fs.
* id is the result of a successful call to
* `PropertySpecNameToId(cx, fs->name, &id)` or
`PropertySpecNameToPermanentId(cx, fs->name, &id)`.
*
* Unlike JS_DefineFunctions, this does not treat fs as an array.
* *fs must not be JS_FS_END.
*/
extern JS_PUBLIC_API JSFunction* NewFunctionFromSpec(JSContext* cx,
const JSFunctionSpec* fs,
HandleId id);
/**
* Same as above, but without an id arg, for callers who don't have
* the id already.
*/
extern JS_PUBLIC_API JSFunction* NewFunctionFromSpec(JSContext* cx,
const JSFunctionSpec* fs);
} /* namespace JS */
extern JS_PUBLIC_API JSObject* JS_GetFunctionObject(JSFunction* fun);
/**
* Return the function's identifier as a JSString, or null if fun is unnamed.
* The returned string lives as long as fun, so you don't need to root a saved
* reference to it if fun is well-connected or rooted, and provided you bound
* the use of the saved reference by fun's lifetime.
*/
extern JS_PUBLIC_API JSString* JS_GetFunctionId(JSFunction* fun);
/**
* Return a function's display name. This is the defined name if one was given
* where the function was defined, or it could be an inferred name by the JS
* engine in the case that the function was defined to be anonymous. This can
* still return nullptr if a useful display name could not be inferred. The
* same restrictions on rooting as those in JS_GetFunctionId apply.
*/
extern JS_PUBLIC_API JSString* JS_GetFunctionDisplayId(JSFunction* fun);
/*
* Return the arity of fun, which includes default parameters and rest
* parameter. This can be used as `nargs` parameter for other functions.
*/
extern JS_PUBLIC_API uint16_t JS_GetFunctionArity(JSFunction* fun);
/*
* Return the length of fun, which is the original value of .length property.
*/
JS_PUBLIC_API bool JS_GetFunctionLength(JSContext* cx, JS::HandleFunction fun,
uint16_t* length);
/**
* Infallible predicate to test whether obj is a function object (faster than
* comparing obj's class name to "Function", but equivalent unless someone has
* overwritten the "Function" identifier with a different constructor and then
* created instances using that constructor that might be passed in as obj).
*/
extern JS_PUBLIC_API bool JS_ObjectIsFunction(JSObject* obj);
extern JS_PUBLIC_API bool JS_IsNativeFunction(JSObject* funobj, JSNative call);
/** Return whether the given function is a valid constructor. */
extern JS_PUBLIC_API bool JS_IsConstructor(JSFunction* fun);
extern JS_PUBLIC_API bool JS_IsFunctionBound(JSFunction* fun);
extern JS_PUBLIC_API JSObject* JS_GetBoundFunctionTarget(JSFunction* fun);
extern JS_PUBLIC_API JSObject* JS_GetGlobalFromScript(JSScript* script);
extern JS_PUBLIC_API const char* JS_GetScriptFilename(JSScript* script);
extern JS_PUBLIC_API unsigned JS_GetScriptBaseLineNumber(JSContext* cx,
JSScript* script);
extern JS_PUBLIC_API JSScript* JS_GetFunctionScript(JSContext* cx,
JS::HandleFunction fun);
extern JS_PUBLIC_API JSString* JS_DecompileScript(JSContext* cx,
JS::Handle<JSScript*> script);
extern JS_PUBLIC_API JSString* JS_DecompileFunction(
JSContext* cx, JS::Handle<JSFunction*> fun);
namespace JS {
/**
* Set a private value associated with a script. Note that this value is shared
* by all nested scripts compiled from a single source file.
*/
extern JS_PUBLIC_API void SetScriptPrivate(JSScript* script,
const JS::Value& value);
/**
* Get the private value associated with a script. Note that this value is
* shared by all nested scripts compiled from a single source file.
*/
extern JS_PUBLIC_API JS::Value GetScriptPrivate(JSScript* script);
/*
* Return the private value associated with currently executing script or
* module, or undefined if there is no such script.
*/
extern JS_PUBLIC_API JS::Value GetScriptedCallerPrivate(JSContext* cx);
/**
* Hooks called when references to a script private value are created or
* destroyed. This allows use of a reference counted object as the
* script private.
*/
using ScriptPrivateReferenceHook = void (*)(const JS::Value&);
/**
* Set the script private finalize hook for the runtime to the given function.
*/
extern JS_PUBLIC_API void SetScriptPrivateReferenceHooks(
JSRuntime* rt, ScriptPrivateReferenceHook addRefHook,
ScriptPrivateReferenceHook releaseHook);
} /* namespace JS */
extern JS_PUBLIC_API bool JS_CheckForInterrupt(JSContext* cx);
/*
* These functions allow setting an interrupt callback that will be called
* from the JS thread some time after any thread triggered the callback using
* JS_RequestInterruptCallback(cx).
*
* To schedule the GC and for other activities the engine internally triggers
* interrupt callbacks. The embedding should thus not rely on callbacks being
* triggered through the external API only.
*
* Important note: Additional callbacks can occur inside the callback handler
* if it re-enters the JS engine. The embedding must ensure that the callback
* is disconnected before attempting such re-entry.
*/
extern JS_PUBLIC_API bool JS_AddInterruptCallback(JSContext* cx,
JSInterruptCallback callback);
extern JS_PUBLIC_API bool JS_DisableInterruptCallback(JSContext* cx);
extern JS_PUBLIC_API void JS_ResetInterruptCallback(JSContext* cx, bool enable);
extern JS_PUBLIC_API void JS_RequestInterruptCallback(JSContext* cx);
extern JS_PUBLIC_API void JS_RequestInterruptCallbackCanWait(JSContext* cx);
namespace JS {
/**
* The ConsumeStreamCallback is called from an active JSContext, passing a
* StreamConsumer that wishes to consume the given host object as a stream of
* bytes with the given MIME type. On failure, the embedding must report the
* appropriate error on 'cx'. On success, the embedding must call
* consumer->consumeChunk() repeatedly on any thread until exactly one of:
* - consumeChunk() returns false
* - the embedding calls consumer->streamEnd()
* - the embedding calls consumer->streamError()
* before JS_DestroyContext(cx) or JS::ShutdownAsyncTasks(cx) is called.
*
* Note: consumeChunk(), streamEnd() and streamError() may be called
* synchronously by ConsumeStreamCallback.
*
* When streamEnd() is called, the embedding may optionally pass an
* OptimizedEncodingListener*, indicating that there is a cache entry associated
* with this stream that can store an optimized encoding of the bytes that were
* just streamed at some point in the future by having SpiderMonkey call
* storeOptimizedEncoding(). Until the optimized encoding is ready, SpiderMonkey
* will hold an outstanding refcount to keep the listener alive.
*
* After storeOptimizedEncoding() is called, on cache hit, the embedding
* may call consumeOptimizedEncoding() instead of consumeChunk()/streamEnd().
* The embedding must ensure that the GetOptimizedEncodingBuildId() (see
* js/BuildId.h) at the time when an optimized encoding is created is the same
* as when it is later consumed.
*/
using OptimizedEncodingBytes = js::Vector<uint8_t, 0, js::SystemAllocPolicy>;
using UniqueOptimizedEncodingBytes = js::UniquePtr<OptimizedEncodingBytes>;
class OptimizedEncodingListener {
protected:
virtual ~OptimizedEncodingListener() = default;
public:
// SpiderMonkey will hold an outstanding reference count as long as it holds
// a pointer to OptimizedEncodingListener.
virtual MozExternalRefCountType MOZ_XPCOM_ABI AddRef() = 0;
virtual MozExternalRefCountType MOZ_XPCOM_ABI Release() = 0;
// SpiderMonkey may optionally call storeOptimizedEncoding() after it has
// finished processing a streamed resource.
virtual void storeOptimizedEncoding(UniqueOptimizedEncodingBytes bytes) = 0;
};
class JS_PUBLIC_API StreamConsumer {
protected:
// AsyncStreamConsumers are created and destroyed by SpiderMonkey.
StreamConsumer() = default;
virtual ~StreamConsumer() = default;
public:
// Called by the embedding as each chunk of bytes becomes available.
// If this function returns 'false', the stream must drop all pointers to
// this StreamConsumer.
virtual bool consumeChunk(const uint8_t* begin, size_t length) = 0;
// Called by the embedding when the stream reaches end-of-file, passing the
// listener described above.
virtual void streamEnd(OptimizedEncodingListener* listener = nullptr) = 0;
// Called by the embedding when there is an error during streaming. The
// given error code should be passed to the ReportStreamErrorCallback on the
// main thread to produce the semantically-correct rejection value.
virtual void streamError(size_t errorCode) = 0;
// Called by the embedding *instead of* consumeChunk()/streamEnd() if an
// optimized encoding is available from a previous streaming of the same
// contents with the same optimized build id.
virtual void consumeOptimizedEncoding(const uint8_t* begin,
size_t length) = 0;
// Provides optional stream attributes such as base or source mapping URLs.
// Necessarily called before consumeChunk(), streamEnd(), streamError() or
// consumeOptimizedEncoding(). The caller retains ownership of the strings.
virtual void noteResponseURLs(const char* maybeUrl,
const char* maybeSourceMapUrl) = 0;
};
enum class MimeType { Wasm };
using ConsumeStreamCallback = bool (*)(JSContext*, JS::HandleObject, MimeType,
StreamConsumer*);
using ReportStreamErrorCallback = void (*)(JSContext*, size_t);
extern JS_PUBLIC_API void InitConsumeStreamCallback(
JSContext* cx, ConsumeStreamCallback consume,
ReportStreamErrorCallback report);
/**
* Supply an alternative stack to incorporate into captured SavedFrame
* backtraces as the imputed caller of asynchronous JavaScript calls, like async
* function resumptions and DOM callbacks.
*
* When one async function awaits the result of another, it's natural to think
* of that as a sort of function call: just as execution resumes from an
* ordinary call expression when the callee returns, with the return value
* providing the value of the call expression, execution resumes from an 'await'
* expression after the awaited asynchronous function call returns, passing the
* return value along.
*
* Call the two async functions in such a situation the 'awaiter' and the
* 'awaitee'.
*
* As an async function, the awaitee contains 'await' expressions of its own.
* Whenever it executes after its first 'await', there are never any actual
* frames on the JavaScript stack under it; its awaiter is certainly not there.
* An await expression's continuation is invoked as a promise callback, and
* those are always called directly from the event loop in their own microtick.
* (Ignore unusual cases like nested event loops.)
*
* But because await expressions bear such a strong resemblance to calls (and
* deliberately so!), it would be unhelpful for stacks captured within the
* awaitee to be empty; instead, they should present the awaiter as the caller.
*
* The AutoSetAsyncStackForNewCalls RAII class supplies a SavedFrame stack to
* treat as the caller of any JavaScript invocations that occur within its
* lifetime. Any SavedFrame stack captured during such an invocation uses the
* SavedFrame passed to the constructor's 'stack' parameter as the 'asyncParent'
* property of the SavedFrame for the invocation's oldest frame. Its 'parent'
* property will be null, so stack-walking code can distinguish this
* awaiter/awaitee transition from an ordinary caller/callee transition.
*
* The constructor's 'asyncCause' parameter supplies a string explaining what
* sort of asynchronous call caused 'stack' to be spliced into the backtrace;
* for example, async function resumptions use the string "async". This appears
* as the 'asyncCause' property of the 'asyncParent' SavedFrame.
*
* Async callers are distinguished in the string form of a SavedFrame chain by
* including the 'asyncCause' string in the frame. It appears before the
* function name, with the two separated by a '*'.
*
* Note that, as each compartment has its own set of SavedFrames, the
* 'asyncParent' may actually point to a copy of 'stack', rather than the exact
* SavedFrame object passed.
*
* The youngest frame of 'stack' is not mutated to take the asyncCause string as
* its 'asyncCause' property; SavedFrame objects are immutable. Rather, a fresh
* clone of the frame is created with the needed 'asyncCause' property.
*
* The 'kind' argument specifies how aggressively 'stack' supplants any
* JavaScript frames older than this AutoSetAsyncStackForNewCalls object. If
* 'kind' is 'EXPLICIT', then all captured SavedFrame chains take on 'stack' as
* their 'asyncParent' where the chain crosses this object's scope. If 'kind' is
* 'IMPLICIT', then 'stack' is only included in captured chains if there are no
* other JavaScript frames on the stack --- that is, only if the stack would
* otherwise end at that point.
*
* AutoSetAsyncStackForNewCalls affects only SavedFrame chains; it does not
* affect Debugger.Frame or js::FrameIter. SavedFrame chains are used for
* Error.stack, allocation profiling, Promise debugging, and so on.
*
* See also `js/src/doc/SavedFrame/SavedFrame.md` for documentation on async
* stack frames.
*/
class MOZ_STACK_CLASS JS_PUBLIC_API AutoSetAsyncStackForNewCalls {
JSContext* cx;
RootedObject oldAsyncStack;
const char* oldAsyncCause;
bool oldAsyncCallIsExplicit;
public:
enum class AsyncCallKind {
// The ordinary kind of call, where we may apply an async
// parent if there is no ordinary parent.
IMPLICIT,
// An explicit async parent, e.g., callFunctionWithAsyncStack,
// where we always want to override any ordinary parent.
EXPLICIT
};
// The stack parameter cannot be null by design, because it would be
// ambiguous whether that would clear any scheduled async stack and make the
// normal stack reappear in the new call, or just keep the async stack
// already scheduled for the new call, if any.
//
// asyncCause is owned by the caller and its lifetime must outlive the
// lifetime of the AutoSetAsyncStackForNewCalls object. It is strongly
// encouraged that asyncCause be a string constant or similar statically
// allocated string.
AutoSetAsyncStackForNewCalls(JSContext* cx, HandleObject stack,
const char* asyncCause,
AsyncCallKind kind = AsyncCallKind::IMPLICIT);
~AutoSetAsyncStackForNewCalls();
};
} // namespace JS
/************************************************************************/
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 */
/************************************************************************/
/**
* 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);
/************************************************************************/
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(IC_FORCE_MEGAMORPHIC, "ic.force-megamorphic") \
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(INLINING_BYTECODE_MAX_LENGTH, "inlining.bytecode-max-length") \
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, "spectre.object-mitigations") \
Register(SPECTRE_STRING_MITIGATIONS, "spectre.string-mitigations") \
Register(SPECTRE_VALUE_MASKING, "spectre.value-masking") \
Register(SPECTRE_JIT_TO_CXX_CALLS, "spectre.jit-to-cxx-calls") \
Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") \
Register(WASM_DELAY_TIER2, "wasm.delay-tier2") \
Register(WASM_JIT_BASELINE, "wasm.baseline") \
Register(WASM_JIT_OPTIMIZING, "wasm.optimizing") \
// clang-format on
typedef enum JSJitCompilerOption {
#define JIT_COMPILER_DECLARE(key, str) JSJITCOMPILER_##key,
JIT_COMPILER_OPTIONS(JIT_COMPILER_DECLARE)
#undef JIT_COMPILER_DECLARE
JSJITCOMPILER_NOT_AN_OPTION
} JSJitCompilerOption;
extern JS_PUBLIC_API void JS_SetGlobalJitCompilerOption(JSContext* cx,
JSJitCompilerOption opt,
uint32_t value);
extern JS_PUBLIC_API bool JS_GetGlobalJitCompilerOption(JSContext* cx,
JSJitCompilerOption opt,
uint32_t* valueOut);
/**
* Convert a uint32_t index into a jsid.
*/
extern JS_PUBLIC_API bool JS_IndexToId(JSContext* cx, uint32_t index,
JS::MutableHandleId);
/**
* Convert chars into a jsid.
*
* |chars| may not be an index.
*/
extern JS_PUBLIC_API bool JS_CharsToId(JSContext* cx, JS::TwoByteChars chars,
JS::MutableHandleId);
/**
* Test if the given string is a valid ECMAScript identifier
*/
extern JS_PUBLIC_API bool JS_IsIdentifier(JSContext* cx, JS::HandleString str,
bool* isIdentifier);
/**
* Test whether the given chars + length are a valid ECMAScript identifier.
* This version is infallible, so just returns whether the chars are an
* identifier.
*/
extern JS_PUBLIC_API bool JS_IsIdentifier(const char16_t* chars, size_t length);
namespace js {
class ScriptSource;
} // namespace js
namespace JS {
class MOZ_RAII JS_PUBLIC_API AutoFilename {
private:
js::ScriptSource* ss_;
mozilla::Variant<const char*, UniqueChars> filename_;
AutoFilename(const AutoFilename&) = delete;
AutoFilename& operator=(const AutoFilename&) = delete;
public:
AutoFilename()
: ss_(nullptr), filename_(mozilla::AsVariant<const char*>(nullptr)) {}
~AutoFilename() { reset(); }
void reset();
void setOwned(UniqueChars&& filename);
void setUnowned(const char* filename);
void setScriptSource(js::ScriptSource* ss);
const char* get() const;
};
/**
* Return the current filename, line number and column number of the most
* currently running frame. Returns true if a scripted frame was found, false
* otherwise.
*
* If a the embedding has hidden the scripted caller for the topmost activation
* record, this will also return false.
*/
extern JS_PUBLIC_API bool DescribeScriptedCaller(
JSContext* cx, AutoFilename* filename = nullptr, unsigned* lineno = nullptr,
unsigned* column = nullptr);
extern JS_PUBLIC_API JSObject* GetScriptedCallerGlobal(JSContext* cx);
/**
* Informs the JS engine that the scripted caller should be hidden. This can be
* used by the embedding to maintain an override of the scripted caller in its
* calculations, by hiding the scripted caller in the JS engine and pushing data
* onto a separate stack, which it inspects when DescribeScriptedCaller returns
* null.
*
* We maintain a counter on each activation record. Add() increments the counter
* of the topmost activation, and Remove() decrements it. The count may never
* drop below zero, and must always be exactly zero when the activation is
* popped from the stack.
*/
extern JS_PUBLIC_API void HideScriptedCaller(JSContext* cx);
extern JS_PUBLIC_API void UnhideScriptedCaller(JSContext* cx);
class MOZ_RAII AutoHideScriptedCaller {
public:
explicit AutoHideScriptedCaller(JSContext* cx) : mContext(cx) {
HideScriptedCaller(mContext);
}
~AutoHideScriptedCaller() { UnhideScriptedCaller(mContext); }
protected:
JSContext* mContext;
};
} /* namespace JS */
namespace js {
enum class StackFormat { SpiderMonkey, V8, Default };
/*
* Sets the format used for stringifying Error stacks.
*
* The default format is StackFormat::SpiderMonkey. Use StackFormat::V8
* in order to emulate V8's stack formatting. StackFormat::Default can't be
* used here.
*/
extern JS_PUBLIC_API void SetStackFormat(JSContext* cx, StackFormat format);
extern JS_PUBLIC_API StackFormat GetStackFormat(JSContext* cx);
} // namespace js
namespace JS {
/**
* Attempt to disable Wasm's usage of reserving a large virtual memory
* allocation to avoid bounds checking overhead. This must be called before any
* Wasm module or memory is created in this process, or else this function will
* fail.
*/
[[nodiscard]] extern JS_PUBLIC_API bool DisableWasmHugeMemory();
/**
* If a large allocation fails when calling pod_{calloc,realloc}CanGC, the JS
* engine may call the large-allocation-failure callback, if set, to allow the
* embedding to flush caches, possibly perform shrinking GCs, etc. to make some
* room. The allocation will then be retried (and may still fail.) This callback
* can be called on any thread and must be set at most once in a process.
*/
using LargeAllocationFailureCallback = void (*)();
extern JS_PUBLIC_API void SetProcessLargeAllocationFailureCallback(
LargeAllocationFailureCallback afc);
/**
* Unlike the error reporter, which is only called if the exception for an OOM
* bubbles up and is not caught, the OutOfMemoryCallback is called immediately
* at the OOM site to allow the embedding to capture the current state of heap
* allocation before anything is freed. If the large-allocation-failure callback
* is called at all (not all allocation sites call the large-allocation-failure
* callback on failure), it is called before the out-of-memory callback; the
* out-of-memory callback is only called if the allocation still fails after the
* large-allocation-failure callback has returned.
*/
using OutOfMemoryCallback = void (*)(JSContext*, void*);
extern JS_PUBLIC_API void SetOutOfMemoryCallback(JSContext* cx,
OutOfMemoryCallback cb,
void* data);
/**
* When the JSRuntime is about to block in an Atomics.wait() JS call or in a
* `wait` instruction in WebAssembly, it can notify the host by means of a call
* to BeforeWaitCallback. After the wait, it can notify the host by means of a
* call to AfterWaitCallback. Both callbacks must be null, or neither.
*
* (If you change the callbacks from null to not-null or vice versa while some
* thread on the runtime is in a wait, you will be sorry.)
*
* The argument to the BeforeWaitCallback is a pointer to uninitialized
* stack-allocated working memory of size WAIT_CALLBACK_CLIENT_MAXMEM bytes.
* The caller of SetWaitCallback() must pass the amount of memory it will need,
* and this amount will be checked against that limit and the process will crash
* reliably if the check fails.
*
* The value returned by the BeforeWaitCallback will be passed to the
* AfterWaitCallback.
*
* The AfterWaitCallback will be called even if the wakeup is spurious and the
* thread goes right back to waiting again. Of course the thread will call the
* BeforeWaitCallback once more before it goes to sleep in this situation.
*/
static constexpr size_t WAIT_CALLBACK_CLIENT_MAXMEM = 32;
using BeforeWaitCallback = void* (*)(uint8_t* memory);
using AfterWaitCallback = void (*)(void* cookie);
extern JS_PUBLIC_API void SetWaitCallback(JSRuntime* rt,
BeforeWaitCallback beforeWait,
AfterWaitCallback afterWait,
size_t requiredMemory);
/**
* Capture all frames.
*/
struct AllFrames {};
/**
* Capture at most this many frames.
*/
struct MaxFrames {
uint32_t maxFrames;
explicit MaxFrames(uint32_t max) : maxFrames(max) { MOZ_ASSERT(max > 0); }
};
/**
* Capture the first frame with the given principals. By default, do not
* consider self-hosted frames with the given principals as satisfying the stack
* capture.
*/
struct JS_PUBLIC_API FirstSubsumedFrame {
JSContext* cx;
JSPrincipals* principals;
bool ignoreSelfHosted;
/**
* Use the cx's current compartment's principals.
*/
explicit FirstSubsumedFrame(JSContext* cx,
bool ignoreSelfHostedFrames = true);
explicit FirstSubsumedFrame(JSContext* ctx, JSPrincipals* p,
bool ignoreSelfHostedFrames = true)
: cx(ctx), principals(p), ignoreSelfHosted(ignoreSelfHostedFrames) {
if (principals) {
JS_HoldPrincipals(principals);
}
}
// No copying because we want to avoid holding and dropping principals
// unnecessarily.
FirstSubsumedFrame(const FirstSubsumedFrame&) = delete;
FirstSubsumedFrame& operator=(const FirstSubsumedFrame&) = delete;
FirstSubsumedFrame(FirstSubsumedFrame&& rhs)
: principals(rhs.principals), ignoreSelfHosted(rhs.ignoreSelfHosted) {
MOZ_ASSERT(this != &rhs, "self move disallowed");
rhs.principals = nullptr;
}
FirstSubsumedFrame& operator=(FirstSubsumedFrame&& rhs) {
new (this) FirstSubsumedFrame(std::move(rhs));
return *this;
}
~FirstSubsumedFrame() {
if (principals) {
JS_DropPrincipals(cx, principals);
}
}
};
using StackCapture = mozilla::Variant<AllFrames, MaxFrames, FirstSubsumedFrame>;
/**
* Capture the current call stack as a chain of SavedFrame JSObjects, and set
* |stackp| to the SavedFrame for the youngest stack frame, or nullptr if there
* are no JS frames on the stack.
*
* The |capture| parameter describes the portion of the JS stack to capture:
*
* * |JS::AllFrames|: Capture all frames on the stack.
*
* * |JS::MaxFrames|: Capture no more than |JS::MaxFrames::maxFrames| from the
* stack.
*
* * |JS::FirstSubsumedFrame|: Capture the first frame whose principals are
* subsumed by |JS::FirstSubsumedFrame::principals|. By default, do not
* consider self-hosted frames; this can be controlled via the
* |JS::FirstSubsumedFrame::ignoreSelfHosted| flag. Do not capture any async
* stack.
*/
extern JS_PUBLIC_API bool CaptureCurrentStack(
JSContext* cx, MutableHandleObject stackp,
StackCapture&& capture = StackCapture(AllFrames()));
/**
* Returns true if capturing stack trace data to associate with an asynchronous
* operation is currently enabled for the current context realm.
*
* Users should check this state before capturing a stack that will be passed
* back to AutoSetAsyncStackForNewCalls later, in order to avoid capturing a
* stack for async use when we don't actually want to capture it.
*/
extern JS_PUBLIC_API bool IsAsyncStackCaptureEnabledForRealm(JSContext* cx);
/*
* This is a utility function for preparing an async stack to be used
* by some other object. This may be used when you need to treat a
* given stack trace as an async parent. If you just need to capture
* the current stack, async parents and all, use CaptureCurrentStack
* instead.
*
* Here |asyncStack| is the async stack to prepare. It is copied into
* |cx|'s current compartment, and the newest frame is given
* |asyncCause| as its asynchronous cause. If |maxFrameCount| is
* |Some(n)|, capture at most the youngest |n| frames. The
* new stack object is written to |stackp|. Returns true on success,
* or sets an exception and returns |false| on error.
*/
extern JS_PUBLIC_API bool CopyAsyncStack(
JSContext* cx, HandleObject asyncStack, HandleString asyncCause,
MutableHandleObject stackp, const mozilla::Maybe<size_t>& maxFrameCount);
/**
* Given a SavedFrame JSObject stack, stringify it in the same format as
* Error.prototype.stack. The stringified stack out parameter is placed in the
* cx's compartment. Defaults to the empty string.
*
* The same notes above about SavedFrame accessors applies here as well: cx
* doesn't need to be in stack's compartment, and stack can be null, a
* SavedFrame object, or a wrapper (CCW or Xray) around a SavedFrame object.
* SavedFrames not subsumed by |principals| are skipped.
*
* Optional indent parameter specifies the number of white spaces to indent
* each line.
*/
extern JS_PUBLIC_API bool BuildStackString(
JSContext* cx, JSPrincipals* principals, HandleObject stack,
MutableHandleString stringp, size_t indent = 0,
js::StackFormat stackFormat = js::StackFormat::Default);
/**
* Return true iff the given object is either a SavedFrame object or wrapper
* around a SavedFrame object, and it is not the SavedFrame.prototype object.
*/
extern JS_PUBLIC_API bool IsMaybeWrappedSavedFrame(JSObject* obj);
/**
* Return true iff the given object is a SavedFrame object and not the
* SavedFrame.prototype object.
*/
extern JS_PUBLIC_API bool IsUnwrappedSavedFrame(JSObject* obj);
} /* namespace JS */
namespace js {
/**
* Hint that we expect a crash. Currently, the only thing that cares is the
* breakpad injector, which (if loaded) will suppress minidump generation.
*/
extern JS_PUBLIC_API void NoteIntentionalCrash();
} /* namespace js */
namespace js {
enum class CompletionKind { Normal, Return, Throw };
} /* namespace js */
#ifdef DEBUG
namespace JS {
extern JS_PUBLIC_API void SetSupportDifferentialTesting(bool value);
}
#endif /* DEBUG */
#endif /* jsapi_h */