asm-types.h 11.7 KB
Newer Older
jpp's avatar
jpp committed
1 2 3 4
// Copyright 2016 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
#ifndef SRC_ASMJS_ASM_TYPES_H_
#define SRC_ASMJS_ASM_TYPES_H_
jpp's avatar
jpp committed
7 8 9

#include <string>

10
#include "src/base/compiler-specific.h"
jpp's avatar
jpp committed
11
#include "src/base/macros.h"
12
#include "src/globals.h"
13 14
#include "src/zone/zone-containers.h"
#include "src/zone/zone.h"
jpp's avatar
jpp committed
15 16 17 18 19 20

namespace v8 {
namespace internal {
namespace wasm {

class AsmType;
21
class AsmFFIType;
jpp's avatar
jpp committed
22 23
class AsmFunctionType;
class AsmOverloadedFunctionType;
24
class AsmFunctionTableType;
jpp's avatar
jpp committed
25 26 27 28 29 30

// List of V(CamelName, string_name, number, parent_types)
#define FOR_EACH_ASM_VALUE_TYPE_LIST(V)                                       \
  /* These tags are not types that are expressable in the asm source. They */ \
  /* are used to express semantic information about the types they tag.    */ \
  V(Heap, "[]", 1, 0)                                                         \
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
  V(FloatishDoubleQ, "floatish|double?", 2, 0)                                \
  V(FloatQDoubleQ, "float?|double?", 3, 0)                                    \
  /* The following are actual types that appear in the asm source. */         \
  V(Void, "void", 4, 0)                                                       \
  V(Extern, "extern", 5, 0)                                                   \
  V(DoubleQ, "double?", 6, kAsmFloatishDoubleQ | kAsmFloatQDoubleQ)           \
  V(Double, "double", 7, kAsmDoubleQ | kAsmExtern)                            \
  V(Intish, "intish", 8, 0)                                                   \
  V(Int, "int", 9, kAsmIntish)                                                \
  V(Signed, "signed", 10, kAsmInt | kAsmExtern)                               \
  V(Unsigned, "unsigned", 11, kAsmInt)                                        \
  V(FixNum, "fixnum", 12, kAsmSigned | kAsmUnsigned)                          \
  V(Floatish, "floatish", 13, kAsmFloatishDoubleQ)                            \
  V(FloatQ, "float?", 14, kAsmFloatQDoubleQ | kAsmFloatish)                   \
  V(Float, "float", 15, kAsmFloatQ)                                           \
jpp's avatar
jpp committed
46
  /* Types used for expressing the Heap accesses. */                          \
47 48 49 50 51 52 53 54
  V(Uint8Array, "Uint8Array", 16, kAsmHeap)                                   \
  V(Int8Array, "Int8Array", 17, kAsmHeap)                                     \
  V(Uint16Array, "Uint16Array", 18, kAsmHeap)                                 \
  V(Int16Array, "Int16Array", 19, kAsmHeap)                                   \
  V(Uint32Array, "Uint32Array", 20, kAsmHeap)                                 \
  V(Int32Array, "Int32Array", 21, kAsmHeap)                                   \
  V(Float32Array, "Float32Array", 22, kAsmHeap)                               \
  V(Float64Array, "Float64Array", 23, kAsmHeap)                               \
jpp's avatar
jpp committed
55 56 57 58 59 60
  /* None is used to represent errors in the type checker. */                 \
  V(None, "<none>", 31, 0)

// List of V(CamelName)
#define FOR_EACH_ASM_CALLABLE_TYPE_LIST(V) \
  V(FunctionType)                          \
61 62 63
  V(FFIType)                               \
  V(OverloadedFunctionType)                \
  V(FunctionTableType)
jpp's avatar
jpp committed
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

class AsmValueType {
 public:
  typedef uint32_t bitset_t;

  enum : uint32_t {
#define DEFINE_TAG(CamelName, string_name, number, parent_types) \
  kAsm##CamelName = ((1u << (number)) | (parent_types)),
    FOR_EACH_ASM_VALUE_TYPE_LIST(DEFINE_TAG)
#undef DEFINE_TAG
        kAsmUnknown = 0,
    kAsmValueTypeTag = 1u
  };

 private:
  friend class AsmType;

  static AsmValueType* AsValueType(AsmType* type) {
    if ((reinterpret_cast<uintptr_t>(type) & kAsmValueTypeTag) ==
        kAsmValueTypeTag) {
      return reinterpret_cast<AsmValueType*>(type);
    }
    return nullptr;
  }

  bitset_t Bitset() const {
    DCHECK((reinterpret_cast<uintptr_t>(this) & kAsmValueTypeTag) ==
           kAsmValueTypeTag);
    return static_cast<bitset_t>(reinterpret_cast<uintptr_t>(this) &
                                 ~kAsmValueTypeTag);
  }

