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 : #ifndef V8_PARSING_PREPARSED_SCOPE_DATA_H_
6 : #define V8_PARSING_PREPARSED_SCOPE_DATA_H_
7 :
8 : #include <set>
9 : #include <unordered_map>
10 : #include <vector>
11 :
12 : #include "src/globals.h"
13 : #include "src/handles.h"
14 : #include "src/objects/shared-function-info.h"
15 : #include "src/parsing/preparse-data.h"
16 : #include "src/zone/zone-containers.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 :
21 : template <typename T>
22 : class Handle;
23 :
24 : class PreParser;
25 : class PreParsedScopeData;
26 :
27 : /*
28 :
29 : Skipping inner functions.
30 :
31 : Consider the following code:
32 : (function eager_outer() {
33 : function lazy_inner() {
34 : let a;
35 : function skip_me() { a; }
36 : }
37 :
38 : return lazy_inner;
39 : })();
40 :
41 : ... lazy_inner(); ...
42 :
43 : When parsing the code the first time, eager_outer is parsed and lazy_inner
44 : (and everything inside it) is preparsed. When lazy_inner is called, we don't
45 : want to parse or preparse skip_me again. Instead, we want to skip over it,
46 : since it has already been preparsed once.
47 :
48 : In order to be able to do this, we need to store the information needed for
49 : allocating the variables in lazy_inner when we preparse it, and then later do
50 : scope allocation based on that data.
51 :
52 : We need the following data for each scope in lazy_inner's scope tree:
53 : For each Variable:
54 : - is_used
55 : - maybe_assigned
56 : - has_forced_context_allocation
57 :
58 : For each Scope:
59 : - inner_scope_calls_eval_.
60 :
61 : ProducedPreParsedScopeData implements storing the above mentioned data and
62 : ConsumedPreParsedScopeData implements restoring it (= setting the context
63 : allocation status of the variables in a Scope (and its subscopes) based on the
64 : data).
65 :
66 : */
67 :
68 : class ProducedPreParsedScopeData : public ZoneObject {
69 : public:
70 : class ByteData : public ZoneObject {
71 : public:
72 : explicit ByteData(Zone* zone) : backing_store_(zone) {}
73 :
74 : void WriteUint32(uint32_t data);
75 : void WriteUint8(uint8_t data);
76 :
77 : // For overwriting previously written data at position 0.
78 : void OverwriteFirstUint32(uint32_t data);
79 :
80 : Handle<PodArray<uint8_t>> Serialize(Isolate* isolate) const;
81 :
82 : size_t size() const { return backing_store_.size(); }
83 :
84 : private:
85 : ZoneDeque<uint8_t> backing_store_;
86 : };
87 :
88 : // Create a ProducedPreParsedScopeData object which will collect data as we
89 : // parse.
90 : ProducedPreParsedScopeData(Zone* zone, ProducedPreParsedScopeData* parent);
91 :
92 : // Create a ProducedPreParsedScopeData which is just a proxy for a previous
93 : // produced PreParsedScopeData.
94 : ProducedPreParsedScopeData(Handle<PreParsedScopeData> data, Zone* zone);
95 :
96 : ProducedPreParsedScopeData* parent() const { return parent_; }
97 :
98 : // For gathering the inner function data and splitting it up according to the
99 : // laziness boundaries. Each lazy function gets its own
100 : // ProducedPreParsedScopeData, and so do all lazy functions inside it.
101 : class DataGatheringScope {
102 : public:
103 : DataGatheringScope(DeclarationScope* function_scope, PreParser* preparser);
104 : ~DataGatheringScope();
105 :
106 : void MarkFunctionAsSkippable(int end_position, int num_inner_functions);
107 :
108 : private:
109 : DeclarationScope* function_scope_;
110 : PreParser* preparser_;
111 : ProducedPreParsedScopeData* produced_preparsed_scope_data_;
112 :
113 : DISALLOW_COPY_AND_ASSIGN(DataGatheringScope);
114 : };
115 :
116 : // Saves the information needed for allocating the Scope's (and its
117 : // subscopes') variables.
118 : void SaveScopeAllocationData(DeclarationScope* scope);
119 :
120 : // In some cases, PreParser cannot produce the same Scope structure as
121 : // Parser. If it happens, we're unable to produce the data that would enable
122 : // skipping the inner functions of that function.
123 : void Bailout() {
124 59 : bailed_out_ = true;
125 :
126 : // We don't need to call Bailout on existing / future children: the only way
127 : // to try to retrieve their data is through calling Serialize on the parent,
128 : // and if the parent is bailed out, it won't call Serialize on its children.
129 : }
130 :
131 : bool bailed_out() const { return bailed_out_; }
132 :
133 : #ifdef DEBUG
134 : bool ThisOrParentBailedOut() const {
135 : if (bailed_out_) {
136 : return true;
137 : }
138 : if (parent_ == nullptr) {
139 : return false;
140 : }
141 : return parent_->ThisOrParentBailedOut();
142 : }
143 : #endif // DEBUG
144 :
145 : bool ContainsInnerFunctions() const;
146 :
147 : // If there is data (if the Scope contains skippable inner functions), move
148 : // the data into the heap and return a Handle to it; otherwise return a null
149 : // MaybeHandle.
150 : MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) const;
151 :
152 : static bool ScopeNeedsData(Scope* scope);
153 : static bool ScopeIsSkippableFunctionScope(Scope* scope);
154 :
155 : private:
156 : void AddSkippableFunction(int start_position, int end_position,
157 : int num_parameters, int num_inner_functions,
158 : LanguageMode language_mode,
159 : bool uses_super_property);
160 :
161 : void SaveDataForScope(Scope* scope);
162 : void SaveDataForVariable(Variable* var);
163 : void SaveDataForInnerScopes(Scope* scope);
164 :
165 : ProducedPreParsedScopeData* parent_;
166 :
167 : ByteData* byte_data_;
168 : ZoneDeque<ProducedPreParsedScopeData*> data_for_inner_functions_;
169 :
170 : // Whether we've given up producing the data for this function.
171 : bool bailed_out_;
172 :
173 : // ProducedPreParsedScopeData can also mask a Handle<PreParsedScopeData>
174 : // which was produced already earlier. This happens for deeper lazy functions.
175 : Handle<PreParsedScopeData> previously_produced_preparsed_scope_data_;
176 :
177 : DISALLOW_COPY_AND_ASSIGN(ProducedPreParsedScopeData);
178 : };
179 :
180 : class ConsumedPreParsedScopeData {
181 : public:
182 : class ByteData {
183 : public:
184 2806601 : ByteData() : data_(nullptr), index_(0) {}
185 :
186 : // Reading from the ByteData is only allowed when a ReadingScope is on the
187 : // stack. This ensures that we have a DisallowHeapAllocation in place
188 : // whenever ByteData holds a raw pointer into the heap.
189 : class ReadingScope {
190 : public:
191 : ReadingScope(ByteData* consumed_data, PodArray<uint8_t>* data)
192 0 : : consumed_data_(consumed_data) {
193 87364 : consumed_data->data_ = data;
194 : }
195 : explicit ReadingScope(ConsumedPreParsedScopeData* parent);
196 87364 : ~ReadingScope() { consumed_data_->data_ = nullptr; }
197 :
198 : private:
199 : ByteData* consumed_data_;
200 : DisallowHeapAllocation no_gc;
201 : };
202 :
203 68462 : void SetPosition(int position) { index_ = position; }
204 :
205 : int32_t ReadUint32();
206 : uint8_t ReadUint8();
207 :
208 : size_t RemainingBytes() const {
209 : DCHECK_NOT_NULL(data_);
210 35336 : return data_->length() - index_;
211 : }
212 :
213 : // private:
214 : PodArray<uint8_t>* data_;
215 : int index_;
216 : };
217 :
218 : ConsumedPreParsedScopeData();
219 : ~ConsumedPreParsedScopeData();
220 :
221 : void SetData(Handle<PreParsedScopeData> data);
222 :
223 : bool HasData() const { return !data_.is_null(); }
224 :
225 : ProducedPreParsedScopeData* GetDataForSkippableFunction(
226 : Zone* zone, int start_position, int* end_position, int* num_parameters,
227 : int* num_inner_functions, bool* uses_super_property,
228 : LanguageMode* language_mode);
229 :
230 : // Restores the information needed for allocating the Scope's (and its
231 : // subscopes') variables.
232 : void RestoreScopeAllocationData(DeclarationScope* scope);
233 :
234 : // Skips the data about skippable functions, moves straight to the scope
235 : // allocation data. Useful for tests which don't want to verify only the scope
236 : // allocation data.
237 : void SkipFunctionDataForTesting();
238 :
239 : private:
240 : void RestoreData(Scope* scope);
241 : void RestoreDataForVariable(Variable* var);
242 : void RestoreDataForInnerScopes(Scope* scope);
243 :
244 : Handle<PreParsedScopeData> data_;
245 : std::unique_ptr<ByteData> scope_data_;
246 : // When consuming the data, these indexes point to the data we're going to
247 : // consume next.
248 : int child_index_;
249 :
250 : DISALLOW_COPY_AND_ASSIGN(ConsumedPreParsedScopeData);
251 : };
252 :
253 : } // namespace internal
254 : } // namespace v8
255 :
256 : #endif // V8_PARSING_PREPARSED_SCOPE_DATA_H_
|