wasm-value.h 7.61 KB
Newer Older
1 2 3 4
// Copyright 2017 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.

5 6 7 8
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif  // !V8_ENABLE_WEBASSEMBLY

9 10
#ifndef V8_WASM_WASM_VALUE_H_
#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 17 18 19 20 21
#include "src/zone/zone-containers.h"

namespace v8 {
namespace internal {
namespace wasm {

22
#define FOREACH_SIMD_TYPE(V)  \
23
  V(double, float2, f64x2, 2) \
24 25 26 27
  V(float, float4, f32x4, 4)  \
  V(int64_t, int2, i64x2, 2)  \
  V(int32_t, int4, i32x4, 4)  \
  V(int16_t, int8, i16x8, 8)  \
28
  V(int8_t, int16, i8x16, 16)
29 30 31 32 33 34 35 36 37 38

#define DEFINE_SIMD_TYPE(cType, sType, name, kSize) \
  struct sType {                                    \
    cType val[kSize];                               \
  };
FOREACH_SIMD_TYPE(DEFINE_SIMD_TYPE)
#undef DEFINE_SIMD_TYPE

class Simd128 {
 public:
39 40
  Simd128() = default;

41 42 43 44
#define DEFINE_SIMD_TYPE_SPECIFIC_METHODS(cType, sType, name, size)          \
  explicit Simd128(sType val) {                                              \
    base::WriteUnalignedValue<sType>(reinterpret_cast<Address>(val_), val);  \
  }                                                                          \
45
  sType to_##name() const {                                                  \
46
    return base::ReadUnalignedValue<sType>(reinterpret_cast<Address>(val_)); \
47 48 49 50
  }
  FOREACH_SIMD_TYPE(DEFINE_SIMD_TYPE_SPECIFIC_METHODS)
#undef DEFINE_SIMD_TYPE_SPECIFIC_METHODS

51
  explicit Simd128(byte* bytes) {
52 53
    memcpy(static_cast<void*>(val_), reinterpret_cast<void*>(bytes),
           kSimd128Size);
54 55
  }

56 57
  const uint8_t* bytes() { return val_; }

58
  template <typename T>
59
  inline T to() const;
60

61
 private:
62
  uint8_t val_[16] = {0};
63 64
};

65 66
#define DECLARE_CAST(cType, sType, name, size) \
  template <>                                  \
67
  inline sType Simd128::to() const {           \
68 69 70 71 72
    return to_##name();                        \
  }
FOREACH_SIMD_TYPE(DECLARE_CAST)
#undef DECLARE_CAST

73 74 75 76 77
// Macro for defining WasmValue methods for different types.
// Elements:
// - name (for to_<name>() method)
// - wasm type
// - c type
78 79 80 81 82 83 84 85 86 87 88 89
#define FOREACH_PRIMITIVE_WASMVAL_TYPE(V) \
  V(i8, kWasmI8, int8_t)                  \
  V(i16, kWasmI16, int16_t)               \
  V(i32, kWasmI32, int32_t)               \
  V(u32, kWasmI32, uint32_t)              \
  V(i64, kWasmI64, int64_t)               \
  V(u64, kWasmI64, uint64_t)              \
  V(f32, kWasmF32, float)                 \
  V(f32_boxed, kWasmF32, Float32)         \
  V(f64, kWasmF64, double)                \
  V(f64_boxed, kWasmF64, Float64)         \
  V(s128, kWasmS128, Simd128)
90 91

ASSERT_TRIVIALLY_COPYABLE(Handle<Object>);
92 93 94 95

// A wasm value with type information.
class WasmValue {
 public:
96
  WasmValue() : type_(kWasmVoid), bit_pattern_{} {}
97

98 99 100 101 102 103 104 105 106 107 108 109 110 111
#define DEFINE_TYPE_SPECIFIC_METHODS(name, localtype, ctype)                  \
  explicit WasmValue(ctype v) : type_(localtype), bit_pattern_{} {            \
    static_assert(sizeof(ctype) <= sizeof(bit_pattern_),                      \
                  "size too big for WasmValue");                              \
    base::WriteUnalignedValue<ctype>(reinterpret_cast<Address>(bit_pattern_), \
                                     v);                                      \
  }                                                                           \
  ctype to_##name() const {                                                   \
    DCHECK_EQ(localtype, type_);                                              \
    return to_##name##_unchecked();                                           \
  }                                                                           \
  ctype to_##name##_unchecked() const {                                       \
    return base::ReadUnalignedValue<ctype>(                                   \
        reinterpret_cast<Address>(bit_pattern_));                             \
112
  }
113

114
  FOREACH_PRIMITIVE_WASMVAL_TYPE(DEFINE_TYPE_SPECIFIC_METHODS)
115 116
#undef DEFINE_TYPE_SPECIFIC_METHODS

117 118
  WasmValue(byte* raw_bytes, ValueType type) : type_(type), bit_pattern_{} {
    DCHECK(type_.is_numeric());
119
    memcpy(bit_pattern_, raw_bytes, type.value_kind_size());
120 121
  }

122 123 124
  WasmValue(Handle<Object> ref, ValueType type) : type_(type), bit_pattern_{} {
    static_assert(sizeof(Handle<Object>) <= sizeof(bit_pattern_),
                  "bit_pattern_ must be large enough to fit a Handle");
125
    DCHECK(type.is_reference());
126 127 128
    base::WriteUnalignedValue<Handle<Object>>(
        reinterpret_cast<Address>(bit_pattern_), ref);
  }
129

130 131 132 133 134 135
  Handle<Object> to_ref() const {
    DCHECK(type_.is_reference());
    return base::ReadUnalignedValue<Handle<Object>>(
        reinterpret_cast<Address>(bit_pattern_));
  }

136 137
  ValueType type() const { return type_; }

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 142
           !memcmp(bit_pattern_, other.bit_pattern_,
                   type_.is_reference() ? sizeof(Handle<Object>)
143
                                        : type_.value_kind_size());
144 145
  }

