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