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
32namespace KJS {
33
34class JSObject;
35class JSVariableObject;
36class ScopeChainNode;
37
38class KJS_EXPORT ScopeChainLink {
39public:
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.
95class KJS_EXPORT ScopeChainNode {
96public:
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
117class KJS_EXPORT ScopeChainIterator {
118public:
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
130private:
131 ScopeChainLink m_node;
132};
133
134class KJS_EXPORT ScopeChain {
135public:
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
169private:
170 ScopeChainLink m_top;
171};
172
173inline void ScopeChainLink::deref()
174{
175 if (isToScopeChainNode())
176 asScopeChainNode()->deref();
177 ptr = 0;
178}
179
180inline void ScopeChainLink::ref()
181{
182 if (isToScopeChainNode())
183 asScopeChainNode()->ref();
184}
185
186inline ScopeChainIterator ScopeChain::begin() const
187{
188 return ScopeChainIterator(m_top);
189}
190
191inline ScopeChainIterator ScopeChain::end() const
192{
193 ScopeChainLink empty;
194 empty.init();
195 return ScopeChainIterator(empty);
196}
197
198inline 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
207inline 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
215inline 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