preparse-data.h 9.3 KB
Newer Older
1 2 3 4
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef V8_PARSING_PREPARSE_DATA_H_
#define V8_PARSING_PREPARSE_DATA_H_
7

8 9
#include <memory>

10
#include "src/common/globals.h"
11 12
#include "src/handles/handles.h"
#include "src/handles/maybe-handles.h"
13
#include "src/utils/vector.h"
14
#include "src/zone/zone-chunk-list.h"
15
#include "src/zone/zone-containers.h"
16 17 18 19

namespace v8 {
namespace internal {

20
template <typename T>
21
class PodArray;
22

23
class Parser;
24
class PreParser;
25 26
class PreparseData;
class ZonePreparseData;
27
class AstValueFactory;
28

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/*

  Skipping inner functions.

  Consider the following code:
  (function eager_outer() {
    function lazy_inner() {
      let a;
      function skip_me() { a; }
    }

    return lazy_inner;
  })();

  ... lazy_inner(); ...

  When parsing the code the first time, eager_outer is parsed and lazy_inner
  (and everything inside it) is preparsed. When lazy_inner is called, we don't
  want to parse or preparse skip_me again. Instead, we want to skip over it,
  since it has already been preparsed once.

  In order to be able to do this, we need to store the information needed for
  allocating the variables in lazy_inner when we preparse it, and then later do
  scope allocation based on that data.

  We need the following data for each scope in lazy_inner's scope tree:
  For each Variable:
  - is_used
  - maybe_assigned
  - has_forced_context_allocation

  For each Scope:
  - inner_scope_calls_eval_.

63 64
  ProducedPreparseData implements storing the above mentioned data and
  ConsumedPreparseData implements restoring it (= setting the context
65 66
  allocation status of the variables in a Scope (and its subscopes) based on the
  data).
67 68 69

 */

70 71 72 73 74
struct PreparseByteDataConstants {
#ifdef DEBUG
  static constexpr int kMagicValue = 0xC0DE0DE;

  static constexpr size_t kUint32Size = 5;
75 76 77
  static constexpr size_t kVarint32MinSize = 3;
  static constexpr size_t kVarint32MaxSize = 7;
  static constexpr size_t kVarint32EndMarker = 0xF1;
78
  static constexpr size_t kUint8Size = 2;
79
  static constexpr size_t kQuarterMarker = 0xF2;
80 81 82
  static constexpr size_t kPlaceholderSize = kUint32Size;
#else
  static constexpr size_t kUint32Size = 4;
83 84
  static constexpr size_t kVarint32MinSize = 1;
  static constexpr size_t kVarint32MaxSize = 5;
85 86 87 88
  static constexpr size_t kUint8Size = 1;
  static constexpr size_t kPlaceholderSize = 0;
#endif

89
  static const size_t kSkippableFunctionMinDataSize =
90 91 92
      4 * kVarint32MinSize + 1 * kUint8Size;
  static const size_t kSkippableFunctionMaxDataSize =
      4 * kVarint32MaxSize + 1 * kUint8Size;
93
};
94

95 96
class V8_EXPORT_PRIVATE PreparseDataBuilder : public ZoneObject,
                                              public PreparseByteDataConstants {
97
 public:
98
  // Create a PreparseDataBuilder object which will collect data as we
99
  // parse.
100 101 102
  explicit PreparseDataBuilder(Zone* zone, PreparseDataBuilder* parent_builder,
                               std::vector<void*>* children_buffer);
  ~PreparseDataBuilder() {}
103

104
  PreparseDataBuilder* parent() const { return parent_; }
105

106 107
  // For gathering the inner function data and splitting it up according to the
  // laziness boundaries. Each lazy function gets its own
108
  // ProducedPreparseData, and so do all lazy functions inside it.
109 110
  class DataGatheringScope {
   public:
111 112 113 114
    explicit DataGatheringScope(PreParser* preparser)
        : preparser_(preparser), builder_(nullptr) {}

    void Start(DeclarationScope* function_scope);
115
    void SetSkippableFunction(DeclarationScope* function_scope,
116
                              int function_length, int num_inner_functions);
117 118 119 120
    inline ~DataGatheringScope() {
      if (builder_ == nullptr) return;
      Close();
    }
121 122

   private:
123 124
    void Close();

125
    PreParser* preparser_;
126
    PreparseDataBuilder* builder_;
127 128 129

    DISALLOW_COPY_AND_ASSIGN(DataGatheringScope);
  };
130

131 132
  class V8_EXPORT_PRIVATE ByteData : public ZoneObject,
                                     public PreparseByteDataConstants {
133
   public:
134 135
    ByteData()
        : byte_data_(nullptr), index_(0), free_quarters_in_last_byte_(0) {}
136 137 138 139 140 141 142

    ~ByteData() {}

    void Start(std::vector<uint8_t>* buffer);
    void Finalize(Zone* zone);

    Handle<PreparseData> CopyToHeap(Isolate* isolate, int children_length);
143
    inline ZonePreparseData* CopyToZone(Zone* zone, int children_length);
144

145 146 147 148
    void Reserve(size_t bytes);
    void Add(uint8_t byte);
    int length() const;

149
    void WriteVarint32(uint32_t data);
150 151 152 153
    void WriteUint8(uint8_t data);
    void WriteQuarter(uint8_t data);

#ifdef DEBUG
154
    void WriteUint32(uint32_t data);
155 156 157 158 159 160
    // For overwriting previously written data at position 0.
    void SaveCurrentSizeAtFirstUint32();
#endif

   private:
    union {
161 162 163 164 165
      struct {
        // Only used during construction (is_finalized_ == false).
        std::vector<uint8_t>* byte_data_;
        int index_;
      };
166 167 168 169 170 171 172 173 174 175 176
      // Once the data is finalized, it lives in a Zone, this implies
      // is_finalized_ == true.
      Vector<uint8_t> zone_byte_data_;
    };
    uint8_t free_quarters_in_last_byte_;

#ifdef DEBUG
    bool is_finalized_ = false;
#endif
  };

177 178
  // Saves the information needed for allocating the Scope's (and its
  // subscopes') variables.
179
  void SaveScopeAllocationData(DeclarationScope* scope, Parser* parser);
180

181 182 183 184 185 186 187 188 189 190 191 192 193 194
  // In some cases, PreParser cannot produce the same Scope structure as
  // Parser. If it happens, we're unable to produce the data that would enable
  // skipping the inner functions of that function.
  void Bailout() {
    bailed_out_ = true;
    // We don't need to call Bailout on existing / future children: the only way
    // to try to retrieve their data is through calling Serialize on the parent,
    // and if the parent is bailed out, it won't call Serialize on its children.
  }

  bool bailed_out() const { return bailed_out_; }

#ifdef DEBUG
  bool ThisOrParentBailedOut() const {
195 196
    if (bailed_out_) return true;
    if (parent_ == nullptr) return false;
197 198 199 200
    return parent_->ThisOrParentBailedOut();
  }
#endif  // DEBUG

201
  bool HasInnerFunctions() const;
202
  bool HasData() const;
203
  bool HasDataForParent() const;
204

205
  static bool ScopeNeedsData(Scope* scope);
206 207

 private:
208
  friend class BuilderProducedPreparseData;
209

210
  Handle<PreparseData> Serialize(Isolate* isolate);
211
  ZonePreparseData* Serialize(Zone* zone);
212

213 214 215
  void FinalizeChildren(Zone* zone);
  void AddChild(PreparseDataBuilder* child);

216
  void SaveDataForScope(Scope* scope);
217
  void SaveDataForVariable(Variable* var);
218
  void SaveDataForInnerScopes(Scope* scope);
219 220 221
  bool SaveDataForSkippableFunction(PreparseDataBuilder* builder);

  void CopyByteData(Zone* zone);
222

223
  PreparseDataBuilder* parent_;
224
  ByteData byte_data_;
225 226 227 228
  union {
    ScopedPtrList<PreparseDataBuilder> children_buffer_;
    Vector<PreparseDataBuilder*> children_;
  };
229

230
  DeclarationScope* function_scope_;
231
  int function_length_;
232 233
  int num_inner_functions_;
  int num_inner_with_data_;
234

235
  // Whether we've given up producing the data for this function.
236 237
  bool bailed_out_ : 1;
  bool has_data_ : 1;
238

239 240 241 242
#ifdef DEBUG
  bool finalized_children_ = false;
#endif

243
  DISALLOW_COPY_AND_ASSIGN(PreparseDataBuilder);
244
};
245

246
class ProducedPreparseData : public ZoneObject {
247 248 249 250
 public:
  // If there is data (if the Scope contains skippable inner functions), move
  // the data into the heap and return a Handle to it; otherwise return a null
  // MaybeHandle.
251
  virtual Handle<PreparseData> Serialize(Isolate* isolate) = 0;
252

253
  // If there is data (if the Scope contains skippable inner functions), return
254
  // an off-heap ZonePreparseData representing the data; otherwise
255
  // return nullptr.
256 257 258 259 260 261 262 263 264 265 266 267 268
  virtual ZonePreparseData* Serialize(Zone* zone) = 0;

