summaryrefslogtreecommitdiff
path: root/deps/v8/src/snapshot/builtin-deserializer-allocator.h
blob: 65c5872d7a1d8c89cf98c7c6adfaaa8a61abccca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// 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.

#ifndef V8_SNAPSHOT_BUILTIN_DESERIALIZER_ALLOCATOR_H_
#define V8_SNAPSHOT_BUILTIN_DESERIALIZER_ALLOCATOR_H_

#include <unordered_set>

#include "src/globals.h"
#include "src/heap/heap.h"
#include "src/interpreter/interpreter.h"
#include "src/snapshot/serializer-common.h"

namespace v8 {
namespace internal {

template <class AllocatorT>
class Deserializer;

class BuiltinDeserializer;
class BuiltinSnapshotUtils;

class BuiltinDeserializerAllocator final {
  using BSU = BuiltinSnapshotUtils;
  using Bytecode = interpreter::Bytecode;
  using OperandScale = interpreter::OperandScale;

 public:
  BuiltinDeserializerAllocator(
      Deserializer<BuiltinDeserializerAllocator>* deserializer);

  ~BuiltinDeserializerAllocator();

  // ------- Allocation Methods -------
  // Methods related to memory allocation during deserialization.

  // Allocation works differently here than in other deserializers. Instead of
  // a statically-known memory area determined at serialization-time, our
  // memory requirements here are determined at runtime. Another major
  // difference is that we create builtin Code objects up-front (before
  // deserialization) in order to avoid having to patch builtin references
  // later on. See also the kBuiltin case in deserializer.cc.
  //
  // There are three ways that we use to reserve / allocate space. In all
  // cases, required objects are requested from the GC prior to
  // deserialization. 1. pre-allocated builtin code objects are written into
  // the builtins table (this is to make deserialization of builtin references
  // easier). Pre-allocated handler code objects are 2. stored in the
  // {handler_allocations_} vector (at eager-deserialization time) and 3.
  // stored in {handler_allocation_} (at lazy-deserialization time).
  //
  // Allocate simply returns the pre-allocated object prepared by
  // InitializeFromReservations.
  Address Allocate(AllocationSpace space, int size);

  void MoveToNextChunk(AllocationSpace space) { UNREACHABLE(); }
  void SetAlignment(AllocationAlignment alignment) { UNREACHABLE(); }

  void set_next_reference_is_weak(bool next_reference_is_weak) {
    next_reference_is_weak_ = next_reference_is_weak;
  }

  bool GetAndClearNextReferenceIsWeak() {
    bool saved = next_reference_is_weak_;
    next_reference_is_weak_ = false;
    return saved;
  }

#ifdef DEBUG
  bool next_reference_is_weak() const { return next_reference_is_weak_; }
#endif

  HeapObject* GetMap(uint32_t index) { UNREACHABLE(); }
  HeapObject* GetLargeObject(uint32_t index) { UNREACHABLE(); }
  HeapObject* GetObject(AllocationSpace space, uint32_t chunk_index,
                        uint32_t chunk_offset) {
    UNREACHABLE();
  }

  // ------- Reservation Methods -------
  // Methods related to memory reservations (prior to deserialization).

  // Builtin deserialization does not bake reservations into the snapshot, hence
  // this is a nop.
  void DecodeReservation(std::vector<SerializedData::Reservation> res) {}

  // These methods are used to pre-allocate builtin objects prior to
  // deserialization.
  // TODO(jgruber): Refactor reservation/allocation logic in deserializers to
  // make this less messy.
  Heap::Reservation CreateReservationsForEagerBuiltinsAndHandlers();
  void InitializeFromReservations(const Heap::Reservation& reservation);

  // Creates reservations and initializes the builtins table in preparation for
  // lazily deserializing a single builtin.
  void ReserveAndInitializeBuiltinsTableForBuiltin(int builtin_id);

  // Pre-allocates a code object preparation for lazily deserializing a single
  // handler.
  void ReserveForHandler(Bytecode bytecode, OperandScale operand_scale);

#ifdef DEBUG
  bool ReservationsAreFullyUsed() const;
#endif

 private:
  Isolate* isolate() const;
  BuiltinDeserializer* deserializer() const;

  // Used after memory allocation prior to isolate initialization, to register
  // the newly created object in code space and add it to the builtins table.
  void InitializeBuiltinFromReservation(const Heap::Chunk& chunk,
                                        int builtin_id);

  // As above, but for interpreter bytecode handlers.
  void InitializeHandlerFromReservation(
      const Heap::Chunk& chunk, interpreter::Bytecode bytecode,
      interpreter::OperandScale operand_scale);

#ifdef DEBUG
  void RegisterCodeObjectReservation(int code_object_id);
  void RegisterCodeObjectAllocation(int code_object_id);
  std::unordered_set<int> unused_reservations_;
#endif

 private:
  // The current deserializer. Note that this always points to a
  // BuiltinDeserializer instance, but we can't perform the cast during
  // construction since that makes vtable-based checks fail.
  Deserializer<BuiltinDeserializerAllocator>* const deserializer_;

  // Stores allocated space for bytecode handlers during eager deserialization.
  std::vector<Address>* handler_allocations_ = nullptr;

  // Stores the allocated space for a single handler during lazy
  // deserialization.
  Address handler_allocation_ = kNullAddress;

  bool next_reference_is_weak_ = false;

  DISALLOW_COPY_AND_ASSIGN(BuiltinDeserializerAllocator)
};

}  // namespace internal
}  // namespace v8

#endif  // V8_SNAPSHOT_BUILTIN_DESERIALIZER_ALLOCATOR_H_