• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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_WASM_VALUE_H_
10 #define V8_WASM_WASM_VALUE_H_
11 
12 #include "src/base/memory.h"
13 #include "src/handles/handles.h"
14 #include "src/utils/boxed-float.h"
15 #include "src/wasm/value-type.h"
16 #include "src/zone/zone-containers.h"
17 
18 namespace v8 {
19 namespace internal {
20 namespace wasm {
21 
22 #define FOREACH_SIMD_TYPE(V)  \
23   V(double, float2, f64x2, 2) \
24   V(float, float4, f32x4, 4)  \
25   V(int64_t, int2, i64x2, 2)  \
26   V(int32_t, int4, i32x4, 4)  \
27   V(int16_t, int8, i16x8, 8)  \
28   V(int8_t, int16, i8x16, 16)
29 
30 #define DEFINE_SIMD_TYPE(cType, sType, name, kSize) \
31   struct sType {                                    \
32     cType val[kSize];                               \
33   };
FOREACH_SIMD_TYPE(DEFINE_SIMD_TYPE)34 FOREACH_SIMD_TYPE(DEFINE_SIMD_TYPE)
35 #undef DEFINE_SIMD_TYPE
36 
37 class Simd128 {
38  public:
39   Simd128() = default;
40 
41 #define DEFINE_SIMD_TYPE_SPECIFIC_METHODS(cType, sType, name, size)          \
42   explicit Simd128(sType val) {                                              \
43     base::WriteUnalignedValue<sType>(reinterpret_cast<Address>(val_), val);  \
44   }                                                                          \
45   sType to_##name() const {                                                  \
46     return base::ReadUnalignedValue<sType>(reinterpret_cast<Address>(val_)); \
47   }
48   FOREACH_SIMD_TYPE(DEFINE_SIMD_TYPE_SPECIFIC_METHODS)
49 #undef DEFINE_SIMD_TYPE_SPECIFIC_METHODS
50 
51   explicit Simd128(byte* bytes) {
52     memcpy(static_cast<void*>(val_), reinterpret_cast<void*>(bytes),
53            kSimd128Size);
54   }
55 
56   const uint8_t* bytes() { return val_; }
57 
58   template <typename T>
59   inline T to() const;
60 
61  private:
62   uint8_t val_[16] = {0};
63 };
64 
65 #define DECLARE_CAST(cType, sType, name, size) \
66   template <>                                  \
67   inline sType Simd128::to() const {           \
68     return to_##name();                        \
69   }
70 FOREACH_SIMD_TYPE(DECLARE_CAST)
71 #undef DECLARE_CAST
72 
73 // Macro for defining WasmValue methods for different types.
74 // Elements:
75 // - name (for to_<name>() method)
76 // - wasm type
77 // - c type
78 #define FOREACH_PRIMITIVE_WASMVAL_TYPE(V) \
79   V(i8, kWasmI8, int8_t)                  \
80   V(i16, kWasmI16, int16_t)               \
81   V(i32, kWasmI32, int32_t)               \
82   V(u32, kWasmI32, uint32_t)              \
83   V(i64, kWasmI64, int64_t)               \
84   V(u64, kWasmI64, uint64_t)              \
85   V(f32, kWasmF32, float)                 \
86   V(f32_boxed, kWasmF32, Float32)         \
87   V(f64, kWasmF64, double)                \
88   V(f64_boxed, kWasmF64, Float64)         \
89   V(s128, kWasmS128, Simd128)
90 
91 ASSERT_TRIVIALLY_COPYABLE(Handle<Object>);
92 
93 // A wasm value with type information.
94 class WasmValue {
95  public:
WasmValue()96   WasmValue() : type_(kWasmVoid), bit_pattern_{} {}
97 
98 #define DEFINE_TYPE_SPECIFIC_METHODS(name, localtype, ctype)                  \
99   explicit WasmValue(ctype v) : type_(localtype), bit_pattern_{} {            \
100     static_assert(sizeof(ctype) <= sizeof(bit_pattern_),                      \
101                   "size too big for WasmValue");                              \
102     base::WriteUnalignedValue<ctype>(reinterpret_cast<Address>(bit_pattern_), \
103                                      v);                                      \
104   }                                                                           \
105   ctype to_##name() const {                                                   \
106     DCHECK_EQ(localtype, type_);                                              \
107     return to_##name##_unchecked();                                           \
108   }                                                                           \
109   ctype to_##name##_unchecked() const {                                       \
110     return base::ReadUnalignedValue<ctype>(                                   \
111         reinterpret_cast<Address>(bit_pattern_));                             \
112   }
113 
114   FOREACH_PRIMITIVE_WASMVAL_TYPE(DEFINE_TYPE_SPECIFIC_METHODS)
115 #undef DEFINE_TYPE_SPECIFIC_METHODS
116 
WasmValue(byte * raw_bytes,ValueType type)117   WasmValue(byte* raw_bytes, ValueType type) : type_(type), bit_pattern_{} {
118     DCHECK(type_.is_numeric());
119     memcpy(bit_pattern_, raw_bytes, type.value_kind_size());
120   }
121 
WasmValue(Handle<Object> ref,ValueType type)122   WasmValue(Handle<Object> ref, ValueType type) : type_(type), bit_pattern_{} {
123     static_assert(sizeof(Handle<Object>) <= sizeof(bit_pattern_),
124                   "bit_pattern_ must be large enough to fit a Handle");
125     DCHECK(type.is_reference());
126     base::WriteUnalignedValue<Handle<Object>>(
127         reinterpret_cast<Address>(bit_pattern_), ref);
128   }
129 
to_ref()130   Handle<Object> to_ref() const {
131     DCHECK(type_.is_reference());
132     return base::ReadUnalignedValue<Handle<Object>>(
133         reinterpret_cast<Address>(bit_pattern_));
134   }
135 
type()136   ValueType type() const { return type_; }
137 
138   // Checks equality of type and bit pattern (also for float and double values).
139   bool operator==(const WasmValue& other) const {
140     return type_ == other.type_ &&
141            !memcmp(bit_pattern_, other.bit_pattern_,
142                    type_.is_reference() ? sizeof(Handle<Object>)
143                                         : type_.value_kind_size());
144   }
145 
CopyTo(byte * to)146   void CopyTo(byte* to) const {
147     STATIC_ASSERT(sizeof(float) == sizeof(Float32));
148     STATIC_ASSERT(sizeof(double) == sizeof(Float64));
149     DCHECK(type_.is_numeric());
150     memcpy(to, bit_pattern_, type_.value_kind_size());
151   }
152 
153   // If {packed_type.is_packed()}, create a new value of {packed_type()}.
154   // Otherwise, return this object.
Packed(ValueType packed_type)155   WasmValue Packed(ValueType packed_type) const {
156     if (packed_type == kWasmI8) {
157       DCHECK_EQ(type_, kWasmI32);
158       return WasmValue(static_cast<int8_t>(to_i32()));
159     }
160     if (packed_type == kWasmI16) {
161       DCHECK_EQ(type_, kWasmI32);
162       return WasmValue(static_cast<int16_t>(to_i32()));
163     }
164     return *this;
165   }
166 
167   template <typename T>
168   inline T to() const;
169 
170   template <typename T>
171   inline T to_unchecked() const;
172 
ForUintPtr(uintptr_t value)173   static WasmValue ForUintPtr(uintptr_t value) {
174     using type =
175         std::conditional<kSystemPointerSize == 8, uint64_t, uint32_t>::type;
176     return WasmValue{type{value}};
177   }
178 
to_string()179   inline std::string to_string() const {
180     switch (type_.kind()) {
181       case kI8:
182         return std::to_string(to_i8());
183       case kI16:
184         return std::to_string(to_i16());
185       case kI32:
186         return std::to_string(to_i32());
187       case kI64:
188         return std::to_string(to_i64());
189       case kF32:
190         return std::to_string(to_f32());
191       case kF64:
192         return std::to_string(to_f64());
193       case kS128: {
194         std::stringstream stream;
195         stream << "0x" << std::hex;
196         for (int8_t byte : bit_pattern_) {
197           if (!(byte & 0xf0)) stream << '0';
198           stream << byte;
199         }
200         return stream.str();
201       }
202       case kOptRef:
203       case kRef:
204       case kRtt:
205         return "Handle [" + std::to_string(to_ref().address()) + "]";
206       case kVoid:
207       case kBottom:
208         UNREACHABLE();
209     }
210   }
211 
212  private:
213   ValueType type_;
214   uint8_t bit_pattern_[16];
215 };
216 
217 #define DECLARE_CAST(name, localtype, ctype, ...) \
218   template <>                                     \
219   inline ctype WasmValue::to_unchecked() const {  \
220     return to_##name##_unchecked();               \
221   }                                               \
222   template <>                                     \
223   inline ctype WasmValue::to() const {            \
224     return to_##name();                           \
225   }
226 FOREACH_PRIMITIVE_WASMVAL_TYPE(DECLARE_CAST)
227 #undef DECLARE_CAST
228 
229 }  // namespace wasm
230 }  // namespace internal
231 }  // namespace v8
232 
233 #endif  // V8_WASM_WASM_VALUE_H_
234