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