Move JavaScriptCore to Source
[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 "FastAllocBase.h"
25
26 namespace JSC {
27
28     class JSGlobalData;
29     class JSGlobalObject;
30     class JSObject;
31     class MarkStack;
32     class ScopeChainIterator;
33     
34     class ScopeChainNode : public FastAllocBase {
35     public:
36         ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
37             : next(next)
38             , object(object)
39             , globalData(globalData)
40             , globalObject(globalObject)
41             , globalThis(globalThis)
42             , refCount(1)
43         {
44             ASSERT(globalData);
45             ASSERT(globalObject);
46         }
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;
56             globalObject = 0;
57             globalThis = 0;
58         }
59 #endif
60
61         ScopeChainNode* next;
62         JSObject* object;
63         JSGlobalData* globalData;
64         JSGlobalObject* globalObject;
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
89 #ifndef NDEBUG        
90         void print() const;
91 #endif
92     };
93
94     inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
95     {
96         ASSERT(o);
97         return new ScopeChainNode(this, o, globalData, globalObject, globalThis);
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
167         ScopeChain(JSObject* o, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
168             : m_node(new ScopeChainNode(0, o, globalData, globalObject, globalThis))
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();
188 #ifndef NDEBUG
189             m_node = 0;
190 #endif
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         
207         JSGlobalObject* globalObject() const { return m_node->globalObject; }
208
209         void markAggregate(MarkStack&) const;
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