Commit 08fed37e authored by jpp's avatar jpp Committed by Commit bot

V8. ASM-2-WASM. Fixes technical debt in asm-types.

BUG= https://bugs.chromium.org/p/v8/issues/detail?id=4203
TEST= cctest/asmjs/test-asm-typer
LOG=N

Review-Url: https://codereview.chromium.org/2148073002
Cr-Commit-Position: refs/heads/master@{#37731}
parent efefadc6
......@@ -811,7 +811,6 @@ AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
}
AsmType* table_element_type = nullptr;
AsmCallableType* callable_type = nullptr;
for (auto* initializer : *pointers) {
auto* var_proxy = initializer->AsVariableProxy();
if (var_proxy == nullptr) {
......@@ -831,8 +830,8 @@ AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
"library.");
}
auto* initializer_callable = var_info->type()->AsFunctionType();
if (initializer_callable == nullptr) {
auto* initializer_type = var_info->type();
if (initializer_type->AsFunctionType() == nullptr) {
FAIL(initializer,
"Function pointer table initializer must be an asm.js function.");
}
......@@ -840,12 +839,9 @@ AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
DCHECK(var_info->type()->AsFFIType() == nullptr);
DCHECK(var_info->type()->AsFunctionTableType() == nullptr);
if (callable_type == nullptr) {
table_element_type = var_info->type();
callable_type = initializer_callable;
} else if (callable_type->ValidateCall(initializer_callable->ReturnType(),
initializer_callable->Arguments()) ==
AsmType::None()) {
if (table_element_type == nullptr) {
table_element_type = initializer_type;
} else if (!initializer_type->IsA(table_element_type)) {
FAIL(initializer, "Type mismatch in function pointer table initializer.");
}
}
......@@ -882,10 +878,8 @@ AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
FAIL(assign, "Function table size mismatch.");
}
auto* function_type = callable_type->AsFunctionType();
if (target_info_table->ValidateCall(function_type->ReturnType(),
function_type->Arguments()) ==
AsmType::None()) {
DCHECK(target_info_table->signature()->AsFunctionType());
if (!table_element_type->IsA(target_info_table->signature())) {
FAIL(assign, "Function table initializer does not match previous type.");
}
......@@ -1050,8 +1044,8 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
auto* fun_var = fun_decl_proxy->var();
auto* fun_info = new (zone_) VariableInfo(fun_type);
fun_info->set_mutability(VariableInfo::kImmutableGlobal);
auto* old_fun_type = Lookup(fun_var);
if (old_fun_type == nullptr) {
auto* old_fun_info = Lookup(fun_var);
if (old_fun_info == nullptr) {
if (!ValidAsmIdentifier(fun_var->name())) {
FAIL(fun_decl_proxy, "Invalid asm.js identifier in function name.");
}
......@@ -1067,22 +1061,20 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
// Not necessarily an error -- fun_decl might have been used before being
// defined. If that's the case, then the type in the global environment must
// be the same as the type inferred by the parameter/return type annotations.
auto* old_fun_callable = old_fun_type->type()->AsCallableType();
if (old_fun_callable == nullptr) {
auto* old_fun_type = old_fun_info->type();
if (old_fun_type->AsFunctionType() == nullptr) {
FAIL(fun_decl, "Identifier redefined as function.");
}
if (!old_fun_type->missing_definition()) {
if (!old_fun_info->missing_definition()) {
FAIL(fun_decl, "Identifier redefined (function name).");
}
if (old_fun_callable->ValidateCall(fun_type_as_function->ReturnType(),
fun_type_as_function->Arguments()) ==
AsmType::None()) {
if (!fun_type->IsA(old_fun_type)) {
FAIL(fun_decl, "Signature mismatch when defining function.");
}
old_fun_type->MarkDefined();
old_fun_info->MarkDefined();
SetTypeOf(fun, fun_type);
return fun_type;
......
......@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#include "src/asmjs/asm-types.h"
#include <cinttypes>
#include "src/v8.h"
namespace v8 {
namespace internal {
namespace wasm {
......@@ -15,10 +17,6 @@ AsmCallableType* AsmType::AsCallableType() {
return nullptr;
}
DCHECK(this->AsFunctionType() != nullptr ||
this->AsOverloadedFunctionType() != nullptr ||
this->AsFFIType() != nullptr ||
this->AsFunctionTableType() != nullptr);
return reinterpret_cast<AsmCallableType*>(this);
}
......@@ -58,16 +56,18 @@ bool AsmType::IsExactly(AsmType* that) {
bool AsmType::IsA(AsmType* that) {
// IsA is used for querying inheritance relationships. Therefore it is only
// meaningful for basic types.
AsmValueType* tavt = that->AsValueType();
if (tavt != nullptr) {
AsmValueType* avt = this->AsValueType();
if (avt == nullptr) {
return false;
if (auto* avt = this->AsValueType()) {
if (auto* tavt = that->AsValueType()) {
return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset();
}
return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset();
return false;
}
if (auto* as_callable = this->AsCallableType()) {
return as_callable->IsA(that);
}
// TODO(jpp): is it useful to allow non-value types to be tested with IsA?
UNREACHABLE();
return that == this;
}
......@@ -138,11 +138,11 @@ AsmType* AsmType::StoreType() {
}
}
std::string AsmFunctionType::Name() {
if (IsFroundType()) {
return "fround";
}
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) {
......@@ -151,54 +151,30 @@ std::string AsmFunctionType::Name() {
ret += ", ";
}
}
if (IsMinMaxType()) {
DCHECK_EQ(args_.size(), 2);
ret += "...";
}
ret += ") -> ";
ret += return_type_->Name();
return ret;
}
namespace {
class AsmFroundType final : public AsmFunctionType {
class AsmFroundType final : public AsmCallableType {
public:
bool IsFroundType() const override { return true; }
private:
friend AsmType;
explicit AsmFroundType(Zone* zone)
: AsmFunctionType(zone, AsmType::Float()) {}
AsmFroundType() : AsmCallableType() {}
AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
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(zone);
auto* Fround = new (zone) AsmFroundType();
return reinterpret_cast<AsmType*>(Fround);
}
// TODO(jpp): Remove this method.
AsmType* AsmFroundType::ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
if (args.size() != 1) {
return AsmType::None();
}
auto* arg = args[0];
if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) &&
!arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) {
return AsmType::None();
}
return AsmType::Float();
}
bool AsmFroundType::CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
if (args.size() != 1) {
......@@ -215,41 +191,16 @@ bool AsmFroundType::CanBeInvokedWith(AsmType* return_type,
}
namespace {
class AsmMinMaxType final : public AsmFunctionType {
public:
bool IsMinMaxType() const override { return true; }
class AsmMinMaxType final : public AsmCallableType {
private:
friend AsmType;
AsmMinMaxType(Zone* zone, AsmType* dest, AsmType* src)
: AsmFunctionType(zone, dest) {
AddArgument(src);
AddArgument(src);
}
AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override {
if (!ReturnType()->IsExactly(return_type)) {
return AsmType::None();
}
if (args.size() < 2) {
return AsmType::None();
}
for (size_t ii = 0; ii < Arguments().size(); ++ii) {
if (!Arguments()[0]->IsExactly(args[ii])) {
return AsmType::None();
}
}
return ReturnType();
}
AsmMinMaxType(AsmType* dest, AsmType* src)
: AsmCallableType(), return_type_(dest), arg_(src) {}
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override {
if (!ReturnType()->IsExactly(return_type)) {
if (!return_type_->IsExactly(return_type)) {
return false;
}
......@@ -257,36 +208,32 @@ class AsmMinMaxType final : public AsmFunctionType {
return false;
}
auto* arg_type = Arguments()[0];
for (size_t ii = 0; ii < Arguments().size(); ++ii) {
if (!args[ii]->IsA(arg_type)) {
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(dest->AsValueType() != nullptr);
DCHECK(src->AsValueType() != nullptr);
auto* MinMax = new (zone) AsmMinMaxType(zone, dest, src);
auto* MinMax = new (zone) AsmMinMaxType(dest, src);
return reinterpret_cast<AsmType*>(MinMax);
}
AsmType* AsmFFIType::ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
for (size_t ii = 0; ii < args.size(); ++ii) {
if (!args[ii]->IsA(AsmType::Extern())) {
return AsmType::None();
}
}
return return_type;
}
bool AsmFFIType::CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
if (return_type->IsExactly(AsmType::Float())) {
......@@ -302,23 +249,26 @@ bool AsmFFIType::CanBeInvokedWith(AsmType* return_type,
return true;
}
AsmType* AsmFunctionType::ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
if (!return_type_->IsExactly(return_type)) {
return AsmType::None();
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() != args.size()) {
return AsmType::None();
if (args_.size() != that->args_.size()) {
return false;
}
for (size_t ii = 0; ii < args_.size(); ++ii) {
if (!args_[ii]->IsExactly(args[ii])) {
return AsmType::None();
if (!args_[ii]->IsExactly(that->args_[ii])) {
return false;
}
}
return return_type_;
return true;
}
bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type,
......@@ -353,19 +303,6 @@ std::string AsmOverloadedFunctionType::Name() {
return ret;
}
AsmType* AsmOverloadedFunctionType::ValidateCall(
AsmType* return_type, const ZoneVector<AsmType*>& args) {
for (size_t ii = 0; ii < overloads_.size(); ++ii) {
auto* validated_type =
overloads_[ii]->AsCallableType()->ValidateCall(return_type, args);
if (validated_type != AsmType::None()) {
return validated_type;
}
}
return AsmType::None();
}
bool AsmOverloadedFunctionType::CanBeInvokedWith(
AsmType* return_type, const ZoneVector<AsmType*>& args) {
for (size_t ii = 0; ii < overloads_.size(); ++ii) {
......@@ -378,7 +315,7 @@ bool AsmOverloadedFunctionType::CanBeInvokedWith(
}
void AsmOverloadedFunctionType::AddOverload(AsmType* overload) {
DCHECK(overload->AsFunctionType() != nullptr);
DCHECK(overload->AsCallableType() != nullptr);
overloads_.push_back(overload);
}
......@@ -388,13 +325,23 @@ AsmFunctionTableType::AsmFunctionTableType(size_t length, AsmType* signature)
DCHECK(signature_->AsFunctionType() != nullptr);
}
std::string AsmFunctionTableType::Name() {
return signature_->Name() + "[" + std::to_string(length_) + "]";
namespace {
// ToString is used for reporting function tables' names. It converts its
// argument to uint32_t because asm.js integers are 32-bits, thus effectively
// limiting the max function table's length.
std::string ToString(size_t s) {
auto u32 = static_cast<uint32_t>(s);
// 16 bytes is more than enough to represent a 32-bit integer as a base 10
// string.
char digits[16];
int length = base::OS::SNPrintF(digits, arraysize(digits), "%" PRIu32, u32);
DCHECK_NE(length, -1);
return std::string(digits, length);
}
} // namespace
AsmType* AsmFunctionTableType::ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
return signature_->AsCallableType()->ValidateCall(return_type, args);
std::string AsmFunctionTableType::Name() {
return "(" + signature_->Name() + ")[" + ToString(length_) + "]";
}
bool AsmFunctionTableType::CanBeInvokedWith(AsmType* return_type,
......
......@@ -26,33 +26,30 @@ class AsmFunctionTableType;
/* These tags are not types that are expressable in the asm source. They */ \
/* are used to express semantic information about the types they tag. */ \
V(Heap, "[]", 1, 0) \
/*The following are actual types that appear in the asm source. */ \
V(Void, "void", 2, 0) \
V(Extern, "extern", 3, 0) \
V(DoubleQ, "double?", 4, 0) \
V(Double, "double", 5, kAsmDoubleQ | kAsmExtern) \
V(Intish, "intish", 6, 0) \
V(Int, "int", 7, kAsmIntish) \
V(Signed, "signed", 8, kAsmInt | kAsmExtern) \
V(Unsigned, "unsigned", 9, kAsmInt) \
V(FixNum, "fixnum", 10, kAsmSigned | kAsmUnsigned) \
V(Floatish, "floatish", 11, 0) \
V(FloatQ, "float?", 12, kAsmFloatish) \
V(Float, "float", 13, kAsmFloatQ) \
V(FloatishDoubleQ, "floatish|double?", 2, 0) \
V(FloatQDoubleQ, "float?|double?", 3, 0) \
/* The following are actual types that appear in the asm source. */ \
V(Void, "void", 4, 0) \
V(Extern, "extern", 5, 0) \
V(DoubleQ, "double?", 6, kAsmFloatishDoubleQ | kAsmFloatQDoubleQ) \
V(Double, "double", 7, kAsmDoubleQ | kAsmExtern) \
V(Intish, "intish", 8, 0) \
V(Int, "int", 9, kAsmIntish) \
V(Signed, "signed", 10, kAsmInt | kAsmExtern) \
V(Unsigned, "unsigned", 11, kAsmInt) \
V(FixNum, "fixnum", 12, kAsmSigned | kAsmUnsigned) \
V(Floatish, "floatish", 13, kAsmFloatishDoubleQ) \
V(FloatQ, "float?", 14, kAsmFloatQDoubleQ | kAsmFloatish) \
V(Float, "float", 15, kAsmFloatQ) \
/* Types used for expressing the Heap accesses. */ \
V(Uint8Array, "Uint8Array", 14, kAsmHeap) \
V(Int8Array, "Int8Array", 15, kAsmHeap) \
V(Uint16Array, "Uint16Array", 16, kAsmHeap) \
V(Int16Array, "Int16Array", 17, kAsmHeap) \
V(Uint32Array, "Uint32Array", 18, kAsmHeap) \
V(Int32Array, "Int32Array", 19, kAsmHeap) \
V(Float32Array, "Float32Array", 20, kAsmHeap) \
V(Float64Array, "Float64Array", 21, kAsmHeap) \
/* Pseudo-types used in representing heap access for fp types.*/ \
/* TODO(jpp): FloatishDoubleQ should be a base type.*/ \
V(FloatishDoubleQ, "floatish|double?", 22, kAsmFloatish | kAsmDoubleQ) \
/* TODO(jpp): FloatQDoubleQ should be a base type.*/ \
V(FloatQDoubleQ, "float?|double?", 23, kAsmFloatQ | kAsmDoubleQ) \
V(Uint8Array, "Uint8Array", 16, kAsmHeap) \
V(Int8Array, "Int8Array", 17, kAsmHeap) \
V(Uint16Array, "Uint16Array", 18, kAsmHeap) \
V(Int16Array, "Int16Array", 19, kAsmHeap) \
V(Uint32Array, "Uint32Array", 20, kAsmHeap) \
V(Int32Array, "Int32Array", 21, kAsmHeap) \
V(Float32Array, "Float32Array", 22, kAsmHeap) \
V(Float64Array, "Float64Array", 23, kAsmHeap) \
/* None is used to represent errors in the type checker. */ \
V(None, "<none>", 31, 0)
......@@ -107,8 +104,6 @@ class AsmValueType {
class AsmCallableType : public ZoneObject {
public:
virtual std::string Name() = 0;
virtual AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) = 0;
virtual bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) = 0;
......@@ -121,12 +116,15 @@ class AsmCallableType : public ZoneObject {
protected:
AsmCallableType() = default;
virtual ~AsmCallableType() = default;
virtual bool IsA(AsmType* other);
private:
friend class AsmType;
DISALLOW_COPY_AND_ASSIGN(AsmCallableType);
};
class AsmFunctionType : public AsmCallableType {
class AsmFunctionType final : public AsmCallableType {
public:
AsmFunctionType* AsFunctionType() final { return this; }
......@@ -134,11 +132,6 @@ class AsmFunctionType : public AsmCallableType {
const ZoneVector<AsmType*> Arguments() const { return args_; }
AsmType* ReturnType() const { return return_type_; }
virtual bool IsMinMaxType() const { return false; }
virtual bool IsFroundType() const { return false; }
AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
......@@ -150,6 +143,7 @@ class AsmFunctionType : public AsmCallableType {
friend AsmType;
std::string Name() override;
bool IsA(AsmType* other) override;
AsmType* return_type_;
ZoneVector<AsmType*> args_;
......@@ -171,8 +165,6 @@ class AsmOverloadedFunctionType final : public AsmCallableType {
explicit AsmOverloadedFunctionType(Zone* zone) : overloads_(zone) {}
std::string Name() override;
AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
......@@ -186,8 +178,6 @@ class AsmFFIType final : public AsmCallableType {
AsmFFIType* AsFFIType() override { return this; }
std::string Name() override { return "Function"; }
AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
......@@ -205,8 +195,6 @@ class AsmFunctionTableType : public AsmCallableType {
std::string Name() override;
AsmType* ValidateCall(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment