summaryrefslogtreecommitdiffstats
path: root/Source/JavaScriptCore/runtime/ScopeChain.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/ScopeChain.h')
-rw-r--r--Source/JavaScriptCore/runtime/ScopeChain.h242
1 files changed, 242 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/runtime/ScopeChain.h b/Source/JavaScriptCore/runtime/ScopeChain.h
new file mode 100644
index 0000000..0b15b67
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ScopeChain.h
@@ -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