michael@0: 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: #ifndef vm_SavedStacks_h michael@0: #define vm_SavedStacks_h michael@0: michael@0: #include "jscntxt.h" michael@0: #include "js/HashTable.h" michael@0: #include "vm/Stack.h" michael@0: michael@0: namespace js { michael@0: michael@0: class SavedFrame : public JSObject { michael@0: friend class SavedStacks; michael@0: michael@0: public: michael@0: static const Class class_; michael@0: static void finalize(FreeOp *fop, JSObject *obj); michael@0: michael@0: // Prototype methods and properties to be exposed to JS. michael@0: static const JSPropertySpec properties[]; michael@0: static const JSFunctionSpec methods[]; michael@0: static bool construct(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool sourceProperty(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool lineProperty(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool columnProperty(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool parentProperty(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool toStringMethod(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: // Convenient getters for SavedFrame's reserved slots for use from C++. michael@0: JSAtom *getSource(); michael@0: size_t getLine(); michael@0: size_t getColumn(); michael@0: JSAtom *getFunctionDisplayName(); michael@0: SavedFrame *getParent(); michael@0: JSPrincipals *getPrincipals(); michael@0: michael@0: bool isSelfHosted(); michael@0: michael@0: struct Lookup; michael@0: struct HashPolicy; michael@0: michael@0: typedef HashSet Set; michael@0: michael@0: private: michael@0: void initFromLookup(Lookup &lookup); michael@0: michael@0: enum { michael@0: // The reserved slots in the SavedFrame class. michael@0: JSSLOT_SOURCE, michael@0: JSSLOT_LINE, michael@0: JSSLOT_COLUMN, michael@0: JSSLOT_FUNCTIONDISPLAYNAME, michael@0: JSSLOT_PARENT, michael@0: JSSLOT_PRINCIPALS, michael@0: JSSLOT_PRIVATE_PARENT, michael@0: michael@0: // The total number of reserved slots in the SavedFrame class. michael@0: JSSLOT_COUNT michael@0: }; michael@0: michael@0: // Because we hash the parent pointer, we need to rekey a saved frame michael@0: // whenever its parent was relocated by the GC. However, the GC doesn't michael@0: // notify us when this occurs. As a work around, we keep a duplicate copy of michael@0: // the parent pointer as a private value in a reserved slot. Whenever the michael@0: // private value parent pointer doesn't match the regular parent pointer, we michael@0: // know that GC moved the parent and we need to update our private value and michael@0: // rekey the saved frame in its hash set. These two methods are helpers for michael@0: // this process. michael@0: bool parentMoved(); michael@0: void updatePrivateParent(); michael@0: michael@0: static SavedFrame *checkThis(JSContext *cx, CallArgs &args, const char *fnName); michael@0: }; michael@0: michael@0: struct SavedFrame::Lookup { michael@0: Lookup(JSAtom *source, size_t line, size_t column, JSAtom *functionDisplayName, michael@0: Handle parent, JSPrincipals *principals) michael@0: : source(source), michael@0: line(line), michael@0: column(column), michael@0: functionDisplayName(functionDisplayName), michael@0: parent(parent), michael@0: principals(principals) michael@0: { michael@0: JS_ASSERT(source); michael@0: } michael@0: michael@0: JSAtom *source; michael@0: size_t line; michael@0: size_t column; michael@0: JSAtom *functionDisplayName; michael@0: Handle parent; michael@0: JSPrincipals *principals; michael@0: }; michael@0: michael@0: struct SavedFrame::HashPolicy michael@0: { michael@0: typedef SavedFrame::Lookup Lookup; michael@0: typedef PointerHasher SavedFramePtrHasher; michael@0: typedef PointerHasher JSPrincipalsPtrHasher; michael@0: michael@0: static HashNumber hash(const Lookup &lookup); michael@0: static bool match(SavedFrame *existing, const Lookup &lookup); michael@0: michael@0: typedef SavedFrame* Key; michael@0: static void rekey(Key &key, const Key &newKey); michael@0: }; michael@0: michael@0: class SavedStacks { michael@0: public: michael@0: SavedStacks() : frames(), savedFrameProto(nullptr) { } michael@0: michael@0: bool init(); michael@0: bool initialized() const { return frames.initialized(); } michael@0: bool saveCurrentStack(JSContext *cx, MutableHandle frame); michael@0: void sweep(JSRuntime *rt); michael@0: uint32_t count(); michael@0: void clear(); michael@0: michael@0: size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); michael@0: michael@0: private: michael@0: SavedFrame::Set frames; michael@0: JSObject *savedFrameProto; michael@0: michael@0: bool insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandle frame); michael@0: SavedFrame *getOrCreateSavedFrame(JSContext *cx, SavedFrame::Lookup &lookup); michael@0: // |SavedFrame.prototype| is created lazily and held weakly. It should only michael@0: // be accessed through this method. michael@0: JSObject *getOrCreateSavedFramePrototype(JSContext *cx); michael@0: SavedFrame *createFrameFromLookup(JSContext *cx, SavedFrame::Lookup &lookup); michael@0: }; michael@0: michael@0: } /* namespace js */ michael@0: michael@0: #endif /* vm_SavedStacks_h */