146
  void CopyTo(byte* to) const {
147 148
    STATIC_ASSERT(sizeof(float) == sizeof(Float32));
    STATIC_ASSERT(sizeof(double) == sizeof(Float64));
149
    DCHECK(type_.is_numeric());
150
    memcpy(to, bit_pattern_, type_.value_kind_size());
151 152
  }

153 154 155 156 157 158 159 160 161 162 163 164 165 166
  // If {packed_type.is_packed()}, create a new value of {packed_type()}.
  // Otherwise, return this object.
  WasmValue Packed(ValueType packed_type) const {
    if (packed_type == kWasmI8) {
      DCHECK_EQ(type_, kWasmI32);
      return WasmValue(static_cast<int8_t>(to_i32()));
    }
    if (packed_type == kWasmI16) {
      DCHECK_EQ(type_, kWasmI32);
      return WasmValue(static_cast<int16_t>(to_i32()));
    }
    return *this;
  }

167
  template <typename T>
168
  inline T to() const;
169 170

  template <typename T>
171
  inline T to_unchecked() const;
172

173 174 175 176 177 178
  static WasmValue ForUintPtr(uintptr_t value) {
    using type =
        std::conditional<kSystemPointerSize == 8, uint64_t, uint32_t>::type;
    return WasmValue{type{value}};
  }

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
  inline std::string to_string() const {
    switch (type_.kind()) {
      case kI8:
        return std::to_string(to_i8());
      case kI16:
        return std::to_string(to_i16());
      case kI32:
        return std::to_string(to_i32());
      case kI64:
        return std::to_string(to_i64());
      case kF32:
        return std::to_string(to_f32());
      case kF64:
        return std::to_string(to_f64());
      case kS128: {
        std::stringstream stream;
        stream << "0x" << std::hex;
        for (int8_t byte : bit_pattern_) {
          if (!(byte & 0xf0)) stream << '0';
          stream << byte;
        }
        return stream.str();
      }
      case kOptRef:
      case kRef:
      case kRtt:
        return "Handle [" + std::to_string(to_ref().address()) + "]";
      case kVoid:
      case kBottom:
        UNREACHABLE();
    }
  }

212 213
 private:
  ValueType type_;
214
  uint8_t bit_pattern_[16];
215 216
};

217 218 219
#define DECLARE_CAST(name, localtype, ctype, ...) \
  template <>                                     \
  inline ctype WasmValue::to_unchecked() const {  \
220
    return to_##name##_unchecked();               \
221 222 223
  }                                               \
  template <>                                     \
  inline ctype WasmValue::to() const {            \
224
    return to_##name();                           \
225
  }
226
FOREACH_PRIMITIVE_WASMVAL_TYPE(DECLARE_CAST)
227 228 229 230 231 232
#undef DECLARE_CAST

}  // namespace wasm
}  // namespace internal
}  // namespace v8

233
#endif  // V8_WASM_WASM_VALUE_H_