ScopeChain.h revision ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb
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 <wtf/FastAllocBase.h>
25
26namespace JSC {
27
28    class JSGlobalData;
29    class JSGlobalObject;
30    class JSObject;
31    class MarkStack;
32    class ScopeChainIterator;
33
34    class ScopeChainNode {
35        WTF_MAKE_FAST_ALLOCATED;
36    public:
37        ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
38            : next(next)
39            , object(object)
40            , globalData(globalData)
41            , globalObject(globalObject)
42            , globalThis(globalThis)
43            , refCount(1)
44        {
45            ASSERT(globalData);
46            ASSERT(globalObject);
47        }
48#ifndef NDEBUG
49        // Due to the number of subtle and timing dependent bugs that have occurred due
50        // to deleted but still "valid" ScopeChainNodes we now deliberately clobber the
51        // contents in debug builds.
52        ~ScopeChainNode()
53        {
54            next = 0;
55            object = 0;
56            globalData = 0;
57            globalObject = 0;
58            globalThis = 0;
59        }
60#endif
61
62        ScopeChainNode* next;
63        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        JSObject* const & operator*() const { return m_node->object; }
135        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; }
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
244