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:
ScopeChainNode(ScopeChainNode * next,JSObject * object,JSGlobalData * globalData,JSGlobalObject * globalObject,JSObject * globalThis)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.
~ScopeChainNode()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 
deref()68         void deref() { ASSERT(refCount); if (--refCount == 0) { release();} }
ref()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.
copy()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 
push(JSObject * o)94     inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
95     {
96         ASSERT(o);
97         return new ScopeChainNode(this, o, globalData, globalObject, globalThis);
98     }
99 
pop()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 
release()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:
ScopeChainIterator(const ScopeChainNode * node)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 
begin()147     inline ScopeChainIterator ScopeChainNode::begin() const
148     {
149         return ScopeChainIterator(this);
150     }
151 
end()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:
ScopeChain(NoScopeChain)162         ScopeChain(NoScopeChain)
163             : m_node(0)
164         {
165         }
166 
ScopeChain(JSObject * o,JSGlobalData * globalData,JSGlobalObject * globalObject,JSObject * globalThis)167         ScopeChain(JSObject* o, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
168             : m_node(new ScopeChainNode(0, o, globalData, globalObject, globalThis))
169         {
170         }
171 
ScopeChain(const ScopeChain & c)172         ScopeChain(const ScopeChain& c)
173             : m_node(c.m_node->copy())
174         {
175         }
176 
177         ScopeChain& operator=(const ScopeChain& c);
178 
ScopeChain(ScopeChainNode * node)179         explicit ScopeChain(ScopeChainNode* node)
180             : m_node(node->copy())
181         {
182         }
183 
~ScopeChain()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 
node()195         ScopeChainNode* node() const { return m_node; }
196 
top()197         JSObject* top() const { return m_node->object; }
198 
begin()199         ScopeChainIterator begin() const { return m_node->begin(); }
end()200         ScopeChainIterator end() const { return m_node->end(); }
201 
push(JSObject * o)202         void push(JSObject* o) { m_node = m_node->push(o); }
203 
pop()204         void pop() { m_node = m_node->pop(); }
clear()205         void clear() { m_node->deref(); m_node = 0; }
206 
globalObject()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
print()219         void print() const { m_node->print(); }
220 #endif
221 
222     private:
223         ScopeChainNode* m_node;
224     };
225 
swap(ScopeChain & o)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
243