  static AsmType* New(bitset_t bits) {
97
    DCHECK_EQ((bits & kAsmValueTypeTag), 0u);
jpp's avatar
jpp committed
98 99 100 101 102 103 104 105
    return reinterpret_cast<AsmType*>(
        static_cast<uintptr_t>(bits | kAsmValueTypeTag));
  }

  // AsmValueTypes can't be created except through AsmValueType::New.
  DISALLOW_IMPLICIT_CONSTRUCTORS(AsmValueType);
};

106
class V8_EXPORT_PRIVATE AsmCallableType : public NON_EXPORTED_BASE(ZoneObject) {
jpp's avatar
jpp committed
107 108 109
 public:
  virtual std::string Name() = 0;

110 111 112
  virtual bool CanBeInvokedWith(AsmType* return_type,
                                const ZoneVector<AsmType*>& args) = 0;

jpp's avatar
jpp committed
113 114 115 116 117 118 119 120
#define DECLARE_CAST(CamelName) \
  virtual Asm##CamelName* As##CamelName() { return nullptr; }
  FOR_EACH_ASM_CALLABLE_TYPE_LIST(DECLARE_CAST)
#undef DECLARE_CAST

 protected:
  AsmCallableType() = default;
  virtual ~AsmCallableType() = default;
121
  virtual bool IsA(AsmType* other);
jpp's avatar
jpp committed
122 123

 private:
124 125
  friend class AsmType;

jpp's avatar
jpp committed
126 127 128
  DISALLOW_COPY_AND_ASSIGN(AsmCallableType);
};

129
class V8_EXPORT_PRIVATE AsmFunctionType final : public AsmCallableType {
jpp's avatar
jpp committed
130 131 132 133 134 135 136
 public:
  AsmFunctionType* AsFunctionType() final { return this; }

  void AddArgument(AsmType* type) { args_.push_back(type); }
  const ZoneVector<AsmType*> Arguments() const { return args_; }
  AsmType* ReturnType() const { return return_type_; }

137 138
  bool CanBeInvokedWith(AsmType* return_type,
                        const ZoneVector<AsmType*>& args) override;
jpp's avatar
jpp committed
139

jpp's avatar
jpp committed
140 141 142 143 144 145 146 147
 protected:
  AsmFunctionType(Zone* zone, AsmType* return_type)
      : return_type_(return_type), args_(zone) {}

 private:
  friend AsmType;

  std::string Name() override;
148
  bool IsA(AsmType* other) override;
jpp's avatar
jpp committed
149 150 151 152 153 154 155

  AsmType* return_type_;
  ZoneVector<AsmType*> args_;

  DISALLOW_COPY_AND_ASSIGN(AsmFunctionType);
};

156 157
class V8_EXPORT_PRIVATE AsmOverloadedFunctionType final
    : public AsmCallableType {
jpp's avatar
jpp committed
158 159 160 161 162 163 164 165 166 167 168 169 170
 public:
  AsmOverloadedFunctionType* AsOverloadedFunctionType() override {
    return this;
  }

  void AddOverload(AsmType* overload);

 private:
  friend AsmType;

  explicit AsmOverloadedFunctionType(Zone* zone) : overloads_(zone) {}

  std::string Name() override;
171 172
  bool CanBeInvokedWith(AsmType* return_type,
                        const ZoneVector<AsmType*>& args) override;
jpp's avatar
jpp committed
173 174 175 176 177 178

  ZoneVector<AsmType*> overloads_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(AsmOverloadedFunctionType);
};

179
class V8_EXPORT_PRIVATE AsmFFIType final : public AsmCallableType {
180 181 182 183
 public:
  AsmFFIType* AsFFIType() override { return this; }

  std::string Name() override { return "Function"; }
184 185
  bool CanBeInvokedWith(AsmType* return_type,
                        const ZoneVector<AsmType*>& args) override;
186 187 188 189 190 191 192 193 194

 private:
  friend AsmType;

  AsmFFIType() = default;

  DISALLOW_COPY_AND_ASSIGN(AsmFFIType);
};

195
class V8_EXPORT_PRIVATE AsmFunctionTableType : public AsmCallableType {
196 197 198 199 200
 public:
  AsmFunctionTableType* AsFunctionTableType() override { return this; }

  std::string Name() override;

201 202
  bool CanBeInvokedWith(AsmType* return_type,
                        const ZoneVector<AsmType*>& args) override;
203 204

  size_t length() const { return length_; }
jpp's avatar
jpp committed
205
  AsmType* signature() { return signature_; }
206 207 208 209 210 211 212 213 214 215 216 217

 private:
  friend class AsmType;

  AsmFunctionTableType(size_t length, AsmType* signature);

  size_t length_;
  AsmType* signature_;

