v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
struct-types.h
Go to the documentation of this file.
1// Copyright 2020 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_WASM_STRUCT_TYPES_H_
6#define V8_WASM_STRUCT_TYPES_H_
7
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
10#endif // !V8_ENABLE_WEBASSEMBLY
11
12#include "src/base/iterator.h"
13#include "src/base/macros.h"
14#include "src/common/globals.h"
15#include "src/wasm/value-type.h"
16#include "src/zone/zone.h"
17
18namespace v8::internal::wasm {
19
20class StructTypeBase : public ZoneObject {
21 public:
22 StructTypeBase(uint32_t field_count, uint32_t* field_offsets,
23 const ValueTypeBase* reps, const bool* mutabilities,
24 bool is_descriptor)
27 field_offsets_(field_offsets),
28 reps_(reps),
31 }
32
33 bool is_descriptor() const { return is_descriptor_; }
34
35 uint32_t field_count() const { return field_count_; }
36
37 ValueTypeBase field(uint32_t index) const {
38 DCHECK_LT(index, field_count_);
39 return reps_[index];
40 }
41
42 bool mutability(uint32_t index) const {
43 DCHECK_LT(index, field_count_);
44 return mutabilities_[index];
45 }
46
47 // Iteration support.
54
55 // Returns the offset of this field in the runtime representation of the
56 // object, from the start of the object fields (disregarding the object
57 // header).
58 uint32_t field_offset(uint32_t index) const {
59 DCHECK_LT(index, field_count());
60 if (index == 0) {
61 return is_descriptor() ? kTaggedSize : 0;
62 }
63 DCHECK(offsets_initialized_);
64 return field_offsets_[index - 1];
65 }
66 uint32_t total_fields_size() const {
67 if (field_count() == 0) {
68 return is_descriptor() ? kTaggedSize : 0;
69 }
70 return field_offsets_[field_count() - 1];
71 }
72
73 uint32_t Align(uint32_t offset, uint32_t alignment) {
74 return RoundUp(offset, std::min(alignment, uint32_t{kTaggedSize}));
75 }
76
78 if (field_count() == 0) return;
79 DCHECK(!offsets_initialized_);
80 uint32_t offset = is_descriptor() ? kTaggedSize : 0;
82 // Optimization: we track the last gap that was introduced by alignment,
83 // and place any sufficiently-small fields in it.
84 // It's important that the algorithm that assigns offsets to fields is
85 // subtyping-safe, i.e. two lists of fields with a common prefix must
86 // always compute the same offsets for the fields in this common prefix.
87 uint32_t gap_position = 0;
88 uint32_t gap_size = 0;
89 for (uint32_t i = 1; i < field_count(); i++) {
90 uint32_t field_size = field(i).value_kind_size();
91 if (field_size <= gap_size) {
92 uint32_t aligned_gap = Align(gap_position, field_size);
93 uint32_t gap_before = aligned_gap - gap_position;
94 uint32_t aligned_gap_size = gap_size - gap_before;
95 if (field_size <= aligned_gap_size) {
96 field_offsets_[i - 1] = aligned_gap;
97 uint32_t gap_after = aligned_gap_size - field_size;
98 if (gap_before > gap_after) {
99 // Keep old {gap_position}.
100 gap_size = gap_before;
101 } else {
102 gap_position = aligned_gap + field_size;
103 gap_size = gap_after;
104 }
105 continue; // Successfully placed the field in the gap.
106 }
107 }
108 uint32_t old_offset = offset;
109 offset = Align(offset, field_size);
110 uint32_t gap = offset - old_offset;
111 if (gap > gap_size) {
112 gap_size = gap;
113 gap_position = old_offset;
114 }
115 field_offsets_[i - 1] = offset;
116 offset += field_size;
117 }
120#if DEBUG
121 offsets_initialized_ = true;
122#endif
123 }
124
125 // For incrementally building StructTypes.
126 template <class Subclass, class ValueTypeSubclass>
128 public:
129 enum ComputeOffsets : bool {
131 kUseProvidedOffsets = false
132 };
133
135 : zone_(zone),
138 cursor_(0),
139 field_offsets_(zone_->AllocateArray<uint32_t>(field_count_)),
140 buffer_(zone->AllocateArray<ValueTypeSubclass>(
141 static_cast<int>(field_count))),
143 zone->AllocateArray<bool>(static_cast<int>(field_count))) {}
144
145 void AddField(ValueTypeSubclass type, bool mutability,
146 uint32_t offset = 0) {
148 if (cursor_ > 0) {
150 } else {
151 // offset == 0 could mean that we'll compute the offsets later,
152 // or that this is the first field's offset being copied over from
153 // another struct type.
155 }
157 buffer_[cursor_++] = type;
158 }
159
160 void set_total_fields_size(uint32_t size) {
161 if (field_count_ == 0) {
163 return;
164 }
166 }
167
168 Subclass* Build(ComputeOffsets compute_offsets = kComputeOffsets) {
170 Subclass* result = zone_->New<Subclass>(
172 if (compute_offsets == kComputeOffsets) {
173 result->InitializeOffsets();
174 } else {
175#if DEBUG
176 bool offsets_specified = true;
177 for (uint32_t i = 0; i < field_count_; i++) {
178 if (field_offsets_[i] == 0) {
179 offsets_specified = false;
180 break;
181 }
182 }
183 result->offsets_initialized_ = offsets_specified;
184#endif
185 }
186 return result;
187 }
188
189 private:
190 Zone* const zone_;
191 const uint32_t field_count_;
192 const bool is_descriptor_;
193 uint32_t cursor_;
194 uint32_t* field_offsets_;
195 ValueTypeSubclass* const buffer_;
196 bool* const mutabilities_;
197 };
198
199 static const size_t kMaxFieldOffset =
201
202 private:
203 friend class StructType;
205
206 static_assert(kV8MaxWasmStructFields < std::numeric_limits<uint16_t>::max());
207 const uint16_t field_count_;
208 const bool is_descriptor_;
209#if DEBUG
210 bool offsets_initialized_ = false;
211#endif
212 uint32_t* const field_offsets_;
213 const ValueTypeBase* const reps_;
214 const bool* const mutabilities_;
215};
216
217// Module-relative type indices.
219 public:
221
222 StructType(uint32_t field_count, uint32_t* field_offsets,
223 const ValueType* reps, const bool* mutabilities,
224 bool is_descriptor)
225 : StructTypeBase(field_count, field_offsets, reps, mutabilities,
226 is_descriptor) {}
227
228 bool operator==(const StructType& other) const {
229 if (this == &other) return true;
230 if (field_count() != other.field_count()) return false;
231 if (this->is_descriptor() != other.is_descriptor()) return false;
232 return std::equal(fields().begin(), fields().end(),
233 other.fields().begin()) &&
234 std::equal(mutabilities().begin(), mutabilities().end(),
235 other.mutabilities().begin());
236 }
237
238 ValueType field(uint32_t index) const {
239 return ValueType{StructTypeBase::field(index)};
240 }
241
243 const ValueType* cast_reps = static_cast<const ValueType*>(reps_);
244 return {cast_reps, cast_reps + field_count_};
245 }
246};
247
248// Canonicalized type indices.
250 public:
251 using Builder =
253
254 CanonicalStructType(uint32_t field_count, uint32_t* field_offsets,
255 const CanonicalValueType* reps, const bool* mutabilities,
256 bool is_descriptor)
257 : StructTypeBase(field_count, field_offsets, reps, mutabilities,
258 is_descriptor) {}
259
260 CanonicalValueType field(uint32_t index) const {
262 }
263
264 bool operator==(const CanonicalStructType& other) const {
265 if (this == &other) return true;
266 if (field_count() != other.field_count()) return false;
267 if (is_descriptor() != other.is_descriptor()) return false;
268 return std::equal(fields().begin(), fields().end(),
269 other.fields().begin()) &&
270 std::equal(mutabilities().begin(), mutabilities().end(),
271 other.mutabilities().begin());
272 }
273
275 const CanonicalValueType* cast_reps =
276 static_cast<const CanonicalValueType*>(reps_);
277 return {cast_reps, cast_reps + field_count_};
278 }
279};
280
281inline std::ostream& operator<<(std::ostream& out, StructTypeBase type) {
282 out << "[";
283 for (ValueTypeBase field : type.fields()) {
284 out << field.name() << ", ";
285 }
286 out << "]";
287 return out;
288}
289
290class ArrayTypeBase : public ZoneObject {
291 public:
292 constexpr explicit ArrayTypeBase(bool mutability) : mutability_(mutability) {}
293
294 bool mutability() const { return mutability_; }
295
296 protected:
297 const bool mutability_;
298};
299
300class ArrayType : public ArrayTypeBase {
301 public:
302 constexpr ArrayType(ValueType rep, bool mutability)
303 : ArrayTypeBase(mutability), rep_(rep) {}
304
305 bool operator==(const ArrayType& other) const {
306 return rep_ == other.rep_ && mutability_ == other.mutability_;
307 }
308
309 ValueType element_type() const { return rep_; }
310 // Only for the ModuleDecoder, to finish populating the type.
312
313 private:
315};
316
318 public:
321
322 bool operator==(const CanonicalArrayType& other) const {
323 return rep_ == other.rep_ && mutability_ == other.mutability_;
324 }
325
327
328 private:
330};
331
332class ContType : public ZoneObject {
333 public:
334 constexpr explicit ContType(ModuleTypeIndex idx) : index_(idx) {}
335
336 bool operator==(const ContType& other) const {
337 return index_ == other.index_;
338 }
339
341
342 private:
343 // TODO(jkummerow): Consider storing a HeapType instead.
345};
346
348 public:
350
351 bool operator==(const CanonicalContType& other) const {
352 return index_ == other.index_;
353 }
354
356
357 private:
359};
360} // namespace v8::internal::wasm
361
362#endif // V8_WASM_STRUCT_TYPES_H_
T * New(Args &&... args)
Definition zone.h:114
constexpr ArrayTypeBase(bool mutability)
ValueType * element_type_writable_ptr()
bool operator==(const ArrayType &other) const
ValueType element_type() const
constexpr ArrayType(ValueType rep, bool mutability)
bool operator==(const CanonicalArrayType &other) const
CanonicalValueType element_type() const
CanonicalArrayType(CanonicalValueType rep, bool mutability)
CanonicalTypeIndex contfun_typeindex() const
CanonicalContType(CanonicalTypeIndex idx)
bool operator==(const CanonicalContType &other) const
base::iterator_range< const CanonicalValueType * > fields() const
CanonicalValueType field(uint32_t index) const
bool operator==(const CanonicalStructType &other) const
CanonicalStructType(uint32_t field_count, uint32_t *field_offsets, const CanonicalValueType *reps, const bool *mutabilities, bool is_descriptor)
ModuleTypeIndex contfun_typeindex() const
constexpr ContType(ModuleTypeIndex idx)
bool operator==(const ContType &other) const
BuilderImpl(Zone *zone, uint32_t field_count, bool is_descriptor)
void AddField(ValueTypeSubclass type, bool mutability, uint32_t offset=0)
Subclass * Build(ComputeOffsets compute_offsets=kComputeOffsets)
ValueTypeBase field(uint32_t index) const
bool mutability(uint32_t index) const
StructTypeBase(uint32_t field_count, uint32_t *field_offsets, const ValueTypeBase *reps, const bool *mutabilities, bool is_descriptor)
base::iterator_range< const bool * > mutabilities() const
uint32_t field_offset(uint32_t index) const
static const size_t kMaxFieldOffset
const ValueTypeBase *const reps_
base::iterator_range< const ValueTypeBase * > fields() const
uint32_t Align(uint32_t offset, uint32_t alignment)
bool operator==(const StructType &other) const
ValueType field(uint32_t index) const
StructType(uint32_t field_count, uint32_t *field_offsets, const ValueType *reps, const bool *mutabilities, bool is_descriptor)
base::iterator_range< const ValueType * > fields() const
constexpr int value_kind_size() const
Definition value-type.h:485
int end
int32_t offset
ZoneVector< RpoNumber > & result
std::ostream & operator<<(std::ostream &os, LiftoffVarState slot)
constexpr int kMaxValueTypeSize
Definition value-type.h:49
constexpr size_t kV8MaxWasmStructFields
Definition wasm-limits.h:64
constexpr int kTaggedSize
Definition globals.h:542
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387
wasm::ValueType type