• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (C) 2003, 2008 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 <wtf/Assertions.h>
25 
26 namespace JSC {
27 
28     class JSGlobalData;
29     class JSGlobalObject;
30     class JSObject;
31     class ScopeChainIterator;
32 
33     class ScopeChainNode {
34     public:
ScopeChainNode(ScopeChainNode * next,JSObject * object,JSGlobalData * globalData,JSObject * globalThis)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 
45         ScopeChainNode* next;
46         JSObject* object;
47         JSGlobalData* globalData;
48         JSObject* globalThis;
49         int refCount;
50 
deref()51         void deref() { ASSERT(refCount); if (--refCount == 0) { release();} }
ref()52         void ref() { ASSERT(refCount); ++refCount; }
53         void release();
54 
55         // Before calling "push" on a bare ScopeChainNode, a client should
56         // logically "copy" the node. Later, the client can "deref" the head
57         // of its chain of ScopeChainNodes to reclaim all the nodes it added
58         // after the logical copy, leaving nodes added before the logical copy
59         // (nodes shared with other clients) untouched.
copy()60         ScopeChainNode* copy()
61         {
62             ref();
63             return this;
64         }
65 
66         ScopeChainNode* push(JSObject*);
67         ScopeChainNode* pop();
68 
69         ScopeChainIterator begin() const;
70         ScopeChainIterator end() const;
71 
72         JSGlobalObject* globalObject() const; // defined in JSGlobalObject.h
globalThisObject()73         JSObject* globalThisObject() const { return globalThis; }
74 
75 #ifndef NDEBUG
76         void print() const;
77 #endif
78     };
79 
push(JSObject * o)80     inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
81     {
82         ASSERT(o);
83         return new ScopeChainNode(this, o, globalData, globalThis);
84     }
85 
pop()86     inline ScopeChainNode* ScopeChainNode::pop()
87     {
88         ASSERT(next);
89         ScopeChainNode* result = next;
90 
91         if (--refCount != 0)
92             ++result->refCount;
93         else
94             delete this;
95 
96         return result;
97     }
98 
release()99     inline void ScopeChainNode::release()
100     {
101         // This function is only called by deref(),
102         // Deref ensures these conditions are true.
103         ASSERT(refCount == 0);
104         ScopeChainNode* n = this;
105         do {
106             ScopeChainNode* next = n->next;
107             delete n;
108             n = next;
109         } while (n && --n->refCount == 0);
110     }
111 
112     class ScopeChainIterator {
113     public:
ScopeChainIterator(const ScopeChainNode * node)114         ScopeChainIterator(const ScopeChainNode* node)
115             : m_node(node)
116         {
117         }
118 
119         JSObject* const & operator*() const { return m_node->object; }
120         JSObject* const * operator->() const { return &(operator*()); }
121 
122         ScopeChainIterator& operator++() { m_node = m_node->next; return *this; }
123 
124         // postfix ++ intentionally omitted
125 
126         bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; }
127         bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; }
128 
129     private:
130         const ScopeChainNode* m_node;
131     };
132 
begin()133     inline ScopeChainIterator ScopeChainNode::begin() const
134     {
135         return ScopeChainIterator(this);
136     }
137 
end()138     inline ScopeChainIterator ScopeChainNode::end() const
139     {
140         return ScopeChainIterator(0);
141     }
142 
143     class NoScopeChain {};
144 
145     class ScopeChain {
146         friend class JIT;
147     public:
ScopeChain(NoScopeChain)148         ScopeChain(NoScopeChain)
149             : m_node(0)
150         {
151         }
152 
ScopeChain(JSObject * o,JSGlobalData * globalData,JSObject * globalThis)153         ScopeChain(JSObject* o, JSGlobalData* globalData, JSObject* globalThis)
154             : m_node(new ScopeChainNode(0, o, globalData, globalThis))
155         {
156         }
157 
ScopeChain(const ScopeChain & c)158         ScopeChain(const ScopeChain& c)
159             : m_node(c.m_node->copy())
160         {
161         }
162 
163         ScopeChain& operator=(const ScopeChain& c);
164 
ScopeChain(ScopeChainNode * node)165         explicit ScopeChain(ScopeChainNode* node)
166             : m_node(node->copy())
167         {
168         }
169 
~ScopeChain()170         ~ScopeChain()
171         {
172             if (m_node)
173                 m_node->deref();
174         }
175 
176         void swap(ScopeChain&);
177 
node()178         ScopeChainNode* node() const { return m_node; }
179 
top()180         JSObject* top() const { return m_node->object; }
181 
begin()182         ScopeChainIterator begin() const { return m_node->begin(); }
end()183         ScopeChainIterator end() const { return m_node->end(); }
184 
push(JSObject * o)185         void push(JSObject* o) { m_node = m_node->push(o); }
186 
pop()187         void pop() { m_node = m_node->pop(); }
clear()188         void clear() { m_node->deref(); m_node = 0; }
189 
globalObject()190         JSGlobalObject* globalObject() const { return m_node->globalObject(); }
191 
192         void mark() const;
193 
194         // Caution: this should only be used if the codeblock this is being used
195         // with needs a full scope chain, otherwise this returns the depth of
196         // the preceeding call frame
197         //
198         // Returns the depth of the current call frame's scope chain
199         int localDepth() const;
200 
201 #ifndef NDEBUG
print()202         void print() const { m_node->print(); }
203 #endif
204 
205     private:
206         ScopeChainNode* m_node;
207     };
208 
swap(ScopeChain & o)209     inline void ScopeChain::swap(ScopeChain& o)
210     {
211         ScopeChainNode* tmp = m_node;
212         m_node = o.m_node;
213         o.m_node = tmp;
214     }
215 
216     inline ScopeChain& ScopeChain::operator=(const ScopeChain& c)
217     {
218         ScopeChain tmp(c);
219         swap(tmp);
220         return *this;
221     }
222 
223 } // namespace JSC
224 
225 #endif // ScopeChain_h
226