// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/asmjs/asm-types.h" #include #include "src/utils.h" #include "src/v8.h" namespace v8 { namespace internal { namespace wasm { AsmCallableType* AsmType::AsCallableType() { if (AsValueType() != nullptr) { return nullptr; } return reinterpret_cast(this); } std::string AsmType::Name() { AsmValueType* avt = this->AsValueType(); if (avt != nullptr) { switch (avt->Bitset()) { #define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \ case AsmValueType::kAsm##CamelName: \ return string_name; FOR_EACH_ASM_VALUE_TYPE_LIST(RETURN_TYPE_NAME) #undef RETURN_TYPE_NAME default: UNREACHABLE(); } } return this->AsCallableType()->Name(); } bool AsmType::IsExactly(AsmType* that) { // TODO(jpp): maybe this can become this == that. AsmValueType* avt = this->AsValueType(); if (avt != nullptr) { AsmValueType* tavt = that->AsValueType(); if (tavt == nullptr) { return false; } return avt->Bitset() == tavt->Bitset(); } // TODO(jpp): is it useful to allow non-value types to be tested with // IsExactly? return that == this; } bool AsmType::IsA(AsmType* that) { // IsA is used for querying inheritance relationships. Therefore it is only // meaningful for basic types. if (auto* avt = this->AsValueType()) { if (auto* tavt = that->AsValueType()) { return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset(); } return false; } if (auto* as_callable = this->AsCallableType()) { return as_callable->IsA(that); } UNREACHABLE(); } int32_t AsmType::ElementSizeInBytes() { auto* value = AsValueType(); if (value == nullptr) { return AsmType::kNotHeapType; } switch (value->Bitset()) { case AsmValueType::kAsmInt8Array: case AsmValueType::kAsmUint8Array: return 1; case AsmValueType::kAsmInt16Array: case AsmValueType::kAsmUint16Array: return 2; case AsmValueType::kAsmInt32Array: case AsmValueType::kAsmUint32Array: case AsmValueType::kAsmFloat32Array: return 4; case AsmValueType::kAsmFloat64Array: return 8; default: return AsmType::kNotHeapType; } } AsmType* AsmType::LoadType() { auto* value = AsValueType(); if (value == nullptr) { return AsmType::None(); } switch (value->Bitset()) { case AsmValueType::kAsmInt8Array: case AsmValueType::kAsmUint8Array: case AsmValueType::kAsmInt16Array: case AsmValueType::kAsmUint16Array: case AsmValueType::kAsmInt32Array: case AsmValueType::kAsmUint32Array: return AsmType::Intish(); case AsmValueType::kAsmFloat32Array: return AsmType::FloatQ(); case AsmValueType::kAsmFloat64Array: return AsmType::DoubleQ(); default: return AsmType::None(); } } AsmType* AsmType::StoreType() { auto* value = AsValueType(); if (value == nullptr) { return AsmType::None(); } switch (value->Bitset()) { case AsmValueType::kAsmInt8Array: case AsmValueType::kAsmUint8Array: case AsmValueType::kAsmInt16Array: case AsmValueType::kAsmUint16Array: case AsmValueType::kAsmInt32Array: case AsmValueType::kAsmUint32Array: return AsmType::Intish(); case AsmValueType::kAsmFloat32Array: return AsmType::FloatishDoubleQ(); case AsmValueType::kAsmFloat64Array: return AsmType::FloatQDoubleQ(); default: return AsmType::None(); } } bool AsmCallableType::IsA(AsmType* other) { return other->AsCallableType() == this; } std::string AsmFunctionType::Name() { std::string ret; ret += "("; for (size_t ii = 0; ii < args_.size(); ++ii) { ret += args_[ii]->Name(); if (ii != args_.size() - 1) { ret += ", "; } } ret += ") -> "; ret += return_type_->Name(); return ret; } namespace { class AsmFroundType final : public AsmCallableType { public: friend AsmType; AsmFroundType() : AsmCallableType() {} bool CanBeInvokedWith(AsmType* return_type, const ZoneVector& args) override; std::string Name() override { return "fround"; } }; } // namespace AsmType* AsmType::FroundType(Zone* zone) { auto* Fround = new (zone) AsmFroundType(); return reinterpret_cast(Fround); } bool AsmFroundType::CanBeInvokedWith(AsmType* return_type, const ZoneVector& args) { if (args.size() != 1) { return false; } auto* arg = args[0]; if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) && !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) { return false; } return true; } namespace { class AsmMinMaxType final : public AsmCallableType { private: friend AsmType; AsmMinMaxType(AsmType* dest, AsmType* src) : AsmCallableType(), return_type_(dest), arg_(src) {} bool CanBeInvokedWith(AsmType* return_type, const ZoneVector& args) override { if (!return_type_->IsExactly(return_type)) { return false; } if (args.size() < 2) { return false; } for (size_t ii = 0; ii < args.size(); ++ii) { if (!args[ii]->IsA(arg_)) { return false; } } return true; } std::string Name() override { return "(" + arg_->Name() + ", " + arg_->Name() + "...) -> " + return_type_->Name(); } AsmType* return_type_; AsmType* arg_; }; } // namespace AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) { DCHECK_NOT_NULL(dest->AsValueType()); DCHECK_NOT_NULL(src->AsValueType()); auto* MinMax = new (zone) AsmMinMaxType(dest, src); return reinterpret_cast(MinMax); } bool AsmFunctionType::IsA(AsmType* other) { auto* that = other->AsFunctionType(); if (that == nullptr) { return false; } if (!return_type_->IsExactly(that->return_type_)) { return false; } if (args_.size() != that->args_.size()) { return false; } for (size_t ii = 0; ii < args_.size(); ++ii) { if (!args_[ii]->IsExactly(that->args_[ii])) { return false; } } return true; } bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type, const ZoneVector& args) { if (!return_type_->IsExactly(return_type)) { return false; } if (args_.size() != args.size()) { return false; } for (size_t ii = 0; ii < args_.size(); ++ii) { if (!args[ii]->IsA(args_[ii])) { return false; } } return true; } std::string AsmOverloadedFunctionType::Name() { std::string ret; for (size_t ii = 0; ii < overloads_.size(); ++ii) { if (ii != 0) { ret += " /\\ "; } ret += overloads_[ii]->Name(); } return ret; } bool AsmOverloadedFunctionType::CanBeInvokedWith( AsmType* return_type, const ZoneVector& args) { for (size_t ii = 0; ii < overloads_.size(); ++ii) { if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) { return true; } } return false; } void AsmOverloadedFunctionType::AddOverload(AsmType* overload) { DCHECK_NOT_NULL(overload->AsCallableType()); overloads_.push_back(overload); } } // namespace wasm } // namespace internal } // namespace v8