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_PREPARSE_DATA_H_
6 : #define V8_PARSING_PREPARSE_DATA_H_
7 :
8 : #include "src/globals.h"
9 : #include "src/handles.h"
10 : #include "src/maybe-handles.h"
11 : #include "src/zone/zone-chunk-list.h"
12 : #include "src/zone/zone-containers.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 : template <typename T>
18 : class PodArray;
19 :
20 : class Parser;
21 : class PreParser;
22 : class PreparseData;
23 : class ZonePreparseData;
24 :
25 : /*
26 :
27 : Skipping inner functions.
28 :
29 : Consider the following code:
30 : (function eager_outer() {
31 : function lazy_inner() {
32 : let a;
33 : function skip_me() { a; }
34 : }
35 :
36 : return lazy_inner;
37 : })();
38 :
39 : ... lazy_inner(); ...
40 :
41 : When parsing the code the first time, eager_outer is parsed and lazy_inner
42 : (and everything inside it) is preparsed. When lazy_inner is called, we don't
43 : want to parse or preparse skip_me again. Instead, we want to skip over it,
44 : since it has already been preparsed once.
45 :
46 : In order to be able to do this, we need to store the information needed for
47 : allocating the variables in lazy_inner when we preparse it, and then later do
48 : scope allocation based on that data.
49 :
50 : We need the following data for each scope in lazy_inner's scope tree:
51 : For each Variable:
52 : - is_used
53 : - maybe_assigned
54 : - has_forced_context_allocation
55 :
56 : For each Scope:
57 : - inner_scope_calls_eval_.
58 :
59 : ProducedPreparseData implements storing the above mentioned data and
60 : ConsumedPreparseData implements restoring it (= setting the context
61 : allocation status of the variables in a Scope (and its subscopes) based on the
62 : data).
63 :
64 : */
65 :
66 : struct PreparseByteDataConstants {
67 : #ifdef DEBUG
68 : static constexpr int kMagicValue = 0xC0DE0DE;
69 :
70 : static constexpr size_t kUint32Size = 5;
71 : static constexpr size_t kVarint32MinSize = 3;
72 : static constexpr size_t kVarint32MaxSize = 7;
73 : static constexpr size_t kVarint32EndMarker = 0xF1;
74 : static constexpr size_t kUint8Size = 2;
75 : static constexpr size_t kQuarterMarker = 0xF2;
76 : static constexpr size_t kPlaceholderSize = kUint32Size;
77 : #else
78 : static constexpr size_t kUint32Size = 4;
79 : static constexpr size_t kVarint32MinSize = 1;
80 : static constexpr size_t kVarint32MaxSize = 5;
81 : static constexpr size_t kUint8Size = 1;
82 : static constexpr size_t kPlaceholderSize = 0;
83 : #endif
84 :
85 : static const size_t kSkippableFunctionMinDataSize =
86 : 4 * kVarint32MinSize + 1 * kUint8Size;
87 : static const size_t kSkippableFunctionMaxDataSize =
88 : 4 * kVarint32MaxSize + 1 * kUint8Size;
89 : };
90 :
91 : class PreparseDataBuilder : public ZoneObject,
92 : public PreparseByteDataConstants {
93 : public:
94 : // Create a PreparseDataBuilder object which will collect data as we
95 : // parse.
96 : explicit PreparseDataBuilder(Zone* zone, PreparseDataBuilder* parent_builder,
97 : std::vector<void*>* children_buffer);
98 : ~PreparseDataBuilder() {}
99 :
100 : PreparseDataBuilder* parent() const { return parent_; }
101 :
102 : // For gathering the inner function data and splitting it up according to the
103 : // laziness boundaries. Each lazy function gets its own
104 : // ProducedPreparseData, and so do all lazy functions inside it.
105 : class DataGatheringScope {
106 : public:
107 : explicit DataGatheringScope(PreParser* preparser)
108 2931713 : : preparser_(preparser), builder_(nullptr) {}
109 :
110 : void Start(DeclarationScope* function_scope);
111 : void SetSkippableFunction(DeclarationScope* function_scope,
112 : int num_inner_functions);
113 : inline ~DataGatheringScope() {
114 2931830 : if (builder_ == nullptr) return;
115 2626862 : Close();
116 : }
117 :
118 : private:
119 : void Close();
120 :
121 : PreParser* preparser_;
122 : PreparseDataBuilder* builder_;
123 :
124 : DISALLOW_COPY_AND_ASSIGN(DataGatheringScope);
125 : };
126 :
127 : class ByteData : public ZoneObject, public PreparseByteDataConstants {
128 : public:
129 : ByteData()
130 2626690 : : byte_data_(nullptr), index_(0), free_quarters_in_last_byte_(0) {}
131 :
132 : ~ByteData() {}
133 :
134 : void Start(std::vector<uint8_t>* buffer);
135 : void Finalize(Zone* zone);
136 :
137 : Handle<PreparseData> CopyToHeap(Isolate* isolate, int children_length);
138 : inline ZonePreparseData* CopyToZone(Zone* zone, int children_length);
139 :
140 : void Reserve(size_t bytes);
141 : void Add(uint8_t byte);
142 : int length() const;
143 :
144 : void WriteVarint32(uint32_t data);
145 : void WriteUint8(uint8_t data);
146 : void WriteQuarter(uint8_t data);
147 :
148 : #ifdef DEBUG
149 : void WriteUint32(uint32_t data);
150 : // For overwriting previously written data at position 0.
151 : void SaveCurrentSizeAtFirstUint32();
152 : #endif
153 :
154 : private:
155 : union {
156 : struct {
157 : // Only used during construction (is_finalized_ == false).
158 : std::vector<uint8_t>* byte_data_;
159 : int index_;
160 : };
161 : // Once the data is finalized, it lives in a Zone, this implies
162 : // is_finalized_ == true.
163 : Vector<uint8_t> zone_byte_data_;
164 : };
165 : uint8_t free_quarters_in_last_byte_;
166 :
167 : #ifdef DEBUG
168 : bool is_finalized_ = false;
169 : #endif
170 : };
171 :
172 : // Saves the information needed for allocating the Scope's (and its
173 : // subscopes') variables.
174 : void SaveScopeAllocationData(DeclarationScope* scope, Parser* parser);
175 :
176 : // In some cases, PreParser cannot produce the same Scope structure as
177 : // Parser. If it happens, we're unable to produce the data that would enable
178 : // skipping the inner functions of that function.
179 : void Bailout() {
180 63 : bailed_out_ = true;
181 : // We don't need to call Bailout on existing / future children: the only way
182 : // to try to retrieve their data is through calling Serialize on the parent,
183 : // and if the parent is bailed out, it won't call Serialize on its children.
184 : }
185 :
186 : bool bailed_out() const { return bailed_out_; }
187 :
188 : #ifdef DEBUG
189 : bool ThisOrParentBailedOut() const {
190 : if (bailed_out_) return true;
191 : if (parent_ == nullptr) return false;
192 : return parent_->ThisOrParentBailedOut();
193 : }
194 : #endif // DEBUG
195 :
196 : bool HasInnerFunctions() const;
197 : bool HasData() const;
198 : bool HasDataForParent() const;
199 :
200 : static bool ScopeNeedsData(Scope* scope);
201 : void AddSkippableFunction(int start_position, int end_position,
202 : int num_parameters, int num_inner_functions,
203 : LanguageMode language_mode, bool has_data,
204 : bool uses_super_property);
205 :
206 : private:
207 : friend class BuilderProducedPreparseData;
208 :
209 : Handle<PreparseData> Serialize(Isolate* isolate);
210 : ZonePreparseData* Serialize(Zone* zone);
211 :
212 : void FinalizeChildren(Zone* zone);
213 : void AddChild(PreparseDataBuilder* child);
214 :
215 : void SaveDataForScope(Scope* scope);
216 : void SaveDataForVariable(Variable* var);
217 : void SaveDataForInnerScopes(Scope* scope);
218 : bool SaveDataForSkippableFunction(PreparseDataBuilder* builder);
219 :
220 : void CopyByteData(Zone* zone);
221 :
222 : PreparseDataBuilder* parent_;
223 : ByteData byte_data_;
224 : union {
225 : ScopedPtrList<PreparseDataBuilder> children_buffer_;
226 : Vector<PreparseDataBuilder*> children_;
227 : };
228 :
229 : DeclarationScope* function_scope_;
230 : int num_inner_functions_;
231 : int num_inner_with_data_;
232 :
233 : // Whether we've given up producing the data for this function.
234 : bool bailed_out_ : 1;
235 : bool has_data_ : 1;
236 :
237 : #ifdef DEBUG
238 : bool finalized_children_ = false;
239 : #endif
240 :
241 : DISALLOW_COPY_AND_ASSIGN(PreparseDataBuilder);
242 : };
243 :
244 87264 : class ProducedPreparseData : public ZoneObject {
245 : public:
246 : // If there is data (if the Scope contains skippable inner functions), move
247 : // the data into the heap and return a Handle to it; otherwise return a null
248 : // MaybeHandle.
249 : virtual Handle<PreparseData> Serialize(Isolate* isolate) = 0;
250 :
251 : // If there is data (if the Scope contains skippable inner functions), return
252 : // an off-heap ZonePreparseData representing the data; otherwise
253 : // return nullptr.
254 : virtual ZonePreparseData* Serialize(Zone* zone) = 0;
255 :
256 : // Create a ProducedPreparseData which is a proxy for a previous
257 : // produced PreparseData in zone.
258 : static ProducedPreparseData* For(PreparseDataBuilder* builder, Zone* zone);
259 :
260 : // Create a ProducedPreparseData which is a proxy for a previous
261 : // produced PreparseData on the heap.
262 : static ProducedPreparseData* For(Handle<PreparseData> data, Zone* zone);
263 :
264 : // Create a ProducedPreparseData which is a proxy for a previous
265 : // produced PreparseData in zone.
266 : static ProducedPreparseData* For(ZonePreparseData* data, Zone* zone);
267 : };
268 :
269 : class ConsumedPreparseData {
270 : public:
271 : // Creates a ConsumedPreparseData representing the data of an on-heap
272 : // PreparseData |data|.
273 : static std::unique_ptr<ConsumedPreparseData> For(Isolate* isolate,
274 : Handle<PreparseData> data);
275 :
276 : // Creates a ConsumedPreparseData representing the data of an off-heap
277 : // ZonePreparseData |data|.
278 : static std::unique_ptr<ConsumedPreparseData> For(Zone* zone,
279 : ZonePreparseData* data);
280 :
281 36574 : virtual ~ConsumedPreparseData() = default;
282 :
283 : virtual ProducedPreparseData* GetDataForSkippableFunction(
284 : Zone* zone, int start_position, int* end_position, int* num_parameters,
285 : int* num_inner_functions, bool* uses_super_property,
286 : LanguageMode* language_mode) = 0;
287 :
288 : // Restores the information needed for allocating the Scope's (and its
289 : // subscopes') variables.
290 : virtual void RestoreScopeAllocationData(DeclarationScope* scope) = 0;
291 :
292 : protected:
293 36574 : ConsumedPreparseData() = default;
294 :
295 : private:
296 : DISALLOW_COPY_AND_ASSIGN(ConsumedPreparseData);
297 : };
298 :
299 : } // namespace internal
300 : } // namespace v8
301 :
302 : #endif // V8_PARSING_PREPARSE_DATA_H_
|