/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * 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/MemoryReporting.h" #include "mozilla/Range.h" #include "mozilla/RangedPtr.h" #include "mozilla/RefPtr.h" #include #include #include #include #include "jsalloc.h" #include "jspubtd.h" #include "js/CallArgs.h" #include "js/Class.h" #include "js/HashTable.h" #include "js/Id.h" #include "js/Principals.h" #include "js/RootingAPI.h" #include "js/TraceableVector.h" #include "js/TracingAPI.h" #include "js/Utility.h" #include "js/Value.h" #include "js/Vector.h" /************************************************************************/ namespace JS { class TwoByteChars; #ifdef JS_DEBUG class JS_PUBLIC_API(AutoCheckRequestDepth) { JSContext* cx; public: explicit AutoCheckRequestDepth(JSContext* cx); explicit AutoCheckRequestDepth(js::ContextFriendFields* cx); ~AutoCheckRequestDepth(); }; # define CHECK_REQUEST(cx) \ JS::AutoCheckRequestDepth _autoCheckRequestDepth(cx) #else # define CHECK_REQUEST(cx) \ ((void) 0) #endif /* JS_DEBUG */ /** AutoValueArray roots an internal fixed-size array of Values. */ template class MOZ_RAII AutoValueArray : public AutoGCRooter { const size_t length_; Value elements_[N]; public: explicit AutoValueArray(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, VALARRAY), length_(N) { /* Always initialize in case we GC before assignment. */ mozilla::PodArrayZero(elements_); MOZ_GUARD_OBJECT_NOTIFIER_INIT; } unsigned length() const { return length_; } const Value* begin() const { return elements_; } Value* begin() { return elements_; } HandleValue operator[](unsigned i) const { MOZ_ASSERT(i < N); return HandleValue::fromMarkedLocation(&elements_[i]); } MutableHandleValue operator[](unsigned i) { MOZ_ASSERT(i < N); return MutableHandleValue::fromMarkedLocation(&elements_[i]); } MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; template class MOZ_RAII AutoVectorRooterBase : protected AutoGCRooter { typedef js::Vector VectorImpl; VectorImpl vector; public: explicit AutoVectorRooterBase(JSContext* cx, ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, tag), vector(cx) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } explicit AutoVectorRooterBase(js::ContextFriendFields* cx, ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, tag), vector(cx) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } typedef T ElementType; typedef typename VectorImpl::Range Range; size_t length() const { return vector.length(); } bool empty() const { return vector.empty(); } bool append(const T& v) { return vector.append(v); } bool appendN(const T& v, size_t len) { return vector.appendN(v, len); } bool append(const T* ptr, size_t len) { return vector.append(ptr, len); } bool appendAll(const AutoVectorRooterBase& other) { return vector.appendAll(other.vector); } bool insert(T* p, const T& val) { return vector.insert(p, val); } /* For use when space has already been reserved. */ void infallibleAppend(const T& v) { vector.infallibleAppend(v); } void popBack() { vector.popBack(); } T popCopy() { return vector.popCopy(); } bool growBy(size_t inc) { size_t oldLength = vector.length(); if (!vector.growByUninitialized(inc)) return false; makeRangeGCSafe(oldLength); return true; } bool resize(size_t newLength) { size_t oldLength = vector.length(); if (newLength <= oldLength) { vector.shrinkBy(oldLength - newLength); return true; } if (!vector.growByUninitialized(newLength - oldLength)) return false; makeRangeGCSafe(oldLength); return true; } void clear() { vector.clear(); } bool reserve(size_t newLength) { return vector.reserve(newLength); } JS::MutableHandle operator[](size_t i) { return JS::MutableHandle::fromMarkedLocation(&vector[i]); } JS::Handle operator[](size_t i) const { return JS::Handle::fromMarkedLocation(&vector[i]); } const T* begin() const { return vector.begin(); } T* begin() { return vector.begin(); } const T* end() const { return vector.end(); } T* end() { return vector.end(); } Range all() { return vector.all(); } const T& back() const { return vector.back(); } friend void AutoGCRooter::trace(JSTracer* trc); private: void makeRangeGCSafe(size_t oldLength) { T* t = vector.begin() + oldLength; for (size_t i = oldLength; i < vector.length(); ++i, ++t) memset(t, 0, sizeof(T)); } MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; template class MOZ_RAII AutoVectorRooter : public AutoVectorRooterBase { public: explicit AutoVectorRooter(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoVectorRooterBase(cx, this->GetTag(T())) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } explicit AutoVectorRooter(js::ContextFriendFields* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoVectorRooterBase(cx, this->GetTag(T())) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; typedef AutoVectorRooter AutoValueVector; typedef AutoVectorRooter AutoIdVector; typedef AutoVectorRooter AutoObjectVector; using ValueVector = js::TraceableVector; using IdVector = js::TraceableVector; using ScriptVector = js::TraceableVector; template class MOZ_RAII AutoHashMapRooter : protected AutoGCRooter { private: typedef js::HashMap HashMapImpl; public: explicit AutoHashMapRooter(JSContext* cx, ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, tag), map(cx) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } typedef Key KeyType; typedef Value ValueType; typedef typename HashMapImpl::Entry Entry; typedef typename HashMapImpl::Lookup Lookup; typedef typename HashMapImpl::Ptr Ptr; typedef typename HashMapImpl::AddPtr AddPtr; bool init(uint32_t len = 16) { return map.init(len); } bool initialized() const { return map.initialized(); } Ptr lookup(const Lookup& l) const { return map.lookup(l); } void remove(Ptr p) { map.remove(p); } AddPtr lookupForAdd(const Lookup& l) const { return map.lookupForAdd(l); } template bool add(AddPtr& p, const KeyInput& k, const ValueInput& v) { return map.add(p, k, v); } bool add(AddPtr& p, const Key& k) { return map.add(p, k); } template bool relookupOrAdd(AddPtr& p, const KeyInput& k, const ValueInput& v) { return map.relookupOrAdd(p, k, v); } typedef typename HashMapImpl::Range Range; Range all() const { return map.all(); } typedef typename HashMapImpl::Enum Enum; void clear() { map.clear(); } void finish() { map.finish(); } bool empty() const { return map.empty(); } uint32_t count() const { return map.count(); } size_t capacity() const { return map.capacity(); } size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return map.sizeOfExcludingThis(mallocSizeOf); } size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return map.sizeOfIncludingThis(mallocSizeOf); } /************************************************** Shorthand operations */ bool has(const Lookup& l) const { return map.has(l); } template bool put(const KeyInput& k, const ValueInput& v) { return map.put(k, v); } template bool putNew(const KeyInput& k, const ValueInput& v) { return map.putNew(k, v); } Ptr lookupWithDefault(const Key& k, const Value& defaultValue) { return map.lookupWithDefault(k, defaultValue); } void remove(const Lookup& l) { map.remove(l); } friend void AutoGCRooter::trace(JSTracer* trc); private: AutoHashMapRooter(const AutoHashMapRooter& hmr) = delete; AutoHashMapRooter& operator=(const AutoHashMapRooter& hmr) = delete; HashMapImpl map; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; template class MOZ_RAII AutoHashSetRooter : protected AutoGCRooter { private: typedef js::HashSet HashSetImpl; public: explicit AutoHashSetRooter(JSContext* cx, ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, tag), set(cx) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } typedef typename HashSetImpl::Lookup Lookup; typedef typename HashSetImpl::Ptr Ptr; typedef typename HashSetImpl::AddPtr AddPtr; bool init(uint32_t len = 16) { return set.init(len); } bool initialized() const { return set.initialized(); } Ptr lookup(const Lookup& l) const { return set.lookup(l); } void remove(Ptr p) { set.remove(p); } AddPtr lookupForAdd(const Lookup& l) const { return set.lookupForAdd(l); } bool add(AddPtr& p, const T& t) { return set.add(p, t); } bool relookupOrAdd(AddPtr& p, const Lookup& l, const T& t) { return set.relookupOrAdd(p, l, t); } typedef typename HashSetImpl::Range Range; Range all() const { return set.all(); } typedef typename HashSetImpl::Enum Enum; void clear() { set.clear(); } void finish() { set.finish(); } bool empty() const { return set.empty(); } uint32_t count() const { return set.count(); } size_t capacity() const { return set.capacity(); } size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return set.sizeOfExcludingThis(mallocSizeOf); } size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { return set.sizeOfIncludingThis(mallocSizeOf); } /************************************************** Shorthand operations */ bool has(const Lookup& l) const { return set.has(l); } bool put(const T& t) { return set.put(t); } bool putNew(const T& t) { return set.putNew(t); } void remove(const Lookup& l) { set.remove(l); } friend void AutoGCRooter::trace(JSTracer* trc); private: AutoHashSetRooter(const AutoHashSetRooter& hmr) = delete; AutoHashSetRooter& operator=(const AutoHashSetRooter& hmr) = delete; HashSetImpl set; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /** * Custom rooting behavior for internal and external clients. */ class MOZ_RAII JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter { public: template explicit CustomAutoRooter(CX* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, CUSTOM) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } friend void AutoGCRooter::trace(JSTracer* trc); protected: /** Supplied by derived class to trace roots. */ virtual void trace(JSTracer* trc) = 0; private: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /** A handle to an array of rooted values. */ class HandleValueArray { const size_t length_; const Value * const elements_; HandleValueArray(size_t len, const Value* elements) : length_(len), elements_(elements) {} public: explicit HandleValueArray(const RootedValue& value) : length_(1), elements_(value.address()) {} MOZ_IMPLICIT HandleValueArray(const AutoValueVector& values) : length_(values.length()), elements_(values.begin()) {} template MOZ_IMPLICIT HandleValueArray(const AutoValueArray& values) : length_(N), elements_(values.begin()) {} /** CallArgs must already be rooted somewhere up the stack. */ MOZ_IMPLICIT HandleValueArray(const JS::CallArgs& args) : length_(args.length()), elements_(args.array()) {} /** Use with care! Only call this if the data is guaranteed to be marked. */ static HandleValueArray fromMarkedLocation(size_t len, const Value* elements) { return HandleValueArray(len, elements); } static HandleValueArray subarray(const HandleValueArray& values, size_t startIndex, size_t len) { MOZ_ASSERT(startIndex + len <= values.length()); return HandleValueArray(len, values.begin() + startIndex); } static HandleValueArray empty() { return HandleValueArray(0, nullptr); } size_t length() const { return length_; } const Value* begin() const { return elements_; } HandleValue operator[](size_t i) const { MOZ_ASSERT(i < length_); return HandleValue::fromMarkedLocation(&elements_[i]); } }; } /* namespace JS */ /************************************************************************/ struct JSFreeOp { private: JSRuntime* runtime_; protected: explicit JSFreeOp(JSRuntime* rt) : runtime_(rt) { } public: JSRuntime* runtime() const { return runtime_; } }; /* Callbacks and their arguments. */ /************************************************************************/ typedef enum JSContextOp { JSCONTEXT_NEW, JSCONTEXT_DESTROY } JSContextOp; /** * The possible values for contextOp when the runtime calls the callback are: * JSCONTEXT_NEW JS_NewContext successfully created a new JSContext * instance. The callback can initialize the instance as * required. If the callback returns false, the instance * will be destroyed and JS_NewContext returns null. In * this case the callback is not called again. * JSCONTEXT_DESTROY One of JS_DestroyContext* methods is called. The * callback may perform its own cleanup and must always * return true. * Any other value For future compatibility the callback must do nothing * and return true in this case. */ typedef bool (* JSContextCallback)(JSContext* cx, unsigned contextOp, void* data); typedef enum JSGCStatus { JSGC_BEGIN, JSGC_END } JSGCStatus; typedef void (* JSGCCallback)(JSRuntime* rt, JSGCStatus status, void* data); typedef enum JSFinalizeStatus { /** * Called when preparing to sweep a group of compartments, before anything * has been swept. The collector will not yield to the mutator before * calling the callback with JSFINALIZE_GROUP_END status. */ JSFINALIZE_GROUP_START, /** * Called when preparing to sweep a group of compartments. Weak references * to unmarked things have been removed and things that are not swept * incrementally have been finalized at this point. The collector may yield * to the mutator after this point. */ JSFINALIZE_GROUP_END, /** * Called at the end of collection when everything has been swept. */ JSFINALIZE_COLLECTION_END } JSFinalizeStatus; typedef void (* JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, bool isCompartment, void* data); typedef void (* JSWeakPointerZoneGroupCallback)(JSRuntime* rt, void* data); typedef void (* JSWeakPointerCompartmentCallback)(JSRuntime* rt, JSCompartment* comp, void* data); typedef bool (* JSInterruptCallback)(JSContext* cx); typedef void (* JSErrorReporter)(JSContext* cx, const char* message, JSErrorReport* report); /** * Possible exception types. These types are part of a JSErrorFormatString * structure. They define which error to throw in case of a runtime error. * JSEXN_NONE marks an unthrowable error. */ typedef enum JSExnType { JSEXN_NONE = -1, JSEXN_ERR, JSEXN_INTERNALERR, JSEXN_EVALERR, JSEXN_RANGEERR, JSEXN_REFERENCEERR, JSEXN_SYNTAXERR, JSEXN_TYPEERR, JSEXN_URIERR, JSEXN_LIMIT } JSExnType; typedef struct JSErrorFormatString { /** The error format string in ASCII. */ const char* format; /** The number of arguments to expand in the formatted error message. */ uint16_t argCount; /** One of the JSExnType constants above. */ int16_t exnType; } JSErrorFormatString; typedef const JSErrorFormatString* (* JSErrorCallback)(void* userRef, const unsigned errorNumber); typedef bool (* JSLocaleToUpperCase)(JSContext* cx, JS::HandleString src, JS::MutableHandleValue rval); typedef bool (* JSLocaleToLowerCase)(JSContext* cx, JS::HandleString src, JS::MutableHandleValue rval); typedef bool (* JSLocaleCompare)(JSContext* cx, JS::HandleString src1, JS::HandleString src2, JS::MutableHandleValue rval); typedef bool (* JSLocaleToUnicode)(JSContext* cx, const char* src, JS::MutableHandleValue rval); /** * 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. */ typedef JSObject* (* JSWrapObjectCallback)(JSContext* cx, JS::HandleObject existing, JS::HandleObject obj); /** * 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. */ typedef JSObject* (* JSPreWrapCallback)(JSContext* cx, JS::HandleObject scope, JS::HandleObject obj, JS::HandleObject objectPassedToWrap); struct JSWrapObjectCallbacks { JSWrapObjectCallback wrap; JSPreWrapCallback preWrap; }; typedef void (* JSDestroyCompartmentCallback)(JSFreeOp* fop, JSCompartment* compartment); typedef void (* JSZoneCallback)(JS::Zone* zone); typedef void (* JSCompartmentNameCallback)(JSRuntime* rt, JSCompartment* compartment, char* buf, size_t bufsize); /************************************************************************/ 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); namespace JS { /** * Container class for passing in script source buffers to the JS engine. This * not only groups the buffer and length values, it also provides a way to * optionally pass ownership of the buffer to the JS engine without copying. * Rules for use: * * 1) The data array must be allocated with js_malloc() or js_realloc() if * ownership is being granted to the SourceBufferHolder. * 2) If ownership is not given to the SourceBufferHolder, then the memory * must be kept alive until the JS compilation is complete. * 3) Any code calling SourceBufferHolder::take() must guarantee to keep the * memory alive until JS compilation completes. Normally only the JS * engine should be calling take(). * * Example use: * * size_t length = 512; * char16_t* chars = static_cast(js_malloc(sizeof(char16_t) * length)); * JS::SourceBufferHolder srcBuf(chars, length, JS::SourceBufferHolder::GiveOwnership); * JS::Compile(cx, options, srcBuf); */ class MOZ_STACK_CLASS SourceBufferHolder final { public: enum Ownership { NoOwnership, GiveOwnership }; SourceBufferHolder(const char16_t* data, size_t dataLength, Ownership ownership) : data_(data), length_(dataLength), ownsChars_(ownership == GiveOwnership) { // Ensure that null buffers properly return an unowned, empty, // null-terminated string. static const char16_t NullChar_ = 0; if (!get()) { data_ = &NullChar_; length_ = 0; ownsChars_ = false; } } ~SourceBufferHolder() { if (ownsChars_) js_free(const_cast(data_)); } // Access the underlying source buffer without affecting ownership. const char16_t* get() const { return data_; } // Length of the source buffer in char16_t code units (not bytes) size_t length() const { return length_; } // Returns true if the SourceBufferHolder owns the buffer and will free // it upon destruction. If true, it is legal to call take(). bool ownsChars() const { return ownsChars_; } // Retrieve and take ownership of the underlying data buffer. The caller // is now responsible for calling js_free() on the returned value, *but only // after JS script compilation has completed*. // // After the buffer has been taken the SourceBufferHolder functions as if // it had been constructed on an unowned buffer; get() and length() still // work. In order for this to be safe the taken buffer must be kept alive // until after JS script compilation completes as noted above. // // Note, it's the caller's responsibility to check ownsChars() before taking // the buffer. Taking and then free'ing an unowned buffer will have dire // consequences. char16_t* take() { MOZ_ASSERT(ownsChars_); ownsChars_ = false; return const_cast(data_); } private: SourceBufferHolder(SourceBufferHolder&) = delete; SourceBufferHolder& operator=(SourceBufferHolder&) = delete; const char16_t* data_; size_t length_; bool ownsChars_; }; } /* namespace JS */ /************************************************************************/ /* Property attributes, set in JSPropertySpec and passed to API functions. * * NB: The data structure in which some of these values are stored only uses * a uint8_t to store the relevant information. Proceed with caution if * trying to reorder or change the the first byte worth of flags. */ #define JSPROP_ENUMERATE 0x01 /* property is visible to for/in loop */ #define JSPROP_READONLY 0x02 /* not settable: assignment is no-op. This flag is only valid when neither JSPROP_GETTER nor JSPROP_SETTER is set. */ #define JSPROP_PERMANENT 0x04 /* property cannot be deleted */ #define JSPROP_PROPOP_ACCESSORS 0x08 /* Passed to JS_Define(UC)Property* and JS_DefineElement if getters/setters are JSGetterOp/JSSetterOp */ #define JSPROP_GETTER 0x10 /* property holds getter function */ #define JSPROP_SETTER 0x20 /* property holds setter function */ #define JSPROP_SHARED 0x40 /* don't allocate a value slot for this property; don't copy the property on set of the same-named property in an object that delegates to a prototype containing this property */ #define JSPROP_INTERNAL_USE_BIT 0x80 /* internal JS engine use only */ #define JSPROP_DEFINE_LATE 0x100 /* Don't define property when initially creating the constructor. Some objects like Function/Object have self-hosted functions that can only be defined after the initialization is already finished. */ #define JSFUN_STUB_GSOPS 0x200 /* use JS_PropertyStub getter/setter instead of defaulting to class gsops for property holding function */ #define JSFUN_CONSTRUCTOR 0x400 /* native that can be called as a ctor */ /* * Specify a generic native prototype methods, i.e., methods of a class * prototype that are exposed as static methods taking an extra leading * argument: the generic |this| parameter. * * If you set this flag in a JSFunctionSpec struct's flags initializer, then * that struct must live at least as long as the native static method object * created due to this flag by JS_DefineFunctions or JS_InitClass. Typically * JSFunctionSpec structs are allocated in static arrays. */ #define JSFUN_GENERIC_NATIVE 0x800 #define JSFUN_FLAGS_MASK 0xe00 /* | of all the JSFUN_* flags */ /* * If set, will allow redefining a non-configurable property, but only on a * non-DOM global. This is a temporary hack that will need to go away in bug * 1105518. */ #define JSPROP_REDEFINE_NONCONFIGURABLE 0x1000 /* * Resolve hooks and enumerate hooks must pass this flag when calling * JS_Define* APIs to reify lazily-defined properties. * * JSPROP_RESOLVING is used only with property-defining APIs. It tells the * engine to skip the resolve hook when performing the lookup at the beginning * of property definition. This keeps the resolve hook from accidentally * triggering itself: unchecked recursion. * * For enumerate hooks, triggering the resolve hook would be merely silly, not * fatal, except in some cases involving non-configurable properties. */ #define JSPROP_RESOLVING 0x2000 #define JSPROP_IGNORE_ENUMERATE 0x4000 /* ignore the value in JSPROP_ENUMERATE. This flag only valid when defining over an existing property. */ #define JSPROP_IGNORE_READONLY 0x8000 /* ignore the value in JSPROP_READONLY. This flag only valid when defining over an existing property. */ #define JSPROP_IGNORE_PERMANENT 0x10000 /* ignore the value in JSPROP_PERMANENT. This flag only valid when defining over an existing property. */ #define JSPROP_IGNORE_VALUE 0x20000 /* ignore the Value in the descriptor. Nothing was specified when passed to Object.defineProperty from script. */ /** * The first call to JS_CallOnce by any thread in a process will call 'func'. * Later calls to JS_CallOnce with the same JSCallOnceType object will be * suppressed. * * Equivalently: each distinct JSCallOnceType object will allow one JS_CallOnce * to invoke its JSInitCallback. */ extern JS_PUBLIC_API(bool) JS_CallOnce(JSCallOnceType* once, JSInitCallback func); /** 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_GetNaNValue(JSContext* cx); extern JS_PUBLIC_API(JS::Value) JS_GetNegativeInfinityValue(JSContext* cx); extern JS_PUBLIC_API(JS::Value) JS_GetPositiveInfinityValue(JSContext* cx); extern JS_PUBLIC_API(JS::Value) JS_GetEmptyStringValue(JSContext* cx); extern JS_PUBLIC_API(JSString*) JS_GetEmptyString(JSRuntime* rt); 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); extern JS_PUBLIC_API(bool) JS_StrictlyEqual(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* equal); extern JS_PUBLIC_API(bool) JS_LooselyEqual(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* equal); extern JS_PUBLIC_API(bool) JS_SameValue(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* same); /** 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); /************************************************************************/ /* * Locking, contexts, and memory allocation. * * It is important that SpiderMonkey be initialized, and the first runtime and * first context be created, in a single-threaded fashion. Otherwise the * behavior of the library is undefined. * See: http://developer.mozilla.org/en/docs/Category:JSAPI_Reference */ extern JS_PUBLIC_API(JSRuntime*) JS_NewRuntime(uint32_t maxbytes, uint32_t maxNurseryBytes = JS::DefaultNurseryBytes, JSRuntime* parentRuntime = nullptr); extern JS_PUBLIC_API(void) JS_DestroyRuntime(JSRuntime* rt); typedef double (*JS_CurrentEmbedderTimeFunction)(); /** * The embedding can specify a time function that will be used in some * situations. The function can return the time however it likes; but * the norm is to return times in units of milliseconds since an * arbitrary, but consistent, epoch. If the time function is not set, * a built-in default will be used. */ JS_PUBLIC_API(void) JS_SetCurrentEmbedderTimeFunction(JS_CurrentEmbedderTimeFunction timeFn); /** * Return the time as computed using the current time function, or a * suitable default if one has not been set. */ JS_PUBLIC_API(double) JS_GetCurrentEmbedderTime(); JS_PUBLIC_API(void*) JS_GetRuntimePrivate(JSRuntime* rt); extern JS_PUBLIC_API(JSRuntime*) JS_GetRuntime(JSContext* cx); extern JS_PUBLIC_API(JSRuntime*) JS_GetParentRuntime(JSContext* cx); JS_PUBLIC_API(void) JS_SetRuntimePrivate(JSRuntime* rt, void* data); extern JS_PUBLIC_API(void) JS_BeginRequest(JSContext* cx); extern JS_PUBLIC_API(void) JS_EndRequest(JSContext* cx); namespace js { void AssertHeapIsIdle(JSRuntime* rt); void AssertHeapIsIdle(JSContext* cx); } /* namespace js */ class MOZ_RAII JSAutoRequest { public: explicit JSAutoRequest(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mContext(cx) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; JS_BeginRequest(mContext); } ~JSAutoRequest() { JS_EndRequest(mContext); } protected: JSContext* mContext; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER #if 0 private: static void* operator new(size_t) CPP_THROW_NEW { return 0; } static void operator delete(void*, size_t) { } #endif }; extern JS_PUBLIC_API(void) JS_SetContextCallback(JSRuntime* rt, JSContextCallback cxCallback, void* data); extern JS_PUBLIC_API(JSContext*) JS_NewContext(JSRuntime* rt, size_t stackChunkSize); extern JS_PUBLIC_API(void) JS_DestroyContext(JSContext* cx); extern JS_PUBLIC_API(void) JS_DestroyContextNoGC(JSContext* cx); extern JS_PUBLIC_API(void*) JS_GetContextPrivate(JSContext* cx); extern JS_PUBLIC_API(void) JS_SetContextPrivate(JSContext* cx, void* data); extern JS_PUBLIC_API(void*) JS_GetSecondContextPrivate(JSContext* cx); extern JS_PUBLIC_API(void) JS_SetSecondContextPrivate(JSContext* cx, void* data); extern JS_PUBLIC_API(JSRuntime*) JS_GetRuntime(JSContext* cx); extern JS_PUBLIC_API(JSContext*) JS_ContextIterator(JSRuntime* rt, JSContext** iterp); extern JS_PUBLIC_API(JSVersion) JS_GetVersion(JSContext* cx); /** * Mutate the version on the compartment. This is generally discouraged, but * necessary to support the version mutation in the js and xpc shell command * set. * * It would be nice to put this in jsfriendapi, but the linkage requirements * of the shells make that impossible. */ JS_PUBLIC_API(void) JS_SetVersionForCompartment(JSCompartment* compartment, JSVersion version); extern JS_PUBLIC_API(const char*) JS_VersionToString(JSVersion version); extern JS_PUBLIC_API(JSVersion) JS_StringToVersion(const char* string); namespace JS { class JS_PUBLIC_API(RuntimeOptions) { public: RuntimeOptions() : baseline_(true), ion_(true), asmJS_(true), throwOnAsmJSValidationFailure_(false), nativeRegExp_(true), unboxedArrays_(false), asyncStack_(true), asyncFuncs_(false), werror_(false), strictMode_(false), extraWarnings_(false) { } bool baseline() const { return baseline_; } RuntimeOptions& setBaseline(bool flag) { baseline_ = flag; return *this; } RuntimeOptions& toggleBaseline() { baseline_ = !baseline_; return *this; } bool ion() const { return ion_; } RuntimeOptions& setIon(bool flag) { ion_ = flag; return *this; } RuntimeOptions& toggleIon() { ion_ = !ion_; return *this; } bool asmJS() const { return asmJS_; } RuntimeOptions& setAsmJS(bool flag) { asmJS_ = flag; return *this; } RuntimeOptions& toggleAsmJS() { asmJS_ = !asmJS_; return *this; } bool throwOnAsmJSValidationFailure() const { return throwOnAsmJSValidationFailure_; } RuntimeOptions& setThrowOnAsmJSValidationFailure(bool flag) { throwOnAsmJSValidationFailure_ = flag; return *this; } RuntimeOptions& toggleThrowOnAsmJSValidationFailure() { throwOnAsmJSValidationFailure_ = !throwOnAsmJSValidationFailure_; return *this; } bool nativeRegExp() const { return nativeRegExp_; } RuntimeOptions& setNativeRegExp(bool flag) { nativeRegExp_ = flag; return *this; } bool unboxedArrays() const { return unboxedArrays_; } RuntimeOptions& setUnboxedArrays(bool flag) { unboxedArrays_ = flag; return *this; } bool asyncStack() const { return asyncStack_; } RuntimeOptions& setAsyncStack(bool flag) { asyncStack_ = flag; return *this; } bool asyncFuncs() const { return asyncFuncs_; } RuntimeOptions& setAsyncFuncs(bool flag) { asyncFuncs_ = flag; return *this; } bool werror() const { return werror_; } RuntimeOptions& setWerror(bool flag) { werror_ = flag; return *this; } RuntimeOptions& toggleWerror() { werror_ = !werror_; return *this; } bool strictMode() const { return strictMode_; } RuntimeOptions& setStrictMode(bool flag) { strictMode_ = flag; return *this; } RuntimeOptions& toggleStrictMode() { strictMode_ = !strictMode_; return *this; } bool extraWarnings() const { return extraWarnings_; } RuntimeOptions& setExtraWarnings(bool flag) { extraWarnings_ = flag; return *this; } RuntimeOptions& toggleExtraWarnings() { extraWarnings_ = !extraWarnings_; return *this; } private: bool baseline_ : 1; bool ion_ : 1; bool asmJS_ : 1; bool throwOnAsmJSValidationFailure_ : 1; bool nativeRegExp_ : 1; bool unboxedArrays_ : 1; bool asyncStack_ : 1; bool asyncFuncs_ : 1; bool werror_ : 1; bool strictMode_ : 1; bool extraWarnings_ : 1; }; JS_PUBLIC_API(RuntimeOptions&) RuntimeOptionsRef(JSRuntime* rt); JS_PUBLIC_API(RuntimeOptions&) RuntimeOptionsRef(JSContext* cx); class JS_PUBLIC_API(ContextOptions) { public: ContextOptions() : privateIsNSISupports_(false), dontReportUncaught_(false), autoJSAPIOwnsErrorReporting_(false) { } bool privateIsNSISupports() const { return privateIsNSISupports_; } ContextOptions& setPrivateIsNSISupports(bool flag) { privateIsNSISupports_ = flag; return *this; } ContextOptions& togglePrivateIsNSISupports() { privateIsNSISupports_ = !privateIsNSISupports_; return *this; } bool dontReportUncaught() const { return dontReportUncaught_; } ContextOptions& setDontReportUncaught(bool flag) { dontReportUncaught_ = flag; return *this; } ContextOptions& toggleDontReportUncaught() { dontReportUncaught_ = !dontReportUncaught_; return *this; } bool autoJSAPIOwnsErrorReporting() const { return autoJSAPIOwnsErrorReporting_; } ContextOptions& setAutoJSAPIOwnsErrorReporting(bool flag) { autoJSAPIOwnsErrorReporting_ = flag; return *this; } ContextOptions& toggleAutoJSAPIOwnsErrorReporting() { autoJSAPIOwnsErrorReporting_ = !autoJSAPIOwnsErrorReporting_; return *this; } private: bool privateIsNSISupports_ : 1; bool dontReportUncaught_ : 1; // dontReportUncaught isn't respected by all JSAPI codepaths, particularly the // JS_ReportError* functions that eventually report the error even when dontReportUncaught is // set, if script is not running. We want a way to indicate that the embedder will always // handle any exceptions, and that SpiderMonkey should just leave them on the context. This is // the way we want to do all future error handling in Gecko - stealing the exception explicitly // from the context and handling it as per the situation. This will eventually become the // default and these 2 flags should go away. bool autoJSAPIOwnsErrorReporting_ : 1; }; JS_PUBLIC_API(ContextOptions&) ContextOptionsRef(JSContext* cx); class JS_PUBLIC_API(AutoSaveContextOptions) { public: explicit AutoSaveContextOptions(JSContext* cx) : cx_(cx), oldOptions_(ContextOptionsRef(cx_)) { } ~AutoSaveContextOptions() { ContextOptionsRef(cx_) = oldOptions_; } private: JSContext* cx_; JS::ContextOptions oldOptions_; }; } /* namespace JS */ extern JS_PUBLIC_API(const char*) JS_GetImplementationVersion(void); extern JS_PUBLIC_API(void) JS_SetDestroyCompartmentCallback(JSRuntime* rt, JSDestroyCompartmentCallback callback); extern JS_PUBLIC_API(void) JS_SetDestroyZoneCallback(JSRuntime* rt, JSZoneCallback callback); extern JS_PUBLIC_API(void) JS_SetSweepZoneCallback(JSRuntime* rt, JSZoneCallback callback); extern JS_PUBLIC_API(void) JS_SetCompartmentNameCallback(JSRuntime* rt, JSCompartmentNameCallback callback); extern JS_PUBLIC_API(void) JS_SetWrapObjectCallbacks(JSRuntime* rt, const JSWrapObjectCallbacks* callbacks); extern JS_PUBLIC_API(void) JS_SetCompartmentPrivate(JSCompartment* compartment, void* data); extern JS_PUBLIC_API(void*) JS_GetCompartmentPrivate(JSCompartment* 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) compartment. * Compartments are described in: * * developer.mozilla.org/en-US/docs/SpiderMonkey/SpiderMonkey_compartments * * The current compartment of a context may be changed. The preferred way to do * this is with JSAutoCompartment: * * void foo(JSContext* cx, JSObject* obj) { * // in some compartment 'c' * { * JSAutoCompartment ac(cx, obj); // constructor enters * // in the compartment of 'obj' * } // destructor leaves * // back in compartment 'c' * } * * For more complicated uses that don't neatly fit in a C++ stack frame, the * compartment can entered and left using separate function calls: * * void foo(JSContext* cx, JSObject* obj) { * // in 'oldCompartment' * JSCompartment* oldCompartment = JS_EnterCompartment(cx, obj); * // in the compartment of 'obj' * JS_LeaveCompartment(cx, oldCompartment); * // back in 'oldCompartment' * } * * 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_EnterCompartment call may be passed as the 'oldCompartment' argument of * the corresponding JS_LeaveCompartment call. */ class MOZ_RAII JS_PUBLIC_API(JSAutoCompartment) { JSContext* cx_; JSCompartment* oldCompartment_; public: JSAutoCompartment(JSContext* cx, JSObject* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM); JSAutoCompartment(JSContext* cx, JSScript* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM); ~JSAutoCompartment(); MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; class MOZ_RAII JS_PUBLIC_API(JSAutoNullableCompartment) { JSContext* cx_; JSCompartment* oldCompartment_; public: explicit JSAutoNullableCompartment(JSContext* cx, JSObject* targetOrNull MOZ_GUARD_OBJECT_NOTIFIER_PARAM); ~JSAutoNullableCompartment(); MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; /** NB: This API is infallible; a nullptr return value does not indicate error. */ extern JS_PUBLIC_API(JSCompartment*) JS_EnterCompartment(JSContext* cx, JSObject* target); extern JS_PUBLIC_API(void) JS_LeaveCompartment(JSContext* cx, JSCompartment* oldCompartment); typedef void (*JSIterateCompartmentCallback)(JSRuntime* rt, void* data, JSCompartment* compartment); /** * This function calls |compartmentCallback| on every compartment. 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(JSRuntime* rt, void* data, JSIterateCompartmentCallback compartmentCallback); /** * Initialize standard JS class constructors, prototypes, and any top-level * functions and constants associated with the standard classes (e.g. isNaN * for Number). * * NB: This sets cx's global object to obj if it was null. */ extern JS_PUBLIC_API(bool) JS_InitStandardClasses(JSContext* cx, JS::Handle obj); /** * 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's enumerate op should call * JS_EnumerateStandardClasses(cx, obj), to define eagerly during for..in * loops any classes not yet resolved lazily. */ 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); 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); /** * Returns the original value of |Function.prototype| from the global object in * which |forObj| was created. */ extern JS_PUBLIC_API(JSObject*) JS_GetFunctionPrototype(JSContext* cx, JS::HandleObject forObj); /** * Returns the original value of |Object.prototype| from the global object in * which |forObj| was created. */ extern JS_PUBLIC_API(JSObject*) JS_GetObjectPrototype(JSContext* cx, JS::HandleObject forObj); /** * Returns the original value of |Array.prototype| from the global object in * which |forObj| was created. */ extern JS_PUBLIC_API(JSObject*) JS_GetArrayPrototype(JSContext* cx, JS::HandleObject forObj); /** * Returns the original value of |Error.prototype| from the global * object of the current compartment of cx. */ extern JS_PUBLIC_API(JSObject*) JS_GetErrorPrototype(JSContext* cx); /** * Returns the %IteratorPrototype% object that all built-in iterator prototype * chains go through for the global object of the current compartment of cx. */ extern JS_PUBLIC_API(JSObject*) JS_GetIteratorPrototype(JSContext* cx); extern JS_PUBLIC_API(JSObject*) JS_GetGlobalForObject(JSContext* cx, JSObject* obj); extern JS_PUBLIC_API(bool) JS_IsGlobalObject(JSObject* obj); extern JS_PUBLIC_API(JSObject*) JS_GlobalLexicalScope(JSObject* obj); extern JS_PUBLIC_API(bool) JS_HasExtensibleLexicalScope(JSObject* obj); extern JS_PUBLIC_API(JSObject*) JS_ExtensibleLexicalScope(JSObject* obj); /** * May return nullptr, if |c| never had a global (e.g. the atoms compartment), * or if |c|'s global has been collected. */ extern JS_PUBLIC_API(JSObject*) JS_GetGlobalForCompartmentOrNull(JSContext* cx, JSCompartment* c); namespace JS { extern JS_PUBLIC_API(JSObject*) CurrentGlobalOrNull(JSContext* cx); } // 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); #ifdef JS_HAS_CTYPES /** * Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes' * object will be sealed. */ extern JS_PUBLIC_API(bool) JS_InitCTypesClass(JSContext* cx, JS::HandleObject global); /** * Convert a unicode string 'source' of length 'slen' to the platform native * charset, returning a null-terminated string allocated with JS_malloc. On * failure, this function should report an error. */ typedef char* (* JSCTypesUnicodeToNativeFun)(JSContext* cx, const char16_t* source, size_t slen); /** * Set of function pointers that ctypes can use for various internal functions. * See JS_SetCTypesCallbacks below. Providing nullptr for a function is safe, * and will result in the applicable ctypes functionality not being available. */ struct JSCTypesCallbacks { JSCTypesUnicodeToNativeFun unicodeToNative; }; typedef struct JSCTypesCallbacks JSCTypesCallbacks; /** * Set the callbacks on the provided 'ctypesObj' object. 'callbacks' should be a * pointer to static data that exists for the lifetime of 'ctypesObj', but it * may safely be altered after calling this function and without having * to call this function again. */ extern JS_PUBLIC_API(void) JS_SetCTypesCallbacks(JSObject* ctypesObj, const JSCTypesCallbacks* callbacks); #endif extern JS_PUBLIC_API(void*) JS_malloc(JSContext* cx, size_t nbytes); extern JS_PUBLIC_API(void*) JS_realloc(JSContext* cx, void* p, size_t oldBytes, size_t newBytes); /** * A wrapper for js_free(p) that may delay js_free(p) invocation as a * performance optimization. * cx may be nullptr. */ extern JS_PUBLIC_API(void) JS_free(JSContext* cx, void* p); /** * A wrapper for js_free(p) that may delay js_free(p) invocation as a * performance optimization as specified by the given JSFreeOp instance. */ extern JS_PUBLIC_API(void) JS_freeop(JSFreeOp* fop, void* p); extern JS_PUBLIC_API(JSFreeOp*) JS_GetDefaultFreeOp(JSRuntime* rt); extern JS_PUBLIC_API(void) JS_updateMallocCounter(JSContext* cx, size_t nbytes); extern JS_PUBLIC_API(char*) JS_strdup(JSContext* cx, const char* s); /** Duplicate a string. Does not report an error on failure. */ extern JS_PUBLIC_API(char*) JS_strdup(JSRuntime* rt, const char* s); /** * Register externally maintained GC roots. * * traceOp: the trace operation. For each root the implementation should call * JS_CallTracer whenever the root contains a traceable thing. * data: the data argument to pass to each invocation of traceOp. */ extern JS_PUBLIC_API(bool) JS_AddExtraGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data); /** Undo a call to JS_AddExtraGCRootsTracer. */ extern JS_PUBLIC_API(void) JS_RemoveExtraGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data); /* * Garbage collector API. */ extern JS_PUBLIC_API(void) JS_GC(JSRuntime* rt); extern JS_PUBLIC_API(void) JS_MaybeGC(JSContext* cx); extern JS_PUBLIC_API(void) JS_SetGCCallback(JSRuntime* rt, JSGCCallback cb, void* data); extern JS_PUBLIC_API(bool) JS_AddFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb, void* data); extern JS_PUBLIC_API(void) JS_RemoveFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb); /* * Weak pointers and garbage collection * * Weak pointers are by their nature not marked as part of garbage collection, * but they may need to be updated in two cases after a GC: * * 1) Their referent was found not to be live and is about to be finalized * 2) Their referent has been moved by a compacting GC * * To handle this, any part of the system that maintain weak pointers to * JavaScript GC things must register a callback with * JS_(Add,Remove)WeakPointer{ZoneGroup,Compartment}Callback(). This callback * must then call JS_UpdateWeakPointerAfterGC() on all weak pointers it knows * about. * * Since sweeping is incremental, we have several callbacks to avoid repeatedly * having to visit all embedder structures. The WeakPointerZoneGroupCallback is * called once for each strongly connected group of zones, whereas the * WeakPointerCompartmentCallback is called once for each compartment that is * visited while sweeping. Structures that cannot contain references in more * than one compartment should sweep the relevant per-compartment structures * using the latter callback to minimizer per-slice overhead. * * The argument to JS_UpdateWeakPointerAfterGC() is an in-out param. If the * referent is about to be finalized the pointer will be set to null. If the * referent has been moved then the pointer will be updated to point to the new * location. * * Callers of this method are responsible for updating any state that is * dependent on the object's address. For example, if the object's address is * used as a key in a hashtable, then the object must be removed and * re-inserted with the correct hash. */ extern JS_PUBLIC_API(bool) JS_AddWeakPointerZoneGroupCallback(JSRuntime* rt, JSWeakPointerZoneGroupCallback cb, void* data); extern JS_PUBLIC_API(void) JS_RemoveWeakPointerZoneGroupCallback(JSRuntime* rt, JSWeakPointerZoneGroupCallback cb); extern JS_PUBLIC_API(bool) JS_AddWeakPointerCompartmentCallback(JSRuntime* rt, JSWeakPointerCompartmentCallback cb, void* data); extern JS_PUBLIC_API(void) JS_RemoveWeakPointerCompartmentCallback(JSRuntime* rt, JSWeakPointerCompartmentCallback cb); extern JS_PUBLIC_API(void) JS_UpdateWeakPointerAfterGC(JS::Heap* objp); extern JS_PUBLIC_API(void) JS_UpdateWeakPointerAfterGCUnbarriered(JSObject** objp); typedef enum JSGCParamKey { /** Maximum nominal heap before last ditch GC. */ JSGC_MAX_BYTES = 0, /** Number of JS_malloc bytes before last ditch GC. */ JSGC_MAX_MALLOC_BYTES = 1, /** Amount of bytes allocated by the GC. */ JSGC_BYTES = 3, /** Number of times GC has been invoked. Includes both major and minor GC. */ JSGC_NUMBER = 4, /** Max size of the code cache in bytes. */ JSGC_MAX_CODE_CACHE_BYTES = 5, /** Select GC mode. */ JSGC_MODE = 6, /** Number of cached empty GC chunks. */ JSGC_UNUSED_CHUNKS = 7, /** Total number of allocated GC chunks. */ JSGC_TOTAL_CHUNKS = 8, /** Max milliseconds to spend in an incremental GC slice. */ JSGC_SLICE_TIME_BUDGET = 9, /** Maximum size the GC mark stack can grow to. */ JSGC_MARK_STACK_LIMIT = 10, /** * GCs less than this far apart in time will be considered 'high-frequency GCs'. * See setGCLastBytes in jsgc.cpp. */ JSGC_HIGH_FREQUENCY_TIME_LIMIT = 11, /** Start of dynamic heap growth. */ JSGC_HIGH_FREQUENCY_LOW_LIMIT = 12, /** End of dynamic heap growth. */ JSGC_HIGH_FREQUENCY_HIGH_LIMIT = 13, /** Upper bound of heap growth. */ JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX = 14, /** Lower bound of heap growth. */ JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN = 15, /** Heap growth for low frequency GCs. */ JSGC_LOW_FREQUENCY_HEAP_GROWTH = 16, /** * If false, the heap growth factor is fixed at 3. If true, it is determined * based on whether GCs are high- or low- frequency. */ JSGC_DYNAMIC_HEAP_GROWTH = 17, /** If true, high-frequency GCs will use a longer mark slice. */ JSGC_DYNAMIC_MARK_SLICE = 18, /** Lower limit after which we limit the heap growth. */ JSGC_ALLOCATION_THRESHOLD = 19, /** * We decommit memory lazily. If more than this number of megabytes is * available to be decommitted, then JS_MaybeGC will trigger a shrinking GC * to decommit it. */ JSGC_DECOMMIT_THRESHOLD = 20, /** * We try to keep at least this many unused chunks in the free chunk pool at * all times, even after a shrinking GC. */ JSGC_MIN_EMPTY_CHUNK_COUNT = 21, /** We never keep more than this many unused chunks in the free chunk pool. */ JSGC_MAX_EMPTY_CHUNK_COUNT = 22, /** Whether compacting GC is enabled. */ JSGC_COMPACTING_ENABLED = 23 } JSGCParamKey; extern JS_PUBLIC_API(void) JS_SetGCParameter(JSRuntime* rt, JSGCParamKey key, uint32_t value); extern JS_PUBLIC_API(uint32_t) JS_GetGCParameter(JSRuntime* rt, JSGCParamKey key); extern JS_PUBLIC_API(void) JS_SetGCParameterForThread(JSContext* cx, JSGCParamKey key, uint32_t value); extern JS_PUBLIC_API(uint32_t) JS_GetGCParameterForThread(JSContext* cx, JSGCParamKey key); extern JS_PUBLIC_API(void) JS_SetGCParametersBasedOnAvailableMemory(JSRuntime* rt, uint32_t availMem); /** * Create a new JSString whose chars member refers to external memory, i.e., * memory requiring application-specific finalization. */ extern JS_PUBLIC_API(JSString*) JS_NewExternalString(JSContext* cx, const char16_t* chars, size_t length, const JSStringFinalizer* fin); /** * Create a new JSString whose chars member may refer to external memory. * If the returned string refers to the external memory, |*isExternal| is set * to true. Otherwise the returned string is not an external string and * |*isExternal| is set to false. If |*isExternal| is false, |fin| won't be * called. */ extern JS_PUBLIC_API(JSString*) JS_NewMaybeExternalString(JSContext* cx, const char16_t* chars, size_t length, const JSStringFinalizer* fin, bool* isExternal); /** * Return whether 'str' was created with JS_NewExternalString or * JS_NewExternalStringWithClosure. */ extern JS_PUBLIC_API(bool) JS_IsExternalString(JSString* str); /** * Return the 'fin' arg passed to JS_NewExternalString. */ extern JS_PUBLIC_API(const JSStringFinalizer*) JS_GetExternalStringFinalizer(JSString* str); /** * 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(JSRuntime* 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_VOID (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_VOID 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(bool) JS_PropertyStub(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); extern JS_PUBLIC_API(bool) JS_StrictPropertyStub(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result); template struct JSConstScalarSpec { const char* name; T val; }; typedef JSConstScalarSpec JSConstDoubleSpec; typedef JSConstScalarSpec JSConstIntegerSpec; struct JSJitInfo; /** * Wrapper to relace JSNative for JSPropertySpecs and JSFunctionSpecs. This will * allow us to pass one JSJitInfo per function with the property/function spec, * without additional field overhead. */ typedef struct JSNativeWrapper { JSNative op; const JSJitInfo* info; } JSNativeWrapper; /* * Macro static initializers which make it easy to pass no JSJitInfo as part of a * JSPropertySpec or JSFunctionSpec. */ #define JSNATIVE_WRAPPER(native) { {native, nullptr} } /** * Description of a property. JS_DefineProperties and JS_InitClass take arrays * of these and define many properties at once. JS_PSG, JS_PSGS and JS_PS_END * are helper macros for defining such arrays. */ struct JSPropertySpec { struct SelfHostedWrapper { void* unused; const char* funname; }; const char* name; uint8_t flags; union { JSNativeWrapper native; SelfHostedWrapper selfHosted; } getter; union { JSNativeWrapper native; SelfHostedWrapper selfHosted; } setter; bool isSelfHosted() const { #ifdef DEBUG // Verify that our accessors match our JSPROP_GETTER flag. if (flags & JSPROP_GETTER) checkAccessorsAreSelfHosted(); else checkAccessorsAreNative(); #endif return (flags & JSPROP_GETTER); } static_assert(sizeof(SelfHostedWrapper) == sizeof(JSNativeWrapper), "JSPropertySpec::getter/setter must be compact"); static_assert(offsetof(SelfHostedWrapper, funname) == offsetof(JSNativeWrapper, info), "JS_SELF_HOSTED* macros below require that " "SelfHostedWrapper::funname overlay " "JSNativeWrapper::info"); private: void checkAccessorsAreNative() const { MOZ_ASSERT(getter.native.op); // We may not have a setter at all. So all we can assert here, for the // native case is that if we have a jitinfo for the setter then we have // a setter op too. This is good enough to make sure we don't have a // SelfHostedWrapper for the setter. MOZ_ASSERT_IF(setter.native.info, setter.native.op); } void checkAccessorsAreSelfHosted() const { MOZ_ASSERT(!getter.selfHosted.unused); MOZ_ASSERT(!setter.selfHosted.unused); } }; namespace JS { namespace detail { /* NEVER DEFINED, DON'T USE. For use by JS_CAST_NATIVE_TO only. */ inline int CheckIsNative(JSNative native); /* NEVER DEFINED, DON'T USE. For use by JS_CAST_STRING_TO only. */ template inline int CheckIsCharacterLiteral(const char (&arr)[N]); /* NEVER DEFINED, DON'T USE. For use by JS_PROPERTYOP_GETTER only. */ inline int CheckIsGetterOp(JSGetterOp op); /* NEVER DEFINED, DON'T USE. For use by JS_PROPERTYOP_SETTER only. */ inline int CheckIsSetterOp(JSSetterOp op); } // namespace detail } // namespace JS #define JS_CAST_NATIVE_TO(v, To) \ (static_cast(sizeof(JS::detail::CheckIsNative(v))), \ reinterpret_cast(v)) #define JS_CAST_STRING_TO(s, To) \ (static_cast(sizeof(JS::detail::CheckIsCharacterLiteral(s))), \ reinterpret_cast(s)) #define JS_CHECK_ACCESSOR_FLAGS(flags) \ (static_cast::Type>(0), \ (flags)) #define JS_PROPERTYOP_GETTER(v) \ (static_cast(sizeof(JS::detail::CheckIsGetterOp(v))), \ reinterpret_cast(v)) #define JS_PROPERTYOP_SETTER(v) \ (static_cast(sizeof(JS::detail::CheckIsSetterOp(v))), \ reinterpret_cast(v)) #define JS_STUBGETTER JS_PROPERTYOP_GETTER(JS_PropertyStub) #define JS_STUBSETTER JS_PROPERTYOP_SETTER(JS_StrictPropertyStub) /* * JSPropertySpec uses JSNativeWrapper. These macros encapsulate the definition * of JSNative-backed JSPropertySpecs, by defining the JSNativeWrappers for * them. */ #define JS_PSG(name, getter, flags) \ {name, \ uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED), \ JSNATIVE_WRAPPER(getter), \ JSNATIVE_WRAPPER(nullptr)} #define JS_PSGS(name, getter, setter, flags) \ {name, \ uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED), \ JSNATIVE_WRAPPER(getter), \ JSNATIVE_WRAPPER(setter)} #define JS_SELF_HOSTED_GET(name, getterName, flags) \ {name, \ uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER), \ { { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo*) } }, \ JSNATIVE_WRAPPER(nullptr) } #define JS_SELF_HOSTED_GETSET(name, getterName, setterName, flags) \ {name, \ uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER | JSPROP_SETTER), \ { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo*) }, \ { nullptr, JS_CAST_STRING_TO(setterName, const JSJitInfo*) } } #define JS_PS_END { nullptr, 0, JSNATIVE_WRAPPER(nullptr), JSNATIVE_WRAPPER(nullptr) } #define JS_SELF_HOSTED_SYM_GET(symbol, getterName, flags) \ {reinterpret_cast(uint32_t(::JS::SymbolCode::symbol) + 1), \ uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER), \ { { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo*) } }, \ JSNATIVE_WRAPPER(nullptr) } /** * To define a native function, set call to a JSNativeWrapper. To define a * self-hosted function, set selfHostedName to the name of a function * compiled during JSRuntime::initSelfHosting. */ struct JSFunctionSpec { const char* name; JSNativeWrapper call; uint16_t nargs; uint16_t flags; const char* selfHostedName; }; /* * Terminating sentinel initializer to put at the end of a JSFunctionSpec array * that's passed to JS_DefineFunctions or JS_InitClass. */ #define JS_FS_END JS_FS(nullptr,nullptr,0,0) /* * Initializer macros for a JSFunctionSpec array element. JS_FN (whose name pays * homage to the old JSNative/JSFastNative split) simply adds the flag * JSFUN_STUB_GSOPS. JS_FNINFO allows the simple adding of * JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted function. * JS_INLINABLE_FN allows specifying an InlinableNative enum value for natives * inlined or specialized by the JIT. Finally JS_FNSPEC has slots for all the * fields. * * The _SYM variants allow defining a function with a symbol key rather than a * string key. For example, use JS_SYM_FN(iterator, ...) to define an * @@iterator method. */ #define JS_FS(name,call,nargs,flags) \ JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr) #define JS_FN(name,call,nargs,flags) \ JS_FNSPEC(name, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) #define JS_INLINABLE_FN(name,call,nargs,flags,native) \ JS_FNSPEC(name, call, &js::jit::JitInfo_##native, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) #define JS_SYM_FN(symbol,call,nargs,flags) \ JS_SYM_FNSPEC(symbol, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) #define JS_FNINFO(name,call,info,nargs,flags) \ JS_FNSPEC(name, call, info, nargs, flags, nullptr) #define JS_SELF_HOSTED_FN(name,selfHostedName,nargs,flags) \ JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName) #define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \ JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName) #define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \ JS_FNSPEC(reinterpret_cast( \ uint32_t(::JS::SymbolCode::symbol) + 1), \ call, info, nargs, flags, selfHostedName) #define JS_FNSPEC(name,call,info,nargs,flags,selfHostedName) \ {name, {call, info}, nargs, flags, selfHostedName} 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(const JSClass*) JS_GetClass(JSObject* obj); 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); extern JS_PUBLIC_API(void*) JS_GetPrivate(JSObject* obj); extern JS_PUBLIC_API(void) JS_SetPrivate(JSObject* obj, void* data); 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 { enum ZoneSpecifier { FreshZone = 0, SystemZone = 1 }; class JS_PUBLIC_API(CompartmentOptions) { public: class Override { public: Override() : mode_(Default) {} bool get(bool defaultValue) const { if (mode_ == Default) return defaultValue; return mode_ == ForceTrue; } void set(bool overrideValue) { mode_ = overrideValue ? ForceTrue : ForceFalse; } void reset() { mode_ = Default; } private: enum Mode { Default, ForceTrue, ForceFalse }; Mode mode_; }; explicit CompartmentOptions() : version_(JSVERSION_UNKNOWN) , invisibleToDebugger_(false) , mergeable_(false) , discardSource_(false) , disableLazyParsing_(false) , cloneSingletons_(false) , traceGlobal_(nullptr) , singletonsAsTemplates_(true) , addonId_(nullptr) , preserveJitCode_(false) { zone_.spec = JS::FreshZone; } JSVersion version() const { return version_; } CompartmentOptions& setVersion(JSVersion aVersion) { MOZ_ASSERT(aVersion != JSVERSION_UNKNOWN); version_ = aVersion; return *this; } // Certain scopes (i.e. XBL compilation scopes) are implementation details // of the embedding, and references to them should never leak out to script. // This flag causes the this compartment to skip firing onNewGlobalObject // and makes addDebuggee a no-op for this global. bool invisibleToDebugger() const { return invisibleToDebugger_; } CompartmentOptions& setInvisibleToDebugger(bool flag) { invisibleToDebugger_ = flag; return *this; } // Compartments used for off-thread compilation have their contents merged // into a target compartment when the compilation is finished. This is only // allowed if this flag is set. The invisibleToDebugger flag must also be // set for such compartments. bool mergeable() const { return mergeable_; } CompartmentOptions& setMergeable(bool flag) { mergeable_ = flag; return *this; } // For certain globals, we know enough about the code that will run in them // that we can discard script source entirely. bool discardSource() const { return discardSource_; } CompartmentOptions& setDiscardSource(bool flag) { discardSource_ = flag; return *this; } bool disableLazyParsing() const { return disableLazyParsing_; } CompartmentOptions& setDisableLazyParsing(bool flag) { disableLazyParsing_ = flag; return *this; } bool cloneSingletons() const { return cloneSingletons_; } CompartmentOptions& setCloneSingletons(bool flag) { cloneSingletons_ = flag; return *this; } bool extraWarnings(JSRuntime* rt) const; bool extraWarnings(JSContext* cx) const; Override& extraWarningsOverride() { return extraWarningsOverride_; } void* zonePointer() const { MOZ_ASSERT(uintptr_t(zone_.pointer) > uintptr_t(JS::SystemZone)); return zone_.pointer; } ZoneSpecifier zoneSpecifier() const { return zone_.spec; } CompartmentOptions& setZone(ZoneSpecifier spec); CompartmentOptions& setSameZoneAs(JSObject* obj); void setSingletonsAsValues() { singletonsAsTemplates_ = false; } bool getSingletonsAsTemplates() const { return singletonsAsTemplates_; } // A null add-on ID means that the compartment is not associated with an // add-on. JSAddonId* addonIdOrNull() const { return addonId_; } CompartmentOptions& setAddonId(JSAddonId* id) { addonId_ = id; return *this; } CompartmentOptions& setTrace(JSTraceOp op) { traceGlobal_ = op; return *this; } JSTraceOp getTrace() const { return traceGlobal_; } bool preserveJitCode() const { return preserveJitCode_; } CompartmentOptions& setPreserveJitCode(bool flag) { preserveJitCode_ = flag; return *this; } private: JSVersion version_; bool invisibleToDebugger_; bool mergeable_; bool discardSource_; bool disableLazyParsing_; bool cloneSingletons_; Override extraWarningsOverride_; union { ZoneSpecifier spec; void* pointer; // js::Zone* is not exposed in the API. } zone_; JSTraceOp traceGlobal_; // To XDR singletons, we need to ensure that all singletons are all used as // templates, by making JSOP_OBJECT return a clone of the JSScript // singleton, instead of returning the value which is baked in the JSScript. bool singletonsAsTemplates_; JSAddonId* addonId_; bool preserveJitCode_; }; JS_PUBLIC_API(CompartmentOptions&) CompartmentOptionsRef(JSCompartment* compartment); JS_PUBLIC_API(CompartmentOptions&) CompartmentOptionsRef(JSObject* obj); JS_PUBLIC_API(CompartmentOptions&) CompartmentOptionsRef(JSContext* cx); /** * 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::CompartmentOptions& options = JS::CompartmentOptions()); /** * 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 CompartmentOptions passed to JS_NewGlobalObject. */ extern JS_PUBLIC_API(void) JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global); 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); extern JS_PUBLIC_API(JSRuntime*) JS_GetObjectRuntime(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); /*** Property descriptors ************************************************************************/ struct JSPropertyDescriptor : public JS::Traceable { JSObject* obj; unsigned attrs; JSGetterOp getter; JSSetterOp setter; JS::Value value; JSPropertyDescriptor() : obj(nullptr), attrs(0), getter(nullptr), setter(nullptr), value(JS::UndefinedValue()) {} static void trace(JSPropertyDescriptor* self, JSTracer* trc) { self->trace(trc); } void trace(JSTracer* trc); }; namespace JS { template class PropertyDescriptorOperations { const JSPropertyDescriptor& desc() const { return static_cast(this)->get(); } bool has(unsigned bit) const { MOZ_ASSERT(bit != 0); MOZ_ASSERT((bit & (bit - 1)) == 0); // only a single bit return (desc().attrs & bit) != 0; } bool hasAny(unsigned bits) const { return (desc().attrs & bits) != 0; } bool hasAll(unsigned bits) const { return (desc().attrs & bits) == bits; } // Non-API attributes bit used internally for arguments objects. enum { SHADOWABLE = JSPROP_INTERNAL_USE_BIT }; public: // Descriptors with JSGetterOp/JSSetterOp are considered data // descriptors. It's complicated. bool isAccessorDescriptor() const { return hasAny(JSPROP_GETTER | JSPROP_SETTER); } bool isGenericDescriptor() const { return (desc().attrs& (JSPROP_GETTER | JSPROP_SETTER | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE)) == (JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE); } bool isDataDescriptor() const { return !isAccessorDescriptor() && !isGenericDescriptor(); } bool hasConfigurable() const { return !has(JSPROP_IGNORE_PERMANENT); } bool configurable() const { MOZ_ASSERT(hasConfigurable()); return !has(JSPROP_PERMANENT); } bool hasEnumerable() const { return !has(JSPROP_IGNORE_ENUMERATE); } bool enumerable() const { MOZ_ASSERT(hasEnumerable()); return has(JSPROP_ENUMERATE); } bool hasValue() const { return !isAccessorDescriptor() && !has(JSPROP_IGNORE_VALUE); } JS::HandleValue value() const { return JS::HandleValue::fromMarkedLocation(&desc().value); } bool hasWritable() const { return !isAccessorDescriptor() && !has(JSPROP_IGNORE_READONLY); } bool writable() const { MOZ_ASSERT(hasWritable()); return !has(JSPROP_READONLY); } bool hasGetterObject() const { return has(JSPROP_GETTER); } JS::HandleObject getterObject() const { MOZ_ASSERT(hasGetterObject()); return JS::HandleObject::fromMarkedLocation( reinterpret_cast(&desc().getter)); } bool hasSetterObject() const { return has(JSPROP_SETTER); } JS::HandleObject setterObject() const { MOZ_ASSERT(hasSetterObject()); return JS::HandleObject::fromMarkedLocation( reinterpret_cast(&desc().setter)); } bool hasGetterOrSetter() const { return desc().getter || desc().setter; } bool isShared() const { return has(JSPROP_SHARED); } JS::HandleObject object() const { return JS::HandleObject::fromMarkedLocation(&desc().obj); } unsigned attributes() const { return desc().attrs; } JSGetterOp getter() const { return desc().getter; } JSSetterOp setter() const { return desc().setter; } void assertValid() const { #ifdef DEBUG MOZ_ASSERT((attributes() & ~(JSPROP_ENUMERATE | JSPROP_IGNORE_ENUMERATE | JSPROP_PERMANENT | JSPROP_IGNORE_PERMANENT | JSPROP_READONLY | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED | JSPROP_REDEFINE_NONCONFIGURABLE | JSPROP_RESOLVING | SHADOWABLE)) == 0); MOZ_ASSERT(!hasAll(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)); MOZ_ASSERT(!hasAll(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)); if (isAccessorDescriptor()) { MOZ_ASSERT(has(JSPROP_SHARED)); MOZ_ASSERT(!has(JSPROP_READONLY)); MOZ_ASSERT(!has(JSPROP_IGNORE_READONLY)); MOZ_ASSERT(!has(JSPROP_IGNORE_VALUE)); MOZ_ASSERT(!has(SHADOWABLE)); MOZ_ASSERT(value().isUndefined()); MOZ_ASSERT_IF(!has(JSPROP_GETTER), !getter()); MOZ_ASSERT_IF(!has(JSPROP_SETTER), !setter()); } else { MOZ_ASSERT(!hasAll(JSPROP_IGNORE_READONLY | JSPROP_READONLY)); MOZ_ASSERT_IF(has(JSPROP_IGNORE_VALUE), value().isUndefined()); } MOZ_ASSERT(getter() != JS_PropertyStub); MOZ_ASSERT(setter() != JS_StrictPropertyStub); MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_ENUMERATE)); MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_PERMANENT)); MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_READONLY)); MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_IGNORE_VALUE)); MOZ_ASSERT_IF(has(JSPROP_RESOLVING), !has(JSPROP_REDEFINE_NONCONFIGURABLE)); #endif } void assertComplete() const { #ifdef DEBUG assertValid(); MOZ_ASSERT((attributes() & ~(JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED | JSPROP_REDEFINE_NONCONFIGURABLE | JSPROP_RESOLVING | SHADOWABLE)) == 0); MOZ_ASSERT_IF(isAccessorDescriptor(), has(JSPROP_GETTER) && has(JSPROP_SETTER)); #endif } void assertCompleteIfFound() const { #ifdef DEBUG if (object()) assertComplete(); #endif } }; template class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations { JSPropertyDescriptor& desc() { return static_cast(this)->get(); } public: void clear() { object().set(nullptr); setAttributes(0); setGetter(nullptr); setSetter(nullptr); value().setUndefined(); } void initFields(HandleObject obj, HandleValue v, unsigned attrs, JSGetterOp getterOp, JSSetterOp setterOp) { MOZ_ASSERT(getterOp != JS_PropertyStub); MOZ_ASSERT(setterOp != JS_StrictPropertyStub); object().set(obj); value().set(v); setAttributes(attrs); setGetter(getterOp); setSetter(setterOp); } void assign(JSPropertyDescriptor& other) { object().set(other.obj); setAttributes(other.attrs); setGetter(other.getter); setSetter(other.setter); value().set(other.value); } void setDataDescriptor(HandleValue v, unsigned attrs) { MOZ_ASSERT((attrs & ~(JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_PERMANENT | JSPROP_IGNORE_READONLY)) == 0); object().set(nullptr); setAttributes(attrs); setGetter(nullptr); setSetter(nullptr); value().set(v); } JS::MutableHandleObject object() { return JS::MutableHandleObject::fromMarkedLocation(&desc().obj); } unsigned& attributesRef() { return desc().attrs; } JSGetterOp& getter() { return desc().getter; } JSSetterOp& setter() { return desc().setter; } JS::MutableHandleValue value() { return JS::MutableHandleValue::fromMarkedLocation(&desc().value); } void setValue(JS::HandleValue v) { MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); attributesRef() &= ~JSPROP_IGNORE_VALUE; value().set(v); } void setConfigurable(bool configurable) { setAttributes((desc().attrs & ~(JSPROP_IGNORE_PERMANENT | JSPROP_PERMANENT)) | (configurable ? 0 : JSPROP_PERMANENT)); } void setEnumerable(bool enumerable) { setAttributes((desc().attrs & ~(JSPROP_IGNORE_ENUMERATE | JSPROP_ENUMERATE)) | (enumerable ? JSPROP_ENUMERATE : 0)); } void setWritable(bool writable) { MOZ_ASSERT(!(desc().attrs & (JSPROP_GETTER | JSPROP_SETTER))); setAttributes((desc().attrs & ~(JSPROP_IGNORE_READONLY | JSPROP_READONLY)) | (writable ? 0 : JSPROP_READONLY)); } void setAttributes(unsigned attrs) { desc().attrs = attrs; } void setGetter(JSGetterOp op) { MOZ_ASSERT(op != JS_PropertyStub); desc().getter = op; } void setSetter(JSSetterOp op) { MOZ_ASSERT(op != JS_StrictPropertyStub); desc().setter = op; } void setGetterObject(JSObject* obj) { desc().getter = reinterpret_cast(obj); desc().attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); desc().attrs |= JSPROP_GETTER | JSPROP_SHARED; } void setSetterObject(JSObject* obj) { desc().setter = reinterpret_cast(obj); desc().attrs &= ~(JSPROP_IGNORE_VALUE | JSPROP_IGNORE_READONLY | JSPROP_READONLY); desc().attrs |= JSPROP_SETTER | JSPROP_SHARED; } JS::MutableHandleObject getterObject() { MOZ_ASSERT(this->hasGetterObject()); return JS::MutableHandleObject::fromMarkedLocation( reinterpret_cast(&desc().getter)); } JS::MutableHandleObject setterObject() { MOZ_ASSERT(this->hasSetterObject()); return JS::MutableHandleObject::fromMarkedLocation( reinterpret_cast(&desc().setter)); } }; } /* namespace JS */ namespace js { template <> class RootedBase : public JS::MutablePropertyDescriptorOperations> {}; template <> class HandleBase : public JS::PropertyDescriptorOperations> {}; template <> class MutableHandleBase : public JS::MutablePropertyDescriptorOperations> {}; } /* namespace js */ namespace JS { extern JS_PUBLIC_API(bool) ObjectToCompletePropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleValue descriptor, JS::MutableHandle desc); } // namespace JS /*** 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 result. * * Implements: ES6 [[GetPrototypeOf]] internal method. */ extern JS_PUBLIC_API(bool) JS_GetPrototype(JSContext* cx, JS::HandleObject obj, 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, 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); /** * 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, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleString value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, int32_t value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, uint32_t value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, double value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleValue value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleObject value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, JS::HandleString value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, int32_t value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, uint32_t value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, double value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); 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, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::HandleObject value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, JS::HandleString value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, int32_t value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, uint32_t value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, double value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleObject value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::HandleString value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, int32_t value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, uint32_t value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineElement(JSContext* cx, JS::HandleObject obj, uint32_t index, double value, unsigned attrs, JSNative getter = nullptr, JSNative setter = nullptr); /** * 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 JSIdArray returned by JS_Enumerate must be rooted to protect its * contents from garbage collection. Use JS::AutoIdArray. */ extern JS_PUBLIC_API(bool) JS_Enumerate(JSContext* cx, JS::HandleObject obj, JS::MutableHandle props); /* * 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, MutableHandleValue rval); /** * Invoke a constructor. This is the C++ equivalent of * `rval = new fun(...args)`. * * The value left in rval on success is always an object in practice, * though at the moment this is not enforced by the C++ type system. * * 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, MutableHandleValue rval); } /* 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_DefineConstDoubles(JSContext* cx, JS::HandleObject obj, const JSConstDoubleSpec* cds); extern JS_PUBLIC_API(bool) JS_DefineConstIntegers(JSContext* cx, JS::HandleObject obj, const JSConstIntegerSpec* cis); 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); extern JS_PUBLIC_API(JSObject*) JS_NewArrayObject(JSContext* cx, const JS::HandleValueArray& contents); extern JS_PUBLIC_API(JSObject*) JS_NewArrayObject(JSContext* cx, size_t length); /** * Returns true and sets |*isArray| indicating whether |value| is an Array * object or a wrapper around one, otherwise returns false on failure. * * This method returns true with |*isArray == false| when passed a proxy whose * target is an Array, or when passed a revoked proxy. */ extern JS_PUBLIC_API(bool) JS_IsArrayObject(JSContext* cx, JS::HandleValue value, bool* isArray); /** * Returns true and sets |*isArray| indicating whether |obj| is an Array object * or a wrapper around one, otherwise returns false on failure. * * This method returns true with |*isArray == false| when passed a proxy whose * target is an Array, or when passed a revoked proxy. */ extern JS_PUBLIC_API(bool) JS_IsArrayObject(JSContext* cx, JS::HandleObject obj, bool* isArray); extern JS_PUBLIC_API(bool) JS_GetArrayLength(JSContext* cx, JS::Handle obj, uint32_t* lengthp); extern JS_PUBLIC_API(bool) JS_SetArrayLength(JSContext* cx, JS::Handle obj, uint32_t length); /** * 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(JSContext* cx, JSObject* objArg); /** * Create a new array buffer with the given contents. It must be legal to pass * these contents to free(). On success, the ownership is transferred to the * new array buffer. */ extern JS_PUBLIC_API(JSObject*) JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* contents); /** * Steal the contents of the given array buffer. The array buffer has its * length set to 0 and its contents array cleared. The caller takes ownership * of the return value and must free it or transfer ownership via * JS_NewArrayBufferWithContents when done using it. */ extern JS_PUBLIC_API(void*) JS_StealArrayBufferContents(JSContext* cx, JS::HandleObject obj); /** * Create a new mapped array buffer with the given memory mapped contents. It * must be legal to free the contents pointer by unmapping it. On success, * ownership is transferred to the new mapped array buffer. */ extern JS_PUBLIC_API(JSObject*) JS_NewMappedArrayBufferWithContents(JSContext* cx, size_t nbytes, void* contents); /** * Create memory mapped array buffer contents. * Caller must take care of closing fd after calling this function. */ extern JS_PUBLIC_API(void*) JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length); /** * Release the allocated resource of mapped array buffer contents before the * object is created. * If a new object has been created by JS_NewMappedArrayBufferWithContents() * with this content, then JS_NeuterArrayBuffer() should be used instead to * release the resource used by the object. */ extern JS_PUBLIC_API(void) JS_ReleaseMappedArrayBufferContents(void* contents, size_t length); extern JS_PUBLIC_API(JS::Value) JS_GetReservedSlot(JSObject* obj, uint32_t index); extern JS_PUBLIC_API(void) JS_SetReservedSlot(JSObject* obj, uint32_t index, JS::Value v); /************************************************************************/ /* * 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 * `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); } /* 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 (length) of fun. */ extern JS_PUBLIC_API(uint16_t) JS_GetFunctionArity(JSFunction* fun); /** * 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(JSContext* cx, 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); /** * This enum is used to select if properties with JSPROP_DEFINE_LATE flag * should be defined on the object. * Normal JSAPI consumers probably always want DefineAllProperties here. */ enum PropertyDefinitionBehavior { DefineAllProperties, OnlyDefineLateProperties, DontDefineLateProperties }; extern JS_PUBLIC_API(bool) JS_DefineFunctions(JSContext* cx, JS::Handle obj, const JSFunctionSpec* fs, PropertyDefinitionBehavior behavior = DefineAllProperties); 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); namespace JS { /** * Clone a top-level function into cx's global. This function will dynamically * fail if funobj was lexically nested inside some other function. */ extern JS_PUBLIC_API(JSObject*) CloneFunctionObject(JSContext* cx, HandleObject funobj); /** * As above, but providing an explicit scope chain. scopeChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the clone's scope chain. */ extern JS_PUBLIC_API(JSObject*) CloneFunctionObject(JSContext* cx, HandleObject funobj, AutoObjectVector& scopeChain); } // namespace JS /** * Given a buffer, return false if the buffer might become a valid * javascript statement with the addition of more lines. Otherwise return * true. The intent is to support interactive compilation - accumulate * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to * the compiler. */ extern JS_PUBLIC_API(bool) JS_BufferIsCompilableUnit(JSContext* cx, JS::Handle obj, const char* utf8, size_t length); /** * |script| will always be set. On failure, it will be set to nullptr. */ extern JS_PUBLIC_API(bool) JS_CompileScript(JSContext* cx, const char* ascii, size_t length, const JS::CompileOptions& options, JS::MutableHandleScript script); /** * |script| will always be set. On failure, it will be set to nullptr. */ extern JS_PUBLIC_API(bool) JS_CompileUCScript(JSContext* cx, const char16_t* chars, size_t length, const JS::CompileOptions& options, JS::MutableHandleScript script); 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); namespace JS { /* Options for JavaScript compilation. */ /* * In the most common use case, a CompileOptions instance is allocated on the * stack, and holds non-owning references to non-POD option values: strings; * principals; objects; and so on. The code declaring the instance guarantees * that such option values will outlive the CompileOptions itself: objects are * otherwise rooted; principals have had their reference counts bumped; strings * will not be freed until the CompileOptions goes out of scope. In this * situation, CompileOptions only refers to things others own, so it can be * lightweight. * * In some cases, however, we need to hold compilation options with a * non-stack-like lifetime. For example, JS::CompileOffThread needs to save * compilation options where a worker thread can find them, and then return * immediately. The worker thread will come along at some later point, and use * the options. * * The compiler itself just needs to be able to access a collection of options; * it doesn't care who owns them, or what's keeping them alive. It does its own * addrefs/copies/tracing/etc. * * Furthermore, in some cases compile options are propagated from one entity to * another (e.g. from a scriipt to a function defined in that script). This * involves copying over some, but not all, of the options. * * So, we have a class hierarchy that reflects these four use cases: * * - TransitiveCompileOptions is the common base class, representing options * that should get propagated from a script to functions defined in that * script. This is never instantiated directly. * * - ReadOnlyCompileOptions is the only subclass of TransitiveCompileOptions, * representing a full set of compile options. It can be used by code that * simply needs to access options set elsewhere, like the compiler. This, * again, is never instantiated directly. * * - The usual CompileOptions class must be stack-allocated, and holds * non-owning references to the filename, element, and so on. It's derived * from ReadOnlyCompileOptions, so the compiler can use it. * * - OwningCompileOptions roots / copies / reference counts of all its values, * and unroots / frees / releases them when it is destructed. It too is * derived from ReadOnlyCompileOptions, so the compiler accepts it. */ enum class AsmJSOption : uint8_t { Enabled, Disabled, DisabledByDebugger }; /** * The common base class for the CompileOptions hierarchy. * * Use this in code that needs to propagate compile options from one compilation * unit to another. */ class JS_FRIEND_API(TransitiveCompileOptions) { protected: // The Web Platform allows scripts to be loaded from arbitrary cross-origin // sources. This allows an attack by which a malicious website loads a // sensitive file (say, a bank statement) cross-origin (using the user's // cookies), and sniffs the generated syntax errors (via a window.onerror // handler) for juicy morsels of its contents. // // To counter this attack, HTML5 specifies that script errors should be // sanitized ("muted") when the script is not same-origin with the global // for which it is loaded. Callers should set this flag for cross-origin // scripts, and it will be propagated appropriately to child scripts and // passed back in JSErrorReports. bool mutedErrors_; const char* filename_; const char* introducerFilename_; const char16_t* sourceMapURL_; // This constructor leaves 'version' set to JSVERSION_UNKNOWN. The structure // is unusable until that's set to something more specific; the derived // classes' constructors take care of that, in ways appropriate to their // purpose. TransitiveCompileOptions() : mutedErrors_(false), filename_(nullptr), introducerFilename_(nullptr), sourceMapURL_(nullptr), version(JSVERSION_UNKNOWN), versionSet(false), utf8(false), selfHostingMode(false), canLazilyParse(true), strictOption(false), extraWarningsOption(false), werrorOption(false), asmJSOption(AsmJSOption::Disabled), throwOnAsmJSValidationFailureOption(false), forceAsync(false), installedFile(false), sourceIsLazy(false), introductionType(nullptr), introductionLineno(0), introductionOffset(0), hasIntroductionInfo(false) { } // Set all POD options (those not requiring reference counts, copies, // rooting, or other hand-holding) to their values in |rhs|. void copyPODTransitiveOptions(const TransitiveCompileOptions& rhs); public: // Read-only accessors for non-POD options. The proper way to set these // depends on the derived type. bool mutedErrors() const { return mutedErrors_; } const char* filename() const { return filename_; } const char* introducerFilename() const { return introducerFilename_; } const char16_t* sourceMapURL() const { return sourceMapURL_; } virtual JSObject* element() const = 0; virtual JSString* elementAttributeName() const = 0; virtual JSScript* introductionScript() const = 0; // POD options. JSVersion version; bool versionSet; bool utf8; bool selfHostingMode; bool canLazilyParse; bool strictOption; bool extraWarningsOption; bool werrorOption; AsmJSOption asmJSOption; bool throwOnAsmJSValidationFailureOption; bool forceAsync; bool installedFile; // 'true' iff pre-compiling js file in packaged app bool sourceIsLazy; // |introductionType| is a statically allocated C string: // one of "eval", "Function", or "GeneratorFunction". const char* introductionType; unsigned introductionLineno; uint32_t introductionOffset; bool hasIntroductionInfo; private: void operator=(const TransitiveCompileOptions&) = delete; }; /** * The class representing a full set of compile options. * * Use this in code that only needs to access compilation options created * elsewhere, like the compiler. Don't instantiate this class (the constructor * is protected anyway); instead, create instances only of the derived classes: * CompileOptions and OwningCompileOptions. */ class JS_FRIEND_API(ReadOnlyCompileOptions) : public TransitiveCompileOptions { friend class CompileOptions; protected: ReadOnlyCompileOptions() : TransitiveCompileOptions(), lineno(1), column(0), isRunOnce(false), forEval(false), noScriptRval(false) { } // Set all POD options (those not requiring reference counts, copies, // rooting, or other hand-holding) to their values in |rhs|. void copyPODOptions(const ReadOnlyCompileOptions& rhs); public: // Read-only accessors for non-POD options. The proper way to set these // depends on the derived type. bool mutedErrors() const { return mutedErrors_; } const char* filename() const { return filename_; } const char* introducerFilename() const { return introducerFilename_; } const char16_t* sourceMapURL() const { return sourceMapURL_; } virtual JSObject* element() const = 0; virtual JSString* elementAttributeName() const = 0; virtual JSScript* introductionScript() const = 0; // POD options. unsigned lineno; unsigned column; // isRunOnce only applies to non-function scripts. bool isRunOnce; bool forEval; bool noScriptRval; private: void operator=(const ReadOnlyCompileOptions&) = delete; }; /** * Compilation options, with dynamic lifetime. An instance of this type * makes a copy of / holds / roots all dynamically allocated resources * (principals; elements; strings) that it refers to. Its destructor frees * / drops / unroots them. This is heavier than CompileOptions, below, but * unlike CompileOptions, it can outlive any given stack frame. * * Note that this *roots* any JS values it refers to - they're live * unconditionally. Thus, instances of this type can't be owned, directly * or indirectly, by a JavaScript object: if any value that this roots ever * comes to refer to the object that owns this, then the whole cycle, and * anything else it entrains, will never be freed. */ class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions { JSRuntime* runtime; PersistentRootedObject elementRoot; PersistentRootedString elementAttributeNameRoot; PersistentRootedScript introductionScriptRoot; public: // A minimal constructor, for use with OwningCompileOptions::copy. This // leaves |this.version| set to JSVERSION_UNKNOWN; the instance // shouldn't be used until we've set that to something real (as |copy| // will). explicit OwningCompileOptions(JSContext* cx); ~OwningCompileOptions(); JSObject* element() const override { return elementRoot; } JSString* elementAttributeName() const override { return elementAttributeNameRoot; } JSScript* introductionScript() const override { return introductionScriptRoot; } // Set this to a copy of |rhs|. Return false on OOM. bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs); /* These setters make copies of their string arguments, and are fallible. */ bool setFile(JSContext* cx, const char* f); bool setFileAndLine(JSContext* cx, const char* f, unsigned l); bool setSourceMapURL(JSContext* cx, const char16_t* s); bool setIntroducerFilename(JSContext* cx, const char* s); /* These setters are infallible, and can be chained. */ OwningCompileOptions& setLine(unsigned l) { lineno = l; return *this; } OwningCompileOptions& setElement(JSObject* e) { elementRoot = e; return *this; } OwningCompileOptions& setElementAttributeName(JSString* p) { elementAttributeNameRoot = p; return *this; } OwningCompileOptions& setIntroductionScript(JSScript* s) { introductionScriptRoot = s; return *this; } OwningCompileOptions& setMutedErrors(bool mute) { mutedErrors_ = mute; return *this; } OwningCompileOptions& setVersion(JSVersion v) { version = v; versionSet = true; return *this; } OwningCompileOptions& setUTF8(bool u) { utf8 = u; return *this; } OwningCompileOptions& setColumn(unsigned c) { column = c; return *this; } OwningCompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; } OwningCompileOptions& setForEval(bool eval) { forEval = eval; return *this; } OwningCompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } OwningCompileOptions& setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; } OwningCompileOptions& setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; } OwningCompileOptions& setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; } OwningCompileOptions& setIntroductionType(const char* t) { introductionType = t; return *this; } bool setIntroductionInfo(JSContext* cx, const char* introducerFn, const char* intro, unsigned line, JSScript* script, uint32_t offset) { if (!setIntroducerFilename(cx, introducerFn)) return false; introductionType = intro; introductionLineno = line; introductionScriptRoot = script; introductionOffset = offset; hasIntroductionInfo = true; return true; } private: void operator=(const CompileOptions& rhs) = delete; }; /** * Compilation options stored on the stack. An instance of this type * simply holds references to dynamically allocated resources (element; * filename; source map URL) that are owned by something else. If you * create an instance of this type, it's up to you to guarantee that * everything you store in it will outlive it. */ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOptions { RootedObject elementRoot; RootedString elementAttributeNameRoot; RootedScript introductionScriptRoot; public: explicit CompileOptions(JSContext* cx, JSVersion version = JSVERSION_UNKNOWN); CompileOptions(js::ContextFriendFields* cx, const ReadOnlyCompileOptions& rhs) : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx), introductionScriptRoot(cx) { copyPODOptions(rhs); filename_ = rhs.filename(); introducerFilename_ = rhs.introducerFilename(); sourceMapURL_ = rhs.sourceMapURL(); elementRoot = rhs.element(); elementAttributeNameRoot = rhs.elementAttributeName(); introductionScriptRoot = rhs.introductionScript(); } CompileOptions(js::ContextFriendFields* cx, const TransitiveCompileOptions& rhs) : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx), introductionScriptRoot(cx) { copyPODTransitiveOptions(rhs); filename_ = rhs.filename(); introducerFilename_ = rhs.introducerFilename(); sourceMapURL_ = rhs.sourceMapURL(); elementRoot = rhs.element(); elementAttributeNameRoot = rhs.elementAttributeName(); introductionScriptRoot = rhs.introductionScript(); } JSObject* element() const override { return elementRoot; } JSString* elementAttributeName() const override { return elementAttributeNameRoot; } JSScript* introductionScript() const override { return introductionScriptRoot; } CompileOptions& setFile(const char* f) { filename_ = f; return *this; } CompileOptions& setLine(unsigned l) { lineno = l; return *this; } CompileOptions& setFileAndLine(const char* f, unsigned l) { filename_ = f; lineno = l; return *this; } CompileOptions& setSourceMapURL(const char16_t* s) { sourceMapURL_ = s; return *this; } CompileOptions& setElement(JSObject* e) { elementRoot = e; return *this; } CompileOptions& setElementAttributeName(JSString* p) { elementAttributeNameRoot = p; return *this; } CompileOptions& setIntroductionScript(JSScript* s) { introductionScriptRoot = s; return *this; } CompileOptions& setMutedErrors(bool mute) { mutedErrors_ = mute; return *this; } CompileOptions& setVersion(JSVersion v) { version = v; versionSet = true; return *this; } CompileOptions& setUTF8(bool u) { utf8 = u; return *this; } CompileOptions& setColumn(unsigned c) { column = c; return *this; } CompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; } CompileOptions& setForEval(bool eval) { forEval = eval; return *this; } CompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } CompileOptions& setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; } CompileOptions& setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; } CompileOptions& setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; } CompileOptions& setIntroductionType(const char* t) { introductionType = t; return *this; } CompileOptions& setIntroductionInfo(const char* introducerFn, const char* intro, unsigned line, JSScript* script, uint32_t offset) { introducerFilename_ = introducerFn; introductionType = intro; introductionLineno = line; introductionScriptRoot = script; introductionOffset = offset; hasIntroductionInfo = true; return *this; } CompileOptions& maybeMakeStrictMode(bool strict) { strictOption = strictOption || strict; return *this; } private: void operator=(const CompileOptions& rhs) = delete; }; /** * |script| will always be set. On failure, it will be set to nullptr. */ extern JS_PUBLIC_API(bool) Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SourceBufferHolder& srcBuf, JS::MutableHandleScript script); extern JS_PUBLIC_API(bool) Compile(JSContext* cx, const ReadOnlyCompileOptions& options, const char* bytes, size_t length, JS::MutableHandleScript script); extern JS_PUBLIC_API(bool) Compile(JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, JS::MutableHandleScript script); extern JS_PUBLIC_API(bool) Compile(JSContext* cx, const ReadOnlyCompileOptions& options, FILE* file, JS::MutableHandleScript script); extern JS_PUBLIC_API(bool) Compile(JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, JS::MutableHandleScript script); extern JS_PUBLIC_API(bool) CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, SourceBufferHolder& srcBuf, JS::MutableHandleScript script); extern JS_PUBLIC_API(bool) CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, const char* bytes, size_t length, JS::MutableHandleScript script); extern JS_PUBLIC_API(bool) CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, JS::MutableHandleScript script); extern JS_PUBLIC_API(bool) CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, FILE* file, JS::MutableHandleScript script); extern JS_PUBLIC_API(bool) CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, JS::MutableHandleScript script); extern JS_PUBLIC_API(bool) CanCompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length); /* * Off thread compilation control flow. * * After successfully triggering an off thread compile of a script, the * callback will eventually be invoked with the specified data and a token * for the compilation. The callback will be invoked while off the main thread, * so must ensure that its operations are thread safe. Afterwards, * FinishOffThreadScript must be invoked on the main thread to get the result * script or nullptr. If maybecx is not specified, the resources will be freed, * but no script will be returned. * * The characters passed in to CompileOffThread must remain live until the * callback is invoked, and the resulting script will be rooted until the call * to FinishOffThreadScript. */ extern JS_PUBLIC_API(bool) CompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, OffThreadCompileCallback callback, void* callbackData); extern JS_PUBLIC_API(JSScript*) FinishOffThreadScript(JSContext* maybecx, JSRuntime* rt, void* token); /** * Compile a function with scopeChain plus the global as its scope chain. * scopeChain must contain objects in the current compartment of cx. The actual * scope chain used for the function will consist of With wrappers for those * objects, followed by the current global of the compartment cx is in. This * global must not be explicitly included in the scope chain. */ extern JS_PUBLIC_API(bool) CompileFunction(JSContext* cx, AutoObjectVector& scopeChain, const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, const char* const* argnames, const char16_t* chars, size_t length, JS::MutableHandleFunction fun); /** * Same as above, but taking a SourceBufferHolder for the function body. */ extern JS_PUBLIC_API(bool) CompileFunction(JSContext* cx, AutoObjectVector& scopeChain, const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, const char* const* argnames, SourceBufferHolder& srcBuf, JS::MutableHandleFunction fun); /** * Same as above, but taking a const char * for the function body. */ extern JS_PUBLIC_API(bool) CompileFunction(JSContext* cx, AutoObjectVector& scopeChain, const ReadOnlyCompileOptions& options, const char* name, unsigned nargs, const char* const* argnames, const char* bytes, size_t length, JS::MutableHandleFunction fun); } /* namespace JS */ extern JS_PUBLIC_API(JSString*) JS_DecompileScript(JSContext* cx, JS::Handle script, const char* name, unsigned indent); /* * API extension: OR this into indent to avoid pretty-printing the decompiled * source resulting from JS_DecompileFunction. */ #define JS_DONT_PRETTY_PRINT ((unsigned)0x8000) extern JS_PUBLIC_API(JSString*) JS_DecompileFunction(JSContext* cx, JS::Handle fun, unsigned indent); /* * NB: JS_ExecuteScript and the JS::Evaluate APIs come in two flavors: either * they use the global as the scope, or they take an AutoObjectVector of objects * to use as the scope chain. In the former case, the global is also used as * the "this" keyword value and the variables object (ECMA parlance for where * 'var' and 'function' bind names) of the execution context for script. In the * latter case, the first object in the provided list is used, unless the list * is empty, in which case the global is used. * * Why a runtime option? The alternative is to add APIs duplicating those * for the other value of flags, and that doesn't seem worth the code bloat * cost. Such new entry points would probably have less obvious names, too, so * would not tend to be used. The RuntimeOptionsRef adjustment, OTOH, can be * more easily hacked into existing code that does not depend on the bug; such * code can continue to use the familiar JS::Evaluate, etc., entry points. */ /** * Evaluate a script in the scope of the current global of cx. */ extern JS_PUBLIC_API(bool) JS_ExecuteScript(JSContext* cx, JS::HandleScript script, JS::MutableHandleValue rval); extern JS_PUBLIC_API(bool) JS_ExecuteScript(JSContext* cx, JS::HandleScript script); /** * As above, but providing an explicit scope chain. scopeChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the script's scope chain. */ extern JS_PUBLIC_API(bool) JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& scopeChain, JS::HandleScript script, JS::MutableHandleValue rval); extern JS_PUBLIC_API(bool) JS_ExecuteScript(JSContext* cx, JS::AutoObjectVector& scopeChain, JS::HandleScript script); namespace JS { /** * Like the above, but handles a cross-compartment script. If the script is * cross-compartment, it is cloned into the current compartment before executing. */ extern JS_PUBLIC_API(bool) CloneAndExecuteScript(JSContext* cx, JS::Handle script); } /* namespace JS */ namespace JS { /** * Evaluate the given source buffer in the scope of the current global of cx. */ extern JS_PUBLIC_API(bool) Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, SourceBufferHolder& srcBuf, JS::MutableHandleValue rval); /** * As above, but providing an explicit scope chain. scopeChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the script's scope chain. */ extern JS_PUBLIC_API(bool) Evaluate(JSContext* cx, AutoObjectVector& scopeChain, const ReadOnlyCompileOptions& options, SourceBufferHolder& srcBuf, JS::MutableHandleValue rval); /** * Evaluate the given character buffer in the scope of the current global of cx. */ extern JS_PUBLIC_API(bool) Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, JS::MutableHandleValue rval); /** * As above, but providing an explicit scope chain. scopeChain must not include * the global object on it; that's implicit. It needs to contain the other * objects that should end up on the script's scope chain. */ extern JS_PUBLIC_API(bool) Evaluate(JSContext* cx, AutoObjectVector& scopeChain, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, JS::MutableHandleValue rval); /** * Evaluate the given byte buffer in the scope of the current global of cx. */ extern JS_PUBLIC_API(bool) Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, const char* bytes, size_t length, JS::MutableHandleValue rval); /** * Evaluate the given file in the scope of the current global of cx. */ extern JS_PUBLIC_API(bool) Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, const char* filename, JS::MutableHandleValue rval); } /* 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(rt). * * 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(JSInterruptCallback) JS_SetInterruptCallback(JSRuntime* rt, JSInterruptCallback callback); extern JS_PUBLIC_API(JSInterruptCallback) JS_GetInterruptCallback(JSRuntime* rt); extern JS_PUBLIC_API(void) JS_RequestInterruptCallback(JSRuntime* rt); extern JS_PUBLIC_API(bool) JS_IsRunning(JSContext* cx); /* * Saving and restoring frame chains. * * These two functions are used to set aside cx's call stack while that stack * is inactive. After a call to JS_SaveFrameChain, it looks as if there is no * code running on cx. Before calling JS_RestoreFrameChain, cx's call stack * must be balanced and all nested calls to JS_SaveFrameChain must have had * matching JS_RestoreFrameChain calls. * * JS_SaveFrameChain deals with cx not having any code running on it. */ extern JS_PUBLIC_API(bool) JS_SaveFrameChain(JSContext* cx); extern JS_PUBLIC_API(void) JS_RestoreFrameChain(JSContext* cx); namespace JS { /** * This class can be used to store a pointer to the youngest frame of a saved * stack in the specified JSContext. This reference will be picked up by any new * calls performed until the class is destroyed, with the specified asyncCause, * that must not be empty. * * Any stack capture initiated during these new calls will go through the async * stack instead of the current stack. * * Capturing the stack before a new call is performed will not be affected. * * The provided chain of SavedFrame objects can live in any compartment, * although it will be copied to the compartment where the stack is captured. * * 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; RootedString 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. AutoSetAsyncStackForNewCalls(JSContext* cx, HandleObject stack, HandleString 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_AtomizeAndPinJSString(JSContext* cx, JS::HandleString str); 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_NewUCString(JSContext* cx, char16_t* 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_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(bool) JS_StringEqualsAscii(JSContext* cx, JSString* str, const char* asciiBytes, bool* match); extern JS_PUBLIC_API(size_t) JS_PutEscapedString(JSContext* cx, char* buffer, size_t size, JSString* str, char quote); extern JS_PUBLIC_API(bool) JS_FileEscapedString(FILE* fp, 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 "flat" strings that have been explicitly prepared in a * fallible context by JS_FlattenString. To catch errors, a separate opaque * JSFlatString type is returned by JS_FlattenString and expected by * JS_GetFlatStringChars. Note, though, that this is purely a syntactic * distinction: the input and output of JS_FlattenString are the same actual * GC-thing. If a JSString is known to be flat, JS_ASSERT_STRING_IS_FLAT can be * used to make a debug-checked cast. Example: * * // in a fallible context * JSFlatString* fstr = JS_FlattenString(cx, str); * if (!fstr) * return false; * MOZ_ASSERT(fstr == JS_ASSERT_STRING_IS_FLAT(str)); * * // in an infallible context, for the same 'str' * AutoCheckCannotGC nogc; * const char16_t* chars = JS_GetTwoByteFlatStringChars(nogc, fstr) * MOZ_ASSERT(chars); * * Flat strings and interned strings are always null-terminated, so * JS_FlattenString can be used to get a null-terminated string. * * 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_StringIsFlat(JSString* str); /** Returns true iff the string's characters are stored as Latin1. */ extern JS_PUBLIC_API(bool) JS_StringHasLatin1Chars(JSString* str); extern JS_PUBLIC_API(const JS::Latin1Char*) JS_GetLatin1StringCharsAndLength(JSContext* cx, const JS::AutoCheckCannotGC& nogc, JSString* str, size_t* length); extern JS_PUBLIC_API(const char16_t*) JS_GetTwoByteStringCharsAndLength(JSContext* cx, const JS::AutoCheckCannotGC& 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(char16_t) JS_GetFlatStringCharAt(JSFlatString* str, size_t index); 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); extern JS_PUBLIC_API(JSFlatString*) JS_FlattenString(JSContext* cx, JSString* str); extern JS_PUBLIC_API(const JS::Latin1Char*) JS_GetLatin1FlatStringChars(const JS::AutoCheckCannotGC& nogc, JSFlatString* str); extern JS_PUBLIC_API(const char16_t*) JS_GetTwoByteFlatStringChars(const JS::AutoCheckCannotGC& nogc, JSFlatString* str); static MOZ_ALWAYS_INLINE JSFlatString* JSID_TO_FLAT_STRING(jsid jid) { MOZ_ASSERT(JSID_IS_STRING(jid)); return (JSFlatString*)(JSID_BITS(jid)); } static MOZ_ALWAYS_INLINE JSFlatString* JS_ASSERT_STRING_IS_FLAT(JSString* str) { MOZ_ASSERT(JS_StringIsFlat(str)); return (JSFlatString*)str; } static MOZ_ALWAYS_INLINE JSString* JS_FORGET_STRING_FLATNESS(JSFlatString* fstr) { return (JSString*)fstr; } /* * Additional APIs that avoid fallibility when given a flat string. */ extern JS_PUBLIC_API(bool) JS_FlatStringEqualsAscii(JSFlatString* str, const char* asciiBytes); extern JS_PUBLIC_API(size_t) JS_PutEscapedFlatString(char* buffer, size_t size, JSFlatString* 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); /** * A variation on JS_EncodeCharacters where a null terminated string is * returned that you are expected to call JS_free on when done. */ JS_PUBLIC_API(char*) JS_EncodeString(JSContext* cx, JSString* str); /** * Same behavior as JS_EncodeString(), but encode into UTF-8 string */ JS_PUBLIC_API(char*) JS_EncodeStringToUTF8(JSContext* cx, JS::HandleString str); /** * 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. */ JS_PUBLIC_API(size_t) JS_EncodeStringToBuffer(JSContext* cx, JSString* str, char* buffer, size_t length); class MOZ_RAII JSAutoByteString { public: JSAutoByteString(JSContext* cx, JSString* str MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mBytes(JS_EncodeString(cx, str)) { MOZ_ASSERT(cx); MOZ_GUARD_OBJECT_NOTIFIER_INIT; } explicit JSAutoByteString(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) : mBytes(nullptr) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } ~JSAutoByteString() { JS_free(nullptr, mBytes); } /* Take ownership of the given byte array. */ void initBytes(char* bytes) { MOZ_ASSERT(!mBytes); mBytes = bytes; } char* encodeLatin1(JSContext* cx, JSString* str) { MOZ_ASSERT(!mBytes); MOZ_ASSERT(cx); mBytes = JS_EncodeString(cx, str); return mBytes; } char* encodeLatin1(js::ExclusiveContext* cx, JSString* str); char* encodeUtf8(JSContext* cx, JS::HandleString str) { MOZ_ASSERT(!mBytes); MOZ_ASSERT(cx); mBytes = JS_EncodeStringToUTF8(cx, str); return mBytes; } void clear() { js_free(mBytes); mBytes = nullptr; } char* ptr() const { return mBytes; } bool operator!() const { return !mBytes; } size_t length() const { if (!mBytes) return 0; return strlen(mBytes); } private: char* mBytes; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER /* Copy and assignment are not supported. */ JSAutoByteString(const JSAutoByteString& another); JSAutoByteString& operator=(const JSAutoByteString& another); }; namespace JS { extern JS_PUBLIC_API(JSAddonId*) NewAddonId(JSContext* cx, JS::HandleString str); extern JS_PUBLIC_API(JSString*) StringOfAddonId(JSAddonId* id); extern JS_PUBLIC_API(JSAddonId*) AddonIdOfObject(JSObject* obj); } // namespace JS /************************************************************************/ /* * Symbols */ namespace JS { /** * Create a new Symbol with the given description. This function never returns * a Symbol that is in the Runtime-wide symbol registry. * * If description is null, the new Symbol's [[Description]] attribute is * undefined. */ JS_PUBLIC_API(Symbol*) NewSymbol(JSContext* cx, HandleString description); /** * Symbol.for as specified in ES6. * * Get a Symbol with the description 'key' from the Runtime-wide symbol registry. * If there is not already a Symbol with that description in the registry, a new * Symbol is created and registered. 'key' must not be null. */ JS_PUBLIC_API(Symbol*) GetSymbolFor(JSContext* cx, HandleString key); /** * Get the [[Description]] attribute of the given symbol. * * This function is infallible. If it returns null, that means the symbol's * [[Description]] is undefined. */ JS_PUBLIC_API(JSString*) GetSymbolDescription(HandleSymbol symbol); /* Well-known symbols. */ #define JS_FOR_EACH_WELL_KNOWN_SYMBOL(macro) \ macro(iterator) \ macro(match) \ macro(species) \ macro(hasInstance) \ macro(toPrimitive) \ macro(toStringTag) \ macro(unscopables) enum class SymbolCode : uint32_t { // There is one SymbolCode for each well-known symbol. #define JS_DEFINE_SYMBOL_ENUM(name) name, JS_FOR_EACH_WELL_KNOWN_SYMBOL(JS_DEFINE_SYMBOL_ENUM) // SymbolCode::iterator, etc. #undef JS_DEFINE_SYMBOL_ENUM Limit, InSymbolRegistry = 0xfffffffe, // created by Symbol.for() or JS::GetSymbolFor() UniqueSymbol = 0xffffffff // created by Symbol() or JS::NewSymbol() }; /* For use in loops that iterate over the well-known symbols. */ const size_t WellKnownSymbolLimit = size_t(SymbolCode::Limit); /** * Return the SymbolCode telling what sort of symbol `symbol` is. * * A symbol's SymbolCode never changes once it is created. */ JS_PUBLIC_API(SymbolCode) GetSymbolCode(Handle symbol); /** * Get one of the well-known symbols defined by ES6. A single set of well-known * symbols is shared by all compartments in a JSRuntime. * * `which` must be in the range [0, WellKnownSymbolLimit). */ JS_PUBLIC_API(Symbol*) GetWellKnownSymbol(JSContext* cx, SymbolCode which); /** * Return true if the given JSPropertySpec::name or JSFunctionSpec::name value * is actually a symbol code and not a string. See JS_SYM_FN. */ inline bool PropertySpecNameIsSymbol(const char* name) { uintptr_t u = reinterpret_cast(name); return u != 0 && u - 1 < WellKnownSymbolLimit; } JS_PUBLIC_API(bool) PropertySpecNameEqualsId(const char* 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, const char* name, jsid* idp); } /* namespace JS */ /************************************************************************/ /* * JSON functions */ typedef bool (* JSONWriteCallback)(const char16_t* buf, uint32_t len, void* data); /** * JSON.stringify as specified by ES5. */ JS_PUBLIC_API(bool) JS_Stringify(JSContext* cx, JS::MutableHandleValue value, JS::HandleObject replacer, JS::HandleValue space, JSONWriteCallback callback, void* data); /** * JSON.parse as specified by ES5. */ JS_PUBLIC_API(bool) JS_ParseJSON(JSContext* cx, const char16_t* chars, uint32_t len, JS::MutableHandleValue vp); JS_PUBLIC_API(bool) JS_ParseJSON(JSContext* cx, JS::HandleString str, JS::MutableHandleValue vp); JS_PUBLIC_API(bool) JS_ParseJSONWithReviver(JSContext* cx, const char16_t* chars, uint32_t len, JS::HandleValue reviver, JS::MutableHandleValue vp); JS_PUBLIC_API(bool) JS_ParseJSONWithReviver(JSContext* cx, JS::HandleString str, JS::HandleValue reviver, JS::MutableHandleValue vp); /************************************************************************/ /** * The default locale for the ECMAScript Internationalization API * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat). * Note that the Internationalization API encourages clients to * specify their own locales. * The locale string remains owned by the caller. */ extern JS_PUBLIC_API(bool) JS_SetDefaultLocale(JSRuntime* rt, const char* locale); /** * Reset the default locale to OS defaults. */ extern JS_PUBLIC_API(void) JS_ResetDefaultLocale(JSRuntime* rt); /** * Locale specific string conversion and error message callbacks. */ struct JSLocaleCallbacks { JSLocaleToUpperCase localeToUpperCase; JSLocaleToLowerCase localeToLowerCase; JSLocaleCompare localeCompare; // not used #if EXPOSE_INTL_API JSLocaleToUnicode localeToUnicode; }; /** * Establish locale callbacks. The pointer must persist as long as the * JSRuntime. Passing nullptr restores the default behaviour. */ extern JS_PUBLIC_API(void) JS_SetLocaleCallbacks(JSRuntime* rt, const JSLocaleCallbacks* callbacks); /** * Return the address of the current locale callbacks struct, which may * be nullptr. */ extern JS_PUBLIC_API(const JSLocaleCallbacks*) JS_GetLocaleCallbacks(JSRuntime* rt); /************************************************************************/ /* * Error reporting. */ namespace JS { const uint16_t MaxNumErrorArguments = 10; }; /** * Report an exception represented by the sprintf-like conversion of format * and its arguments. This exception message string is passed to a pre-set * JSErrorReporter function (set by JS_SetErrorReporter). */ extern JS_PUBLIC_API(void) JS_ReportError(JSContext* cx, const char* format, ...); /* * Use an errorNumber to retrieve the format string, args are char* */ extern JS_PUBLIC_API(void) JS_ReportErrorNumber(JSContext* cx, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...); #ifdef va_start extern JS_PUBLIC_API(void) JS_ReportErrorNumberVA(JSContext* cx, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, va_list ap); #endif /* * 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); /** * As above, but report a warning instead (JSREPORT_IS_WARNING(report.flags)). * Return true if there was no error trying to issue the warning, and if the * warning was not converted into an error due to the JSOPTION_WERROR option * being set, false otherwise. */ extern JS_PUBLIC_API(bool) JS_ReportWarning(JSContext* cx, const char* format, ...); extern JS_PUBLIC_API(bool) JS_ReportErrorFlagsAndNumber(JSContext* cx, unsigned flags, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...); extern JS_PUBLIC_API(bool) JS_ReportErrorFlagsAndNumberUC(JSContext* cx, unsigned flags, JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, ...); /** * Complain when out of memory. */ extern JS_PUBLIC_API(void) JS_ReportOutOfMemory(JSContext* cx); /** * Complain when an allocation size overflows the maximum supported limit. */ extern JS_PUBLIC_API(void) JS_ReportAllocationOverflow(JSContext* cx); class JSErrorReport { // Offending source line without final '\n'. const char16_t* linebuf_; // Number of chars in linebuf_. Does not include trailing '\0'. size_t linebufLength_; // The 0-based offset of error token in linebuf_. size_t tokenOffset_; public: JSErrorReport() : linebuf_(nullptr), linebufLength_(0), tokenOffset_(0), filename(nullptr), lineno(0), column(0), isMuted(false), flags(0), errorNumber(0), ucmessage(nullptr), messageArgs(nullptr), exnType(0) {} const char* filename; /* source file name, URL, etc., or null */ unsigned lineno; /* source line number */ unsigned column; /* zero-based column index in line */ bool isMuted; /* See the comment in ReadOnlyCompileOptions. */ unsigned flags; /* error/warning, etc. */ unsigned errorNumber; /* the error number, e.g. see js.msg */ const char16_t* ucmessage; /* the (default) error message */ const char16_t** messageArgs; /* arguments for the error message */ int16_t exnType; /* One of the JSExnType constants */ const char16_t* linebuf() const { return linebuf_; } size_t linebufLength() const { return linebufLength_; } size_t tokenOffset() const { return tokenOffset_; } void initLinebuf(const char16_t* linebuf, size_t linebufLength, size_t tokenOffset); }; /* * JSErrorReport flag values. These may be freely composed. */ #define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */ #define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */ #define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ #define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ /* * This condition is an error in strict mode code, a warning if * JS_HAS_STRICT_OPTION(cx), and otherwise should not be reported at * all. We check the strictness of the context's top frame's script; * where that isn't appropriate, the caller should do the right checks * itself instead of using this flag. */ #define JSREPORT_STRICT_MODE_ERROR 0x8 /* * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception * has been thrown for this runtime error, and the host should ignore it. * Exception-aware hosts should also check for JS_IsExceptionPending if * JS_ExecuteScript returns failure, and signal or propagate the exception, as * appropriate. */ #define JSREPORT_IS_WARNING(flags) (((flags) & JSREPORT_WARNING) != 0) #define JSREPORT_IS_EXCEPTION(flags) (((flags) & JSREPORT_EXCEPTION) != 0) #define JSREPORT_IS_STRICT(flags) (((flags) & JSREPORT_STRICT) != 0) #define JSREPORT_IS_STRICT_MODE_ERROR(flags) (((flags) & \ JSREPORT_STRICT_MODE_ERROR) != 0) extern JS_PUBLIC_API(JSErrorReporter) JS_GetErrorReporter(JSRuntime* rt); extern JS_PUBLIC_API(JSErrorReporter) JS_SetErrorReporter(JSRuntime* rt, JSErrorReporter er); 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 */ /* * Dates. */ extern JS_PUBLIC_API(JSObject*) JS_NewDateObject(JSContext* cx, int year, int mon, int mday, int hour, int min, int sec); /** * Returns true and sets |*isDate| indicating whether |obj| is a Date object or * a wrapper around one, otherwise returns false on failure. * * This method returns true with |*isDate == false| when passed a proxy whose * target is a Date, or when passed a revoked proxy. */ extern JS_PUBLIC_API(bool) JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, bool* isDate); /************************************************************************/ /* * Regular Expressions. */ #define JSREG_FOLD 0x01u /* fold uppercase to lowercase */ #define JSREG_GLOB 0x02u /* global exec, creates array of matches */ #define JSREG_MULTILINE 0x04u /* treat ^ and $ as begin and end of line */ #define JSREG_STICKY 0x08u /* only match starting at lastIndex */ #define JSREG_UNICODE 0x10u /* unicode */ extern JS_PUBLIC_API(JSObject*) JS_NewRegExpObject(JSContext* cx, JS::HandleObject obj, const char* bytes, size_t length, unsigned flags); extern JS_PUBLIC_API(JSObject*) JS_NewUCRegExpObject(JSContext* cx, JS::HandleObject obj, const char16_t* chars, size_t length, unsigned flags); extern JS_PUBLIC_API(bool) JS_SetRegExpInput(JSContext* cx, JS::HandleObject obj, JS::HandleString input, bool multiline); extern JS_PUBLIC_API(bool) JS_ClearRegExpStatics(JSContext* cx, JS::HandleObject obj); extern JS_PUBLIC_API(bool) JS_ExecuteRegExp(JSContext* cx, JS::HandleObject obj, JS::HandleObject reobj, char16_t* chars, size_t length, size_t* indexp, bool test, JS::MutableHandleValue rval); /* RegExp interface for clients without a global object. */ extern JS_PUBLIC_API(JSObject*) JS_NewRegExpObjectNoStatics(JSContext* cx, char* bytes, size_t length, unsigned flags); extern JS_PUBLIC_API(JSObject*) JS_NewUCRegExpObjectNoStatics(JSContext* cx, char16_t* chars, size_t length, unsigned flags); extern JS_PUBLIC_API(bool) JS_ExecuteRegExpNoStatics(JSContext* cx, JS::HandleObject reobj, char16_t* chars, size_t length, size_t* indexp, bool test, JS::MutableHandleValue rval); /** * Returns true and sets |*isRegExp| indicating whether |obj| is a RegExp * object or a wrapper around one, otherwise returns false on failure. * * This method returns true with |*isRegExp == false| when passed a proxy whose * target is a RegExp, or when passed a revoked proxy. */ extern JS_PUBLIC_API(bool) JS_ObjectIsRegExp(JSContext* cx, JS::HandleObject obj, bool* isRegExp); extern JS_PUBLIC_API(unsigned) JS_GetRegExpFlags(JSContext* cx, JS::HandleObject obj); extern JS_PUBLIC_API(JSString*) JS_GetRegExpSource(JSContext* cx, JS::HandleObject obj); /************************************************************************/ extern JS_PUBLIC_API(bool) JS_IsExceptionPending(JSContext* cx); extern JS_PUBLIC_API(bool) JS_GetPendingException(JSContext* cx, JS::MutableHandleValue vp); extern JS_PUBLIC_API(void) JS_SetPendingException(JSContext* cx, JS::HandleValue v); extern JS_PUBLIC_API(void) JS_ClearPendingException(JSContext* cx); extern JS_PUBLIC_API(bool) JS_ReportPendingException(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; 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() { wasPropagatingForcedReturn = false; wasOverRecursed = false; wasThrowing = false; exceptionValue.setUndefined(); } /* * 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 */ /* Deprecated API. Use AutoSaveExceptionState instead. */ extern JS_PUBLIC_API(JSExceptionState*) JS_SaveExceptionState(JSContext* cx); extern JS_PUBLIC_API(void) JS_RestoreExceptionState(JSContext* cx, JSExceptionState* state); extern JS_PUBLIC_API(void) JS_DropExceptionState(JSContext* cx, JSExceptionState* state); /** * 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); extern JS_PUBLIC_API(JSObject*) ExceptionStackOrNull(JSContext* cx, JS::HandleObject obj); /* * Throws a StopIteration exception on cx. */ extern JS_PUBLIC_API(bool) JS_ThrowStopIteration(JSContext* cx); extern JS_PUBLIC_API(bool) JS_IsStopIteration(JS::Value v); extern JS_PUBLIC_API(intptr_t) JS_GetCurrentThread(); /** * A JS runtime always has an "owner thread". The owner thread is set when the * runtime is created (to the current thread) and practically all entry points * into the JS engine check that a runtime (or anything contained in the * runtime: context, 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(JSRuntime* rt); /************************************************************************/ /** * 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_GetGCZeal(JSContext* cx, uint8_t* zeal, 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_ScheduleGC(JSContext* cx, uint32_t count); #endif extern JS_PUBLIC_API(void) JS_SetParallelParsingEnabled(JSRuntime* rt, bool enabled); extern JS_PUBLIC_API(void) JS_SetOffthreadIonCompilationEnabled(JSRuntime* rt, bool enabled); #define JIT_COMPILER_OPTIONS(Register) \ Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \ Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \ Register(ION_GVN_ENABLE, "ion.gvn.enable") \ Register(ION_FORCE_IC, "ion.forceinlineCaches") \ Register(ION_ENABLE, "ion.enable") \ Register(BASELINE_ENABLE, "baseline.enable") \ Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ Register(SIGNALS_ENABLE, "signals.enable") 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(JSRuntime* rt, JSJitCompilerOption opt, uint32_t value); extern JS_PUBLIC_API(int) JS_GetGlobalJitCompilerOption(JSRuntime* rt, JSJitCompilerOption opt); /** * 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 { /** * AutoFilename encapsulates a pointer to a C-string and keeps the C-string * alive for as long as the associated AutoFilename object is alive. */ class MOZ_STACK_CLASS JS_PUBLIC_API(AutoFilename) { void* scriptSource_; AutoFilename(const AutoFilename&) = delete; void operator=(const AutoFilename&) = delete; public: AutoFilename() : scriptSource_(nullptr) {} ~AutoFilename() { reset(nullptr); } const char* get() const; void reset(void* newScriptSource); }; /** * 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 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : mContext(cx) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; HideScriptedCaller(mContext); } ~AutoHideScriptedCaller() { UnhideScriptedCaller(mContext); } protected: JSContext* mContext; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; } /* namespace JS */ /* * Encode/Decode interpreted scripts and functions to/from memory. */ extern JS_PUBLIC_API(void*) JS_EncodeScript(JSContext* cx, JS::HandleScript script, uint32_t* lengthp); extern JS_PUBLIC_API(void*) JS_EncodeInterpretedFunction(JSContext* cx, JS::HandleObject funobj, uint32_t* lengthp); extern JS_PUBLIC_API(JSScript*) JS_DecodeScript(JSContext* cx, const void* data, uint32_t length); extern JS_PUBLIC_API(JSObject*) JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length); namespace JS { /* * This callback represents a request by the JS engine to open for reading the * existing cache entry for the given global and char range that may contain a * module. If a cache entry exists, the callback shall return 'true' and return * the size, base address and an opaque file handle as outparams. If the * callback returns 'true', the JS engine guarantees a call to * CloseAsmJSCacheEntryForReadOp, passing the same base address, size and * handle. */ typedef bool (* OpenAsmJSCacheEntryForReadOp)(HandleObject global, const char16_t* begin, const char16_t* limit, size_t* size, const uint8_t** memory, intptr_t* handle); typedef void (* CloseAsmJSCacheEntryForReadOp)(size_t size, const uint8_t* memory, intptr_t handle); /** The list of reasons why an asm.js module may not be stored in the cache. */ enum AsmJSCacheResult { AsmJSCache_MIN, AsmJSCache_Success = AsmJSCache_MIN, AsmJSCache_ModuleTooSmall, AsmJSCache_SynchronousScript, AsmJSCache_QuotaExceeded, AsmJSCache_StorageInitFailure, AsmJSCache_Disabled_Internal, AsmJSCache_Disabled_ShellFlags, AsmJSCache_Disabled_JitInspector, AsmJSCache_InternalError, AsmJSCache_LIMIT }; /* * This callback represents a request by the JS engine to open for writing a * cache entry of the given size for the given global and char range containing * the just-compiled module. If cache entry space is available, the callback * shall return 'true' and return the base address and an opaque file handle as * outparams. If the callback returns 'true', the JS engine guarantees a call * to CloseAsmJSCacheEntryForWriteOp passing the same base address, size and * handle. * * If 'installed' is true, then the cache entry is associated with a permanently * installed JS file (e.g., in a packaged webapp). This information allows the * embedding to store the cache entry in a installed location associated with * the principal of 'global' where it will not be evicted until the associated * installed JS file is removed. */ typedef AsmJSCacheResult (* OpenAsmJSCacheEntryForWriteOp)(HandleObject global, bool installed, const char16_t* begin, const char16_t* end, size_t size, uint8_t** memory, intptr_t* handle); typedef void (* CloseAsmJSCacheEntryForWriteOp)(size_t size, uint8_t* memory, intptr_t handle); typedef js::Vector BuildIdCharVector; /** * Return the buildId (represented as a sequence of characters) associated with * the currently-executing build. If the JS engine is embedded such that a * single cache entry can be observed by different compiled versions of the JS * engine, it is critical that the buildId shall change for each new build of * the JS engine. */ typedef bool (* BuildIdOp)(BuildIdCharVector* buildId); struct AsmJSCacheOps { OpenAsmJSCacheEntryForReadOp openEntryForRead; CloseAsmJSCacheEntryForReadOp closeEntryForRead; OpenAsmJSCacheEntryForWriteOp openEntryForWrite; CloseAsmJSCacheEntryForWriteOp closeEntryForWrite; BuildIdOp buildId; }; extern JS_PUBLIC_API(void) SetAsmJSCacheOps(JSRuntime* rt, const AsmJSCacheOps* callbacks); /** * Convenience class for imitating a JS level for-of loop. Typical usage: * * ForOfIterator it(cx); * if (!it.init(iterable)) * return false; * RootedValue val(cx); * while (true) { * bool done; * if (!it.next(&val, &done)) * return false; * if (done) * break; * if (!DoStuff(cx, val)) * return false; * } */ class MOZ_STACK_CLASS JS_PUBLIC_API(ForOfIterator) { protected: JSContext* cx_; /* * Use the ForOfPIC on the global object (see vm/GlobalObject.h) to try * to optimize iteration across arrays. * * Case 1: Regular Iteration * iterator - pointer to the iterator object. * index - fixed to NOT_ARRAY (== UINT32_MAX) * * Case 2: Optimized Array Iteration * iterator - pointer to the array object. * index - current position in array. * * The cases are distinguished by whether or not |index| is equal to NOT_ARRAY. */ JS::RootedObject iterator; uint32_t index; static const uint32_t NOT_ARRAY = UINT32_MAX; ForOfIterator(const ForOfIterator&) = delete; ForOfIterator& operator=(const ForOfIterator&) = delete; public: explicit ForOfIterator(JSContext* cx) : cx_(cx), iterator(cx_), index(NOT_ARRAY) { } enum NonIterableBehavior { ThrowOnNonIterable, AllowNonIterable }; /** * Initialize the iterator. If AllowNonIterable is passed then if getting * the @@iterator property from iterable returns undefined init() will just * return true instead of throwing. Callers must then check * valueIsIterable() before continuing with the iteration. */ bool init(JS::HandleValue iterable, NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable); /** * Get the next value from the iterator. If false *done is true * after this call, do not examine val. */ bool next(JS::MutableHandleValue val, bool* done); /** * If initialized with throwOnNonCallable = false, check whether * the value is iterable. */ bool valueIsIterable() const { return iterator; } private: inline bool nextFromOptimizedArray(MutableHandleValue val, bool* done); bool materializeArrayIterator(); }; /** * 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.) */ typedef void (* LargeAllocationFailureCallback)(void* data); extern JS_PUBLIC_API(void) SetLargeAllocationFailureCallback(JSRuntime* rt, LargeAllocationFailureCallback afc, void* data); /** * 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. */ typedef void (* OutOfMemoryCallback)(JSContext* cx, void* data); extern JS_PUBLIC_API(void) SetOutOfMemoryCallback(JSRuntime* rt, OutOfMemoryCallback cb, void* data); /** * 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. If |maxFrameCount| is non-zero, capture at * most the youngest |maxFrameCount| frames. */ extern JS_PUBLIC_API(bool) CaptureCurrentStack(JSContext* cx, MutableHandleObject stackp, unsigned maxFrameCount = 0); /* * 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 * non-zero, capture at most the youngest |maxFrameCount| 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, unsigned maxFrameCount); /* * Accessors for working with SavedFrame JSObjects * * Each of these functions assert that if their `HandleObject savedFrame` * argument is non-null, its JSClass is the SavedFrame class (or it is a * cross-compartment or Xray wrapper around an object with the SavedFrame class) * and the object is not the SavedFrame.prototype object. * * Each of these functions will find the first SavedFrame object in the chain * whose underlying stack frame principals are subsumed by the cx's current * compartment's principals, and operate on that SavedFrame object. This * prevents leaking information about privileged frames to un-privileged * callers. As a result, the SavedFrame in parameters do _NOT_ need to be in the * same compartment as the cx, and the various out parameters are _NOT_ * guaranteed to be in the same compartment as cx. * * You may consider or skip over self-hosted frames by passing * `SavedFrameSelfHosted::Include` or `SavedFrameSelfHosted::Exclude` * respectively. * * Additionally, it may be the case that there is no such SavedFrame object * whose captured frame's principals are subsumed by the caller's compartment's * principals! If the `HandleObject savedFrame` argument is null, or the * caller's principals do not subsume any of the chained SavedFrame object's * principals, `SavedFrameResult::AccessDenied` is returned and a (hopefully) * sane default value is chosen for the out param. * * See also `js/src/doc/SavedFrame/SavedFrame.md`. */ enum class SavedFrameResult { Ok, AccessDenied }; enum class SavedFrameSelfHosted { Include, Exclude }; /** * Given a SavedFrame JSObject, get its source property. Defaults to the empty * string. */ extern JS_PUBLIC_API(SavedFrameResult) GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString sourcep, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its line property. Defaults to 0. */ extern JS_PUBLIC_API(SavedFrameResult) GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its column property. Defaults to 0. */ extern JS_PUBLIC_API(SavedFrameResult) GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its functionDisplayName string, or nullptr * if SpiderMonkey was unable to infer a name for the captured frame's * function. Defaults to nullptr. */ extern JS_PUBLIC_API(SavedFrameResult) GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, MutableHandleString namep, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its asyncCause string. Defaults to nullptr. */ extern JS_PUBLIC_API(SavedFrameResult) GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleString asyncCausep, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its asyncParent SavedFrame object or nullptr * if there is no asyncParent. The `asyncParentp` out parameter is _NOT_ * guaranteed to be in the cx's compartment. Defaults to nullptr. */ extern JS_PUBLIC_API(SavedFrameResult) GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject asyncParentp, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * Given a SavedFrame JSObject, get its parent SavedFrame object or nullptr if * it is the oldest frame in the stack. The `parentp` out parameter is _NOT_ * guaranteed to be in the cx's compartment. Defaults to nullptr. */ extern JS_PUBLIC_API(SavedFrameResult) GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject parentp, SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include); /** * 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. * * Optional indent parameter specifies the number of white spaces to indent * each line. */ extern JS_PUBLIC_API(bool) BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp, size_t indent = 0); } /* namespace JS */ /* Stopwatch-based performance monitoring. */ namespace js { class AutoStopwatch; /** * Abstract base class for a representation of the performance of a * component. Embeddings interested in performance monitoring should * provide a concrete implementation of this class, as well as the * relevant callbacks (see below). */ struct PerformanceGroup { PerformanceGroup(); // The current iteration of the event loop. uint64_t iteration() const; // `true` if an instance of `AutoStopwatch` is already monitoring // the performance of this performance group for this iteration // of the event loop, `false` otherwise. bool isAcquired(uint64_t it) const; // `true` if a specific instance of `AutoStopwatch` is already monitoring // the performance of this performance group for this iteration // of the event loop, `false` otherwise. bool isAcquired(uint64_t it, const AutoStopwatch* owner) const; // Mark that an instance of `AutoStopwatch` is monitoring // the performance of this group for a given iteration. void acquire(uint64_t it, const AutoStopwatch* owner); // Mark that no `AutoStopwatch` is monitoring the // performance of this group for the iteration. void release(uint64_t it, const AutoStopwatch* owner); // The number of cycles spent in this group during this iteration // of the event loop. Note that cycles are not a reliable measure, // especially over short intervals. See Stopwatch.* for a more // complete discussion on the imprecision of cycle measurement. uint64_t recentCycles(uint64_t iteration) const; void addRecentCycles(uint64_t iteration, uint64_t cycles); // The number of times this group has been activated during this // iteration of the event loop. uint64_t recentTicks(uint64_t iteration) const; void addRecentTicks(uint64_t iteration, uint64_t ticks); // The number of microseconds spent doing CPOW during this // iteration of the event loop. uint64_t recentCPOW(uint64_t iteration) const; void addRecentCPOW(uint64_t iteration, uint64_t CPOW); // Get rid of any data that pretends to be recent. void resetRecentData(); // `true` if new measures should be added to this group, `false` // otherwise. bool isActive() const; void setIsActive(bool); // `true` if this group has been used in the current iteration, // `false` otherwise. bool isUsedInThisIteration() const; void setIsUsedInThisIteration(bool); protected: // An implementation of `delete` for this object. Must be provided // by the embedding. virtual void Delete() = 0; private: // The number of cycles spent in this group during this iteration // of the event loop. Note that cycles are not a reliable measure, // especially over short intervals. See Runtime.cpp for a more // complete discussion on the imprecision of cycle measurement. uint64_t recentCycles_; // The number of times this group has been activated during this // iteration of the event loop. uint64_t recentTicks_; // The number of microseconds spent doing CPOW during this // iteration of the event loop. uint64_t recentCPOW_; // The current iteration of the event loop. If necessary, // may safely overflow. uint64_t iteration_; // `true` if new measures should be added to this group, `false` // otherwise. bool isActive_; // `true` if this group has been used in the current iteration, // `false` otherwise. bool isUsedInThisIteration_; // The stopwatch currently monitoring the group, // or `nullptr` if none. Used ony for comparison. const AutoStopwatch* owner_; public: // Compatibility with RefPtr<> void AddRef(); void Release(); uint64_t refCount_; }; /** * Commit any Performance Monitoring data. * * Until `FlushMonitoring` has been called, all PerformanceMonitoring data is invisible * to the outside world and can cancelled with a call to `ResetMonitoring`. */ extern JS_PUBLIC_API(bool) FlushPerformanceMonitoring(JSRuntime*); /** * Cancel any measurement that hasn't been committed. */ extern JS_PUBLIC_API(void) ResetPerformanceMonitoring(JSRuntime*); /** * Cleanup any memory used by performance monitoring. */ extern JS_PUBLIC_API(void) DisposePerformanceMonitoring(JSRuntime*); /** * Turn on/off stopwatch-based CPU monitoring. * * `SetStopwatchIsMonitoringCPOW` or `SetStopwatchIsMonitoringJank` * may return `false` if monitoring could not be activated, which may * happen if we are out of memory. */ extern JS_PUBLIC_API(bool) SetStopwatchIsMonitoringCPOW(JSRuntime*, bool); extern JS_PUBLIC_API(bool) GetStopwatchIsMonitoringCPOW(JSRuntime*); extern JS_PUBLIC_API(bool) SetStopwatchIsMonitoringJank(JSRuntime*, bool); extern JS_PUBLIC_API(bool) GetStopwatchIsMonitoringJank(JSRuntime*); extern JS_PUBLIC_API(bool) IsStopwatchActive(JSRuntime*); // Extract the CPU rescheduling data. extern JS_PUBLIC_API(void) GetPerfMonitoringTestCpuRescheduling(JSRuntime*, uint64_t* stayed, uint64_t* moved); /** * Add a number of microseconds to the time spent waiting on CPOWs * since process start. */ extern JS_PUBLIC_API(void) AddCPOWPerformanceDelta(JSRuntime*, uint64_t delta); typedef bool (*StopwatchStartCallback)(uint64_t, void*); extern JS_PUBLIC_API(bool) SetStopwatchStartCallback(JSRuntime*, StopwatchStartCallback, void*); typedef bool (*StopwatchCommitCallback)(uint64_t, mozilla::Vector>&, void*); extern JS_PUBLIC_API(bool) SetStopwatchCommitCallback(JSRuntime*, StopwatchCommitCallback, void*); typedef bool (*GetGroupsCallback)(JSContext*, mozilla::Vector>&, void*); extern JS_PUBLIC_API(bool) SetGetPerformanceGroupsCallback(JSRuntime*, GetGroupsCallback, void*); } /* namespace js */ #endif /* jsapi_h */