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