source: webkit/trunk/JavaScriptCore/runtime/ScopeChain.h@ 47022

Last change on this file since 47022 was 47022, checked in by [email protected], 16 years ago

Stack overflow crash in JavaScript garbage collector mark pass
https://bugs.webkit.org/show_bug.cgi?id=12216

Reviewed by Gavin Barraclough and Sam Weinig

Make the GC mark phase iterative by using an explicit mark stack.
To do this marking any single object is performed in multiple stages

  • The object is appended to the MarkStack, this sets the marked bit for the object using the new markDirect() function, and then returns
  • When the MarkStack is drain()ed the object is popped off the stack and markChildren(MarkStack&) is called on the object to collect all of its children. drain() then repeats until the stack is empty.

Additionally I renamed a number of methods from 'mark' to 'markAggregate'
in order to make it more clear that marking of those object was not
going to result in an actual recursive mark.

  • Property svn:eol-style set to native
File size: 6.6 KB
Line 
1/*
2 * Copyright (C) 2003, 2008, 2009 Apple Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20
21#ifndef ScopeChain_h
22#define ScopeChain_h
23
24#include "FastAllocBase.h"
25
26namespace JSC {
27
28 class JSGlobalData;
29 class JSGlobalObject;
30 class JSObject;
31 class ScopeChainIterator;
32
33 class ScopeChainNode : public FastAllocBase {
34 public:
35 ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSObject* globalThis)
36 : next(next)
37 , object(object)
38 , globalData(globalData)
39 , globalThis(globalThis)
40 , refCount(1)
41 {
42 ASSERT(globalData);
43 }
44#ifndef NDEBUG
45 // Due to the number of subtle and timing dependent bugs that have occurred due
46 // to deleted but still "valid" ScopeChainNodes we now deliberately clobber the
47 // contents in debug builds.
48 ~ScopeChainNode()
49 {
50 next = 0;
51 object = 0;
52 globalData = 0;
53 globalThis = 0;
54 }
55#endif
56
57 ScopeChainNode* next;
58 JSObject* object;
59 JSGlobalData* globalData;
60 JSObject* globalThis;
61 int refCount;
62
63 void deref() { ASSERT(refCount); if (--refCount == 0) { release();} }
64 void ref() { ASSERT(refCount); ++refCount; }
65 void release();
66
67 // Before calling "push" on a bare ScopeChainNode, a client should
68 // logically "copy" the node. Later, the client can "deref" the head
69 // of its chain of ScopeChainNodes to reclaim all the nodes it added
70 // after the logical copy, leaving nodes added before the logical copy
71 // (nodes shared with other clients) untouched.
72 ScopeChainNode* copy()
73 {
74 ref();
75 return this;
76 }
77
78 ScopeChainNode* push(JSObject*);
79 ScopeChainNode* pop();
80
81 ScopeChainIterator begin() const;
82 ScopeChainIterator end() const;
83
84 JSGlobalObject* globalObject() const; // defined in JSGlobalObject.h
85 JSObject* globalThisObject() const { return globalThis; }
86
87#ifndef NDEBUG
88 void print() const;
89#endif
90 };
91
92 inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
93 {
94 ASSERT(o);
95 return new ScopeChainNode(this, o, globalData, globalThis);
96 }
97
98 inline ScopeChainNode* ScopeChainNode::pop()
99 {
100 ASSERT(next);
101 ScopeChainNode* result = next;
102
103 if (--refCount != 0)
104 ++result->refCount;
105 else
106 delete this;
107
108 return result;
109 }
110
111 inline void ScopeChainNode::release()
112 {
113 // This function is only called by deref(),
114 // Deref ensures these conditions are true.
115 ASSERT(refCount == 0);
116 ScopeChainNode* n = this;
117 do {
118 ScopeChainNode* next = n->next;
119 delete n;
120 n = next;
121 } while (n && --n->refCount == 0);
122 }
123
124 class ScopeChainIterator {
125 public:
126 ScopeChainIterator(const ScopeChainNode* node)
127 : m_node(node)
128 {
129 }
130
131 JSObject* const & operator*() const { return m_node->object; }
132 JSObject* const * operator->() const { return &(operator*()); }
133
134 ScopeChainIterator& operator++() { m_node = m_node->next; return *this; }
135
136 // postfix ++ intentionally omitted
137
138 bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; }
139 bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; }
140
141 private:
142 const ScopeChainNode* m_node;
143 };
144
145 inline ScopeChainIterator ScopeChainNode::begin() const
146 {
147 return ScopeChainIterator(this);
148 }
149
150 inline ScopeChainIterator ScopeChainNode::end() const
151 {
152 return ScopeChainIterator(0);
153 }
154
155 class NoScopeChain {};
156
157 class ScopeChain {
158 friend class JIT;
159 public:
160 ScopeChain(NoScopeChain)
161 : m_node(0)
162 {
163 }
164
165 ScopeChain(JSObject* o, JSGlobalData* globalData, JSObject* globalThis)
166 : m_node(new ScopeChainNode(0, o, globalData, globalThis))
167 {
168 }
169
170 ScopeChain(const ScopeChain& c)
171 : m_node(c.m_node->copy())
172 {
173 }
174
175 ScopeChain& operator=(const ScopeChain& c);
176
177 explicit ScopeChain(ScopeChainNode* node)
178 : m_node(node->copy())
179 {
180 }
181
182 ~ScopeChain()
183 {
184 if (m_node)
185 m_node->deref();
186#ifndef NDEBUG
187 m_node = 0;
188#endif
189 }
190
191 void swap(ScopeChain&);
192
193 ScopeChainNode* node() const { return m_node; }
194
195 JSObject* top() const { return m_node->object; }
196
197 ScopeChainIterator begin() const { return m_node->begin(); }
198 ScopeChainIterator end() const { return m_node->end(); }
199
200 void push(JSObject* o) { m_node = m_node->push(o); }
201
202 void pop() { m_node = m_node->pop(); }
203 void clear() { m_node->deref(); m_node = 0; }
204
205 JSGlobalObject* globalObject() const { return m_node->globalObject(); }
206
207 void markAggregate(MarkStack&) const;
208
209 // Caution: this should only be used if the codeblock this is being used
210 // with needs a full scope chain, otherwise this returns the depth of
211 // the preceeding call frame
212 //
213 // Returns the depth of the current call frame's scope chain
214 int localDepth() const;
215
216#ifndef NDEBUG
217 void print() const { m_node->print(); }
218#endif
219
220 private:
221 ScopeChainNode* m_node;
222 };
223
224 inline void ScopeChain::swap(ScopeChain& o)
225 {
226 ScopeChainNode* tmp = m_node;
227 m_node = o.m_node;
228 o.m_node = tmp;
229 }
230
231 inline ScopeChain& ScopeChain::operator=(const ScopeChain& c)
232 {
233 ScopeChain tmp(c);
234 swap(tmp);
235 return *this;
236 }
237
238} // namespace JSC
239
240#endif // ScopeChain_h
Note: See TracBrowser for help on using the repository browser.