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 V8_EXPORT_PRIVATE 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 2991851 : : preparser_(preparser), builder_(nullptr) {}
110 :
111 : void Start(DeclarationScope* function_scope);
112 : void SetSkippableFunction(DeclarationScope* function_scope,
113 : int function_length, int num_inner_functions);
114 2681360 : inline ~DataGatheringScope() {
115 2991856 : if (builder_ == nullptr) return;
116 2681366 : 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 V8_EXPORT_PRIVATE ByteData : public ZoneObject,
129 : public PreparseByteDataConstants {
130 : public:
131 : ByteData()
132 2681358 : : byte_data_(nullptr), index_(0), free_quarters_in_last_byte_(0) {}
133 :
134 5 : ~ByteData() {}
135 :
136 : void Start(std::vector<uint8_t>* buffer);
137 : void Finalize(Zone* zone);
138 :
139 : Handle<PreparseData> CopyToHeap(Isolate* isolate, int children_length);
140 : inline ZonePreparseData* CopyToZone(Zone* zone, int children_length);
141 :
142 : void Reserve(size_t bytes);
143 : void Add(uint8_t byte);
144 : int length() const;
145 :
146 : void WriteVarint32(uint32_t data);
147 : void WriteUint8(uint8_t data);
148 : void WriteQuarter(uint8_t data);
149 :
150 : #ifdef DEBUG
151 : void WriteUint32(uint32_t data);
152 : // For overwriting previously written data at position 0.
153 : void SaveCurrentSizeAtFirstUint32();
154 : #endif
155 :
156 : private:
157 : union {
158 : struct {
159 : // Only used during construction (is_finalized_ == false).
160 : std::vector<uint8_t>* byte_data_;
161 : int index_;
162 : };
163 : // Once the data is finalized, it lives in a Zone, this implies
164 : // is_finalized_ == true.
165 : Vector<uint8_t> zone_byte_data_;
166 : };
167 : uint8_t free_quarters_in_last_byte_;
168 :
169 : #ifdef DEBUG
170 : bool is_finalized_ = false;
171 : #endif
172 : };
173 :
174 : // Saves the information needed for allocating the Scope's (and its
175 : // subscopes') variables.
176 : void SaveScopeAllocationData(DeclarationScope* scope, Parser* parser);
177 :
178 : // In some cases, PreParser cannot produce the same Scope structure as
179 : // Parser. If it happens, we're unable to produce the data that would enable
180 : // skipping the inner functions of that function.
181 : void Bailout() {
182 63 : bailed_out_ = true;
183 : // We don't need to call Bailout on existing / future children: the only way
184 : // to try to retrieve their data is through calling Serialize on the parent,
185 : // and if the parent is bailed out, it won't call Serialize on its children.
186 : }
187 :
188 : bool bailed_out() const { return bailed_out_; }
189 :
190 : #ifdef DEBUG
191 : bool ThisOrParentBailedOut() const {
192 : if (bailed_out_) return true;
193 : if (parent_ == nullptr) return false;
194 : return parent_->ThisOrParentBailedOut();
195 : }
196 : #endif // DEBUG
197 :
198 : bool HasInnerFunctions() const;
199 : bool HasData() const;
200 : bool HasDataForParent() const;
201 :
202 : static bool ScopeNeedsData(Scope* scope);
203 :
204 : private:
205 : friend class BuilderProducedPreparseData;
206 :
207 : Handle<PreparseData> Serialize(Isolate* isolate);
208 : ZonePreparseData* Serialize(Zone* zone);
209 :
210 : void FinalizeChildren(Zone* zone);
211 : void AddChild(PreparseDataBuilder* child);
212 :
213 : void SaveDataForScope(Scope* scope);
214 : void SaveDataForVariable(Variable* var);
215 : void SaveDataForInnerScopes(Scope* scope);
216 : bool SaveDataForSkippableFunction(PreparseDataBuilder* builder);
217 :
218 : void CopyByteData(Zone* zone);
219 :
220 : PreparseDataBuilder* parent_;
221 : ByteData byte_data_;
222 : union {
223 : ScopedPtrList<PreparseDataBuilder> children_buffer_;
224 : Vector<PreparseDataBuilder*> children_;
225 : };
226 :
227 : DeclarationScope* function_scope_;
228 : int function_length_;
229 : int num_inner_functions_;
230 : int num_inner_with_data_;
231 :
232 : // Whether we've given up producing the data for this function.
233 : bool bailed_out_ : 1;
234 : bool has_data_ : 1;
235 :
236 : #ifdef DEBUG
237 : bool finalized_children_ = false;
238 : #endif
239 :
240 : DISALLOW_COPY_AND_ASSIGN(PreparseDataBuilder);
241 : };
242 :
243 87801 : class ProducedPreparseData : public ZoneObject {
244 : public:
245 : // If there is data (if the Scope contains skippable inner functions), move
246 : // the data into the heap and return a Handle to it; otherwise return a null
247 : // MaybeHandle.
248 : virtual Handle<PreparseData> Serialize(Isolate* isolate) = 0;
249 :
250 : // If there is data (if the Scope contains skippable inner functions), return
251 : // an off-heap ZonePreparseData representing the data; otherwise
252 : // return nullptr.
253 : virtual ZonePreparseData* Serialize(Zone* zone) = 0;
254 :
255 : // Create a ProducedPreparseData which is a proxy for a previous
256 : // produced PreparseData in zone.
257 : static ProducedPreparseData* For(PreparseDataBuilder* builder, Zone* zone);
258 :
259 : // Create a ProducedPreparseData which is a proxy for a previous
260 : // produced PreparseData on the heap.
261 : static ProducedPreparseData* For(Handle<PreparseData> data, Zone* zone);
262 :
263 : // Create a ProducedPreparseData which is a proxy for a previous
264 : // produced PreparseData in zone.
265 : static ProducedPreparseData* For(ZonePreparseData* data, Zone* zone);
266 : };
267 :
268 : class ConsumedPreparseData {
269 : public:
270 : // Creates a ConsumedPreparseData representing the data of an on-heap
271 : // PreparseData |data|.
272 : V8_EXPORT_PRIVATE static std::unique_ptr<ConsumedPreparseData> For(
273 : Isolate* isolate, Handle<PreparseData> data);
274 :
275 : // Creates a ConsumedPreparseData representing the data of an off-heap
276 : // ZonePreparseData |data|.
277 : static std::unique_ptr<ConsumedPreparseData> For(Zone* zone,
278 : ZonePreparseData* data);
279 :
280 36778 : virtual ~ConsumedPreparseData() = default;
281 :
282 : virtual ProducedPreparseData* GetDataForSkippableFunction(
283 : Zone* zone, int start_position, int* end_position, int* num_parameters,
284 : int* function_length, int* num_inner_functions, bool* uses_super_property,
285 : LanguageMode* language_mode) = 0;
286 :
287 : // Restores the information needed for allocating the Scope's (and its
288 : // subscopes') variables.
289 : virtual void RestoreScopeAllocationData(DeclarationScope* scope) = 0;
290 :
291 : protected:
292 36778 : ConsumedPreparseData() = default;
293 :
294 : private:
295 : DISALLOW_COPY_AND_ASSIGN(ConsumedPreparseData);
296 : };
297 :
298 : } // namespace internal
299 : } // namespace v8
300 :
301 : #endif // V8_PARSING_PREPARSE_DATA_H_
|