/* -*- 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(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 */