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