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 "JSCell.h"
25#include "Structure.h"
26#include <wtf/FastAllocBase.h>
27
28namespace JSC {
29
30    class JSGlobalData;
31    class JSGlobalObject;
32    class JSObject;
33    class MarkStack;
34    class ScopeChainIterator;
35
36    class ScopeChainNode : public JSCell {
37    public:
38        ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
39            : JSCell(*globalData, globalData->scopeChainNodeStructure.get())
40            , globalData(globalData)
41            , next(*globalData, this, next)
42            , object(*globalData, this, object)
43            , globalObject(*globalData, this, globalObject)
44            , globalThis(*globalData, this, globalThis)
45        {
46            ASSERT(globalData);
47            ASSERT(globalObject);
48        }
49
50        JSGlobalData* globalData;
51        WriteBarrier<ScopeChainNode> next;
52        WriteBarrier<JSObject> object;
53        WriteBarrier<JSGlobalObject> globalObject;
54        WriteBarrier<JSObject> globalThis;
55
56        ScopeChainNode* push(JSObject*);
57        ScopeChainNode* pop();
58
59        ScopeChainIterator begin();
60        ScopeChainIterator end();
61
62        int localDepth();
63
64#ifndef NDEBUG
65        void print();
66#endif
67
68        static Structure* createStructure(JSGlobalData& globalData, JSValue proto) { return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info); }
69        virtual void markChildren(MarkStack&);
70    private:
71        static const unsigned StructureFlags = OverridesMarkChildren;
72        static const ClassInfo s_info;
73    };
74
75    inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
76    {
77        ASSERT(o);
78        return new (globalData) ScopeChainNode(this, o, globalData, globalObject.get(), globalThis.get());
79    }
80
81    inline ScopeChainNode* ScopeChainNode::pop()
82    {
83        ASSERT(next);
84        return next.get();
85    }
86
87    class ScopeChainIterator {
88    public:
89        ScopeChainIterator(ScopeChainNode* node)
90            : m_node(node)
91        {
92        }
93
94        WriteBarrier<JSObject> const & operator*() const { return m_node->object; }
95        WriteBarrier<JSObject> const * operator->() const { return &(operator*()); }
96
97        ScopeChainIterator& operator++() { m_node = m_node->next.get(); return *this; }
98
99        // postfix ++ intentionally omitted
100
101        bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; }
102        bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; }
103
104    private:
105        ScopeChainNode* m_node;
106    };
107
108    inline ScopeChainIterator ScopeChainNode::begin()
109    {
110        return ScopeChainIterator(this);
111    }
112
113    inline ScopeChainIterator ScopeChainNode::end()
114    {
115        return ScopeChainIterator(0);
116    }
117
118    ALWAYS_INLINE JSGlobalData& ExecState::globalData() const
119    {
120        ASSERT(scopeChain()->globalData);
121        return *scopeChain()->globalData;
122    }
123
124    ALWAYS_INLINE JSGlobalObject* ExecState::lexicalGlobalObject() const
125    {
126        return scopeChain()->globalObject.get();
127    }
128
129    ALWAYS_INLINE JSObject* ExecState::globalThisValue() const
130    {
131        return scopeChain()->globalThis.get();
132    }
133
134    ALWAYS_INLINE ScopeChainNode* Register::scopeChain() const
135    {
136        return static_cast<ScopeChainNode*>(jsValue().asCell());
137    }
138
139    ALWAYS_INLINE Register& Register::operator=(ScopeChainNode* scopeChain)
140    {
141        *this = JSValue(scopeChain);
142        return *this;
143    }
144
145} // namespace JSC
146
147#endif // ScopeChain_h
148