| // 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. |
| |
| #ifndef V8_TORQUE_TYPES_H_ |
| #define V8_TORQUE_TYPES_H_ |
| |
| #include <algorithm> |
| #include <map> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "src/base/optional.h" |
| #include "src/torque/ast.h" |
| #include "src/torque/constants.h" |
| #include "src/torque/source-positions.h" |
| #include "src/torque/utils.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace torque { |
| |
| class AggregateType; |
| struct Identifier; |
| class Macro; |
| class Method; |
| class GenericType; |
| class StructType; |
| class Type; |
| class ClassType; |
| class Value; |
| class Namespace; |
| |
| class TypeBase { |
| public: |
| enum class Kind { |
| kTopType, |
| kAbstractType, |
| kBuiltinPointerType, |
| kUnionType, |
| kBitFieldStructType, |
| kStructType, |
| kClassType |
| }; |
| virtual ~TypeBase() = default; |
| bool IsTopType() const { return kind() == Kind::kTopType; } |
| bool IsAbstractType() const { return kind() == Kind::kAbstractType; } |
| bool IsBuiltinPointerType() const { |
| return kind() == Kind::kBuiltinPointerType; |
| } |
| bool IsUnionType() const { return kind() == Kind::kUnionType; } |
| bool IsBitFieldStructType() const { |
| return kind() == Kind::kBitFieldStructType; |
| } |
| bool IsStructType() const { return kind() == Kind::kStructType; } |
| bool IsClassType() const { return kind() == Kind::kClassType; } |
| bool IsAggregateType() const { return IsStructType() || IsClassType(); } |
| |
| protected: |
| explicit TypeBase(Kind kind) : kind_(kind) {} |
| Kind kind() const { return kind_; } |
| |
| private: |
| const Kind kind_; |
| }; |
| |
| #define DECLARE_TYPE_BOILERPLATE(x) \ |
| static x* cast(TypeBase* declarable) { \ |
| DCHECK(declarable->Is##x()); \ |
| return static_cast<x*>(declarable); \ |
| } \ |
| static const x* cast(const TypeBase* declarable) { \ |
| DCHECK(declarable->Is##x()); \ |
| return static_cast<const x*>(declarable); \ |
| } \ |
| static x* DynamicCast(TypeBase* declarable) { \ |
| if (!declarable) return nullptr; \ |
| if (!declarable->Is##x()) return nullptr; \ |
| return static_cast<x*>(declarable); \ |
| } \ |
| static const x* DynamicCast(const TypeBase* declarable) { \ |
| if (!declarable) return nullptr; \ |
| if (!declarable->Is##x()) return nullptr; \ |
| return static_cast<const x*>(declarable); \ |
| } |
| |
| using TypeVector = std::vector<const Type*>; |
| |
| template <typename T> |
| struct SpecializationKey { |
| T* generic; |
| TypeVector specialized_types; |
| }; |
| |
| using MaybeSpecializationKey = base::Optional<SpecializationKey<GenericType>>; |
| |
| struct TypeChecker { |
| // The type of the object. This string is not guaranteed to correspond to a |
| // C++ class, but just to a type checker function: for any type "Foo" here, |
| // the function Object::IsFoo must exist. |
| std::string type; |
| // If {type} is "MaybeObject", then {weak_ref_to} indicates the corresponding |
| // strong object type. Otherwise, {weak_ref_to} is empty. |
| std::string weak_ref_to; |
| }; |
| |
| class V8_EXPORT_PRIVATE Type : public TypeBase { |
| public: |
| Type& operator=(const Type& other) = delete; |
| virtual bool IsSubtypeOf(const Type* supertype) const; |
| |
| // Default rendering for error messages etc. |
| std::string ToString() const; |
| |
| // This name is not unique, but short and somewhat descriptive. |
| // Used for naming generated code. |
| virtual std::string SimpleName() const; |
| |
| std::string UnhandlifiedCppTypeName() const; |
| std::string HandlifiedCppTypeName() const; |
| |
| const Type* parent() const { return parent_; } |
| bool IsVoid() const { return IsAbstractName(VOID_TYPE_STRING); } |
| bool IsNever() const { return IsAbstractName(NEVER_TYPE_STRING); } |
| bool IsBool() const { return IsAbstractName(BOOL_TYPE_STRING); } |
| bool IsConstexprBool() const { |
| return IsAbstractName(CONSTEXPR_BOOL_TYPE_STRING); |
| } |
| bool IsVoidOrNever() const { return IsVoid() || IsNever(); } |
| std::string GetGeneratedTypeName() const; |
| std::string GetGeneratedTNodeTypeName() const; |
| virtual bool IsConstexpr() const { |
| if (parent()) DCHECK(!parent()->IsConstexpr()); |
| return false; |
| } |
| virtual bool IsTransient() const { return false; } |
| virtual const Type* NonConstexprVersion() const { return this; } |
| std::string GetConstexprGeneratedTypeName() const; |
| base::Optional<const ClassType*> ClassSupertype() const; |
| base::Optional<const StructType*> StructSupertype() const; |
| virtual std::vector<TypeChecker> GetTypeCheckers() const { return {}; } |
| virtual std::string GetRuntimeType() const; |
| static const Type* CommonSupertype(const Type* a, const Type* b); |
| void AddAlias(std::string alias) const { aliases_.insert(std::move(alias)); } |
| size_t id() const { return id_; } |
| const MaybeSpecializationKey& GetSpecializedFrom() const { |
| return specialized_from_; |
| } |
| |
| static base::Optional<const Type*> MatchUnaryGeneric(const Type* type, |
| GenericType* generic); |
| |
| static std::string ComputeName(const std::string& basename, |
| MaybeSpecializationKey specialized_from); |
| virtual void SetConstexprVersion(const Type* type) const { |
| constexpr_version_ = type; |
| } |
| |
| virtual const Type* ConstexprVersion() const { |
| if (constexpr_version_) return constexpr_version_; |
| if (IsConstexpr()) return this; |
| if (parent()) return parent()->ConstexprVersion(); |
| return nullptr; |
| } |
| |
| virtual size_t AlignmentLog2() const; |
| |
| protected: |
| Type(TypeBase::Kind kind, const Type* parent, |
| MaybeSpecializationKey specialized_from = base::nullopt); |
| Type(const Type& other) V8_NOEXCEPT; |
| void set_parent(const Type* t) { parent_ = t; } |
| int Depth() const; |
| virtual std::string ToExplicitString() const = 0; |
| virtual std::string GetGeneratedTypeNameImpl() const = 0; |
| virtual std::string GetGeneratedTNodeTypeNameImpl() const = 0; |
| virtual std::string SimpleNameImpl() const = 0; |
| |
| private: |
| bool IsAbstractName(const std::string& name) const; |
| |
| // If {parent_} is not nullptr, then this type is a subtype of {parent_}. |
| const Type* parent_; |
| mutable std::set<std::string> aliases_; |
| size_t id_; |
| MaybeSpecializationKey specialized_from_; |
| mutable const Type* constexpr_version_ = nullptr; |
| }; |
| |
| inline size_t hash_value(const TypeVector& types) { |
| size_t hash = 0; |
| for (const Type* t : types) { |
| hash = base::hash_combine(hash, t); |
| } |
| return hash; |
| } |
| |
| struct NameAndType { |
| std::string name; |
| const Type* type; |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type); |
| |
| struct Field { |
| // TODO(danno): This likely should be refactored, the handling of the types |
| // using the universal grab-bag utility with std::tie, as well as the |
| // reliance of string types is quite clunky. |
| std::tuple<size_t, std::string> GetFieldSizeInformation() const; |
| |
| void ValidateAlignment(ResidueClass at_offset) const; |
| |
| SourcePosition pos; |
| const AggregateType* aggregate; |
| base::Optional<Expression*> index; |
| NameAndType name_and_type; |
| |
| // The byte offset of this field from the beginning of the containing class or |
| // struct. Most structs are never packed together in memory, and are only used |
| // to hold a batch of related CSA TNode values, in which case |offset| is |
| // irrelevant. |
| // The offset may be unknown because the field is after an indexed field or |
| // because we don't support the struct field for on-heap layouts. |
| base::Optional<size_t> offset; |
| |
| bool is_weak; |
| bool const_qualified; |
| bool generate_verify; |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, const Field& name_and_type); |
| |
| class TopType final : public Type { |
| public: |
| DECLARE_TYPE_BOILERPLATE(TopType) |
| std::string GetGeneratedTypeNameImpl() const override { UNREACHABLE(); } |
| std::string GetGeneratedTNodeTypeNameImpl() const override { |
| return source_type_->GetGeneratedTNodeTypeName(); |
| } |
| std::string ToExplicitString() const override { |
| std::stringstream s; |
| s << "inaccessible " + source_type_->ToString(); |
| return s.str(); |
| } |
| |
| const Type* source_type() const { return source_type_; } |
| const std::string reason() const { return reason_; } |
| |
| private: |
| friend class TypeOracle; |
| explicit TopType(std::string reason, const Type* source_type) |
| : Type(Kind::kTopType, nullptr), |
| reason_(std::move(reason)), |
| source_type_(source_type) {} |
| std::string SimpleNameImpl() const override { return "TopType"; } |
| |
| std::string reason_; |
| const Type* source_type_; |
| }; |
| |
| class AbstractType final : public Type { |
| public: |
| DECLARE_TYPE_BOILERPLATE(AbstractType) |
| const std::string& name() const { return name_; } |
| std::string ToExplicitString() const override { return name(); } |
| std::string GetGeneratedTypeNameImpl() const override { |
| if (generated_type_.empty()) { |
| return parent()->GetGeneratedTypeName(); |
| } |
| return IsConstexpr() ? generated_type_ : "TNode<" + generated_type_ + ">"; |
| } |
| std::string GetGeneratedTNodeTypeNameImpl() const override; |
| bool IsConstexpr() const final { |
| const bool is_constexpr = flags_ & AbstractTypeFlag::kConstexpr; |
| DCHECK_IMPLIES(non_constexpr_version_ != nullptr, is_constexpr); |
| return is_constexpr; |
| } |
| |
| const Type* NonConstexprVersion() const override { |
| if (non_constexpr_version_) return non_constexpr_version_; |
| if (!IsConstexpr()) return this; |
| if (parent()) return parent()->NonConstexprVersion(); |
| return nullptr; |
| } |
| |
| std::vector<TypeChecker> GetTypeCheckers() const override; |
| |
| size_t AlignmentLog2() const override; |
| |
| private: |
| friend class TypeOracle; |
| AbstractType(const Type* parent, AbstractTypeFlags flags, |
| const std::string& name, const std::string& generated_type, |
| const Type* non_constexpr_version, |
| MaybeSpecializationKey specialized_from) |
| : Type(Kind::kAbstractType, parent, specialized_from), |
| flags_(flags), |
| name_(name), |
| generated_type_(generated_type), |
| non_constexpr_version_(non_constexpr_version) { |
| if (parent) DCHECK_EQ(parent->IsConstexpr(), IsConstexpr()); |
| DCHECK_EQ(IsConstexprName(name), IsConstexpr()); |
| DCHECK_IMPLIES(non_constexpr_version_ != nullptr, IsConstexpr()); |
| DCHECK(!(IsConstexpr() && (flags_ & AbstractTypeFlag::kTransient))); |
| } |
| |
| std::string SimpleNameImpl() const override { |
| if (IsConstexpr()) { |
| const Type* non_constexpr_version = NonConstexprVersion(); |
| if (non_constexpr_version == nullptr) { |
| ReportError("Cannot find non-constexpr type corresponding to ", *this); |
| } |
| return "constexpr_" + non_constexpr_version->SimpleName(); |
| } |
| return name(); |
| } |
| |
| bool IsTransient() const override { |
| return flags_ & AbstractTypeFlag::kTransient; |
| } |
| |
| bool UseParentTypeChecker() const { |
| return flags_ & AbstractTypeFlag::kUseParentTypeChecker; |
| } |
| |
| AbstractTypeFlags flags_; |
| const std::string name_; |
| const std::string generated_type_; |
| const Type* non_constexpr_version_; |
| }; |
| |
| // For now, builtin pointers are restricted to Torque-defined builtins. |
| class V8_EXPORT_PRIVATE BuiltinPointerType final : public Type { |
| public: |
| DECLARE_TYPE_BOILERPLATE(BuiltinPointerType) |
| std::string ToExplicitString() const override; |
| std::string GetGeneratedTypeNameImpl() const override { |
| return parent()->GetGeneratedTypeName(); |
| } |
| std::string GetGeneratedTNodeTypeNameImpl() const override { |
| return parent()->GetGeneratedTNodeTypeName(); |
| } |
| |
| const TypeVector& parameter_types() const { return parameter_types_; } |
| const Type* return_type() const { return return_type_; } |
| |
| friend size_t hash_value(const BuiltinPointerType& p) { |
| size_t result = base::hash_value(p.return_type_); |
| for (const Type* parameter : p.parameter_types_) { |
| result = base::hash_combine(result, parameter); |
| } |
| return result; |
| } |
| bool operator==(const BuiltinPointerType& other) const { |
| return parameter_types_ == other.parameter_types_ && |
| return_type_ == other.return_type_; |
| } |
| size_t function_pointer_type_id() const { return function_pointer_type_id_; } |
| |
| std::vector<TypeChecker> GetTypeCheckers() const override { |
| return {{"Smi", ""}}; |
| } |
| |
| bool HasContextParameter() const; |
| |
| private: |
| friend class TypeOracle; |
| BuiltinPointerType(const Type* parent, TypeVector parameter_types, |
| const Type* return_type, size_t function_pointer_type_id) |
| : Type(Kind::kBuiltinPointerType, parent), |
| parameter_types_(parameter_types), |
| return_type_(return_type), |
| function_pointer_type_id_(function_pointer_type_id) {} |
| std::string SimpleNameImpl() const override; |
| |
| const TypeVector parameter_types_; |
| const Type* const return_type_; |
| const size_t function_pointer_type_id_; |
| }; |
| |
| bool operator<(const Type& a, const Type& b); |
| struct TypeLess { |
| bool operator()(const Type* const a, const Type* const b) const { |
| return *a < *b; |
| } |
| }; |
| |
| class V8_EXPORT_PRIVATE UnionType final : public Type { |
| public: |
| DECLARE_TYPE_BOILERPLATE(UnionType) |
| std::string GetGeneratedTypeNameImpl() const override { |
| return "TNode<" + GetGeneratedTNodeTypeName() + ">"; |
| } |
| std::string GetGeneratedTNodeTypeNameImpl() const override; |
| std::string GetRuntimeType() const override { |
| return parent()->GetRuntimeType(); |
| } |
| |
| friend size_t hash_value(const UnionType& p) { |
| size_t result = 0; |
| for (const Type* t : p.types_) { |
| result = base::hash_combine(result, t); |
| } |
| return result; |
| } |
| bool operator==(const UnionType& other) const { |
| return types_ == other.types_; |
| } |
| |
| base::Optional<const Type*> GetSingleMember() const { |
| if (types_.size() == 1) { |
| DCHECK_EQ(*types_.begin(), parent()); |
| return *types_.begin(); |
| } |
| return base::nullopt; |
| } |
| |
| bool IsSubtypeOf(const Type* other) const override { |
| for (const Type* member : types_) { |
| if (!member->IsSubtypeOf(other)) return false; |
| } |
| return true; |
| } |
| |
| bool IsSupertypeOf(const Type* other) const { |
| for (const Type* member : types_) { |
| if (other->IsSubtypeOf(member)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool IsTransient() const override { |
| for (const Type* member : types_) { |
| if (member->IsTransient()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool IsConstexpr() const override { return parent()->IsConstexpr(); } |
| |
| const Type* NonConstexprVersion() const override { |
| if (!IsConstexpr()) return this; |
| return parent()->NonConstexprVersion(); |
| } |
| |
| void Extend(const Type* t) { |
| if (const UnionType* union_type = UnionType::DynamicCast(t)) { |
| for (const Type* member : union_type->types_) { |
| Extend(member); |
| } |
| } else { |
| if (t->IsSubtypeOf(this)) return; |
| set_parent(CommonSupertype(parent(), t)); |
| EraseIf(&types_, |
| [&](const Type* member) { return member->IsSubtypeOf(t); }); |
| types_.insert(t); |
| } |
| } |
| std::string ToExplicitString() const override; |
| |
| void Subtract(const Type* t); |
| |
| static UnionType FromType(const Type* t) { |
| const UnionType* union_type = UnionType::DynamicCast(t); |
| return union_type ? UnionType(*union_type) : UnionType(t); |
| } |
| |
| std::vector<TypeChecker> GetTypeCheckers() const override { |
| std::vector<TypeChecker> result; |
| for (const Type* member : types_) { |
| std::vector<TypeChecker> sub_result = member->GetTypeCheckers(); |
| result.insert(result.end(), sub_result.begin(), sub_result.end()); |
| } |
| return result; |
| } |
| |
| private: |
| explicit UnionType(const Type* t) : Type(Kind::kUnionType, t), types_({t}) {} |
| void RecomputeParent(); |
| std::string SimpleNameImpl() const override; |
| |
| std::set<const Type*, TypeLess> types_; |
| }; |
| |
| const Type* SubtractType(const Type* a, const Type* b); |
| |
| struct BitField { |
| SourcePosition pos; |
| NameAndType name_and_type; |
| int offset; |
| int num_bits; |
| }; |
| |
| class V8_EXPORT_PRIVATE BitFieldStructType final : public Type { |
| public: |
| DECLARE_TYPE_BOILERPLATE(BitFieldStructType) |
| std::string ToExplicitString() const override; |
| std::string GetGeneratedTypeNameImpl() const override { |
| return parent()->GetGeneratedTypeName(); |
| } |
| std::string GetGeneratedTNodeTypeNameImpl() const override { |
| return parent()->GetGeneratedTNodeTypeName(); |
| } |
| |
| std::vector<TypeChecker> GetTypeCheckers() const override { |
| return parent()->GetTypeCheckers(); |
| } |
| |
| void SetConstexprVersion(const Type*) const override { UNREACHABLE(); } |
| const Type* ConstexprVersion() const override { |
| return parent()->ConstexprVersion(); |
| } |
| |
| void RegisterField(BitField field) { fields_.push_back(std::move(field)); } |
| |
| const std::string& name() const { return decl_->name->value; } |
| const std::vector<BitField>& fields() const { return fields_; } |
| |
| const BitField& LookupField(const std::string& name) const; |
| |
| private: |
| friend class TypeOracle; |
| BitFieldStructType(Namespace* nspace, const Type* parent, |
| const BitFieldStructDeclaration* decl) |
| : Type(Kind::kBitFieldStructType, parent), |
| namespace_(nspace), |
| decl_(decl) {} |
| std::string SimpleNameImpl() const override { return name(); } |
| |
| Namespace* namespace_; |
| const BitFieldStructDeclaration* decl_; |
| std::vector<BitField> fields_; |
| }; |
| |
| class AggregateType : public Type { |
| public: |
| DECLARE_TYPE_BOILERPLATE(AggregateType) |
| std::string GetGeneratedTypeNameImpl() const override { UNREACHABLE(); } |
| std::string GetGeneratedTNodeTypeNameImpl() const override { UNREACHABLE(); } |
| |
| virtual void Finalize() const = 0; |
| |
| void SetFields(std::vector<Field> fields) { fields_ = std::move(fields); } |
| const std::vector<Field>& fields() const { |
| if (!is_finalized_) Finalize(); |
| return fields_; |
| } |
| bool HasField(const std::string& name) const; |
| const Field& LookupField(const std::string& name) const; |
| const std::string& name() const { return name_; } |
| Namespace* nspace() const { return namespace_; } |
| |
| virtual const Field& RegisterField(Field field) { |
| fields_.push_back(field); |
| return fields_.back(); |
| } |
| |
| void RegisterMethod(Method* method) { methods_.push_back(method); } |
| const std::vector<Method*>& Methods() const { |
| if (!is_finalized_) Finalize(); |
| return methods_; |
| } |
| std::vector<Method*> Methods(const std::string& name) const; |
| |
| std::vector<const AggregateType*> GetHierarchy() const; |
| std::vector<TypeChecker> GetTypeCheckers() const override { |
| return {{name_, ""}}; |
| } |
| |
| protected: |
| AggregateType(Kind kind, const Type* parent, Namespace* nspace, |
| const std::string& name, |
| MaybeSpecializationKey specialized_from = base::nullopt) |
| : Type(kind, parent, specialized_from), |
| is_finalized_(false), |
| namespace_(nspace), |
| name_(name) {} |
| |
| void CheckForDuplicateFields() const; |
| // Use this lookup if you do not want to trigger finalization on this type. |
| const Field& LookupFieldInternal(const std::string& name) const; |
| std::string SimpleNameImpl() const override { return name_; } |
| |
| protected: |
| mutable bool is_finalized_; |
| std::vector<Field> fields_; |
| |
| private: |
| Namespace* namespace_; |
| std::string name_; |
| std::vector<Method*> methods_; |
| }; |
| |
| class StructType final : public AggregateType { |
| public: |
| DECLARE_TYPE_BOILERPLATE(StructType) |
| |
| std::string GetGeneratedTypeNameImpl() const override; |
| |
| // Returns the sum of the size of all members. |
| size_t PackedSize() const; |
| |
| size_t AlignmentLog2() const override; |
| |
| enum class ClassificationFlag { |
| kEmpty = 0, |
| kTagged = 1 << 0, |
| kUntagged = 1 << 1, |
| kMixed = kTagged | kUntagged, |
| }; |
| using Classification = base::Flags<ClassificationFlag>; |
| |
| // Classifies a struct as containing tagged data, untagged data, or both. |
| Classification ClassifyContents() const; |
| |
| SourcePosition GetPosition() const { return decl_->pos; } |
| |
| private: |
| friend class TypeOracle; |
| StructType(Namespace* nspace, const StructDeclaration* decl, |
| MaybeSpecializationKey specialized_from = base::nullopt); |
| |
| void Finalize() const override; |
| std::string ToExplicitString() const override; |
| std::string SimpleNameImpl() const override; |
| |
| const StructDeclaration* decl_; |
| std::string generated_type_name_; |
| }; |
| |
| class TypeAlias; |
| |
| enum class ObjectSlotKind : uint8_t { |
| kNoPointer, |
| kStrongPointer, |
| kMaybeObjectPointer, |
| kCustomWeakPointer |
| }; |
| |
| inline base::Optional<ObjectSlotKind> Combine(ObjectSlotKind a, |
| ObjectSlotKind b) { |
| if (a == b) return {a}; |
| if (std::min(a, b) == ObjectSlotKind::kStrongPointer && |
| std::max(a, b) == ObjectSlotKind::kMaybeObjectPointer) { |
| return {ObjectSlotKind::kMaybeObjectPointer}; |
| } |
| return base::nullopt; |
| } |
| |
| class ClassType final : public AggregateType { |
| public: |
| DECLARE_TYPE_BOILERPLATE(ClassType) |
| std::string ToExplicitString() const override; |
| std::string GetGeneratedTypeNameImpl() const override; |
| std::string GetGeneratedTNodeTypeNameImpl() const override; |
| bool IsExtern() const { return flags_ & ClassFlag::kExtern; } |
| bool ShouldGeneratePrint() const { |
| return !IsExtern() || |
| ((flags_ & ClassFlag::kGeneratePrint) && !HasUndefinedLayout()); |
| } |
| bool ShouldGenerateVerify() const { |
| return !IsExtern() || ((flags_ & ClassFlag::kGenerateVerify) && |
| (!HasUndefinedLayout() && !IsShape())); |
| } |
| bool ShouldGenerateBodyDescriptor() const { |
| if (IsAbstract()) return false; |
| return flags_ & ClassFlag::kGenerateBodyDescriptor || !IsExtern(); |
| } |
| bool DoNotGenerateCast() const { |
| return flags_ & ClassFlag::kDoNotGenerateCast; |
| } |
| bool IsTransient() const override { return flags_ & ClassFlag::kTransient; } |
| bool IsAbstract() const { return flags_ & ClassFlag::kAbstract; } |
| bool HasSameInstanceTypeAsParent() const { |
| return flags_ & ClassFlag::kHasSameInstanceTypeAsParent; |
| } |
| bool GenerateCppClassDefinitions() const { |
| return flags_ & ClassFlag::kGenerateCppClassDefinitions || !IsExtern() || |
| ShouldGenerateBodyDescriptor(); |
| } |
| bool ShouldGenerateFullClassDefinition() const { |
| return !IsExtern() && !(flags_ & ClassFlag::kCustomCppClass); |
| } |
| // Class with multiple or non-standard maps, do not auto-generate map. |
| bool HasCustomMap() const { return flags_ & ClassFlag::kCustomMap; } |
| bool ShouldExport() const { return flags_ & ClassFlag::kExport; } |
| bool IsShape() const { return flags_ & ClassFlag::kIsShape; } |
| bool HasStaticSize() const; |
| size_t header_size() const { |
| if (!is_finalized_) Finalize(); |
| return header_size_; |
| } |
| ResidueClass size() const { |
| if (!is_finalized_) Finalize(); |
| return size_; |
| } |
| const ClassType* GetSuperClass() const { |
| if (parent() == nullptr) return nullptr; |
| return parent()->IsClassType() ? ClassType::DynamicCast(parent()) : nullptr; |
| } |
| void GenerateAccessors(); |
| bool AllowInstantiation() const; |
| const Field& RegisterField(Field field) override { |
| return AggregateType::RegisterField(field); |
| } |
| void Finalize() const override; |
| |
| std::vector<Field> ComputeAllFields() const; |
| std::vector<Field> ComputeHeaderFields() const; |
| std::vector<Field> ComputeArrayFields() const; |
| // The slots of an object are the tagged pointer sized offsets in an object |
| // that may or may not require GC visiting. These helper functions determine |
| // what kind of GC visiting the individual slots require. |
| std::vector<ObjectSlotKind> ComputeHeaderSlotKinds() const; |
| base::Optional<ObjectSlotKind> ComputeArraySlotKind() const; |
| bool HasNoPointerSlots() const; |
| bool HasIndexedFieldsIncludingInParents() const; |
| const Field* GetFieldPreceding(size_t field_index) const; |
| |
| // Given that the field exists in this class or a superclass, returns the |
| // specific class that declared the field. |
| const ClassType* GetClassDeclaringField(const Field& f) const; |
| |
| std::string GetSliceMacroName(const Field& field) const; |
| |
| const InstanceTypeConstraints& GetInstanceTypeConstraints() const { |
| return decl_->instance_type_constraints; |
| } |
| bool IsHighestInstanceTypeWithinParent() const { |
| return flags_ & ClassFlag::kHighestInstanceTypeWithinParent; |
| } |
| bool IsLowestInstanceTypeWithinParent() const { |
| return flags_ & ClassFlag::kLowestInstanceTypeWithinParent; |
| } |
| bool HasUndefinedLayout() const { |
| return flags_ & ClassFlag::kUndefinedLayout; |
| } |
| SourcePosition GetPosition() const { return decl_->pos; } |
| SourceId AttributedToFile() const; |
| |
| // TODO(tebbi): We should no longer pass around types as const pointers, so |
| // that we can avoid mutable fields and const initializers for |
| // late-initialized portions of types like this one. |
| void InitializeInstanceTypes(base::Optional<int> own, |
| base::Optional<std::pair<int, int>> range) const; |
| base::Optional<int> OwnInstanceType() const; |
| base::Optional<std::pair<int, int>> InstanceTypeRange() const; |
| |
| private: |
| friend class TypeOracle; |
| friend class TypeVisitor; |
| ClassType(const Type* parent, Namespace* nspace, const std::string& name, |
| ClassFlags flags, const std::string& generates, |
| const ClassDeclaration* decl, const TypeAlias* alias); |
| |
| void GenerateSliceAccessor(size_t field_index); |
| |
| size_t header_size_; |
| ResidueClass size_; |
| mutable ClassFlags flags_; |
| const std::string generates_; |
| const ClassDeclaration* decl_; |
| const TypeAlias* alias_; |
| mutable base::Optional<int> own_instance_type_; |
| mutable base::Optional<std::pair<int, int>> instance_type_range_; |
| }; |
| |
| inline std::ostream& operator<<(std::ostream& os, const Type& t) { |
| os << t.ToString(); |
| return os; |
| } |
| |
| class VisitResult { |
| public: |
| VisitResult() = default; |
| VisitResult(const Type* type, const std::string& constexpr_value) |
| : type_(type), constexpr_value_(constexpr_value) { |
| DCHECK(type->IsConstexpr()); |
| } |
| static VisitResult NeverResult(); |
| static VisitResult TopTypeResult(std::string top_reason, |
| const Type* from_type); |
| VisitResult(const Type* type, StackRange stack_range) |
| : type_(type), stack_range_(stack_range) { |
| DCHECK(!type->IsConstexpr()); |
| } |
| const Type* type() const { return type_; } |
| const std::string& constexpr_value() const { return *constexpr_value_; } |
| const StackRange& stack_range() const { return *stack_range_; } |
| void SetType(const Type* new_type) { type_ = new_type; } |
| bool IsOnStack() const { return stack_range_ != base::nullopt; } |
| bool operator==(const VisitResult& other) const { |
| return type_ == other.type_ && constexpr_value_ == other.constexpr_value_ && |
| stack_range_ == other.stack_range_; |
| } |
| |
| private: |
| const Type* type_ = nullptr; |
| base::Optional<std::string> constexpr_value_; |
| base::Optional<StackRange> stack_range_; |
| }; |
| |
| VisitResult ProjectStructField(VisitResult structure, |
| const std::string& fieldname); |
| |
| class VisitResultVector : public std::vector<VisitResult> { |
| public: |
| VisitResultVector() : std::vector<VisitResult>() {} |
| VisitResultVector(std::initializer_list<VisitResult> init) |
| : std::vector<VisitResult>(init) {} |
| TypeVector ComputeTypeVector() const { |
| TypeVector result; |
| for (auto& visit_result : *this) { |
| result.push_back(visit_result.type()); |
| } |
| return result; |
| } |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, const TypeVector& types); |
| |
| using NameAndTypeVector = std::vector<NameAndType>; |
| |
| struct LabelDefinition { |
| std::string name; |
| NameAndTypeVector parameters; |
| }; |
| |
| using LabelDefinitionVector = std::vector<LabelDefinition>; |
| |
| struct LabelDeclaration { |
| Identifier* name; |
| TypeVector types; |
| }; |
| |
| using LabelDeclarationVector = std::vector<LabelDeclaration>; |
| |
| struct ParameterTypes { |
| TypeVector types; |
| bool var_args; |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, const ParameterTypes& parameters); |
| |
| enum class ParameterMode { kProcessImplicit, kIgnoreImplicit }; |
| |
| using NameVector = std::vector<Identifier*>; |
| |
| struct Signature { |
| Signature(NameVector n, base::Optional<std::string> arguments_variable, |
| ParameterTypes p, size_t i, const Type* r, LabelDeclarationVector l, |
| bool transitioning) |
| : parameter_names(std::move(n)), |
| arguments_variable(arguments_variable), |
| parameter_types(std::move(p)), |
| implicit_count(i), |
| return_type(r), |
| labels(std::move(l)), |
| transitioning(transitioning) {} |
| Signature() = default; |
| const TypeVector& types() const { return parameter_types.types; } |
| NameVector parameter_names; |
| base::Optional<std::string> arguments_variable; |
| ParameterTypes parameter_types; |
| size_t implicit_count = 0; |
| size_t ExplicitCount() const { return types().size() - implicit_count; } |
| const Type* return_type; |
| LabelDeclarationVector labels; |
| bool transitioning = false; |
| bool HasSameTypesAs( |
| const Signature& other, |
| ParameterMode mode = ParameterMode::kProcessImplicit) const; |
| TypeVector GetImplicitTypes() const { |
| return TypeVector(parameter_types.types.begin(), |
| parameter_types.types.begin() + implicit_count); |
| } |
| TypeVector GetExplicitTypes() const { |
| return TypeVector(parameter_types.types.begin() + implicit_count, |
| parameter_types.types.end()); |
| } |
| bool HasContextParameter() const; |
| }; |
| |
| void PrintSignature(std::ostream& os, const Signature& sig, bool with_names); |
| std::ostream& operator<<(std::ostream& os, const Signature& sig); |
| |
| bool IsAssignableFrom(const Type* to, const Type* from); |
| |
| TypeVector LowerType(const Type* type); |
| size_t LoweredSlotCount(const Type* type); |
| TypeVector LowerParameterTypes(const TypeVector& parameters); |
| TypeVector LowerParameterTypes(const ParameterTypes& parameter_types, |
| size_t vararg_count = 0); |
| |
| base::Optional<std::tuple<size_t, std::string>> SizeOf(const Type* type); |
| bool IsAnyUnsignedInteger(const Type* type); |
| bool IsAllowedAsBitField(const Type* type); |
| bool IsPointerSizeIntegralType(const Type* type); |
| bool Is32BitIntegralType(const Type* type); |
| |
| base::Optional<NameAndType> ExtractSimpleFieldArraySize( |
| const ClassType& class_type, Expression* array_size); |
| |
| } // namespace torque |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_TORQUE_TYPES_H_ |