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