  DISALLOW_IMPLICIT_CONSTRUCTORS(AsmFunctionTableType);
};

218
class V8_EXPORT_PRIVATE AsmType {
jpp's avatar
jpp committed
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
 public:
#define DEFINE_CONSTRUCTOR(CamelName, string_name, number, parent_types) \
  static AsmType* CamelName() {                                          \
    return AsmValueType::New(AsmValueType::kAsm##CamelName);             \
  }
  FOR_EACH_ASM_VALUE_TYPE_LIST(DEFINE_CONSTRUCTOR)
#undef DEFINE_CONSTRUCTOR

#define DEFINE_CAST(CamelCase)                                        \
  Asm##CamelCase* As##CamelCase() {                                   \
    if (AsValueType() != nullptr) {                                   \
      return nullptr;                                                 \
    }                                                                 \
    return reinterpret_cast<AsmCallableType*>(this)->As##CamelCase(); \
  }
  FOR_EACH_ASM_CALLABLE_TYPE_LIST(DEFINE_CAST)
#undef DEFINE_CAST
  AsmValueType* AsValueType() { return AsmValueType::AsValueType(this); }
  AsmCallableType* AsCallableType();

  // A function returning ret. Callers still need to invoke AddArgument with the
  // returned type to fully create this type.
  static AsmType* Function(Zone* zone, AsmType* ret) {
    AsmFunctionType* f = new (zone) AsmFunctionType(zone, ret);
    return reinterpret_cast<AsmType*>(f);
  }

  // Overloaded function types. Not creatable by asm source, but useful to
  // represent the overloaded stdlib functions.
  static AsmType* OverloadedFunction(Zone* zone) {
    auto* f = new (zone) AsmOverloadedFunctionType(zone);
    return reinterpret_cast<AsmType*>(f);
  }

  // The type for fround(src).
254
  static AsmType* FroundType(Zone* zone);
jpp's avatar
jpp committed
255 256

  // The (variadic) type for min and max.
257
  static AsmType* MinMaxType(Zone* zone, AsmType* dest, AsmType* src);
jpp's avatar
jpp committed
258

259 260 261 262 263 264 265 266 267 268 269 270 271
  // The type for foreign functions.
  static AsmType* FFIType(Zone* zone) {
    auto* f = new (zone) AsmFFIType();
    return reinterpret_cast<AsmType*>(f);
  }

  // The type for function tables.
  static AsmType* FunctionTableType(Zone* zone, size_t length,
                                    AsmType* signature) {
    auto* f = new (zone) AsmFunctionTableType(length, signature);
    return reinterpret_cast<AsmType*>(f);
  }

jpp's avatar
jpp committed
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
  std::string Name();
  // IsExactly returns true if this is the exact same type as that. For
  // non-value types (e.g., callables), this returns this == that.
  bool IsExactly(AsmType* that);
  // IsA is used to query whether this is an instance of that (i.e., if this is
  // a type derived from that.) For non-value types (e.g., callables), this
  // returns this == that.
  bool IsA(AsmType* that);

  // Types allowed in return statements. void is the type for returns without
  // an expression.
  bool IsReturnType() {
    return this == AsmType::Void() || this == AsmType::Double() ||
           this == AsmType::Signed() || this == AsmType::Float();
  }

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
  // Converts this to the corresponding valid argument type.
  AsmType* ToReturnType() {
    if (this->IsA(AsmType::Signed())) {
      return AsmType::Signed();
    }
    if (this->IsA(AsmType::Double())) {
      return AsmType::Double();
    }
    if (this->IsA(AsmType::Float())) {
      return AsmType::Float();
    }
    if (this->IsA(AsmType::Void())) {
      return AsmType::Void();
    }
    return AsmType::None();
  }

jpp's avatar
jpp committed
305 306 307 308 309 310
  // Types allowed to be parameters in asm functions.
  bool IsParameterType() {
    return this == AsmType::Double() || this == AsmType::Int() ||
           this == AsmType::Float();
  }

311 312 313 314 315 316 317 318 319 320 321 322 323 324
  // Converts this to the corresponding valid argument type.
  AsmType* ToParameterType() {
    if (this->IsA(AsmType::Int())) {
      return AsmType::Int();
    }
    if (this->IsA(AsmType::Double())) {
      return AsmType::Double();
    }
    if (this->IsA(AsmType::Float())) {
      return AsmType::Float();
    }
    return AsmType::None();
  }

jpp's avatar
jpp committed
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
  // Types allowed to be compared using the comparison operators.
  bool IsComparableType() {
    return this == AsmType::Double() || this == AsmType::Signed() ||
           this == AsmType::Unsigned() || this == AsmType::Float();
  }

  // The following methods are meant to be used for inspecting the traits of
  // element types for the heap view types.
  enum : int32_t { kNotHeapType = -1 };

  // Returns the element size if this is a heap type. Otherwise returns
  // kNotHeapType.
  int32_t ElementSizeInBytes();
  // Returns the load type if this is a heap type. AsmType::None is returned if
  // this is not a heap type.
  AsmType* LoadType();
  // Returns the store type if this is a heap type. AsmType::None is returned if
  // this is not a heap type.
  AsmType* StoreType();
};

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

jpp's avatar
jpp committed
350
#endif  // SRC_ASMJS_ASM_TYPES_H_