| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/asmjs/asm-types.h" |
| 6 |
| 7 #include <cinttypes> |
| 8 |
| 5 #include "src/v8.h" | 9 #include "src/v8.h" |
| 6 | 10 |
| 7 #include "src/asmjs/asm-types.h" | |
| 8 | |
| 9 namespace v8 { | 11 namespace v8 { |
| 10 namespace internal { | 12 namespace internal { |
| 11 namespace wasm { | 13 namespace wasm { |
| 12 | 14 |
| 13 AsmCallableType* AsmType::AsCallableType() { | 15 AsmCallableType* AsmType::AsCallableType() { |
| 14 if (AsValueType() != nullptr) { | 16 if (AsValueType() != nullptr) { |
| 15 return nullptr; | 17 return nullptr; |
| 16 } | 18 } |
| 17 | 19 |
| 18 DCHECK(this->AsFunctionType() != nullptr || | |
| 19 this->AsOverloadedFunctionType() != nullptr || | |
| 20 this->AsFFIType() != nullptr || | |
| 21 this->AsFunctionTableType() != nullptr); | |
| 22 return reinterpret_cast<AsmCallableType*>(this); | 20 return reinterpret_cast<AsmCallableType*>(this); |
| 23 } | 21 } |
| 24 | 22 |
| 25 std::string AsmType::Name() { | 23 std::string AsmType::Name() { |
| 26 AsmValueType* avt = this->AsValueType(); | 24 AsmValueType* avt = this->AsValueType(); |
| 27 if (avt != nullptr) { | 25 if (avt != nullptr) { |
| 28 switch (avt->Bitset()) { | 26 switch (avt->Bitset()) { |
| 29 #define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \ | 27 #define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \ |
| 30 case AsmValueType::kAsm##CamelName: \ | 28 case AsmValueType::kAsm##CamelName: \ |
| 31 return string_name; | 29 return string_name; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 51 } | 49 } |
| 52 | 50 |
| 53 // TODO(jpp): is it useful to allow non-value types to be tested with | 51 // TODO(jpp): is it useful to allow non-value types to be tested with |
| 54 // IsExactly? | 52 // IsExactly? |
| 55 return that == this; | 53 return that == this; |
| 56 } | 54 } |
| 57 | 55 |
| 58 bool AsmType::IsA(AsmType* that) { | 56 bool AsmType::IsA(AsmType* that) { |
| 59 // IsA is used for querying inheritance relationships. Therefore it is only | 57 // IsA is used for querying inheritance relationships. Therefore it is only |
| 60 // meaningful for basic types. | 58 // meaningful for basic types. |
| 61 AsmValueType* tavt = that->AsValueType(); | 59 if (auto* avt = this->AsValueType()) { |
| 62 if (tavt != nullptr) { | 60 if (auto* tavt = that->AsValueType()) { |
| 63 AsmValueType* avt = this->AsValueType(); | 61 return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset(); |
| 64 if (avt == nullptr) { | |
| 65 return false; | |
| 66 } | 62 } |
| 67 return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset(); | 63 return false; |
| 68 } | 64 } |
| 69 | 65 |
| 70 // TODO(jpp): is it useful to allow non-value types to be tested with IsA? | 66 if (auto* as_callable = this->AsCallableType()) { |
| 67 return as_callable->IsA(that); |
| 68 } |
| 69 |
| 70 UNREACHABLE(); |
| 71 return that == this; | 71 return that == this; |
| 72 } | 72 } |
| 73 | 73 |
| 74 int32_t AsmType::ElementSizeInBytes() { | 74 int32_t AsmType::ElementSizeInBytes() { |
| 75 auto* value = AsValueType(); | 75 auto* value = AsValueType(); |
| 76 if (value == nullptr) { | 76 if (value == nullptr) { |
| 77 return AsmType::kNotHeapType; | 77 return AsmType::kNotHeapType; |
| 78 } | 78 } |
| 79 switch (value->Bitset()) { | 79 switch (value->Bitset()) { |
| 80 case AsmValueType::kAsmInt8Array: | 80 case AsmValueType::kAsmInt8Array: |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 return AsmType::Intish(); | 131 return AsmType::Intish(); |
| 132 case AsmValueType::kAsmFloat32Array: | 132 case AsmValueType::kAsmFloat32Array: |
| 133 return AsmType::FloatishDoubleQ(); | 133 return AsmType::FloatishDoubleQ(); |
| 134 case AsmValueType::kAsmFloat64Array: | 134 case AsmValueType::kAsmFloat64Array: |
| 135 return AsmType::FloatQDoubleQ(); | 135 return AsmType::FloatQDoubleQ(); |
| 136 default: | 136 default: |
| 137 return AsmType::None(); | 137 return AsmType::None(); |
| 138 } | 138 } |
| 139 } | 139 } |
| 140 | 140 |
| 141 bool AsmCallableType::IsA(AsmType* other) { |
| 142 return other->AsCallableType() == this; |
| 143 } |
| 144 |
| 141 std::string AsmFunctionType::Name() { | 145 std::string AsmFunctionType::Name() { |
| 142 if (IsFroundType()) { | |
| 143 return "fround"; | |
| 144 } | |
| 145 | |
| 146 std::string ret; | 146 std::string ret; |
| 147 ret += "("; | 147 ret += "("; |
| 148 for (size_t ii = 0; ii < args_.size(); ++ii) { | 148 for (size_t ii = 0; ii < args_.size(); ++ii) { |
| 149 ret += args_[ii]->Name(); | 149 ret += args_[ii]->Name(); |
| 150 if (ii != args_.size() - 1) { | 150 if (ii != args_.size() - 1) { |
| 151 ret += ", "; | 151 ret += ", "; |
| 152 } | 152 } |
| 153 } | 153 } |
| 154 if (IsMinMaxType()) { | |
| 155 DCHECK_EQ(args_.size(), 2); | |
| 156 ret += "..."; | |
| 157 } | |
| 158 ret += ") -> "; | 154 ret += ") -> "; |
| 159 ret += return_type_->Name(); | 155 ret += return_type_->Name(); |
| 160 return ret; | 156 return ret; |
| 161 } | 157 } |
| 162 | 158 |
| 163 namespace { | 159 namespace { |
| 164 class AsmFroundType final : public AsmFunctionType { | 160 class AsmFroundType final : public AsmCallableType { |
| 165 public: | 161 public: |
| 166 bool IsFroundType() const override { return true; } | |
| 167 | |
| 168 private: | |
| 169 friend AsmType; | 162 friend AsmType; |
| 170 | 163 |
| 171 explicit AsmFroundType(Zone* zone) | 164 AsmFroundType() : AsmCallableType() {} |
| 172 : AsmFunctionType(zone, AsmType::Float()) {} | |
| 173 | 165 |
| 174 AsmType* ValidateCall(AsmType* return_type, | |
| 175 const ZoneVector<AsmType*>& args) override; | |
| 176 bool CanBeInvokedWith(AsmType* return_type, | 166 bool CanBeInvokedWith(AsmType* return_type, |
| 177 const ZoneVector<AsmType*>& args) override; | 167 const ZoneVector<AsmType*>& args) override; |
| 168 |
| 169 std::string Name() override { return "fround"; } |
| 178 }; | 170 }; |
| 179 } // namespace | 171 } // namespace |
| 180 | 172 |
| 181 AsmType* AsmType::FroundType(Zone* zone) { | 173 AsmType* AsmType::FroundType(Zone* zone) { |
| 182 auto* Fround = new (zone) AsmFroundType(zone); | 174 auto* Fround = new (zone) AsmFroundType(); |
| 183 return reinterpret_cast<AsmType*>(Fround); | 175 return reinterpret_cast<AsmType*>(Fround); |
| 184 } | 176 } |
| 185 | 177 |
| 186 // TODO(jpp): Remove this method. | |
| 187 AsmType* AsmFroundType::ValidateCall(AsmType* return_type, | |
| 188 const ZoneVector<AsmType*>& args) { | |
| 189 if (args.size() != 1) { | |
| 190 return AsmType::None(); | |
| 191 } | |
| 192 | |
| 193 auto* arg = args[0]; | |
| 194 if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) && | |
| 195 !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) { | |
| 196 return AsmType::None(); | |
| 197 } | |
| 198 | |
| 199 return AsmType::Float(); | |
| 200 } | |
| 201 | |
| 202 bool AsmFroundType::CanBeInvokedWith(AsmType* return_type, | 178 bool AsmFroundType::CanBeInvokedWith(AsmType* return_type, |
| 203 const ZoneVector<AsmType*>& args) { | 179 const ZoneVector<AsmType*>& args) { |
| 204 if (args.size() != 1) { | 180 if (args.size() != 1) { |
| 205 return false; | 181 return false; |
| 206 } | 182 } |
| 207 | 183 |
| 208 auto* arg = args[0]; | 184 auto* arg = args[0]; |
| 209 if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) && | 185 if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) && |
| 210 !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) { | 186 !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) { |
| 211 return false; | 187 return false; |
| 212 } | 188 } |
| 213 | 189 |
| 214 return true; | 190 return true; |
| 215 } | 191 } |
| 216 | 192 |
| 217 namespace { | 193 namespace { |
| 218 class AsmMinMaxType final : public AsmFunctionType { | 194 class AsmMinMaxType final : public AsmCallableType { |
| 219 public: | |
| 220 bool IsMinMaxType() const override { return true; } | |
| 221 | |
| 222 private: | 195 private: |
| 223 friend AsmType; | 196 friend AsmType; |
| 224 | 197 |
| 225 AsmMinMaxType(Zone* zone, AsmType* dest, AsmType* src) | 198 AsmMinMaxType(AsmType* dest, AsmType* src) |
| 226 : AsmFunctionType(zone, dest) { | 199 : AsmCallableType(), return_type_(dest), arg_(src) {} |
| 227 AddArgument(src); | |
| 228 AddArgument(src); | |
| 229 } | |
| 230 | |
| 231 AsmType* ValidateCall(AsmType* return_type, | |
| 232 const ZoneVector<AsmType*>& args) override { | |
| 233 if (!ReturnType()->IsExactly(return_type)) { | |
| 234 return AsmType::None(); | |
| 235 } | |
| 236 | |
| 237 if (args.size() < 2) { | |
| 238 return AsmType::None(); | |
| 239 } | |
| 240 | |
| 241 for (size_t ii = 0; ii < Arguments().size(); ++ii) { | |
| 242 if (!Arguments()[0]->IsExactly(args[ii])) { | |
| 243 return AsmType::None(); | |
| 244 } | |
| 245 } | |
| 246 | |
| 247 return ReturnType(); | |
| 248 } | |
| 249 | 200 |
| 250 bool CanBeInvokedWith(AsmType* return_type, | 201 bool CanBeInvokedWith(AsmType* return_type, |
| 251 const ZoneVector<AsmType*>& args) override { | 202 const ZoneVector<AsmType*>& args) override { |
| 252 if (!ReturnType()->IsExactly(return_type)) { | 203 if (!return_type_->IsExactly(return_type)) { |
| 253 return false; | 204 return false; |
| 254 } | 205 } |
| 255 | 206 |
| 256 if (args.size() < 2) { | 207 if (args.size() < 2) { |
| 257 return false; | 208 return false; |
| 258 } | 209 } |
| 259 | 210 |
| 260 auto* arg_type = Arguments()[0]; | 211 for (size_t ii = 0; ii < args.size(); ++ii) { |
| 261 for (size_t ii = 0; ii < Arguments().size(); ++ii) { | 212 if (!args[ii]->IsA(arg_)) { |
| 262 if (!args[ii]->IsA(arg_type)) { | |
| 263 return false; | 213 return false; |
| 264 } | 214 } |
| 265 } | 215 } |
| 266 | 216 |
| 267 return true; | 217 return true; |
| 268 } | 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_; |
| 269 }; | 227 }; |
| 270 } // namespace | 228 } // namespace |
| 271 | 229 |
| 272 AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) { | 230 AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) { |
| 273 DCHECK(dest->AsValueType() != nullptr); | 231 DCHECK(dest->AsValueType() != nullptr); |
| 274 DCHECK(src->AsValueType() != nullptr); | 232 DCHECK(src->AsValueType() != nullptr); |
| 275 auto* MinMax = new (zone) AsmMinMaxType(zone, dest, src); | 233 auto* MinMax = new (zone) AsmMinMaxType(dest, src); |
| 276 return reinterpret_cast<AsmType*>(MinMax); | 234 return reinterpret_cast<AsmType*>(MinMax); |
| 277 } | 235 } |
| 278 | 236 |
| 279 AsmType* AsmFFIType::ValidateCall(AsmType* return_type, | |
| 280 const ZoneVector<AsmType*>& args) { | |
| 281 for (size_t ii = 0; ii < args.size(); ++ii) { | |
| 282 if (!args[ii]->IsA(AsmType::Extern())) { | |
| 283 return AsmType::None(); | |
| 284 } | |
| 285 } | |
| 286 | |
| 287 return return_type; | |
| 288 } | |
| 289 | |
| 290 bool AsmFFIType::CanBeInvokedWith(AsmType* return_type, | 237 bool AsmFFIType::CanBeInvokedWith(AsmType* return_type, |
| 291 const ZoneVector<AsmType*>& args) { | 238 const ZoneVector<AsmType*>& args) { |
| 292 if (return_type->IsExactly(AsmType::Float())) { | 239 if (return_type->IsExactly(AsmType::Float())) { |
| 293 return false; | 240 return false; |
| 294 } | 241 } |
| 295 | 242 |
| 296 for (size_t ii = 0; ii < args.size(); ++ii) { | 243 for (size_t ii = 0; ii < args.size(); ++ii) { |
| 297 if (!args[ii]->IsA(AsmType::Extern())) { | 244 if (!args[ii]->IsA(AsmType::Extern())) { |
| 298 return false; | 245 return false; |
| 299 } | 246 } |
| 300 } | 247 } |
| 301 | 248 |
| 302 return true; | 249 return true; |
| 303 } | 250 } |
| 304 | 251 |
| 305 AsmType* AsmFunctionType::ValidateCall(AsmType* return_type, | 252 bool AsmFunctionType::IsA(AsmType* other) { |
| 306 const ZoneVector<AsmType*>& args) { | 253 auto* that = other->AsFunctionType(); |
| 307 if (!return_type_->IsExactly(return_type)) { | 254 if (that == nullptr) { |
| 308 return AsmType::None(); | 255 return false; |
| 256 } |
| 257 if (!return_type_->IsExactly(that->return_type_)) { |
| 258 return false; |
| 309 } | 259 } |
| 310 | 260 |
| 311 if (args_.size() != args.size()) { | 261 if (args_.size() != that->args_.size()) { |
| 312 return AsmType::None(); | 262 return false; |
| 313 } | 263 } |
| 314 | 264 |
| 315 for (size_t ii = 0; ii < args_.size(); ++ii) { | 265 for (size_t ii = 0; ii < args_.size(); ++ii) { |
| 316 if (!args_[ii]->IsExactly(args[ii])) { | 266 if (!args_[ii]->IsExactly(that->args_[ii])) { |
| 317 return AsmType::None(); | 267 return false; |
| 318 } | 268 } |
| 319 } | 269 } |
| 320 | 270 |
| 321 return return_type_; | 271 return true; |
| 322 } | 272 } |
| 323 | 273 |
| 324 bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type, | 274 bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type, |
| 325 const ZoneVector<AsmType*>& args) { | 275 const ZoneVector<AsmType*>& args) { |
| 326 if (!return_type_->IsExactly(return_type)) { | 276 if (!return_type_->IsExactly(return_type)) { |
| 327 return false; | 277 return false; |
| 328 } | 278 } |
| 329 | 279 |
| 330 if (args_.size() != args.size()) { | 280 if (args_.size() != args.size()) { |
| 331 return false; | 281 return false; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 346 for (size_t ii = 0; ii < overloads_.size(); ++ii) { | 296 for (size_t ii = 0; ii < overloads_.size(); ++ii) { |
| 347 if (ii != 0) { | 297 if (ii != 0) { |
| 348 ret += " /\\ "; | 298 ret += " /\\ "; |
| 349 } | 299 } |
| 350 ret += overloads_[ii]->Name(); | 300 ret += overloads_[ii]->Name(); |
| 351 } | 301 } |
| 352 | 302 |
| 353 return ret; | 303 return ret; |
| 354 } | 304 } |
| 355 | 305 |
| 356 AsmType* AsmOverloadedFunctionType::ValidateCall( | |
| 357 AsmType* return_type, const ZoneVector<AsmType*>& args) { | |
| 358 for (size_t ii = 0; ii < overloads_.size(); ++ii) { | |
| 359 auto* validated_type = | |
| 360 overloads_[ii]->AsCallableType()->ValidateCall(return_type, args); | |
| 361 if (validated_type != AsmType::None()) { | |
| 362 return validated_type; | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 return AsmType::None(); | |
| 367 } | |
| 368 | |
| 369 bool AsmOverloadedFunctionType::CanBeInvokedWith( | 306 bool AsmOverloadedFunctionType::CanBeInvokedWith( |
| 370 AsmType* return_type, const ZoneVector<AsmType*>& args) { | 307 AsmType* return_type, const ZoneVector<AsmType*>& args) { |
| 371 for (size_t ii = 0; ii < overloads_.size(); ++ii) { | 308 for (size_t ii = 0; ii < overloads_.size(); ++ii) { |
| 372 if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) { | 309 if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) { |
| 373 return true; | 310 return true; |
| 374 } | 311 } |
| 375 } | 312 } |
| 376 | 313 |
| 377 return false; | 314 return false; |
| 378 } | 315 } |
| 379 | 316 |
| 380 void AsmOverloadedFunctionType::AddOverload(AsmType* overload) { | 317 void AsmOverloadedFunctionType::AddOverload(AsmType* overload) { |
| 381 DCHECK(overload->AsFunctionType() != nullptr); | 318 DCHECK(overload->AsCallableType() != nullptr); |
| 382 overloads_.push_back(overload); | 319 overloads_.push_back(overload); |
| 383 } | 320 } |
| 384 | 321 |
| 385 AsmFunctionTableType::AsmFunctionTableType(size_t length, AsmType* signature) | 322 AsmFunctionTableType::AsmFunctionTableType(size_t length, AsmType* signature) |
| 386 : length_(length), signature_(signature) { | 323 : length_(length), signature_(signature) { |
| 387 DCHECK(signature_ != nullptr); | 324 DCHECK(signature_ != nullptr); |
| 388 DCHECK(signature_->AsFunctionType() != nullptr); | 325 DCHECK(signature_->AsFunctionType() != nullptr); |
| 389 } | 326 } |
| 390 | 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 |
| 391 std::string AsmFunctionTableType::Name() { | 343 std::string AsmFunctionTableType::Name() { |
| 392 return signature_->Name() + "[" + std::to_string(length_) + "]"; | 344 return "(" + signature_->Name() + ")[" + ToString(length_) + "]"; |
| 393 } | |
| 394 | |
| 395 AsmType* AsmFunctionTableType::ValidateCall(AsmType* return_type, | |
| 396 const ZoneVector<AsmType*>& args) { | |
| 397 return signature_->AsCallableType()->ValidateCall(return_type, args); | |
| 398 } | 345 } |
| 399 | 346 |
| 400 bool AsmFunctionTableType::CanBeInvokedWith(AsmType* return_type, | 347 bool AsmFunctionTableType::CanBeInvokedWith(AsmType* return_type, |
| 401 const ZoneVector<AsmType*>& args) { | 348 const ZoneVector<AsmType*>& args) { |
| 402 return signature_->AsCallableType()->CanBeInvokedWith(return_type, args); | 349 return signature_->AsCallableType()->CanBeInvokedWith(return_type, args); |
| 403 } | 350 } |
| 404 | 351 |
| 405 } // namespace wasm | 352 } // namespace wasm |
| 406 } // namespace internal | 353 } // namespace internal |
| 407 } // namespace v8 | 354 } // namespace v8 |
| OLD | NEW |