|
1 |
|
2 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
3 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
4 * This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #ifndef vm_SavedStacks_h |
|
9 #define vm_SavedStacks_h |
|
10 |
|
11 #include "jscntxt.h" |
|
12 #include "js/HashTable.h" |
|
13 #include "vm/Stack.h" |
|
14 |
|
15 namespace js { |
|
16 |
|
17 class SavedFrame : public JSObject { |
|
18 friend class SavedStacks; |
|
19 |
|
20 public: |
|
21 static const Class class_; |
|
22 static void finalize(FreeOp *fop, JSObject *obj); |
|
23 |
|
24 // Prototype methods and properties to be exposed to JS. |
|
25 static const JSPropertySpec properties[]; |
|
26 static const JSFunctionSpec methods[]; |
|
27 static bool construct(JSContext *cx, unsigned argc, Value *vp); |
|
28 static bool sourceProperty(JSContext *cx, unsigned argc, Value *vp); |
|
29 static bool lineProperty(JSContext *cx, unsigned argc, Value *vp); |
|
30 static bool columnProperty(JSContext *cx, unsigned argc, Value *vp); |
|
31 static bool functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp); |
|
32 static bool parentProperty(JSContext *cx, unsigned argc, Value *vp); |
|
33 static bool toStringMethod(JSContext *cx, unsigned argc, Value *vp); |
|
34 |
|
35 // Convenient getters for SavedFrame's reserved slots for use from C++. |
|
36 JSAtom *getSource(); |
|
37 size_t getLine(); |
|
38 size_t getColumn(); |
|
39 JSAtom *getFunctionDisplayName(); |
|
40 SavedFrame *getParent(); |
|
41 JSPrincipals *getPrincipals(); |
|
42 |
|
43 bool isSelfHosted(); |
|
44 |
|
45 struct Lookup; |
|
46 struct HashPolicy; |
|
47 |
|
48 typedef HashSet<SavedFrame *, |
|
49 HashPolicy, |
|
50 SystemAllocPolicy> Set; |
|
51 |
|
52 private: |
|
53 void initFromLookup(Lookup &lookup); |
|
54 |
|
55 enum { |
|
56 // The reserved slots in the SavedFrame class. |
|
57 JSSLOT_SOURCE, |
|
58 JSSLOT_LINE, |
|
59 JSSLOT_COLUMN, |
|
60 JSSLOT_FUNCTIONDISPLAYNAME, |
|
61 JSSLOT_PARENT, |
|
62 JSSLOT_PRINCIPALS, |
|
63 JSSLOT_PRIVATE_PARENT, |
|
64 |
|
65 // The total number of reserved slots in the SavedFrame class. |
|
66 JSSLOT_COUNT |
|
67 }; |
|
68 |
|
69 // Because we hash the parent pointer, we need to rekey a saved frame |
|
70 // whenever its parent was relocated by the GC. However, the GC doesn't |
|
71 // notify us when this occurs. As a work around, we keep a duplicate copy of |
|
72 // the parent pointer as a private value in a reserved slot. Whenever the |
|
73 // private value parent pointer doesn't match the regular parent pointer, we |
|
74 // know that GC moved the parent and we need to update our private value and |
|
75 // rekey the saved frame in its hash set. These two methods are helpers for |
|
76 // this process. |
|
77 bool parentMoved(); |
|
78 void updatePrivateParent(); |
|
79 |
|
80 static SavedFrame *checkThis(JSContext *cx, CallArgs &args, const char *fnName); |
|
81 }; |
|
82 |
|
83 struct SavedFrame::Lookup { |
|
84 Lookup(JSAtom *source, size_t line, size_t column, JSAtom *functionDisplayName, |
|
85 Handle<SavedFrame*> parent, JSPrincipals *principals) |
|
86 : source(source), |
|
87 line(line), |
|
88 column(column), |
|
89 functionDisplayName(functionDisplayName), |
|
90 parent(parent), |
|
91 principals(principals) |
|
92 { |
|
93 JS_ASSERT(source); |
|
94 } |
|
95 |
|
96 JSAtom *source; |
|
97 size_t line; |
|
98 size_t column; |
|
99 JSAtom *functionDisplayName; |
|
100 Handle<SavedFrame*> parent; |
|
101 JSPrincipals *principals; |
|
102 }; |
|
103 |
|
104 struct SavedFrame::HashPolicy |
|
105 { |
|
106 typedef SavedFrame::Lookup Lookup; |
|
107 typedef PointerHasher<SavedFrame *, 3> SavedFramePtrHasher; |
|
108 typedef PointerHasher<JSPrincipals *, 3> JSPrincipalsPtrHasher; |
|
109 |
|
110 static HashNumber hash(const Lookup &lookup); |
|
111 static bool match(SavedFrame *existing, const Lookup &lookup); |
|
112 |
|
113 typedef SavedFrame* Key; |
|
114 static void rekey(Key &key, const Key &newKey); |
|
115 }; |
|
116 |
|
117 class SavedStacks { |
|
118 public: |
|
119 SavedStacks() : frames(), savedFrameProto(nullptr) { } |
|
120 |
|
121 bool init(); |
|
122 bool initialized() const { return frames.initialized(); } |
|
123 bool saveCurrentStack(JSContext *cx, MutableHandle<SavedFrame*> frame); |
|
124 void sweep(JSRuntime *rt); |
|
125 uint32_t count(); |
|
126 void clear(); |
|
127 |
|
128 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); |
|
129 |
|
130 private: |
|
131 SavedFrame::Set frames; |
|
132 JSObject *savedFrameProto; |
|
133 |
|
134 bool insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandle<SavedFrame*> frame); |
|
135 SavedFrame *getOrCreateSavedFrame(JSContext *cx, SavedFrame::Lookup &lookup); |
|
136 // |SavedFrame.prototype| is created lazily and held weakly. It should only |
|
137 // be accessed through this method. |
|
138 JSObject *getOrCreateSavedFramePrototype(JSContext *cx); |
|
139 SavedFrame *createFrameFromLookup(JSContext *cx, SavedFrame::Lookup &lookup); |
|
140 }; |
|
141 |
|
142 } /* namespace js */ |
|
143 |
|
144 #endif /* vm_SavedStacks_h */ |