| // 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 (supertype->IsTopType()) return true; |
| 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 { |
| return generated_type_; |
| } |
| |
| std::string BuiltinPointerType::ToExplicitString() const { |
| std::stringstream result; |
| result << "builtin ("; |
| PrintCommaSeparatedList(result, parameter_types_); |
| result << ") => " << *return_type_; |
| return result.str(); |
| } |
| |
| std::string BuiltinPointerType::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(); |
| } |
| |
| std::string StructType::GetGeneratedTypeName() const { |
| return namespace_->ExternalName() + "::" + GetStructName(); |
| } |
| |
| 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 && sig.implicit_count != 0) os << "implicit "; |
| if (sig.implicit_count > 0 && sig.implicit_count == i) { |
| os << ")("; |
| } else { |
| if (i > 0) os << ", "; |
| } |
| if (with_names && !sig.parameter_names.empty()) { |
| if (i < sig.parameter_names.size()) { |
| 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 << ", "; |
| 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, |
| ParameterMode mode) const { |
| auto compare_types = GetTypes(); |
| auto other_compare_types = other.GetTypes(); |
| if (mode == ParameterMode::kIgnoreImplicit) { |
| compare_types = GetExplicitTypes(); |
| other_compare_types = other.GetExplicitTypes(); |
| } |
| if (!(compare_types == other_compare_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 (const 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 operator<(const Type& a, const Type& b) { |
| return a.MangledName() < b.MangledName(); |
| } |
| |
| VisitResult ProjectStructField(VisitResult structure, |
| const std::string& fieldname) { |
| DCHECK(structure.IsOnStack()); |
| BottomOffset begin = structure.stack_range().begin(); |
| const StructType* type = StructType::cast(structure.type()); |
| for (auto& field : type->fields()) { |
| BottomOffset end = begin + LoweredSlotCount(field.type); |
| if (field.name == fieldname) { |
| return VisitResult(field.type, StackRange{begin, end}); |
| } |
| begin = end; |
| } |
| UNREACHABLE(); |
| } |
| |
| namespace { |
| void AppendLoweredTypes(const Type* type, std::vector<const Type*>* result) { |
| DCHECK_NE(type, TypeOracle::GetNeverType()); |
| if (type->IsConstexpr()) return; |
| if (type == TypeOracle::GetVoidType()) return; |
| if (auto* s = StructType::DynamicCast(type)) { |
| for (const NameAndType& field : s->fields()) { |
| AppendLoweredTypes(field.type, result); |
| } |
| } else { |
| result->push_back(type); |
| } |
| } |
| } // namespace |
| |
| TypeVector LowerType(const Type* type) { |
| TypeVector result; |
| AppendLoweredTypes(type, &result); |
| return result; |
| } |
| |
| size_t LoweredSlotCount(const Type* type) { return LowerType(type).size(); } |
| |
| TypeVector LowerParameterTypes(const TypeVector& parameters) { |
| std::vector<const Type*> result; |
| for (const Type* t : parameters) { |
| AppendLoweredTypes(t, &result); |
| } |
| return result; |
| } |
| |
| TypeVector LowerParameterTypes(const ParameterTypes& parameter_types, |
| size_t arg_count) { |
| std::vector<const Type*> result = LowerParameterTypes(parameter_types.types); |
| for (size_t i = parameter_types.types.size(); i < arg_count; ++i) { |
| DCHECK(parameter_types.var_args); |
| AppendLoweredTypes(TypeOracle::GetObjectType(), &result); |
| } |
| return result; |
| } |
| |
| VisitResult VisitResult::NeverResult() { |
| VisitResult result; |
| result.type_ = TypeOracle::GetNeverType(); |
| return result; |
| } |
| |
| } // namespace torque |
| } // namespace internal |
| } // namespace v8 |