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/v8.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 namespace wasm {
     14 
     15 AsmCallableType* AsmType::AsCallableType() {
     16   if (AsValueType() != nullptr) {
     17     return nullptr;
     18   }
     19 
     20   return reinterpret_cast<AsmCallableType*>(this);
     21 }
     22 
     23 std::string AsmType::Name() {
     24   AsmValueType* avt = this->AsValueType();
     25   if (avt != nullptr) {
     26     switch (avt->Bitset()) {
     27 #define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \
     28   case AsmValueType::kAsm##CamelName:                                  \
     29     return string_name;
     30       FOR_EACH_ASM_VALUE_TYPE_LIST(RETURN_TYPE_NAME)
     31 #undef RETURN_TYPE_NAME
     32       default:
     33         UNREACHABLE();
     34     }
     35   }
     36 
     37   return this->AsCallableType()->Name();
     38 }
     39 
     40 bool AsmType::IsExactly(AsmType* that) {
     41   // TODO(jpp): maybe this can become this == that.
     42   AsmValueType* avt = this->AsValueType();
     43   if (avt != nullptr) {
     44     AsmValueType* tavt = that->AsValueType();
     45     if (tavt == nullptr) {
     46       return false;
     47     }
     48     return avt->Bitset() == tavt->Bitset();
     49   }
     50 
     51   // TODO(jpp): is it useful to allow non-value types to be tested with
     52   // IsExactly?
     53   return that == this;
     54 }
     55 
     56 bool AsmType::IsA(AsmType* that) {
     57   // IsA is used for querying inheritance relationships. Therefore it is only
     58   // meaningful for basic types.
     59   if (auto* avt = this->AsValueType()) {
     60     if (auto* tavt = that->AsValueType()) {
     61       return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset();
     62     }
     63     return false;
     64   }
     65 
     66   if (auto* as_callable = this->AsCallableType()) {
     67     return as_callable->IsA(that);
     68   }
     69 
     70   UNREACHABLE();
     71   return that == this;
     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(dest->AsValueType() != nullptr);
    232   DCHECK(src->AsValueType() != nullptr);
    233   auto* MinMax = new (zone) AsmMinMaxType(dest, src);
    234   return reinterpret_cast<AsmType*>(MinMax);
    235 }
    236 
    237 bool AsmFFIType::CanBeInvokedWith(AsmType* return_type,
    238                                   const ZoneVector<AsmType*>& args) {
    239   if (return_type->IsExactly(AsmType::Float())) {
    240     return false;
    241   }
    242 
    243   for (size_t ii = 0; ii < args.size(); ++ii) {
    244     if (!args[ii]->IsA(AsmType::Extern())) {
    245       return false;
    246     }
    247   }
    248 
    249   return true;
    250 }
    251 
    252 bool AsmFunctionType::IsA(AsmType* other) {
    253   auto* that = other->AsFunctionType();
    254   if (that == nullptr) {
    255     return false;
    256   }
    257   if (!return_type_->IsExactly(that->return_type_)) {
    258     return false;
    259   }
    260 
    261   if (args_.size() != that->args_.size()) {
    262     return false;
    263   }
    264 
    265   for (size_t ii = 0; ii < args_.size(); ++ii) {
    266     if (!args_[ii]->IsExactly(that->args_[ii])) {
    267       return false;
    268     }
    269   }
    270 
    271   return true;
    272 }
    273 
    274 bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type,
    275                                        const ZoneVector<AsmType*>& args) {
    276   if (!return_type_->IsExactly(return_type)) {
    277     return false;
    278   }
    279 
    280   if (args_.size() != args.size()) {
    281     return false;
    282   }
    283 
    284   for (size_t ii = 0; ii < args_.size(); ++ii) {
    285     if (!args[ii]->IsA(args_[ii])) {
    286       return false;
    287     }
    288   }
    289 
    290   return true;
    291 }
    292 
    293 std::string AsmOverloadedFunctionType::Name() {
    294   std::string ret;
    295 
    296   for (size_t ii = 0; ii < overloads_.size(); ++ii) {
    297     if (ii != 0) {
    298       ret += " /\\ ";
    299     }
    300     ret += overloads_[ii]->Name();
    301   }
    302 
    303   return ret;
    304 }
    305 
    306 bool AsmOverloadedFunctionType::CanBeInvokedWith(
    307     AsmType* return_type, const ZoneVector<AsmType*>& args) {
    308   for (size_t ii = 0; ii < overloads_.size(); ++ii) {
    309     if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) {
    310       return true;
    311     }
    312   }
    313 
    314   return false;
    315 }
    316 
    317 void AsmOverloadedFunctionType::AddOverload(AsmType* overload) {
    318   DCHECK(overload->AsCallableType() != nullptr);
    319   overloads_.push_back(overload);
    320 }
    321 
    322 AsmFunctionTableType::AsmFunctionTableType(size_t length, AsmType* signature)
    323     : length_(length), signature_(signature) {
    324   DCHECK(signature_ != nullptr);
    325   DCHECK(signature_->AsFunctionType() != nullptr);
    326 }
    327 
    328 namespace {
    329 // ToString is used for reporting function tables' names. It converts its
    330 // argument to uint32_t because asm.js integers are 32-bits, thus effectively
    331 // limiting the max function table's length.
    332 std::string ToString(size_t s) {
    333   auto u32 = static_cast<uint32_t>(s);
    334   // 16 bytes is more than enough to represent a 32-bit integer as a base 10
    335   // string.
    336   char digits[16];
    337   int length = base::OS::SNPrintF(digits, arraysize(digits), "%" PRIu32, u32);
    338   DCHECK_NE(length, -1);
    339   return std::string(digits, length);
    340 }
    341 }  // namespace
    342 
    343 std::string AsmFunctionTableType::Name() {
    344   return "(" + signature_->Name() + ")[" + ToString(length_) + "]";
    345 }
    346 
    347 bool AsmFunctionTableType::CanBeInvokedWith(AsmType* return_type,
    348                                             const ZoneVector<AsmType*>& args) {
    349   return signature_->AsCallableType()->CanBeInvokedWith(return_type, args);
    350 }
    351 
    352 }  // namespace wasm
    353 }  // namespace internal
    354 }  // namespace v8
    355