blob: 25c849597db7e3aa585e86726afce20fb3cdcd10 [file] [log] [blame]
// 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_