// 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 <cinttypes>
|
|
#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<AsmCallableType*>(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<AsmType*>& args) override;
|
|
std::string Name() override { return "fround"; }
|
};
|
} // namespace
|
|
AsmType* AsmType::FroundType(Zone* zone) {
|
auto* Fround = new (zone) AsmFroundType();
|
return reinterpret_cast<AsmType*>(Fround);
|
}
|
|
bool AsmFroundType::CanBeInvokedWith(AsmType* return_type,
|
const ZoneVector<AsmType*>& 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<AsmType*>& 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<AsmType*>(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<AsmType*>& 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<AsmType*>& 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
|