Home | History | Annotate | Download | only in runtime
      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 "FastAllocBase.h"
     25 
     26 namespace JSC {
     27 
     28     class JSGlobalData;
     29     class JSGlobalObject;
     30     class JSObject;
     31     class MarkStack;
     32     class ScopeChainIterator;
     33 
     34     class ScopeChainNode : public FastAllocBase {
     35     public:
     36         ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
     37             : next(next)
     38             , object(object)
     39             , globalData(globalData)
     40             , globalObject(globalObject)
     41             , globalThis(globalThis)
     42             , refCount(1)
     43         {
     44             ASSERT(globalData);
     45             ASSERT(globalObject);
     46         }
     47 #ifndef NDEBUG
     48         // Due to the number of subtle and timing dependent bugs that have occurred due
     49         // to deleted but still "valid" ScopeChainNodes we now deliberately clobber the
     50         // contents in debug builds.
     51         ~ScopeChainNode()
     52         {
     53             next = 0;
     54             object = 0;
     55             globalData = 0;
     56             globalObject = 0;
     57             globalThis = 0;
     58         }
     59 #endif
     60 
     61         ScopeChainNode* next;
     62         JSObject* object;
     63         JSGlobalData* globalData;
     64         JSGlobalObject* globalObject;
     65         JSObject* globalThis;
     66         int refCount;
     67 
     68         void deref() { ASSERT(refCount); if (--refCount == 0) { release();} }
     69         void ref() { ASSERT(refCount); ++refCount; }
     70         void release();
     71 
     72         // Before calling "push" on a bare ScopeChainNode, a client should
     73         // logically "copy" the node. Later, the client can "deref" the head
     74         // of its chain of ScopeChainNodes to reclaim all the nodes it added
     75         // after the logical copy, leaving nodes added before the logical copy
     76         // (nodes shared with other clients) untouched.
     77         ScopeChainNode* copy()
     78         {
     79             ref();
     80             return this;
     81         }
     82 
     83         ScopeChainNode* push(JSObject*);
     84         ScopeChainNode* pop();
     85 
     86         ScopeChainIterator begin() const;
     87         ScopeChainIterator end() const;
     88 
     89 #ifndef NDEBUG
     90         void print() const;
     91 #endif
     92     };
     93 
     94     inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
     95     {
     96         ASSERT(o);
     97         return new ScopeChainNode(this, o, globalData, globalObject, globalThis);
     98     }
     99 
    100     inline ScopeChainNode* ScopeChainNode::pop()
    101     {
    102         ASSERT(next);
    103         ScopeChainNode* result = next;
    104 
    105         if (--refCount != 0)
    106             ++result->refCount;
    107         else
    108             delete this;
    109 
    110         return result;
    111     }
    112 
    113     inline void ScopeChainNode::release()
    114     {
    115         // This function is only called by deref(),
    116         // Deref ensures these conditions are true.
    117         ASSERT(refCount == 0);
    118         ScopeChainNode* n = this;
    119         do {
    120             ScopeChainNode* next = n->next;
    121             delete n;
    122             n = next;
    123         } while (n && --n->refCount == 0);
    124     }
    125 
    126     class ScopeChainIterator {
    127     public:
    128         ScopeChainIterator(const ScopeChainNode* node)
    129             : m_node(node)
    130         {
    131         }
    132 
    133         JSObject* const & operator*() const { return m_node->object; }
    134         JSObject* const * operator->() const { return &(operator*()); }
    135 
    136         ScopeChainIterator& operator++() { m_node = m_node->next; return *this; }
    137 
    138         // postfix ++ intentionally omitted
    139 
    140         bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; }
    141         bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; }
    142 
    143     private:
    144         const ScopeChainNode* m_node;
    145     };
    146 
    147     inline ScopeChainIterator ScopeChainNode::begin() const
    148     {
    149         return ScopeChainIterator(this);
    150     }
    151 
    152     inline ScopeChainIterator ScopeChainNode::end() const
    153     {
    154         return ScopeChainIterator(0);
    155     }
    156 
    157     class NoScopeChain {};
    158 
    159     class ScopeChain {
    160         friend class JIT;
    161     public:
    162         ScopeChain(NoScopeChain)
    163             : m_node(0)
    164         {
    165         }
    166 
    167         ScopeChain(JSObject* o, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
    168             : m_node(new ScopeChainNode(0, o, globalData, globalObject, globalThis))
    169         {
    170         }
    171 
    172         ScopeChain(const ScopeChain& c)
    173             : m_node(c.m_node->copy())
    174         {
    175         }
    176 
    177         ScopeChain& operator=(const ScopeChain& c);
    178 
    179         explicit ScopeChain(ScopeChainNode* node)
    180             : m_node(node->copy())
    181         {
    182         }
    183 
    184         ~ScopeChain()
    185         {
    186             if (m_node)
    187                 m_node->deref();
    188 #ifndef NDEBUG
    189             m_node = 0;
    190 #endif
    191         }
    192 
    193         void swap(ScopeChain&);
    194 
    195         ScopeChainNode* node() const { return m_node; }
    196 
    197         JSObject* top() const { return m_node->object; }
    198 
    199         ScopeChainIterator begin() const { return m_node->begin(); }
    200         ScopeChainIterator end() const { return m_node->end(); }
    201 
    202         void push(JSObject* o) { m_node = m_node->push(o); }
    203 
    204         void pop() { m_node = m_node->pop(); }
    205         void clear() { m_node->deref(); m_node = 0; }
    206 
    207         JSGlobalObject* globalObject() const { return m_node->globalObject; }
    208 
    209         void markAggregate(MarkStack&) const;
    210 
    211         // Caution: this should only be used if the codeblock this is being used
    212         // with needs a full scope chain, otherwise this returns the depth of
    213         // the preceeding call frame
    214         //
    215         // Returns the depth of the current call frame's scope chain
    216         int localDepth() const;
    217 
    218 #ifndef NDEBUG
    219         void print() const { m_node->print(); }
    220 #endif
    221 
    222     private:
    223         ScopeChainNode* m_node;
    224     };
    225 
    226     inline void ScopeChain::swap(ScopeChain& o)
    227     {
    228         ScopeChainNode* tmp = m_node;
    229         m_node = o.m_node;
    230         o.m_node = tmp;
    231     }
    232 
    233     inline ScopeChain& ScopeChain::operator=(const ScopeChain& c)
    234     {
    235         ScopeChain tmp(c);
    236         swap(tmp);
    237         return *this;
    238     }
    239 
    240 } // namespace JSC
    241 
    242 #endif // ScopeChain_h
    243