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: ScopeChainNode(ScopeChainNode * next,JSObject * object,JSGlobalData * globalData,JSGlobalObject * globalObject,JSObject * globalThis)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. ~ScopeChainNode()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 deref()68 void deref() { ASSERT(refCount); if (--refCount == 0) { release();} } ref()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. copy()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 push(JSObject * o)94 inline ScopeChainNode* ScopeChainNode::push(JSObject* o) 95 { 96 ASSERT(o); 97 return new ScopeChainNode(this, o, globalData, globalObject, globalThis); 98 } 99 pop()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 release()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: ScopeChainIterator(const ScopeChainNode * node)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 begin()147 inline ScopeChainIterator ScopeChainNode::begin() const 148 { 149 return ScopeChainIterator(this); 150 } 151 end()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: ScopeChain(NoScopeChain)162 ScopeChain(NoScopeChain) 163 : m_node(0) 164 { 165 } 166 ScopeChain(JSObject * o,JSGlobalData * globalData,JSGlobalObject * globalObject,JSObject * globalThis)167 ScopeChain(JSObject* o, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis) 168 : m_node(new ScopeChainNode(0, o, globalData, globalObject, globalThis)) 169 { 170 } 171 ScopeChain(const ScopeChain & c)172 ScopeChain(const ScopeChain& c) 173 : m_node(c.m_node->copy()) 174 { 175 } 176 177 ScopeChain& operator=(const ScopeChain& c); 178 ScopeChain(ScopeChainNode * node)179 explicit ScopeChain(ScopeChainNode* node) 180 : m_node(node->copy()) 181 { 182 } 183 ~ScopeChain()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 node()195 ScopeChainNode* node() const { return m_node; } 196 top()197 JSObject* top() const { return m_node->object; } 198 begin()199 ScopeChainIterator begin() const { return m_node->begin(); } end()200 ScopeChainIterator end() const { return m_node->end(); } 201 push(JSObject * o)202 void push(JSObject* o) { m_node = m_node->push(o); } 203 pop()204 void pop() { m_node = m_node->pop(); } clear()205 void clear() { m_node->deref(); m_node = 0; } 206 globalObject()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 print()219 void print() const { m_node->print(); } 220 #endif 221 222 private: 223 ScopeChainNode* m_node; 224 }; 225 swap(ScopeChain & o)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(tmp); 237 return *this; 238 } 239 240 } // namespace JSC 241 242 #endif // ScopeChain_h 243