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#include "config.h"
27#include "VariableEnvironment.h"
28#include <wtf/text/UniquedStringImpl.h>
29
30namespace JSC {
31
32void VariableEnvironment::markVariableAsCapturedIfDefined(const RefPtr<UniquedStringImpl>& identifier)
33{
34 auto findResult = m_map.find(identifier);
35 if (findResult != m_map.end())
36 findResult->value.setIsCaptured();
37}
38
39void VariableEnvironment::markVariableAsCaptured(const RefPtr<UniquedStringImpl>& identifier)
40{
41 auto findResult = m_map.find(identifier);
42 RELEASE_ASSERT(findResult != m_map.end());
43 findResult->value.setIsCaptured();
44}
45
46void VariableEnvironment::markAllVariablesAsCaptured()
47{
48 if (m_isEverythingCaptured)
49 return;
50
51 m_isEverythingCaptured = true; // For fast queries.
52 // We must mark every entry as captured for when we iterate through m_map and entry.isCaptured() is called.
53 for (auto& value : m_map.values())
54 value.setIsCaptured();
55}
56
57bool VariableEnvironment::hasCapturedVariables() const
58{
59 if (m_isEverythingCaptured)
60 return size() > 0;
61 for (auto& value : m_map.values()) {
62 if (value.isCaptured())
63 return true;
64 }
65 return false;
66}
67
68bool VariableEnvironment::captures(UniquedStringImpl* identifier) const
69{
70 if (m_isEverythingCaptured)
71 return true;
72
73 auto findResult = m_map.find(identifier);
74 if (findResult == m_map.end())
75 return false;
76 return findResult->value.isCaptured();
77}
78
79void VariableEnvironment::swap(VariableEnvironment& other)
80{
81 m_map.swap(other.m_map);
82 m_isEverythingCaptured = other.m_isEverythingCaptured;
83}
84
85void VariableEnvironment::markVariableAsImported(const RefPtr<UniquedStringImpl>& identifier)
86{
87 auto findResult = m_map.find(identifier);
88 RELEASE_ASSERT(findResult != m_map.end());
89 findResult->value.setIsImported();
90}
91
92void VariableEnvironment::markVariableAsExported(const RefPtr<UniquedStringImpl>& identifier)
93{
94 auto findResult = m_map.find(identifier);
95 RELEASE_ASSERT(findResult != m_map.end());
96 findResult->value.setIsExported();
97}
98
99CompactVariableEnvironment::CompactVariableEnvironment(const VariableEnvironment& env)
100 : m_isEverythingCaptured(env.isEverythingCaptured())
101{
102 Vector<std::pair<UniquedStringImpl*, VariableEnvironmentEntry>, 32> sortedEntries;
103 sortedEntries.reserveInitialCapacity(env.size());
104 for (auto& pair : env)
105 sortedEntries.append({ pair.key.get(), pair.value });
106
107 std::sort(sortedEntries.begin(), sortedEntries.end(), [] (const auto& a, const auto& b) {
108 return a.first < b.first;
109 });
110
111 m_hash = 0;
112 m_variables.reserveInitialCapacity(sortedEntries.size());
113 m_variableMetadata.reserveInitialCapacity(sortedEntries.size());
114 for (const auto& pair : sortedEntries) {
115 m_variables.append(pair.first);
116 m_variableMetadata.append(pair.second);
117 m_hash ^= pair.first->hash();
118 m_hash += pair.second.bits();
119 }
120
121 if (m_isEverythingCaptured)
122 m_hash *= 2;
123}
124
125bool CompactVariableEnvironment::operator==(const CompactVariableEnvironment& other) const
126{
127 if (this == &other)
128 return true;
129 if (m_isEverythingCaptured != other.m_isEverythingCaptured)
130 return false;
131 if (m_variables != other.m_variables)
132 return false;
133 if (m_variableMetadata != other.m_variableMetadata)
134 return false;
135 return true;
136}
137
138VariableEnvironment CompactVariableEnvironment::toVariableEnvironment() const
139{
140 VariableEnvironment result;
141 ASSERT(m_variables.size() == m_variableMetadata.size());
142 for (size_t i = 0; i < m_variables.size(); ++i) {
143 auto addResult = result.add(m_variables[i]);
144 ASSERT(addResult.isNewEntry);
145 addResult.iterator->value = m_variableMetadata[i];
146 }
147
148 if (m_isEverythingCaptured)
149 result.markAllVariablesAsCaptured();
150
151 return result;
152}
153
154CompactVariableMap::Handle CompactVariableMap::get(const VariableEnvironment& env)
155{
156 auto* environment = new CompactVariableEnvironment(env);
157 bool isNewEntry;
158 auto handle = get(environment, isNewEntry);
159 if (!isNewEntry)
160 delete environment;
161 return handle;
162}
163
164CompactVariableMap::Handle CompactVariableMap::get(CompactVariableEnvironment* environment, bool& isNewEntry)
165{
166 CompactVariableMapKey key { *environment };
167 auto addResult = m_map.add(key, 1);
168 isNewEntry = addResult.isNewEntry;
169 if (addResult.isNewEntry)
170 return CompactVariableMap::Handle(*environment, *this);
171
172 ++addResult.iterator->value;
173 return CompactVariableMap::Handle(addResult.iterator->key.environment(), *this);
174}
175
176CompactVariableMap::Handle::~Handle()
177{
178 if (!m_map) {
179 ASSERT(!m_environment);
180 // This happens if we were moved into a different handle.
181 return;
182 }
183
184 RELEASE_ASSERT(m_environment);
185 auto iter = m_map->m_map.find(CompactVariableMapKey { *m_environment });
186 RELEASE_ASSERT(iter != m_map->m_map.end());
187 --iter->value;
188 if (!iter->value) {
189 ASSERT(m_environment == &iter->key.environment());
190 m_map->m_map.remove(iter);
191 delete m_environment;
192 }
193}
194
195CompactVariableMap::Handle::Handle(const CompactVariableMap::Handle& other)
196 : m_environment(other.m_environment)
197 , m_map(other.m_map)
198{
199 if (m_map) {
200 auto iter = m_map->m_map.find(CompactVariableMapKey { *m_environment });
201 RELEASE_ASSERT(iter != m_map->m_map.end());
202 ++iter->value;
203 }
204}
205
206CompactVariableMap::Handle::Handle(CompactVariableEnvironment& environment, CompactVariableMap& map)
207 : m_environment(&environment)
208 , m_map(&map)
209{
210}
211
212} // namespace JSC
213