Home | History | Annotate | Download | only in asmjs
      1 // Copyright 2016 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 #ifndef SRC_ASMJS_ASM_TYPES_H_
      6 #define SRC_ASMJS_ASM_TYPES_H_
      7 
      8 #include <string>
      9 
     10 #include "src/base/compiler-specific.h"
     11 #include "src/base/macros.h"
     12 #include "src/globals.h"
     13 #include "src/zone/zone-containers.h"
     14 #include "src/zone/zone.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 namespace wasm {
     19 
     20 class AsmType;
     21 class AsmFFIType;
     22 class AsmFunctionType;
     23 class AsmOverloadedFunctionType;
     24 class AsmFunctionTableType;
     25 
     26 // List of V(CamelName, string_name, number, parent_types)
     27 #define FOR_EACH_ASM_VALUE_TYPE_LIST(V)                                       \
     28   /* These tags are not types that are expressable in the asm source. They */ \
     29   /* are used to express semantic information about the types they tag.    */ \
     30   V(Heap, "[]", 1, 0)                                                         \
     31   V(FloatishDoubleQ, "floatish|double?", 2, 0)                                \
     32   V(FloatQDoubleQ, "float?|double?", 3, 0)                                    \
     33   /* The following are actual types that appear in the asm source. */         \
     34   V(Void, "void", 4, 0)                                                       \
     35   V(Extern, "extern", 5, 0)                                                   \
     36   V(DoubleQ, "double?", 6, kAsmFloatishDoubleQ | kAsmFloatQDoubleQ)           \
     37   V(Double, "double", 7, kAsmDoubleQ | kAsmExtern)                            \
     38   V(Intish, "intish", 8, 0)                                                   \
     39   V(Int, "int", 9, kAsmIntish)                                                \
     40   V(Signed, "signed", 10, kAsmInt | kAsmExtern)                               \
     41   V(Unsigned, "unsigned", 11, kAsmInt)                                        \
     42   V(FixNum, "fixnum", 12, kAsmSigned | kAsmUnsigned)                          \
     43   V(Floatish, "floatish", 13, kAsmFloatishDoubleQ)                            \
     44   V(FloatQ, "float?", 14, kAsmFloatQDoubleQ | kAsmFloatish)                   \
     45   V(Float, "float", 15, kAsmFloatQ)                                           \
     46   /* Types used for expressing the Heap accesses. */                          \
     47   V(Uint8Array, "Uint8Array", 16, kAsmHeap)                                   \
     48   V(Int8Array, "Int8Array", 17, kAsmHeap)                                     \
     49   V(Uint16Array, "Uint16Array", 18, kAsmHeap)                                 \
     50   V(Int16Array, "Int16Array", 19, kAsmHeap)                                   \
     51   V(Uint32Array, "Uint32Array", 20, kAsmHeap)                                 \
     52   V(Int32Array, "Int32Array", 21, kAsmHeap)                                   \
     53   V(Float32Array, "Float32Array", 22, kAsmHeap)                               \
     54   V(Float64Array, "Float64Array", 23, kAsmHeap)                               \
     55   /* None is used to represent errors in the type checker. */                 \
     56   V(None, "<none>", 31, 0)
     57 
     58 // List of V(CamelName)
     59 #define FOR_EACH_ASM_CALLABLE_TYPE_LIST(V) \
     60   V(FunctionType)                          \
     61   V(FFIType)                               \
     62   V(OverloadedFunctionType)                \
     63   V(FunctionTableType)
     64 
     65 class AsmValueType {
     66  public:
     67   typedef uint32_t bitset_t;
     68 
     69   enum : uint32_t {
     70 #define DEFINE_TAG(CamelName, string_name, number, parent_types) \
     71   kAsm##CamelName = ((1u << (number)) | (parent_types)),
     72     FOR_EACH_ASM_VALUE_TYPE_LIST(DEFINE_TAG)
     73 #undef DEFINE_TAG
     74         kAsmUnknown = 0,
     75     kAsmValueTypeTag = 1u
     76   };
     77 
     78  private:
     79   friend class AsmType;
     80 
     81   static AsmValueType* AsValueType(AsmType* type) {
     82     if ((reinterpret_cast<uintptr_t>(type) & kAsmValueTypeTag) ==
     83         kAsmValueTypeTag) {
     84       return reinterpret_cast<AsmValueType*>(type);
     85     }
     86     return nullptr;
     87   }
     88 
     89   bitset_t Bitset() const {
     90     DCHECK((reinterpret_cast<uintptr_t>(this) & kAsmValueTypeTag) ==
     91            kAsmValueTypeTag);
     92     return static_cast<bitset_t>(reinterpret_cast<uintptr_t>(this) &
     93                                  ~kAsmValueTypeTag);
     94   }
     95 
     96   static AsmType* New(bitset_t bits) {
     97     DCHECK_EQ((bits & kAsmValueTypeTag), 0u);
     98     return reinterpret_cast<AsmType*>(
     99         static_cast<uintptr_t>(bits | kAsmValueTypeTag));
    100   }
    101 
    102   // AsmValueTypes can't be created except through AsmValueType::New.
    103   DISALLOW_IMPLICIT_CONSTRUCTORS(AsmValueType);
    104 };
    105 
    106 class V8_EXPORT_PRIVATE AsmCallableType : public NON_EXPORTED_BASE(ZoneObject) {
    107  public:
    108   virtual std::string Name() = 0;
    109 
    110   virtual bool CanBeInvokedWith(AsmType* return_type,
    111                                 const ZoneVector<AsmType*>& args) = 0;
    112 
    113 #define DECLARE_CAST(CamelName) \
    114   virtual Asm##CamelName* As##CamelName() { return nullptr; }
    115   FOR_EACH_ASM_CALLABLE_TYPE_LIST(DECLARE_CAST)
    116 #undef DECLARE_CAST
    117 
    118  protected:
    119   AsmCallableType() = default;
    120   virtual ~AsmCallableType() = default;
    121   virtual bool IsA(AsmType* other);
    122 
    123  private:
    124   friend class AsmType;
    125 
    126   DISALLOW_COPY_AND_ASSIGN(AsmCallableType);
    127 };
    128 
    129 class V8_EXPORT_PRIVATE AsmFunctionType final : public AsmCallableType {
    130  public:
    131   AsmFunctionType* AsFunctionType() final { return this; }
    132 
    133   void AddArgument(AsmType* type) { args_.push_back(type); }
    134   const ZoneVector<AsmType*> Arguments() const { return args_; }
    135   AsmType* ReturnType() const { return return_type_; }
    136 
    137   bool CanBeInvokedWith(AsmType* return_type,
    138                         const ZoneVector<AsmType*>& args) override;
    139 
    140  protected:
    141   AsmFunctionType(Zone* zone, AsmType* return_type)
    142       : return_type_(return_type), args_(zone) {}
    143 
    144  private:
    145   friend AsmType;
    146 
    147   std::string Name() override;
    148   bool IsA(AsmType* other) override;
    149 
    150   AsmType* return_type_;
    151   ZoneVector<AsmType*> args_;
    152 
    153   DISALLOW_COPY_AND_ASSIGN(AsmFunctionType);
    154 };
    155 
    156 class V8_EXPORT_PRIVATE AsmOverloadedFunctionType final
    157     : public AsmCallableType {
    158  public:
    159   AsmOverloadedFunctionType* AsOverloadedFunctionType() override {
    160     return this;
    161   }
    162 
    163   void AddOverload(AsmType* overload);
    164 
    165  private:
    166   friend AsmType;
    167 
    168   explicit AsmOverloadedFunctionType(Zone* zone) : overloads_(zone) {}
    169 
    170   std::string Name() override;
    171   bool CanBeInvokedWith(AsmType* return_type,
    172                         const ZoneVector<AsmType*>& args) override;
    173 
    174   ZoneVector<AsmType*> overloads_;
    175 
    176   DISALLOW_IMPLICIT_CONSTRUCTORS(AsmOverloadedFunctionType);
    177 };
    178 
    179 class V8_EXPORT_PRIVATE AsmFFIType final : public AsmCallableType {
    180  public:
    181   AsmFFIType* AsFFIType() override { return this; }
    182 
    183   std::string Name() override { return "Function"; }
    184   bool CanBeInvokedWith(AsmType* return_type,
    185                         const ZoneVector<AsmType*>& args) override;
    186 
    187  private:
    188   friend AsmType;
    189 
    190   AsmFFIType() = default;
    191 
    192   DISALLOW_COPY_AND_ASSIGN(AsmFFIType);
    193 };
    194 
    195 class V8_EXPORT_PRIVATE AsmFunctionTableType : public AsmCallableType {
    196  public:
    197   AsmFunctionTableType* AsFunctionTableType() override { return this; }
    198 
    199   std::string Name() override;
    200 
    201   bool CanBeInvokedWith(AsmType* return_type,
    202                         const ZoneVector<AsmType*>& args) override;
    203 
    204   size_t length() const { return length_; }
    205   AsmType* signature() { return signature_; }
    206 
    207  private:
    208   friend class AsmType;
    209 
    210   AsmFunctionTableType(size_t length, AsmType* signature);
    211 
    212   size_t length_;
    213   AsmType* signature_;
    214 
    215   DISALLOW_IMPLICIT_CONSTRUCTORS(AsmFunctionTableType);
    216 };
    217 
    218 class V8_EXPORT_PRIVATE AsmType {
    219  public:
    220 #define DEFINE_CONSTRUCTOR(CamelName, string_name, number, parent_types) \
    221   static AsmType* CamelName() {                                          \
    222     return AsmValueType::New(AsmValueType::kAsm##CamelName);             \
    223   }
    224   FOR_EACH_ASM_VALUE_TYPE_LIST(DEFINE_CONSTRUCTOR)
    225 #undef DEFINE_CONSTRUCTOR
    226 
    227 #define DEFINE_CAST(CamelCase)                                        \
    228   Asm##CamelCase* As##CamelCase() {                                   \
    229     if (AsValueType() != nullptr) {                                   \
    230       return nullptr;                                                 \
    231     }                                                                 \
    232     return reinterpret_cast<AsmCallableType*>(this)->As##CamelCase(); \
    233   }
    234   FOR_EACH_ASM_CALLABLE_TYPE_LIST(DEFINE_CAST)
    235 #undef DEFINE_CAST
    236   AsmValueType* AsValueType() { return AsmValueType::AsValueType(this); }
    237   AsmCallableType* AsCallableType();
    238 
    239   // A function returning ret. Callers still need to invoke AddArgument with the
    240   // returned type to fully create this type.
    241   static AsmType* Function(Zone* zone, AsmType* ret) {
    242     AsmFunctionType* f = new (zone) AsmFunctionType(zone, ret);
    243     return reinterpret_cast<AsmType*>(f);
    244   }
    245 
    246   // Overloaded function types. Not creatable by asm source, but useful to
    247   // represent the overloaded stdlib functions.
    248   static AsmType* OverloadedFunction(Zone* zone) {
    249     auto* f = new (zone) AsmOverloadedFunctionType(zone);
    250     return reinterpret_cast<AsmType*>(f);
    251   }
    252 
    253   // The type for fround(src).
    254   static AsmType* FroundType(Zone* zone);
    255 
    256   // The (variadic) type for min and max.
    257   static AsmType* MinMaxType(Zone* zone, AsmType* dest, AsmType* src);
    258 
    259   // The type for foreign functions.
    260   static AsmType* FFIType(Zone* zone) {
    261     auto* f = new (zone) AsmFFIType();
    262     return reinterpret_cast<AsmType*>(f);
    263   }
    264 
    265   // The type for function tables.
    266   static AsmType* FunctionTableType(Zone* zone, size_t length,
    267                                     AsmType* signature) {
    268     auto* f = new (zone) AsmFunctionTableType(length, signature);
    269     return reinterpret_cast<AsmType*>(f);
    270   }
    271 
    272   std::string Name();
    273   // IsExactly returns true if this is the exact same type as that. For
    274   // non-value types (e.g., callables), this returns this == that.
    275   bool IsExactly(AsmType* that);
    276   // IsA is used to query whether this is an instance of that (i.e., if this is
    277   // a type derived from that.) For non-value types (e.g., callables), this
    278   // returns this == that.
    279   bool IsA(AsmType* that);
    280 
    281   // Types allowed in return statements. void is the type for returns without
    282   // an expression.
    283   bool IsReturnType() {
    284     return this == AsmType::Void() || this == AsmType::Double() ||
    285            this == AsmType::Signed() || this == AsmType::Float();
    286   }
    287 
    288   // Converts this to the corresponding valid argument type.
    289   AsmType* ToReturnType() {
    290     if (this->IsA(AsmType::Signed())) {
    291       return AsmType::Signed();
    292     }
    293     if (this->IsA(AsmType::Double())) {
    294       return AsmType::Double();
    295     }
    296     if (this->IsA(AsmType::Float())) {
    297       return AsmType::Float();
    298     }
    299     if (this->IsA(AsmType::Void())) {
    300       return AsmType::Void();
    301     }
    302     return AsmType::None();
    303   }
    304 
    305   // Types allowed to be parameters in asm functions.
    306   bool IsParameterType() {
    307     return this == AsmType::Double() || this == AsmType::Int() ||
    308            this == AsmType::Float();
    309   }
    310 
    311   // Converts this to the corresponding valid argument type.
    312   AsmType* ToParameterType() {
    313     if (this->IsA(AsmType::Int())) {
    314       return AsmType::Int();
    315     }
    316     if (this->IsA(AsmType::Double())) {
    317       return AsmType::Double();
    318     }
    319     if (this->IsA(AsmType::Float())) {
    320       return AsmType::Float();
    321     }
    322     return AsmType::None();
    323   }
    324 
    325   // Types allowed to be compared using the comparison operators.
    326   bool IsComparableType() {
    327     return this == AsmType::Double() || this == AsmType::Signed() ||
    328            this == AsmType::Unsigned() || this == AsmType::Float();
    329   }
    330 
    331   // The following methods are meant to be used for inspecting the traits of
    332   // element types for the heap view types.
    333   enum : int32_t { kNotHeapType = -1 };
    334 
    335   // Returns the element size if this is a heap type. Otherwise returns
    336   // kNotHeapType.
    337   int32_t ElementSizeInBytes();
    338   // Returns the load type if this is a heap type. AsmType::None is returned if
    339   // this is not a heap type.
    340   AsmType* LoadType();
    341   // Returns the store type if this is a heap type. AsmType::None is returned if
    342   // this is not a heap type.
    343   AsmType* StoreType();
    344 };
    345 
    346 }  // namespace wasm
    347 }  // namespace internal
    348 }  // namespace v8
    349 
    350 #endif  // SRC_ASMJS_ASM_TYPES_H_
    351