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