michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* JavaScript API. */ michael@0: michael@0: #ifndef jsapi_h michael@0: #define jsapi_h michael@0: michael@0: #include "mozilla/FloatingPoint.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/RangedPtr.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "jsalloc.h" michael@0: #include "jspubtd.h" michael@0: michael@0: #include "js/CallArgs.h" michael@0: #include "js/Class.h" michael@0: #include "js/HashTable.h" michael@0: #include "js/Id.h" michael@0: #include "js/Principals.h" michael@0: #include "js/RootingAPI.h" michael@0: #include "js/TracingAPI.h" michael@0: #include "js/Utility.h" michael@0: #include "js/Value.h" michael@0: #include "js/Vector.h" michael@0: michael@0: /************************************************************************/ michael@0: michael@0: namespace JS { michael@0: michael@0: class Latin1CharsZ; michael@0: class TwoByteChars; michael@0: michael@0: #if defined JS_THREADSAFE && defined JS_DEBUG michael@0: michael@0: class JS_PUBLIC_API(AutoCheckRequestDepth) michael@0: { michael@0: JSContext *cx; michael@0: public: michael@0: AutoCheckRequestDepth(JSContext *cx); michael@0: AutoCheckRequestDepth(js::ContextFriendFields *cx); michael@0: ~AutoCheckRequestDepth(); michael@0: }; michael@0: michael@0: # define CHECK_REQUEST(cx) \ michael@0: JS::AutoCheckRequestDepth _autoCheckRequestDepth(cx) michael@0: michael@0: #else michael@0: michael@0: # define CHECK_REQUEST(cx) \ michael@0: ((void) 0) michael@0: michael@0: #endif /* JS_THREADSAFE && JS_DEBUG */ michael@0: michael@0: #ifdef JS_DEBUG michael@0: /* michael@0: * Assert that we're not doing GC on cx, that we're in a request as michael@0: * needed, and that the compartments for cx and v are correct. michael@0: * Also check that GC would be safe at this point. michael@0: */ michael@0: JS_PUBLIC_API(void) michael@0: AssertArgumentsAreSane(JSContext *cx, JS::HandleValue v); michael@0: #else michael@0: inline void AssertArgumentsAreSane(JSContext *cx, JS::HandleValue v) { michael@0: /* Do nothing */ michael@0: } michael@0: #endif /* JS_DEBUG */ michael@0: michael@0: class JS_PUBLIC_API(AutoGCRooter) { michael@0: public: michael@0: AutoGCRooter(JSContext *cx, ptrdiff_t tag); michael@0: AutoGCRooter(js::ContextFriendFields *cx, ptrdiff_t tag); michael@0: michael@0: ~AutoGCRooter() { michael@0: JS_ASSERT(this == *stackTop); michael@0: *stackTop = down; michael@0: } michael@0: michael@0: /* Implemented in gc/RootMarking.cpp. */ michael@0: inline void trace(JSTracer *trc); michael@0: static void traceAll(JSTracer *trc); michael@0: static void traceAllWrappers(JSTracer *trc); michael@0: michael@0: protected: michael@0: AutoGCRooter * const down; michael@0: michael@0: /* michael@0: * Discriminates actual subclass of this being used. If non-negative, the michael@0: * subclass roots an array of values of the length stored in this field. michael@0: * If negative, meaning is indicated by the corresponding value in the enum michael@0: * below. Any other negative value indicates some deeper problem such as michael@0: * memory corruption. michael@0: */ michael@0: ptrdiff_t tag_; michael@0: michael@0: enum { michael@0: VALARRAY = -2, /* js::AutoValueArray */ michael@0: PARSER = -3, /* js::frontend::Parser */ michael@0: SHAPEVECTOR = -4, /* js::AutoShapeVector */ michael@0: IDARRAY = -6, /* js::AutoIdArray */ michael@0: DESCRIPTORS = -7, /* js::AutoPropDescArrayRooter */ michael@0: ID = -9, /* js::AutoIdRooter */ michael@0: VALVECTOR = -10, /* js::AutoValueVector */ michael@0: IDVECTOR = -13, /* js::AutoIdVector */ michael@0: OBJVECTOR = -14, /* js::AutoObjectVector */ michael@0: STRINGVECTOR =-15, /* js::AutoStringVector */ michael@0: SCRIPTVECTOR =-16, /* js::AutoScriptVector */ michael@0: NAMEVECTOR = -17, /* js::AutoNameVector */ michael@0: HASHABLEVALUE=-18, /* js::HashableValue */ michael@0: IONMASM = -19, /* js::jit::MacroAssembler */ michael@0: IONALLOC = -20, /* js::jit::AutoTempAllocatorRooter */ michael@0: WRAPVECTOR = -21, /* js::AutoWrapperVector */ michael@0: WRAPPER = -22, /* js::AutoWrapperRooter */ michael@0: OBJOBJHASHMAP=-23, /* js::AutoObjectObjectHashMap */ michael@0: OBJU32HASHMAP=-24, /* js::AutoObjectUnsigned32HashMap */ michael@0: OBJHASHSET = -25, /* js::AutoObjectHashSet */ michael@0: JSONPARSER = -26, /* js::JSONParser */ michael@0: CUSTOM = -27, /* js::CustomAutoRooter */ michael@0: FUNVECTOR = -28 /* js::AutoFunctionVector */ michael@0: }; michael@0: michael@0: private: michael@0: AutoGCRooter ** const stackTop; michael@0: michael@0: /* No copy or assignment semantics. */ michael@0: AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE; michael@0: void operator=(AutoGCRooter &ida) MOZ_DELETE; michael@0: }; michael@0: michael@0: /* AutoValueArray roots an internal fixed-size array of Values. */ michael@0: template michael@0: class AutoValueArray : public AutoGCRooter michael@0: { michael@0: const size_t length_; michael@0: Value elements_[N]; michael@0: michael@0: public: michael@0: AutoValueArray(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoGCRooter(cx, VALARRAY), length_(N) michael@0: { michael@0: /* Always initialize in case we GC before assignment. */ michael@0: mozilla::PodArrayZero(elements_); michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: unsigned length() const { return length_; } michael@0: const Value *begin() const { return elements_; } michael@0: Value *begin() { return elements_; } michael@0: michael@0: HandleValue operator[](unsigned i) const { michael@0: JS_ASSERT(i < N); michael@0: return HandleValue::fromMarkedLocation(&elements_[i]); michael@0: } michael@0: MutableHandleValue operator[](unsigned i) { michael@0: JS_ASSERT(i < N); michael@0: return MutableHandleValue::fromMarkedLocation(&elements_[i]); michael@0: } michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: template michael@0: class AutoVectorRooter : protected AutoGCRooter michael@0: { michael@0: typedef js::Vector VectorImpl; michael@0: VectorImpl vector; michael@0: michael@0: public: michael@0: explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoGCRooter(cx, tag), vector(cx) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: explicit AutoVectorRooter(js::ContextFriendFields *cx, ptrdiff_t tag michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoGCRooter(cx, tag), vector(cx) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: typedef T ElementType; michael@0: typedef typename VectorImpl::Range Range; michael@0: michael@0: size_t length() const { return vector.length(); } michael@0: bool empty() const { return vector.empty(); } michael@0: michael@0: bool append(const T &v) { return vector.append(v); } michael@0: bool append(const T *ptr, size_t len) { return vector.append(ptr, len); } michael@0: bool appendAll(const AutoVectorRooter &other) { michael@0: return vector.appendAll(other.vector); michael@0: } michael@0: michael@0: bool insert(T *p, const T &val) { return vector.insert(p, val); } michael@0: michael@0: /* For use when space has already been reserved. */ michael@0: void infallibleAppend(const T &v) { vector.infallibleAppend(v); } michael@0: michael@0: void popBack() { vector.popBack(); } michael@0: T popCopy() { return vector.popCopy(); } michael@0: michael@0: bool growBy(size_t inc) { michael@0: size_t oldLength = vector.length(); michael@0: if (!vector.growByUninitialized(inc)) michael@0: return false; michael@0: makeRangeGCSafe(oldLength); michael@0: return true; michael@0: } michael@0: michael@0: bool resize(size_t newLength) { michael@0: size_t oldLength = vector.length(); michael@0: if (newLength <= oldLength) { michael@0: vector.shrinkBy(oldLength - newLength); michael@0: return true; michael@0: } michael@0: if (!vector.growByUninitialized(newLength - oldLength)) michael@0: return false; michael@0: makeRangeGCSafe(oldLength); michael@0: return true; michael@0: } michael@0: michael@0: void clear() { vector.clear(); } michael@0: michael@0: bool reserve(size_t newLength) { michael@0: return vector.reserve(newLength); michael@0: } michael@0: michael@0: T &operator[](size_t i) { return vector[i]; } michael@0: const T &operator[](size_t i) const { return vector[i]; } michael@0: michael@0: JS::MutableHandle handleAt(size_t i) { michael@0: return JS::MutableHandle::fromMarkedLocation(&vector[i]); michael@0: } michael@0: JS::Handle handleAt(size_t i) const { michael@0: return JS::Handle::fromMarkedLocation(&vector[i]); michael@0: } michael@0: michael@0: const T *begin() const { return vector.begin(); } michael@0: T *begin() { return vector.begin(); } michael@0: michael@0: const T *end() const { return vector.end(); } michael@0: T *end() { return vector.end(); } michael@0: michael@0: Range all() { return vector.all(); } michael@0: michael@0: const T &back() const { return vector.back(); } michael@0: michael@0: friend void AutoGCRooter::trace(JSTracer *trc); michael@0: michael@0: private: michael@0: void makeRangeGCSafe(size_t oldLength) { michael@0: T *t = vector.begin() + oldLength; michael@0: for (size_t i = oldLength; i < vector.length(); ++i, ++t) michael@0: memset(t, 0, sizeof(T)); michael@0: } michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: template michael@0: class AutoHashMapRooter : protected AutoGCRooter michael@0: { michael@0: private: michael@0: typedef js::HashMap HashMapImpl; michael@0: michael@0: public: michael@0: explicit AutoHashMapRooter(JSContext *cx, ptrdiff_t tag michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoGCRooter(cx, tag), map(cx) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: typedef Key KeyType; michael@0: typedef Value ValueType; michael@0: typedef typename HashMapImpl::Entry Entry; michael@0: typedef typename HashMapImpl::Lookup Lookup; michael@0: typedef typename HashMapImpl::Ptr Ptr; michael@0: typedef typename HashMapImpl::AddPtr AddPtr; michael@0: michael@0: bool init(uint32_t len = 16) { michael@0: return map.init(len); michael@0: } michael@0: bool initialized() const { michael@0: return map.initialized(); michael@0: } michael@0: Ptr lookup(const Lookup &l) const { michael@0: return map.lookup(l); michael@0: } michael@0: void remove(Ptr p) { michael@0: map.remove(p); michael@0: } michael@0: AddPtr lookupForAdd(const Lookup &l) const { michael@0: return map.lookupForAdd(l); michael@0: } michael@0: michael@0: template michael@0: bool add(AddPtr &p, const KeyInput &k, const ValueInput &v) { michael@0: return map.add(p, k, v); michael@0: } michael@0: michael@0: bool add(AddPtr &p, const Key &k) { michael@0: return map.add(p, k); michael@0: } michael@0: michael@0: template michael@0: bool relookupOrAdd(AddPtr &p, const KeyInput &k, const ValueInput &v) { michael@0: return map.relookupOrAdd(p, k, v); michael@0: } michael@0: michael@0: typedef typename HashMapImpl::Range Range; michael@0: Range all() const { michael@0: return map.all(); michael@0: } michael@0: michael@0: typedef typename HashMapImpl::Enum Enum; michael@0: michael@0: void clear() { michael@0: map.clear(); michael@0: } michael@0: michael@0: void finish() { michael@0: map.finish(); michael@0: } michael@0: michael@0: bool empty() const { michael@0: return map.empty(); michael@0: } michael@0: michael@0: uint32_t count() const { michael@0: return map.count(); michael@0: } michael@0: michael@0: size_t capacity() const { michael@0: return map.capacity(); michael@0: } michael@0: michael@0: size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { michael@0: return map.sizeOfExcludingThis(mallocSizeOf); michael@0: } michael@0: size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { michael@0: return map.sizeOfIncludingThis(mallocSizeOf); michael@0: } michael@0: michael@0: unsigned generation() const { michael@0: return map.generation(); michael@0: } michael@0: michael@0: /************************************************** Shorthand operations */ michael@0: michael@0: bool has(const Lookup &l) const { michael@0: return map.has(l); michael@0: } michael@0: michael@0: template michael@0: bool put(const KeyInput &k, const ValueInput &v) { michael@0: return map.put(k, v); michael@0: } michael@0: michael@0: template michael@0: bool putNew(const KeyInput &k, const ValueInput &v) { michael@0: return map.putNew(k, v); michael@0: } michael@0: michael@0: Ptr lookupWithDefault(const Key &k, const Value &defaultValue) { michael@0: return map.lookupWithDefault(k, defaultValue); michael@0: } michael@0: michael@0: void remove(const Lookup &l) { michael@0: map.remove(l); michael@0: } michael@0: michael@0: friend void AutoGCRooter::trace(JSTracer *trc); michael@0: michael@0: private: michael@0: AutoHashMapRooter(const AutoHashMapRooter &hmr) MOZ_DELETE; michael@0: AutoHashMapRooter &operator=(const AutoHashMapRooter &hmr) MOZ_DELETE; michael@0: michael@0: HashMapImpl map; michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: template michael@0: class AutoHashSetRooter : protected AutoGCRooter michael@0: { michael@0: private: michael@0: typedef js::HashSet HashSetImpl; michael@0: michael@0: public: michael@0: explicit AutoHashSetRooter(JSContext *cx, ptrdiff_t tag michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoGCRooter(cx, tag), set(cx) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: typedef typename HashSetImpl::Lookup Lookup; michael@0: typedef typename HashSetImpl::Ptr Ptr; michael@0: typedef typename HashSetImpl::AddPtr AddPtr; michael@0: michael@0: bool init(uint32_t len = 16) { michael@0: return set.init(len); michael@0: } michael@0: bool initialized() const { michael@0: return set.initialized(); michael@0: } michael@0: Ptr lookup(const Lookup &l) const { michael@0: return set.lookup(l); michael@0: } michael@0: void remove(Ptr p) { michael@0: set.remove(p); michael@0: } michael@0: AddPtr lookupForAdd(const Lookup &l) const { michael@0: return set.lookupForAdd(l); michael@0: } michael@0: michael@0: bool add(AddPtr &p, const T &t) { michael@0: return set.add(p, t); michael@0: } michael@0: michael@0: bool relookupOrAdd(AddPtr &p, const Lookup &l, const T &t) { michael@0: return set.relookupOrAdd(p, l, t); michael@0: } michael@0: michael@0: typedef typename HashSetImpl::Range Range; michael@0: Range all() const { michael@0: return set.all(); michael@0: } michael@0: michael@0: typedef typename HashSetImpl::Enum Enum; michael@0: michael@0: void clear() { michael@0: set.clear(); michael@0: } michael@0: michael@0: void finish() { michael@0: set.finish(); michael@0: } michael@0: michael@0: bool empty() const { michael@0: return set.empty(); michael@0: } michael@0: michael@0: uint32_t count() const { michael@0: return set.count(); michael@0: } michael@0: michael@0: size_t capacity() const { michael@0: return set.capacity(); michael@0: } michael@0: michael@0: size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { michael@0: return set.sizeOfExcludingThis(mallocSizeOf); michael@0: } michael@0: size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { michael@0: return set.sizeOfIncludingThis(mallocSizeOf); michael@0: } michael@0: michael@0: unsigned generation() const { michael@0: return set.generation(); michael@0: } michael@0: michael@0: /************************************************** Shorthand operations */ michael@0: michael@0: bool has(const Lookup &l) const { michael@0: return set.has(l); michael@0: } michael@0: michael@0: bool put(const T &t) { michael@0: return set.put(t); michael@0: } michael@0: michael@0: bool putNew(const T &t) { michael@0: return set.putNew(t); michael@0: } michael@0: michael@0: void remove(const Lookup &l) { michael@0: set.remove(l); michael@0: } michael@0: michael@0: friend void AutoGCRooter::trace(JSTracer *trc); michael@0: michael@0: private: michael@0: AutoHashSetRooter(const AutoHashSetRooter &hmr) MOZ_DELETE; michael@0: AutoHashSetRooter &operator=(const AutoHashSetRooter &hmr) MOZ_DELETE; michael@0: michael@0: HashSetImpl set; michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: class MOZ_STACK_CLASS AutoValueVector : public AutoVectorRooter michael@0: { michael@0: public: michael@0: explicit AutoValueVector(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoVectorRooter(cx, VALVECTOR) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: class AutoIdVector : public AutoVectorRooter michael@0: { michael@0: public: michael@0: explicit AutoIdVector(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoVectorRooter(cx, IDVECTOR) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: class AutoObjectVector : public AutoVectorRooter michael@0: { michael@0: public: michael@0: explicit AutoObjectVector(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoVectorRooter(cx, OBJVECTOR) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: class AutoFunctionVector : public AutoVectorRooter michael@0: { michael@0: public: michael@0: explicit AutoFunctionVector(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoVectorRooter(cx, FUNVECTOR) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: explicit AutoFunctionVector(js::ContextFriendFields *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoVectorRooter(cx, FUNVECTOR) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: class AutoScriptVector : public AutoVectorRooter michael@0: { michael@0: public: michael@0: explicit AutoScriptVector(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoVectorRooter(cx, SCRIPTVECTOR) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: /* michael@0: * Cutsom rooting behavior for internal and external clients. michael@0: */ michael@0: class JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter michael@0: { michael@0: public: michael@0: template michael@0: explicit CustomAutoRooter(CX *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoGCRooter(cx, CUSTOM) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: friend void AutoGCRooter::trace(JSTracer *trc); michael@0: michael@0: protected: michael@0: /* Supplied by derived class to trace roots. */ michael@0: virtual void trace(JSTracer *trc) = 0; michael@0: michael@0: private: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: /* A handle to an array of rooted values. */ michael@0: class HandleValueArray michael@0: { michael@0: const size_t length_; michael@0: const Value * const elements_; michael@0: michael@0: HandleValueArray(size_t len, const Value *elements) : length_(len), elements_(elements) {} michael@0: michael@0: public: michael@0: HandleValueArray(const RootedValue& value) : length_(1), elements_(value.address()) {} michael@0: michael@0: HandleValueArray(const AutoValueVector& values) michael@0: : length_(values.length()), elements_(values.begin()) {} michael@0: michael@0: template michael@0: HandleValueArray(const AutoValueArray& values) : length_(N), elements_(values.begin()) {} michael@0: michael@0: /* CallArgs must already be rooted somewhere up the stack. */ michael@0: HandleValueArray(const JS::CallArgs& args) : length_(args.length()), elements_(args.array()) {} michael@0: michael@0: /* Use with care! Only call this if the data is guaranteed to be marked. */ michael@0: static HandleValueArray fromMarkedLocation(size_t len, const Value *elements) { michael@0: return HandleValueArray(len, elements); michael@0: } michael@0: michael@0: static HandleValueArray subarray(const HandleValueArray& values, size_t startIndex, size_t len) { michael@0: JS_ASSERT(startIndex + len <= values.length()); michael@0: return HandleValueArray(len, values.begin() + startIndex); michael@0: } michael@0: michael@0: static HandleValueArray empty() { michael@0: return HandleValueArray(0, nullptr); michael@0: } michael@0: michael@0: size_t length() const { return length_; } michael@0: const Value *begin() const { return elements_; } michael@0: michael@0: HandleValue operator[](size_t i) const { michael@0: JS_ASSERT(i < length_); michael@0: return HandleValue::fromMarkedLocation(&elements_[i]); michael@0: } michael@0: }; michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: /************************************************************************/ michael@0: michael@0: struct JSFreeOp { michael@0: private: michael@0: JSRuntime *runtime_; michael@0: michael@0: protected: michael@0: JSFreeOp(JSRuntime *rt) michael@0: : runtime_(rt) { } michael@0: michael@0: public: michael@0: JSRuntime *runtime() const { michael@0: return runtime_; michael@0: } michael@0: }; michael@0: michael@0: /* Callbacks and their arguments. */ michael@0: michael@0: /************************************************************************/ michael@0: michael@0: typedef enum JSContextOp { michael@0: JSCONTEXT_NEW, michael@0: JSCONTEXT_DESTROY michael@0: } JSContextOp; michael@0: michael@0: /* michael@0: * The possible values for contextOp when the runtime calls the callback are: michael@0: * JSCONTEXT_NEW JS_NewContext successfully created a new JSContext michael@0: * instance. The callback can initialize the instance as michael@0: * required. If the callback returns false, the instance michael@0: * will be destroyed and JS_NewContext returns null. In michael@0: * this case the callback is not called again. michael@0: * JSCONTEXT_DESTROY One of JS_DestroyContext* methods is called. The michael@0: * callback may perform its own cleanup and must always michael@0: * return true. michael@0: * Any other value For future compatibility the callback must do nothing michael@0: * and return true in this case. michael@0: */ michael@0: typedef bool michael@0: (* JSContextCallback)(JSContext *cx, unsigned contextOp, void *data); michael@0: michael@0: typedef enum JSGCStatus { michael@0: JSGC_BEGIN, michael@0: JSGC_END michael@0: } JSGCStatus; michael@0: michael@0: typedef void michael@0: (* JSGCCallback)(JSRuntime *rt, JSGCStatus status, void *data); michael@0: michael@0: typedef enum JSFinalizeStatus { michael@0: /* michael@0: * Called when preparing to sweep a group of compartments, before anything michael@0: * has been swept. The collector will not yield to the mutator before michael@0: * calling the callback with JSFINALIZE_GROUP_END status. michael@0: */ michael@0: JSFINALIZE_GROUP_START, michael@0: michael@0: /* michael@0: * Called when preparing to sweep a group of compartments. Weak references michael@0: * to unmarked things have been removed and things that are not swept michael@0: * incrementally have been finalized at this point. The collector may yield michael@0: * to the mutator after this point. michael@0: */ michael@0: JSFINALIZE_GROUP_END, michael@0: michael@0: /* michael@0: * Called at the end of collection when everything has been swept. michael@0: */ michael@0: JSFINALIZE_COLLECTION_END michael@0: } JSFinalizeStatus; michael@0: michael@0: typedef void michael@0: (* JSFinalizeCallback)(JSFreeOp *fop, JSFinalizeStatus status, bool isCompartment); michael@0: michael@0: typedef bool michael@0: (* JSInterruptCallback)(JSContext *cx); michael@0: michael@0: typedef void michael@0: (* JSErrorReporter)(JSContext *cx, const char *message, JSErrorReport *report); michael@0: michael@0: #ifdef MOZ_TRACE_JSCALLS michael@0: typedef void michael@0: (* JSFunctionCallback)(const JSFunction *fun, michael@0: const JSScript *scr, michael@0: const JSContext *cx, michael@0: int entering); michael@0: #endif michael@0: michael@0: /* michael@0: * Possible exception types. These types are part of a JSErrorFormatString michael@0: * structure. They define which error to throw in case of a runtime error. michael@0: * JSEXN_NONE marks an unthrowable error. michael@0: */ michael@0: typedef enum JSExnType { michael@0: JSEXN_NONE = -1, michael@0: JSEXN_ERR, michael@0: JSEXN_INTERNALERR, michael@0: JSEXN_EVALERR, michael@0: JSEXN_RANGEERR, michael@0: JSEXN_REFERENCEERR, michael@0: JSEXN_SYNTAXERR, michael@0: JSEXN_TYPEERR, michael@0: JSEXN_URIERR, michael@0: JSEXN_LIMIT michael@0: } JSExnType; michael@0: michael@0: typedef struct JSErrorFormatString { michael@0: /* The error format string in ASCII. */ michael@0: const char *format; michael@0: michael@0: /* The number of arguments to expand in the formatted error message. */ michael@0: uint16_t argCount; michael@0: michael@0: /* One of the JSExnType constants above. */ michael@0: int16_t exnType; michael@0: } JSErrorFormatString; michael@0: michael@0: typedef const JSErrorFormatString * michael@0: (* JSErrorCallback)(void *userRef, const char *locale, michael@0: const unsigned errorNumber); michael@0: michael@0: typedef bool michael@0: (* JSLocaleToUpperCase)(JSContext *cx, JS::HandleString src, JS::MutableHandleValue rval); michael@0: michael@0: typedef bool michael@0: (* JSLocaleToLowerCase)(JSContext *cx, JS::HandleString src, JS::MutableHandleValue rval); michael@0: michael@0: typedef bool michael@0: (* JSLocaleCompare)(JSContext *cx, JS::HandleString src1, JS::HandleString src2, michael@0: JS::MutableHandleValue rval); michael@0: michael@0: typedef bool michael@0: (* JSLocaleToUnicode)(JSContext *cx, const char *src, JS::MutableHandleValue rval); michael@0: michael@0: /* michael@0: * Callback used to ask the embedding for the cross compartment wrapper handler michael@0: * that implements the desired prolicy for this kind of object in the michael@0: * destination compartment. |obj| is the object to be wrapped. If |existing| is michael@0: * non-nullptr, it will point to an existing wrapper object that should be michael@0: * re-used if possible. |existing| is guaranteed to be a cross-compartment michael@0: * wrapper with a lazily-defined prototype and the correct global. It is michael@0: * guaranteed not to wrap a function. michael@0: */ michael@0: typedef JSObject * michael@0: (* JSWrapObjectCallback)(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj, michael@0: JS::HandleObject proto, JS::HandleObject parent, michael@0: unsigned flags); michael@0: michael@0: /* michael@0: * Callback used by the wrap hook to ask the embedding to prepare an object michael@0: * for wrapping in a context. This might include unwrapping other wrappers michael@0: * or even finding a more suitable object for the new compartment. michael@0: */ michael@0: typedef JSObject * michael@0: (* JSPreWrapCallback)(JSContext *cx, JS::HandleObject scope, JS::HandleObject obj, michael@0: unsigned flags); michael@0: michael@0: struct JSWrapObjectCallbacks michael@0: { michael@0: JSWrapObjectCallback wrap; michael@0: JSPreWrapCallback preWrap; michael@0: }; michael@0: michael@0: typedef void michael@0: (* JSDestroyCompartmentCallback)(JSFreeOp *fop, JSCompartment *compartment); michael@0: michael@0: typedef void michael@0: (* JSZoneCallback)(JS::Zone *zone); michael@0: michael@0: typedef void michael@0: (* JSCompartmentNameCallback)(JSRuntime *rt, JSCompartment *compartment, michael@0: char *buf, size_t bufsize); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: static MOZ_ALWAYS_INLINE jsval michael@0: JS_NumberValue(double d) michael@0: { michael@0: int32_t i; michael@0: d = JS::CanonicalizeNaN(d); michael@0: if (mozilla::NumberIsInt32(d, &i)) michael@0: return INT_TO_JSVAL(i); michael@0: return DOUBLE_TO_JSVAL(d); michael@0: } michael@0: michael@0: /************************************************************************/ michael@0: michael@0: JS_PUBLIC_API(bool) michael@0: JS_StringHasBeenInterned(JSContext *cx, JSString *str); michael@0: michael@0: /* michael@0: * Only JSStrings that have been interned via the JSAPI can be turned into michael@0: * jsids by API clients. michael@0: * michael@0: * N.B. if a jsid is backed by a string which has not been interned, that michael@0: * string must be appropriately rooted to avoid being collected by the GC. michael@0: */ michael@0: JS_PUBLIC_API(jsid) michael@0: INTERNED_STRING_TO_JSID(JSContext *cx, JSString *str); michael@0: michael@0: /* michael@0: * Returns true iff the given jsval is immune to GC and can be used across michael@0: * multiple JSRuntimes without requiring any conversion API. michael@0: */ michael@0: static MOZ_ALWAYS_INLINE bool michael@0: JSVAL_IS_UNIVERSAL(jsval v) michael@0: { michael@0: return !JSVAL_IS_GCTHING(v); michael@0: } michael@0: michael@0: namespace JS { michael@0: michael@0: class AutoIdRooter : private AutoGCRooter michael@0: { michael@0: public: michael@0: explicit AutoIdRooter(JSContext *cx, jsid aId = INT_TO_JSID(0) michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoGCRooter(cx, ID), id_(aId) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: jsid id() { michael@0: return id_; michael@0: } michael@0: michael@0: jsid * addr() { michael@0: return &id_; michael@0: } michael@0: michael@0: friend void AutoGCRooter::trace(JSTracer *trc); michael@0: michael@0: private: michael@0: jsid id_; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: // Container class for passing in script source buffers to the JS engine. This michael@0: // not only groups the buffer and length values, it also provides a way to michael@0: // optionally pass ownership of the buffer to the JS engine without copying. michael@0: // Rules for use: michael@0: // michael@0: // 1) The data array must be allocated with js_malloc() or js_realloc() if michael@0: // ownership is being granted to the SourceBufferHolder. michael@0: // 2) If ownership is not given to the SourceBufferHolder, then the memory michael@0: // must be kept alive until the JS compilation is complete. michael@0: // 3) Any code calling SourceBufferHolder::take() must guarantee to keep the michael@0: // memory alive until JS compilation completes. Normally only the JS michael@0: // engine should be calling take(). michael@0: // michael@0: // Example use: michael@0: // michael@0: // size_t length = 512; michael@0: // jschar* chars = static_cast(js_malloc(sizeof(jschar) * length)); michael@0: // JS::SourceBufferHolder srcBuf(chars, length, JS::SourceBufferHolder::GiveOwnership); michael@0: // JS::Compile(cx, obj, options, srcBuf); michael@0: // michael@0: class MOZ_STACK_CLASS SourceBufferHolder MOZ_FINAL michael@0: { michael@0: public: michael@0: enum Ownership { michael@0: NoOwnership, michael@0: GiveOwnership michael@0: }; michael@0: michael@0: SourceBufferHolder(const jschar *data, size_t dataLength, Ownership ownership) michael@0: : data_(data), michael@0: length_(dataLength), michael@0: ownsChars_(ownership == GiveOwnership) michael@0: { michael@0: // Ensure that null buffers properly return an unowned, empty, michael@0: // null-terminated string. michael@0: static const jschar NullChar_ = 0; michael@0: if (!get()) { michael@0: data_ = &NullChar_; michael@0: length_ = 0; michael@0: ownsChars_ = false; michael@0: } michael@0: } michael@0: michael@0: ~SourceBufferHolder() { michael@0: if (ownsChars_) michael@0: js_free(const_cast(data_)); michael@0: } michael@0: michael@0: // Access the underlying source buffer without affecting ownership. michael@0: const jschar *get() const { return data_; } michael@0: michael@0: // Length of the source buffer in jschars (not bytes) michael@0: size_t length() const { return length_; } michael@0: michael@0: // Returns true if the SourceBufferHolder owns the buffer and will free michael@0: // it upon destruction. If true, it is legal to call take(). michael@0: bool ownsChars() const { return ownsChars_; } michael@0: michael@0: // Retrieve and take ownership of the underlying data buffer. The caller michael@0: // is now responsible for calling js_free() on the returned value, *but only michael@0: // after JS script compilation has completed*. michael@0: // michael@0: // After the buffer has been taken the SourceBufferHolder functions as if michael@0: // it had been constructed on an unowned buffer; get() and length() still michael@0: // work. In order for this to be safe the taken buffer must be kept alive michael@0: // until after JS script compilation completes as noted above. michael@0: // michael@0: // Note, it's the caller's responsibility to check ownsChars() before taking michael@0: // the buffer. Taking and then free'ing an unowned buffer will have dire michael@0: // consequences. michael@0: jschar *take() { michael@0: JS_ASSERT(ownsChars_); michael@0: ownsChars_ = false; michael@0: return const_cast(data_); michael@0: } michael@0: michael@0: private: michael@0: SourceBufferHolder(SourceBufferHolder &) MOZ_DELETE; michael@0: SourceBufferHolder &operator=(SourceBufferHolder &) MOZ_DELETE; michael@0: michael@0: const jschar *data_; michael@0: size_t length_; michael@0: bool ownsChars_; michael@0: }; michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* Property attributes, set in JSPropertySpec and passed to API functions. */ michael@0: #define JSPROP_ENUMERATE 0x01 /* property is visible to for/in loop */ michael@0: #define JSPROP_READONLY 0x02 /* not settable: assignment is no-op. michael@0: This flag is only valid when neither michael@0: JSPROP_GETTER nor JSPROP_SETTER is michael@0: set. */ michael@0: #define JSPROP_PERMANENT 0x04 /* property cannot be deleted */ michael@0: #define JSPROP_NATIVE_ACCESSORS 0x08 /* set in JSPropertyDescriptor.flags michael@0: if getters/setters are JSNatives */ michael@0: #define JSPROP_GETTER 0x10 /* property holds getter function */ michael@0: #define JSPROP_SETTER 0x20 /* property holds setter function */ michael@0: #define JSPROP_SHARED 0x40 /* don't allocate a value slot for this michael@0: property; don't copy the property on michael@0: set of the same-named property in an michael@0: object that delegates to a prototype michael@0: containing this property */ michael@0: #define JSPROP_INDEX 0x80 /* name is actually (int) index */ michael@0: michael@0: #define JSFUN_STUB_GSOPS 0x200 /* use JS_PropertyStub getter/setter michael@0: instead of defaulting to class gsops michael@0: for property holding function */ michael@0: michael@0: #define JSFUN_CONSTRUCTOR 0x400 /* native that can be called as a ctor */ michael@0: michael@0: michael@0: /* michael@0: * Specify a generic native prototype methods, i.e., methods of a class michael@0: * prototype that are exposed as static methods taking an extra leading michael@0: * argument: the generic |this| parameter. michael@0: * michael@0: * If you set this flag in a JSFunctionSpec struct's flags initializer, then michael@0: * that struct must live at least as long as the native static method object michael@0: * created due to this flag by JS_DefineFunctions or JS_InitClass. Typically michael@0: * JSFunctionSpec structs are allocated in static arrays. michael@0: */ michael@0: #define JSFUN_GENERIC_NATIVE 0x800 michael@0: michael@0: #define JSFUN_FLAGS_MASK 0xe00 /* | of all the JSFUN_* flags */ michael@0: michael@0: /* michael@0: * The first call to JS_CallOnce by any thread in a process will call 'func'. michael@0: * Later calls to JS_CallOnce with the same JSCallOnceType object will be michael@0: * suppressed. michael@0: * michael@0: * Equivalently: each distinct JSCallOnceType object will allow one JS_CallOnce michael@0: * to invoke its JSInitCallback. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_CallOnce(JSCallOnceType *once, JSInitCallback func); michael@0: michael@0: /* Microseconds since the epoch, midnight, January 1, 1970 UTC. */ michael@0: extern JS_PUBLIC_API(int64_t) michael@0: JS_Now(void); michael@0: michael@0: /* Don't want to export data, so provide accessors for non-inline jsvals. */ michael@0: extern JS_PUBLIC_API(jsval) michael@0: JS_GetNaNValue(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(jsval) michael@0: JS_GetNegativeInfinityValue(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(jsval) michael@0: JS_GetPositiveInfinityValue(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(jsval) michael@0: JS_GetEmptyStringValue(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_GetEmptyString(JSRuntime *rt); michael@0: michael@0: /* michael@0: * Format is a string of the following characters (spaces are insignificant), michael@0: * specifying the tabulated type conversions: michael@0: * michael@0: * b bool Boolean michael@0: * c uint16_t/jschar ECMA uint16_t, Unicode char michael@0: * i int32_t ECMA int32_t michael@0: * j int32_t ECMA int32_t (used to be different) michael@0: * u uint32_t ECMA uint32_t michael@0: * d double IEEE double michael@0: * I double Integral IEEE double michael@0: * S JSString * Unicode string, accessed by a JSString pointer michael@0: * W jschar * Unicode character vector, 0-terminated (W for wide) michael@0: * o JSObject * Object reference michael@0: * f JSFunction * Function private michael@0: * v jsval Argument value (no conversion) michael@0: * * N/A Skip this argument (no vararg) michael@0: * / N/A End of required arguments michael@0: * michael@0: * The variable argument list after format must consist of &b, &c, &s, e.g., michael@0: * where those variables have the types given above. For the pointer types michael@0: * char *, JSString *, and JSObject *, the pointed-at memory returned belongs michael@0: * to the JS runtime, not to the calling native code. The runtime promises michael@0: * to keep this memory valid so long as argv refers to allocated stack space michael@0: * (so long as the native function is active). michael@0: * michael@0: * Fewer arguments than format specifies may be passed only if there is a / michael@0: * in format after the last required argument specifier and argc is at least michael@0: * the number of required arguments. More arguments than format specifies michael@0: * may be passed without error; it is up to the caller to deal with trailing michael@0: * unconverted arguments. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ConvertArguments(JSContext *cx, const JS::CallArgs &args, const char *format, ...); michael@0: michael@0: #ifdef va_start michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ConvertArgumentsVA(JSContext *cx, const JS::CallArgs &args, const char *format, michael@0: va_list ap); michael@0: #endif michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ConvertValue(JSContext *cx, JS::HandleValue v, JSType type, JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ValueToObject(JSContext *cx, JS::HandleValue v, JS::MutableHandleObject objp); michael@0: michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: JS_ValueToFunction(JSContext *cx, JS::HandleValue v); michael@0: michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: JS_ValueToConstructor(JSContext *cx, JS::HandleValue v); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_ValueToSource(JSContext *cx, JS::Handle v); michael@0: michael@0: namespace js { michael@0: /* michael@0: * DO NOT CALL THIS. Use JS::ToNumber michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: ToNumberSlow(JSContext *cx, JS::Value v, double *dp); michael@0: michael@0: /* michael@0: * DO NOT CALL THIS. Use JS::ToBoolean michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: ToBooleanSlow(JS::HandleValue v); michael@0: michael@0: /* michael@0: * DO NOT CALL THIS. Use JS::ToString michael@0: */ michael@0: extern JS_PUBLIC_API(JSString*) michael@0: ToStringSlow(JSContext *cx, JS::HandleValue v); michael@0: } /* namespace js */ michael@0: michael@0: namespace JS { michael@0: michael@0: /* ES5 9.3 ToNumber. */ michael@0: MOZ_ALWAYS_INLINE bool michael@0: ToNumber(JSContext *cx, HandleValue v, double *out) michael@0: { michael@0: AssertArgumentsAreSane(cx, v); michael@0: michael@0: if (v.isNumber()) { michael@0: *out = v.toNumber(); michael@0: return true; michael@0: } michael@0: return js::ToNumberSlow(cx, v, out); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE bool michael@0: ToBoolean(HandleValue v) michael@0: { michael@0: if (v.isBoolean()) michael@0: return v.toBoolean(); michael@0: if (v.isInt32()) michael@0: return v.toInt32() != 0; michael@0: if (v.isNullOrUndefined()) michael@0: return false; michael@0: if (v.isDouble()) { michael@0: double d = v.toDouble(); michael@0: return !mozilla::IsNaN(d) && d != 0; michael@0: } michael@0: michael@0: /* The slow path handles strings and objects. */ michael@0: return js::ToBooleanSlow(v); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE JSString* michael@0: ToString(JSContext *cx, HandleValue v) michael@0: { michael@0: if (v.isString()) michael@0: return v.toString(); michael@0: return js::ToStringSlow(cx, v); michael@0: } michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DoubleIsInt32(double d, int32_t *ip); michael@0: michael@0: extern JS_PUBLIC_API(int32_t) michael@0: JS_DoubleToInt32(double d); michael@0: michael@0: extern JS_PUBLIC_API(uint32_t) michael@0: JS_DoubleToUint32(double d); michael@0: michael@0: michael@0: namespace js { michael@0: /* DO NOT CALL THIS. Use JS::ToUint16. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: ToUint16Slow(JSContext *cx, JS::HandleValue v, uint16_t *out); michael@0: michael@0: /* DO NOT CALL THIS. Use JS::ToInt32. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: ToInt32Slow(JSContext *cx, JS::HandleValue v, int32_t *out); michael@0: michael@0: /* DO NOT CALL THIS. Use JS::ToUint32. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: ToUint32Slow(JSContext *cx, JS::HandleValue v, uint32_t *out); michael@0: michael@0: /* DO NOT CALL THIS. Use JS::ToInt64. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: ToInt64Slow(JSContext *cx, JS::HandleValue v, int64_t *out); michael@0: michael@0: /* DO NOT CALL THIS. Use JS::ToUint64. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: ToUint64Slow(JSContext *cx, JS::HandleValue v, uint64_t *out); michael@0: } /* namespace js */ michael@0: michael@0: namespace JS { michael@0: michael@0: MOZ_ALWAYS_INLINE bool michael@0: ToUint16(JSContext *cx, JS::HandleValue v, uint16_t *out) michael@0: { michael@0: AssertArgumentsAreSane(cx, v); michael@0: michael@0: if (v.isInt32()) { michael@0: *out = uint16_t(v.toInt32()); michael@0: return true; michael@0: } michael@0: return js::ToUint16Slow(cx, v, out); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE bool michael@0: ToInt32(JSContext *cx, JS::HandleValue v, int32_t *out) michael@0: { michael@0: AssertArgumentsAreSane(cx, v); michael@0: michael@0: if (v.isInt32()) { michael@0: *out = v.toInt32(); michael@0: return true; michael@0: } michael@0: return js::ToInt32Slow(cx, v, out); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE bool michael@0: ToUint32(JSContext *cx, JS::HandleValue v, uint32_t *out) michael@0: { michael@0: AssertArgumentsAreSane(cx, v); michael@0: michael@0: if (v.isInt32()) { michael@0: *out = uint32_t(v.toInt32()); michael@0: return true; michael@0: } michael@0: return js::ToUint32Slow(cx, v, out); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE bool michael@0: ToInt64(JSContext *cx, JS::HandleValue v, int64_t *out) michael@0: { michael@0: AssertArgumentsAreSane(cx, v); michael@0: michael@0: if (v.isInt32()) { michael@0: *out = int64_t(v.toInt32()); michael@0: return true; michael@0: } michael@0: return js::ToInt64Slow(cx, v, out); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE bool michael@0: ToUint64(JSContext *cx, JS::HandleValue v, uint64_t *out) michael@0: { michael@0: AssertArgumentsAreSane(cx, v); michael@0: michael@0: if (v.isInt32()) { michael@0: /* Account for sign extension of negatives into the longer 64bit space. */ michael@0: *out = uint64_t(int64_t(v.toInt32())); michael@0: return true; michael@0: } michael@0: return js::ToUint64Slow(cx, v, out); michael@0: } michael@0: michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: extern JS_PUBLIC_API(JSType) michael@0: JS_TypeOfValue(JSContext *cx, JS::Handle v); michael@0: michael@0: extern JS_PUBLIC_API(const char *) michael@0: JS_GetTypeName(JSContext *cx, JSType type); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, bool *equal); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_LooselyEqual(JSContext *cx, JS::Handle v1, JS::Handle v2, bool *equal); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SameValue(JSContext *cx, jsval v1, jsval v2, bool *same); michael@0: michael@0: /* True iff fun is the global eval function. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsBuiltinEvalFunction(JSFunction *fun); michael@0: michael@0: /* True iff fun is the Function constructor. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsBuiltinFunctionConstructor(JSFunction *fun); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * Initialization, locking, contexts, and memory allocation. michael@0: * michael@0: * It is important that the first runtime and first context be created in a michael@0: * single-threaded fashion, otherwise the behavior of the library is undefined. michael@0: * See: http://developer.mozilla.org/en/docs/Category:JSAPI_Reference michael@0: */ michael@0: michael@0: typedef enum JSUseHelperThreads michael@0: { michael@0: JS_NO_HELPER_THREADS, michael@0: JS_USE_HELPER_THREADS michael@0: } JSUseHelperThreads; michael@0: michael@0: /** michael@0: * Initialize SpiderMonkey, returning true only if initialization succeeded. michael@0: * Once this method has succeeded, it is safe to call JS_NewRuntime and other michael@0: * JSAPI methods. michael@0: * michael@0: * This method must be called before any other JSAPI method is used on any michael@0: * thread. Once it has been used, it is safe to call any JSAPI method, and it michael@0: * remains safe to do so until JS_ShutDown is correctly called. michael@0: * michael@0: * It is currently not possible to initialize SpiderMonkey multiple times (that michael@0: * is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so michael@0: * again). This restriction may eventually be lifted. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_Init(void); michael@0: michael@0: /** michael@0: * Destroy free-standing resources allocated by SpiderMonkey, not associated michael@0: * with any runtime, context, or other structure. michael@0: * michael@0: * This method should be called after all other JSAPI data has been properly michael@0: * cleaned up: every new runtime must have been destroyed, every new context michael@0: * must have been destroyed, and so on. Calling this method before all other michael@0: * resources have been destroyed has undefined behavior. michael@0: * michael@0: * Failure to call this method, at present, has no adverse effects other than michael@0: * leaking memory. This may not always be the case; it's recommended that all michael@0: * embedders call this method when all other JSAPI operations have completed. michael@0: * michael@0: * It is currently not possible to initialize SpiderMonkey multiple times (that michael@0: * is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so michael@0: * again). This restriction may eventually be lifted. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ShutDown(void); michael@0: michael@0: extern JS_PUBLIC_API(JSRuntime *) michael@0: JS_NewRuntime(uint32_t maxbytes, JSUseHelperThreads useHelperThreads, michael@0: JSRuntime *parentRuntime = nullptr); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_DestroyRuntime(JSRuntime *rt); michael@0: michael@0: // These are equivalent to ICU's |UMemAllocFn|, |UMemReallocFn|, and michael@0: // |UMemFreeFn| types. The first argument (called |context| in the ICU docs) michael@0: // will always be nullptr, and should be ignored. michael@0: typedef void *(*JS_ICUAllocFn)(const void *, size_t size); michael@0: typedef void *(*JS_ICUReallocFn)(const void *, void *p, size_t size); michael@0: typedef void (*JS_ICUFreeFn)(const void *, void *p); michael@0: michael@0: // This function can be used to track memory used by ICU. michael@0: // Do not use it unless you know what you are doing! michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn); michael@0: michael@0: JS_PUBLIC_API(void *) michael@0: JS_GetRuntimePrivate(JSRuntime *rt); michael@0: michael@0: extern JS_PUBLIC_API(JSRuntime *) michael@0: JS_GetRuntime(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(JSRuntime *) michael@0: JS_GetParentRuntime(JSContext *cx); michael@0: michael@0: JS_PUBLIC_API(void) michael@0: JS_SetRuntimePrivate(JSRuntime *rt, void *data); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_BeginRequest(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_EndRequest(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsInRequest(JSRuntime *rt); michael@0: michael@0: namespace js { michael@0: michael@0: void michael@0: AssertHeapIsIdle(JSRuntime *rt); michael@0: michael@0: void michael@0: AssertHeapIsIdle(JSContext *cx); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: class JSAutoRequest michael@0: { michael@0: public: michael@0: JSAutoRequest(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : mContext(cx) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: JS_BeginRequest(mContext); michael@0: } michael@0: ~JSAutoRequest() { michael@0: JS_EndRequest(mContext); michael@0: } michael@0: michael@0: protected: michael@0: JSContext *mContext; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: michael@0: #if 0 michael@0: private: michael@0: static void *operator new(size_t) CPP_THROW_NEW { return 0; }; michael@0: static void operator delete(void *, size_t) { }; michael@0: #endif michael@0: }; michael@0: michael@0: class JSAutoCheckRequest michael@0: { michael@0: public: michael@0: JSAutoCheckRequest(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: { michael@0: #if defined JS_THREADSAFE && defined JS_DEBUG michael@0: mContext = cx; michael@0: JS_ASSERT(JS_IsInRequest(JS_GetRuntime(cx))); michael@0: #endif michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: ~JSAutoCheckRequest() { michael@0: #if defined JS_THREADSAFE && defined JS_DEBUG michael@0: JS_ASSERT(JS_IsInRequest(JS_GetRuntime(mContext))); michael@0: #endif michael@0: } michael@0: michael@0: michael@0: private: michael@0: #if defined JS_THREADSAFE && defined JS_DEBUG michael@0: JSContext *mContext; michael@0: #endif michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback, void *data); michael@0: michael@0: extern JS_PUBLIC_API(JSContext *) michael@0: JS_NewContext(JSRuntime *rt, size_t stackChunkSize); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_DestroyContext(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_DestroyContextNoGC(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_GetContextPrivate(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetContextPrivate(JSContext *cx, void *data); michael@0: michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_GetSecondContextPrivate(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetSecondContextPrivate(JSContext *cx, void *data); michael@0: michael@0: extern JS_PUBLIC_API(JSRuntime *) michael@0: JS_GetRuntime(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(JSContext *) michael@0: JS_ContextIterator(JSRuntime *rt, JSContext **iterp); michael@0: michael@0: extern JS_PUBLIC_API(JSVersion) michael@0: JS_GetVersion(JSContext *cx); michael@0: michael@0: // Mutate the version on the compartment. This is generally discouraged, but michael@0: // necessary to support the version mutation in the js and xpc shell command michael@0: // set. michael@0: // michael@0: // It would be nice to put this in jsfriendapi, but the linkage requirements michael@0: // of the shells make that impossible. michael@0: JS_PUBLIC_API(void) michael@0: JS_SetVersionForCompartment(JSCompartment *compartment, JSVersion version); michael@0: michael@0: extern JS_PUBLIC_API(const char *) michael@0: JS_VersionToString(JSVersion version); michael@0: michael@0: extern JS_PUBLIC_API(JSVersion) michael@0: JS_StringToVersion(const char *string); michael@0: michael@0: namespace JS { michael@0: michael@0: class JS_PUBLIC_API(RuntimeOptions) { michael@0: public: michael@0: RuntimeOptions() michael@0: : baseline_(false), michael@0: ion_(false), michael@0: asmJS_(false) michael@0: { michael@0: } michael@0: michael@0: bool baseline() const { return baseline_; } michael@0: RuntimeOptions &setBaseline(bool flag) { michael@0: baseline_ = flag; michael@0: return *this; michael@0: } michael@0: RuntimeOptions &toggleBaseline() { michael@0: baseline_ = !baseline_; michael@0: return *this; michael@0: } michael@0: michael@0: bool ion() const { return ion_; } michael@0: RuntimeOptions &setIon(bool flag) { michael@0: ion_ = flag; michael@0: return *this; michael@0: } michael@0: RuntimeOptions &toggleIon() { michael@0: ion_ = !ion_; michael@0: return *this; michael@0: } michael@0: michael@0: bool asmJS() const { return asmJS_; } michael@0: RuntimeOptions &setAsmJS(bool flag) { michael@0: asmJS_ = flag; michael@0: return *this; michael@0: } michael@0: RuntimeOptions &toggleAsmJS() { michael@0: asmJS_ = !asmJS_; michael@0: return *this; michael@0: } michael@0: michael@0: private: michael@0: bool baseline_ : 1; michael@0: bool ion_ : 1; michael@0: bool asmJS_ : 1; michael@0: }; michael@0: michael@0: JS_PUBLIC_API(RuntimeOptions &) michael@0: RuntimeOptionsRef(JSRuntime *rt); michael@0: michael@0: JS_PUBLIC_API(RuntimeOptions &) michael@0: RuntimeOptionsRef(JSContext *cx); michael@0: michael@0: class JS_PUBLIC_API(ContextOptions) { michael@0: public: michael@0: ContextOptions() michael@0: : extraWarnings_(false), michael@0: werror_(false), michael@0: varObjFix_(false), michael@0: privateIsNSISupports_(false), michael@0: dontReportUncaught_(false), michael@0: noDefaultCompartmentObject_(false), michael@0: noScriptRval_(false), michael@0: strictMode_(false), michael@0: cloneSingletons_(false) michael@0: { michael@0: } michael@0: michael@0: bool extraWarnings() const { return extraWarnings_; } michael@0: ContextOptions &setExtraWarnings(bool flag) { michael@0: extraWarnings_ = flag; michael@0: return *this; michael@0: } michael@0: ContextOptions &toggleExtraWarnings() { michael@0: extraWarnings_ = !extraWarnings_; michael@0: return *this; michael@0: } michael@0: michael@0: bool werror() const { return werror_; } michael@0: ContextOptions &setWerror(bool flag) { michael@0: werror_ = flag; michael@0: return *this; michael@0: } michael@0: ContextOptions &toggleWerror() { michael@0: werror_ = !werror_; michael@0: return *this; michael@0: } michael@0: michael@0: bool varObjFix() const { return varObjFix_; } michael@0: ContextOptions &setVarObjFix(bool flag) { michael@0: varObjFix_ = flag; michael@0: return *this; michael@0: } michael@0: ContextOptions &toggleVarObjFix() { michael@0: varObjFix_ = !varObjFix_; michael@0: return *this; michael@0: } michael@0: michael@0: bool privateIsNSISupports() const { return privateIsNSISupports_; } michael@0: ContextOptions &setPrivateIsNSISupports(bool flag) { michael@0: privateIsNSISupports_ = flag; michael@0: return *this; michael@0: } michael@0: ContextOptions &togglePrivateIsNSISupports() { michael@0: privateIsNSISupports_ = !privateIsNSISupports_; michael@0: return *this; michael@0: } michael@0: michael@0: bool dontReportUncaught() const { return dontReportUncaught_; } michael@0: ContextOptions &setDontReportUncaught(bool flag) { michael@0: dontReportUncaught_ = flag; michael@0: return *this; michael@0: } michael@0: ContextOptions &toggleDontReportUncaught() { michael@0: dontReportUncaught_ = !dontReportUncaught_; michael@0: return *this; michael@0: } michael@0: michael@0: bool noDefaultCompartmentObject() const { return noDefaultCompartmentObject_; } michael@0: ContextOptions &setNoDefaultCompartmentObject(bool flag) { michael@0: noDefaultCompartmentObject_ = flag; michael@0: return *this; michael@0: } michael@0: ContextOptions &toggleNoDefaultCompartmentObject() { michael@0: noDefaultCompartmentObject_ = !noDefaultCompartmentObject_; michael@0: return *this; michael@0: } michael@0: michael@0: bool noScriptRval() const { return noScriptRval_; } michael@0: ContextOptions &setNoScriptRval(bool flag) { michael@0: noScriptRval_ = flag; michael@0: return *this; michael@0: } michael@0: ContextOptions &toggleNoScriptRval() { michael@0: noScriptRval_ = !noScriptRval_; michael@0: return *this; michael@0: } michael@0: michael@0: bool strictMode() const { return strictMode_; } michael@0: ContextOptions &setStrictMode(bool flag) { michael@0: strictMode_ = flag; michael@0: return *this; michael@0: } michael@0: ContextOptions &toggleStrictMode() { michael@0: strictMode_ = !strictMode_; michael@0: return *this; michael@0: } michael@0: michael@0: bool cloneSingletons() const { return cloneSingletons_; } michael@0: ContextOptions &setCloneSingletons(bool flag) { michael@0: cloneSingletons_ = flag; michael@0: return *this; michael@0: } michael@0: ContextOptions &toggleCloneSingletons() { michael@0: cloneSingletons_ = !cloneSingletons_; michael@0: return *this; michael@0: } michael@0: michael@0: private: michael@0: bool extraWarnings_ : 1; michael@0: bool werror_ : 1; michael@0: bool varObjFix_ : 1; michael@0: bool privateIsNSISupports_ : 1; michael@0: bool dontReportUncaught_ : 1; michael@0: bool noDefaultCompartmentObject_ : 1; michael@0: bool noScriptRval_ : 1; michael@0: bool strictMode_ : 1; michael@0: bool cloneSingletons_ : 1; michael@0: }; michael@0: michael@0: JS_PUBLIC_API(ContextOptions &) michael@0: ContextOptionsRef(JSContext *cx); michael@0: michael@0: class JS_PUBLIC_API(AutoSaveContextOptions) { michael@0: public: michael@0: AutoSaveContextOptions(JSContext *cx) michael@0: : cx_(cx), michael@0: oldOptions_(ContextOptionsRef(cx_)) michael@0: { michael@0: } michael@0: michael@0: ~AutoSaveContextOptions() michael@0: { michael@0: ContextOptionsRef(cx_) = oldOptions_; michael@0: } michael@0: michael@0: private: michael@0: JSContext *cx_; michael@0: JS::ContextOptions oldOptions_; michael@0: }; michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: extern JS_PUBLIC_API(const char *) michael@0: JS_GetImplementationVersion(void); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetDestroyZoneCallback(JSRuntime *rt, JSZoneCallback callback); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetSweepZoneCallback(JSRuntime *rt, JSZoneCallback callback); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetCompartmentNameCallback(JSRuntime *rt, JSCompartmentNameCallback callback); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetWrapObjectCallbacks(JSRuntime *rt, const JSWrapObjectCallbacks *callbacks); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetCompartmentPrivate(JSCompartment *compartment, void *data); michael@0: michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_GetCompartmentPrivate(JSCompartment *compartment); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetZoneUserData(JS::Zone *zone, void *data); michael@0: michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_GetZoneUserData(JS::Zone *zone); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_WrapObject(JSContext *cx, JS::MutableHandleObject objp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_WrapValue(JSContext *cx, JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_WrapId(JSContext *cx, JS::MutableHandleId idp); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_TransplantObject(JSContext *cx, JS::HandleObject origobj, JS::HandleObject target); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_RefreshCrossCompartmentWrappers(JSContext *cx, JS::Handle obj); michael@0: michael@0: /* michael@0: * At any time, a JSContext has a current (possibly-nullptr) compartment. michael@0: * Compartments are described in: michael@0: * michael@0: * developer.mozilla.org/en-US/docs/SpiderMonkey/SpiderMonkey_compartments michael@0: * michael@0: * The current compartment of a context may be changed. The preferred way to do michael@0: * this is with JSAutoCompartment: michael@0: * michael@0: * void foo(JSContext *cx, JSObject *obj) { michael@0: * // in some compartment 'c' michael@0: * { michael@0: * JSAutoCompartment ac(cx, obj); // constructor enters michael@0: * // in the compartment of 'obj' michael@0: * } // destructor leaves michael@0: * // back in compartment 'c' michael@0: * } michael@0: * michael@0: * For more complicated uses that don't neatly fit in a C++ stack frame, the michael@0: * compartment can entered and left using separate function calls: michael@0: * michael@0: * void foo(JSContext *cx, JSObject *obj) { michael@0: * // in 'oldCompartment' michael@0: * JSCompartment *oldCompartment = JS_EnterCompartment(cx, obj); michael@0: * // in the compartment of 'obj' michael@0: * JS_LeaveCompartment(cx, oldCompartment); michael@0: * // back in 'oldCompartment' michael@0: * } michael@0: * michael@0: * Note: these calls must still execute in a LIFO manner w.r.t all other michael@0: * enter/leave calls on the context. Furthermore, only the return value of a michael@0: * JS_EnterCompartment call may be passed as the 'oldCompartment' argument of michael@0: * the corresponding JS_LeaveCompartment call. michael@0: */ michael@0: michael@0: class JS_PUBLIC_API(JSAutoCompartment) michael@0: { michael@0: JSContext *cx_; michael@0: JSCompartment *oldCompartment_; michael@0: public: michael@0: JSAutoCompartment(JSContext *cx, JSObject *target); michael@0: JSAutoCompartment(JSContext *cx, JSScript *target); michael@0: ~JSAutoCompartment(); michael@0: }; michael@0: michael@0: class JS_PUBLIC_API(JSAutoNullCompartment) michael@0: { michael@0: JSContext *cx_; michael@0: JSCompartment *oldCompartment_; michael@0: public: michael@0: JSAutoNullCompartment(JSContext *cx); michael@0: ~JSAutoNullCompartment(); michael@0: }; michael@0: michael@0: /* NB: This API is infallible; a nullptr return value does not indicate error. */ michael@0: extern JS_PUBLIC_API(JSCompartment *) michael@0: JS_EnterCompartment(JSContext *cx, JSObject *target); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_LeaveCompartment(JSContext *cx, JSCompartment *oldCompartment); michael@0: michael@0: typedef void (*JSIterateCompartmentCallback)(JSRuntime *rt, void *data, JSCompartment *compartment); michael@0: michael@0: /* michael@0: * This function calls |compartmentCallback| on every compartment. Beware that michael@0: * there is no guarantee that the compartment will survive after the callback michael@0: * returns. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_IterateCompartments(JSRuntime *rt, void *data, michael@0: JSIterateCompartmentCallback compartmentCallback); michael@0: michael@0: /* michael@0: * Initialize standard JS class constructors, prototypes, and any top-level michael@0: * functions and constants associated with the standard classes (e.g. isNaN michael@0: * for Number). michael@0: * michael@0: * NB: This sets cx's global object to obj if it was null. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_InitStandardClasses(JSContext *cx, JS::Handle obj); michael@0: michael@0: /* michael@0: * Resolve id, which must contain either a string or an int, to a standard michael@0: * class name in obj if possible, defining the class's constructor and/or michael@0: * prototype and storing true in *resolved. If id does not name a standard michael@0: * class or a top-level property induced by initializing a standard class, michael@0: * store false in *resolved and just return true. Return false on error, michael@0: * as usual for bool result-typed API entry points. michael@0: * michael@0: * This API can be called directly from a global object class's resolve op, michael@0: * to define standard classes lazily. The class's enumerate op should call michael@0: * JS_EnumerateStandardClasses(cx, obj), to define eagerly during for..in michael@0: * loops any classes not yet resolved lazily. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ResolveStandardClass(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *resolved); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_EnumerateStandardClasses(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetClassObject(JSContext *cx, JSProtoKey key, JS::MutableHandle objp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetClassPrototype(JSContext *cx, JSProtoKey key, JS::MutableHandle objp); michael@0: michael@0: namespace JS { michael@0: michael@0: /* michael@0: * Determine if the given object is an instance or prototype for a standard michael@0: * class. If so, return the associated JSProtoKey. If not, return JSProto_Null. michael@0: */ michael@0: michael@0: extern JS_PUBLIC_API(JSProtoKey) michael@0: IdentifyStandardInstance(JSObject *obj); michael@0: michael@0: extern JS_PUBLIC_API(JSProtoKey) michael@0: IdentifyStandardPrototype(JSObject *obj); michael@0: michael@0: extern JS_PUBLIC_API(JSProtoKey) michael@0: IdentifyStandardInstanceOrPrototype(JSObject *obj); michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: extern JS_PUBLIC_API(JSProtoKey) michael@0: JS_IdToProtoKey(JSContext *cx, JS::HandleId id); michael@0: michael@0: /* michael@0: * Returns the original value of |Function.prototype| from the global object in michael@0: * which |forObj| was created. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_GetFunctionPrototype(JSContext *cx, JS::HandleObject forObj); michael@0: michael@0: /* michael@0: * Returns the original value of |Object.prototype| from the global object in michael@0: * which |forObj| was created. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_GetObjectPrototype(JSContext *cx, JS::HandleObject forObj); michael@0: michael@0: /* michael@0: * Returns the original value of |Array.prototype| from the global object in michael@0: * which |forObj| was created. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_GetArrayPrototype(JSContext *cx, JS::HandleObject forObj); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_GetGlobalForObject(JSContext *cx, JSObject *obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsGlobalObject(JSObject *obj); michael@0: michael@0: /* michael@0: * May return nullptr, if |c| never had a global (e.g. the atoms compartment), michael@0: * or if |c|'s global has been collected. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_GetGlobalForCompartmentOrNull(JSContext *cx, JSCompartment *c); michael@0: michael@0: namespace JS { michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: CurrentGlobalOrNull(JSContext *cx); michael@0: michael@0: } michael@0: michael@0: /* michael@0: * Initialize the 'Reflect' object on a global object. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_InitReflect(JSContext *cx, JS::HandleObject global); michael@0: michael@0: #ifdef JS_HAS_CTYPES michael@0: /* michael@0: * Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes' michael@0: * object will be sealed. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_InitCTypesClass(JSContext *cx, JS::HandleObject global); michael@0: michael@0: /* michael@0: * Convert a unicode string 'source' of length 'slen' to the platform native michael@0: * charset, returning a null-terminated string allocated with JS_malloc. On michael@0: * failure, this function should report an error. michael@0: */ michael@0: typedef char * michael@0: (* JSCTypesUnicodeToNativeFun)(JSContext *cx, const jschar *source, size_t slen); michael@0: michael@0: /* michael@0: * Set of function pointers that ctypes can use for various internal functions. michael@0: * See JS_SetCTypesCallbacks below. Providing nullptr for a function is safe, michael@0: * and will result in the applicable ctypes functionality not being available. michael@0: */ michael@0: struct JSCTypesCallbacks { michael@0: JSCTypesUnicodeToNativeFun unicodeToNative; michael@0: }; michael@0: michael@0: typedef struct JSCTypesCallbacks JSCTypesCallbacks; michael@0: michael@0: /* michael@0: * Set the callbacks on the provided 'ctypesObj' object. 'callbacks' should be a michael@0: * pointer to static data that exists for the lifetime of 'ctypesObj', but it michael@0: * may safely be altered after calling this function and without having michael@0: * to call this function again. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetCTypesCallbacks(JSObject *ctypesObj, JSCTypesCallbacks *callbacks); michael@0: #endif michael@0: michael@0: typedef bool michael@0: (* JSEnumerateDiagnosticMemoryCallback)(void *ptr, size_t length); michael@0: michael@0: /* michael@0: * Enumerate memory regions that contain diagnostic information michael@0: * intended to be included in crash report minidumps. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback); michael@0: michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_malloc(JSContext *cx, size_t nbytes); michael@0: michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_realloc(JSContext *cx, void *p, size_t nbytes); michael@0: michael@0: /* michael@0: * A wrapper for js_free(p) that may delay js_free(p) invocation as a michael@0: * performance optimization. michael@0: * cx may be nullptr. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_free(JSContext *cx, void *p); michael@0: michael@0: /* michael@0: * A wrapper for js_free(p) that may delay js_free(p) invocation as a michael@0: * performance optimization as specified by the given JSFreeOp instance. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_freeop(JSFreeOp *fop, void *p); michael@0: michael@0: extern JS_PUBLIC_API(JSFreeOp *) michael@0: JS_GetDefaultFreeOp(JSRuntime *rt); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_updateMallocCounter(JSContext *cx, size_t nbytes); michael@0: michael@0: extern JS_PUBLIC_API(char *) michael@0: JS_strdup(JSContext *cx, const char *s); michael@0: michael@0: /* Duplicate a string. Does not report an error on failure. */ michael@0: extern JS_PUBLIC_API(char *) michael@0: JS_strdup(JSRuntime *rt, const char *s); michael@0: michael@0: namespace JS { michael@0: michael@0: /* michael@0: * A GC root is a pointer to a jsval, JSObject * or JSString * that itself michael@0: * points into the GC heap. JS_AddValueRoot takes a pointer to a jsval and michael@0: * JS_AddGCThingRoot takes a pointer to a JSObject * or JString *. michael@0: * michael@0: * Note that, since JS_Add*Root stores the address of a variable (of type michael@0: * jsval, JSString *, or JSObject *), that variable must live until michael@0: * JS_Remove*Root is called to remove that variable. For example, after: michael@0: * michael@0: * void some_function() { michael@0: * jsval v; michael@0: * JS_AddNamedValueRoot(cx, &v, "name"); michael@0: * michael@0: * the caller must perform michael@0: * michael@0: * JS_RemoveValueRoot(cx, &v); michael@0: * michael@0: * before some_function() returns. michael@0: * michael@0: * Also, use JS_AddNamed*Root(cx, &structPtr->memberObj, "structPtr->memberObj") michael@0: * in preference to JS_Add*Root(cx, &structPtr->memberObj), in order to identify michael@0: * roots by their source callsites. This way, you can find the callsite while michael@0: * debugging if you should fail to do JS_Remove*Root(cx, &structPtr->memberObj) michael@0: * before freeing structPtr's memory. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: AddValueRoot(JSContext *cx, JS::Heap *vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: AddStringRoot(JSContext *cx, JS::Heap *rp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: AddObjectRoot(JSContext *cx, JS::Heap *rp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: AddNamedValueRoot(JSContext *cx, JS::Heap *vp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: AddNamedValueRootRT(JSRuntime *rt, JS::Heap *vp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: AddNamedStringRoot(JSContext *cx, JS::Heap *rp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: AddNamedObjectRoot(JSContext *cx, JS::Heap *rp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: AddNamedScriptRoot(JSContext *cx, JS::Heap *rp, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: RemoveValueRoot(JSContext *cx, JS::Heap *vp); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: RemoveStringRoot(JSContext *cx, JS::Heap *rp); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: RemoveObjectRoot(JSContext *cx, JS::Heap *rp); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: RemoveScriptRoot(JSContext *cx, JS::Heap *rp); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: RemoveValueRootRT(JSRuntime *rt, JS::Heap *vp); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: RemoveStringRootRT(JSRuntime *rt, JS::Heap *rp); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: RemoveObjectRootRT(JSRuntime *rt, JS::Heap *rp); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: RemoveScriptRootRT(JSRuntime *rt, JS::Heap *rp); michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: /* michael@0: * Register externally maintained GC roots. michael@0: * michael@0: * traceOp: the trace operation. For each root the implementation should call michael@0: * JS_CallTracer whenever the root contains a traceable thing. michael@0: * data: the data argument to pass to each invocation of traceOp. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data); michael@0: michael@0: /* Undo a call to JS_AddExtraGCRootsTracer. */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data); michael@0: michael@0: #ifdef JS_DEBUG michael@0: michael@0: /* michael@0: * Debug-only method to dump the object graph of heap-allocated things. michael@0: * michael@0: * fp: file for the dump output. michael@0: * start: when non-null, dump only things reachable from start michael@0: * thing. Otherwise dump all things reachable from the michael@0: * runtime roots. michael@0: * startKind: trace kind of start if start is not null. Must be michael@0: * JSTRACE_OBJECT when start is null. michael@0: * thingToFind: dump only paths in the object graph leading to thingToFind michael@0: * when non-null. michael@0: * maxDepth: the upper bound on the number of edges to descend from the michael@0: * graph roots. michael@0: * thingToIgnore: thing to ignore during the graph traversal when non-null. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DumpHeap(JSRuntime *rt, FILE *fp, void* startThing, JSGCTraceKind kind, michael@0: void *thingToFind, size_t maxDepth, void *thingToIgnore); michael@0: michael@0: #endif michael@0: michael@0: /* michael@0: * Garbage collector API. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_GC(JSRuntime *rt); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_MaybeGC(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb, void *data); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsGCMarkingTracer(JSTracer *trc); michael@0: michael@0: /* For assertions only. */ michael@0: #ifdef JS_DEBUG michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsMarkingGray(JSTracer *trc); michael@0: #endif michael@0: michael@0: /* michael@0: * JS_IsAboutToBeFinalized checks if the given object is going to be finalized michael@0: * at the end of the current GC. When called outside of the context of a GC, michael@0: * this function will return false. Typically this function is used on weak michael@0: * references, where the reference should be nulled out or destroyed if the michael@0: * given object is about to be finalized. michael@0: * michael@0: * The argument to JS_IsAboutToBeFinalized is an in-out param: when the michael@0: * function returns false, the object being referenced is still alive, but the michael@0: * garbage collector might have moved it. In this case, the reference passed michael@0: * to JS_IsAboutToBeFinalized will be updated to the object's new location. michael@0: * Callers of this method are responsible for updating any state that is michael@0: * dependent on the object's address. For example, if the object's address is michael@0: * used as a key in a hashtable, then the object must be removed and michael@0: * re-inserted with the correct hash. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsAboutToBeFinalized(JS::Heap *objp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsAboutToBeFinalizedUnbarriered(JSObject **objp); michael@0: michael@0: typedef enum JSGCParamKey { michael@0: /* Maximum nominal heap before last ditch GC. */ michael@0: JSGC_MAX_BYTES = 0, michael@0: michael@0: /* Number of JS_malloc bytes before last ditch GC. */ michael@0: JSGC_MAX_MALLOC_BYTES = 1, michael@0: michael@0: /* Amount of bytes allocated by the GC. */ michael@0: JSGC_BYTES = 3, michael@0: michael@0: /* Number of times when GC was invoked. */ michael@0: JSGC_NUMBER = 4, michael@0: michael@0: /* Max size of the code cache in bytes. */ michael@0: JSGC_MAX_CODE_CACHE_BYTES = 5, michael@0: michael@0: /* Select GC mode. */ michael@0: JSGC_MODE = 6, michael@0: michael@0: /* Number of cached empty GC chunks. */ michael@0: JSGC_UNUSED_CHUNKS = 7, michael@0: michael@0: /* Total number of allocated GC chunks. */ michael@0: JSGC_TOTAL_CHUNKS = 8, michael@0: michael@0: /* Max milliseconds to spend in an incremental GC slice. */ michael@0: JSGC_SLICE_TIME_BUDGET = 9, michael@0: michael@0: /* Maximum size the GC mark stack can grow to. */ michael@0: JSGC_MARK_STACK_LIMIT = 10, michael@0: michael@0: /* michael@0: * GCs less than this far apart in time will be considered 'high-frequency GCs'. michael@0: * See setGCLastBytes in jsgc.cpp. michael@0: */ michael@0: JSGC_HIGH_FREQUENCY_TIME_LIMIT = 11, michael@0: michael@0: /* Start of dynamic heap growth. */ michael@0: JSGC_HIGH_FREQUENCY_LOW_LIMIT = 12, michael@0: michael@0: /* End of dynamic heap growth. */ michael@0: JSGC_HIGH_FREQUENCY_HIGH_LIMIT = 13, michael@0: michael@0: /* Upper bound of heap growth. */ michael@0: JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX = 14, michael@0: michael@0: /* Lower bound of heap growth. */ michael@0: JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN = 15, michael@0: michael@0: /* Heap growth for low frequency GCs. */ michael@0: JSGC_LOW_FREQUENCY_HEAP_GROWTH = 16, michael@0: michael@0: /* michael@0: * If false, the heap growth factor is fixed at 3. If true, it is determined michael@0: * based on whether GCs are high- or low- frequency. michael@0: */ michael@0: JSGC_DYNAMIC_HEAP_GROWTH = 17, michael@0: michael@0: /* If true, high-frequency GCs will use a longer mark slice. */ michael@0: JSGC_DYNAMIC_MARK_SLICE = 18, michael@0: michael@0: /* Lower limit after which we limit the heap growth. */ michael@0: JSGC_ALLOCATION_THRESHOLD = 19, michael@0: michael@0: /* michael@0: * We decommit memory lazily. If more than this number of megabytes is michael@0: * available to be decommitted, then JS_MaybeGC will trigger a shrinking GC michael@0: * to decommit it. michael@0: */ michael@0: JSGC_DECOMMIT_THRESHOLD = 20 michael@0: } JSGCParamKey; michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value); michael@0: michael@0: extern JS_PUBLIC_API(uint32_t) michael@0: JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32_t value); michael@0: michael@0: extern JS_PUBLIC_API(uint32_t) michael@0: JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetGCParametersBasedOnAvailableMemory(JSRuntime *rt, uint32_t availMem); michael@0: michael@0: /* michael@0: * Create a new JSString whose chars member refers to external memory, i.e., michael@0: * memory requiring application-specific finalization. michael@0: */ michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_NewExternalString(JSContext *cx, const jschar *chars, size_t length, michael@0: const JSStringFinalizer *fin); michael@0: michael@0: /* michael@0: * Return whether 'str' was created with JS_NewExternalString or michael@0: * JS_NewExternalStringWithClosure. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsExternalString(JSString *str); michael@0: michael@0: /* michael@0: * Return the 'closure' arg passed to JS_NewExternalStringWithClosure or michael@0: * nullptr if the external string was created via JS_NewExternalString. michael@0: */ michael@0: extern JS_PUBLIC_API(const JSStringFinalizer *) michael@0: JS_GetExternalStringFinalizer(JSString *str); michael@0: michael@0: /* michael@0: * Set the size of the native stack that should not be exceed. To disable michael@0: * stack size checking pass 0. michael@0: * michael@0: * SpiderMonkey allows for a distinction between system code (such as GCs, which michael@0: * may incidentally be triggered by script but are not strictly performed on michael@0: * behalf of such script), trusted script (as determined by JS_SetTrustedPrincipals), michael@0: * and untrusted script. Each kind of code may have a different stack quota, michael@0: * allowing embedders to keep higher-priority machinery running in the face of michael@0: * scripted stack exhaustion by something else. michael@0: * michael@0: * The stack quotas for each kind of code should be monotonically descending, michael@0: * and may be specified with this function. If 0 is passed for a given kind michael@0: * of code, it defaults to the value of the next-highest-priority kind. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetNativeStackQuota(JSRuntime *cx, size_t systemCodeStackSize, michael@0: size_t trustedScriptStackSize = 0, michael@0: size_t untrustedScriptStackSize = 0); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: extern JS_PUBLIC_API(int) michael@0: JS_IdArrayLength(JSContext *cx, JSIdArray *ida); michael@0: michael@0: extern JS_PUBLIC_API(jsid) michael@0: JS_IdArrayGet(JSContext *cx, JSIdArray *ida, int index); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_DestroyIdArray(JSContext *cx, JSIdArray *ida); michael@0: michael@0: namespace JS { michael@0: michael@0: class AutoIdArray : private AutoGCRooter michael@0: { michael@0: public: michael@0: AutoIdArray(JSContext *cx, JSIdArray *ida michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoGCRooter(cx, IDARRAY), context(cx), idArray(ida) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: ~AutoIdArray() { michael@0: if (idArray) michael@0: JS_DestroyIdArray(context, idArray); michael@0: } michael@0: bool operator!() { michael@0: return !idArray; michael@0: } michael@0: jsid operator[](size_t i) const { michael@0: JS_ASSERT(idArray); michael@0: return JS_IdArrayGet(context, idArray, i); michael@0: } michael@0: size_t length() const { michael@0: return JS_IdArrayLength(context, idArray); michael@0: } michael@0: michael@0: friend void AutoGCRooter::trace(JSTracer *trc); michael@0: michael@0: JSIdArray *steal() { michael@0: JSIdArray *copy = idArray; michael@0: idArray = nullptr; michael@0: return copy; michael@0: } michael@0: michael@0: protected: michael@0: inline void trace(JSTracer *trc); michael@0: michael@0: private: michael@0: JSContext *context; michael@0: JSIdArray *idArray; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: michael@0: /* No copy or assignment semantics. */ michael@0: AutoIdArray(AutoIdArray &ida) MOZ_DELETE; michael@0: void operator=(AutoIdArray &ida) MOZ_DELETE; michael@0: }; michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ValueToId(JSContext *cx, JS::HandleValue v, JS::MutableHandleId idp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_StringToId(JSContext *cx, JS::HandleString s, JS::MutableHandleId idp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IdToValue(JSContext *cx, jsid id, JS::MutableHandle vp); michael@0: michael@0: /* michael@0: * Invoke the [[DefaultValue]] hook (see ES5 8.6.2) with the provided hint on michael@0: * the specified object, computing a primitive default value for the object. michael@0: * The hint must be JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_VOID (no hint). On michael@0: * success the resulting value is stored in *vp. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefaultValue(JSContext *cx, JS::Handle obj, JSType hint, michael@0: JS::MutableHandle vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_PropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, michael@0: JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_StrictPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool strict, michael@0: JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DeletePropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, michael@0: bool *succeeded); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_EnumerateStub(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ResolveStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ConvertStub(JSContext *cx, JS::HandleObject obj, JSType type, michael@0: JS::MutableHandleValue vp); michael@0: michael@0: struct JSConstDoubleSpec { michael@0: double dval; michael@0: const char *name; michael@0: uint8_t flags; michael@0: uint8_t spare[3]; michael@0: }; michael@0: michael@0: struct JSJitInfo; michael@0: michael@0: /* michael@0: * Wrappers to replace {Strict,}PropertyOp for JSPropertySpecs. This will allow michael@0: * us to pass one JSJitInfo per function with the property spec, without michael@0: * additional field overhead. michael@0: */ michael@0: typedef struct JSStrictPropertyOpWrapper { michael@0: JSStrictPropertyOp op; michael@0: const JSJitInfo *info; michael@0: } JSStrictPropertyOpWrapper; michael@0: michael@0: typedef struct JSPropertyOpWrapper { michael@0: JSPropertyOp op; michael@0: const JSJitInfo *info; michael@0: } JSPropertyOpWrapper; michael@0: michael@0: /* michael@0: * Wrapper to do as above, but for JSNatives for JSFunctionSpecs. michael@0: */ michael@0: typedef struct JSNativeWrapper { michael@0: JSNative op; michael@0: const JSJitInfo *info; michael@0: } JSNativeWrapper; michael@0: michael@0: /* michael@0: * Macro static initializers which make it easy to pass no JSJitInfo as part of a michael@0: * JSPropertySpec or JSFunctionSpec. michael@0: */ michael@0: #define JSOP_WRAPPER(op) { {op, nullptr} } michael@0: #define JSOP_NULLWRAPPER JSOP_WRAPPER(nullptr) michael@0: michael@0: /* michael@0: * To define an array element rather than a named property member, cast the michael@0: * element's index to (const char *) and initialize name with it, and set the michael@0: * JSPROP_INDEX bit in flags. michael@0: */ michael@0: struct JSPropertySpec { michael@0: struct SelfHostedWrapper { michael@0: void *unused; michael@0: const char *funname; michael@0: }; michael@0: michael@0: const char *name; michael@0: uint8_t flags; michael@0: union { michael@0: JSPropertyOpWrapper propertyOp; michael@0: SelfHostedWrapper selfHosted; michael@0: } getter; michael@0: union { michael@0: JSStrictPropertyOpWrapper propertyOp; michael@0: SelfHostedWrapper selfHosted; michael@0: } setter; michael@0: michael@0: private: michael@0: void StaticAsserts() { michael@0: JS_STATIC_ASSERT(sizeof(SelfHostedWrapper) == sizeof(JSPropertyOpWrapper)); michael@0: JS_STATIC_ASSERT(sizeof(SelfHostedWrapper) == sizeof(JSStrictPropertyOpWrapper)); michael@0: JS_STATIC_ASSERT(offsetof(SelfHostedWrapper, funname) == michael@0: offsetof(JSPropertyOpWrapper, info)); michael@0: } michael@0: }; michael@0: michael@0: namespace JS { michael@0: namespace detail { michael@0: michael@0: /* NEVER DEFINED, DON'T USE. For use by JS_CAST_NATIVE_TO only. */ michael@0: inline int CheckIsNative(JSNative native); michael@0: michael@0: /* NEVER DEFINED, DON'T USE. For use by JS_CAST_STRING_TO only. */ michael@0: template michael@0: inline int michael@0: CheckIsCharacterLiteral(const char (&arr)[N]); michael@0: michael@0: } // namespace detail michael@0: } // namespace JS michael@0: michael@0: #define JS_CAST_NATIVE_TO(v, To) \ michael@0: (static_cast(sizeof(JS::detail::CheckIsNative(v))), \ michael@0: reinterpret_cast(v)) michael@0: michael@0: #define JS_CAST_STRING_TO(s, To) \ michael@0: (static_cast(sizeof(JS::detail::CheckIsCharacterLiteral(s))), \ michael@0: reinterpret_cast(s)) michael@0: michael@0: #define JS_CHECK_ACCESSOR_FLAGS(flags) \ michael@0: (static_cast::Type>(0), \ michael@0: (flags)) michael@0: michael@0: /* michael@0: * JSPropertySpec uses JSAPI JSPropertyOp and JSStrictPropertyOp in function michael@0: * signatures. These macros encapsulate the definition of JSNative-backed michael@0: * JSPropertySpecs, performing type-safe casts on the getter/setter functions michael@0: * and adding the necessary property flags to trigger interpretation as michael@0: * JSNatives. michael@0: */ michael@0: #define JS_PSG(name, getter, flags) \ michael@0: {name, \ michael@0: uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS), \ michael@0: JSOP_WRAPPER(JS_CAST_NATIVE_TO(getter, JSPropertyOp)), \ michael@0: JSOP_NULLWRAPPER} michael@0: #define JS_PSGS(name, getter, setter, flags) \ michael@0: {name, \ michael@0: uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS), \ michael@0: JSOP_WRAPPER(JS_CAST_NATIVE_TO(getter, JSPropertyOp)), \ michael@0: JSOP_WRAPPER(JS_CAST_NATIVE_TO(setter, JSStrictPropertyOp))} michael@0: #define JS_SELF_HOSTED_GET(name, getterName, flags) \ michael@0: {name, \ michael@0: uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER), \ michael@0: { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo *) }, \ michael@0: JSOP_NULLWRAPPER } michael@0: #define JS_SELF_HOSTED_GETSET(name, getterName, setterName, flags) \ michael@0: {name, \ michael@0: uint8_t(JS_CHECK_ACCESSOR_FLAGS(flags) | JSPROP_SHARED | JSPROP_GETTER | JSPROP_SETTER), \ michael@0: { nullptr, JS_CAST_STRING_TO(getterName, const JSJitInfo *) }, \ michael@0: { nullptr, JS_CAST_STRING_TO(setterName, const JSJitInfo *) } } michael@0: #define JS_PS_END { nullptr, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER } michael@0: michael@0: /* michael@0: * To define a native function, set call to a JSNativeWrapper. To define a michael@0: * self-hosted function, set selfHostedName to the name of a function michael@0: * compiled during JSRuntime::initSelfHosting. michael@0: */ michael@0: struct JSFunctionSpec { michael@0: const char *name; michael@0: JSNativeWrapper call; michael@0: uint16_t nargs; michael@0: uint16_t flags; michael@0: const char *selfHostedName; michael@0: }; michael@0: michael@0: /* michael@0: * Terminating sentinel initializer to put at the end of a JSFunctionSpec array michael@0: * that's passed to JS_DefineFunctions or JS_InitClass. michael@0: */ michael@0: #define JS_FS_END JS_FS(nullptr,nullptr,0,0) michael@0: michael@0: /* michael@0: * Initializer macros for a JSFunctionSpec array element. JS_FN (whose name pays michael@0: * homage to the old JSNative/JSFastNative split) simply adds the flag michael@0: * JSFUN_STUB_GSOPS. JS_FNINFO allows the simple adding of michael@0: * JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted function. Finally michael@0: * JS_FNSPEC has slots for all the fields. michael@0: */ michael@0: #define JS_FS(name,call,nargs,flags) \ michael@0: JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr) michael@0: #define JS_FN(name,call,nargs,flags) \ michael@0: JS_FNSPEC(name, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr) michael@0: #define JS_FNINFO(name,call,info,nargs,flags) \ michael@0: JS_FNSPEC(name, call, info, nargs, flags, nullptr) michael@0: #define JS_SELF_HOSTED_FN(name,selfHostedName,nargs,flags) \ michael@0: JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName) michael@0: #define JS_FNSPEC(name,call,info,nargs,flags,selfHostedName) \ michael@0: {name, {call, info}, nargs, flags, selfHostedName} michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_InitClass(JSContext *cx, JS::HandleObject obj, JS::HandleObject parent_proto, michael@0: const JSClass *clasp, JSNative constructor, unsigned nargs, michael@0: const JSPropertySpec *ps, const JSFunctionSpec *fs, michael@0: const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs); michael@0: michael@0: /* michael@0: * Set up ctor.prototype = proto and proto.constructor = ctor with the michael@0: * right property flags. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_LinkConstructorAndPrototype(JSContext *cx, JS::Handle ctor, michael@0: JS::Handle proto); michael@0: michael@0: extern JS_PUBLIC_API(const JSClass *) michael@0: JS_GetClass(JSObject *obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_InstanceOf(JSContext *cx, JS::Handle obj, const JSClass *clasp, JS::CallArgs *args); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_HasInstance(JSContext *cx, JS::Handle obj, JS::Handle v, bool *bp); michael@0: michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_GetPrivate(JSObject *obj); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetPrivate(JSObject *obj, void *data); michael@0: michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_GetInstancePrivate(JSContext *cx, JS::Handle obj, const JSClass *clasp, michael@0: JS::CallArgs *args); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetPrototype(JSContext *cx, JS::HandleObject obj, JS::MutableHandleObject protop); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetPrototype(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_GetParent(JSObject *obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetParent(JSContext *cx, JS::HandleObject obj, JS::HandleObject parent); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_GetConstructor(JSContext *cx, JS::Handle proto); michael@0: michael@0: namespace JS { michael@0: michael@0: enum ZoneSpecifier { michael@0: FreshZone = 0, michael@0: SystemZone = 1 michael@0: }; michael@0: michael@0: class JS_PUBLIC_API(CompartmentOptions) michael@0: { michael@0: public: michael@0: class Override { michael@0: public: michael@0: Override() : mode_(Default) {} michael@0: michael@0: bool get(bool defaultValue) const { michael@0: if (mode_ == Default) michael@0: return defaultValue; michael@0: return mode_ == ForceTrue; michael@0: }; michael@0: michael@0: void set(bool overrideValue) { michael@0: mode_ = overrideValue ? ForceTrue : ForceFalse; michael@0: }; michael@0: michael@0: void reset() { michael@0: mode_ = Default; michael@0: } michael@0: michael@0: private: michael@0: enum Mode { michael@0: Default, michael@0: ForceTrue, michael@0: ForceFalse michael@0: }; michael@0: michael@0: Mode mode_; michael@0: }; michael@0: michael@0: explicit CompartmentOptions() michael@0: : version_(JSVERSION_UNKNOWN) michael@0: , invisibleToDebugger_(false) michael@0: , mergeable_(false) michael@0: , discardSource_(false) michael@0: , traceGlobal_(nullptr) michael@0: , singletonsAsTemplates_(true) michael@0: { michael@0: zone_.spec = JS::FreshZone; michael@0: } michael@0: michael@0: JSVersion version() const { return version_; } michael@0: CompartmentOptions &setVersion(JSVersion aVersion) { michael@0: MOZ_ASSERT(aVersion != JSVERSION_UNKNOWN); michael@0: version_ = aVersion; michael@0: return *this; michael@0: } michael@0: michael@0: // Certain scopes (i.e. XBL compilation scopes) are implementation details michael@0: // of the embedding, and references to them should never leak out to script. michael@0: // This flag causes the this compartment to skip firing onNewGlobalObject michael@0: // and makes addDebuggee a no-op for this global. michael@0: bool invisibleToDebugger() const { return invisibleToDebugger_; } michael@0: CompartmentOptions &setInvisibleToDebugger(bool flag) { michael@0: invisibleToDebugger_ = flag; michael@0: return *this; michael@0: } michael@0: michael@0: // Compartments used for off-thread compilation have their contents merged michael@0: // into a target compartment when the compilation is finished. This is only michael@0: // allowed if this flag is set. The invisibleToDebugger flag must also be michael@0: // set for such compartments. michael@0: bool mergeable() const { return mergeable_; } michael@0: CompartmentOptions &setMergeable(bool flag) { michael@0: mergeable_ = flag; michael@0: return *this; michael@0: } michael@0: michael@0: // For certain globals, we know enough about the code that will run in them michael@0: // that we can discard script source entirely. michael@0: bool discardSource() const { return discardSource_; } michael@0: CompartmentOptions &setDiscardSource(bool flag) { michael@0: discardSource_ = flag; michael@0: return *this; michael@0: } michael@0: michael@0: michael@0: bool cloneSingletons(JSContext *cx) const; michael@0: Override &cloneSingletonsOverride() { return cloneSingletonsOverride_; } michael@0: michael@0: void *zonePointer() const { michael@0: JS_ASSERT(uintptr_t(zone_.pointer) > uintptr_t(JS::SystemZone)); michael@0: return zone_.pointer; michael@0: } michael@0: ZoneSpecifier zoneSpecifier() const { return zone_.spec; } michael@0: CompartmentOptions &setZone(ZoneSpecifier spec); michael@0: CompartmentOptions &setSameZoneAs(JSObject *obj); michael@0: michael@0: void setSingletonsAsValues() { michael@0: singletonsAsTemplates_ = false; michael@0: } michael@0: bool getSingletonsAsTemplates() const { michael@0: return singletonsAsTemplates_; michael@0: }; michael@0: michael@0: CompartmentOptions &setTrace(JSTraceOp op) { michael@0: traceGlobal_ = op; michael@0: return *this; michael@0: } michael@0: JSTraceOp getTrace() const { michael@0: return traceGlobal_; michael@0: } michael@0: michael@0: private: michael@0: JSVersion version_; michael@0: bool invisibleToDebugger_; michael@0: bool mergeable_; michael@0: bool discardSource_; michael@0: Override cloneSingletonsOverride_; michael@0: union { michael@0: ZoneSpecifier spec; michael@0: void *pointer; // js::Zone* is not exposed in the API. michael@0: } zone_; michael@0: JSTraceOp traceGlobal_; michael@0: michael@0: // To XDR singletons, we need to ensure that all singletons are all used as michael@0: // templates, by making JSOP_OBJECT return a clone of the JSScript michael@0: // singleton, instead of returning the value which is baked in the JSScript. michael@0: bool singletonsAsTemplates_; michael@0: }; michael@0: michael@0: JS_PUBLIC_API(CompartmentOptions &) michael@0: CompartmentOptionsRef(JSCompartment *compartment); michael@0: michael@0: JS_PUBLIC_API(CompartmentOptions &) michael@0: CompartmentOptionsRef(JSObject *obj); michael@0: michael@0: JS_PUBLIC_API(CompartmentOptions &) michael@0: CompartmentOptionsRef(JSContext *cx); michael@0: michael@0: // During global creation, we fire notifications to callbacks registered michael@0: // via the Debugger API. These callbacks are arbitrary script, and can touch michael@0: // the global in arbitrary ways. When that happens, the global should not be michael@0: // in a half-baked state. But this creates a problem for consumers that need michael@0: // to set slots on the global to put it in a consistent state. michael@0: // michael@0: // This API provides a way for consumers to set slots atomically (immediately michael@0: // after the global is created), before any debugger hooks are fired. It's michael@0: // unfortunately on the clunky side, but that's the way the cookie crumbles. michael@0: // michael@0: // If callers have no additional state on the global to set up, they may pass michael@0: // |FireOnNewGlobalHook| to JS_NewGlobalObject, which causes that function to michael@0: // fire the hook as its final act before returning. Otherwise, callers should michael@0: // pass |DontFireOnNewGlobalHook|, which means that they are responsible for michael@0: // invoking JS_FireOnNewGlobalObject upon successfully creating the global. If michael@0: // an error occurs and the operation aborts, callers should skip firing the michael@0: // hook. But otherwise, callers must take care to fire the hook exactly once michael@0: // before compiling any script in the global's scope (we have assertions in michael@0: // place to enforce this). This lets us be sure that debugger clients never miss michael@0: // breakpoints. michael@0: enum OnNewGlobalHookOption { michael@0: FireOnNewGlobalHook, michael@0: DontFireOnNewGlobalHook michael@0: }; michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewGlobalObject(JSContext *cx, const JSClass *clasp, JSPrincipals *principals, michael@0: JS::OnNewGlobalHookOption hookOption, michael@0: const JS::CompartmentOptions &options = JS::CompartmentOptions()); michael@0: /* michael@0: * Spidermonkey does not have a good way of keeping track of what compartments should be marked on michael@0: * their own. We can mark the roots unconditionally, but marking GC things only relevant in live michael@0: * compartments is hard. To mitigate this, we create a static trace hook, installed on each global michael@0: * object, from which we can be sure the compartment is relevant, and mark it. michael@0: * michael@0: * It is still possible to specify custom trace hooks for global object classes. They can be michael@0: * provided via the CompartmentOptions passed to JS_NewGlobalObject. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_GlobalObjectTraceHook(JSTracer *trc, JSObject *global); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_FireOnNewGlobalObject(JSContext *cx, JS::HandleObject global); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewObject(JSContext *cx, const JSClass *clasp, JS::Handle proto, michael@0: JS::Handle parent); michael@0: michael@0: /* Queries the [[Extensible]] property of the object. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsExtensible(JSContext *cx, JS::HandleObject obj, bool *extensible); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsNative(JSObject *obj); michael@0: michael@0: extern JS_PUBLIC_API(JSRuntime *) michael@0: JS_GetObjectRuntime(JSObject *obj); michael@0: michael@0: /* michael@0: * Unlike JS_NewObject, JS_NewObjectWithGivenProto does not compute a default michael@0: * proto if proto's actual parameter value is null. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewObjectWithGivenProto(JSContext *cx, const JSClass *clasp, JS::Handle proto, michael@0: JS::Handle parent); michael@0: michael@0: /* michael@0: * Freeze obj, and all objects it refers to, recursively. This will not recurse michael@0: * through non-extensible objects, on the assumption that those are already michael@0: * deep-frozen. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DeepFreezeObject(JSContext *cx, JS::Handle obj); michael@0: michael@0: /* michael@0: * Freezes an object; see ES5's Object.freeze(obj) method. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_FreezeObject(JSContext *cx, JS::Handle obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_PreventExtensions(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_New(JSContext *cx, JS::HandleObject ctor, const JS::HandleValueArray& args); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, const JSClass *clasp, michael@0: JSObject *proto, unsigned attrs); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineConstDoubles(JSContext *cx, JS::HandleObject obj, const JSConstDoubleSpec *cds); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineProperties(JSContext *cx, JS::HandleObject obj, const JSPropertySpec *ps); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::HandleValue value, michael@0: unsigned attrs, michael@0: JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::HandleObject value, michael@0: unsigned attrs, michael@0: JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::HandleString value, michael@0: unsigned attrs, michael@0: JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, int32_t value, michael@0: unsigned attrs, michael@0: JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, uint32_t value, michael@0: unsigned attrs, michael@0: JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, double value, michael@0: unsigned attrs, michael@0: JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, michael@0: JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, michael@0: JS::HandleValue descriptor, bool *bp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_AlreadyHasOwnProperty(JSContext *cx, JS::HandleObject obj, const char *name, michael@0: bool *foundp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_AlreadyHasOwnPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, michael@0: bool *foundp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_HasProperty(JSContext *cx, JS::HandleObject obj, const char *name, bool *foundp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_HasPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *foundp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_LookupProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_LookupPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, michael@0: JS::MutableHandleValue vp); michael@0: michael@0: struct JSPropertyDescriptor { michael@0: JSObject *obj; michael@0: unsigned attrs; michael@0: JSPropertyOp getter; michael@0: JSStrictPropertyOp setter; michael@0: JS::Value value; michael@0: michael@0: JSPropertyDescriptor() michael@0: : obj(nullptr), attrs(0), getter(nullptr), setter(nullptr), value(JSVAL_VOID) michael@0: {} michael@0: michael@0: void trace(JSTracer *trc); michael@0: }; michael@0: michael@0: namespace JS { michael@0: michael@0: template michael@0: class PropertyDescriptorOperations michael@0: { michael@0: const JSPropertyDescriptor * desc() const { return static_cast(this)->extract(); } michael@0: michael@0: public: michael@0: bool isEnumerable() const { return desc()->attrs & JSPROP_ENUMERATE; } michael@0: bool isReadonly() const { return desc()->attrs & JSPROP_READONLY; } michael@0: bool isPermanent() const { return desc()->attrs & JSPROP_PERMANENT; } michael@0: bool hasNativeAccessors() const { return desc()->attrs & JSPROP_NATIVE_ACCESSORS; } michael@0: bool hasGetterObject() const { return desc()->attrs & JSPROP_GETTER; } michael@0: bool hasSetterObject() const { return desc()->attrs & JSPROP_SETTER; } michael@0: bool hasGetterOrSetterObject() const { return desc()->attrs & (JSPROP_GETTER | JSPROP_SETTER); } michael@0: bool isShared() const { return desc()->attrs & JSPROP_SHARED; } michael@0: bool isIndex() const { return desc()->attrs & JSPROP_INDEX; } michael@0: bool hasAttributes(unsigned attrs) const { return desc()->attrs & attrs; } michael@0: michael@0: JS::HandleObject object() const { michael@0: return JS::HandleObject::fromMarkedLocation(&desc()->obj); michael@0: } michael@0: unsigned attributes() const { return desc()->attrs; } michael@0: JSPropertyOp getter() const { return desc()->getter; } michael@0: JSStrictPropertyOp setter() const { return desc()->setter; } michael@0: JS::HandleObject getterObject() const { michael@0: MOZ_ASSERT(hasGetterObject()); michael@0: return JS::HandleObject::fromMarkedLocation( michael@0: reinterpret_cast(&desc()->getter)); michael@0: } michael@0: JS::HandleObject setterObject() const { michael@0: MOZ_ASSERT(hasSetterObject()); michael@0: return JS::HandleObject::fromMarkedLocation( michael@0: reinterpret_cast(&desc()->setter)); michael@0: } michael@0: JS::HandleValue value() const { michael@0: return JS::HandleValue::fromMarkedLocation(&desc()->value); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations michael@0: { michael@0: JSPropertyDescriptor * desc() { return static_cast(this)->extractMutable(); } michael@0: michael@0: public: michael@0: michael@0: void clear() { michael@0: object().set(nullptr); michael@0: setAttributes(0); michael@0: setGetter(nullptr); michael@0: setSetter(nullptr); michael@0: value().setUndefined(); michael@0: } michael@0: michael@0: JS::MutableHandleObject object() { michael@0: return JS::MutableHandleObject::fromMarkedLocation(&desc()->obj); michael@0: } michael@0: unsigned &attributesRef() { return desc()->attrs; } michael@0: JSPropertyOp &getter() { return desc()->getter; } michael@0: JSStrictPropertyOp &setter() { return desc()->setter; } michael@0: JS::MutableHandleValue value() { michael@0: return JS::MutableHandleValue::fromMarkedLocation(&desc()->value); michael@0: } michael@0: michael@0: void setEnumerable() { desc()->attrs |= JSPROP_ENUMERATE; } michael@0: void setAttributes(unsigned attrs) { desc()->attrs = attrs; } michael@0: michael@0: void setGetter(JSPropertyOp op) { desc()->getter = op; } michael@0: void setSetter(JSStrictPropertyOp op) { desc()->setter = op; } michael@0: void setGetterObject(JSObject *obj) { desc()->getter = reinterpret_cast(obj); } michael@0: void setSetterObject(JSObject *obj) { desc()->setter = reinterpret_cast(obj); } michael@0: }; michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: namespace js { michael@0: michael@0: template <> michael@0: struct GCMethods { michael@0: static JSPropertyDescriptor initial() { return JSPropertyDescriptor(); } michael@0: static ThingRootKind kind() { return THING_ROOT_PROPERTY_DESCRIPTOR; } michael@0: static bool poisoned(const JSPropertyDescriptor &desc) { michael@0: return (desc.obj && JS::IsPoisonedPtr(desc.obj)) || michael@0: (desc.attrs & JSPROP_GETTER && desc.getter && JS::IsPoisonedPtr(desc.getter)) || michael@0: (desc.attrs & JSPROP_SETTER && desc.setter && JS::IsPoisonedPtr(desc.setter)) || michael@0: (desc.value.isGCThing() && JS::IsPoisonedPtr(desc.value.toGCThing())); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: class RootedBase michael@0: : public JS::MutablePropertyDescriptorOperations > michael@0: { michael@0: friend class JS::PropertyDescriptorOperations >; michael@0: friend class JS::MutablePropertyDescriptorOperations >; michael@0: const JSPropertyDescriptor *extract() const { michael@0: return static_cast*>(this)->address(); michael@0: } michael@0: JSPropertyDescriptor *extractMutable() { michael@0: return static_cast*>(this)->address(); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: class HandleBase michael@0: : public JS::PropertyDescriptorOperations > michael@0: { michael@0: friend class JS::PropertyDescriptorOperations >; michael@0: const JSPropertyDescriptor *extract() const { michael@0: return static_cast*>(this)->address(); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: class MutableHandleBase michael@0: : public JS::MutablePropertyDescriptorOperations > michael@0: { michael@0: friend class JS::PropertyDescriptorOperations >; michael@0: friend class JS::MutablePropertyDescriptorOperations >; michael@0: const JSPropertyDescriptor *extract() const { michael@0: return static_cast*>(this)->address(); michael@0: } michael@0: JSPropertyDescriptor *extractMutable() { michael@0: return static_cast*>(this)->address(); michael@0: } michael@0: }; michael@0: michael@0: } /* namespace js */ michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetOwnPropertyDescriptorById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, michael@0: JS::MutableHandle desc); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetOwnPropertyDescriptor(JSContext *cx, JS::HandleObject obj, const char *name, michael@0: JS::MutableHandle desc); michael@0: michael@0: /* michael@0: * Like JS_GetOwnPropertyDescriptorById but will return a property on michael@0: * an object on the prototype chain (returned in desc->obj). If desc->obj is null, michael@0: * then this property was not found on the prototype chain. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetPropertyDescriptorById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, michael@0: JS::MutableHandle desc); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetPropertyDescriptor(JSContext *cx, JS::HandleObject obj, const char *name, michael@0: JS::MutableHandle desc); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ForwardGetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject onBehalfOf, michael@0: JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::HandleValue v); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DeleteProperty(JSContext *cx, JS::HandleObject obj, const char *name); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DeleteProperty2(JSContext *cx, JS::HandleObject obj, const char *name, bool *succeeded); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DeletePropertyById(JSContext *cx, JS::HandleObject obj, jsid id); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DeletePropertyById2(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *succeeded); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineUCProperty(JSContext *cx, JSObject *obj, michael@0: const jschar *name, size_t namelen, jsval value, michael@0: JSPropertyOp getter, JSStrictPropertyOp setter, michael@0: unsigned attrs); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_AlreadyHasOwnUCProperty(JSContext *cx, JS::HandleObject obj, const jschar *name, michael@0: size_t namelen, bool *foundp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_HasUCProperty(JSContext *cx, JS::HandleObject obj, michael@0: const jschar *name, size_t namelen, michael@0: bool *vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_LookupUCProperty(JSContext *cx, JS::HandleObject obj, michael@0: const jschar *name, size_t namelen, michael@0: JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetUCProperty(JSContext *cx, JS::HandleObject obj, michael@0: const jschar *name, size_t namelen, michael@0: JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetUCProperty(JSContext *cx, JS::HandleObject obj, michael@0: const jschar *name, size_t namelen, michael@0: JS::HandleValue v); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DeleteUCProperty2(JSContext *cx, JS::HandleObject obj, const jschar *name, size_t namelen, michael@0: bool *succeeded); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewArrayObject(JSContext *cx, const JS::HandleValueArray& contents); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewArrayObject(JSContext *cx, size_t length); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsArrayObject(JSContext *cx, JS::HandleValue value); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsArrayObject(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetArrayLength(JSContext *cx, JS::Handle obj, uint32_t *lengthp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetArrayLength(JSContext *cx, JS::Handle obj, uint32_t length); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, jsval value, michael@0: JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_AlreadyHasOwnElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *foundp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_HasElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *foundp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_LookupElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ForwardGetElementTo(JSContext *cx, JS::HandleObject obj, uint32_t index, michael@0: JS::HandleObject onBehalfOf, JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue v); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleObject v); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleString v); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, int32_t v); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, uint32_t v); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, double v); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DeleteElement(JSContext *cx, JS::HandleObject obj, uint32_t index); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DeleteElement2(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *succeeded); michael@0: michael@0: /* michael@0: * Remove all configurable properties from the given (non-global) object and michael@0: * assign undefined to all writable data properties. michael@0: */ michael@0: JS_PUBLIC_API(void) michael@0: JS_ClearNonGlobalObject(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: /* michael@0: * Assign 'undefined' to all of the object's non-reserved slots. Note: this is michael@0: * done for all slots, regardless of the associated property descriptor. michael@0: */ michael@0: JS_PUBLIC_API(void) michael@0: JS_SetAllNonReservedSlotsToUndefined(JSContext *cx, JSObject *objArg); michael@0: michael@0: /* michael@0: * Create a new array buffer with the given contents. On success, the ownership michael@0: * is transferred to the new array buffer. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewArrayBufferWithContents(JSContext *cx, size_t nbytes, void *contents); michael@0: michael@0: /* michael@0: * Steal the contents of the given array buffer. The array buffer has its michael@0: * length set to 0 and its contents array cleared. The caller takes ownership michael@0: * of the return value and must free it or transfer ownership via michael@0: * JS_NewArrayBufferWithContents when done using it. michael@0: */ michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_StealArrayBufferContents(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: /* michael@0: * Allocate memory that may be eventually passed to michael@0: * JS_NewArrayBufferWithContents. |maybecx| is optional; if a non-nullptr cx is michael@0: * given, it will be used for memory accounting and OOM reporting. |nbytes| is michael@0: * the number of payload bytes required. michael@0: */ michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes); michael@0: michael@0: /* michael@0: * Reallocate memory allocated by JS_AllocateArrayBufferContents, growing or michael@0: * shrinking it as appropriate. If oldContents is null then this behaves like michael@0: * JS_AllocateArrayBufferContents. michael@0: */ michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_ReallocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void *oldContents, uint32_t oldNbytes); michael@0: michael@0: /* michael@0: * Create a new mapped array buffer with the given memory mapped contents. On success, michael@0: * the ownership is transferred to the new mapped array buffer. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewMappedArrayBufferWithContents(JSContext *cx, size_t nbytes, void *contents); michael@0: michael@0: /* michael@0: * Create memory mapped array buffer contents. michael@0: * Caller must take care of closing fd after calling this function. michael@0: */ michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length); michael@0: michael@0: /* michael@0: * Release the allocated resource of mapped array buffer contents before the michael@0: * object is created. michael@0: * If a new object has been created by JS_NewMappedArrayBufferWithContents() michael@0: * with this content, then JS_NeuterArrayBuffer() should be used instead to michael@0: * release the resource used by the object. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ReleaseMappedArrayBufferContents(void *contents, size_t length); michael@0: michael@0: extern JS_PUBLIC_API(JSIdArray *) michael@0: JS_Enumerate(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: /* michael@0: * Create an object to iterate over enumerable properties of obj, in arbitrary michael@0: * property definition order. NB: This differs from longstanding for..in loop michael@0: * order, which uses order of property definition in obj. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewPropertyIterator(JSContext *cx, JS::Handle obj); michael@0: michael@0: /* michael@0: * Return true on success with *idp containing the id of the next enumerable michael@0: * property to visit using iterobj, or JSID_IS_VOID if there is no such property michael@0: * left to visit. Return false on error. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_NextProperty(JSContext *cx, JS::Handle iterobj, jsid *idp); michael@0: michael@0: extern JS_PUBLIC_API(jsval) michael@0: JS_GetReservedSlot(JSObject *obj, uint32_t index); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetReservedSlot(JSObject *obj, uint32_t index, jsval v); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * Functions and scripts. michael@0: */ michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: JS_NewFunction(JSContext *cx, JSNative call, unsigned nargs, unsigned flags, michael@0: JS::Handle parent, const char *name); michael@0: michael@0: /* michael@0: * Create the function with the name given by the id. JSID_IS_STRING(id) must michael@0: * be true. michael@0: */ michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: JS_NewFunctionById(JSContext *cx, JSNative call, unsigned nargs, unsigned flags, michael@0: JS::Handle parent, JS::Handle id); michael@0: michael@0: namespace JS { michael@0: michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, JS::Handle id, michael@0: unsigned nargs); michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_GetFunctionObject(JSFunction *fun); michael@0: michael@0: /* michael@0: * Return the function's identifier as a JSString, or null if fun is unnamed. michael@0: * The returned string lives as long as fun, so you don't need to root a saved michael@0: * reference to it if fun is well-connected or rooted, and provided you bound michael@0: * the use of the saved reference by fun's lifetime. michael@0: */ michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_GetFunctionId(JSFunction *fun); michael@0: michael@0: /* michael@0: * Return a function's display name. This is the defined name if one was given michael@0: * where the function was defined, or it could be an inferred name by the JS michael@0: * engine in the case that the function was defined to be anonymous. This can michael@0: * still return nullptr if a useful display name could not be inferred. The michael@0: * same restrictions on rooting as those in JS_GetFunctionId apply. michael@0: */ michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_GetFunctionDisplayId(JSFunction *fun); michael@0: michael@0: /* michael@0: * Return the arity (length) of fun. michael@0: */ michael@0: extern JS_PUBLIC_API(uint16_t) michael@0: JS_GetFunctionArity(JSFunction *fun); michael@0: michael@0: /* michael@0: * Infallible predicate to test whether obj is a function object (faster than michael@0: * comparing obj's class name to "Function", but equivalent unless someone has michael@0: * overwritten the "Function" identifier with a different constructor and then michael@0: * created instances using that constructor that might be passed in as obj). michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ObjectIsFunction(JSContext *cx, JSObject *obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ObjectIsCallable(JSContext *cx, JSObject *obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsNativeFunction(JSObject *funobj, JSNative call); michael@0: michael@0: /* Return whether the given function is a valid constructor. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsConstructor(JSFunction *fun); michael@0: michael@0: /* michael@0: * Bind the given callable to use the given object as "this". michael@0: * michael@0: * If |callable| is not callable, will throw and return nullptr. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject*) michael@0: JS_BindCallable(JSContext *cx, JS::Handle callable, JS::Handle newThis); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_DefineFunctions(JSContext *cx, JS::Handle obj, const JSFunctionSpec *fs); michael@0: michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: JS_DefineFunction(JSContext *cx, JS::Handle obj, const char *name, JSNative call, michael@0: unsigned nargs, unsigned attrs); michael@0: michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: JS_DefineUCFunction(JSContext *cx, JS::Handle obj, michael@0: const jschar *name, size_t namelen, JSNative call, michael@0: unsigned nargs, unsigned attrs); michael@0: michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: JS_DefineFunctionById(JSContext *cx, JS::Handle obj, JS::Handle id, JSNative call, michael@0: unsigned nargs, unsigned attrs); michael@0: michael@0: /* michael@0: * Clone a top-level function into a new scope. This function will dynamically michael@0: * fail if funobj was lexically nested inside some other function. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_CloneFunctionObject(JSContext *cx, JS::Handle funobj, JS::Handle parent); michael@0: michael@0: /* michael@0: * Given a buffer, return false if the buffer might become a valid michael@0: * javascript statement with the addition of more lines. Otherwise return michael@0: * true. The intent is to support interactive compilation - accumulate michael@0: * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to michael@0: * the compiler. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_BufferIsCompilableUnit(JSContext *cx, JS::Handle obj, const char *utf8, michael@0: size_t length); michael@0: michael@0: extern JS_PUBLIC_API(JSScript *) michael@0: JS_CompileScript(JSContext *cx, JS::HandleObject obj, michael@0: const char *ascii, size_t length, michael@0: const JS::CompileOptions &options); michael@0: michael@0: extern JS_PUBLIC_API(JSScript *) michael@0: JS_CompileUCScript(JSContext *cx, JS::HandleObject obj, michael@0: const jschar *chars, size_t length, michael@0: const JS::CompileOptions &options); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_GetGlobalFromScript(JSScript *script); michael@0: michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: JS_CompileFunction(JSContext *cx, JS::HandleObject obj, const char *name, michael@0: unsigned nargs, const char *const *argnames, michael@0: const char *bytes, size_t length, michael@0: const JS::CompileOptions &options); michael@0: michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: JS_CompileUCFunction(JSContext *cx, JS::HandleObject obj, const char *name, michael@0: unsigned nargs, const char *const *argnames, michael@0: const jschar *chars, size_t length, michael@0: const JS::CompileOptions &options); michael@0: michael@0: namespace JS { michael@0: michael@0: /* Options for JavaScript compilation. */ michael@0: michael@0: /* michael@0: * In the most common use case, a CompileOptions instance is allocated on the michael@0: * stack, and holds non-owning references to non-POD option values: strings; michael@0: * principals; objects; and so on. The code declaring the instance guarantees michael@0: * that such option values will outlive the CompileOptions itself: objects are michael@0: * otherwise rooted; principals have had their reference counts bumped; strings michael@0: * will not be freed until the CompileOptions goes out of scope. In this michael@0: * situation, CompileOptions only refers to things others own, so it can be michael@0: * lightweight. michael@0: * michael@0: * In some cases, however, we need to hold compilation options with a michael@0: * non-stack-like lifetime. For example, JS::CompileOffThread needs to save michael@0: * compilation options where a worker thread can find them, and then return michael@0: * immediately. The worker thread will come along at some later point, and use michael@0: * the options. michael@0: * michael@0: * The compiler itself just needs to be able to access a collection of options; michael@0: * it doesn't care who owns them, or what's keeping them alive. It does its own michael@0: * addrefs/copies/tracing/etc. michael@0: * michael@0: * So, we have a class hierarchy that reflects these three use cases: michael@0: * michael@0: * - ReadOnlyCompileOptions is the common base class. It can be used by code michael@0: * that simply needs to access options set elsewhere, like the compiler. michael@0: * michael@0: * - The usual CompileOptions class must be stack-allocated, and holds michael@0: * non-owning references to the filename, element, and so on. It's derived michael@0: * from ReadOnlyCompileOptions, so the compiler can use it. michael@0: * michael@0: * - OwningCompileOptions roots / copies / reference counts of all its values, michael@0: * and unroots / frees / releases them when it is destructed. It too is michael@0: * derived from ReadOnlyCompileOptions, so the compiler accepts it. michael@0: */ michael@0: michael@0: /* michael@0: * The common base class for the CompileOptions hierarchy. michael@0: * michael@0: * Use this in code that only needs to access compilation options created michael@0: * elsewhere, like the compiler. Don't instantiate this class (the constructor michael@0: * is protected anyway); instead, create instances only of the derived classes: michael@0: * CompileOptions and OwningCompileOptions. michael@0: */ michael@0: class JS_FRIEND_API(ReadOnlyCompileOptions) michael@0: { michael@0: friend class CompileOptions; michael@0: michael@0: protected: michael@0: JSPrincipals *originPrincipals_; michael@0: const char *filename_; michael@0: const char *introducerFilename_; michael@0: const jschar *sourceMapURL_; michael@0: michael@0: // This constructor leaves 'version' set to JSVERSION_UNKNOWN. The structure michael@0: // is unusable until that's set to something more specific; the derived michael@0: // classes' constructors take care of that, in ways appropriate to their michael@0: // purpose. michael@0: ReadOnlyCompileOptions() michael@0: : originPrincipals_(nullptr), michael@0: filename_(nullptr), michael@0: introducerFilename_(nullptr), michael@0: sourceMapURL_(nullptr), michael@0: version(JSVERSION_UNKNOWN), michael@0: versionSet(false), michael@0: utf8(false), michael@0: lineno(1), michael@0: column(0), michael@0: compileAndGo(false), michael@0: forEval(false), michael@0: defineOnScope(true), michael@0: noScriptRval(false), michael@0: selfHostingMode(false), michael@0: canLazilyParse(true), michael@0: strictOption(false), michael@0: extraWarningsOption(false), michael@0: werrorOption(false), michael@0: asmJSOption(false), michael@0: forceAsync(false), michael@0: installedFile(false), michael@0: sourceIsLazy(false), michael@0: introductionType(nullptr), michael@0: introductionLineno(0), michael@0: introductionOffset(0), michael@0: hasIntroductionInfo(false) michael@0: { } michael@0: michael@0: // Set all POD options (those not requiring reference counts, copies, michael@0: // rooting, or other hand-holding) to their values in |rhs|. michael@0: void copyPODOptions(const ReadOnlyCompileOptions &rhs); michael@0: michael@0: public: michael@0: // Read-only accessors for non-POD options. The proper way to set these michael@0: // depends on the derived type. michael@0: JSPrincipals *originPrincipals(js::ExclusiveContext *cx) const; michael@0: const char *filename() const { return filename_; } michael@0: const char *introducerFilename() const { return introducerFilename_; } michael@0: const jschar *sourceMapURL() const { return sourceMapURL_; } michael@0: virtual JSObject *element() const = 0; michael@0: virtual JSString *elementAttributeName() const = 0; michael@0: virtual JSScript *introductionScript() const = 0; michael@0: michael@0: // POD options. michael@0: JSVersion version; michael@0: bool versionSet; michael@0: bool utf8; michael@0: unsigned lineno; michael@0: unsigned column; michael@0: bool compileAndGo; michael@0: bool forEval; michael@0: bool defineOnScope; michael@0: bool noScriptRval; michael@0: bool selfHostingMode; michael@0: bool canLazilyParse; michael@0: bool strictOption; michael@0: bool extraWarningsOption; michael@0: bool werrorOption; michael@0: bool asmJSOption; michael@0: bool forceAsync; michael@0: bool installedFile; // 'true' iff pre-compiling js file in packaged app michael@0: bool sourceIsLazy; michael@0: michael@0: // |introductionType| is a statically allocated C string: michael@0: // one of "eval", "Function", or "GeneratorFunction". michael@0: const char *introductionType; michael@0: unsigned introductionLineno; michael@0: uint32_t introductionOffset; michael@0: bool hasIntroductionInfo; michael@0: michael@0: // Wrap any compilation option values that need it as appropriate for michael@0: // use from |compartment|. michael@0: virtual bool wrap(JSContext *cx, JSCompartment *compartment) = 0; michael@0: michael@0: private: michael@0: static JSObject * const nullObjectPtr; michael@0: void operator=(const ReadOnlyCompileOptions &) MOZ_DELETE; michael@0: }; michael@0: michael@0: /* michael@0: * Compilation options, with dynamic lifetime. An instance of this type michael@0: * makes a copy of / holds / roots all dynamically allocated resources michael@0: * (principals; elements; strings) that it refers to. Its destructor frees michael@0: * / drops / unroots them. This is heavier than CompileOptions, below, but michael@0: * unlike CompileOptions, it can outlive any given stack frame. michael@0: * michael@0: * Note that this *roots* any JS values it refers to - they're live michael@0: * unconditionally. Thus, instances of this type can't be owned, directly michael@0: * or indirectly, by a JavaScript object: if any value that this roots ever michael@0: * comes to refer to the object that owns this, then the whole cycle, and michael@0: * anything else it entrains, will never be freed. michael@0: */ michael@0: class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions michael@0: { michael@0: JSRuntime *runtime; michael@0: PersistentRootedObject elementRoot; michael@0: PersistentRootedString elementAttributeNameRoot; michael@0: PersistentRootedScript introductionScriptRoot; michael@0: michael@0: public: michael@0: // A minimal constructor, for use with OwningCompileOptions::copy. This michael@0: // leaves |this.version| set to JSVERSION_UNKNOWN; the instance michael@0: // shouldn't be used until we've set that to something real (as |copy| michael@0: // will). michael@0: explicit OwningCompileOptions(JSContext *cx); michael@0: ~OwningCompileOptions(); michael@0: michael@0: JSObject *element() const MOZ_OVERRIDE { return elementRoot; } michael@0: JSString *elementAttributeName() const MOZ_OVERRIDE { return elementAttributeNameRoot; } michael@0: JSScript *introductionScript() const MOZ_OVERRIDE { return introductionScriptRoot; } michael@0: michael@0: // Set this to a copy of |rhs|. Return false on OOM. michael@0: bool copy(JSContext *cx, const ReadOnlyCompileOptions &rhs); michael@0: michael@0: /* These setters make copies of their string arguments, and are fallible. */ michael@0: bool setFile(JSContext *cx, const char *f); michael@0: bool setFileAndLine(JSContext *cx, const char *f, unsigned l); michael@0: bool setSourceMapURL(JSContext *cx, const jschar *s); michael@0: bool setIntroducerFilename(JSContext *cx, const char *s); michael@0: michael@0: /* These setters are infallible, and can be chained. */ michael@0: OwningCompileOptions &setLine(unsigned l) { lineno = l; return *this; } michael@0: OwningCompileOptions &setElement(JSObject *e) { michael@0: elementRoot = e; michael@0: return *this; michael@0: } michael@0: OwningCompileOptions &setElementAttributeName(JSString *p) { michael@0: elementAttributeNameRoot = p; michael@0: return *this; michael@0: } michael@0: OwningCompileOptions &setIntroductionScript(JSScript *s) { michael@0: introductionScriptRoot = s; michael@0: return *this; michael@0: } michael@0: OwningCompileOptions &setOriginPrincipals(JSPrincipals *p) { michael@0: if (p) JS_HoldPrincipals(p); michael@0: if (originPrincipals_) JS_DropPrincipals(runtime, originPrincipals_); michael@0: originPrincipals_ = p; michael@0: return *this; michael@0: } michael@0: OwningCompileOptions &setVersion(JSVersion v) { michael@0: version = v; michael@0: versionSet = true; michael@0: return *this; michael@0: } michael@0: OwningCompileOptions &setUTF8(bool u) { utf8 = u; return *this; } michael@0: OwningCompileOptions &setColumn(unsigned c) { column = c; return *this; } michael@0: OwningCompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; } michael@0: OwningCompileOptions &setForEval(bool eval) { forEval = eval; return *this; } michael@0: OwningCompileOptions &setDefineOnScope(bool define) { defineOnScope = define; return *this; } michael@0: OwningCompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } michael@0: OwningCompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; } michael@0: OwningCompileOptions &setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; } michael@0: OwningCompileOptions &setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; } michael@0: OwningCompileOptions &setIntroductionType(const char *t) { introductionType = t; return *this; } michael@0: bool setIntroductionInfo(JSContext *cx, const char *introducerFn, const char *intro, michael@0: unsigned line, JSScript *script, uint32_t offset) michael@0: { michael@0: if (!setIntroducerFilename(cx, introducerFn)) michael@0: return false; michael@0: introductionType = intro; michael@0: introductionLineno = line; michael@0: introductionScriptRoot = script; michael@0: introductionOffset = offset; michael@0: hasIntroductionInfo = true; michael@0: return true; michael@0: } michael@0: michael@0: virtual bool wrap(JSContext *cx, JSCompartment *compartment) MOZ_OVERRIDE; michael@0: michael@0: private: michael@0: void operator=(const CompileOptions &rhs) MOZ_DELETE; michael@0: }; michael@0: michael@0: /* michael@0: * Compilation options stored on the stack. An instance of this type michael@0: * simply holds references to dynamically allocated resources (element; michael@0: * filename; source map URL) that are owned by something else. If you michael@0: * create an instance of this type, it's up to you to guarantee that michael@0: * everything you store in it will outlive it. michael@0: */ michael@0: class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOptions michael@0: { michael@0: RootedObject elementRoot; michael@0: RootedString elementAttributeNameRoot; michael@0: RootedScript introductionScriptRoot; michael@0: michael@0: public: michael@0: explicit CompileOptions(JSContext *cx, JSVersion version = JSVERSION_UNKNOWN); michael@0: CompileOptions(js::ContextFriendFields *cx, const ReadOnlyCompileOptions &rhs) michael@0: : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx), michael@0: introductionScriptRoot(cx) michael@0: { michael@0: copyPODOptions(rhs); michael@0: michael@0: originPrincipals_ = rhs.originPrincipals_; michael@0: filename_ = rhs.filename(); michael@0: sourceMapURL_ = rhs.sourceMapURL(); michael@0: elementRoot = rhs.element(); michael@0: elementAttributeNameRoot = rhs.elementAttributeName(); michael@0: introductionScriptRoot = rhs.introductionScript(); michael@0: } michael@0: michael@0: JSObject *element() const MOZ_OVERRIDE { return elementRoot; } michael@0: JSString *elementAttributeName() const MOZ_OVERRIDE { return elementAttributeNameRoot; } michael@0: JSScript *introductionScript() const MOZ_OVERRIDE { return introductionScriptRoot; } michael@0: michael@0: CompileOptions &setFile(const char *f) { filename_ = f; return *this; } michael@0: CompileOptions &setLine(unsigned l) { lineno = l; return *this; } michael@0: CompileOptions &setFileAndLine(const char *f, unsigned l) { michael@0: filename_ = f; lineno = l; return *this; michael@0: } michael@0: CompileOptions &setSourceMapURL(const jschar *s) { sourceMapURL_ = s; return *this; } michael@0: CompileOptions &setElement(JSObject *e) { elementRoot = e; return *this; } michael@0: CompileOptions &setElementAttributeName(JSString *p) { michael@0: elementAttributeNameRoot = p; michael@0: return *this; michael@0: } michael@0: CompileOptions &setIntroductionScript(JSScript *s) { michael@0: introductionScriptRoot = s; michael@0: return *this; michael@0: } michael@0: CompileOptions &setOriginPrincipals(JSPrincipals *p) { michael@0: originPrincipals_ = p; michael@0: return *this; michael@0: } michael@0: CompileOptions &setVersion(JSVersion v) { michael@0: version = v; michael@0: versionSet = true; michael@0: return *this; michael@0: } michael@0: CompileOptions &setUTF8(bool u) { utf8 = u; return *this; } michael@0: CompileOptions &setColumn(unsigned c) { column = c; return *this; } michael@0: CompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; } michael@0: CompileOptions &setForEval(bool eval) { forEval = eval; return *this; } michael@0: CompileOptions &setDefineOnScope(bool define) { defineOnScope = define; return *this; } michael@0: CompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } michael@0: CompileOptions &setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; } michael@0: CompileOptions &setCanLazilyParse(bool clp) { canLazilyParse = clp; return *this; } michael@0: CompileOptions &setSourceIsLazy(bool l) { sourceIsLazy = l; return *this; } michael@0: CompileOptions &setIntroductionType(const char *t) { introductionType = t; return *this; } michael@0: CompileOptions &setIntroductionInfo(const char *introducerFn, const char *intro, michael@0: unsigned line, JSScript *script, uint32_t offset) michael@0: { michael@0: introducerFilename_ = introducerFn; michael@0: introductionType = intro; michael@0: introductionLineno = line; michael@0: introductionScriptRoot = script; michael@0: introductionOffset = offset; michael@0: hasIntroductionInfo = true; michael@0: return *this; michael@0: } michael@0: michael@0: virtual bool wrap(JSContext *cx, JSCompartment *compartment) MOZ_OVERRIDE; michael@0: michael@0: private: michael@0: void operator=(const CompileOptions &rhs) MOZ_DELETE; michael@0: }; michael@0: michael@0: /* michael@0: * |script| will always be set. On failure, it will be set to nullptr. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: SourceBufferHolder &srcBuf, JS::MutableHandleScript script); michael@0: michael@0: extern JS_PUBLIC_API(JSScript *) michael@0: Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const char *bytes, size_t length); michael@0: michael@0: extern JS_PUBLIC_API(JSScript *) michael@0: Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const jschar *chars, size_t length); michael@0: michael@0: extern JS_PUBLIC_API(JSScript *) michael@0: Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, FILE *file); michael@0: michael@0: extern JS_PUBLIC_API(JSScript *) michael@0: Compile(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, const char *filename); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, size_t length); michael@0: michael@0: /* michael@0: * Off thread compilation control flow. michael@0: * michael@0: * After successfully triggering an off thread compile of a script, the michael@0: * callback will eventually be invoked with the specified data and a token michael@0: * for the compilation. The callback will be invoked while off the main thread, michael@0: * so must ensure that its operations are thread safe. Afterwards, michael@0: * FinishOffThreadScript must be invoked on the main thread to get the result michael@0: * script or nullptr. If maybecx is not specified, the resources will be freed, michael@0: * but no script will be returned. michael@0: * michael@0: * The characters passed in to CompileOffThread must remain live until the michael@0: * callback is invoked, and the resulting script will be rooted until the call michael@0: * to FinishOffThreadScript. michael@0: */ michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: CompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, michael@0: const jschar *chars, size_t length, michael@0: OffThreadCompileCallback callback, void *callbackData); michael@0: michael@0: extern JS_PUBLIC_API(JSScript *) michael@0: FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: CompileFunction(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const char *name, unsigned nargs, const char *const *argnames, michael@0: SourceBufferHolder &srcBuf, JS::MutableHandleFunction fun); michael@0: michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: CompileFunction(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const char *name, unsigned nargs, const char *const *argnames, michael@0: const char *bytes, size_t length); michael@0: michael@0: extern JS_PUBLIC_API(JSFunction *) michael@0: CompileFunction(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const char *name, unsigned nargs, const char *const *argnames, michael@0: const jschar *chars, size_t length); michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_DecompileScript(JSContext *cx, JS::Handle script, const char *name, unsigned indent); michael@0: michael@0: /* michael@0: * API extension: OR this into indent to avoid pretty-printing the decompiled michael@0: * source resulting from JS_DecompileFunction{,Body}. michael@0: */ michael@0: #define JS_DONT_PRETTY_PRINT ((unsigned)0x8000) michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_DecompileFunction(JSContext *cx, JS::Handle fun, unsigned indent); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_DecompileFunctionBody(JSContext *cx, JS::Handle fun, unsigned indent); michael@0: michael@0: /* michael@0: * NB: JS_ExecuteScript and the JS_Evaluate*Script* quadruplets use the obj michael@0: * parameter as the initial scope chain header, the 'this' keyword value, and michael@0: * the variables object (ECMA parlance for where 'var' and 'function' bind michael@0: * names) of the execution context for script. michael@0: * michael@0: * Using obj as the variables object is problematic if obj's parent (which is michael@0: * the scope chain link; see JS_SetParent and JS_NewObject) is not null: in michael@0: * this case, variables created by 'var x = 0', e.g., go in obj, but variables michael@0: * created by assignment to an unbound id, 'x = 0', go in the last object on michael@0: * the scope chain linked by parent. michael@0: * michael@0: * ECMA calls that last scoping object the "global object", but note that many michael@0: * embeddings have several such objects. ECMA requires that "global code" be michael@0: * executed with the variables object equal to this global object. But these michael@0: * JS API entry points provide freedom to execute code against a "sub-global", michael@0: * i.e., a parented or scoped object, in which case the variables object will michael@0: * differ from the last object on the scope chain, resulting in confusing and michael@0: * non-ECMA explicit vs. implicit variable creation. michael@0: * michael@0: * Caveat embedders: unless you already depend on this buggy variables object michael@0: * binding behavior, you should call ContextOptionsRef(cx).setVarObjFix(true) michael@0: * for each context in the application, if you pass parented objects as the obj michael@0: * parameter, or may ever pass such objects in the future. michael@0: * michael@0: * Why a runtime option? The alternative is to add six or so new API entry michael@0: * points with signatures matching the following six, and that doesn't seem michael@0: * worth the code bloat cost. Such new entry points would probably have less michael@0: * obvious names, too, so would not tend to be used. The JS_SetOption call, michael@0: * OTOH, can be more easily hacked into existing code that does not depend on michael@0: * the bug; such code can continue to use the familiar JS_EvaluateScript, michael@0: * etc., entry points. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ExecuteScript(JSContext *cx, JS::HandleObject obj, JS::HandleScript script, JS::MutableHandleValue rval); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ExecuteScript(JSContext *cx, JS::HandleObject obj, JS::HandleScript script); michael@0: michael@0: namespace JS { michael@0: michael@0: /* michael@0: * Like the above, but handles a cross-compartment script. If the script is michael@0: * cross-compartment, it is cloned into the current compartment before executing. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: CloneAndExecuteScript(JSContext *cx, JS::Handle obj, JS::Handle script); michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ExecuteScriptVersion(JSContext *cx, JS::HandleObject obj, JS::HandleScript script, michael@0: JS::MutableHandleValue rval, JSVersion version); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ExecuteScriptVersion(JSContext *cx, JS::HandleObject obj, JS::HandleScript script, michael@0: JSVersion version); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_EvaluateScript(JSContext *cx, JS::HandleObject obj, michael@0: const char *bytes, unsigned length, michael@0: const char *filename, unsigned lineno, michael@0: JS::MutableHandleValue rval); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_EvaluateScript(JSContext *cx, JS::HandleObject obj, michael@0: const char *bytes, unsigned length, michael@0: const char *filename, unsigned lineno); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_EvaluateUCScript(JSContext *cx, JS::Handle obj, michael@0: const jschar *chars, unsigned length, michael@0: const char *filename, unsigned lineno, michael@0: JS::MutableHandle rval); michael@0: michael@0: namespace JS { michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: Evaluate(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: SourceBufferHolder &srcBuf, JS::MutableHandleValue rval); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: Evaluate(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const jschar *chars, size_t length, JS::MutableHandleValue rval); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: Evaluate(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const char *bytes, size_t length, JS::MutableHandleValue rval); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: Evaluate(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const char *filename, JS::MutableHandleValue rval); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: Evaluate(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: SourceBufferHolder &srcBuf); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: Evaluate(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const jschar *chars, size_t length); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: Evaluate(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const char *bytes, size_t length); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: Evaluate(JSContext *cx, JS::HandleObject obj, const ReadOnlyCompileOptions &options, michael@0: const char *filename); michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_CallFunction(JSContext *cx, JS::HandleObject obj, JS::HandleFunction fun, michael@0: const JS::HandleValueArray& args, JS::MutableHandleValue rval); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_CallFunctionName(JSContext *cx, JS::HandleObject obj, const char *name, michael@0: const JS::HandleValueArray& args, JS::MutableHandleValue rval); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_CallFunctionValue(JSContext *cx, JS::HandleObject obj, JS::HandleValue fval, michael@0: const JS::HandleValueArray& args, JS::MutableHandleValue rval); michael@0: michael@0: namespace JS { michael@0: michael@0: static inline bool michael@0: Call(JSContext *cx, JS::HandleObject thisObj, JS::HandleFunction fun, michael@0: const JS::HandleValueArray &args, MutableHandleValue rval) michael@0: { michael@0: return !!JS_CallFunction(cx, thisObj, fun, args, rval); michael@0: } michael@0: michael@0: static inline bool michael@0: Call(JSContext *cx, JS::HandleObject thisObj, const char *name, const JS::HandleValueArray& args, michael@0: MutableHandleValue rval) michael@0: { michael@0: return !!JS_CallFunctionName(cx, thisObj, name, args, rval); michael@0: } michael@0: michael@0: static inline bool michael@0: Call(JSContext *cx, JS::HandleObject thisObj, JS::HandleValue fun, const JS::HandleValueArray& args, michael@0: MutableHandleValue rval) michael@0: { michael@0: return !!JS_CallFunctionValue(cx, thisObj, fun, args, rval); michael@0: } michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: Call(JSContext *cx, JS::HandleValue thisv, JS::HandleValue fun, const JS::HandleValueArray& args, michael@0: MutableHandleValue rval); michael@0: michael@0: static inline bool michael@0: Call(JSContext *cx, JS::HandleValue thisv, JS::HandleObject funObj, const JS::HandleValueArray& args, michael@0: MutableHandleValue rval) michael@0: { michael@0: JS_ASSERT(funObj); michael@0: JS::RootedValue fun(cx, JS::ObjectValue(*funObj)); michael@0: return Call(cx, thisv, fun, args, rval); michael@0: } michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: /* michael@0: * These functions allow setting an interrupt callback that will be called michael@0: * from the JS thread some time after any thread triggered the callback using michael@0: * JS_RequestInterruptCallback(rt). michael@0: * michael@0: * To schedule the GC and for other activities the engine internally triggers michael@0: * interrupt callbacks. The embedding should thus not rely on callbacks being michael@0: * triggered through the external API only. michael@0: * michael@0: * Important note: Additional callbacks can occur inside the callback handler michael@0: * if it re-enters the JS engine. The embedding must ensure that the callback michael@0: * is disconnected before attempting such re-entry. michael@0: */ michael@0: extern JS_PUBLIC_API(JSInterruptCallback) michael@0: JS_SetInterruptCallback(JSRuntime *rt, JSInterruptCallback callback); michael@0: michael@0: extern JS_PUBLIC_API(JSInterruptCallback) michael@0: JS_GetInterruptCallback(JSRuntime *rt); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_RequestInterruptCallback(JSRuntime *rt); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsRunning(JSContext *cx); michael@0: michael@0: /* michael@0: * Saving and restoring frame chains. michael@0: * michael@0: * These two functions are used to set aside cx's call stack while that stack michael@0: * is inactive. After a call to JS_SaveFrameChain, it looks as if there is no michael@0: * code running on cx. Before calling JS_RestoreFrameChain, cx's call stack michael@0: * must be balanced and all nested calls to JS_SaveFrameChain must have had michael@0: * matching JS_RestoreFrameChain calls. michael@0: * michael@0: * JS_SaveFrameChain deals with cx not having any code running on it. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SaveFrameChain(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_RestoreFrameChain(JSContext *cx); michael@0: michael@0: #ifdef MOZ_TRACE_JSCALLS michael@0: /* michael@0: * The callback is expected to be quick and noninvasive. It should not michael@0: * request interrupts, turn on debugging, or produce uncaught JS michael@0: * exceptions. The state of the stack and registers in the context michael@0: * cannot be relied upon, since this callback may be invoked directly michael@0: * from either JIT. The 'entering' field means we are entering a michael@0: * function if it is positive, leaving a function if it is zero or michael@0: * negative. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb); michael@0: michael@0: extern JS_PUBLIC_API(JSFunctionCallback) michael@0: JS_GetFunctionCallback(JSContext *cx); michael@0: #endif /* MOZ_TRACE_JSCALLS */ michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * Strings. michael@0: * michael@0: * NB: JS_NewUCString takes ownership of bytes on success, avoiding a copy; michael@0: * but on error (signified by null return), it leaves chars owned by the michael@0: * caller. So the caller must free bytes in the error case, if it has no use michael@0: * for them. In contrast, all the JS_New*StringCopy* functions do not take michael@0: * ownership of the character memory passed to them -- they copy it. michael@0: */ michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_NewStringCopyN(JSContext *cx, const char *s, size_t n); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_NewStringCopyZ(JSContext *cx, const char *s); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_InternJSString(JSContext *cx, JS::HandleString str); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_InternStringN(JSContext *cx, const char *s, size_t length); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_InternString(JSContext *cx, const char *s); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_NewUCString(JSContext *cx, jschar *chars, size_t length); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_NewUCStringCopyZ(JSContext *cx, const jschar *s); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_InternUCString(JSContext *cx, const jschar *s); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, bool *match); michael@0: michael@0: extern JS_PUBLIC_API(size_t) michael@0: JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_FileEscapedString(FILE *fp, JSString *str, char quote); michael@0: michael@0: /* michael@0: * Extracting string characters and length. michael@0: * michael@0: * While getting the length of a string is infallible, getting the chars can michael@0: * fail. As indicated by the lack of a JSContext parameter, there are two michael@0: * special cases where getting the chars is infallible: michael@0: * michael@0: * The first case is interned strings, i.e., strings from JS_InternString or michael@0: * JSID_TO_STRING(id), using JS_GetInternedStringChars*. michael@0: * michael@0: * The second case is "flat" strings that have been explicitly prepared in a michael@0: * fallible context by JS_FlattenString. To catch errors, a separate opaque michael@0: * JSFlatString type is returned by JS_FlattenString and expected by michael@0: * JS_GetFlatStringChars. Note, though, that this is purely a syntactic michael@0: * distinction: the input and output of JS_FlattenString are the same actual michael@0: * GC-thing so only one needs to be rooted. If a JSString is known to be flat, michael@0: * JS_ASSERT_STRING_IS_FLAT can be used to make a debug-checked cast. Example: michael@0: * michael@0: * // in a fallible context michael@0: * JSFlatString *fstr = JS_FlattenString(cx, str); michael@0: * if (!fstr) michael@0: * return false; michael@0: * JS_ASSERT(fstr == JS_ASSERT_STRING_IS_FLAT(str)); michael@0: * michael@0: * // in an infallible context, for the same 'str' michael@0: * const jschar *chars = JS_GetFlatStringChars(fstr) michael@0: * JS_ASSERT(chars); michael@0: * michael@0: * The CharsZ APIs guarantee that the returned array has a null character at michael@0: * chars[length]. This can require additional copying so clients should prefer michael@0: * APIs without CharsZ if possible. The infallible functions also return michael@0: * null-terminated arrays. (There is no additional cost or non-Z alternative michael@0: * for the infallible functions, so 'Z' is left out of the identifier.) michael@0: */ michael@0: michael@0: extern JS_PUBLIC_API(size_t) michael@0: JS_GetStringLength(JSString *str); michael@0: michael@0: extern JS_PUBLIC_API(const jschar *) michael@0: JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *length); michael@0: michael@0: extern JS_PUBLIC_API(const jschar *) michael@0: JS_GetInternedStringChars(JSString *str); michael@0: michael@0: extern JS_PUBLIC_API(const jschar *) michael@0: JS_GetInternedStringCharsAndLength(JSString *str, size_t *length); michael@0: michael@0: extern JS_PUBLIC_API(const jschar *) michael@0: JS_GetStringCharsZ(JSContext *cx, JSString *str); michael@0: michael@0: extern JS_PUBLIC_API(const jschar *) michael@0: JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *length); michael@0: michael@0: extern JS_PUBLIC_API(JSFlatString *) michael@0: JS_FlattenString(JSContext *cx, JSString *str); michael@0: michael@0: extern JS_PUBLIC_API(const jschar *) michael@0: JS_GetFlatStringChars(JSFlatString *str); michael@0: michael@0: static MOZ_ALWAYS_INLINE JSFlatString * michael@0: JSID_TO_FLAT_STRING(jsid id) michael@0: { michael@0: JS_ASSERT(JSID_IS_STRING(id)); michael@0: return (JSFlatString *)(JSID_BITS(id)); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE JSFlatString * michael@0: JS_ASSERT_STRING_IS_FLAT(JSString *str) michael@0: { michael@0: JS_ASSERT(JS_GetFlatStringChars((JSFlatString *)str)); michael@0: return (JSFlatString *)str; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE JSString * michael@0: JS_FORGET_STRING_FLATNESS(JSFlatString *fstr) michael@0: { michael@0: return (JSString *)fstr; michael@0: } michael@0: michael@0: /* michael@0: * Additional APIs that avoid fallibility when given a flat string. michael@0: */ michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes); michael@0: michael@0: extern JS_PUBLIC_API(size_t) michael@0: JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote); michael@0: michael@0: /* michael@0: * Create a dependent string, i.e., a string that owns no character storage, michael@0: * but that refers to a slice of another string's chars. Dependent strings michael@0: * are mutable by definition, so the thread safety comments above apply. michael@0: */ michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_NewDependentString(JSContext *cx, JS::HandleString str, size_t start, michael@0: size_t length); michael@0: michael@0: /* michael@0: * Concatenate two strings, possibly resulting in a rope. michael@0: * See above for thread safety comments. michael@0: */ michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_ConcatStrings(JSContext *cx, JS::HandleString left, JS::HandleString right); michael@0: michael@0: /* michael@0: * For JS_DecodeBytes, set *dstlenp to the size of the destination buffer before michael@0: * the call; on return, *dstlenp contains the number of jschars actually stored. michael@0: * To determine the necessary destination buffer size, make a sizing call that michael@0: * passes nullptr for dst. michael@0: * michael@0: * On errors, the functions report the error. In that case, *dstlenp contains michael@0: * the number of characters or bytes transferred so far. If cx is nullptr, no michael@0: * error is reported on failure, and the functions simply return false. michael@0: * michael@0: * NB: This function does not store an additional zero byte or jschar after the michael@0: * transcoded string. michael@0: */ michael@0: JS_PUBLIC_API(bool) michael@0: JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, michael@0: size_t *dstlenp); michael@0: michael@0: /* michael@0: * A variation on JS_EncodeCharacters where a null terminated string is michael@0: * returned that you are expected to call JS_free on when done. michael@0: */ michael@0: JS_PUBLIC_API(char *) michael@0: JS_EncodeString(JSContext *cx, JSString *str); michael@0: michael@0: /* michael@0: * Same behavior as JS_EncodeString(), but encode into UTF-8 string michael@0: */ michael@0: JS_PUBLIC_API(char *) michael@0: JS_EncodeStringToUTF8(JSContext *cx, JS::HandleString str); michael@0: michael@0: /* michael@0: * Get number of bytes in the string encoding (without accounting for a michael@0: * terminating zero bytes. The function returns (size_t) -1 if the string michael@0: * can not be encoded into bytes and reports an error using cx accordingly. michael@0: */ michael@0: JS_PUBLIC_API(size_t) michael@0: JS_GetStringEncodingLength(JSContext *cx, JSString *str); michael@0: michael@0: /* michael@0: * Encode string into a buffer. The function does not stores an additional michael@0: * zero byte. The function returns (size_t) -1 if the string can not be michael@0: * encoded into bytes with no error reported. Otherwise it returns the number michael@0: * of bytes that are necessary to encode the string. If that exceeds the michael@0: * length parameter, the string will be cut and only length bytes will be michael@0: * written into the buffer. michael@0: */ michael@0: JS_PUBLIC_API(size_t) michael@0: JS_EncodeStringToBuffer(JSContext *cx, JSString *str, char *buffer, size_t length); michael@0: michael@0: class JSAutoByteString michael@0: { michael@0: public: michael@0: JSAutoByteString(JSContext *cx, JSString *str michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : mBytes(JS_EncodeString(cx, str)) michael@0: { michael@0: JS_ASSERT(cx); michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: JSAutoByteString(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) michael@0: : mBytes(nullptr) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: ~JSAutoByteString() { michael@0: js_free(mBytes); michael@0: } michael@0: michael@0: /* Take ownership of the given byte array. */ michael@0: void initBytes(char *bytes) { michael@0: JS_ASSERT(!mBytes); michael@0: mBytes = bytes; michael@0: } michael@0: michael@0: char *encodeLatin1(JSContext *cx, JSString *str) { michael@0: JS_ASSERT(!mBytes); michael@0: JS_ASSERT(cx); michael@0: mBytes = JS_EncodeString(cx, str); michael@0: return mBytes; michael@0: } michael@0: michael@0: char *encodeLatin1(js::ExclusiveContext *cx, JSString *str); michael@0: michael@0: char *encodeUtf8(JSContext *cx, JS::HandleString str) { michael@0: JS_ASSERT(!mBytes); michael@0: JS_ASSERT(cx); michael@0: mBytes = JS_EncodeStringToUTF8(cx, str); michael@0: return mBytes; michael@0: } michael@0: michael@0: void clear() { michael@0: js_free(mBytes); michael@0: mBytes = nullptr; michael@0: } michael@0: michael@0: char *ptr() const { michael@0: return mBytes; michael@0: } michael@0: michael@0: bool operator!() const { michael@0: return !mBytes; michael@0: } michael@0: michael@0: size_t length() const { michael@0: if (!mBytes) michael@0: return 0; michael@0: return strlen(mBytes); michael@0: } michael@0: michael@0: private: michael@0: char *mBytes; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: michael@0: /* Copy and assignment are not supported. */ michael@0: JSAutoByteString(const JSAutoByteString &another); michael@0: JSAutoByteString &operator=(const JSAutoByteString &another); michael@0: }; michael@0: michael@0: /************************************************************************/ michael@0: /* michael@0: * JSON functions michael@0: */ michael@0: typedef bool (* JSONWriteCallback)(const jschar *buf, uint32_t len, void *data); michael@0: michael@0: /* michael@0: * JSON.stringify as specified by ES5. michael@0: */ michael@0: JS_PUBLIC_API(bool) michael@0: JS_Stringify(JSContext *cx, JS::MutableHandleValue value, JS::HandleObject replacer, michael@0: JS::HandleValue space, JSONWriteCallback callback, void *data); michael@0: michael@0: /* michael@0: * JSON.parse as specified by ES5. michael@0: */ michael@0: JS_PUBLIC_API(bool) michael@0: JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, JS::MutableHandleValue vp); michael@0: michael@0: JS_PUBLIC_API(bool) michael@0: JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, JS::HandleValue reviver, michael@0: JS::MutableHandleValue vp); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * The default locale for the ECMAScript Internationalization API michael@0: * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat). michael@0: * Note that the Internationalization API encourages clients to michael@0: * specify their own locales. michael@0: * The locale string remains owned by the caller. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_SetDefaultLocale(JSRuntime *rt, const char *locale); michael@0: michael@0: /* michael@0: * Returns the default locale for the ECMAScript Internationalization API michael@0: * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat). michael@0: * Note that the Internationalization API encourages clients to michael@0: * specify their own locales. michael@0: */ michael@0: extern JS_PUBLIC_API(const char*) michael@0: JS_GetDefaultLocale(JSRuntime *rt); michael@0: michael@0: /* michael@0: * Reset the default locale to OS defaults. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ResetDefaultLocale(JSRuntime *rt); michael@0: michael@0: /* michael@0: * Locale specific string conversion and error message callbacks. michael@0: */ michael@0: struct JSLocaleCallbacks { michael@0: JSLocaleToUpperCase localeToUpperCase; michael@0: JSLocaleToLowerCase localeToLowerCase; michael@0: JSLocaleCompare localeCompare; // not used #if EXPOSE_INTL_API michael@0: JSLocaleToUnicode localeToUnicode; michael@0: JSErrorCallback localeGetErrorMessage; michael@0: }; michael@0: michael@0: /* michael@0: * Establish locale callbacks. The pointer must persist as long as the michael@0: * JSRuntime. Passing nullptr restores the default behaviour. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetLocaleCallbacks(JSRuntime *rt, JSLocaleCallbacks *callbacks); michael@0: michael@0: /* michael@0: * Return the address of the current locale callbacks struct, which may michael@0: * be nullptr. michael@0: */ michael@0: extern JS_PUBLIC_API(JSLocaleCallbacks *) michael@0: JS_GetLocaleCallbacks(JSRuntime *rt); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * Error reporting. michael@0: */ michael@0: michael@0: /* michael@0: * Report an exception represented by the sprintf-like conversion of format michael@0: * and its arguments. This exception message string is passed to a pre-set michael@0: * JSErrorReporter function (set by JS_SetErrorReporter). michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ReportError(JSContext *cx, const char *format, ...); michael@0: michael@0: /* michael@0: * Use an errorNumber to retrieve the format string, args are char * michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback, michael@0: void *userRef, const unsigned errorNumber, ...); michael@0: michael@0: #ifdef va_start michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ReportErrorNumberVA(JSContext *cx, JSErrorCallback errorCallback, michael@0: void *userRef, const unsigned errorNumber, va_list ap); michael@0: #endif michael@0: michael@0: /* michael@0: * Use an errorNumber to retrieve the format string, args are jschar * michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback, michael@0: void *userRef, const unsigned errorNumber, ...); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ReportErrorNumberUCArray(JSContext *cx, JSErrorCallback errorCallback, michael@0: void *userRef, const unsigned errorNumber, michael@0: const jschar **args); michael@0: michael@0: /* michael@0: * As above, but report a warning instead (JSREPORT_IS_WARNING(report.flags)). michael@0: * Return true if there was no error trying to issue the warning, and if the michael@0: * warning was not converted into an error due to the JSOPTION_WERROR option michael@0: * being set, false otherwise. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ReportWarning(JSContext *cx, const char *format, ...); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ReportErrorFlagsAndNumber(JSContext *cx, unsigned flags, michael@0: JSErrorCallback errorCallback, void *userRef, michael@0: const unsigned errorNumber, ...); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ReportErrorFlagsAndNumberUC(JSContext *cx, unsigned flags, michael@0: JSErrorCallback errorCallback, void *userRef, michael@0: const unsigned errorNumber, ...); michael@0: michael@0: /* michael@0: * Complain when out of memory. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ReportOutOfMemory(JSContext *cx); michael@0: michael@0: /* michael@0: * Complain when an allocation size overflows the maximum supported limit. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ReportAllocationOverflow(JSContext *cx); michael@0: michael@0: struct JSErrorReport { michael@0: const char *filename; /* source file name, URL, etc., or null */ michael@0: JSPrincipals *originPrincipals; /* see 'originPrincipals' comment above */ michael@0: unsigned lineno; /* source line number */ michael@0: const char *linebuf; /* offending source line without final \n */ michael@0: const char *tokenptr; /* pointer to error token in linebuf */ michael@0: const jschar *uclinebuf; /* unicode (original) line buffer */ michael@0: const jschar *uctokenptr; /* unicode (original) token pointer */ michael@0: unsigned flags; /* error/warning, etc. */ michael@0: unsigned errorNumber; /* the error number, e.g. see js.msg */ michael@0: const jschar *ucmessage; /* the (default) error message */ michael@0: const jschar **messageArgs; /* arguments for the error message */ michael@0: int16_t exnType; /* One of the JSExnType constants */ michael@0: unsigned column; /* zero-based column index in line */ michael@0: }; michael@0: michael@0: /* michael@0: * JSErrorReport flag values. These may be freely composed. michael@0: */ michael@0: #define JSREPORT_ERROR 0x0 /* pseudo-flag for default case */ michael@0: #define JSREPORT_WARNING 0x1 /* reported via JS_ReportWarning */ michael@0: #define JSREPORT_EXCEPTION 0x2 /* exception was thrown */ michael@0: #define JSREPORT_STRICT 0x4 /* error or warning due to strict option */ michael@0: michael@0: /* michael@0: * This condition is an error in strict mode code, a warning if michael@0: * JS_HAS_STRICT_OPTION(cx), and otherwise should not be reported at michael@0: * all. We check the strictness of the context's top frame's script; michael@0: * where that isn't appropriate, the caller should do the right checks michael@0: * itself instead of using this flag. michael@0: */ michael@0: #define JSREPORT_STRICT_MODE_ERROR 0x8 michael@0: michael@0: /* michael@0: * If JSREPORT_EXCEPTION is set, then a JavaScript-catchable exception michael@0: * has been thrown for this runtime error, and the host should ignore it. michael@0: * Exception-aware hosts should also check for JS_IsExceptionPending if michael@0: * JS_ExecuteScript returns failure, and signal or propagate the exception, as michael@0: * appropriate. michael@0: */ michael@0: #define JSREPORT_IS_WARNING(flags) (((flags) & JSREPORT_WARNING) != 0) michael@0: #define JSREPORT_IS_EXCEPTION(flags) (((flags) & JSREPORT_EXCEPTION) != 0) michael@0: #define JSREPORT_IS_STRICT(flags) (((flags) & JSREPORT_STRICT) != 0) michael@0: #define JSREPORT_IS_STRICT_MODE_ERROR(flags) (((flags) & \ michael@0: JSREPORT_STRICT_MODE_ERROR) != 0) michael@0: extern JS_PUBLIC_API(JSErrorReporter) michael@0: JS_GetErrorReporter(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(JSErrorReporter) michael@0: JS_SetErrorReporter(JSContext *cx, JSErrorReporter er); michael@0: michael@0: namespace JS { michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: CreateTypeError(JSContext *cx, HandleString stack, HandleString fileName, michael@0: uint32_t lineNumber, uint32_t columnNumber, JSErrorReport *report, michael@0: HandleString message, MutableHandleValue rval); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * Weak Maps. michael@0: */ michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: NewWeakMapObject(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: IsWeakMapObject(JSObject *obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: GetWeakMapEntry(JSContext *cx, JS::HandleObject mapObj, JS::HandleObject key, michael@0: JS::MutableHandleValue val); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: SetWeakMapEntry(JSContext *cx, JS::HandleObject mapObj, JS::HandleObject key, michael@0: JS::HandleValue val); michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: /* michael@0: * Dates. michael@0: */ michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewDateObjectMsec(JSContext *cx, double msec); michael@0: michael@0: /* michael@0: * Infallible predicate to test whether obj is a date object. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ObjectIsDate(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: /* michael@0: * Clears the cache of calculated local time from each Date object. michael@0: * Call to propagate a system timezone change. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ClearDateCaches(JSContext *cx); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * Regular Expressions. michael@0: */ michael@0: #define JSREG_FOLD 0x01 /* fold uppercase to lowercase */ michael@0: #define JSREG_GLOB 0x02 /* global exec, creates array of matches */ michael@0: #define JSREG_MULTILINE 0x04 /* treat ^ and $ as begin and end of line */ michael@0: #define JSREG_STICKY 0x08 /* only match starting at lastIndex */ michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewRegExpObject(JSContext *cx, JS::HandleObject obj, char *bytes, size_t length, michael@0: unsigned flags); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewUCRegExpObject(JSContext *cx, JS::HandleObject obj, jschar *chars, size_t length, michael@0: unsigned flags); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetRegExpInput(JSContext *cx, JS::HandleObject obj, JS::HandleString input, michael@0: bool multiline); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ClearRegExpStatics(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ExecuteRegExp(JSContext *cx, JS::HandleObject obj, JS::HandleObject reobj, michael@0: jschar *chars, size_t length, size_t *indexp, bool test, michael@0: JS::MutableHandleValue rval); michael@0: michael@0: /* RegExp interface for clients without a global object. */ michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, unsigned flags); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, unsigned flags); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ExecuteRegExpNoStatics(JSContext *cx, JS::HandleObject reobj, jschar *chars, size_t length, michael@0: size_t *indexp, bool test, JS::MutableHandleValue rval); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ObjectIsRegExp(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_PUBLIC_API(unsigned) michael@0: JS_GetRegExpFlags(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_PUBLIC_API(JSString *) michael@0: JS_GetRegExpSource(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsExceptionPending(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_GetPendingException(JSContext *cx, JS::MutableHandleValue vp); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetPendingException(JSContext *cx, JS::HandleValue v); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ClearPendingException(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ReportPendingException(JSContext *cx); michael@0: michael@0: namespace JS { michael@0: michael@0: /* michael@0: * Save and later restore the current exception state of a given JSContext. michael@0: * This is useful for implementing behavior in C++ that's like try/catch michael@0: * or try/finally in JS. michael@0: * michael@0: * Typical usage: michael@0: * michael@0: * bool ok = JS_EvaluateScript(cx, ...); michael@0: * AutoSaveExceptionState savedExc(cx); michael@0: * ... cleanup that might re-enter JS ... michael@0: * return ok; michael@0: */ michael@0: class JS_PUBLIC_API(AutoSaveExceptionState) michael@0: { michael@0: private: michael@0: JSContext *context; michael@0: bool wasThrowing; michael@0: RootedValue exceptionValue; michael@0: michael@0: public: michael@0: /* michael@0: * Take a snapshot of cx's current exception state. Then clear any current michael@0: * pending exception in cx. michael@0: */ michael@0: explicit AutoSaveExceptionState(JSContext *cx); michael@0: michael@0: /* michael@0: * If neither drop() nor restore() was called, restore the exception michael@0: * state only if no exception is currently pending on cx. michael@0: */ michael@0: ~AutoSaveExceptionState(); michael@0: michael@0: /* michael@0: * Discard any stored exception state. michael@0: * If this is called, the destructor is a no-op. michael@0: */ michael@0: void drop() { michael@0: wasThrowing = false; michael@0: exceptionValue.setUndefined(); michael@0: } michael@0: michael@0: /* michael@0: * Replace cx's exception state with the stored exception state. Then michael@0: * discard the stored exception state. If this is called, the michael@0: * destructor is a no-op. michael@0: */ michael@0: void restore(); michael@0: }; michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: /* Deprecated API. Use AutoSaveExceptionState instead. */ michael@0: extern JS_PUBLIC_API(JSExceptionState *) michael@0: JS_SaveExceptionState(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_DropExceptionState(JSContext *cx, JSExceptionState *state); michael@0: michael@0: /* michael@0: * If the given object is an exception object, the exception will have (or be michael@0: * able to lazily create) an error report struct, and this function will return michael@0: * the address of that struct. Otherwise, it returns nullptr. The lifetime michael@0: * of the error report struct that might be returned is the same as the michael@0: * lifetime of the exception object. michael@0: */ michael@0: extern JS_PUBLIC_API(JSErrorReport *) michael@0: JS_ErrorFromException(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: /* michael@0: * Throws a StopIteration exception on cx. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_ThrowStopIteration(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsStopIteration(jsval v); michael@0: michael@0: extern JS_PUBLIC_API(intptr_t) michael@0: JS_GetCurrentThread(); michael@0: michael@0: /* michael@0: * A JS runtime always has an "owner thread". The owner thread is set when the michael@0: * runtime is created (to the current thread) and practically all entry points michael@0: * into the JS engine check that a runtime (or anything contained in the michael@0: * runtime: context, compartment, object, etc) is only touched by its owner michael@0: * thread. Embeddings may check this invariant outside the JS engine by calling michael@0: * JS_AbortIfWrongThread (which will abort if not on the owner thread, even for michael@0: * non-debug builds). michael@0: */ michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_AbortIfWrongThread(JSRuntime *rt); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: /* michael@0: * A constructor can request that the JS engine create a default new 'this' michael@0: * object of the given class, using the callee to determine parentage and michael@0: * [[Prototype]]. michael@0: */ michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_NewObjectForConstructor(JSContext *cx, const JSClass *clasp, const JS::CallArgs& args); michael@0: michael@0: /************************************************************************/ michael@0: michael@0: #ifdef JS_GC_ZEAL michael@0: #define JS_DEFAULT_ZEAL_FREQ 100 michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_ScheduleGC(JSContext *cx, uint32_t count); michael@0: #endif michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetParallelParsingEnabled(JSRuntime *rt, bool enabled); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetParallelIonCompilationEnabled(JSRuntime *rt, bool enabled); michael@0: michael@0: #define JIT_COMPILER_OPTIONS(Register) \ michael@0: Register(BASELINE_USECOUNT_TRIGGER, "baseline.usecount.trigger") \ michael@0: Register(ION_USECOUNT_TRIGGER, "ion.usecount.trigger") \ michael@0: Register(ION_ENABLE, "ion.enable") \ michael@0: Register(BASELINE_ENABLE, "baseline.enable") \ michael@0: Register(PARALLEL_COMPILATION_ENABLE, "parallel-compilation.enable") michael@0: michael@0: typedef enum JSJitCompilerOption { michael@0: #define JIT_COMPILER_DECLARE(key, str) \ michael@0: JSJITCOMPILER_ ## key, michael@0: michael@0: JIT_COMPILER_OPTIONS(JIT_COMPILER_DECLARE) michael@0: #undef JIT_COMPILER_DECLARE michael@0: michael@0: JSJITCOMPILER_NOT_AN_OPTION michael@0: } JSJitCompilerOption; michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: JS_SetGlobalJitCompilerOption(JSRuntime *rt, JSJitCompilerOption opt, uint32_t value); michael@0: extern JS_PUBLIC_API(int) michael@0: JS_GetGlobalJitCompilerOption(JSRuntime *rt, JSJitCompilerOption opt); michael@0: michael@0: /* michael@0: * Convert a uint32_t index into a jsid. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IndexToId(JSContext *cx, uint32_t index, JS::MutableHandleId); michael@0: michael@0: /* michael@0: * Convert chars into a jsid. michael@0: * michael@0: * |chars| may not be an index. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, JS::MutableHandleId); michael@0: michael@0: /* michael@0: * Test if the given string is a valid ECMAScript identifier michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: JS_IsIdentifier(JSContext *cx, JS::HandleString str, bool *isIdentifier); michael@0: michael@0: namespace JS { michael@0: michael@0: /* michael@0: * AutoFilename encapsulates a pointer to a C-string and keeps the C-string michael@0: * alive for as long as the associated AutoFilename object is alive. michael@0: */ michael@0: class MOZ_STACK_CLASS JS_PUBLIC_API(AutoFilename) michael@0: { michael@0: void *scriptSource_; michael@0: michael@0: AutoFilename(const AutoFilename &) MOZ_DELETE; michael@0: void operator=(const AutoFilename &) MOZ_DELETE; michael@0: michael@0: public: michael@0: AutoFilename() : scriptSource_(nullptr) {} michael@0: ~AutoFilename() { reset(nullptr); } michael@0: michael@0: const char *get() const; michael@0: michael@0: void reset(void *newScriptSource); michael@0: }; michael@0: michael@0: /* michael@0: * Return the current filename and line number of the most currently running michael@0: * frame. Returns true if a scripted frame was found, false otherwise. michael@0: * michael@0: * If a the embedding has hidden the scripted caller for the topmost activation michael@0: * record, this will also return false. michael@0: */ michael@0: extern JS_PUBLIC_API(bool) michael@0: DescribeScriptedCaller(JSContext *cx, AutoFilename *filename = nullptr, michael@0: unsigned *lineno = nullptr); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: GetScriptedCallerGlobal(JSContext *cx); michael@0: michael@0: /* michael@0: * Informs the JS engine that the scripted caller should be hidden. This can be michael@0: * used by the embedding to maintain an override of the scripted caller in its michael@0: * calculations, by hiding the scripted caller in the JS engine and pushing data michael@0: * onto a separate stack, which it inspects when DescribeScriptedCaller returns michael@0: * null. michael@0: * michael@0: * We maintain a counter on each activation record. Add() increments the counter michael@0: * of the topmost activation, and Remove() decrements it. The count may never michael@0: * drop below zero, and must always be exactly zero when the activation is michael@0: * popped from the stack. michael@0: */ michael@0: extern JS_PUBLIC_API(void) michael@0: HideScriptedCaller(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: UnhideScriptedCaller(JSContext *cx); michael@0: michael@0: class AutoHideScriptedCaller michael@0: { michael@0: public: michael@0: AutoHideScriptedCaller(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : mContext(cx) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: HideScriptedCaller(mContext); michael@0: } michael@0: ~AutoHideScriptedCaller() { michael@0: UnhideScriptedCaller(mContext); michael@0: } michael@0: michael@0: protected: michael@0: JSContext *mContext; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: /* michael@0: * Encode/Decode interpreted scripts and functions to/from memory. michael@0: */ michael@0: michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_EncodeScript(JSContext *cx, JS::HandleScript script, uint32_t *lengthp); michael@0: michael@0: extern JS_PUBLIC_API(void *) michael@0: JS_EncodeInterpretedFunction(JSContext *cx, JS::HandleObject funobj, uint32_t *lengthp); michael@0: michael@0: extern JS_PUBLIC_API(JSScript *) michael@0: JS_DecodeScript(JSContext *cx, const void *data, uint32_t length, JSPrincipals *originPrincipals); michael@0: michael@0: extern JS_PUBLIC_API(JSObject *) michael@0: JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length, michael@0: JSPrincipals *originPrincipals); michael@0: michael@0: namespace JS { michael@0: michael@0: /* michael@0: * This callback represents a request by the JS engine to open for reading the michael@0: * existing cache entry for the given global and char range that may contain a michael@0: * module. If a cache entry exists, the callback shall return 'true' and return michael@0: * the size, base address and an opaque file handle as outparams. If the michael@0: * callback returns 'true', the JS engine guarantees a call to michael@0: * CloseAsmJSCacheEntryForReadOp, passing the same base address, size and michael@0: * handle. michael@0: */ michael@0: typedef bool michael@0: (* OpenAsmJSCacheEntryForReadOp)(HandleObject global, const jschar *begin, const jschar *limit, michael@0: size_t *size, const uint8_t **memory, intptr_t *handle); michael@0: typedef void michael@0: (* CloseAsmJSCacheEntryForReadOp)(HandleObject global, size_t size, const uint8_t *memory, michael@0: intptr_t handle); michael@0: michael@0: /* michael@0: * This callback represents a request by the JS engine to open for writing a michael@0: * cache entry of the given size for the given global and char range containing michael@0: * the just-compiled module. If cache entry space is available, the callback michael@0: * shall return 'true' and return the base address and an opaque file handle as michael@0: * outparams. If the callback returns 'true', the JS engine guarantees a call michael@0: * to CloseAsmJSCacheEntryForWriteOp passing the same base address, size and michael@0: * handle. michael@0: * michael@0: * If 'installed' is true, then the cache entry is associated with a permanently michael@0: * installed JS file (e.g., in a packaged webapp). This information allows the michael@0: * embedding to store the cache entry in a installed location associated with michael@0: * the principal of 'global' where it will not be evicted until the associated michael@0: * installed JS file is removed. michael@0: */ michael@0: typedef bool michael@0: (* OpenAsmJSCacheEntryForWriteOp)(HandleObject global, bool installed, michael@0: const jschar *begin, const jschar *end, michael@0: size_t size, uint8_t **memory, intptr_t *handle); michael@0: typedef void michael@0: (* CloseAsmJSCacheEntryForWriteOp)(HandleObject global, size_t size, uint8_t *memory, michael@0: intptr_t handle); michael@0: michael@0: typedef js::Vector BuildIdCharVector; michael@0: michael@0: // Return the buildId (represented as a sequence of characters) associated with michael@0: // the currently-executing build. If the JS engine is embedded such that a michael@0: // single cache entry can be observed by different compiled versions of the JS michael@0: // engine, it is critical that the buildId shall change for each new build of michael@0: // the JS engine. michael@0: michael@0: typedef bool michael@0: (* BuildIdOp)(BuildIdCharVector *buildId); michael@0: michael@0: struct AsmJSCacheOps michael@0: { michael@0: OpenAsmJSCacheEntryForReadOp openEntryForRead; michael@0: CloseAsmJSCacheEntryForReadOp closeEntryForRead; michael@0: OpenAsmJSCacheEntryForWriteOp openEntryForWrite; michael@0: CloseAsmJSCacheEntryForWriteOp closeEntryForWrite; michael@0: BuildIdOp buildId; michael@0: }; michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: SetAsmJSCacheOps(JSRuntime *rt, const AsmJSCacheOps *callbacks); michael@0: michael@0: /* michael@0: * Convenience class for imitating a JS level for-of loop. Typical usage: michael@0: * michael@0: * ForOfIterator it(cx); michael@0: * if (!it.init(iterable)) michael@0: * return false; michael@0: * RootedValue val(cx); michael@0: * while (true) { michael@0: * bool done; michael@0: * if (!it.next(&val, &done)) michael@0: * return false; michael@0: * if (done) michael@0: * break; michael@0: * if (!DoStuff(cx, val)) michael@0: * return false; michael@0: * } michael@0: */ michael@0: class MOZ_STACK_CLASS JS_PUBLIC_API(ForOfIterator) { michael@0: protected: michael@0: JSContext *cx_; michael@0: /* michael@0: * Use the ForOfPIC on the global object (see vm/GlobalObject.h) to try michael@0: * to optimize iteration across arrays. michael@0: * michael@0: * Case 1: Regular Iteration michael@0: * iterator - pointer to the iterator object. michael@0: * index - fixed to NOT_ARRAY (== UINT32_MAX) michael@0: * michael@0: * Case 2: Optimized Array Iteration michael@0: * iterator - pointer to the array object. michael@0: * index - current position in array. michael@0: * michael@0: * The cases are distinguished by whether or not |index| is equal to NOT_ARRAY. michael@0: */ michael@0: JS::RootedObject iterator; michael@0: uint32_t index; michael@0: michael@0: static const uint32_t NOT_ARRAY = UINT32_MAX; michael@0: michael@0: ForOfIterator(const ForOfIterator &) MOZ_DELETE; michael@0: ForOfIterator &operator=(const ForOfIterator &) MOZ_DELETE; michael@0: michael@0: public: michael@0: ForOfIterator(JSContext *cx) : cx_(cx), iterator(cx_), index(NOT_ARRAY) { } michael@0: michael@0: enum NonIterableBehavior { michael@0: ThrowOnNonIterable, michael@0: AllowNonIterable michael@0: }; michael@0: michael@0: /* michael@0: * Initialize the iterator. If AllowNonIterable is passed then if iterable michael@0: * does not have a callable @@iterator init() will just return true instead michael@0: * of throwing. Callers should then check valueIsIterable() before michael@0: * continuing with the iteration. michael@0: */ michael@0: bool init(JS::HandleValue iterable, michael@0: NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable); michael@0: michael@0: /* michael@0: * Get the next value from the iterator. If false *done is true michael@0: * after this call, do not examine val. michael@0: */ michael@0: bool next(JS::MutableHandleValue val, bool *done); michael@0: michael@0: /* michael@0: * If initialized with throwOnNonCallable = false, check whether michael@0: * the value is iterable. michael@0: */ michael@0: bool valueIsIterable() const { michael@0: return iterator; michael@0: } michael@0: michael@0: private: michael@0: inline bool nextFromOptimizedArray(MutableHandleValue val, bool *done); michael@0: bool materializeArrayIterator(); michael@0: }; michael@0: michael@0: michael@0: /* michael@0: * If a large allocation fails, the JS engine may call the large-allocation- michael@0: * failure callback, if set, to allow the embedding to flush caches, possibly michael@0: * perform shrinking GCs, etc. to make some room so that the allocation will michael@0: * succeed if retried. After the callback returns, the JS engine will try to michael@0: * allocate again and may be succesful. michael@0: */ michael@0: michael@0: typedef void michael@0: (* LargeAllocationFailureCallback)(); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: SetLargeAllocationFailureCallback(JSRuntime *rt, LargeAllocationFailureCallback afc); michael@0: michael@0: /* michael@0: * Unlike the error reporter, which is only called if the exception for an OOM michael@0: * bubbles up and is not caught, the OutOfMemoryCallback is called immediately michael@0: * at the OOM site to allow the embedding to capture the current state of heap michael@0: * allocation before anything is freed. If the large-allocation-failure callback michael@0: * is called at all (not all allocation sites call the large-allocation-failure michael@0: * callback on failure), it is called before the out-of-memory callback; the michael@0: * out-of-memory callback is only called if the allocation still fails after the michael@0: * large-allocation-failure callback has returned. michael@0: */ michael@0: michael@0: typedef void michael@0: (* OutOfMemoryCallback)(JSContext *cx); michael@0: michael@0: extern JS_PUBLIC_API(void) michael@0: SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb); michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: #endif /* jsapi_h */