]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/ScopeChain.h
JavaScriptCore-721.26.tar.gz
[apple/javascriptcore.git] / runtime / ScopeChain.h
CommitLineData
9dae56ea 1/*
f9bf01c6 2 * Copyright (C) 2003, 2008, 2009 Apple Inc. All rights reserved.
9dae56ea
A
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
ba379fdc 24#include "FastAllocBase.h"
9dae56ea
A
25
26namespace JSC {
27
28 class JSGlobalData;
29 class JSGlobalObject;
30 class JSObject;
f9bf01c6 31 class MarkStack;
9dae56ea
A
32 class ScopeChainIterator;
33
ba379fdc 34 class ScopeChainNode : public FastAllocBase {
9dae56ea 35 public:
f9bf01c6 36 ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
9dae56ea
A
37 : next(next)
38 , object(object)
39 , globalData(globalData)
f9bf01c6 40 , globalObject(globalObject)
9dae56ea
A
41 , globalThis(globalThis)
42 , refCount(1)
43 {
44 ASSERT(globalData);
f9bf01c6 45 ASSERT(globalObject);
9dae56ea 46 }
ba379fdc
A
47#ifndef NDEBUG
48 // Due to the number of subtle and timing dependent bugs that have occurred due
49 // to deleted but still "valid" ScopeChainNodes we now deliberately clobber the
50 // contents in debug builds.
51 ~ScopeChainNode()
52 {
53 next = 0;
54 object = 0;
55 globalData = 0;
f9bf01c6 56 globalObject = 0;
ba379fdc
A
57 globalThis = 0;
58 }
59#endif
9dae56ea
A
60
61 ScopeChainNode* next;
62 JSObject* object;
63 JSGlobalData* globalData;
f9bf01c6 64 JSGlobalObject* globalObject;
9dae56ea
A
65 JSObject* globalThis;
66 int refCount;
67
68 void deref() { ASSERT(refCount); if (--refCount == 0) { release();} }
69 void ref() { ASSERT(refCount); ++refCount; }
70 void release();
71
72 // Before calling "push" on a bare ScopeChainNode, a client should
73 // logically "copy" the node. Later, the client can "deref" the head
74 // of its chain of ScopeChainNodes to reclaim all the nodes it added
75 // after the logical copy, leaving nodes added before the logical copy
76 // (nodes shared with other clients) untouched.
77 ScopeChainNode* copy()
78 {
79 ref();
80 return this;
81 }
82
83 ScopeChainNode* push(JSObject*);
84 ScopeChainNode* pop();
85
86 ScopeChainIterator begin() const;
87 ScopeChainIterator end() const;
88
9dae56ea
A
89#ifndef NDEBUG
90 void print() const;
91#endif
92 };
93
94 inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
95 {
96 ASSERT(o);
f9bf01c6 97 return new ScopeChainNode(this, o, globalData, globalObject, globalThis);
9dae56ea
A
98 }
99
100 inline ScopeChainNode* ScopeChainNode::pop()
101 {
102 ASSERT(next);
103 ScopeChainNode* result = next;
104
105 if (--refCount != 0)
106 ++result->refCount;
107 else
108 delete this;
109
110 return result;
111 }
112
113 inline void ScopeChainNode::release()
114 {
115 // This function is only called by deref(),
116 // Deref ensures these conditions are true.
117 ASSERT(refCount == 0);
118 ScopeChainNode* n = this;
119 do {
120 ScopeChainNode* next = n->next;
121 delete n;
122 n = next;
123 } while (n && --n->refCount == 0);
124 }
125
126 class ScopeChainIterator {
127 public:
128 ScopeChainIterator(const ScopeChainNode* node)
129 : m_node(node)
130 {
131 }
132
133 JSObject* const & operator*() const { return m_node->object; }
134 JSObject* const * operator->() const { return &(operator*()); }
135
136 ScopeChainIterator& operator++() { m_node = m_node->next; return *this; }
137
138 // postfix ++ intentionally omitted
139
140 bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; }
141 bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; }
142
143 private:
144 const ScopeChainNode* m_node;
145 };
146
147 inline ScopeChainIterator ScopeChainNode::begin() const
148 {
149 return ScopeChainIterator(this);
150 }
151
152 inline ScopeChainIterator ScopeChainNode::end() const
153 {
154 return ScopeChainIterator(0);
155 }
156
157 class NoScopeChain {};
158
159 class ScopeChain {
160 friend class JIT;
161 public:
162 ScopeChain(NoScopeChain)
163 : m_node(0)
164 {
165 }
166
f9bf01c6
A
167 ScopeChain(JSObject* o, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
168 : m_node(new ScopeChainNode(0, o, globalData, globalObject, globalThis))
9dae56ea
A
169 {
170 }
171
172 ScopeChain(const ScopeChain& c)
173 : m_node(c.m_node->copy())
174 {
175 }
176
177 ScopeChain& operator=(const ScopeChain& c);
178
179 explicit ScopeChain(ScopeChainNode* node)
180 : m_node(node->copy())
181 {
182 }
183
184 ~ScopeChain()
185 {
186 if (m_node)
187 m_node->deref();
ba379fdc
A
188#ifndef NDEBUG
189 m_node = 0;
190#endif
9dae56ea
A
191 }
192
193 void swap(ScopeChain&);
194
195 ScopeChainNode* node() const { return m_node; }
196
197 JSObject* top() const { return m_node->object; }
198
199 ScopeChainIterator begin() const { return m_node->begin(); }
200 ScopeChainIterator end() const { return m_node->end(); }
201
202 void push(JSObject* o) { m_node = m_node->push(o); }
203
204 void pop() { m_node = m_node->pop(); }
205 void clear() { m_node->deref(); m_node = 0; }
206
f9bf01c6 207 JSGlobalObject* globalObject() const { return m_node->globalObject; }
9dae56ea 208
f9bf01c6 209 void markAggregate(MarkStack&) const;
9dae56ea
A
210
211 // Caution: this should only be used if the codeblock this is being used
212 // with needs a full scope chain, otherwise this returns the depth of
213 // the preceeding call frame
214 //
215 // Returns the depth of the current call frame's scope chain
216 int localDepth() const;
217
218#ifndef NDEBUG
219 void print() const { m_node->print(); }
220#endif
221
222 private:
223 ScopeChainNode* m_node;
224 };
225
226 inline void ScopeChain::swap(ScopeChain& o)
227 {
228 ScopeChainNode* tmp = m_node;
229 m_node = o.m_node;
230 o.m_node = tmp;
231 }
232
233 inline ScopeChain& ScopeChain::operator=(const ScopeChain& c)
234 {
235 ScopeChain tmp(c);
236 swap(tmp);
237 return *this;
238 }
239
240} // namespace JSC
241
242#endif // ScopeChain_h