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 #include "src/asmjs/asm-types.h"
      6 
      7 #include <cinttypes>
      8 
      9 #include "src/utils.h"
     10 #include "src/v8.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 namespace wasm {
     15 
     16 AsmCallableType* AsmType::AsCallableType() {
     17   if (AsValueType() != nullptr) {
     18     return nullptr;
     19   }
     20 
     21   return reinterpret_cast<AsmCallableType*>(this);
     22 }
     23 
     24 std::string AsmType::Name() {
     25   AsmValueType* avt = this->AsValueType();
     26   if (avt != nullptr) {
     27     switch (avt->Bitset()) {
     28 #define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \
     29   case AsmValueType::kAsm##CamelName:                                  \
     30     return string_name;
     31       FOR_EACH_ASM_VALUE_TYPE_LIST(RETURN_TYPE_NAME)
     32 #undef RETURN_TYPE_NAME
     33       default:
     34         UNREACHABLE();
     35     }
     36   }
     37 
     38   return this->AsCallableType()->Name();
     39 }
     40 
     41 bool AsmType::IsExactly(AsmType* that) {
     42   // TODO(jpp): maybe this can become this == that.
     43   AsmValueType* avt = this->AsValueType();
     44   if (avt != nullptr) {
     45     AsmValueType* tavt = that->AsValueType();
     46     if (tavt == nullptr) {
     47       return false;
     48     }
     49     return avt->Bitset() == tavt->Bitset();
     50   }
     51 
     52   // TODO(jpp): is it useful to allow non-value types to be tested with
     53   // IsExactly?
     54   return that == this;
     55 }
     56 
     57 bool AsmType::IsA(AsmType* that) {
     58   // IsA is used for querying inheritance relationships. Therefore it is only
     59   // meaningful for basic types.
     60   if (auto* avt = this->AsValueType()) {
     61     if (auto* tavt = that->AsValueType()) {
     62       return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset();
     63     }
     64     return false;
     65   }
     66 
     67   if (auto* as_callable = this->AsCallableType()) {
     68     return as_callable->IsA(that);
     69   }
     70 
     71   UNREACHABLE();
     72 }
     73 
     74 int32_t AsmType::ElementSizeInBytes() {
     75   auto* value = AsValueType();
     76   if (value == nullptr) {
     77     return AsmType::kNotHeapType;
     78   }
     79   switch (value->Bitset()) {
     80     case AsmValueType::kAsmInt8Array:
     81     case AsmValueType::kAsmUint8Array:
     82       return 1;
     83     case AsmValueType::kAsmInt16Array:
     84     case AsmValueType::kAsmUint16Array:
     85       return 2;
     86     case AsmValueType::kAsmInt32Array:
     87     case AsmValueType::kAsmUint32Array:
     88     case AsmValueType::kAsmFloat32Array:
     89       return 4;
     90     case AsmValueType::kAsmFloat64Array:
     91       return 8;
     92     default:
     93       return AsmType::kNotHeapType;
     94   }
     95 }
     96 
     97 AsmType* AsmType::LoadType() {
     98   auto* value = AsValueType();
     99   if (value == nullptr) {
    100     return AsmType::None();
    101   }
    102   switch (value->Bitset()) {
    103     case AsmValueType::kAsmInt8Array:
    104     case AsmValueType::kAsmUint8Array:
    105     case AsmValueType::kAsmInt16Array:
    106     case AsmValueType::kAsmUint16Array:
    107     case AsmValueType::kAsmInt32Array:
    108     case AsmValueType::kAsmUint32Array:
    109       return AsmType::Intish();
    110     case AsmValueType::kAsmFloat32Array:
    111       return AsmType::FloatQ();
    112     case AsmValueType::kAsmFloat64Array:
    113       return AsmType::DoubleQ();
    114     default:
    115       return AsmType::None();
    116   }
    117 }
    118 
    119 AsmType* AsmType::StoreType() {
    120   auto* value = AsValueType();
    121   if (value == nullptr) {
    122     return AsmType::None();
    123   }
    124   switch (value->Bitset()) {
    125     case AsmValueType::kAsmInt8Array:
    126     case AsmValueType::kAsmUint8Array:
    127     case AsmValueType::kAsmInt16Array:
    128     case AsmValueType::kAsmUint16Array:
    129     case AsmValueType::kAsmInt32Array:
    130     case AsmValueType::kAsmUint32Array:
    131       return AsmType::Intish();
    132     case AsmValueType::kAsmFloat32Array:
    133       return AsmType::FloatishDoubleQ();
    134     case AsmValueType::kAsmFloat64Array:
    135       return AsmType::FloatQDoubleQ();
    136     default:
    137       return AsmType::None();
    138   }
    139 }
    140 
    141 bool AsmCallableType::IsA(AsmType* other) {
    142   return other->AsCallableType() == this;
    143 }
    144 
    145 std::string AsmFunctionType::Name() {
    146   std::string ret;
    147   ret += "(";
    148   for (size_t ii = 0; ii < args_.size(); ++ii) {
    149     ret += args_[ii]->Name();
    150     if (ii != args_.size() - 1) {
    151       ret += ", ";
    152     }
    153   }
    154   ret += ") -> ";
    155   ret += return_type_->Name();
    156   return ret;
    157 }
    158 
    159 namespace {
    160 class AsmFroundType final : public AsmCallableType {
    161  public:
    162   friend AsmType;
    163 
    164   AsmFroundType() : AsmCallableType() {}
    165 
    166   bool CanBeInvokedWith(AsmType* return_type,
    167                         const ZoneVector<AsmType*>& args) override;
    168 
    169   std::string Name() override { return "fround"; }
    170 };
    171 }  // namespace
    172 
    173 AsmType* AsmType::FroundType(Zone* zone) {
    174   auto* Fround = new (zone) AsmFroundType();
    175   return reinterpret_cast<AsmType*>(Fround);
    176 }
    177 
    178 bool AsmFroundType::CanBeInvokedWith(AsmType* return_type,
    179                                      const ZoneVector<AsmType*>& args) {
    180   if (args.size() != 1) {
    181     return false;
    182   }
    183 
    184   auto* arg = args[0];
    185   if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) &&
    186       !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) {
    187     return false;
    188   }
    189 
    190   return true;
    191 }
    192 
    193 namespace {
    194 class AsmMinMaxType final : public AsmCallableType {
    195  private:
    196   friend AsmType;
    197 
    198   AsmMinMaxType(AsmType* dest, AsmType* src)
    199       : AsmCallableType(), return_type_(dest), arg_(src) {}
    200 
    201   bool CanBeInvokedWith(AsmType* return_type,
    202                         const ZoneVector<AsmType*>& args) override {
    203     if (!return_type_->IsExactly(return_type)) {
    204       return false;
    205     }
    206 
    207     if (args.size() < 2) {
    208       return false;
    209     }
    210 
    211     for (size_t ii = 0; ii < args.size(); ++ii) {
    212       if (!args[ii]->IsA(arg_)) {
    213         return false;
    214       }
    215     }
    216 
    217     return true;
    218   }
    219 
    220   std::string Name() override {
    221     return "(" + arg_->Name() + ", " + arg_->Name() + "...) -> " +
    222            return_type_->Name();
    223   }
    224 
    225   AsmType* return_type_;
    226   AsmType* arg_;
    227 };
    228 }  // namespace
    229 
    230 AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) {
    231   DCHECK_NOT_NULL(dest->AsValueType());
    232   DCHECK_NOT_NULL(src->AsValueType());
    233   auto* MinMax = new (zone) AsmMinMaxType(dest, src);
    234   return reinterpret_cast<AsmType*>(MinMax);
    235 }
    236 
    237 bool AsmFunctionType::IsA(AsmType* other) {
    238   auto* that = other->AsFunctionType();
    239   if (that == nullptr) {
    240     return false;
    241   }
    242   if (!return_type_->IsExactly(that->return_type_)) {
    243     return false;
    244   }
    245 
    246   if (args_.size() != that->args_.size()) {
    247     return false;
    248   }
    249 
    250   for (size_t ii = 0; ii < args_.size(); ++ii) {
    251     if (!args_[ii]->IsExactly(that->args_[ii])) {
    252       return false;
    253     }
    254   }
    255 
    256   return true;
    257 }
    258 
    259 bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type,
    260                                        const ZoneVector<AsmType*>& args) {
    261   if (!return_type_->IsExactly(return_type)) {
    262     return false;
    263   }
    264 
    265   if (args_.size() != args.size()) {
    266     return false;
    267   }
    268 
    269   for (size_t ii = 0; ii < args_.size(); ++ii) {
    270     if (!args[ii]->IsA(args_[ii])) {
    271       return false;
    272     }
    273   }
    274 
    275   return true;
    276 }
    277 
    278 std::string AsmOverloadedFunctionType::Name() {
    279   std::string ret;
    280 
    281   for (size_t ii = 0; ii < overloads_.size(); ++ii) {
    282     if (ii != 0) {
    283       ret += " /\\ ";
    284     }
    285     ret += overloads_[ii]->Name();
    286   }
    287 
    288   return ret;
    289 }
    290 
    291 bool AsmOverloadedFunctionType::CanBeInvokedWith(
    292     AsmType* return_type, const ZoneVector<AsmType*>& args) {
    293   for (size_t ii = 0; ii < overloads_.size(); ++ii) {
    294     if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) {
    295       return true;
    296     }
    297   }
    298 
    299   return false;
    300 }
    301 
    302 void AsmOverloadedFunctionType::AddOverload(AsmType* overload) {
    303   DCHECK_NOT_NULL(overload->AsCallableType());
    304   overloads_.push_back(overload);
    305 }
    306 
    307 }  // namespace wasm
    308 }  // namespace internal
    309 }  // namespace v8
    310