| 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(o&: tmp); | 
| 237 |         return *this; | 
| 238 |     } | 
| 239 |  | 
| 240 | } // namespace JSC | 
| 241 |  | 
| 242 | #endif // ScopeChain_h | 
| 243 |  |