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