diff options
Diffstat (limited to 'js/src/jspubtd.h')
-rw-r--r-- | js/src/jspubtd.h | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h new file mode 100644 index 000000000..309b9d746 --- /dev/null +++ b/js/src/jspubtd.h @@ -0,0 +1,476 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jspubtd_h +#define jspubtd_h + +/* + * JS public API typedefs. + */ + +#include "mozilla/Assertions.h" +#include "mozilla/EnumeratedArray.h" +#include "mozilla/LinkedList.h" +#include "mozilla/PodOperations.h" + +#include "jsprototypes.h" +#include "jstypes.h" + +#include "js/TraceKind.h" +#include "js/TypeDecls.h" + +#if defined(JS_GC_ZEAL) || defined(DEBUG) +# define JSGC_HASH_TABLE_CHECKS +#endif + +namespace JS { + +class AutoIdVector; +class CallArgs; + +template <typename T> +class Rooted; + +class JS_FRIEND_API(CompileOptions); +class JS_FRIEND_API(ReadOnlyCompileOptions); +class JS_FRIEND_API(OwningCompileOptions); +class JS_FRIEND_API(TransitiveCompileOptions); +class JS_PUBLIC_API(CompartmentOptions); + +struct RootingContext; +class Value; +struct Zone; + +namespace shadow { +struct Runtime; +} // namespace shadow + +} // namespace JS + +namespace js { +class RootLists; +} // namespace js + +/* + * Run-time version enumeration. For compile-time version checking, please use + * the JS_HAS_* macros in jsversion.h, or use MOZJS_MAJOR_VERSION, + * MOZJS_MINOR_VERSION, MOZJS_PATCH_VERSION, and MOZJS_ALPHA definitions. + */ +enum JSVersion { + JSVERSION_ECMA_3 = 148, + JSVERSION_1_6 = 160, + JSVERSION_1_7 = 170, + JSVERSION_1_8 = 180, + JSVERSION_ECMA_5 = 185, + JSVERSION_DEFAULT = 0, + JSVERSION_UNKNOWN = -1, + JSVERSION_LATEST = JSVERSION_ECMA_5 +}; + +/* Result of typeof operator enumeration. */ +enum JSType { + JSTYPE_VOID, /* undefined */ + JSTYPE_OBJECT, /* object */ + JSTYPE_FUNCTION, /* function */ + JSTYPE_STRING, /* string */ + JSTYPE_NUMBER, /* number */ + JSTYPE_BOOLEAN, /* boolean */ + JSTYPE_NULL, /* null */ + JSTYPE_SYMBOL, /* symbol */ + JSTYPE_LIMIT +}; + +/* Dense index into cached prototypes and class atoms for standard objects. */ +enum JSProtoKey { +#define PROTOKEY_AND_INITIALIZER(name,code,init,clasp) JSProto_##name = code, + JS_FOR_EACH_PROTOTYPE(PROTOKEY_AND_INITIALIZER) +#undef PROTOKEY_AND_INITIALIZER + JSProto_LIMIT +}; + +/* Struct forward declarations. */ +struct JSClass; +struct JSCompartment; +struct JSCrossCompartmentCall; +class JSErrorReport; +struct JSExceptionState; +struct JSFunctionSpec; +struct JSLocaleCallbacks; +struct JSObjectMap; +struct JSPrincipals; +struct JSPropertyName; +struct JSPropertySpec; +struct JSRuntime; +struct JSSecurityCallbacks; +struct JSStructuredCloneCallbacks; +struct JSStructuredCloneReader; +struct JSStructuredCloneWriter; +class JS_PUBLIC_API(JSTracer); + +class JSFlatString; + +typedef bool (*JSInitCallback)(void); + +template<typename T> struct JSConstScalarSpec; +typedef JSConstScalarSpec<double> JSConstDoubleSpec; +typedef JSConstScalarSpec<int32_t> JSConstIntegerSpec; + +/* + * Generic trace operation that calls JS::TraceEdge on each traceable thing's + * location reachable from data. + */ +typedef void +(* JSTraceDataOp)(JSTracer* trc, void* data); + +namespace js { +namespace gc { +class AutoTraceSession; +class StoreBuffer; +} // namespace gc + +// Whether the current thread is permitted access to any part of the specified +// runtime or zone. +JS_FRIEND_API(bool) +CurrentThreadCanAccessRuntime(const JSRuntime* rt); + +#ifdef DEBUG +JS_FRIEND_API(bool) +CurrentThreadIsPerformingGC(); +#endif + +} // namespace js + +namespace JS { + +class JS_PUBLIC_API(AutoEnterCycleCollection); +class JS_PUBLIC_API(AutoAssertOnBarrier); +struct JS_PUBLIC_API(PropertyDescriptor); + +typedef void (*OffThreadCompileCallback)(void* token, void* callbackData); + +enum class HeapState { + Idle, // doing nothing with the GC heap + Tracing, // tracing the GC heap without collecting, e.g. IterateCompartments() + MajorCollecting, // doing a GC of the major heap + MinorCollecting, // doing a GC of the minor heap (nursery) + CycleCollecting // in the "Unlink" phase of cycle collection +}; + +namespace shadow { + +struct Runtime +{ + private: + JS::HeapState heapState_; + + protected: + void setHeapState(JS::HeapState newState) { + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(asRuntime())); + MOZ_ASSERT(heapState_ != newState); + heapState_ = newState; + } + + JS::HeapState heapState() const { + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(asRuntime()) || + js::CurrentThreadIsPerformingGC()); + return heapState_; + } + + // In some cases, invoking GC barriers (incremental or otherwise) will break + // things. These barriers assert if this flag is set. + bool allowGCBarriers_; + friend class JS::AutoAssertOnBarrier; + + js::gc::StoreBuffer* gcStoreBufferPtr_; + + // The gray bits can become invalid if UnmarkGray overflows the stack. A + // full GC will reset this bit, since it fills in all the gray bits. + bool gcGrayBitsValid_; + + public: + Runtime() + : heapState_(JS::HeapState::Idle) + , allowGCBarriers_(true) + , gcStoreBufferPtr_(nullptr) + , gcGrayBitsValid_(false) + {} + + bool isHeapBusy() const { return heapState() != JS::HeapState::Idle; } + bool isHeapTracing() const { return heapState() == JS::HeapState::Tracing; } + bool isHeapMajorCollecting() const { return heapState() == JS::HeapState::MajorCollecting; } + bool isHeapMinorCollecting() const { return heapState() == JS::HeapState::MinorCollecting; } + bool isHeapCollecting() const { return isHeapMinorCollecting() || isHeapMajorCollecting(); } + bool isCycleCollecting() const { + return heapState() == JS::HeapState::CycleCollecting; + } + + bool allowGCBarriers() const { return allowGCBarriers_; } + + js::gc::StoreBuffer* gcStoreBufferPtr() { return gcStoreBufferPtr_; } + + bool areGCGrayBitsValid() const { return gcGrayBitsValid_; } + void setGCGrayBitsValid(bool valid) { gcGrayBitsValid_ = valid; } + + const JSRuntime* asRuntime() const { + return reinterpret_cast<const JSRuntime*>(this); + } + + static JS::shadow::Runtime* asShadowRuntime(JSRuntime* rt) { + return reinterpret_cast<JS::shadow::Runtime*>(rt); + } + + protected: + void setGCStoreBufferPtr(js::gc::StoreBuffer* storeBuffer) { + gcStoreBufferPtr_ = storeBuffer; + } +}; + +} /* namespace shadow */ + +// Decorates the Unlinking phase of CycleCollection so that accidental use +// of barriered accessors results in assertions instead of leaks. +class MOZ_STACK_CLASS JS_PUBLIC_API(AutoEnterCycleCollection) +{ +#ifdef DEBUG + JSRuntime* runtime; + + public: + explicit AutoEnterCycleCollection(JSContext* cx); + ~AutoEnterCycleCollection(); +#else + public: + explicit AutoEnterCycleCollection(JSContext* cx) {} + ~AutoEnterCycleCollection() {} +#endif +}; + +class JS_PUBLIC_API(AutoGCRooter) +{ + public: + AutoGCRooter(JSContext* cx, ptrdiff_t tag); + AutoGCRooter(JS::RootingContext* cx, ptrdiff_t tag); + + ~AutoGCRooter() { + MOZ_ASSERT(this == *stackTop); + *stackTop = down; + } + + /* Implemented in gc/RootMarking.cpp. */ + inline void trace(JSTracer* trc); + static void traceAll(JSTracer* trc); + static void traceAllWrappers(JSTracer* trc); + + protected: + AutoGCRooter * const down; + + /* + * Discriminates actual subclass of this being used. If non-negative, the + * subclass roots an array of values of the length stored in this field. + * If negative, meaning is indicated by the corresponding value in the enum + * below. Any other negative value indicates some deeper problem such as + * memory corruption. + */ + ptrdiff_t tag_; + + enum { + VALARRAY = -2, /* js::AutoValueArray */ + PARSER = -3, /* js::frontend::Parser */ + VALVECTOR = -10, /* js::AutoValueVector */ + IDVECTOR = -11, /* js::AutoIdVector */ + OBJVECTOR = -14, /* js::AutoObjectVector */ + IONMASM = -19, /* js::jit::MacroAssembler */ + WRAPVECTOR = -20, /* js::AutoWrapperVector */ + WRAPPER = -21, /* js::AutoWrapperRooter */ + CUSTOM = -26 /* js::CustomAutoRooter */ + }; + + static ptrdiff_t GetTag(const Value& value) { return VALVECTOR; } + static ptrdiff_t GetTag(const jsid& id) { return IDVECTOR; } + static ptrdiff_t GetTag(JSObject* obj) { return OBJVECTOR; } + + private: + AutoGCRooter ** const stackTop; + + /* No copy or assignment semantics. */ + AutoGCRooter(AutoGCRooter& ida) = delete; + void operator=(AutoGCRooter& ida) = delete; +}; + +// Our instantiations of Rooted<void*> and PersistentRooted<void*> require an +// instantiation of MapTypeToRootKind. +template <> +struct MapTypeToRootKind<void*> { + static const RootKind kind = RootKind::Traceable; +}; + +} /* namespace JS */ + +namespace js { + +class ExclusiveContext; + +/* + * This list enumerates the different types of conceptual stacks we have in + * SpiderMonkey. In reality, they all share the C stack, but we allow different + * stack limits depending on the type of code running. + */ +enum StackKind +{ + StackForSystemCode, // C++, such as the GC, running on behalf of the VM. + StackForTrustedScript, // Script running with trusted principals. + StackForUntrustedScript, // Script running with untrusted principals. + StackKindCount +}; + +using RootedListHeads = mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit, + JS::Rooted<void*>*>; + +// Abstracts JS rooting mechanisms so they can be shared between the JSContext +// and JSRuntime. +class RootLists +{ + // Stack GC roots for Rooted GC heap pointers. + RootedListHeads stackRoots_; + template <typename T> friend class JS::Rooted; + + // Stack GC roots for AutoFooRooter classes. + JS::AutoGCRooter* autoGCRooters_; + friend class JS::AutoGCRooter; + + // Heap GC roots for PersistentRooted pointers. + mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit, + mozilla::LinkedList<JS::PersistentRooted<void*>>> heapRoots_; + template <typename T> friend class JS::PersistentRooted; + + public: + RootLists() : autoGCRooters_(nullptr) { + for (auto& stackRootPtr : stackRoots_) + stackRootPtr = nullptr; + } + + ~RootLists() { + // The semantics of PersistentRooted containing pointers and tagged + // pointers are somewhat different from those of PersistentRooted + // containing a structure with a trace method. PersistentRooted + // containing pointers are allowed to outlive the owning RootLists, + // whereas those containing a traceable structure are not. + // + // The purpose of this feature is to support lazy initialization of + // global references for the several places in Gecko that do not have + // access to a tighter context, but that still need to refer to GC + // pointers. For such pointers, FinishPersistentRootedChains ensures + // that the contained references are nulled out when the owning + // RootLists dies to prevent UAF errors. + // + // However, for RootKind::Traceable, we do not know the concrete type + // of the held thing, so we simply cannot do this without accruing + // extra overhead and complexity for all users for a case that is + // unlikely to ever be used in practice. For this reason, the following + // assertion disallows usage of PersistentRooted<Traceable> that + // outlives the RootLists. + MOZ_ASSERT(heapRoots_[JS::RootKind::Traceable].isEmpty()); + } + + void traceStackRoots(JSTracer* trc); + void checkNoGCRooters(); + + void tracePersistentRoots(JSTracer* trc); + void finishPersistentRoots(); +}; + +} // namespace js + +namespace JS { + +/* + * JS::RootingContext is a base class of ContextFriendFields and JSContext. + * This class can be used to let code construct a Rooted<> or PersistentRooted<> + * instance, without giving it full access to the JSContext. + */ +struct RootingContext +{ + js::RootLists roots; + +#ifdef DEBUG + // Whether the derived class is a JSContext or an ExclusiveContext. + bool isJSContext; +#endif + + explicit RootingContext(bool isJSContextArg) +#ifdef DEBUG + : isJSContext(isJSContextArg) +#endif + {} + + static RootingContext* get(JSContext* cx) { + return reinterpret_cast<RootingContext*>(cx); + } +}; + +} // namespace JS + +namespace js { + +struct ContextFriendFields : public JS::RootingContext +{ + protected: + /* The current compartment. */ + JSCompartment* compartment_; + + /* The current zone. */ + JS::Zone* zone_; + + public: + /* Limit pointer for checking native stack consumption. */ + uintptr_t nativeStackLimit[js::StackKindCount]; + + explicit ContextFriendFields(bool isJSContext); + + static const ContextFriendFields* get(const JSContext* cx) { + return reinterpret_cast<const ContextFriendFields*>(cx); + } + + static ContextFriendFields* get(JSContext* cx) { + return reinterpret_cast<ContextFriendFields*>(cx); + } + + friend JSCompartment* GetContextCompartment(const JSContext* cx); + friend JS::Zone* GetContextZone(const JSContext* cx); + template <typename T> friend class JS::Rooted; +}; + +/* + * Inlinable accessors for JSContext. + * + * - These must not be available on the more restricted superclasses of + * JSContext, so we can't simply define them on ContextFriendFields. + * + * - They're perfectly ordinary JSContext functionality, so ought to be + * usable without resorting to jsfriendapi.h, and when JSContext is an + * incomplete type. + */ +inline JSCompartment* +GetContextCompartment(const JSContext* cx) +{ + return ContextFriendFields::get(cx)->compartment_; +} + +inline JS::Zone* +GetContextZone(const JSContext* cx) +{ + return ContextFriendFields::get(cx)->zone_; +} + +} /* namespace js */ + +MOZ_BEGIN_EXTERN_C + +// Defined in NSPR prio.h. +typedef struct PRFileDesc PRFileDesc; + +MOZ_END_EXTERN_C + +#endif /* jspubtd_h */ |