File indexing completed on 2024-05-12 15:43:34
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 2003 Apple Computer, Inc. 0004 * (C) 2008 Maksim Orlovich <maksim@kde.org> 0005 * 0006 * This library is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Library General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Library General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Library General Public License 0017 * along with this library; see the file COPYING.LIB. If not, write to 0018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 * Boston, MA 02110-1301, USA. 0020 * 0021 */ 0022 0023 #ifndef KJS_SCOPE_CHAIN_H 0024 #define KJS_SCOPE_CHAIN_H 0025 0026 #include "global.h" 0027 #if HAVE_STDINT_H 0028 #include <stdint.h> 0029 #endif 0030 #include <assert.h> 0031 0032 namespace KJS 0033 { 0034 0035 class JSObject; 0036 class JSVariableObject; 0037 class ScopeChainNode; 0038 0039 class KJS_EXPORT ScopeChainLink 0040 { 0041 public: 0042 /* This class abstracts a link to a node in a scope chain. The node may be 0043 either a JSVariable, which stores the next pointer in one of its 0044 slots, or a full-blown ScopeChainNode with separate object/next field and a 0045 refcount. 0046 0047 We link to variable object by storing the pointer to them; to ScopeChainNode's by 0048 storing the pointer with lower bit set. 0049 */ 0050 uintptr_t ptr; 0051 0052 // in lieu of constructor, for POD'ness 0053 void init() 0054 { 0055 ptr = 0; 0056 } 0057 0058 void set(ScopeChainNode *node) 0059 { 0060 ptr = reinterpret_cast<uintptr_t>(node) | 1; 0061 } 0062 0063 void set(JSVariableObject *act) 0064 { 0065 ptr = reinterpret_cast<uintptr_t>(act); 0066 } 0067 0068 // these are inline in JSVariableObject.h 0069 JSObject *object() const; 0070 ScopeChainLink next() const; 0071 0072 void deref(); 0073 void ref(); 0074 0075 bool isToScopeChainNode() const 0076 { 0077 return ptr & 1; 0078 } 0079 0080 JSVariableObject *asVariableObject() const 0081 { 0082 assert(!isToScopeChainNode()); 0083 return reinterpret_cast<JSVariableObject *>(ptr); 0084 } 0085 0086 ScopeChainNode *asScopeChainNode() const 0087 { 0088 assert(isToScopeChainNode()); 0089 return reinterpret_cast<ScopeChainNode *>(ptr & ~1); 0090 } 0091 0092 bool operator == (const ScopeChainLink &other) const 0093 { 0094 return other.ptr == ptr; 0095 } 0096 0097 bool operator != (const ScopeChainLink &other) const 0098 { 0099 return other.ptr != ptr; 0100 } 0101 }; 0102 0103 // A ScopeChainNode is used to put things other than JSVariableObject's 0104 // in the scope chain. 0105 class KJS_EXPORT ScopeChainNode 0106 { 0107 public: 0108 ScopeChainNode(ScopeChainLink n, JSObject *o) 0109 : next(n), object(o), refCount(1) 0110 { 0111 // Note: we don't ref the next here, since its reference is 0112 // transferred from top pointer in ScopeChain to us 0113 // We ourselves are ref'd by the refCount(1) 0114 } 0115 0116 ~ScopeChainNode() 0117 { 0118 // ### non-recursive? 0119 next.deref(); 0120 } 0121 0122 ScopeChainLink next; 0123 JSObject *object; 0124 int refCount; 0125 0126 void ref() 0127 { 0128 ++refCount; 0129 } 0130 void deref() 0131 { 0132 --refCount; 0133 if (!refCount) { 0134 delete this; 0135 } 0136 } 0137 }; 0138 0139 class KJS_EXPORT ScopeChainIterator 0140 { 0141 public: 0142 ScopeChainIterator(ScopeChainLink node) : m_node(node) {} 0143 0144 JSObject *operator*() const 0145 { 0146 return m_node.object(); 0147 } 0148 0149 ScopeChainIterator &operator++() 0150 { 0151 m_node = m_node.next(); 0152 return *this; 0153 } 0154 0155 // postfix ++ intentionally omitted 0156 0157 bool operator==(const ScopeChainIterator &other) const 0158 { 0159 return m_node == other.m_node; 0160 } 0161 bool operator!=(const ScopeChainIterator &other) const 0162 { 0163 return m_node != other.m_node; 0164 } 0165 0166 private: 0167 ScopeChainLink m_node; 0168 }; 0169 0170 class KJS_EXPORT ScopeChain 0171 { 0172 public: 0173 ScopeChain() 0174 { 0175 m_top.init(); 0176 } 0177 0178 ~ScopeChain() 0179 { 0180 m_top.deref(); 0181 } 0182 0183 ScopeChain(const ScopeChain &c) : m_top(c.m_top) 0184 { 0185 m_top.ref(); 0186 } 0187 0188 ScopeChain &operator=(const ScopeChain &); 0189 0190 JSObject *top() const 0191 { 0192 return m_top.object(); 0193 } 0194 JSObject *bottom() const; 0195 0196 ScopeChainIterator begin() const; 0197 ScopeChainIterator end() const; 0198 0199 void push(JSObject *obj) 0200 { 0201 m_top.set(new ScopeChainNode(m_top, obj)); 0202 } 0203 0204 // inline def in JSVariableObject.h 0205 void pushVariableObject(JSVariableObject *act); 0206 0207 void pop(); 0208 void mark(); // inline in JSVariableObject.h 0209 0210 #ifndef NDEBUG 0211 void print(); 0212 #endif 0213 0214 private: 0215 ScopeChainLink m_top; 0216 }; 0217 0218 inline void ScopeChainLink::deref() 0219 { 0220 if (isToScopeChainNode()) { 0221 asScopeChainNode()->deref(); 0222 } 0223 ptr = 0; 0224 } 0225 0226 inline void ScopeChainLink::ref() 0227 { 0228 if (isToScopeChainNode()) { 0229 asScopeChainNode()->ref(); 0230 } 0231 } 0232 0233 inline ScopeChainIterator ScopeChain::begin() const 0234 { 0235 return ScopeChainIterator(m_top); 0236 } 0237 0238 inline ScopeChainIterator ScopeChain::end() const 0239 { 0240 ScopeChainLink empty; 0241 empty.init(); 0242 return ScopeChainIterator(empty); 0243 } 0244 0245 inline ScopeChain &ScopeChain::operator=(const ScopeChain &c) 0246 { 0247 ScopeChainLink newTop = c.m_top; 0248 newTop.ref(); 0249 m_top.deref(); 0250 m_top = newTop; 0251 return *this; 0252 } 0253 0254 inline JSObject *ScopeChain::bottom() const 0255 { 0256 ScopeChainLink last; 0257 for (ScopeChainLink n = m_top; n.ptr; n = n.next()) { 0258 last = n; 0259 } 0260 return last.object(); 0261 } 0262 0263 inline void ScopeChain::pop() 0264 { 0265 // ### may need manual CSE, it also thrashes more that needed 0266 ScopeChainLink newTop = m_top.next(); 0267 newTop.ref(); 0268 m_top.deref(); 0269 m_top = newTop; 0270 } 0271 0272 } // namespace KJS 0273 0274 #endif // KJS_SCOPE_CHAIN_H