| 1 | /* |
| 2 | * Copyright (C) 2015-2019 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 | #pragma once |
| 27 | |
| 28 | #include <wtf/text/UniquedStringImpl.h> |
| 29 | |
| 30 | namespace JSC { |
| 31 | |
| 32 | class Structure; |
| 33 | class WatchpointSet; |
| 34 | class JSLexicalEnvironment; |
| 35 | |
| 36 | enum ResolveMode { |
| 37 | ThrowIfNotFound, |
| 38 | DoNotThrowIfNotFound |
| 39 | }; |
| 40 | |
| 41 | enum ResolveType : unsigned { |
| 42 | // Lexical scope guaranteed a certain type of variable access. |
| 43 | GlobalProperty, |
| 44 | GlobalVar, |
| 45 | GlobalLexicalVar, |
| 46 | ClosureVar, |
| 47 | LocalClosureVar, |
| 48 | ModuleVar, |
| 49 | |
| 50 | // Ditto, but at least one intervening scope used non-strict eval, which |
| 51 | // can inject an intercepting var delcaration at runtime. |
| 52 | GlobalPropertyWithVarInjectionChecks, |
| 53 | GlobalVarWithVarInjectionChecks, |
| 54 | GlobalLexicalVarWithVarInjectionChecks, |
| 55 | ClosureVarWithVarInjectionChecks, |
| 56 | |
| 57 | // We haven't found which scope this belongs to, and we also |
| 58 | // haven't ruled out the possibility of it being cached. Ideally, |
| 59 | // we want to transition this to GlobalVar/GlobalLexicalVar/GlobalProperty <with/without injection> |
| 60 | UnresolvedProperty, |
| 61 | UnresolvedPropertyWithVarInjectionChecks, |
| 62 | |
| 63 | // Lexical scope didn't prove anything -- probably because of a 'with' scope. |
| 64 | Dynamic |
| 65 | }; |
| 66 | |
| 67 | enum class InitializationMode : unsigned { |
| 68 | Initialization, // "let x = 20;" |
| 69 | ConstInitialization, // "const x = 20;" |
| 70 | NotInitialization // "x = 20;" |
| 71 | }; |
| 72 | |
| 73 | ALWAYS_INLINE const char* resolveModeName(ResolveMode resolveMode) |
| 74 | { |
| 75 | static const char* const names[] = { |
| 76 | "ThrowIfNotFound" , |
| 77 | "DoNotThrowIfNotFound" |
| 78 | }; |
| 79 | return names[resolveMode]; |
| 80 | } |
| 81 | |
| 82 | ALWAYS_INLINE const char* resolveTypeName(ResolveType type) |
| 83 | { |
| 84 | static const char* const names[] = { |
| 85 | "GlobalProperty" , |
| 86 | "GlobalVar" , |
| 87 | "GlobalLexicalVar" , |
| 88 | "ClosureVar" , |
| 89 | "LocalClosureVar" , |
| 90 | "ModuleVar" , |
| 91 | "GlobalPropertyWithVarInjectionChecks" , |
| 92 | "GlobalVarWithVarInjectionChecks" , |
| 93 | "GlobalLexicalVarWithVarInjectionChecks" , |
| 94 | "ClosureVarWithVarInjectionChecks" , |
| 95 | "UnresolvedProperty" , |
| 96 | "UnresolvedPropertyWithVarInjectionChecks" , |
| 97 | "Dynamic" |
| 98 | }; |
| 99 | return names[type]; |
| 100 | } |
| 101 | |
| 102 | ALWAYS_INLINE const char* initializationModeName(InitializationMode initializationMode) |
| 103 | { |
| 104 | static const char* const names[] = { |
| 105 | "Initialization" , |
| 106 | "ConstInitialization" , |
| 107 | "NotInitialization" |
| 108 | }; |
| 109 | return names[static_cast<unsigned>(initializationMode)]; |
| 110 | } |
| 111 | |
| 112 | ALWAYS_INLINE bool isInitialization(InitializationMode initializationMode) |
| 113 | { |
| 114 | switch (initializationMode) { |
| 115 | case InitializationMode::Initialization: |
| 116 | case InitializationMode::ConstInitialization: |
| 117 | return true; |
| 118 | case InitializationMode::NotInitialization: |
| 119 | return false; |
| 120 | } |
| 121 | ASSERT_NOT_REACHED(); |
| 122 | return false; |
| 123 | } |
| 124 | |
| 125 | ALWAYS_INLINE ResolveType makeType(ResolveType type, bool needsVarInjectionChecks) |
| 126 | { |
| 127 | if (!needsVarInjectionChecks) |
| 128 | return type; |
| 129 | |
| 130 | switch (type) { |
| 131 | case GlobalProperty: |
| 132 | return GlobalPropertyWithVarInjectionChecks; |
| 133 | case GlobalVar: |
| 134 | return GlobalVarWithVarInjectionChecks; |
| 135 | case GlobalLexicalVar: |
| 136 | return GlobalLexicalVarWithVarInjectionChecks; |
| 137 | case ClosureVar: |
| 138 | case LocalClosureVar: |
| 139 | return ClosureVarWithVarInjectionChecks; |
| 140 | case UnresolvedProperty: |
| 141 | return UnresolvedPropertyWithVarInjectionChecks; |
| 142 | case ModuleVar: |
| 143 | case GlobalPropertyWithVarInjectionChecks: |
| 144 | case GlobalVarWithVarInjectionChecks: |
| 145 | case GlobalLexicalVarWithVarInjectionChecks: |
| 146 | case ClosureVarWithVarInjectionChecks: |
| 147 | case UnresolvedPropertyWithVarInjectionChecks: |
| 148 | case Dynamic: |
| 149 | return type; |
| 150 | } |
| 151 | |
| 152 | RELEASE_ASSERT_NOT_REACHED(); |
| 153 | return type; |
| 154 | } |
| 155 | |
| 156 | ALWAYS_INLINE bool needsVarInjectionChecks(ResolveType type) |
| 157 | { |
| 158 | switch (type) { |
| 159 | case GlobalProperty: |
| 160 | case GlobalVar: |
| 161 | case GlobalLexicalVar: |
| 162 | case ClosureVar: |
| 163 | case LocalClosureVar: |
| 164 | case ModuleVar: |
| 165 | case UnresolvedProperty: |
| 166 | return false; |
| 167 | case GlobalPropertyWithVarInjectionChecks: |
| 168 | case GlobalVarWithVarInjectionChecks: |
| 169 | case GlobalLexicalVarWithVarInjectionChecks: |
| 170 | case ClosureVarWithVarInjectionChecks: |
| 171 | case UnresolvedPropertyWithVarInjectionChecks: |
| 172 | case Dynamic: |
| 173 | return true; |
| 174 | default: |
| 175 | RELEASE_ASSERT_NOT_REACHED(); |
| 176 | return true; |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | struct ResolveOp { |
| 181 | ResolveOp(ResolveType type, size_t depth, Structure* structure, JSLexicalEnvironment* lexicalEnvironment, WatchpointSet* watchpointSet, uintptr_t operand, UniquedStringImpl* importedName = nullptr) |
| 182 | : type(type) |
| 183 | , depth(depth) |
| 184 | , structure(structure) |
| 185 | , lexicalEnvironment(lexicalEnvironment) |
| 186 | , watchpointSet(watchpointSet) |
| 187 | , operand(operand) |
| 188 | , importedName(importedName) |
| 189 | { |
| 190 | } |
| 191 | |
| 192 | ResolveType type; |
| 193 | size_t depth; |
| 194 | Structure* structure; |
| 195 | JSLexicalEnvironment* lexicalEnvironment; |
| 196 | WatchpointSet* watchpointSet; |
| 197 | uintptr_t operand; |
| 198 | RefPtr<UniquedStringImpl> importedName; |
| 199 | }; |
| 200 | |
| 201 | class GetPutInfo { |
| 202 | typedef unsigned Operand; |
| 203 | public: |
| 204 | // Give each field 10 bits for simplicity. |
| 205 | static_assert(sizeof(Operand) * 8 > 30, "Not enough bits for GetPutInfo" ); |
| 206 | static const unsigned modeShift = 20; |
| 207 | static const unsigned initializationShift = 10; |
| 208 | static const unsigned typeBits = (1 << initializationShift) - 1; |
| 209 | static const unsigned initializationBits = ((1 << modeShift) - 1) & ~typeBits; |
| 210 | static const unsigned modeBits = ((1 << 30) - 1) & ~initializationBits & ~typeBits; |
| 211 | static_assert((modeBits & initializationBits & typeBits) == 0x0, "There should be no intersection between ResolveMode ResolveType and InitializationMode" ); |
| 212 | |
| 213 | GetPutInfo() = default; |
| 214 | |
| 215 | GetPutInfo(ResolveMode resolveMode, ResolveType resolveType, InitializationMode initializationMode) |
| 216 | : m_operand((resolveMode << modeShift) | (static_cast<unsigned>(initializationMode) << initializationShift) | resolveType) |
| 217 | { |
| 218 | } |
| 219 | |
| 220 | explicit GetPutInfo(unsigned operand) |
| 221 | : m_operand(operand) |
| 222 | { |
| 223 | } |
| 224 | |
| 225 | ResolveType resolveType() const { return static_cast<ResolveType>(m_operand & typeBits); } |
| 226 | InitializationMode initializationMode() const { return static_cast<InitializationMode>((m_operand & initializationBits) >> initializationShift); } |
| 227 | ResolveMode resolveMode() const { return static_cast<ResolveMode>((m_operand & modeBits) >> modeShift); } |
| 228 | unsigned operand() const { return m_operand; } |
| 229 | |
| 230 | void dump(PrintStream&) const; |
| 231 | |
| 232 | private: |
| 233 | Operand m_operand { 0 }; |
| 234 | |
| 235 | friend class JSC::LLIntOffsetsExtractor; |
| 236 | }; |
| 237 | |
| 238 | enum GetOrPut { Get, Put }; |
| 239 | |
| 240 | } // namespace JSC |
| 241 | |
| 242 | namespace WTF { |
| 243 | |
| 244 | class PrintStream; |
| 245 | |
| 246 | void printInternal(PrintStream&, JSC::ResolveMode); |
| 247 | void printInternal(PrintStream&, JSC::ResolveType); |
| 248 | void printInternal(PrintStream&, JSC::InitializationMode); |
| 249 | |
| 250 | } // namespace WTF |
| 251 | |