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
30namespace JSC {
31
32class Structure;
33class WatchpointSet;
34class JSLexicalEnvironment;
35
36enum ResolveMode {
37 ThrowIfNotFound,
38 DoNotThrowIfNotFound
39};
40
41enum 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
67enum class InitializationMode : unsigned {
68 Initialization, // "let x = 20;"
69 ConstInitialization, // "const x = 20;"
70 NotInitialization // "x = 20;"
71};
72
73ALWAYS_INLINE const char* resolveModeName(ResolveMode resolveMode)
74{
75 static const char* const names[] = {
76 "ThrowIfNotFound",
77 "DoNotThrowIfNotFound"
78 };
79 return names[resolveMode];
80}
81
82ALWAYS_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
102ALWAYS_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
112ALWAYS_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
125ALWAYS_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
156ALWAYS_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
180struct 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
201class GetPutInfo {
202 typedef unsigned Operand;
203public:
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
232private:
233 Operand m_operand { 0 };
234
235 friend class JSC::LLIntOffsetsExtractor;
236};
237
238enum GetOrPut { Get, Put };
239
240} // namespace JSC
241
242namespace WTF {
243
244class PrintStream;
245
246void printInternal(PrintStream&, JSC::ResolveMode);
247void printInternal(PrintStream&, JSC::ResolveType);
248void printInternal(PrintStream&, JSC::InitializationMode);
249
250} // namespace WTF
251