1 | /* |
2 | * This file is part of the KDE libraries |
3 | * Copyright (C) 2003 Apple Computer, Inc. |
4 | * (C) 2008 Maksim Orlovich <maksim@kde.org> |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Library General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Library General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Library General Public License |
17 | * along with this library; see the file COPYING.LIB. If not, write to |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | * Boston, MA 02110-1301, USA. |
20 | * |
21 | */ |
22 | |
23 | #ifndef KJS_SCOPE_CHAIN_H |
24 | #define KJS_SCOPE_CHAIN_H |
25 | |
26 | #include "global.h" |
27 | #ifdef HAVE_STDINT_H |
28 | #include <stdint.h> |
29 | #endif |
30 | #include <assert.h> |
31 | |
32 | namespace KJS { |
33 | |
34 | class JSObject; |
35 | class JSVariableObject; |
36 | class ScopeChainNode; |
37 | |
38 | class KJS_EXPORT ScopeChainLink { |
39 | public: |
40 | /* This class abstracts a link to a node in a scope chain. The node may be |
41 | either a JSVariable, which stores the next pointer in one of its |
42 | slots, or a full-blown ScopeChainNode with separate object/next field and a |
43 | refcount. |
44 | |
45 | We link to variable object by storing the pointer to them; to ScopeChainNode's by |
46 | storing the pointer with lower bit set. |
47 | */ |
48 | uintptr_t ptr; |
49 | |
50 | // in lieu of constructor, for POD'ness |
51 | void init() { |
52 | ptr = 0; |
53 | } |
54 | |
55 | void set(ScopeChainNode* node) { |
56 | ptr = reinterpret_cast<uintptr_t>(node) | 1; |
57 | } |
58 | |
59 | void set(JSVariableObject* act) { |
60 | ptr = reinterpret_cast<uintptr_t>(act); |
61 | } |
62 | |
63 | // these are inline in JSVariableObject.h |
64 | JSObject* object() const; |
65 | ScopeChainLink next() const; |
66 | |
67 | void deref(); |
68 | void ref(); |
69 | |
70 | bool isToScopeChainNode() const { |
71 | return ptr & 1; |
72 | } |
73 | |
74 | JSVariableObject* asVariableObject() const { |
75 | assert (!isToScopeChainNode()); |
76 | return reinterpret_cast<JSVariableObject*>(ptr); |
77 | } |
78 | |
79 | ScopeChainNode* asScopeChainNode() const { |
80 | assert (isToScopeChainNode()); |
81 | return reinterpret_cast<ScopeChainNode*>(ptr & ~1); |
82 | } |
83 | |
84 | bool operator == (const ScopeChainLink& other) const { |
85 | return other.ptr == ptr; |
86 | } |
87 | |
88 | bool operator != (const ScopeChainLink& other) const { |
89 | return other.ptr != ptr; |
90 | } |
91 | }; |
92 | |
93 | // A ScopeChainNode is used to put things other than JSVariableObject's |
94 | // in the scope chain. |
95 | class KJS_EXPORT ScopeChainNode { |
96 | public: |
97 | ScopeChainNode(ScopeChainLink n, JSObject *o) |
98 | : next(n), object(o), refCount(1) { |
99 | // Note: we don't ref the next here, since its reference is |
100 | // transferred from top pointer in ScopeChain to us |
101 | // We ourselves are ref'd by the refCount(1) |
102 | } |
103 | |
104 | ~ScopeChainNode() { |
105 | // ### non-recursive? |
106 | next.deref(); |
107 | } |
108 | |
109 | ScopeChainLink next; |
110 | JSObject *object; |
111 | int refCount; |
112 | |
113 | void ref() { ++refCount; } |
114 | void deref() { --refCount; if (!refCount) delete this; } |
115 | }; |
116 | |
117 | class KJS_EXPORT ScopeChainIterator { |
118 | public: |
119 | ScopeChainIterator(ScopeChainLink node) : m_node(node) {} |
120 | |
121 | JSObject* operator*() const { return m_node.object(); } |
122 | |
123 | ScopeChainIterator& operator++() { m_node = m_node.next(); return *this; } |
124 | |
125 | // postfix ++ intentionally omitted |
126 | |
127 | bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; } |
128 | bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; } |
129 | |
130 | private: |
131 | ScopeChainLink m_node; |
132 | }; |
133 | |
134 | class KJS_EXPORT ScopeChain { |
135 | public: |
136 | ScopeChain() { |
137 | m_top.init(); |
138 | } |
139 | |
140 | ~ScopeChain() { |
141 | m_top.deref(); |
142 | } |
143 | |
144 | ScopeChain(const ScopeChain &c) : m_top(c.m_top) |
145 | { m_top.ref(); } |
146 | |
147 | ScopeChain &operator=(const ScopeChain &); |
148 | |
149 | JSObject *top() const { return m_top.object(); } |
150 | JSObject *bottom() const; |
151 | |
152 | ScopeChainIterator begin() const; |
153 | ScopeChainIterator end() const; |
154 | |
155 | void push(JSObject* obj) { |
156 | m_top.set(new ScopeChainNode(m_top, obj)); |
157 | } |
158 | |
159 | // inline def in JSVariableObject.h |
160 | void pushVariableObject(JSVariableObject* act); |
161 | |
162 | void pop(); |
163 | void mark(); // inline in JSVariableObject.h |
164 | |
165 | #ifndef NDEBUG |
166 | void print(); |
167 | #endif |
168 | |
169 | private: |
170 | ScopeChainLink m_top; |
171 | }; |
172 | |
173 | inline void ScopeChainLink::deref() |
174 | { |
175 | if (isToScopeChainNode()) |
176 | asScopeChainNode()->deref(); |
177 | ptr = 0; |
178 | } |
179 | |
180 | inline void ScopeChainLink::ref() |
181 | { |
182 | if (isToScopeChainNode()) |
183 | asScopeChainNode()->ref(); |
184 | } |
185 | |
186 | inline ScopeChainIterator ScopeChain::begin() const |
187 | { |
188 | return ScopeChainIterator(m_top); |
189 | } |
190 | |
191 | inline ScopeChainIterator ScopeChain::end() const |
192 | { |
193 | ScopeChainLink empty; |
194 | empty.init(); |
195 | return ScopeChainIterator(empty); |
196 | } |
197 | |
198 | inline ScopeChain &ScopeChain::operator=(const ScopeChain &c) |
199 | { |
200 | ScopeChainLink newTop = c.m_top; |
201 | newTop.ref(); |
202 | m_top.deref(); |
203 | m_top = newTop; |
204 | return *this; |
205 | } |
206 | |
207 | inline JSObject *ScopeChain::bottom() const |
208 | { |
209 | ScopeChainLink last; |
210 | for (ScopeChainLink n = m_top; n.ptr; n = n.next()) |
211 | last = n; |
212 | return last.object(); |
213 | } |
214 | |
215 | inline void ScopeChain::pop() |
216 | { |
217 | // ### may need manual CSE, it also thrashes more that needed |
218 | ScopeChainLink newTop = m_top.next(); |
219 | newTop.ref(); |
220 | m_top.deref(); |
221 | m_top = newTop; |
222 | } |
223 | |
224 | } // namespace KJS |
225 | |
226 | #endif // KJS_SCOPE_CHAIN_H |
227 | // kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; |
228 | |