• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_TORQUE_TYPES_H_
6 #define V8_TORQUE_TYPES_H_
7 
8 #include <algorithm>
9 #include <set>
10 #include <string>
11 #include <vector>
12 
13 #include "src/base/optional.h"
14 #include "src/torque/ast.h"
15 #include "src/torque/constants.h"
16 #include "src/torque/source-positions.h"
17 #include "src/torque/utils.h"
18 
19 namespace v8 {
20 namespace internal {
21 namespace torque {
22 
23 class AggregateType;
24 struct Identifier;
25 class Macro;
26 class Method;
27 class GenericType;
28 class StructType;
29 class Type;
30 class ClassType;
31 class Value;
32 class Namespace;
33 
34 class TypeBase {
35  public:
36   enum class Kind {
37     kTopType,
38     kAbstractType,
39     kBuiltinPointerType,
40     kUnionType,
41     kBitFieldStructType,
42     kStructType,
43     kClassType
44   };
45   virtual ~TypeBase() = default;
IsTopType()46   bool IsTopType() const { return kind() == Kind::kTopType; }
IsAbstractType()47   bool IsAbstractType() const { return kind() == Kind::kAbstractType; }
IsBuiltinPointerType()48   bool IsBuiltinPointerType() const {
49     return kind() == Kind::kBuiltinPointerType;
50   }
IsUnionType()51   bool IsUnionType() const { return kind() == Kind::kUnionType; }
IsBitFieldStructType()52   bool IsBitFieldStructType() const {
53     return kind() == Kind::kBitFieldStructType;
54   }
IsStructType()55   bool IsStructType() const { return kind() == Kind::kStructType; }
IsClassType()56   bool IsClassType() const { return kind() == Kind::kClassType; }
IsAggregateType()57   bool IsAggregateType() const { return IsStructType() || IsClassType(); }
58 
59  protected:
TypeBase(Kind kind)60   explicit TypeBase(Kind kind) : kind_(kind) {}
kind()61   Kind kind() const { return kind_; }
62 
63  private:
64   const Kind kind_;
65 };
66 
67 #define DECLARE_TYPE_BOILERPLATE(x)                         \
68   static x* cast(TypeBase* declarable) {                    \
69     DCHECK(declarable->Is##x());                            \
70     return static_cast<x*>(declarable);                     \
71   }                                                         \
72   static const x* cast(const TypeBase* declarable) {        \
73     DCHECK(declarable->Is##x());                            \
74     return static_cast<const x*>(declarable);               \
75   }                                                         \
76   static x* DynamicCast(TypeBase* declarable) {             \
77     if (!declarable) return nullptr;                        \
78     if (!declarable->Is##x()) return nullptr;               \
79     return static_cast<x*>(declarable);                     \
80   }                                                         \
81   static const x* DynamicCast(const TypeBase* declarable) { \
82     if (!declarable) return nullptr;                        \
83     if (!declarable->Is##x()) return nullptr;               \
84     return static_cast<const x*>(declarable);               \
85   }
86 
87 using TypeVector = std::vector<const Type*>;
88 
89 template <typename T>
90 struct SpecializationKey {
91   T* generic;
92   TypeVector specialized_types;
93 };
94 
95 using MaybeSpecializationKey = base::Optional<SpecializationKey<GenericType>>;
96 
97 struct TypeChecker {
98   // The type of the object. This string is not guaranteed to correspond to a
99   // C++ class, but just to a type checker function: for any type "Foo" here,
100   // the function Object::IsFoo must exist.
101   std::string type;
102   // If {type} is "MaybeObject", then {weak_ref_to} indicates the corresponding
103   // strong object type. Otherwise, {weak_ref_to} is empty.
104   std::string weak_ref_to;
105 };
106 
107 class V8_EXPORT_PRIVATE Type : public TypeBase {
108  public:
109   Type& operator=(const Type& other) = delete;
110   virtual bool IsSubtypeOf(const Type* supertype) const;
111 
112   // Default rendering for error messages etc.
113   std::string ToString() const;
114 
115   // This name is not unique, but short and somewhat descriptive.
116   // Used for naming generated code.
117   virtual std::string SimpleName() const;
118 
119   std::string UnhandlifiedCppTypeName() const;
120   std::string HandlifiedCppTypeName() const;
121 
parent()122   const Type* parent() const { return parent_; }
IsVoid()123   bool IsVoid() const { return IsAbstractName(VOID_TYPE_STRING); }
IsNever()124   bool IsNever() const { return IsAbstractName(NEVER_TYPE_STRING); }
IsBool()125   bool IsBool() const { return IsAbstractName(BOOL_TYPE_STRING); }
IsConstexprBool()126   bool IsConstexprBool() const {
127     return IsAbstractName(CONSTEXPR_BOOL_TYPE_STRING);
128   }
IsVoidOrNever()129   bool IsVoidOrNever() const { return IsVoid() || IsNever(); }
130   std::string GetGeneratedTypeName() const;
131   std::string GetGeneratedTNodeTypeName() const;
IsConstexpr()132   virtual bool IsConstexpr() const {
133     if (parent()) DCHECK(!parent()->IsConstexpr());
134     return false;
135   }
IsTransient()136   virtual bool IsTransient() const { return false; }
NonConstexprVersion()137   virtual const Type* NonConstexprVersion() const { return this; }
138   std::string GetConstexprGeneratedTypeName() const;
139   base::Optional<const ClassType*> ClassSupertype() const;
140   base::Optional<const StructType*> StructSupertype() const;
141   base::Optional<const AggregateType*> AggregateSupertype() const;
GetTypeCheckers()142   virtual std::vector<TypeChecker> GetTypeCheckers() const { return {}; }
143   virtual std::string GetRuntimeType() const;
144   virtual std::string GetDebugType() const;
145   static const Type* CommonSupertype(const Type* a, const Type* b);
AddAlias(std::string alias)146   void AddAlias(std::string alias) const { aliases_.insert(std::move(alias)); }
id()147   size_t id() const { return id_; }
GetSpecializedFrom()148   const MaybeSpecializationKey& GetSpecializedFrom() const {
149     return specialized_from_;
150   }
151 
152   static base::Optional<const Type*> MatchUnaryGeneric(const Type* type,
153                                                        GenericType* generic);
154 
155   static std::string ComputeName(const std::string& basename,
156                                  MaybeSpecializationKey specialized_from);
SetConstexprVersion(const Type * type)157   virtual void SetConstexprVersion(const Type* type) const {
158     constexpr_version_ = type;
159   }
160 
ConstexprVersion()161   virtual const Type* ConstexprVersion() const {
162     if (constexpr_version_) return constexpr_version_;
163     if (IsConstexpr()) return this;
164     if (parent()) return parent()->ConstexprVersion();
165     return nullptr;
166   }
167 
168   virtual size_t AlignmentLog2() const;
169 
170  protected:
171   Type(TypeBase::Kind kind, const Type* parent,
172        MaybeSpecializationKey specialized_from = base::nullopt);
173   Type(const Type& other) V8_NOEXCEPT;
set_parent(const Type * t)174   void set_parent(const Type* t) { parent_ = t; }
175   int Depth() const;
176   virtual std::string ToExplicitString() const = 0;
177   virtual std::string GetGeneratedTypeNameImpl() const = 0;
178   virtual std::string GetGeneratedTNodeTypeNameImpl() const = 0;
179   virtual std::string SimpleNameImpl() const = 0;
180 
181  private:
182   bool IsAbstractName(const std::string& name) const;
183 
184   // If {parent_} is not nullptr, then this type is a subtype of {parent_}.
185   const Type* parent_;
186   mutable std::set<std::string> aliases_;
187   size_t id_;
188   MaybeSpecializationKey specialized_from_;
189   mutable const Type* constexpr_version_ = nullptr;
190 };
191 
hash_value(const TypeVector & types)192 inline size_t hash_value(const TypeVector& types) {
193   size_t hash = 0;
194   for (const Type* t : types) {
195     hash = base::hash_combine(hash, t);
196   }
197   return hash;
198 }
199 
200 struct NameAndType {
201   std::string name;
202   const Type* type;
203 };
204 
205 std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type);
206 
207 struct Field {
208   // TODO(danno): This likely should be refactored, the handling of the types
209   // using the universal grab-bag utility with std::tie, as well as the
210   // reliance of string types is quite clunky.
211   std::tuple<size_t, std::string> GetFieldSizeInformation() const;
212 
213   void ValidateAlignment(ResidueClass at_offset) const;
214 
215   SourcePosition pos;
216   const AggregateType* aggregate;
217   base::Optional<ClassFieldIndexInfo> index;
218   NameAndType name_and_type;
219 
220   // The byte offset of this field from the beginning of the containing class or
221   // struct. Most structs are never packed together in memory, and are only used
222   // to hold a batch of related CSA TNode values, in which case |offset| is
223   // irrelevant.
224   // The offset may be unknown because the field is after an indexed field or
225   // because we don't support the struct field for on-heap layouts.
226   base::Optional<size_t> offset;
227 
228   bool custom_weak_marking;
229   bool const_qualified;
230   FieldSynchronization read_synchronization;
231   FieldSynchronization write_synchronization;
232 };
233 
234 std::ostream& operator<<(std::ostream& os, const Field& name_and_type);
235 
236 class TopType final : public Type {
237  public:
DECLARE_TYPE_BOILERPLATE(TopType)238   DECLARE_TYPE_BOILERPLATE(TopType)
239   std::string GetGeneratedTypeNameImpl() const override { UNREACHABLE(); }
GetGeneratedTNodeTypeNameImpl()240   std::string GetGeneratedTNodeTypeNameImpl() const override {
241     return source_type_->GetGeneratedTNodeTypeName();
242   }
ToExplicitString()243   std::string ToExplicitString() const override {
244     std::stringstream s;
245     s << "inaccessible " + source_type_->ToString();
246     return s.str();
247   }
248 
source_type()249   const Type* source_type() const { return source_type_; }
reason()250   const std::string reason() const { return reason_; }
251 
252  private:
253   friend class TypeOracle;
TopType(std::string reason,const Type * source_type)254   explicit TopType(std::string reason, const Type* source_type)
255       : Type(Kind::kTopType, nullptr),
256         reason_(std::move(reason)),
257         source_type_(source_type) {}
SimpleNameImpl()258   std::string SimpleNameImpl() const override { return "TopType"; }
259 
260   std::string reason_;
261   const Type* source_type_;
262 };
263 
264 class AbstractType final : public Type {
265  public:
DECLARE_TYPE_BOILERPLATE(AbstractType)266   DECLARE_TYPE_BOILERPLATE(AbstractType)
267   const std::string& name() const { return name_; }
ToExplicitString()268   std::string ToExplicitString() const override { return name(); }
269   std::string GetGeneratedTypeNameImpl() const override;
270   std::string GetGeneratedTNodeTypeNameImpl() const override;
IsConstexpr()271   bool IsConstexpr() const final {
272     const bool is_constexpr = flags_ & AbstractTypeFlag::kConstexpr;
273     DCHECK_IMPLIES(non_constexpr_version_ != nullptr, is_constexpr);
274     return is_constexpr;
275   }
276 
NonConstexprVersion()277   const Type* NonConstexprVersion() const override {
278     if (non_constexpr_version_) return non_constexpr_version_;
279     if (!IsConstexpr()) return this;
280     if (parent()) return parent()->NonConstexprVersion();
281     return nullptr;
282   }
283 
284   std::vector<TypeChecker> GetTypeCheckers() const override;
285 
286   size_t AlignmentLog2() const override;
287 
288  private:
289   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)290   AbstractType(const Type* parent, AbstractTypeFlags flags,
291                const std::string& name, const std::string& generated_type,
292                const Type* non_constexpr_version,
293                MaybeSpecializationKey specialized_from)
294       : Type(Kind::kAbstractType, parent, specialized_from),
295         flags_(flags),
296         name_(name),
297         generated_type_(generated_type),
298         non_constexpr_version_(non_constexpr_version) {
299     if (parent) DCHECK_EQ(parent->IsConstexpr(), IsConstexpr());
300     DCHECK_EQ(IsConstexprName(name), IsConstexpr());
301     DCHECK_IMPLIES(non_constexpr_version_ != nullptr, IsConstexpr());
302     DCHECK(!(IsConstexpr() && (flags_ & AbstractTypeFlag::kTransient)));
303   }
304 
SimpleNameImpl()305   std::string SimpleNameImpl() const override {
306     if (IsConstexpr()) {
307       const Type* non_constexpr_version = NonConstexprVersion();
308       if (non_constexpr_version == nullptr) {
309         ReportError("Cannot find non-constexpr type corresponding to ", *this);
310       }
311       return "constexpr_" + non_constexpr_version->SimpleName();
312     }
313     return name();
314   }
315 
IsTransient()316   bool IsTransient() const override {
317     return flags_ & AbstractTypeFlag::kTransient;
318   }
319 
UseParentTypeChecker()320   bool UseParentTypeChecker() const {
321     return flags_ & AbstractTypeFlag::kUseParentTypeChecker;
322   }
323 
324   AbstractTypeFlags flags_;
325   const std::string name_;
326   const std::string generated_type_;
327   const Type* non_constexpr_version_;
328 };
329 
330 // For now, builtin pointers are restricted to Torque-defined builtins.
331 class V8_EXPORT_PRIVATE BuiltinPointerType final : public Type {
332  public:
333   DECLARE_TYPE_BOILERPLATE(BuiltinPointerType)
334   std::string ToExplicitString() const override;
GetGeneratedTypeNameImpl()335   std::string GetGeneratedTypeNameImpl() const override {
336     return parent()->GetGeneratedTypeName();
337   }
GetGeneratedTNodeTypeNameImpl()338   std::string GetGeneratedTNodeTypeNameImpl() const override {
339     return parent()->GetGeneratedTNodeTypeName();
340   }
341 
parameter_types()342   const TypeVector& parameter_types() const { return parameter_types_; }
return_type()343   const Type* return_type() const { return return_type_; }
344 
hash_value(const BuiltinPointerType & p)345   friend size_t hash_value(const BuiltinPointerType& p) {
346     size_t result = base::hash_value(p.return_type_);
347     for (const Type* parameter : p.parameter_types_) {
348       result = base::hash_combine(result, parameter);
349     }
350     return result;
351   }
352   bool operator==(const BuiltinPointerType& other) const {
353     return parameter_types_ == other.parameter_types_ &&
354            return_type_ == other.return_type_;
355   }
function_pointer_type_id()356   size_t function_pointer_type_id() const { return function_pointer_type_id_; }
357 
GetTypeCheckers()358   std::vector<TypeChecker> GetTypeCheckers() const override {
359     return {{"Smi", ""}};
360   }
361 
362   bool HasContextParameter() const;
363 
364  private:
365   friend class TypeOracle;
BuiltinPointerType(const Type * parent,TypeVector parameter_types,const Type * return_type,size_t function_pointer_type_id)366   BuiltinPointerType(const Type* parent, TypeVector parameter_types,
367                      const Type* return_type, size_t function_pointer_type_id)
368       : Type(Kind::kBuiltinPointerType, parent),
369         parameter_types_(parameter_types),
370         return_type_(return_type),
371         function_pointer_type_id_(function_pointer_type_id) {}
372   std::string SimpleNameImpl() const override;
373 
374   const TypeVector parameter_types_;
375   const Type* const return_type_;
376   const size_t function_pointer_type_id_;
377 };
378 
379 bool operator<(const Type& a, const Type& b);
380 struct TypeLess {
operatorTypeLess381   bool operator()(const Type* const a, const Type* const b) const {
382     return *a < *b;
383   }
384 };
385 
386 class V8_EXPORT_PRIVATE UnionType final : public Type {
387  public:
DECLARE_TYPE_BOILERPLATE(UnionType)388   DECLARE_TYPE_BOILERPLATE(UnionType)
389   std::string GetGeneratedTypeNameImpl() const override {
390     return "TNode<" + GetGeneratedTNodeTypeName() + ">";
391   }
392   std::string GetGeneratedTNodeTypeNameImpl() const override;
GetRuntimeType()393   std::string GetRuntimeType() const override {
394     return parent()->GetRuntimeType();
395   }
GetDebugType()396   std::string GetDebugType() const override { return parent()->GetDebugType(); }
397 
hash_value(const UnionType & p)398   friend size_t hash_value(const UnionType& p) {
399     size_t result = 0;
400     for (const Type* t : p.types_) {
401       result = base::hash_combine(result, t);
402     }
403     return result;
404   }
405   bool operator==(const UnionType& other) const {
406     return types_ == other.types_;
407   }
408 
GetSingleMember()409   base::Optional<const Type*> GetSingleMember() const {
410     if (types_.size() == 1) {
411       DCHECK_EQ(*types_.begin(), parent());
412       return *types_.begin();
413     }
414     return base::nullopt;
415   }
416 
IsSubtypeOf(const Type * other)417   bool IsSubtypeOf(const Type* other) const override {
418     for (const Type* member : types_) {
419       if (!member->IsSubtypeOf(other)) return false;
420     }
421     return true;
422   }
423 
IsSupertypeOf(const Type * other)424   bool IsSupertypeOf(const Type* other) const {
425     for (const Type* member : types_) {
426       if (other->IsSubtypeOf(member)) {
427         return true;
428       }
429     }
430     return false;
431   }
432 
IsTransient()433   bool IsTransient() const override {
434     for (const Type* member : types_) {
435       if (member->IsTransient()) {
436         return true;
437       }
438     }
439     return false;
440   }
441 
IsConstexpr()442   bool IsConstexpr() const override { return parent()->IsConstexpr(); }
443 
NonConstexprVersion()444   const Type* NonConstexprVersion() const override {
445     if (!IsConstexpr()) return this;
446     return parent()->NonConstexprVersion();
447   }
448 
Extend(const Type * t)449   void Extend(const Type* t) {
450     if (const UnionType* union_type = UnionType::DynamicCast(t)) {
451       for (const Type* member : union_type->types_) {
452         Extend(member);
453       }
454     } else {
455       if (t->IsSubtypeOf(this)) return;
456       set_parent(CommonSupertype(parent(), t));
457       EraseIf(&types_,
458               [&](const Type* member) { return member->IsSubtypeOf(t); });
459       types_.insert(t);
460     }
461   }
462   std::string ToExplicitString() const override;
463 
464   void Subtract(const Type* t);
465 
FromType(const Type * t)466   static UnionType FromType(const Type* t) {
467     const UnionType* union_type = UnionType::DynamicCast(t);
468     return union_type ? UnionType(*union_type) : UnionType(t);
469   }
470 
GetTypeCheckers()471   std::vector<TypeChecker> GetTypeCheckers() const override {
472     std::vector<TypeChecker> result;
473     for (const Type* member : types_) {
474       std::vector<TypeChecker> sub_result = member->GetTypeCheckers();
475       result.insert(result.end(), sub_result.begin(), sub_result.end());
476     }
477     return result;
478   }
479 
480  private:
UnionType(const Type * t)481   explicit UnionType(const Type* t) : Type(Kind::kUnionType, t), types_({t}) {}
482   void RecomputeParent();
483   std::string SimpleNameImpl() const override;
484 
485   std::set<const Type*, TypeLess> types_;
486 };
487 
488 const Type* SubtractType(const Type* a, const Type* b);
489 
490 struct BitField {
491   SourcePosition pos;
492   NameAndType name_and_type;
493   int offset;
494   int num_bits;
495 };
496 
497 class V8_EXPORT_PRIVATE BitFieldStructType final : public Type {
498  public:
499   DECLARE_TYPE_BOILERPLATE(BitFieldStructType)
500   std::string ToExplicitString() const override;
GetGeneratedTypeNameImpl()501   std::string GetGeneratedTypeNameImpl() const override {
502     return parent()->GetGeneratedTypeName();
503   }
GetGeneratedTNodeTypeNameImpl()504   std::string GetGeneratedTNodeTypeNameImpl() const override {
505     return parent()->GetGeneratedTNodeTypeName();
506   }
507 
GetTypeCheckers()508   std::vector<TypeChecker> GetTypeCheckers() const override {
509     return parent()->GetTypeCheckers();
510   }
511 
SetConstexprVersion(const Type *)512   void SetConstexprVersion(const Type*) const override { UNREACHABLE(); }
ConstexprVersion()513   const Type* ConstexprVersion() const override {
514     return parent()->ConstexprVersion();
515   }
516 
RegisterField(BitField field)517   void RegisterField(BitField field) { fields_.push_back(std::move(field)); }
518 
name()519   const std::string& name() const { return decl_->name->value; }
fields()520   const std::vector<BitField>& fields() const { return fields_; }
521 
522   const BitField& LookupField(const std::string& name) const;
523 
524  private:
525   friend class TypeOracle;
BitFieldStructType(Namespace * nspace,const Type * parent,const BitFieldStructDeclaration * decl)526   BitFieldStructType(Namespace* nspace, const Type* parent,
527                      const BitFieldStructDeclaration* decl)
528       : Type(Kind::kBitFieldStructType, parent),
529         namespace_(nspace),
530         decl_(decl) {}
SimpleNameImpl()531   std::string SimpleNameImpl() const override { return name(); }
532 
533   Namespace* namespace_;
534   const BitFieldStructDeclaration* decl_;
535   std::vector<BitField> fields_;
536 };
537 
538 class AggregateType : public Type {
539  public:
DECLARE_TYPE_BOILERPLATE(AggregateType)540   DECLARE_TYPE_BOILERPLATE(AggregateType)
541   std::string GetGeneratedTypeNameImpl() const override { UNREACHABLE(); }
GetGeneratedTNodeTypeNameImpl()542   std::string GetGeneratedTNodeTypeNameImpl() const override { UNREACHABLE(); }
543 
544   virtual void Finalize() const = 0;
545 
SetFields(std::vector<Field> fields)546   void SetFields(std::vector<Field> fields) { fields_ = std::move(fields); }
fields()547   const std::vector<Field>& fields() const {
548     if (!is_finalized_) Finalize();
549     return fields_;
550   }
551   bool HasField(const std::string& name) const;
552   const Field& LookupField(const std::string& name) const;
name()553   const std::string& name() const { return name_; }
nspace()554   Namespace* nspace() const { return namespace_; }
555 
RegisterField(Field field)556   virtual const Field& RegisterField(Field field) {
557     fields_.push_back(field);
558     return fields_.back();
559   }
560 
RegisterMethod(Method * method)561   void RegisterMethod(Method* method) { methods_.push_back(method); }
Methods()562   const std::vector<Method*>& Methods() const {
563     if (!is_finalized_) Finalize();
564     return methods_;
565   }
566   std::vector<Method*> Methods(const std::string& name) const;
567 
568   std::vector<const AggregateType*> GetHierarchy() const;
GetTypeCheckers()569   std::vector<TypeChecker> GetTypeCheckers() const override {
570     return {{name_, ""}};
571   }
572 
LastField()573   const Field& LastField() const {
574     for (base::Optional<const AggregateType*> current = this;
575          current.has_value();
576          current = (*current)->parent()->AggregateSupertype()) {
577       const std::vector<Field>& fields = (*current)->fields_;
578       if (!fields.empty()) return fields[fields.size() - 1];
579     }
580     ReportError("Can't get last field of empty aggregate type");
581   }
582 
583  protected:
584   AggregateType(Kind kind, const Type* parent, Namespace* nspace,
585                 const std::string& name,
586                 MaybeSpecializationKey specialized_from = base::nullopt)
Type(kind,parent,specialized_from)587       : Type(kind, parent, specialized_from),
588         is_finalized_(false),
589         namespace_(nspace),
590         name_(name) {}
591 
592   void CheckForDuplicateFields() const;
593   // Use this lookup if you do not want to trigger finalization on this type.
594   const Field& LookupFieldInternal(const std::string& name) const;
SimpleNameImpl()595   std::string SimpleNameImpl() const override { return name_; }
596 
597  protected:
598   mutable bool is_finalized_;
599   std::vector<Field> fields_;
600 
601  private:
602   Namespace* namespace_;
603   std::string name_;
604   std::vector<Method*> methods_;
605 };
606 
607 class StructType final : public AggregateType {
608  public:
609   DECLARE_TYPE_BOILERPLATE(StructType)
610 
611   std::string GetGeneratedTypeNameImpl() const override;
612 
613   // Returns the sum of the size of all members.
614   size_t PackedSize() const;
615 
616   size_t AlignmentLog2() const override;
617 
618   enum class ClassificationFlag {
619     kEmpty = 0,
620     kStrongTagged = 1 << 0,
621     kWeakTagged = 1 << 1,
622     kUntagged = 1 << 2,
623   };
624   using Classification = base::Flags<ClassificationFlag>;
625 
626   // Classifies a struct as containing tagged data, untagged data, or both.
627   Classification ClassifyContents() const;
628 
GetPosition()629   SourcePosition GetPosition() const { return decl_->pos; }
630 
631  private:
632   friend class TypeOracle;
633   StructType(Namespace* nspace, const StructDeclaration* decl,
634              MaybeSpecializationKey specialized_from = base::nullopt);
635 
636   void Finalize() const override;
637   std::string ToExplicitString() const override;
638   std::string SimpleNameImpl() const override;
639 
640   const StructDeclaration* decl_;
641   std::string generated_type_name_;
642 };
643 
644 class TypeAlias;
645 
646 enum class ObjectSlotKind : uint8_t {
647   kNoPointer,
648   kStrongPointer,
649   kMaybeObjectPointer,
650   kCustomWeakPointer
651 };
652 
Combine(ObjectSlotKind a,ObjectSlotKind b)653 inline base::Optional<ObjectSlotKind> Combine(ObjectSlotKind a,
654                                               ObjectSlotKind b) {
655   if (a == b) return {a};
656   if (std::min(a, b) == ObjectSlotKind::kStrongPointer &&
657       std::max(a, b) == ObjectSlotKind::kMaybeObjectPointer) {
658     return {ObjectSlotKind::kMaybeObjectPointer};
659   }
660   return base::nullopt;
661 }
662 
663 class ClassType final : public AggregateType {
664  public:
665   DECLARE_TYPE_BOILERPLATE(ClassType)
666   std::string ToExplicitString() const override;
667   std::string GetGeneratedTypeNameImpl() const override;
668   std::string GetGeneratedTNodeTypeNameImpl() const override;
IsExtern()669   bool IsExtern() const { return flags_ & ClassFlag::kExtern; }
ShouldGeneratePrint()670   bool ShouldGeneratePrint() const {
671     if (flags_ & ClassFlag::kCppObjectDefinition) return false;
672     if (!IsExtern()) return true;
673     if (!ShouldGenerateCppClassDefinitions()) return false;
674     return !IsAbstract() && !HasUndefinedLayout();
675   }
ShouldGenerateVerify()676   bool ShouldGenerateVerify() const {
677     if (flags_ & ClassFlag::kCppObjectDefinition) return false;
678     if (!IsExtern()) return true;
679     if (!ShouldGenerateCppClassDefinitions()) return false;
680     return !HasUndefinedLayout() && !IsShape();
681   }
ShouldGenerateBodyDescriptor()682   bool ShouldGenerateBodyDescriptor() const {
683     if (flags_ & ClassFlag::kCppObjectDefinition) return false;
684     if (flags_ & ClassFlag::kGenerateBodyDescriptor) return true;
685     return !IsAbstract() && !IsExtern();
686   }
DoNotGenerateCast()687   bool DoNotGenerateCast() const {
688     return flags_ & ClassFlag::kDoNotGenerateCast;
689   }
IsTransient()690   bool IsTransient() const override { return flags_ & ClassFlag::kTransient; }
IsAbstract()691   bool IsAbstract() const { return flags_ & ClassFlag::kAbstract; }
HasSameInstanceTypeAsParent()692   bool HasSameInstanceTypeAsParent() const {
693     return flags_ & ClassFlag::kHasSameInstanceTypeAsParent;
694   }
ShouldGenerateCppClassDefinitions()695   bool ShouldGenerateCppClassDefinitions() const {
696     if (flags_ & ClassFlag::kCppObjectDefinition) return false;
697     return (flags_ & ClassFlag::kGenerateCppClassDefinitions) || !IsExtern();
698   }
ShouldGenerateCppObjectDefinitionAsserts()699   bool ShouldGenerateCppObjectDefinitionAsserts() const {
700     return flags_ & ClassFlag::kCppObjectDefinition;
701   }
ShouldGenerateFullClassDefinition()702   bool ShouldGenerateFullClassDefinition() const { return !IsExtern(); }
ShouldGenerateUniqueMap()703   bool ShouldGenerateUniqueMap() const {
704     return (flags_ & ClassFlag::kGenerateUniqueMap) ||
705            (!IsExtern() && !IsAbstract());
706   }
ShouldGenerateFactoryFunction()707   bool ShouldGenerateFactoryFunction() const {
708     return (flags_ & ClassFlag::kGenerateFactoryFunction) ||
709            (ShouldExport() && !IsAbstract());
710   }
ShouldExport()711   bool ShouldExport() const { return flags_ & ClassFlag::kExport; }
IsShape()712   bool IsShape() const { return flags_ & ClassFlag::kIsShape; }
713   bool HasStaticSize() const;
header_size()714   size_t header_size() const {
715     if (!is_finalized_) Finalize();
716     return header_size_;
717   }
size()718   ResidueClass size() const {
719     if (!is_finalized_) Finalize();
720     return size_;
721   }
GetSuperClass()722   const ClassType* GetSuperClass() const {
723     if (parent() == nullptr) return nullptr;
724     return parent()->IsClassType() ? ClassType::DynamicCast(parent()) : nullptr;
725   }
726   void GenerateAccessors();
727   bool AllowInstantiation() const;
RegisterField(Field field)728   const Field& RegisterField(Field field) override {
729     return AggregateType::RegisterField(field);
730   }
731   void Finalize() const override;
732 
733   std::vector<Field> ComputeAllFields() const;
734   std::vector<Field> ComputeHeaderFields() const;
735   std::vector<Field> ComputeArrayFields() const;
736   // The slots of an object are the tagged pointer sized offsets in an object
737   // that may or may not require GC visiting. These helper functions determine
738   // what kind of GC visiting the individual slots require.
739   std::vector<ObjectSlotKind> ComputeHeaderSlotKinds() const;
740   base::Optional<ObjectSlotKind> ComputeArraySlotKind() const;
741   bool HasNoPointerSlots() const;
742   bool HasIndexedFieldsIncludingInParents() const;
743   const Field* GetFieldPreceding(size_t field_index) const;
744 
745   // Given that the field exists in this class or a superclass, returns the
746   // specific class that declared the field.
747   const ClassType* GetClassDeclaringField(const Field& f) const;
748 
749   std::string GetSliceMacroName(const Field& field) const;
750 
GetInstanceTypeConstraints()751   const InstanceTypeConstraints& GetInstanceTypeConstraints() const {
752     return decl_->instance_type_constraints;
753   }
IsHighestInstanceTypeWithinParent()754   bool IsHighestInstanceTypeWithinParent() const {
755     return flags_ & ClassFlag::kHighestInstanceTypeWithinParent;
756   }
IsLowestInstanceTypeWithinParent()757   bool IsLowestInstanceTypeWithinParent() const {
758     return flags_ & ClassFlag::kLowestInstanceTypeWithinParent;
759   }
HasUndefinedLayout()760   bool HasUndefinedLayout() const {
761     return flags_ & ClassFlag::kUndefinedLayout;
762   }
GetPosition()763   SourcePosition GetPosition() const { return decl_->pos; }
764   SourceId AttributedToFile() const;
765 
766   // TODO(turbofan): We should no longer pass around types as const pointers, so
767   // that we can avoid mutable fields and const initializers for
768   // late-initialized portions of types like this one.
769   void InitializeInstanceTypes(base::Optional<int> own,
770                                base::Optional<std::pair<int, int>> range) const;
771   base::Optional<int> OwnInstanceType() const;
772   base::Optional<std::pair<int, int>> InstanceTypeRange() const;
773 
774  private:
775   friend class TypeOracle;
776   friend class TypeVisitor;
777   ClassType(const Type* parent, Namespace* nspace, const std::string& name,
778             ClassFlags flags, const std::string& generates,
779             const ClassDeclaration* decl, const TypeAlias* alias);
780 
781   void GenerateSliceAccessor(size_t field_index);
782 
783   size_t header_size_;
784   ResidueClass size_;
785   mutable ClassFlags flags_;
786   const std::string generates_;
787   const ClassDeclaration* decl_;
788   const TypeAlias* alias_;
789   mutable base::Optional<int> own_instance_type_;
790   mutable base::Optional<std::pair<int, int>> instance_type_range_;
791 };
792 
793 inline std::ostream& operator<<(std::ostream& os, const Type& t) {
794   os << t.ToString();
795   return os;
796 }
797 
798 template <bool success = false>
799 std::ostream& operator<<(std::ostream& os, const Type* t) {
800   static_assert(success,
801                 "Using Type* with an ostream is usually a mistake. Did you "
802                 "mean to use Type& instead? If you actually intended to print "
803                 "a pointer, use static_cast<const void*>.");
804   return os;
805 }
806 
807 // Don't emit an error if a Type* is printed due to CHECK macros.
808 inline std::ostream& operator<<(base::CheckMessageStream& os, const Type* t) {
809   return os << static_cast<const void*>(t);
810 }
811 
812 class VisitResult {
813  public:
814   VisitResult() = default;
VisitResult(const Type * type,const std::string & constexpr_value)815   VisitResult(const Type* type, const std::string& constexpr_value)
816       : type_(type), constexpr_value_(constexpr_value) {
817     DCHECK(type->IsConstexpr());
818   }
819   static VisitResult NeverResult();
820   static VisitResult TopTypeResult(std::string top_reason,
821                                    const Type* from_type);
VisitResult(const Type * type,StackRange stack_range)822   VisitResult(const Type* type, StackRange stack_range)
823       : type_(type), stack_range_(stack_range) {
824     DCHECK(!type->IsConstexpr());
825   }
type()826   const Type* type() const { return type_; }
constexpr_value()827   const std::string& constexpr_value() const { return *constexpr_value_; }
stack_range()828   const StackRange& stack_range() const { return *stack_range_; }
SetType(const Type * new_type)829   void SetType(const Type* new_type) { type_ = new_type; }
IsOnStack()830   bool IsOnStack() const { return stack_range_ != base::nullopt; }
831   bool operator==(const VisitResult& other) const {
832     return type_ == other.type_ && constexpr_value_ == other.constexpr_value_ &&
833            stack_range_ == other.stack_range_;
834   }
835 
836  private:
837   const Type* type_ = nullptr;
838   base::Optional<std::string> constexpr_value_;
839   base::Optional<StackRange> stack_range_;
840 };
841 
842 VisitResult ProjectStructField(VisitResult structure,
843                                const std::string& fieldname);
844 
845 class VisitResultVector : public std::vector<VisitResult> {
846  public:
VisitResultVector()847   VisitResultVector() : std::vector<VisitResult>() {}
VisitResultVector(std::initializer_list<VisitResult> init)848   VisitResultVector(std::initializer_list<VisitResult> init)
849       : std::vector<VisitResult>(init) {}
ComputeTypeVector()850   TypeVector ComputeTypeVector() const {
851     TypeVector result;
852     for (auto& visit_result : *this) {
853       result.push_back(visit_result.type());
854     }
855     return result;
856   }
857 };
858 
859 std::ostream& operator<<(std::ostream& os, const TypeVector& types);
860 
861 using NameAndTypeVector = std::vector<NameAndType>;
862 
863 struct LabelDefinition {
864   std::string name;
865   NameAndTypeVector parameters;
866 };
867 
868 using LabelDefinitionVector = std::vector<LabelDefinition>;
869 
870 struct LabelDeclaration {
871   Identifier* name;
872   TypeVector types;
873 };
874 
875 using LabelDeclarationVector = std::vector<LabelDeclaration>;
876 
877 struct ParameterTypes {
878   TypeVector types;
879   bool var_args;
880 };
881 
882 std::ostream& operator<<(std::ostream& os, const ParameterTypes& parameters);
883 
884 enum class ParameterMode { kProcessImplicit, kIgnoreImplicit };
885 
886 using NameVector = std::vector<Identifier*>;
887 
888 struct Signature {
SignatureSignature889   Signature(NameVector n, base::Optional<std::string> arguments_variable,
890             ParameterTypes p, size_t i, const Type* r, LabelDeclarationVector l,
891             bool transitioning)
892       : parameter_names(std::move(n)),
893         arguments_variable(arguments_variable),
894         parameter_types(std::move(p)),
895         implicit_count(i),
896         return_type(r),
897         labels(std::move(l)),
898         transitioning(transitioning) {}
899   Signature() = default;
typesSignature900   const TypeVector& types() const { return parameter_types.types; }
901   NameVector parameter_names;
902   base::Optional<std::string> arguments_variable;
903   ParameterTypes parameter_types;
904   size_t implicit_count = 0;
ExplicitCountSignature905   size_t ExplicitCount() const { return types().size() - implicit_count; }
906   const Type* return_type;
907   LabelDeclarationVector labels;
908   bool transitioning = false;
909   bool HasSameTypesAs(
910       const Signature& other,
911       ParameterMode mode = ParameterMode::kProcessImplicit) const;
GetImplicitTypesSignature912   TypeVector GetImplicitTypes() const {
913     return TypeVector(parameter_types.types.begin(),
914                       parameter_types.types.begin() + implicit_count);
915   }
GetExplicitTypesSignature916   TypeVector GetExplicitTypes() const {
917     return TypeVector(parameter_types.types.begin() + implicit_count,
918                       parameter_types.types.end());
919   }
920   bool HasContextParameter() const;
921 };
922 
923 void PrintSignature(std::ostream& os, const Signature& sig, bool with_names);
924 std::ostream& operator<<(std::ostream& os, const Signature& sig);
925 
926 bool IsAssignableFrom(const Type* to, const Type* from);
927 
928 TypeVector LowerType(const Type* type);
929 size_t LoweredSlotCount(const Type* type);
930 TypeVector LowerParameterTypes(const TypeVector& parameters);
931 TypeVector LowerParameterTypes(const ParameterTypes& parameter_types,
932                                size_t vararg_count = 0);
933 
934 base::Optional<std::tuple<size_t, std::string>> SizeOf(const Type* type);
935 bool IsAnyUnsignedInteger(const Type* type);
936 bool IsAllowedAsBitField(const Type* type);
937 bool IsPointerSizeIntegralType(const Type* type);
938 bool Is32BitIntegralType(const Type* type);
939 
940 base::Optional<NameAndType> ExtractSimpleFieldArraySize(
941     const ClassType& class_type, Expression* array_size);
942 
943 }  // namespace torque
944 }  // namespace internal
945 }  // namespace v8
946 
947 #endif  // V8_TORQUE_TYPES_H_
948