JavaScriptCore/runtime/ScopeChain.h
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/JavaScriptCore/runtime/ScopeChain.h	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,242 @@
+/*
+ *  Copyright (C) 2003, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this library; see the file COPYING.LIB.  If not, write to
+ *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ScopeChain_h
+#define ScopeChain_h
+
+#include "FastAllocBase.h"
+
+namespace JSC {
+
+    class JSGlobalData;
+    class JSGlobalObject;
+    class JSObject;
+    class MarkStack;
+    class ScopeChainIterator;
+    
+    class ScopeChainNode : public FastAllocBase {
+    public:
+        ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
+            : next(next)
+            , object(object)
+            , globalData(globalData)
+            , globalObject(globalObject)
+            , globalThis(globalThis)
+            , refCount(1)
+        {
+            ASSERT(globalData);
+            ASSERT(globalObject);
+        }
+#ifndef NDEBUG
+        // Due to the number of subtle and timing dependent bugs that have occurred due
+        // to deleted but still "valid" ScopeChainNodes we now deliberately clobber the
+        // contents in debug builds.
+        ~ScopeChainNode()
+        {
+            next = 0;
+            object = 0;
+            globalData = 0;
+            globalObject = 0;
+            globalThis = 0;
+        }
+#endif
+
+        ScopeChainNode* next;
+        JSObject* object;
+        JSGlobalData* globalData;
+        JSGlobalObject* globalObject;
+        JSObject* globalThis;
+        int refCount;
+
+        void deref() { ASSERT(refCount); if (--refCount == 0) { release();} }
+        void ref() { ASSERT(refCount); ++refCount; }
+        void release();
+
+        // Before calling "push" on a bare ScopeChainNode, a client should
+        // logically "copy" the node. Later, the client can "deref" the head
+        // of its chain of ScopeChainNodes to reclaim all the nodes it added
+        // after the logical copy, leaving nodes added before the logical copy
+        // (nodes shared with other clients) untouched.
+        ScopeChainNode* copy()
+        {
+            ref();
+            return this;
+        }
+
+        ScopeChainNode* push(JSObject*);
+        ScopeChainNode* pop();
+
+        ScopeChainIterator begin() const;
+        ScopeChainIterator end() const;
+
+#ifndef NDEBUG        
+        void print() const;
+#endif
+    };
+
+    inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
+    {
+        ASSERT(o);
+        return new ScopeChainNode(this, o, globalData, globalObject, globalThis);
+    }
+
+    inline ScopeChainNode* ScopeChainNode::pop()
+    {
+        ASSERT(next);
+        ScopeChainNode* result = next;
+
+        if (--refCount != 0)
+            ++result->refCount;
+        else
+            delete this;
+
+        return result;
+    }
+
+    inline void ScopeChainNode::release()
+    {
+        // This function is only called by deref(),
+        // Deref ensures these conditions are true.
+        ASSERT(refCount == 0);
+        ScopeChainNode* n = this;
+        do {
+            ScopeChainNode* next = n->next;
+            delete n;
+            n = next;
+        } while (n && --n->refCount == 0);
+    }
+
+    class ScopeChainIterator {
+    public:
+        ScopeChainIterator(const ScopeChainNode* node)
+            : m_node(node)
+        {
+        }
+
+        JSObject* const & operator*() const { return m_node->object; }
+        JSObject* const * operator->() const { return &(operator*()); }
+    
+        ScopeChainIterator& operator++() { m_node = m_node->next; return *this; }
+
+        // postfix ++ intentionally omitted
+
+        bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; }
+        bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; }
+
+    private:
+        const ScopeChainNode* m_node;
+    };
+
+    inline ScopeChainIterator ScopeChainNode::begin() const
+    {
+        return ScopeChainIterator(this); 
+    }
+
+    inline ScopeChainIterator ScopeChainNode::end() const
+    { 
+        return ScopeChainIterator(0); 
+    }
+
+    class NoScopeChain {};
+
+    class ScopeChain {
+        friend class JIT;
+    public:
+        ScopeChain(NoScopeChain)
+            : m_node(0)
+        {
+        }
+
+        ScopeChain(JSObject* o, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
+            : m_node(new ScopeChainNode(0, o, globalData, globalObject, globalThis))
+        {
+        }
+
+        ScopeChain(const ScopeChain& c)
+            : m_node(c.m_node->copy())
+        {
+        }
+
+        ScopeChain& operator=(const ScopeChain& c);
+
+        explicit ScopeChain(ScopeChainNode* node)
+            : m_node(node->copy())
+        {
+        }
+
+        ~ScopeChain()
+        {
+            if (m_node)
+                m_node->deref();
+#ifndef NDEBUG
+            m_node = 0;
+#endif
+        }
+
+        void swap(ScopeChain&);
+
+        ScopeChainNode* node() const { return m_node; }
+
+        JSObject* top() const { return m_node->object; }
+
+        ScopeChainIterator begin() const { return m_node->begin(); }
+        ScopeChainIterator end() const { return m_node->end(); }
+
+        void push(JSObject* o) { m_node = m_node->push(o); }
+
+        void pop() { m_node = m_node->pop(); }
+        void clear() { m_node->deref(); m_node = 0; }
+        
+        JSGlobalObject* globalObject() const { return m_node->globalObject; }
+
+        void markAggregate(MarkStack&) const;
+
+        // Caution: this should only be used if the codeblock this is being used
+        // with needs a full scope chain, otherwise this returns the depth of
+        // the preceeding call frame
+        //
+        // Returns the depth of the current call frame's scope chain
+        int localDepth() const;
+
+#ifndef NDEBUG        
+        void print() const { m_node->print(); }
+#endif
+
+    private:
+        ScopeChainNode* m_node;
+    };
+
+    inline void ScopeChain::swap(ScopeChain& o)
+    {
+        ScopeChainNode* tmp = m_node;
+        m_node = o.m_node;
+        o.m_node = tmp;
+    }
+
+    inline ScopeChain& ScopeChain::operator=(const ScopeChain& c)
+    {
+        ScopeChain tmp(c);
+        swap(tmp);
+        return *this;
+    }
+
+} // namespace JSC
+
+#endif // ScopeChain_h