|  | /* | 
|  | *  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 |