  // Create a ProducedPreparseData which is a proxy for a previous
  // produced PreparseData in zone.
  static ProducedPreparseData* For(PreparseDataBuilder* builder, Zone* zone);

  // Create a ProducedPreparseData which is a proxy for a previous
  // produced PreparseData on the heap.
  static ProducedPreparseData* For(Handle<PreparseData> data, Zone* zone);

  // Create a ProducedPreparseData which is a proxy for a previous
  // produced PreparseData in zone.
  static ProducedPreparseData* For(ZonePreparseData* data, Zone* zone);
269
};
270

271
class ConsumedPreparseData {
272
 public:
273 274
  // Creates a ConsumedPreparseData representing the data of an on-heap
  // PreparseData |data|.
275 276
  V8_EXPORT_PRIVATE static std::unique_ptr<ConsumedPreparseData> For(
      Isolate* isolate, Handle<PreparseData> data);
277

278 279 280 281
  // Creates a ConsumedPreparseData representing the data of an off-heap
  // ZonePreparseData |data|.
  static std::unique_ptr<ConsumedPreparseData> For(Zone* zone,
                                                   ZonePreparseData* data);
282

283
  virtual ~ConsumedPreparseData() = default;
284

285
  virtual ProducedPreparseData* GetDataForSkippableFunction(
286
      Zone* zone, int start_position, int* end_position, int* num_parameters,
287
      int* function_length, int* num_inner_functions, bool* uses_super_property,
288
      LanguageMode* language_mode) = 0;
289 290 291

  // Restores the information needed for allocating the Scope's (and its
  // subscopes') variables.
292 293
  virtual void RestoreScopeAllocationData(
      DeclarationScope* scope, AstValueFactory* ast_value_factory) = 0;
294

295
 protected:
296
  ConsumedPreparseData() = default;
297

298
 private:
299
  DISALLOW_COPY_AND_ASSIGN(ConsumedPreparseData);
300 301 302 303 304
};

}  // namespace internal
}  // namespace v8

305
#endif  // V8_PARSING_PREPARSE_DATA_H_