LCOV - code coverage report
Current view: top level - src/parsing - preparsed-scope-data.h (source / functions) Hit Total Coverage
Test: app.info Lines: 6 7 85.7 %
Date: 2017-10-20 Functions: 0 0 -

          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_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/parsing/preparse-data.h"
      16             : #include "src/zone/zone-containers.h"
      17             : 
      18             : namespace v8 {
      19             : namespace internal {
      20             : 
      21             : template <typename T>
      22             : class Handle;
      23             : 
      24             : class PreParser;
      25             : class PreParsedScopeData;
      26             : 
      27             : /*
      28             : 
      29             :   Skipping inner functions.
      30             : 
      31             :   Consider the following code:
      32             :   (function eager_outer() {
      33             :     function lazy_inner() {
      34             :       let a;
      35             :       function skip_me() { a; }
      36             :     }
      37             : 
      38             :     return lazy_inner;
      39             :   })();
      40             : 
      41             :   ... lazy_inner(); ...
      42             : 
      43             :   When parsing the code the first time, eager_outer is parsed and lazy_inner
      44             :   (and everything inside it) is preparsed. When lazy_inner is called, we don't
      45             :   want to parse or preparse skip_me again. Instead, we want to skip over it,
      46             :   since it has already been preparsed once.
      47             : 
      48             :   In order to be able to do this, we need to store the information needed for
      49             :   allocating the variables in lazy_inner when we preparse it, and then later do
      50             :   scope allocation based on that data.
      51             : 
      52             :   We need the following data for each scope in lazy_inner's scope tree:
      53             :   For each Variable:
      54             :   - is_used
      55             :   - maybe_assigned
      56             :   - has_forced_context_allocation
      57             : 
      58             :   For each Scope:
      59             :   - inner_scope_calls_eval_.
      60             : 
      61             :   ProducedPreParsedScopeData implements storing the above mentioned data and
      62             :   ConsumedPreParsedScopeData implements restoring it (= setting the context
      63             :   allocation status of the variables in a Scope (and its subscopes) based on the
      64             :   data).
      65             : 
      66             :  */
      67             : 
      68             : class ProducedPreParsedScopeData : public ZoneObject {
      69             :  public:
      70             :   class ByteData : public ZoneObject {
      71             :    public:
      72             :     explicit ByteData(Zone* zone) : backing_store_(zone) {}
      73             : 
      74             :     void WriteUint32(uint32_t data);
      75             :     void WriteUint8(uint8_t data);
      76             : 
      77             :     // For overwriting previously written data at position 0.
      78             :     void OverwriteFirstUint32(uint32_t data);
      79             : 
      80             :     Handle<PodArray<uint8_t>> Serialize(Isolate* isolate) const;
      81             : 
      82             :     size_t size() const { return backing_store_.size(); }
      83             : 
      84             :    private:
      85             :     ZoneDeque<uint8_t> backing_store_;
      86             :   };
      87             : 
      88             :   // Create a ProducedPreParsedScopeData object which will collect data as we
      89             :   // parse.
      90             :   ProducedPreParsedScopeData(Zone* zone, ProducedPreParsedScopeData* parent);
      91             : 
      92             :   // Create a ProducedPreParsedScopeData which is just a proxy for a previous
      93             :   // produced PreParsedScopeData.
      94             :   ProducedPreParsedScopeData(Handle<PreParsedScopeData> data, Zone* zone);
      95             : 
      96             :   ProducedPreParsedScopeData* parent() const { return parent_; }
      97             : 
      98             :   // For gathering the inner function data and splitting it up according to the
      99             :   // laziness boundaries. Each lazy function gets its own
     100             :   // ProducedPreParsedScopeData, and so do all lazy functions inside it.
     101             :   class DataGatheringScope {
     102             :    public:
     103             :     DataGatheringScope(DeclarationScope* function_scope, PreParser* preparser);
     104             :     ~DataGatheringScope();
     105             : 
     106             :     void MarkFunctionAsSkippable(int end_position, int num_inner_functions);
     107             : 
     108             :    private:
     109             :     DeclarationScope* function_scope_;
     110             :     PreParser* preparser_;
     111             :     ProducedPreParsedScopeData* produced_preparsed_scope_data_;
     112             : 
     113             :     DISALLOW_COPY_AND_ASSIGN(DataGatheringScope);
     114             :   };
     115             : 
     116             :   // Saves the information needed for allocating the Scope's (and its
     117             :   // subscopes') variables.
     118             :   void SaveScopeAllocationData(DeclarationScope* scope);
     119             : 
     120             :   // In some cases, PreParser cannot produce the same Scope structure as
     121             :   // Parser. If it happens, we're unable to produce the data that would enable
     122             :   // skipping the inner functions of that function.
     123             :   void Bailout() {
     124          59 :     bailed_out_ = true;
     125             : 
     126             :     // We don't need to call Bailout on existing / future children: the only way
     127             :     // to try to retrieve their data is through calling Serialize on the parent,
     128             :     // and if the parent is bailed out, it won't call Serialize on its children.
     129             :   }
     130             : 
     131             :   bool bailed_out() const { return bailed_out_; }
     132             : 
     133             : #ifdef DEBUG
     134             :   bool ThisOrParentBailedOut() const {
     135             :     if (bailed_out_) {
     136             :       return true;
     137             :     }
     138             :     if (parent_ == nullptr) {
     139             :       return false;
     140             :     }
     141             :     return parent_->ThisOrParentBailedOut();
     142             :   }
     143             : #endif  // DEBUG
     144             : 
     145             :   bool ContainsInnerFunctions() const;
     146             : 
     147             :   // If there is data (if the Scope contains skippable inner functions), move
     148             :   // the data into the heap and return a Handle to it; otherwise return a null
     149             :   // MaybeHandle.
     150             :   MaybeHandle<PreParsedScopeData> Serialize(Isolate* isolate) const;
     151             : 
     152             :   static bool ScopeNeedsData(Scope* scope);
     153             :   static bool ScopeIsSkippableFunctionScope(Scope* scope);
     154             : 
     155             :  private:
     156             :   void AddSkippableFunction(int start_position, int end_position,
     157             :                             int num_parameters, int num_inner_functions,
     158             :                             LanguageMode language_mode,
     159             :                             bool uses_super_property);
     160             : 
     161             :   void SaveDataForScope(Scope* scope);
     162             :   void SaveDataForVariable(Variable* var);
     163             :   void SaveDataForInnerScopes(Scope* scope);
     164             : 
     165             :   ProducedPreParsedScopeData* parent_;
     166             : 
     167             :   ByteData* byte_data_;
     168             :   ZoneDeque<ProducedPreParsedScopeData*> data_for_inner_functions_;
     169             : 
     170             :   // Whether we've given up producing the data for this function.
     171             :   bool bailed_out_;
     172             : 
     173             :   // ProducedPreParsedScopeData can also mask a Handle<PreParsedScopeData>
     174             :   // which was produced already earlier. This happens for deeper lazy functions.
     175             :   Handle<PreParsedScopeData> previously_produced_preparsed_scope_data_;
     176             : 
     177             :   DISALLOW_COPY_AND_ASSIGN(ProducedPreParsedScopeData);
     178             : };
     179             : 
     180             : class ConsumedPreParsedScopeData {
     181             :  public:
     182             :   class ByteData {
     183             :    public:
     184     2806601 :     ByteData() : data_(nullptr), index_(0) {}
     185             : 
     186             :     // Reading from the ByteData is only allowed when a ReadingScope is on the
     187             :     // stack. This ensures that we have a DisallowHeapAllocation in place
     188             :     // whenever ByteData holds a raw pointer into the heap.
     189             :     class ReadingScope {
     190             :      public:
     191             :       ReadingScope(ByteData* consumed_data, PodArray<uint8_t>* data)
     192           0 :           : consumed_data_(consumed_data) {
     193       87364 :         consumed_data->data_ = data;
     194             :       }
     195             :       explicit ReadingScope(ConsumedPreParsedScopeData* parent);
     196       87364 :       ~ReadingScope() { consumed_data_->data_ = nullptr; }
     197             : 
     198             :      private:
     199             :       ByteData* consumed_data_;
     200             :       DisallowHeapAllocation no_gc;
     201             :     };
     202             : 
     203       68462 :     void SetPosition(int position) { index_ = position; }
     204             : 
     205             :     int32_t ReadUint32();
     206             :     uint8_t ReadUint8();
     207             : 
     208             :     size_t RemainingBytes() const {
     209             :       DCHECK_NOT_NULL(data_);
     210       35336 :       return data_->length() - index_;
     211             :     }
     212             : 
     213             :     // private:
     214             :     PodArray<uint8_t>* data_;
     215             :     int index_;
     216             :   };
     217             : 
     218             :   ConsumedPreParsedScopeData();
     219             :   ~ConsumedPreParsedScopeData();
     220             : 
     221             :   void SetData(Handle<PreParsedScopeData> data);
     222             : 
     223             :   bool HasData() const { return !data_.is_null(); }
     224             : 
     225             :   ProducedPreParsedScopeData* GetDataForSkippableFunction(
     226             :       Zone* zone, int start_position, int* end_position, int* num_parameters,
     227             :       int* num_inner_functions, bool* uses_super_property,
     228             :       LanguageMode* language_mode);
     229             : 
     230             :   // Restores the information needed for allocating the Scope's (and its
     231             :   // subscopes') variables.
     232             :   void RestoreScopeAllocationData(DeclarationScope* scope);
     233             : 
     234             :   // Skips the data about skippable functions, moves straight to the scope
     235             :   // allocation data. Useful for tests which don't want to verify only the scope
     236             :   // allocation data.
     237             :   void SkipFunctionDataForTesting();
     238             : 
     239             :  private:
     240             :   void RestoreData(Scope* scope);
     241             :   void RestoreDataForVariable(Variable* var);
     242             :   void RestoreDataForInnerScopes(Scope* scope);
     243             : 
     244             :   Handle<PreParsedScopeData> data_;
     245             :   std::unique_ptr<ByteData> scope_data_;
     246             :   // When consuming the data, these indexes point to the data we're going to
     247             :   // consume next.
     248             :   int child_index_;
     249             : 
     250             :   DISALLOW_COPY_AND_ASSIGN(ConsumedPreParsedScopeData);
     251             : };
     252             : 
     253             : }  // namespace internal
     254             : }  // namespace v8
     255             : 
     256             : #endif  // V8_PARSING_PREPARSED_SCOPE_DATA_H_

Generated by: LCOV version 1.10