1/* 2 * Copyright (C) 2012, 2013, 2014 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef JSScope_h 27#define JSScope_h 28 29#include "JSObject.h" 30 31namespace JSC { 32 33class ScopeChainIterator; 34class VariableWatchpointSet; 35 36enum ResolveMode { 37 ThrowIfNotFound, 38 DoNotThrowIfNotFound 39}; 40 41enum ResolveType { 42 // Lexical scope guaranteed a certain type of variable access. 43 GlobalProperty, 44 GlobalVar, 45 ClosureVar, 46 47 // Ditto, but at least one intervening scope used non-strict eval, which 48 // can inject an intercepting var delcaration at runtime. 49 GlobalPropertyWithVarInjectionChecks, 50 GlobalVarWithVarInjectionChecks, 51 ClosureVarWithVarInjectionChecks, 52 53 // Lexical scope didn't prove anything -- probably because of a 'with' scope. 54 Dynamic 55}; 56 57const char* resolveModeName(ResolveMode mode); 58const char* resolveTypeName(ResolveType type); 59 60inline ResolveType makeType(ResolveType type, bool needsVarInjectionChecks) 61{ 62 if (!needsVarInjectionChecks) 63 return type; 64 65 switch (type) { 66 case GlobalProperty: 67 return GlobalPropertyWithVarInjectionChecks; 68 case GlobalVar: 69 return GlobalVarWithVarInjectionChecks; 70 case ClosureVar: 71 return ClosureVarWithVarInjectionChecks; 72 case GlobalPropertyWithVarInjectionChecks: 73 case GlobalVarWithVarInjectionChecks: 74 case ClosureVarWithVarInjectionChecks: 75 case Dynamic: 76 return type; 77 } 78 79 RELEASE_ASSERT_NOT_REACHED(); 80 return type; 81} 82 83inline bool needsVarInjectionChecks(ResolveType type) 84{ 85 switch (type) { 86 case GlobalProperty: 87 case GlobalVar: 88 case ClosureVar: 89 return false; 90 case GlobalPropertyWithVarInjectionChecks: 91 case GlobalVarWithVarInjectionChecks: 92 case ClosureVarWithVarInjectionChecks: 93 case Dynamic: 94 return true; 95 default: 96 RELEASE_ASSERT_NOT_REACHED(); 97 return true; 98 } 99} 100 101struct ResolveOp { 102 ResolveOp(ResolveType type, size_t depth, Structure* structure, JSActivation* activation, VariableWatchpointSet* watchpointSet, uintptr_t operand) 103 : type(type) 104 , depth(depth) 105 , structure(structure) 106 , activation(activation) 107 , watchpointSet(watchpointSet) 108 , operand(operand) 109 { 110 } 111 112 ResolveType type; 113 size_t depth; 114 Structure* structure; 115 JSActivation* activation; 116 VariableWatchpointSet* watchpointSet; 117 uintptr_t operand; 118}; 119 120class ResolveModeAndType { 121 typedef unsigned Operand; 122public: 123 static const size_t shift = sizeof(Operand) * 8 / 2; 124 static const unsigned mask = (1 << shift) - 1; 125 126 ResolveModeAndType(ResolveMode resolveMode, ResolveType resolveType) 127 : m_operand((resolveMode << shift) | resolveType) 128 { 129 } 130 131 explicit ResolveModeAndType(unsigned operand) 132 : m_operand(operand) 133 { 134 } 135 136 ResolveMode mode() { return static_cast<ResolveMode>(m_operand >> shift); } 137 ResolveType type() { return static_cast<ResolveType>(m_operand & mask); } 138 unsigned operand() { return m_operand; } 139 140private: 141 Operand m_operand; 142}; 143 144enum GetOrPut { Get, Put }; 145 146class JSScope : public JSNonFinalObject { 147public: 148 typedef JSNonFinalObject Base; 149 150 friend class LLIntOffsetsExtractor; 151 static size_t offsetOfNext(); 152 153 JS_EXPORT_PRIVATE static JSObject* objectAtScope(JSScope*); 154 155 static JSValue resolve(ExecState*, JSScope*, const Identifier&); 156 static ResolveOp abstractResolve(ExecState*, JSScope*, const Identifier&, GetOrPut, ResolveType); 157 158 static void visitChildren(JSCell*, SlotVisitor&); 159 160 ScopeChainIterator begin(); 161 ScopeChainIterator end(); 162 JSScope* next(); 163 int depth(); 164 165 JSGlobalObject* globalObject(); 166 VM* vm(); 167 JSObject* globalThis(); 168 169protected: 170 JSScope(VM&, Structure*, JSScope* next); 171 static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; 172 173private: 174 WriteBarrier<JSScope> m_next; 175}; 176 177inline JSScope::JSScope(VM& vm, Structure* structure, JSScope* next) 178 : Base(vm, structure) 179 , m_next(vm, this, next, WriteBarrier<JSScope>::MayBeNull) 180{ 181} 182 183class ScopeChainIterator { 184public: 185 ScopeChainIterator(JSScope* node) 186 : m_node(node) 187 { 188 } 189 190 JSObject* get() const { return JSScope::objectAtScope(m_node); } 191 JSObject* operator->() const { return JSScope::objectAtScope(m_node); } 192 193 ScopeChainIterator& operator++() { m_node = m_node->next(); return *this; } 194 195 // postfix ++ intentionally omitted 196 197 bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; } 198 bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; } 199 200private: 201 JSScope* m_node; 202}; 203 204inline ScopeChainIterator JSScope::begin() 205{ 206 return ScopeChainIterator(this); 207} 208 209inline ScopeChainIterator JSScope::end() 210{ 211 return ScopeChainIterator(0); 212} 213 214inline JSScope* JSScope::next() 215{ 216 return m_next.get(); 217} 218 219inline JSGlobalObject* JSScope::globalObject() 220{ 221 return structure()->globalObject(); 222} 223 224inline VM* JSScope::vm() 225{ 226 return MarkedBlock::blockFor(this)->vm(); 227} 228 229inline Register& Register::operator=(JSScope* scope) 230{ 231 *this = JSValue(scope); 232 return *this; 233} 234 235inline JSScope* Register::scope() const 236{ 237 return jsCast<JSScope*>(jsValue()); 238} 239 240inline VM& ExecState::vm() const 241{ 242 ASSERT(scope()->vm()); 243 return *scope()->vm(); 244} 245 246inline JSGlobalObject* ExecState::lexicalGlobalObject() const 247{ 248 return scope()->globalObject(); 249} 250 251inline JSObject* ExecState::globalThisValue() const 252{ 253 return scope()->globalThis(); 254} 255 256inline size_t JSScope::offsetOfNext() 257{ 258 return OBJECT_OFFSETOF(JSScope, m_next); 259} 260 261} // namespace JSC 262 263#endif // JSScope_h 264