Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/parsing/preparsed-scope-data.h"
6 :
7 : #include "src/ast/scopes.h"
8 : #include "src/ast/variables.h"
9 : #include "src/handles.h"
10 : #include "src/objects-inl.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 :
15 : namespace {
16 :
17 : class VariableIsUsedField : public BitField16<bool, 0, 1> {};
18 : class VariableMaybeAssignedField
19 : : public BitField16<bool, VariableIsUsedField::kNext, 1> {};
20 : class VariableContextAllocatedField
21 : : public BitField16<bool, VariableMaybeAssignedField::kNext, 1> {};
22 :
23 : const int kFunctionDataSize = 8;
24 :
25 : } // namespace
26 :
27 : /*
28 :
29 : Internal data format for the backing store:
30 :
31 : ------------------------------------
32 : | scope type << only in debug |
33 : | inner_scope_calls_eval_ |
34 : | data end index |
35 : | ---------------------- |
36 : | | data for variables | |
37 : | | ... | |
38 : | ---------------------- |
39 : ------------------------------------
40 : ------------------------------------
41 : | data for inner scope_1 |
42 : | ... |
43 : ------------------------------------
44 : ...
45 : ------------------------------------
46 : | data for inner scope_n |
47 : | ... |
48 : ------------------------------------
49 : << data end index points here
50 : */
51 :
52 65460 : void PreParsedScopeData::SaveData(Scope* scope) {
53 : DCHECK(!has_data_);
54 :
55 71501 : if (scope->scope_type() == ScopeType::FUNCTION_SCOPE &&
56 31498 : !scope->AsDeclarationScope()->is_arrow_scope()) {
57 : // This cast is OK since we're not going to have more than 2^32 elements in
58 : // the data. FIXME(marja): Implement limits for the data size.
59 50914 : function_data_positions_[scope->start_position()] =
60 170545 : static_cast<uint32_t>(backing_store_.size());
61 : }
62 :
63 40003 : if (!ScopeNeedsData(scope)) {
64 40003 : return;
65 : }
66 :
67 : #ifdef DEBUG
68 : backing_store_.push_back(scope->scope_type());
69 : #endif
70 79754 : backing_store_.push_back(scope->inner_scope_calls_eval());
71 : // Reserve space for the data end index (which we don't know yet). The end
72 : // index is needed for skipping over data for a function scope when we skip
73 : // parsing of the corresponding function.
74 : size_t data_end_index = backing_store_.size();
75 79754 : backing_store_.push_back(0);
76 :
77 39877 : if (!scope->is_hidden()) {
78 289344 : for (Variable* var : *scope->locals()) {
79 106685 : if (IsDeclaredVariableMode(var->mode())) {
80 106685 : SaveDataForVariable(var);
81 : }
82 : }
83 : }
84 :
85 39877 : SaveDataForInnerScopes(scope);
86 :
87 : // FIXME(marja): see above.
88 39877 : backing_store_[data_end_index] = static_cast<uint32_t>(backing_store_.size());
89 : }
90 :
91 10656 : void PreParsedScopeData::AddSkippableFunction(
92 : int start_position, const PreParseData::FunctionData& function_data) {
93 : AddFunction(start_position, function_data);
94 21312 : skippable_functions_.insert(start_position);
95 10656 : }
96 :
97 14801 : void PreParsedScopeData::AddFunction(
98 : int start_position, const PreParseData::FunctionData& function_data) {
99 25457 : function_index_.AddFunctionData(start_position, function_data);
100 14801 : }
101 :
102 14 : void PreParsedScopeData::RestoreData(DeclarationScope* scope) const {
103 14 : uint32_t index = 0;
104 :
105 : DCHECK_EQ(scope->scope_type(), ScopeType::FUNCTION_SCOPE);
106 :
107 14 : bool success = FindFunctionData(scope->start_position(), &index);
108 : DCHECK(success);
109 : USE(success);
110 :
111 14 : RestoreData(scope, &index);
112 14 : }
113 :
114 49490 : void PreParsedScopeData::RestoreData(Scope* scope, uint32_t* index_ptr) const {
115 : // It's possible that scope is not present in the data at all (since PreParser
116 : // doesn't create the corresponding scope). In this case, the Scope won't
117 : // contain any variables for which we need the data.
118 49490 : if (!ScopeNeedsData(scope) && !IsSkippedFunctionScope(scope)) {
119 : return;
120 : }
121 :
122 : uint32_t& index = *index_ptr;
123 :
124 : #ifdef DEBUG
125 : // Data integrity check.
126 : if (scope->scope_type() == ScopeType::FUNCTION_SCOPE &&
127 : !scope->AsDeclarationScope()->is_arrow_scope()) {
128 : const PreParseData::FunctionData& data =
129 : function_index_.GetFunctionData(scope->start_position());
130 : DCHECK_EQ(data.end, scope->end_position());
131 : // FIXME(marja): unify num_parameters too and DCHECK here.
132 : DCHECK_EQ(data.language_mode, scope->language_mode());
133 : DCHECK_EQ(data.uses_super_property,
134 : scope->AsDeclarationScope()->uses_super_property());
135 : uint32_t index_from_data = 0;
136 : FindFunctionData(scope->start_position(), &index_from_data);
137 : DCHECK_EQ(index_from_data, index);
138 : }
139 : #endif
140 :
141 39816 : if (IsSkippedFunctionScope(scope)) {
142 : // This scope is a function scope representing a function we want to
143 : // skip. So just skip over its data.
144 : DCHECK(!scope->must_use_preparsed_scope_data());
145 : // Check that we're moving forward (not backward) in the data.
146 : DCHECK_GT(backing_store_[index + 2], index);
147 39830 : index = backing_store_[index + 2];
148 14 : return;
149 : }
150 :
151 : DCHECK_EQ(backing_store_[index++], scope->scope_type());
152 :
153 79604 : if (backing_store_[index++]) {
154 : scope->RecordEvalCall();
155 : }
156 39802 : uint32_t data_end_index = backing_store_[index++];
157 : USE(data_end_index);
158 :
159 39802 : if (!scope->is_hidden()) {
160 375186 : for (Variable* var : *scope->locals()) {
161 149681 : if (var->mode() == VAR || var->mode() == LET || var->mode() == CONST) {
162 106246 : RestoreDataForVariable(var, index_ptr);
163 : }
164 : }
165 : }
166 :
167 39802 : RestoreDataForInnerScopes(scope, index_ptr);
168 :
169 : DCHECK_EQ(data_end_index, index);
170 : }
171 :
172 23 : Handle<PodArray<uint32_t>> PreParsedScopeData::Serialize(
173 : Isolate* isolate) const {
174 : // FIXME(marja): save space by using a byte array and converting
175 : // function_index_ to bytes.
176 : size_t length =
177 678 : function_index_.size() * kFunctionDataSize + backing_store_.size() + 1;
178 : Handle<PodArray<uint32_t>> array =
179 23 : PodArray<uint32_t>::New(isolate, static_cast<int>(length), TENURED);
180 :
181 46 : array->set(0, static_cast<uint32_t>(function_index_.size()));
182 : int i = 1;
183 123 : for (const auto& item : function_index_) {
184 154 : const auto& it = function_data_positions_.find(item.first);
185 : DCHECK(it != function_data_positions_.end());
186 : const PreParseData::FunctionData& function_data = item.second;
187 154 : array->set(i++, item.first); // start position
188 77 : array->set(i++, it->second); // position in data
189 154 : array->set(i++, function_data.end);
190 154 : array->set(i++, function_data.num_parameters);
191 154 : array->set(i++, function_data.num_inner_functions);
192 154 : array->set(i++, function_data.language_mode);
193 154 : array->set(i++, function_data.uses_super_property);
194 154 : array->set(i++, skippable_functions_.find(item.first) !=
195 154 : skippable_functions_.end());
196 : }
197 :
198 1264 : for (size_t j = 0; j < backing_store_.size(); ++j) {
199 1218 : array->set(i++, static_cast<uint32_t>(backing_store_[j]));
200 : }
201 : DCHECK_EQ(array->length(), length);
202 23 : return array;
203 : }
204 :
205 42 : void PreParsedScopeData::Deserialize(PodArray<uint32_t>* array) {
206 42 : has_data_ = true;
207 : DCHECK_NOT_NULL(array);
208 42 : if (array->length() == 0) {
209 : return;
210 : }
211 42 : int function_count = array->get(0);
212 42 : CHECK(array->length() > function_count * kFunctionDataSize);
213 42 : if (function_count == 0) {
214 : return;
215 : }
216 : int i = 1;
217 210 : for (; i < function_count * kFunctionDataSize + 1; i += kFunctionDataSize) {
218 210 : int start = array->get(i);
219 630 : function_data_positions_[start] = array->get(i + 1);
220 : function_index_.AddFunctionData(
221 : start, PreParseData::FunctionData(
222 630 : array->get(i + 2), array->get(i + 3), array->get(i + 4),
223 1260 : LanguageMode(array->get(i + 5)), array->get(i + 6)));
224 420 : if (array->get(i + 7)) {
225 112 : skippable_functions_.insert(start);
226 : }
227 : }
228 84 : CHECK_EQ(function_index_.size(), function_count);
229 :
230 42 : backing_store_.reserve(array->length() - i);
231 3248 : for (; i < array->length(); ++i) {
232 3164 : backing_store_.push_back(array->get(i));
233 : }
234 : }
235 :
236 14 : PreParseData::FunctionData PreParsedScopeData::FindSkippableFunction(
237 : int start_pos) const {
238 28 : if (skippable_functions_.find(start_pos) == skippable_functions_.end()) {
239 : return PreParseData::FunctionData();
240 : }
241 14 : return function_index_.GetFunctionData(start_pos);
242 : }
243 :
244 106685 : void PreParsedScopeData::SaveDataForVariable(Variable* var) {
245 : #ifdef DEBUG
246 : // Store the variable name in debug mode; this way we can check that we
247 : // restore data to the correct variable.
248 : const AstRawString* name = var->raw_name();
249 : backing_store_.push_back(name->length());
250 : for (int i = 0; i < name->length(); ++i) {
251 : backing_store_.push_back(name->raw_data()[i]);
252 : }
253 : #endif
254 : // FIXME(marja): Only 3 bits needed, not a full byte.
255 : byte variable_data = VariableIsUsedField::encode(var->is_used()) |
256 : VariableMaybeAssignedField::encode(
257 106685 : var->maybe_assigned() == kMaybeAssigned) |
258 : VariableContextAllocatedField::encode(
259 320055 : var->has_forced_context_allocation());
260 :
261 213370 : backing_store_.push_back(variable_data);
262 106685 : }
263 :
264 106246 : void PreParsedScopeData::RestoreDataForVariable(Variable* var,
265 : uint32_t* index_ptr) const {
266 : uint32_t& index = *index_ptr;
267 : #ifdef DEBUG
268 : const AstRawString* name = var->raw_name();
269 : DCHECK_EQ(backing_store_[index++], static_cast<uint32_t>(name->length()));
270 : for (int i = 0; i < name->length(); ++i) {
271 : DCHECK_EQ(backing_store_[index++], name->raw_data()[i]);
272 : }
273 : #endif
274 212492 : byte variable_data = backing_store_[index++];
275 106246 : if (VariableIsUsedField::decode(variable_data)) {
276 : var->set_is_used();
277 : }
278 106246 : if (VariableMaybeAssignedField::decode(variable_data)) {
279 : var->set_maybe_assigned();
280 : }
281 106246 : if (VariableContextAllocatedField::decode(variable_data)) {
282 : var->ForceContextAllocation();
283 : }
284 106246 : }
285 :
286 79754 : void PreParsedScopeData::SaveDataForInnerScopes(Scope* scope) {
287 : // Inner scopes are stored in the reverse order, but we'd like to write the
288 : // data in the logical order. There might be many inner scopes, so we don't
289 : // want to recurse here.
290 : std::vector<Scope*> scopes;
291 65079 : for (Scope* inner = scope->inner_scope(); inner != nullptr;
292 25202 : inner = inner->sibling()) {
293 25202 : scopes.push_back(inner);
294 : }
295 104956 : for (int i = static_cast<int>(scopes.size()) - 1; i >= 0; --i) {
296 50404 : SaveData(scopes[i]);
297 : }
298 39877 : }
299 :
300 79604 : void PreParsedScopeData::RestoreDataForInnerScopes(Scope* scope,
301 : uint32_t* index_ptr) const {
302 : std::vector<Scope*> scopes;
303 74550 : for (Scope* inner = scope->inner_scope(); inner != nullptr;
304 34748 : inner = inner->sibling()) {
305 34748 : scopes.push_back(inner);
306 : }
307 114352 : for (int i = static_cast<int>(scopes.size()) - 1; i >= 0; --i) {
308 69496 : RestoreData(scopes[i], index_ptr);
309 : }
310 39802 : }
311 :
312 0 : bool PreParsedScopeData::FindFunctionData(int start_pos,
313 : uint32_t* index) const {
314 28 : auto it = function_data_positions_.find(start_pos);
315 14 : if (it == function_data_positions_.end()) {
316 : return false;
317 : }
318 14 : *index = it->second;
319 0 : return true;
320 : }
321 :
322 112397 : bool PreParsedScopeData::ScopeNeedsData(Scope* scope) {
323 96045 : if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
324 : return true;
325 : }
326 33110 : if (!scope->is_hidden()) {
327 50946 : for (Variable* var : *scope->locals()) {
328 16758 : if (var->mode() == VAR || var->mode() == LET || var->mode() == CONST) {
329 : return true;
330 : }
331 : }
332 : }
333 19124 : for (Scope* inner = scope->inner_scope(); inner != nullptr;
334 : inner = inner->sibling()) {
335 6552 : if (ScopeNeedsData(inner)) {
336 : return true;
337 : }
338 : }
339 : return false;
340 : }
341 :
342 49490 : bool PreParsedScopeData::IsSkippedFunctionScope(Scope* scope) {
343 81515 : return scope->is_declaration_scope() &&
344 81515 : scope->AsDeclarationScope()->is_skipped_function();
345 : }
346 :
347 : } // namespace internal
348 : } // namespace v8
|