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 kUint8Size = 2;
72 : static constexpr size_t kQuarterMarker = 0;
73 : static constexpr size_t kPlaceholderSize = kUint32Size;
74 : #else
75 : static constexpr size_t kUint32Size = 4;
76 : static constexpr size_t kUint8Size = 1;
77 : static constexpr size_t kPlaceholderSize = 0;
78 : #endif
79 :
80 : static const size_t kSkippableFunctionDataSize =
81 : 4 * kUint32Size + 1 * kUint8Size;
82 : };
83 :
84 : class PreparseDataBuilder : public ZoneObject,
85 : public PreparseByteDataConstants {
86 : public:
87 : // Create a PreparseDataBuilder object which will collect data as we
88 : // parse.
89 : explicit PreparseDataBuilder(Zone* zone, PreparseDataBuilder* parent_builder);
90 :
91 : PreparseDataBuilder* parent() const { return parent_; }
92 :
93 : // For gathering the inner function data and splitting it up according to the
94 : // laziness boundaries. Each lazy function gets its own
95 : // ProducedPreparseData, and so do all lazy functions inside it.
96 : class DataGatheringScope {
97 : public:
98 : explicit DataGatheringScope(PreParser* preparser)
99 2866312 : : preparser_(preparser), builder_(nullptr) {}
100 :
101 : void Start(DeclarationScope* function_scope);
102 : void SetSkippableFunction(DeclarationScope* function_scope,
103 : int num_inner_functions);
104 : ~DataGatheringScope();
105 :
106 : private:
107 : PreParser* preparser_;
108 : PreparseDataBuilder* builder_;
109 :
110 : DISALLOW_COPY_AND_ASSIGN(DataGatheringScope);
111 : };
112 :
113 : class ByteData : public ZoneObject, public PreparseByteDataConstants {
114 : public:
115 2567271 : ByteData() : byte_data_(nullptr), free_quarters_in_last_byte_(0) {}
116 :
117 : ~ByteData() {}
118 :
119 : void Start(std::vector<uint8_t>* buffer);
120 : void Finalize(Zone* zone);
121 :
122 : Handle<PreparseData> CopyToHeap(Isolate* isolate, int children_length);
123 : ZonePreparseData* CopyToZone(Zone* zone, int children_length);
124 :
125 : void WriteUint32(uint32_t data);
126 : void WriteUint8(uint8_t data);
127 : void WriteQuarter(uint8_t data);
128 :
129 : #ifdef DEBUG
130 : // For overwriting previously written data at position 0.
131 : void SaveCurrentSizeAtFirstUint32();
132 : int length() const;
133 : #endif
134 :
135 : private:
136 : union {
137 : // Only used during construction (is_finalized_ == false).
138 : std::vector<uint8_t>* byte_data_;
139 : // Once the data is finalized, it lives in a Zone, this implies
140 : // is_finalized_ == true.
141 : Vector<uint8_t> zone_byte_data_;
142 : };
143 : uint8_t free_quarters_in_last_byte_;
144 :
145 : #ifdef DEBUG
146 : bool is_finalized_ = false;
147 : #endif
148 : };
149 :
150 : // Saves the information needed for allocating the Scope's (and its
151 : // subscopes') variables.
152 : void SaveScopeAllocationData(DeclarationScope* scope, Parser* parser);
153 :
154 : // In some cases, PreParser cannot produce the same Scope structure as
155 : // Parser. If it happens, we're unable to produce the data that would enable
156 : // skipping the inner functions of that function.
157 : void Bailout() {
158 57 : bailed_out_ = true;
159 : // We don't need to call Bailout on existing / future children: the only way
160 : // to try to retrieve their data is through calling Serialize on the parent,
161 : // and if the parent is bailed out, it won't call Serialize on its children.
162 : }
163 :
164 : bool bailed_out() const { return bailed_out_; }
165 :
166 : #ifdef DEBUG
167 : bool ThisOrParentBailedOut() const {
168 : if (bailed_out_) return true;
169 : if (parent_ == nullptr) return false;
170 : return parent_->ThisOrParentBailedOut();
171 : }
172 : #endif // DEBUG
173 :
174 : bool HasInnerFunctions() const;
175 : bool HasData() const;
176 : bool HasDataForParent() const;
177 :
178 : static bool ScopeNeedsData(Scope* scope);
179 : static bool ScopeIsSkippableFunctionScope(Scope* scope);
180 : void AddSkippableFunction(int start_position, int end_position,
181 : int num_parameters, int num_inner_functions,
182 : LanguageMode language_mode, bool has_data,
183 : bool uses_super_property);
184 :
185 : private:
186 : friend class BuilderProducedPreparseData;
187 :
188 : Handle<PreparseData> Serialize(Isolate* isolate);
189 : ZonePreparseData* Serialize(Zone* zone);
190 :
191 : void SaveDataForScope(Scope* scope);
192 : void SaveDataForVariable(Variable* var);
193 : void SaveDataForInnerScopes(Scope* scope);
194 : bool SaveDataForSkippableFunction(PreparseDataBuilder* builder);
195 :
196 : void CopyByteData(Zone* zone);
197 :
198 : PreparseDataBuilder* parent_;
199 : ByteData byte_data_;
200 : ZoneChunkList<PreparseDataBuilder*> children_;
201 :
202 : DeclarationScope* function_scope_;
203 : int num_inner_functions_;
204 : int num_inner_with_data_;
205 :
206 : // Whether we've given up producing the data for this function.
207 : bool bailed_out_ : 1;
208 : bool has_data_ : 1;
209 :
210 : DISALLOW_COPY_AND_ASSIGN(PreparseDataBuilder);
211 : };
212 :
213 87237 : class ProducedPreparseData : public ZoneObject {
214 : public:
215 : // If there is data (if the Scope contains skippable inner functions), move
216 : // the data into the heap and return a Handle to it; otherwise return a null
217 : // MaybeHandle.
218 : virtual Handle<PreparseData> Serialize(Isolate* isolate) = 0;
219 :
220 : // If there is data (if the Scope contains skippable inner functions), return
221 : // an off-heap ZonePreparseData representing the data; otherwise
222 : // return nullptr.
223 : virtual ZonePreparseData* Serialize(Zone* zone) = 0;
224 :
225 : // Create a ProducedPreparseData which is a proxy for a previous
226 : // produced PreparseData in zone.
227 : static ProducedPreparseData* For(PreparseDataBuilder* builder, Zone* zone);
228 :
229 : // Create a ProducedPreparseData which is a proxy for a previous
230 : // produced PreparseData on the heap.
231 : static ProducedPreparseData* For(Handle<PreparseData> data, Zone* zone);
232 :
233 : // Create a ProducedPreparseData which is a proxy for a previous
234 : // produced PreparseData in zone.
235 : static ProducedPreparseData* For(ZonePreparseData* data, Zone* zone);
236 : };
237 :
238 : class ConsumedPreparseData {
239 : public:
240 : // Creates a ConsumedPreparseData representing the data of an on-heap
241 : // PreparseData |data|.
242 : static std::unique_ptr<ConsumedPreparseData> For(Isolate* isolate,
243 : Handle<PreparseData> data);
244 :
245 : // Creates a ConsumedPreparseData representing the data of an off-heap
246 : // ZonePreparseData |data|.
247 : static std::unique_ptr<ConsumedPreparseData> For(Zone* zone,
248 : ZonePreparseData* data);
249 :
250 37126 : virtual ~ConsumedPreparseData() = default;
251 :
252 : virtual ProducedPreparseData* GetDataForSkippableFunction(
253 : Zone* zone, int start_position, int* end_position, int* num_parameters,
254 : int* num_inner_functions, bool* uses_super_property,
255 : LanguageMode* language_mode) = 0;
256 :
257 : // Restores the information needed for allocating the Scope's (and its
258 : // subscopes') variables.
259 : virtual void RestoreScopeAllocationData(DeclarationScope* scope) = 0;
260 :
261 : protected:
262 37126 : ConsumedPreparseData() = default;
263 :
264 : private:
265 : DISALLOW_COPY_AND_ASSIGN(ConsumedPreparseData);
266 : };
267 :
268 : } // namespace internal
269 : } // namespace v8
270 :
271 : #endif // V8_PARSING_PREPARSE_DATA_H_
|