1 // Copyright 2018 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 #if !V8_ENABLE_WEBASSEMBLY
6 #error This header should only be included if WebAssembly is enabled.
7 #endif // !V8_ENABLE_WEBASSEMBLY
8
9 #ifndef V8_WASM_VALUE_TYPE_H_
10 #define V8_WASM_VALUE_TYPE_H_
11
12 #include "src/base/bit-field.h"
13 #include "src/base/optional.h"
14 #include "src/codegen/machine-type.h"
15 #include "src/wasm/wasm-constants.h"
16 #include "src/wasm/wasm-limits.h"
17
18 namespace v8 {
19 namespace internal {
20
21 template <typename T>
22 class Signature;
23
24 namespace wasm {
25
26 // Type for holding simd values, defined in wasm-value.h.
27 class Simd128;
28
29 // Format: kind, log2Size, code, machineType, shortName, typeName
30 //
31 // Some of these types are from proposals that are not standardized yet:
32 // - "ref"/"optref" (a.k.a. "ref null") per
33 // https://github.com/WebAssembly/function-references
34 // - "rtt" per https://github.com/WebAssembly/gc
35 #define FOREACH_NUMERIC_VALUE_TYPE(V) \
36 V(I32, 2, I32, Int32, 'i', "i32") \
37 V(I64, 3, I64, Int64, 'l', "i64") \
38 V(F32, 2, F32, Float32, 'f', "f32") \
39 V(F64, 3, F64, Float64, 'd', "f64") \
40 V(S128, 4, S128, Simd128, 's', "s128") \
41 V(I8, 0, I8, Int8, 'b', "i8") \
42 V(I16, 1, I16, Int16, 'h', "i16")
43
44 #define FOREACH_VALUE_TYPE(V) \
45 V(Void, -1, Void, None, 'v', "<void>") \
46 FOREACH_NUMERIC_VALUE_TYPE(V) \
47 V(Rtt, kTaggedSizeLog2, Rtt, TaggedPointer, 't', "rtt") \
48 V(Ref, kTaggedSizeLog2, Ref, AnyTagged, 'r', "ref") \
49 V(OptRef, kTaggedSizeLog2, OptRef, AnyTagged, 'n', "ref null") \
50 V(Bottom, -1, Void, None, '*', "<bot>")
51
52 constexpr int kMaxValueTypeSize = 16; // bytes
53
54 // Represents a WebAssembly heap type, as per the typed-funcref and gc
55 // proposals.
56 // The underlying Representation enumeration encodes heap types as follows:
57 // a number t < kV8MaxWasmTypes represents the type defined in the module at
58 // index t. Numbers directly beyond that represent the generic heap types. The
59 // next number represents the bottom heap type (internal use).
60 class HeapType {
61 public:
62 enum Representation : uint32_t {
63 kFunc = kV8MaxWasmTypes, // shorthand: c
64 kEq, // shorthand: q
65 kI31, // shorthand: j
66 kData, // shorthand: o
67 kArray, // shorthand: g
68 kAny, // shorthand: a. Aka kExtern.
69 // This value is used to represent failures in the parsing of heap types and
70 // does not correspond to a wasm heap type. It has to be last in this list.
71 kBottom
72 };
73
from_code(uint8_t code)74 static constexpr HeapType from_code(uint8_t code) {
75 switch (code) {
76 case ValueTypeCode::kFuncRefCode:
77 return HeapType(kFunc);
78 case ValueTypeCode::kEqRefCode:
79 return HeapType(kEq);
80 case ValueTypeCode::kI31RefCode:
81 return HeapType(kI31);
82 case ValueTypeCode::kAnyRefCode:
83 case ValueTypeCode::kAnyRefCodeAlias:
84 return HeapType(kAny);
85 case ValueTypeCode::kDataRefCode:
86 return HeapType(kData);
87 case ValueTypeCode::kArrayRefCode:
88 return HeapType(kArray);
89 default:
90 return HeapType(kBottom);
91 }
92 }
93
HeapType(Representation repr)94 explicit constexpr HeapType(Representation repr) : representation_(repr) {
95 DCHECK(is_bottom() || is_valid());
96 }
HeapType(uint32_t repr)97 explicit constexpr HeapType(uint32_t repr)
98 : HeapType(static_cast<Representation>(repr)) {}
99
100 constexpr bool operator==(HeapType other) const {
101 return representation_ == other.representation_;
102 }
103 constexpr bool operator!=(HeapType other) const {
104 return representation_ != other.representation_;
105 }
106
107 constexpr bool operator==(Representation other) const {
108 return representation_ == other;
109 }
110
111 constexpr bool operator!=(Representation other) const {
112 return representation_ != other;
113 }
114
representation()115 constexpr Representation representation() const { return representation_; }
ref_index()116 constexpr uint32_t ref_index() const {
117 DCHECK(is_index());
118 return representation_;
119 }
120
is_generic()121 constexpr bool is_generic() const {
122 return !is_bottom() && representation_ >= kFirstSentinel;
123 }
124
is_index()125 constexpr bool is_index() const { return representation_ < kFirstSentinel; }
126
is_bottom()127 constexpr bool is_bottom() const { return representation_ == kBottom; }
128
name()129 std::string name() const {
130 switch (representation_) {
131 case kFunc:
132 return std::string("func");
133 case kEq:
134 return std::string("eq");
135 case kI31:
136 return std::string("i31");
137 case kData:
138 return std::string("data");
139 case kArray:
140 return std::string("array");
141 case kAny:
142 return std::string(FLAG_experimental_wasm_gc ? "any" : "extern");
143 default:
144 return std::to_string(representation_);
145 }
146 }
147
148 // Returns the code that represents this heap type in the wasm binary format.
code()149 constexpr int32_t code() const {
150 // Type codes represent the first byte of the LEB128 encoding. To get the
151 // int32 represented by a code, we need to sign-extend it from 7 to 32 bits.
152 int32_t mask = 0xFFFFFF80;
153 switch (representation_) {
154 case kFunc:
155 return mask | kFuncRefCode;
156 case kEq:
157 return mask | kEqRefCode;
158 case kI31:
159 return mask | kI31RefCode;
160 case kData:
161 return mask | kDataRefCode;
162 case kArray:
163 return mask | kArrayRefCode;
164 case kAny:
165 return mask | kAnyRefCode;
166 default:
167 return static_cast<int32_t>(representation_);
168 }
169 }
170
171 private:
172 friend class ValueType;
173
is_valid()174 constexpr bool is_valid() const { return representation_ <= kLastSentinel; }
175
176 static constexpr Representation kFirstSentinel =
177 static_cast<Representation>(kV8MaxWasmTypes);
178 static constexpr Representation kLastSentinel =
179 static_cast<Representation>(kBottom - 1);
180 Representation representation_;
181 };
182
183 enum Nullability : bool { kNonNullable, kNullable };
184
185 enum ValueKind : uint8_t {
186 #define DEF_ENUM(kind, ...) k##kind,
187 FOREACH_VALUE_TYPE(DEF_ENUM)
188 #undef DEF_ENUM
189 };
190
is_numeric(ValueKind kind)191 constexpr bool is_numeric(ValueKind kind) {
192 switch (kind) {
193 #define NUMERIC_CASE(kind, ...) \
194 case k##kind: \
195 return true;
196 FOREACH_NUMERIC_VALUE_TYPE(NUMERIC_CASE)
197 #undef NUMERIC_CASE
198 default:
199 return false;
200 }
201 }
202
is_reference(ValueKind kind)203 constexpr bool is_reference(ValueKind kind) {
204 return kind == kRef || kind == kOptRef || kind == kRtt;
205 }
206
is_object_reference(ValueKind kind)207 constexpr bool is_object_reference(ValueKind kind) {
208 return kind == kRef || kind == kOptRef;
209 }
210
value_kind_size_log2(ValueKind kind)211 constexpr int value_kind_size_log2(ValueKind kind) {
212 constexpr int8_t kValueKindSizeLog2[] = {
213 #define VALUE_KIND_SIZE_LOG2(kind, log2Size, ...) log2Size,
214 FOREACH_VALUE_TYPE(VALUE_KIND_SIZE_LOG2)
215 #undef VALUE_KIND_SIZE_LOG2
216 };
217
218 int size_log_2 = kValueKindSizeLog2[kind];
219 DCHECK_LE(0, size_log_2);
220 return size_log_2;
221 }
222
value_kind_size(ValueKind kind)223 constexpr int value_kind_size(ValueKind kind) {
224 constexpr int8_t kElementSize[] = {
225 #define ELEM_SIZE_LOG2(kind, log2Size, ...) \
226 log2Size == -1 ? -1 : (1 << std::max(0, log2Size)),
227 FOREACH_VALUE_TYPE(ELEM_SIZE_LOG2)
228 #undef ELEM_SIZE_LOG2
229 };
230
231 int size = kElementSize[kind];
232 DCHECK_LT(0, size);
233 return size;
234 }
235
value_kind_full_size(ValueKind kind)236 constexpr int value_kind_full_size(ValueKind kind) {
237 if (is_reference(kind)) {
238 // Uncompressed pointer size.
239 return kSystemPointerSize;
240 }
241 return value_kind_size(kind);
242 }
243
short_name(ValueKind kind)244 constexpr char short_name(ValueKind kind) {
245 constexpr char kShortName[] = {
246 #define SHORT_NAME(kind, log2Size, code, machineType, shortName, ...) shortName,
247 FOREACH_VALUE_TYPE(SHORT_NAME)
248 #undef SHORT_NAME
249 };
250
251 return kShortName[kind];
252 }
253
name(ValueKind kind)254 constexpr const char* name(ValueKind kind) {
255 constexpr const char* kKindName[] = {
256 #define KIND_NAME(kind, log2Size, code, machineType, shortName, kindName, ...) \
257 kindName,
258 FOREACH_VALUE_TYPE(KIND_NAME)
259 #undef TYPE_NAME
260 };
261
262 return kKindName[kind];
263 }
264
machine_type(ValueKind kind)265 constexpr MachineType machine_type(ValueKind kind) {
266 DCHECK_NE(kBottom, kind);
267
268 constexpr MachineType kMachineType[] = {
269 #define MACH_TYPE(kind, log2Size, code, machineType, ...) \
270 MachineType::machineType(),
271 FOREACH_VALUE_TYPE(MACH_TYPE)
272 #undef MACH_TYPE
273 };
274
275 return kMachineType[kind];
276 }
277
is_packed(ValueKind kind)278 constexpr bool is_packed(ValueKind kind) { return kind == kI8 || kind == kI16; }
unpacked(ValueKind kind)279 constexpr ValueKind unpacked(ValueKind kind) {
280 return is_packed(kind) ? kI32 : kind;
281 }
282
is_rtt(ValueKind kind)283 constexpr bool is_rtt(ValueKind kind) { return kind == kRtt; }
284
is_defaultable(ValueKind kind)285 constexpr bool is_defaultable(ValueKind kind) {
286 DCHECK(kind != kBottom && kind != kVoid);
287 return kind != kRef && !is_rtt(kind);
288 }
289
290 // A ValueType is encoded by two components: a ValueKind and a heap
291 // representation (for reference types/rtts). Those are encoded into 32 bits
292 // using base::BitField. The underlying ValueKind enumeration includes four
293 // elements which do not strictly correspond to value types: the two packed
294 // types i8 and i16, the void type (for control structures), and a bottom value
295 // (for internal use).
296 // ValueType encoding includes an additional bit marking the index of a type as
297 // relative. This should only be used during type canonicalization.
298 class ValueType {
299 public:
300 /******************************* Constructors *******************************/
ValueType()301 constexpr ValueType() : bit_field_(KindField::encode(kVoid)) {}
Primitive(ValueKind kind)302 static constexpr ValueType Primitive(ValueKind kind) {
303 DCHECK(kind == kBottom || kind <= kI16);
304 return ValueType(KindField::encode(kind));
305 }
Ref(uint32_t heap_type,Nullability nullability)306 static constexpr ValueType Ref(uint32_t heap_type, Nullability nullability) {
307 DCHECK(HeapType(heap_type).is_valid());
308 return ValueType(
309 KindField::encode(nullability == kNullable ? kOptRef : kRef) |
310 HeapTypeField::encode(heap_type));
311 }
Ref(HeapType heap_type,Nullability nullability)312 static constexpr ValueType Ref(HeapType heap_type, Nullability nullability) {
313 return Ref(heap_type.representation(), nullability);
314 }
315
Rtt(uint32_t type_index)316 static constexpr ValueType Rtt(uint32_t type_index) {
317 DCHECK(HeapType(type_index).is_index());
318 return ValueType(KindField::encode(kRtt) |
319 HeapTypeField::encode(type_index));
320 }
321
FromIndex(ValueKind kind,uint32_t index)322 static constexpr ValueType FromIndex(ValueKind kind, uint32_t index) {
323 DCHECK(kind == kOptRef || kind == kRef || kind == kRtt);
324 return ValueType(KindField::encode(kind) | HeapTypeField::encode(index));
325 }
326
327 // Useful when deserializing a type stored in a runtime object.
FromRawBitField(uint32_t bit_field)328 static constexpr ValueType FromRawBitField(uint32_t bit_field) {
329 return ValueType(bit_field);
330 }
331
332 /******************************** Type checks *******************************/
is_numeric()333 constexpr bool is_numeric() const { return wasm::is_numeric(kind()); }
334
is_reference()335 constexpr bool is_reference() const { return wasm::is_reference(kind()); }
336
is_object_reference()337 constexpr bool is_object_reference() const {
338 return wasm::is_object_reference(kind());
339 }
340
is_nullable()341 constexpr bool is_nullable() const { return kind() == kOptRef; }
342
is_reference_to(uint32_t htype)343 constexpr bool is_reference_to(uint32_t htype) const {
344 return (kind() == kRef || kind() == kOptRef) &&
345 heap_representation() == htype;
346 }
347
is_rtt()348 constexpr bool is_rtt() const { return wasm::is_rtt(kind()); }
349
has_index()350 constexpr bool has_index() const {
351 return is_rtt() || (is_object_reference() && heap_type().is_index());
352 }
353
is_defaultable()354 constexpr bool is_defaultable() const { return wasm::is_defaultable(kind()); }
355
is_bottom()356 constexpr bool is_bottom() const { return kind() == kBottom; }
357
is_packed()358 constexpr bool is_packed() const { return wasm::is_packed(kind()); }
359
Unpacked()360 constexpr ValueType Unpacked() const {
361 return is_packed() ? Primitive(kI32) : *this;
362 }
363
364 // Returns the version of this type that does not allow null values. Handles
365 // bottom.
AsNonNull()366 constexpr ValueType AsNonNull() const {
367 DCHECK(is_object_reference() || is_bottom());
368 return is_nullable() ? Ref(heap_type(), kNonNullable) : *this;
369 }
370
371 /***************************** Field Accessors ******************************/
kind()372 constexpr ValueKind kind() const { return KindField::decode(bit_field_); }
heap_representation()373 constexpr HeapType::Representation heap_representation() const {
374 DCHECK(is_object_reference());
375 return static_cast<HeapType::Representation>(
376 HeapTypeField::decode(bit_field_));
377 }
heap_type()378 constexpr HeapType heap_type() const {
379 DCHECK(is_object_reference());
380 return HeapType(heap_representation());
381 }
ref_index()382 constexpr uint32_t ref_index() const {
383 DCHECK(has_index());
384 return HeapTypeField::decode(bit_field_);
385 }
nullability()386 constexpr Nullability nullability() const {
387 DCHECK(is_object_reference());
388 return kind() == kOptRef ? kNullable : kNonNullable;
389 }
390
391 // Useful when serializing this type to store it into a runtime object.
raw_bit_field()392 constexpr uint32_t raw_bit_field() const { return bit_field_; }
393
394 /*************************** Other utility methods **************************/
395 constexpr bool operator==(ValueType other) const {
396 return bit_field_ == other.bit_field_;
397 }
398 constexpr bool operator!=(ValueType other) const {
399 return bit_field_ != other.bit_field_;
400 }
401
bit_field_offset()402 static constexpr size_t bit_field_offset() {
403 return offsetof(ValueType, bit_field_);
404 }
405
value_kind_size_log2()406 constexpr int value_kind_size_log2() const {
407 return wasm::value_kind_size_log2(kind());
408 }
409
value_kind_size()410 constexpr int value_kind_size() const {
411 return wasm::value_kind_size(kind());
412 }
413
value_kind_full_size()414 constexpr int value_kind_full_size() const {
415 return wasm::value_kind_full_size(kind());
416 }
417
418 /*************************** Machine-type related ***************************/
machine_type()419 constexpr MachineType machine_type() const {
420 return wasm::machine_type(kind());
421 }
422
machine_representation()423 constexpr MachineRepresentation machine_representation() const {
424 return machine_type().representation();
425 }
426
For(MachineType type)427 static ValueType For(MachineType type) {
428 switch (type.representation()) {
429 case MachineRepresentation::kWord8:
430 case MachineRepresentation::kWord16:
431 case MachineRepresentation::kWord32:
432 return Primitive(kI32);
433 case MachineRepresentation::kWord64:
434 return Primitive(kI64);
435 case MachineRepresentation::kFloat32:
436 return Primitive(kF32);
437 case MachineRepresentation::kFloat64:
438 return Primitive(kF64);
439 case MachineRepresentation::kTaggedPointer:
440 return Ref(HeapType::kAny, kNullable);
441 case MachineRepresentation::kSimd128:
442 return Primitive(kS128);
443 default:
444 UNREACHABLE();
445 }
446 }
447
448 /********************************* Encoding *********************************/
449
450 // Returns the first byte of this type's representation in the wasm binary
451 // format.
452 // For compatibility with the reftypes and exception-handling proposals, this
453 // function prioritizes shorthand encodings
454 // (e.g., Ref(HeapType::kFunc, kNullable).value_type_code will return
455 // kFuncrefCode and not kOptRefCode).
value_type_code()456 constexpr ValueTypeCode value_type_code() const {
457 DCHECK_NE(kBottom, kind());
458 switch (kind()) {
459 case kOptRef:
460 switch (heap_representation()) {
461 case HeapType::kFunc:
462 return kFuncRefCode;
463 case HeapType::kEq:
464 return kEqRefCode;
465 case HeapType::kAny:
466 return kAnyRefCode;
467 default:
468 return kOptRefCode;
469 }
470 case kRef:
471 switch (heap_representation()) {
472 case HeapType::kI31:
473 return kI31RefCode;
474 case HeapType::kData:
475 return kDataRefCode;
476 case HeapType::kArray:
477 return kArrayRefCode;
478 default:
479 return kRefCode;
480 }
481 case kVoid:
482 return kVoidCode;
483 case kRtt:
484 return kRttCode;
485 #define NUMERIC_TYPE_CASE(kind, ...) \
486 case k##kind: \
487 return k##kind##Code;
488 FOREACH_NUMERIC_VALUE_TYPE(NUMERIC_TYPE_CASE)
489 #undef NUMERIC_TYPE_CASE
490 case kBottom:
491 // Unreachable code
492 return kVoidCode;
493 }
494 }
495
496 // Returns true iff the heap type is needed to encode this type in the wasm
497 // binary format, taking into account available type shorthands.
encoding_needs_heap_type()498 constexpr bool encoding_needs_heap_type() const {
499 switch (kind()) {
500 case kRef:
501 return heap_representation() != HeapType::kI31 &&
502 heap_representation() != HeapType::kArray &&
503 heap_representation() != HeapType::kData;
504 case kOptRef:
505 return heap_representation() != HeapType::kFunc &&
506 heap_representation() != HeapType::kEq &&
507 heap_representation() != HeapType::kAny;
508 default:
509 return false;
510 }
511 }
512
513 /****************************** Pretty-printing *****************************/
short_name()514 constexpr char short_name() const { return wasm::short_name(kind()); }
515
name()516 std::string name() const {
517 std::ostringstream buf;
518 switch (kind()) {
519 case kRef:
520 case kOptRef:
521 if (encoding_needs_heap_type()) {
522 buf << "(ref " << (kind() == kOptRef ? "null " : "")
523 << heap_type().name() << ")";
524 } else {
525 buf << heap_type().name() << "ref";
526 }
527 break;
528 case kRtt:
529 buf << "(rtt " << ref_index() << ")";
530 break;
531 default:
532 buf << kind_name();
533 }
534 return buf.str();
535 }
536
537 /********************** Type canonicalization utilities *********************/
CanonicalWithRelativeIndex(ValueKind kind,uint32_t index)538 static constexpr ValueType CanonicalWithRelativeIndex(ValueKind kind,
539 uint32_t index) {
540 return ValueType(KindField::encode(kind) | HeapTypeField::encode(index) |
541 CanonicalRelativeField::encode(true));
542 }
543
is_canonical_relative()544 constexpr bool is_canonical_relative() const {
545 return has_index() && CanonicalRelativeField::decode(bit_field_);
546 }
547
548 /**************************** Static constants ******************************/
549 static constexpr int kLastUsedBit = 25;
550 static constexpr int kKindBits = 5;
551 static constexpr int kHeapTypeBits = 20;
552
553 private:
554 // {hash_value} directly reads {bit_field_}.
555 friend size_t hash_value(ValueType type);
556
557 using KindField = base::BitField<ValueKind, 0, kKindBits>;
558 using HeapTypeField = KindField::Next<uint32_t, kHeapTypeBits>;
559 // Marks a type as a canonical type which uses an index relative to its
560 // recursive group start. Used only during type canonicalization.
561 using CanonicalRelativeField = HeapTypeField::Next<bool, 1>;
562
563 static_assert(kV8MaxWasmTypes < (1u << kHeapTypeBits),
564 "Type indices fit in kHeapTypeBits");
565 // This is implemented defensively against field order changes.
566 static_assert(kLastUsedBit ==
567 std::max(KindField::kLastUsedBit,
568 std::max(HeapTypeField::kLastUsedBit,
569 CanonicalRelativeField::kLastUsedBit)),
570 "kLastUsedBit is consistent");
571
ValueType(uint32_t bit_field)572 constexpr explicit ValueType(uint32_t bit_field) : bit_field_(bit_field) {}
573
kind_name()574 constexpr const char* kind_name() const { return wasm::name(kind()); }
575
576 uint32_t bit_field_;
577 };
578
579 static_assert(sizeof(ValueType) <= kUInt32Size,
580 "ValueType is small and can be passed by value");
581 static_assert(ValueType::kLastUsedBit < 8 * sizeof(ValueType) - kSmiTagSize,
582 "ValueType has space to be encoded in a Smi");
583
hash_value(ValueType type)584 inline size_t hash_value(ValueType type) {
585 // Just use the whole encoded bit field, similar to {operator==}.
586 return static_cast<size_t>(type.bit_field_);
587 }
588
589 // Output operator, useful for DCHECKS and others.
590 inline std::ostream& operator<<(std::ostream& oss, ValueType type) {
591 return oss << type.name();
592 }
593
594 // Precomputed primitive types.
595 constexpr ValueType kWasmI32 = ValueType::Primitive(kI32);
596 constexpr ValueType kWasmI64 = ValueType::Primitive(kI64);
597 constexpr ValueType kWasmF32 = ValueType::Primitive(kF32);
598 constexpr ValueType kWasmF64 = ValueType::Primitive(kF64);
599 constexpr ValueType kWasmS128 = ValueType::Primitive(kS128);
600 constexpr ValueType kWasmI8 = ValueType::Primitive(kI8);
601 constexpr ValueType kWasmI16 = ValueType::Primitive(kI16);
602 constexpr ValueType kWasmVoid = ValueType::Primitive(kVoid);
603 constexpr ValueType kWasmBottom = ValueType::Primitive(kBottom);
604 // Established reference-type and wasm-gc proposal shorthands.
605 constexpr ValueType kWasmFuncRef = ValueType::Ref(HeapType::kFunc, kNullable);
606 constexpr ValueType kWasmAnyRef = ValueType::Ref(HeapType::kAny, kNullable);
607 constexpr ValueType kWasmEqRef = ValueType::Ref(HeapType::kEq, kNullable);
608 constexpr ValueType kWasmI31Ref = ValueType::Ref(HeapType::kI31, kNonNullable);
609 constexpr ValueType kWasmDataRef =
610 ValueType::Ref(HeapType::kData, kNonNullable);
611 constexpr ValueType kWasmArrayRef =
612 ValueType::Ref(HeapType::kArray, kNonNullable);
613
614 // Constants used by the generic js-to-wasm wrapper.
615 constexpr int kWasmValueKindBitsMask = (1u << ValueType::kKindBits) - 1;
616
617 // This is used in wasm.tq.
618 constexpr ValueType kWasmAnyNonNullableRef =
619 ValueType::Ref(HeapType::kAny, kNonNullable);
620
621 #define FOREACH_WASMVALUE_CTYPES(V) \
622 V(kI32, int32_t) \
623 V(kI64, int64_t) \
624 V(kF32, float) \
625 V(kF64, double) \
626 V(kS128, Simd128)
627
628 using FunctionSig = Signature<ValueType>;
629
630 #define FOREACH_LOAD_TYPE(V) \
631 V(I32, , Int32) \
632 V(I32, 8S, Int8) \
633 V(I32, 8U, Uint8) \
634 V(I32, 16S, Int16) \
635 V(I32, 16U, Uint16) \
636 V(I64, , Int64) \
637 V(I64, 8S, Int8) \
638 V(I64, 8U, Uint8) \
639 V(I64, 16S, Int16) \
640 V(I64, 16U, Uint16) \
641 V(I64, 32S, Int32) \
642 V(I64, 32U, Uint32) \
643 V(F32, , Float32) \
644 V(F64, , Float64) \
645 V(S128, , Simd128)
646
647 class LoadType {
648 public:
649 enum LoadTypeValue : uint8_t {
650 #define DEF_ENUM(type, suffix, ...) k##type##Load##suffix,
651 FOREACH_LOAD_TYPE(DEF_ENUM)
652 #undef DEF_ENUM
653 };
654
655 // Allow implicit conversion of the enum value to this wrapper.
LoadType(LoadTypeValue val)656 constexpr LoadType(LoadTypeValue val) // NOLINT(runtime/explicit)
657 : val_(val) {}
658
value()659 constexpr LoadTypeValue value() const { return val_; }
size_log_2()660 constexpr unsigned size_log_2() const { return kLoadSizeLog2[val_]; }
size()661 constexpr unsigned size() const { return 1 << size_log_2(); }
value_type()662 constexpr ValueType value_type() const { return kValueType[val_]; }
mem_type()663 constexpr MachineType mem_type() const { return kMemType[val_]; }
664
665 static LoadType ForValueKind(ValueKind kind, bool is_signed = false) {
666 switch (kind) {
667 case kI32:
668 return kI32Load;
669 case kI64:
670 return kI64Load;
671 case kF32:
672 return kF32Load;
673 case kF64:
674 return kF64Load;
675 case kS128:
676 return kS128Load;
677 case kI8:
678 return is_signed ? kI32Load8S : kI32Load8U;
679 case kI16:
680 return is_signed ? kI32Load16S : kI32Load16U;
681 default:
682 UNREACHABLE();
683 }
684 }
685
686 private:
687 const LoadTypeValue val_;
688
689 static constexpr uint8_t kLoadSizeLog2[] = {
690 // MSVC wants a static_cast here.
691 #define LOAD_SIZE(_, __, memtype) \
692 static_cast<uint8_t>( \
693 ElementSizeLog2Of(MachineType::memtype().representation())),
694 FOREACH_LOAD_TYPE(LOAD_SIZE)
695 #undef LOAD_SIZE
696 };
697
698 static constexpr ValueType kValueType[] = {
699 #define VALUE_TYPE(type, ...) ValueType::Primitive(k##type),
700 FOREACH_LOAD_TYPE(VALUE_TYPE)
701 #undef VALUE_TYPE
702 };
703
704 static constexpr MachineType kMemType[] = {
705 #define MEMTYPE(_, __, memtype) MachineType::memtype(),
706 FOREACH_LOAD_TYPE(MEMTYPE)
707 #undef MEMTYPE
708 };
709 };
710
711 #define FOREACH_STORE_TYPE(V) \
712 V(I32, , Word32) \
713 V(I32, 8, Word8) \
714 V(I32, 16, Word16) \
715 V(I64, , Word64) \
716 V(I64, 8, Word8) \
717 V(I64, 16, Word16) \
718 V(I64, 32, Word32) \
719 V(F32, , Float32) \
720 V(F64, , Float64) \
721 V(S128, , Simd128)
722
723 class StoreType {
724 public:
725 enum StoreTypeValue : uint8_t {
726 #define DEF_ENUM(type, suffix, ...) k##type##Store##suffix,
727 FOREACH_STORE_TYPE(DEF_ENUM)
728 #undef DEF_ENUM
729 };
730
731 // Allow implicit convertion of the enum value to this wrapper.
StoreType(StoreTypeValue val)732 constexpr StoreType(StoreTypeValue val) // NOLINT(runtime/explicit)
733 : val_(val) {}
734
value()735 constexpr StoreTypeValue value() const { return val_; }
size_log_2()736 constexpr unsigned size_log_2() const { return kStoreSizeLog2[val_]; }
size()737 constexpr unsigned size() const { return 1 << size_log_2(); }
value_type()738 constexpr ValueType value_type() const { return kValueType[val_]; }
mem_rep()739 constexpr MachineRepresentation mem_rep() const { return kMemRep[val_]; }
740
ForValueKind(ValueKind kind)741 static StoreType ForValueKind(ValueKind kind) {
742 switch (kind) {
743 case kI32:
744 return kI32Store;
745 case kI64:
746 return kI64Store;
747 case kF32:
748 return kF32Store;
749 case kF64:
750 return kF64Store;
751 case kS128:
752 return kS128Store;
753 case kI8:
754 return kI32Store8;
755 case kI16:
756 return kI32Store16;
757 default:
758 UNREACHABLE();
759 }
760 }
761
762 private:
763 const StoreTypeValue val_;
764
765 static constexpr uint8_t kStoreSizeLog2[] = {
766 // MSVC wants a static_cast here.
767 #define STORE_SIZE(_, __, memrep) \
768 static_cast<uint8_t>(ElementSizeLog2Of(MachineRepresentation::k##memrep)),
769 FOREACH_STORE_TYPE(STORE_SIZE)
770 #undef STORE_SIZE
771 };
772
773 static constexpr ValueType kValueType[] = {
774 #define VALUE_TYPE(type, ...) ValueType::Primitive(k##type),
775 FOREACH_STORE_TYPE(VALUE_TYPE)
776 #undef VALUE_TYPE
777 };
778
779 static constexpr MachineRepresentation kMemRep[] = {
780 #define MEMREP(_, __, memrep) MachineRepresentation::k##memrep,
781 FOREACH_STORE_TYPE(MEMREP)
782 #undef MEMREP
783 };
784 };
785
786 base::Optional<wasm::ValueKind> WasmReturnTypeFromSignature(
787 const FunctionSig* wasm_signature);
788
789 } // namespace wasm
790 } // namespace internal
791 } // namespace v8
792
793 #endif // V8_WASM_VALUE_TYPE_H_
794