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