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