1/*
2 * Copyright (C) 2015 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 "Identifier.h"
29#include <wtf/HashMap.h>
30
31namespace JSC {
32
33struct VariableEnvironmentEntry {
34public:
35 ALWAYS_INLINE bool isCaptured() const { return m_bits & IsCaptured; }
36 ALWAYS_INLINE bool isConst() const { return m_bits & IsConst; }
37 ALWAYS_INLINE bool isVar() const { return m_bits & IsVar; }
38 ALWAYS_INLINE bool isLet() const { return m_bits & IsLet; }
39 ALWAYS_INLINE bool isExported() const { return m_bits & IsExported; }
40 ALWAYS_INLINE bool isImported() const { return m_bits & IsImported; }
41 ALWAYS_INLINE bool isImportedNamespace() const { return m_bits & IsImportedNamespace; }
42 ALWAYS_INLINE bool isFunction() const { return m_bits & IsFunction; }
43 ALWAYS_INLINE bool isParameter() const { return m_bits & IsParameter; }
44 ALWAYS_INLINE bool isSloppyModeHoistingCandidate() const { return m_bits & IsSloppyModeHoistingCandidate; }
45
46 ALWAYS_INLINE void setIsCaptured() { m_bits |= IsCaptured; }
47 ALWAYS_INLINE void setIsConst() { m_bits |= IsConst; }
48 ALWAYS_INLINE void setIsVar() { m_bits |= IsVar; }
49 ALWAYS_INLINE void setIsLet() { m_bits |= IsLet; }
50 ALWAYS_INLINE void setIsExported() { m_bits |= IsExported; }
51 ALWAYS_INLINE void setIsImported() { m_bits |= IsImported; }
52 ALWAYS_INLINE void setIsImportedNamespace() { m_bits |= IsImportedNamespace; }
53 ALWAYS_INLINE void setIsFunction() { m_bits |= IsFunction; }
54 ALWAYS_INLINE void setIsParameter() { m_bits |= IsParameter; }
55 ALWAYS_INLINE void setIsSloppyModeHoistingCandidate() { m_bits |= IsSloppyModeHoistingCandidate; }
56
57 ALWAYS_INLINE void clearIsVar() { m_bits &= ~IsVar; }
58
59 uint16_t bits() const { return m_bits; }
60
61 bool operator==(const VariableEnvironmentEntry& other) const
62 {
63 return m_bits == other.m_bits;
64 }
65
66private:
67 enum Traits : uint16_t {
68 IsCaptured = 1 << 0,
69 IsConst = 1 << 1,
70 IsVar = 1 << 2,
71 IsLet = 1 << 3,
72 IsExported = 1 << 4,
73 IsImported = 1 << 5,
74 IsImportedNamespace = 1 << 6,
75 IsFunction = 1 << 7,
76 IsParameter = 1 << 8,
77 IsSloppyModeHoistingCandidate = 1 << 9
78 };
79 uint16_t m_bits { 0 };
80};
81
82struct VariableEnvironmentEntryHashTraits : HashTraits<VariableEnvironmentEntry> {
83 static const bool needsDestruction = false;
84};
85
86class VariableEnvironment {
87private:
88 typedef HashMap<RefPtr<UniquedStringImpl>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> Map;
89public:
90 VariableEnvironment() = default;
91 VariableEnvironment(VariableEnvironment&& other) = default;
92 VariableEnvironment(const VariableEnvironment&) = default;
93 VariableEnvironment& operator=(const VariableEnvironment&) = default;
94 VariableEnvironment& operator=(VariableEnvironment&&) = default;
95
96 ALWAYS_INLINE Map::iterator begin() { return m_map.begin(); }
97 ALWAYS_INLINE Map::iterator end() { return m_map.end(); }
98 ALWAYS_INLINE Map::const_iterator begin() const { return m_map.begin(); }
99 ALWAYS_INLINE Map::const_iterator end() const { return m_map.end(); }
100 ALWAYS_INLINE Map::AddResult add(const RefPtr<UniquedStringImpl>& identifier) { return m_map.add(identifier, VariableEnvironmentEntry()); }
101 ALWAYS_INLINE Map::AddResult add(const Identifier& identifier) { return add(identifier.impl()); }
102 ALWAYS_INLINE unsigned size() const { return m_map.size(); }
103 ALWAYS_INLINE bool contains(const RefPtr<UniquedStringImpl>& identifier) const { return m_map.contains(identifier); }
104 ALWAYS_INLINE bool remove(const RefPtr<UniquedStringImpl>& identifier) { return m_map.remove(identifier); }
105 ALWAYS_INLINE Map::iterator find(const RefPtr<UniquedStringImpl>& identifier) { return m_map.find(identifier); }
106 ALWAYS_INLINE Map::const_iterator find(const RefPtr<UniquedStringImpl>& identifier) const { return m_map.find(identifier); }
107 void swap(VariableEnvironment& other);
108 void markVariableAsCapturedIfDefined(const RefPtr<UniquedStringImpl>& identifier);
109 void markVariableAsCaptured(const RefPtr<UniquedStringImpl>& identifier);
110 void markAllVariablesAsCaptured();
111 bool hasCapturedVariables() const;
112 bool captures(UniquedStringImpl* identifier) const;
113 void markVariableAsImported(const RefPtr<UniquedStringImpl>& identifier);
114 void markVariableAsExported(const RefPtr<UniquedStringImpl>& identifier);
115
116 bool isEverythingCaptured() const { return m_isEverythingCaptured; }
117 bool isEmpty() const { return !m_map.size(); }
118
119private:
120 friend class CachedVariableEnvironment;
121
122 Map m_map;
123 bool m_isEverythingCaptured { false };
124};
125
126class CompactVariableEnvironment {
127 WTF_MAKE_FAST_ALLOCATED;
128 WTF_MAKE_NONCOPYABLE(CompactVariableEnvironment);
129
130 friend class CachedCompactVariableEnvironment;
131
132public:
133 CompactVariableEnvironment(const VariableEnvironment&);
134 VariableEnvironment toVariableEnvironment() const;
135
136 bool operator==(const CompactVariableEnvironment&) const;
137 unsigned hash() const { return m_hash; }
138
139private:
140 CompactVariableEnvironment() = default;
141
142 Vector<RefPtr<UniquedStringImpl>> m_variables;
143 Vector<VariableEnvironmentEntry> m_variableMetadata;
144 unsigned m_hash;
145 bool m_isEverythingCaptured;
146};
147
148struct CompactVariableMapKey {
149 CompactVariableMapKey()
150 : m_environment(nullptr)
151 {
152 ASSERT(isHashTableEmptyValue());
153 }
154
155 CompactVariableMapKey(CompactVariableEnvironment& environment)
156 : m_environment(&environment)
157 { }
158
159 static unsigned hash(const CompactVariableMapKey& key) { return key.m_environment->hash(); }
160 static bool equal(const CompactVariableMapKey& a, const CompactVariableMapKey& b) { return *a.m_environment == *b.m_environment; }
161 static const bool safeToCompareToEmptyOrDeleted = false;
162 static void makeDeletedValue(CompactVariableMapKey& key)
163 {
164 key.m_environment = reinterpret_cast<CompactVariableEnvironment*>(1);
165 }
166 bool isHashTableDeletedValue() const
167 {
168 return m_environment == reinterpret_cast<CompactVariableEnvironment*>(1);
169 }
170 bool isHashTableEmptyValue() const
171 {
172 return !m_environment;
173 }
174
175 CompactVariableEnvironment& environment()
176 {
177 RELEASE_ASSERT(!isHashTableDeletedValue());
178 RELEASE_ASSERT(!isHashTableEmptyValue());
179 return *m_environment;
180 }
181
182private:
183 CompactVariableEnvironment* m_environment;
184};
185
186} // namespace JSC
187
188namespace WTF {
189
190template<typename T> struct DefaultHash;
191template<> struct DefaultHash<JSC::CompactVariableMapKey> {
192 using Hash = JSC::CompactVariableMapKey;
193};
194
195template<> struct HashTraits<JSC::CompactVariableMapKey> : GenericHashTraits<JSC::CompactVariableMapKey> {
196 static const bool emptyValueIsZero = true;
197 static JSC::CompactVariableMapKey emptyValue() { return JSC::CompactVariableMapKey(); }
198
199 static const bool hasIsEmptyValueFunction = true;
200 static bool isEmptyValue(JSC::CompactVariableMapKey key) { return key.isHashTableEmptyValue(); }
201
202 static void constructDeletedValue(JSC::CompactVariableMapKey& key) { JSC::CompactVariableMapKey::makeDeletedValue(key); }
203 static bool isDeletedValue(JSC::CompactVariableMapKey key) { return key.isHashTableDeletedValue(); }
204};
205
206} // namespace WTF
207
208namespace JSC {
209
210class CompactVariableMap : public RefCounted<CompactVariableMap> {
211public:
212 class Handle {
213 friend class CachedCompactVariableMapHandle;
214
215 public:
216 Handle() = default;
217
218 Handle(CompactVariableEnvironment&, CompactVariableMap&);
219
220 Handle(Handle&& other)
221 {
222 swap(other);
223 }
224 Handle& operator=(Handle&& other)
225 {
226 Handle handle(WTFMove(other));
227 swap(handle);
228 return *this;
229 }
230
231 Handle(const Handle&);
232 Handle& operator=(const Handle& other)
233 {
234 Handle handle(other);
235 swap(handle);
236 return *this;
237 }
238
239 ~Handle();
240
241 explicit operator bool() const { return !!m_map; }
242
243 const CompactVariableEnvironment& environment() const
244 {
245 return *m_environment;
246 }
247
248 private:
249 void swap(Handle& other)
250 {
251 std::swap(other.m_environment, m_environment);
252 std::swap(other.m_map, m_map);
253 }
254
255 CompactVariableEnvironment* m_environment { nullptr };
256 RefPtr<CompactVariableMap> m_map;
257 };
258
259 Handle get(const VariableEnvironment&);
260
261private:
262 friend class Handle;
263 friend class CachedCompactVariableMapHandle;
264
265 Handle get(CompactVariableEnvironment*, bool& isNewEntry);
266
267 HashMap<CompactVariableMapKey, unsigned> m_map;
268};
269
270} // namespace JSC
271