• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/zone/zone-chunk-list.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 template <typename T>
21 class Handle;
22 
23 class PreParser;
24 class PreParsedScopeData;
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   ProducedPreParsedScopeData implements storing the above mentioned data and
61   ConsumedPreParsedScopeData 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 class ProducedPreParsedScopeData : public ZoneObject {
68  public:
69   class ByteData : public ZoneObject {
70    public:
ByteData(Zone * zone)71     explicit ByteData(Zone* zone)
72         : backing_store_(zone), free_quarters_in_last_byte_(0) {}
73 
74     void WriteUint32(uint32_t data);
75     void WriteUint8(uint8_t data);
76     void WriteQuarter(uint8_t data);
77 
78 #ifdef DEBUG
79     // For overwriting previously written data at position 0.
80     void OverwriteFirstUint32(uint32_t data);
81 #endif
82 
83     Handle<PodArray<uint8_t>> Serialize(Isolate* isolate);
84 
size()85     size_t size() const { return backing_store_.size(); }
86 
87    private:
88     ZoneChunkList<uint8_t> backing_store_;
89     uint8_t free_quarters_in_last_byte_;
90   };
91 
92   // Create a ProducedPreParsedScopeData object which will collect data as we
93   // parse.
94   ProducedPreParsedScopeData(Zone* zone, ProducedPreParsedScopeData* parent);
95 
96   // Create a ProducedPreParsedScopeData which is just a proxy for a previous
97   // produced PreParsedScopeData.
98   ProducedPreParsedScopeData(Handle<PreParsedScopeData> data, Zone* zone);
99 
parent()100   ProducedPreParsedScopeData* 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   // ProducedPreParsedScopeData, and so do all lazy functions inside it.
105   class DataGatheringScope {
106    public:
107     DataGatheringScope(DeclarationScope* function_scope, PreParser* preparser);
108     ~DataGatheringScope();
109 
110     void MarkFunctionAsSkippable(int end_position, int num_inner_functions);
111 
112    private:
113     DeclarationScope* function_scope_;
114     PreParser* preparser_;
115     ProducedPreParsedScopeData* produced_preparsed_scope_data_;
116 
117     DISALLOW_COPY_AND_ASSIGN(DataGatheringScope);
118   };
119 
120   // Saves the information needed for allocating the Scope's (and its
121   // subscopes') variables.
122   void SaveScopeAllocationData(DeclarationScope* scope);
123 
124   // In some cases, PreParser cannot produce the same Scope structure as
125   // Parser. If it happens, we're unable to produce the data that would enable
126   // skipping the inner functions of that function.
Bailout()127   void Bailout() {
128     bailed_out_ = true;
129 
130     // We don't need to call Bailout on existing / future children: the only way
131     // to try to retrieve their data is through calling Serialize on the parent,
132     // and if the parent is bailed out, it won't call Serialize on its children.
133   }
134 
bailed_out()135   bool bailed_out() const { return bailed_out_; }
136 
137 #ifdef DEBUG
ThisOrParentBailedOut()138   bool ThisOrParentBailedOut() const {
139     if (bailed_out_) {
140       return true;
141     }
142     if (parent_ == nullptr) {
143       return false;
144     }
145     return parent_->ThisOrParentBailedOut();
146   }
147 #endif  // DEBUG
148 
149   bool ContainsInnerFunctions() const;
150 
151   // If there is data (if the Scope contains skippable inner functions), move
152   // the data into the heap and return a Handle to it; otherwise return a null
153   // MaybeHandle.
154   MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate);
155 
156   static bool ScopeNeedsData(Scope* scope);
157   static bool ScopeIsSkippableFunctionScope(Scope* scope);
158 
159  private:
160   void AddSkippableFunction(int start_position, int end_position,
161                             int num_parameters, int num_inner_functions,
162                             LanguageMode language_mode,
163                             bool uses_super_property);
164 
165   void SaveDataForScope(Scope* scope);
166   void SaveDataForVariable(Variable* var);
167   void SaveDataForInnerScopes(Scope* scope);
168 
169   ProducedPreParsedScopeData* parent_;
170 
171   ByteData* byte_data_;
172   ZoneChunkList<ProducedPreParsedScopeData*> data_for_inner_functions_;
173 
174   // Whether we've given up producing the data for this function.
175   bool bailed_out_;
176 
177   // ProducedPreParsedScopeData can also mask a Handle<PreParsedScopeData>
178   // which was produced already earlier. This happens for deeper lazy functions.
179   Handle<PreParsedScopeData> previously_produced_preparsed_scope_data_;
180 
181   DISALLOW_COPY_AND_ASSIGN(ProducedPreParsedScopeData);
182 };
183 
184 class ConsumedPreParsedScopeData {
185  public:
186   class ByteData {
187    public:
ByteData()188     ByteData()
189         : data_(nullptr), index_(0), stored_quarters_(0), stored_byte_(0) {}
190 
191     // Reading from the ByteData is only allowed when a ReadingScope is on the
192     // stack. This ensures that we have a DisallowHeapAllocation in place
193     // whenever ByteData holds a raw pointer into the heap.
194     class ReadingScope {
195      public:
ReadingScope(ByteData * consumed_data,PodArray<uint8_t> * data)196       ReadingScope(ByteData* consumed_data, PodArray<uint8_t>* data)
197           : consumed_data_(consumed_data) {
198         consumed_data->data_ = data;
199       }
200       explicit ReadingScope(ConsumedPreParsedScopeData* parent);
~ReadingScope()201       ~ReadingScope() { consumed_data_->data_ = nullptr; }
202 
203      private:
204       ByteData* consumed_data_;
205       DisallowHeapAllocation no_gc;
206     };
207 
SetPosition(int position)208     void SetPosition(int position) { index_ = position; }
209 
210     int32_t ReadUint32();
211     uint8_t ReadUint8();
212     uint8_t ReadQuarter();
213 
214     size_t RemainingBytes() const;
215 
216     // private:
217     PodArray<uint8_t>* data_;
218     int index_;
219     uint8_t stored_quarters_;
220     uint8_t stored_byte_;
221   };
222 
223   ConsumedPreParsedScopeData();
224   ~ConsumedPreParsedScopeData();
225 
226   void SetData(Isolate* isolate, Handle<PreParsedScopeData> data);
227 
HasData()228   bool HasData() const { return !data_.is_null(); }
229 
230   ProducedPreParsedScopeData* GetDataForSkippableFunction(
231       Zone* zone, int start_position, int* end_position, int* num_parameters,
232       int* num_inner_functions, bool* uses_super_property,
233       LanguageMode* language_mode);
234 
235   // Restores the information needed for allocating the Scope's (and its
236   // subscopes') variables.
237   void RestoreScopeAllocationData(DeclarationScope* scope);
238 
239  private:
240   void RestoreData(Scope* scope);
241   void RestoreDataForVariable(Variable* var);
242   void RestoreDataForInnerScopes(Scope* scope);
243 
244   Isolate* isolate_;
245   Handle<PreParsedScopeData> data_;
246   std::unique_ptr<ByteData> scope_data_;
247   // When consuming the data, these indexes point to the data we're going to
248   // consume next.
249   int child_index_;
250 
251   DISALLOW_COPY_AND_ASSIGN(ConsumedPreParsedScopeData);
252 };
253 
254 }  // namespace internal
255 }  // namespace v8
256 
257 #endif  // V8_PARSING_PREPARSED_SCOPE_DATA_H_
258