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