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