• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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