summaryrefslogtreecommitdiff
path: root/deps/v8/src/interpreter/constant-array-builder.h
blob: 87fe0559ae65af975ab8fb3393ff174a1b8f3b7d (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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// Copyright 2015 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_INTERPRETER_CONSTANT_ARRAY_BUILDER_H_
#define V8_INTERPRETER_CONSTANT_ARRAY_BUILDER_H_

#include "src/ast/ast-value-factory.h"
#include "src/common/globals.h"
#include "src/handles/handles.h"
#include "src/interpreter/bytecodes.h"
#include "src/objects/smi.h"
#include "src/utils/identity-map.h"
#include "src/zone/zone-containers.h"

namespace v8 {
namespace internal {

class Isolate;
class AstRawString;
class AstValue;

namespace interpreter {

// Constant array entries that represent singletons.
#define SINGLETON_CONSTANT_ENTRY_TYPES(V)                                    \
  V(AsyncIteratorSymbol, async_iterator_symbol)                              \
  V(ClassFieldsSymbol, class_fields_symbol)                                  \
  V(EmptyObjectBoilerplateDescription, empty_object_boilerplate_description) \
  V(EmptyArrayBoilerplateDescription, empty_array_boilerplate_description)   \
  V(EmptyFixedArray, empty_fixed_array)                                      \
  V(HomeObjectSymbol, home_object_symbol)                                    \
  V(IteratorSymbol, iterator_symbol)                                         \
  V(InterpreterTrampolineSymbol, interpreter_trampoline_symbol)              \
  V(NaN, nan_value)

// A helper class for constructing constant arrays for the
// interpreter. Each instance of this class is intended to be used to
// generate exactly one FixedArray of constants via the ToFixedArray
// method.
class V8_EXPORT_PRIVATE ConstantArrayBuilder final {
 public:
  // Capacity of the 8-bit operand slice.
  static const size_t k8BitCapacity = 1u << kBitsPerByte;

  // Capacity of the 16-bit operand slice.
  static const size_t k16BitCapacity = (1u << 2 * kBitsPerByte) - k8BitCapacity;

  // Capacity of the 32-bit operand slice.
  static const size_t k32BitCapacity =
      kMaxUInt32 - k16BitCapacity - k8BitCapacity + 1;

  explicit ConstantArrayBuilder(Zone* zone);

  // Generate a fixed array of constant handles based on inserted objects.
  template <typename LocalIsolate>
  EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
  Handle<FixedArray> ToFixedArray(LocalIsolate* isolate);

  // Returns the object, as a handle in |isolate|, that is in the constant pool
  // array at index |index|. Returns null if there is no handle at this index.
  // Only expected to be used in tests.
  template <typename LocalIsolate>
  EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
  MaybeHandle<Object> At(size_t index, LocalIsolate* isolate) const;

  // Returns the number of elements in the array.
  size_t size() const;

  // Insert an object into the constants array if it is not already present.
  // Returns the array index associated with the object.
  size_t Insert(Smi smi);
  size_t Insert(double number);
  size_t Insert(const AstRawString* raw_string);
  size_t Insert(AstBigInt bigint);
  size_t Insert(const Scope* scope);
#define INSERT_ENTRY(NAME, ...) size_t Insert##NAME();
  SINGLETON_CONSTANT_ENTRY_TYPES(INSERT_ENTRY)
#undef INSERT_ENTRY

  // Inserts an empty entry and returns the array index associated with the
  // reservation. The entry's handle value can be inserted by calling
  // SetDeferredAt().
  size_t InsertDeferred();

  // Inserts |size| consecutive empty entries and returns the array index
  // associated with the first reservation. Each entry's Smi value can be
  // inserted by calling SetJumpTableSmi().
  size_t InsertJumpTable(size_t size);

  // Sets the deferred value at |index| to |object|.
  void SetDeferredAt(size_t index, Handle<Object> object);

  // Sets the jump table entry at |index| to |smi|. Note that |index| is the
  // constant pool index, not the switch case value.
  void SetJumpTableSmi(size_t index, Smi smi);

  // Creates a reserved entry in the constant pool and returns
  // the size of the operand that'll be required to hold the entry
  // when committed.
  OperandSize CreateReservedEntry();

  // Commit reserved entry and returns the constant pool index for the
  // SMI value.
  size_t CommitReservedEntry(OperandSize operand_size, Smi value);

  // Discards constant pool reservation.
  void DiscardReservedEntry(OperandSize operand_size);

 private:
  using index_t = uint32_t;

  struct ConstantArraySlice;

  class Entry {
   private:
    enum class Tag : uint8_t;

   public:
    explicit Entry(Smi smi) : smi_(smi), tag_(Tag::kSmi) {}
    explicit Entry(double heap_number)
        : heap_number_(heap_number), tag_(Tag::kHeapNumber) {}
    explicit Entry(const AstRawString* raw_string)
        : raw_string_(raw_string), tag_(Tag::kRawString) {}
    explicit Entry(AstBigInt bigint) : bigint_(bigint), tag_(Tag::kBigInt) {}
    explicit Entry(const Scope* scope) : scope_(scope), tag_(Tag::kScope) {}

#define CONSTRUCT_ENTRY(NAME, LOWER_NAME) \
  static Entry NAME() { return Entry(Tag::k##NAME); }
    SINGLETON_CONSTANT_ENTRY_TYPES(CONSTRUCT_ENTRY)
#undef CONSTRUCT_ENTRY

    static Entry Deferred() { return Entry(Tag::kDeferred); }

    static Entry UninitializedJumpTableSmi() {
      return Entry(Tag::kUninitializedJumpTableSmi);
    }

    bool IsDeferred() const { return tag_ == Tag::kDeferred; }

    bool IsJumpTableEntry() const {
      return tag_ == Tag::kUninitializedJumpTableSmi ||
             tag_ == Tag::kJumpTableSmi;
    }

    void SetDeferred(Handle<Object> handle) {
      DCHECK_EQ(tag_, Tag::kDeferred);
      tag_ = Tag::kHandle;
      handle_ = handle;
    }

    void SetJumpTableSmi(Smi smi) {
      DCHECK_EQ(tag_, Tag::kUninitializedJumpTableSmi);
      tag_ = Tag::kJumpTableSmi;
      smi_ = smi;
    }

    template <typename LocalIsolate>
    Handle<Object> ToHandle(LocalIsolate* isolate) const;

   private:
    explicit Entry(Tag tag) : tag_(tag) {}

    union {
      Handle<Object> handle_;
      Smi smi_;
      double heap_number_;
      const AstRawString* raw_string_;
      AstBigInt bigint_;
      const Scope* scope_;
    };

    enum class Tag : uint8_t {
      kDeferred,
      kHandle,
      kSmi,
      kRawString,
      kHeapNumber,
      kBigInt,
      kScope,
      kUninitializedJumpTableSmi,
      kJumpTableSmi,
#define ENTRY_TAG(NAME, ...) k##NAME,
      SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_TAG)
#undef ENTRY_TAG
    } tag_;

#if DEBUG
    // Required by CheckAllElementsAreUnique().
    friend struct ConstantArraySlice;
#endif
  };

  index_t AllocateIndex(Entry constant_entry);
  index_t AllocateIndexArray(Entry constant_entry, size_t size);
  index_t AllocateReservedEntry(Smi value);

  struct ConstantArraySlice final : public ZoneObject {
    ConstantArraySlice(Zone* zone, size_t start_index, size_t capacity,
                       OperandSize operand_size);
    ConstantArraySlice(const ConstantArraySlice&) = delete;
    ConstantArraySlice& operator=(const ConstantArraySlice&) = delete;

    void Reserve();
    void Unreserve();
    size_t Allocate(Entry entry, size_t count = 1);
    Entry& At(size_t index);
    const Entry& At(size_t index) const;

#if DEBUG
    template <typename LocalIsolate>
    void CheckAllElementsAreUnique(LocalIsolate* isolate) const;
#endif

    inline size_t available() const { return capacity() - reserved() - size(); }
    inline size_t reserved() const { return reserved_; }
    inline size_t capacity() const { return capacity_; }
    inline size_t size() const { return constants_.size(); }
    inline size_t start_index() const { return start_index_; }
    inline size_t max_index() const { return start_index_ + capacity() - 1; }
    inline OperandSize operand_size() const { return operand_size_; }

   private:
    const size_t start_index_;
    const size_t capacity_;
    size_t reserved_;
    OperandSize operand_size_;
    ZoneVector<Entry> constants_;
  };

  ConstantArraySlice* IndexToSlice(size_t index) const;
  ConstantArraySlice* OperandSizeToSlice(OperandSize operand_size) const;

  ConstantArraySlice* idx_slice_[3];
  base::TemplateHashMapImpl<intptr_t, index_t,
                            base::KeyEqualityMatcher<intptr_t>,
                            ZoneAllocationPolicy>
      constants_map_;
  ZoneMap<Smi, index_t> smi_map_;
  ZoneVector<std::pair<Smi, index_t>> smi_pairs_;
  ZoneMap<double, index_t> heap_number_map_;

#define SINGLETON_ENTRY_FIELD(NAME, LOWER_NAME) int LOWER_NAME##_ = -1;
  SINGLETON_CONSTANT_ENTRY_TYPES(SINGLETON_ENTRY_FIELD)
#undef SINGLETON_ENTRY_FIELD
};

}  // namespace interpreter
}  // namespace internal
}  // namespace v8

#endif  // V8_INTERPRETER_CONSTANT_ARRAY_BUILDER_H_