// Copyright 2017 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 <iostream> #include "src/torque/declarable.h" #include "src/torque/type-oracle.h" #include "src/torque/types.h" namespace v8 { namespace internal { namespace torque { std::string Type::ToString() const { if (aliases_.size() == 0) return ToExplicitString(); if (aliases_.size() == 1) return *aliases_.begin(); std::stringstream result; int i = 0; for (const std::string& alias : aliases_) { if (i == 0) { result << alias << " (aka. "; } else if (i == 1) { result << alias; } else { result << ", " << alias; } ++i; } result << ")"; return result.str(); } bool Type::IsSubtypeOf(const Type* supertype) const { if (IsNever()) return true; if (const UnionType* union_type = UnionType::DynamicCast(supertype)) { return union_type->IsSupertypeOf(this); } const Type* subtype = this; while (subtype != nullptr) { if (subtype == supertype) return true; subtype = subtype->parent(); } return false; } // static const Type* Type::CommonSupertype(const Type* a, const Type* b) { int diff = a->Depth() - b->Depth(); const Type* a_supertype = a; const Type* b_supertype = b; for (; diff > 0; --diff) a_supertype = a_supertype->parent(); for (; diff < 0; ++diff) b_supertype = b_supertype->parent(); while (a_supertype && b_supertype) { if (a_supertype == b_supertype) return a_supertype; a_supertype = a_supertype->parent(); b_supertype = b_supertype->parent(); } ReportError("types " + a->ToString() + " and " + b->ToString() + " have no common supertype"); } int Type::Depth() const { int result = 0; for (const Type* current = parent_; current; current = current->parent_) { ++result; } return result; } bool Type::IsAbstractName(const std::string& name) const { if (!IsAbstractType()) return false; return AbstractType::cast(this)->name() == name; } std::string AbstractType::GetGeneratedTNodeTypeName() const { std::string result = GetGeneratedTypeName(); DCHECK_EQ(result.substr(0, 6), "TNode<"); result = result.substr(6, result.length() - 7); return result; } std::string FunctionPointerType::ToExplicitString() const { std::stringstream result; result << "builtin ("; PrintCommaSeparatedList(result, parameter_types_); result << ") => " << *return_type_; return result.str(); } std::string FunctionPointerType::MangledName() const { std::stringstream result; result << "FT"; for (const Type* t : parameter_types_) { std::string arg_type_string = t->MangledName(); result << arg_type_string.size() << arg_type_string; } std::string return_type_string = return_type_->MangledName(); result << return_type_string.size() << return_type_string; return result.str(); } std::string UnionType::ToExplicitString() const { std::stringstream result; result << "("; bool first = true; for (const Type* t : types_) { if (!first) { result << " | "; } first = false; result << *t; } result << ")"; return result.str(); } std::string UnionType::MangledName() const { std::stringstream result; result << "UT"; for (const Type* t : types_) { std::string arg_type_string = t->MangledName(); result << arg_type_string.size() << arg_type_string; } return result.str(); } std::string UnionType::GetGeneratedTNodeTypeName() const { if (types_.size() <= 3) { std::set<std::string> members; for (const Type* t : types_) { members.insert(t->GetGeneratedTNodeTypeName()); } if (members == std::set<std::string>{"Smi", "HeapNumber"}) { return "Number"; } if (members == std::set<std::string>{"Smi", "HeapNumber", "BigInt"}) { return "Numeric"; } } return parent()->GetGeneratedTNodeTypeName(); } const Type* UnionType::NonConstexprVersion() const { if (IsConstexpr()) { auto it = types_.begin(); UnionType result((*it)->NonConstexprVersion()); ++it; for (; it != types_.end(); ++it) { result.Extend((*it)->NonConstexprVersion()); } return TypeOracle::GetUnionType(std::move(result)); } return this; } void UnionType::RecomputeParent() { const Type* parent = nullptr; for (const Type* t : types_) { if (parent == nullptr) { parent = t; } else { parent = CommonSupertype(parent, t); } } set_parent(parent); } void UnionType::Subtract(const Type* t) { for (auto it = types_.begin(); it != types_.end();) { if ((*it)->IsSubtypeOf(t)) { it = types_.erase(it); } else { ++it; } } if (types_.size() == 0) types_.insert(TypeOracle::GetNeverType()); RecomputeParent(); } const Type* SubtractType(const Type* a, const Type* b) { UnionType result = UnionType::FromType(a); result.Subtract(b); return TypeOracle::GetUnionType(result); } std::string StructType::ToExplicitString() const { std::stringstream result; result << "{"; PrintCommaSeparatedList(result, fields_); result << "}"; return result.str(); } void PrintSignature(std::ostream& os, const Signature& sig, bool with_names) { os << "("; for (size_t i = 0; i < sig.parameter_types.types.size(); ++i) { if (i > 0) os << ", "; if (with_names && !sig.parameter_names.empty()) { os << sig.parameter_names[i] << ": "; } os << *sig.parameter_types.types[i]; } if (sig.parameter_types.var_args) { if (sig.parameter_names.size()) os << ", "; os << "..."; } os << ")"; os << ": " << *sig.return_type; if (sig.labels.empty()) return; os << " labels "; for (size_t i = 0; i < sig.labels.size(); ++i) { if (i > 0) os << ", "; if (with_names) os << sig.labels[i].name; if (sig.labels[i].types.size() > 0) os << "(" << sig.labels[i].types << ")"; } } std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type) { os << name_and_type.name; os << ": "; os << *name_and_type.type; return os; } std::ostream& operator<<(std::ostream& os, const Signature& sig) { PrintSignature(os, sig, true); return os; } std::ostream& operator<<(std::ostream& os, const TypeVector& types) { PrintCommaSeparatedList(os, types); return os; } std::ostream& operator<<(std::ostream& os, const ParameterTypes& p) { PrintCommaSeparatedList(os, p.types); if (p.var_args) { if (p.types.size() > 0) os << ", "; os << "..."; } return os; } bool Signature::HasSameTypesAs(const Signature& other) const { if (!(parameter_types.types == other.parameter_types.types && parameter_types.var_args == other.parameter_types.var_args && return_type == other.return_type)) { return false; } if (labels.size() != other.labels.size()) { return false; } size_t i = 0; for (auto l : labels) { if (l.types != other.labels[i++].types) { return false; } } return true; } bool IsAssignableFrom(const Type* to, const Type* from) { if (to == from) return true; if (from->IsSubtypeOf(to)) return true; return TypeOracle::IsImplicitlyConvertableFrom(to, from); } bool IsCompatibleSignature(const Signature& sig, const TypeVector& types, const std::vector<Label*>& labels) { auto i = sig.parameter_types.types.begin(); if (sig.parameter_types.types.size() > types.size()) return false; // TODO(danno): The test below is actually insufficient. The labels' // parameters must be checked too. ideally, the named part of // LabelDeclarationVector would be factored out so that the label count and // parameter types could be passed separately. if (sig.labels.size() != labels.size()) return false; for (auto current : types) { if (i == sig.parameter_types.types.end()) { if (!sig.parameter_types.var_args) return false; if (!IsAssignableFrom(TypeOracle::GetObjectType(), current)) return false; } else { if (!IsAssignableFrom(*i++, current)) return false; } } return true; } bool operator<(const Type& a, const Type& b) { return a.MangledName() < b.MangledName(); } VisitResult::VisitResult(const Type* type, const Value* declarable) : type_(type), value_(), declarable_(declarable) {} std::string VisitResult::LValue() const { return std::string("*") + (declarable_ ? (*declarable_)->value() : value_); } std::string VisitResult::RValue() const { std::string result; if (declarable()) { auto value = *declarable(); if (value->IsVariable() && !Variable::cast(value)->IsDefined()) { std::stringstream s; s << "\"" << value->name() << "\" is used before it is defined"; ReportError(s.str()); } result = value->RValue(); } else { result = value_; } return "implicit_cast<" + type()->GetGeneratedTypeName() + ">(" + result + ")"; } } // namespace torque } // namespace internal } // namespace v8