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 <map>
10#include <set>
11#include <string>
12#include <vector>
13
14#include "src/base/optional.h"
15#include "src/torque/source-positions.h"
16#include "src/torque/utils.h"
17
18namespace v8 {
19namespace internal {
20namespace torque {
21
22static const char* const CONSTEXPR_TYPE_PREFIX = "constexpr ";
23static const char* const NEVER_TYPE_STRING = "never";
24static const char* const CONSTEXPR_BOOL_TYPE_STRING = "constexpr bool";
25static const char* const CONSTEXPR_INTPTR_TYPE_STRING = "constexpr intptr";
26static const char* const BOOL_TYPE_STRING = "bool";
27static const char* const VOID_TYPE_STRING = "void";
28static const char* const ARGUMENTS_TYPE_STRING = "Arguments";
29static const char* const CONTEXT_TYPE_STRING = "Context";
30static const char* const MAP_TYPE_STRING = "Map";
31static const char* const OBJECT_TYPE_STRING = "Object";
32static const char* const HEAP_OBJECT_TYPE_STRING = "HeapObject";
33static const char* const JSOBJECT_TYPE_STRING = "JSObject";
34static const char* const SMI_TYPE_STRING = "Smi";
35static const char* const TAGGED_TYPE_STRING = "Tagged";
36static const char* const RAWPTR_TYPE_STRING = "RawPtr";
37static const char* const CONST_STRING_TYPE_STRING = "constexpr string";
38static const char* const STRING_TYPE_STRING = "String";
39static const char* const NUMBER_TYPE_STRING = "Number";
40static const char* const BUILTIN_POINTER_TYPE_STRING = "BuiltinPtr";
41static const char* const INTPTR_TYPE_STRING = "intptr";
42static const char* const UINTPTR_TYPE_STRING = "uintptr";
43static const char* const INT32_TYPE_STRING = "int32";
44static const char* const UINT32_TYPE_STRING = "uint32";
45static const char* const INT16_TYPE_STRING = "int16";
46static const char* const UINT16_TYPE_STRING = "uint16";
47static const char* const INT8_TYPE_STRING = "int8";
48static const char* const UINT8_TYPE_STRING = "uint8";
49static const char* const FLOAT64_TYPE_STRING = "float64";
50static const char* const CONST_INT31_TYPE_STRING = "constexpr int31";
51static const char* const CONST_INT32_TYPE_STRING = "constexpr int32";
52static const char* const CONST_FLOAT64_TYPE_STRING = "constexpr float64";
53
54class AggregateType;
55struct Identifier;
56class Macro;
57class Method;
58class StructType;
59class ClassType;
60class Value;
61class Namespace;
62
63class TypeBase {
64 public:
65 enum class Kind {
66 kTopType,
67 kAbstractType,
68 kBuiltinPointerType,
69 kReferenceType,
70 kUnionType,
71 kStructType,
72 kClassType
73 };
74 virtual ~TypeBase() = default;
75 bool IsTopType() const { return kind() == Kind::kTopType; }
76 bool IsAbstractType() const { return kind() == Kind::kAbstractType; }
77 bool IsBuiltinPointerType() const {
78 return kind() == Kind::kBuiltinPointerType;
79 }
80 bool IsReferenceType() const { return kind() == Kind::kReferenceType; }
81 bool IsUnionType() const { return kind() == Kind::kUnionType; }
82 bool IsStructType() const { return kind() == Kind::kStructType; }
83 bool IsClassType() const { return kind() == Kind::kClassType; }
84 bool IsAggregateType() const { return IsStructType() || IsClassType(); }
85
86 protected:
87 explicit TypeBase(Kind kind) : kind_(kind) {}
88 Kind kind() const { return kind_; }
89
90 private:
91 const Kind kind_;
92};
93
94#define DECLARE_TYPE_BOILERPLATE(x) \
95 static x* cast(TypeBase* declarable) { \
96 DCHECK(declarable->Is##x()); \
97 return static_cast<x*>(declarable); \
98 } \
99 static const x* cast(const TypeBase* declarable) { \
100 DCHECK(declarable->Is##x()); \
101 return static_cast<const x*>(declarable); \
102 } \
103 static x* DynamicCast(TypeBase* declarable) { \
104 if (!declarable) return nullptr; \
105 if (!declarable->Is##x()) return nullptr; \
106 return static_cast<x*>(declarable); \
107 } \
108 static const x* DynamicCast(const TypeBase* declarable) { \
109 if (!declarable) return nullptr; \
110 if (!declarable->Is##x()) return nullptr; \
111 return static_cast<const x*>(declarable); \
112 }
113
114class Type : public TypeBase {
115 public:
116 virtual bool IsSubtypeOf(const Type* supertype) const;
117
118 std::string ToString() const;
119 virtual std::string MangledName() const = 0;
120 bool IsVoid() const { return IsAbstractName(VOID_TYPE_STRING); }
121 bool IsNever() const { return IsAbstractName(NEVER_TYPE_STRING); }
122 bool IsBool() const { return IsAbstractName(BOOL_TYPE_STRING); }
123 bool IsConstexprBool() const {
124 return IsAbstractName(CONSTEXPR_BOOL_TYPE_STRING);
125 }
126 bool IsVoidOrNever() const { return IsVoid() || IsNever(); }
127 std::string GetGeneratedTypeName() const;
128 std::string GetGeneratedTNodeTypeName() const;
129 virtual bool IsConstexpr() const {
130 if (parent()) DCHECK(!parent()->IsConstexpr());
131 return false;
132 }
133 virtual bool IsTransient() const { return false; }
134 virtual const Type* NonConstexprVersion() const { return this; }
135 base::Optional<const ClassType*> ClassSupertype() const;
136 static const Type* CommonSupertype(const Type* a, const Type* b);
137 void AddAlias(std::string alias) const { aliases_.insert(std::move(alias)); }
138
139 protected:
140 Type(TypeBase::Kind kind, const Type* parent)
141 : TypeBase(kind), parent_(parent) {}
142 const Type* parent() const { return parent_; }
143 void set_parent(const Type* t) { parent_ = t; }
144 int Depth() const;
145 virtual std::string ToExplicitString() const = 0;
146 virtual std::string GetGeneratedTypeNameImpl() const = 0;
147 virtual std::string GetGeneratedTNodeTypeNameImpl() const = 0;
148
149 private:
150 bool IsAbstractName(const std::string& name) const;
151
152 // If {parent_} is not nullptr, then this type is a subtype of {parent_}.
153 const Type* parent_;
154 mutable std::set<std::string> aliases_;
155};
156
157using TypeVector = std::vector<const Type*>;
158
159inline size_t hash_value(const TypeVector& types) {
160 size_t hash = 0;
161 for (const Type* t : types) {
162 hash = base::hash_combine(hash, t);
163 }
164 return hash;
165}
166
167struct NameAndType {
168 std::string name;
169 const Type* type;
170};
171
172std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type);
173
174struct Field {
175 // TODO(danno): This likely should be refactored, the handling of the types
176 // using the universal grab-bag utility with std::tie, as well as the
177 // reliance of string types is quite clunky.
178 std::tuple<size_t, std::string, std::string> GetFieldSizeInformation() const;
179
180 SourcePosition pos;
181 const AggregateType* aggregate;
182 base::Optional<const Field*> index;
183 NameAndType name_and_type;
184 size_t offset;
185 bool is_weak;
186 bool const_qualified;
187};
188
189std::ostream& operator<<(std::ostream& os, const Field& name_and_type);
190
191class TopType final : public Type {
192 public:
193 DECLARE_TYPE_BOILERPLATE(TopType)
194 std::string MangledName() const override { return "top"; }
195 std::string GetGeneratedTypeNameImpl() const override { UNREACHABLE(); }
196 std::string GetGeneratedTNodeTypeNameImpl() const override {
197 return source_type_->GetGeneratedTNodeTypeName();
198 }
199 std::string ToExplicitString() const override {
200 std::stringstream s;
201 s << "inaccessible " + source_type_->ToString();
202 return s.str();
203 }
204
205 const Type* source_type() const { return source_type_; }
206 const std::string reason() const { return reason_; }
207
208 private:
209 friend class TypeOracle;
210 explicit TopType(std::string reason, const Type* source_type)
211 : Type(Kind::kTopType, nullptr),
212 reason_(std::move(reason)),
213 source_type_(source_type) {}
214 std::string reason_;
215 const Type* source_type_;
216};
217
218class AbstractType final : public Type {
219 public:
220 DECLARE_TYPE_BOILERPLATE(AbstractType)
221 const std::string& name() const { return name_; }
222 std::string ToExplicitString() const override { return name(); }
223 std::string MangledName() const override {
224 std::string str(name());
225 std::replace(str.begin(), str.end(), ' ', '_');
226 return "AT" + str;
227 }
228 std::string GetGeneratedTypeNameImpl() const override {
229 return IsConstexpr() ? generated_type_
230 : "compiler::TNode<" + generated_type_ + ">";
231 }
232 std::string GetGeneratedTNodeTypeNameImpl() const override;
233 bool IsConstexpr() const override {
234 return name().substr(0, strlen(CONSTEXPR_TYPE_PREFIX)) ==
235 CONSTEXPR_TYPE_PREFIX;
236 }
237 const Type* NonConstexprVersion() const override {
238 if (IsConstexpr()) return *non_constexpr_version_;
239 return this;
240 }
241
242 private:
243 friend class TypeOracle;
244 AbstractType(const Type* parent, bool transient, const std::string& name,
245 const std::string& generated_type,
246 base::Optional<const AbstractType*> non_constexpr_version)
247 : Type(Kind::kAbstractType, parent),
248 transient_(transient),
249 name_(name),
250 generated_type_(generated_type),
251 non_constexpr_version_(non_constexpr_version) {
252 DCHECK_EQ(non_constexpr_version_.has_value(), IsConstexpr());
253 if (parent) DCHECK(parent->IsConstexpr() == IsConstexpr());
254 }
255
256 bool IsTransient() const override { return transient_; }
257
258 bool transient_;
259 const std::string name_;
260 const std::string generated_type_;
261 base::Optional<const AbstractType*> non_constexpr_version_;
262};
263
264// For now, builtin pointers are restricted to Torque-defined builtins.
265class BuiltinPointerType final : public Type {
266 public:
267 DECLARE_TYPE_BOILERPLATE(BuiltinPointerType)
268 std::string ToExplicitString() const override;
269 std::string MangledName() const override;
270 std::string GetGeneratedTypeNameImpl() const override {
271 return parent()->GetGeneratedTypeName();
272 }
273 std::string GetGeneratedTNodeTypeNameImpl() const override {
274 return parent()->GetGeneratedTNodeTypeName();
275 }
276
277 const TypeVector& parameter_types() const { return parameter_types_; }
278 const Type* return_type() const { return return_type_; }
279
280 friend size_t hash_value(const BuiltinPointerType& p) {
281 size_t result = base::hash_value(p.return_type_);
282 for (const Type* parameter : p.parameter_types_) {
283 result = base::hash_combine(result, parameter);
284 }
285 return result;
286 }
287 bool operator==(const BuiltinPointerType& other) const {
288 return parameter_types_ == other.parameter_types_ &&
289 return_type_ == other.return_type_;
290 }
291 size_t function_pointer_type_id() const { return function_pointer_type_id_; }
292
293 private:
294 friend class TypeOracle;
295 BuiltinPointerType(const Type* parent, TypeVector parameter_types,
296 const Type* return_type, size_t function_pointer_type_id)
297 : Type(Kind::kBuiltinPointerType, parent),
298 parameter_types_(parameter_types),
299 return_type_(return_type),
300 function_pointer_type_id_(function_pointer_type_id) {}
301
302 const TypeVector parameter_types_;
303 const Type* const return_type_;
304 const size_t function_pointer_type_id_;
305};
306
307class ReferenceType final : public Type {
308 public:
309 DECLARE_TYPE_BOILERPLATE(ReferenceType)
310 std::string MangledName() const override {
311 return "RT" + referenced_type_->MangledName();
312 }
313 std::string ToExplicitString() const override {
314 std::string s = referenced_type_->ToString();
315 if (s.find(' ') != std::string::npos) {
316 s = "(" + s + ")";
317 }
318 return "&" + s;
319 }
320 std::string GetGeneratedTypeNameImpl() const override {
321 return "CodeStubAssembler::Reference";
322 }
323 std::string GetGeneratedTNodeTypeNameImpl() const override { UNREACHABLE(); }
324
325 const Type* referenced_type() const { return referenced_type_; }
326
327 friend size_t hash_value(const ReferenceType& p) {
328 return base::hash_combine(static_cast<size_t>(Kind::kReferenceType),
329 p.referenced_type_);
330 }
331 bool operator==(const ReferenceType& other) const {
332 return referenced_type_ == other.referenced_type_;
333 }
334
335 private:
336 friend class TypeOracle;
337 explicit ReferenceType(const Type* referenced_type)
338 : Type(Kind::kReferenceType, nullptr),
339 referenced_type_(referenced_type) {}
340
341 const Type* const referenced_type_;
342};
343
344bool operator<(const Type& a, const Type& b);
345struct TypeLess {
346 bool operator()(const Type* const a, const Type* const b) const {
347 return *a < *b;
348 }
349};
350
351class UnionType final : public Type {
352 public:
353 DECLARE_TYPE_BOILERPLATE(UnionType)
354 std::string ToExplicitString() const override;
355 std::string MangledName() const override;
356 std::string GetGeneratedTypeNameImpl() const override {
357 return "compiler::TNode<" + GetGeneratedTNodeTypeName() + ">";
358 }
359 std::string GetGeneratedTNodeTypeNameImpl() const override;
360
361 friend size_t hash_value(const UnionType& p) {
362 size_t result = 0;
363 for (const Type* t : p.types_) {
364 result = base::hash_combine(result, t);
365 }
366 return result;
367 }
368 bool operator==(const UnionType& other) const {
369 return types_ == other.types_;
370 }
371
372 base::Optional<const Type*> GetSingleMember() const {
373 if (types_.size() == 1) {
374 DCHECK_EQ(*types_.begin(), parent());
375 return *types_.begin();
376 }
377 return base::nullopt;
378 }
379
380 bool IsSubtypeOf(const Type* other) const override {
381 for (const Type* member : types_) {
382 if (!member->IsSubtypeOf(other)) return false;
383 }
384 return true;
385 }
386
387 bool IsSupertypeOf(const Type* other) const {
388 for (const Type* member : types_) {
389 if (other->IsSubtypeOf(member)) {
390 return true;
391 }
392 }
393 return false;
394 }
395
396 bool IsTransient() const override {
397 for (const Type* member : types_) {
398 if (member->IsTransient()) {
399 return true;
400 }
401 }
402 return false;
403 }
404
405 void Extend(const Type* t) {
406 if (const UnionType* union_type = UnionType::DynamicCast(t)) {
407 for (const Type* member : union_type->types_) {
408 Extend(member);
409 }
410 } else {
411 if (t->IsSubtypeOf(this)) return;
412 set_parent(CommonSupertype(parent(), t));
413 EraseIf(&types_,
414 [&](const Type* member) { return member->IsSubtypeOf(t); });
415 types_.insert(t);
416 }
417 }
418
419 void Subtract(const Type* t);
420
421 static UnionType FromType(const Type* t) {
422 const UnionType* union_type = UnionType::DynamicCast(t);
423 return union_type ? UnionType(*union_type) : UnionType(t);
424 }
425
426 private:
427 explicit UnionType(const Type* t) : Type(Kind::kUnionType, t), types_({t}) {}
428 void RecomputeParent();
429
430 std::set<const Type*, TypeLess> types_;
431};
432
433const Type* SubtractType(const Type* a, const Type* b);
434
435class AggregateType : public Type {
436 public:
437 DECLARE_TYPE_BOILERPLATE(AggregateType)
438 std::string MangledName() const override { return name_; }
439 std::string GetGeneratedTypeNameImpl() const override { UNREACHABLE(); }
440 std::string GetGeneratedTNodeTypeNameImpl() const override { UNREACHABLE(); }
441
442 virtual bool HasIndexedField() const { return false; }
443
444 void SetFields(std::vector<Field> fields) { fields_ = std::move(fields); }
445 const std::vector<Field>& fields() const { return fields_; }
446 bool HasField(const std::string& name) const;
447 const Field& LookupField(const std::string& name) const;
448 const std::string& name() const { return name_; }
449 Namespace* nspace() const { return namespace_; }
450
451 std::string GetGeneratedMethodName(const std::string& name) const {
452 return "_method_" + name_ + "_" + name;
453 }
454
455 virtual const Field& RegisterField(Field field) {
456 fields_.push_back(field);
457 return fields_.back();
458 }
459
460 void RegisterMethod(Method* method) { methods_.push_back(method); }
461 const std::vector<Method*>& Methods() const { return methods_; }
462 std::vector<Method*> Methods(const std::string& name) const;
463
464 std::vector<const AggregateType*> GetHierarchy();
465
466 protected:
467 AggregateType(Kind kind, const Type* parent, Namespace* nspace,
468 const std::string& name)
469 : Type(kind, parent), namespace_(nspace), name_(name) {}
470
471 void CheckForDuplicateFields();
472
473 private:
474 Namespace* namespace_;
475 std::string name_;
476 std::vector<Method*> methods_;
477 std::vector<Field> fields_;
478};
479
480class StructType final : public AggregateType {
481 public:
482 DECLARE_TYPE_BOILERPLATE(StructType)
483 std::string ToExplicitString() const override;
484 std::string GetGeneratedTypeNameImpl() const override;
485
486 private:
487 friend class TypeOracle;
488 StructType(Namespace* nspace, const std::string& name)
489 : AggregateType(Kind::kStructType, nullptr, nspace, name) {
490 CheckForDuplicateFields();
491 }
492
493 const std::string& GetStructName() const { return name(); }
494};
495
496class ClassType final : public AggregateType {
497 public:
498 DECLARE_TYPE_BOILERPLATE(ClassType)
499 std::string ToExplicitString() const override;
500 std::string GetGeneratedTypeNameImpl() const override;
501 std::string GetGeneratedTNodeTypeNameImpl() const override;
502 bool IsExtern() const { return is_extern_; }
503 bool ShouldGeneratePrint() const { return generate_print_; }
504 bool IsTransient() const override { return transient_; }
505 bool HasIndexedField() const override;
506 size_t size() const { return size_; }
507 const ClassType* GetSuperClass() const {
508 if (parent() == nullptr) return nullptr;
509 return parent()->IsClassType() ? ClassType::DynamicCast(parent()) : nullptr;
510 }
511 void SetSize(size_t size) { size_ = size; }
512 bool AllowInstantiation() const;
513 const Field& RegisterField(Field field) override {
514 if (field.index) {
515 has_indexed_field_ = true;
516 }
517 return AggregateType::RegisterField(field);
518 }
519
520 private:
521 friend class TypeOracle;
522 ClassType(const Type* parent, Namespace* nspace, const std::string& name,
523 bool is_extern, bool generate_print, bool transient,
524 const std::string& generates);
525
526 bool is_extern_;
527 bool generate_print_;
528 bool transient_;
529 size_t size_;
530 bool has_indexed_field_;
531 const std::string generates_;
532};
533
534inline std::ostream& operator<<(std::ostream& os, const Type& t) {
535 os << t.ToString();
536 return os;
537}
538
539class VisitResult {
540 public:
541 VisitResult() = default;
542 VisitResult(const Type* type, const std::string& constexpr_value)
543 : type_(type), constexpr_value_(constexpr_value) {
544 DCHECK(type->IsConstexpr());
545 }
546 static VisitResult NeverResult();
547 VisitResult(const Type* type, StackRange stack_range)
548 : type_(type), stack_range_(stack_range) {
549 DCHECK(!type->IsConstexpr());
550 }
551 const Type* type() const { return type_; }
552 const std::string& constexpr_value() const { return *constexpr_value_; }
553 const StackRange& stack_range() const { return *stack_range_; }
554 void SetType(const Type* new_type) { type_ = new_type; }
555 bool IsOnStack() const { return stack_range_ != base::nullopt; }
556 bool operator==(const VisitResult& other) const {
557 return type_ == other.type_ && constexpr_value_ == other.constexpr_value_ &&
558 stack_range_ == other.stack_range_;
559 }
560
561 private:
562 const Type* type_ = nullptr;
563 base::Optional<std::string> constexpr_value_;
564 base::Optional<StackRange> stack_range_;
565};
566
567typedef std::map<std::string, VisitResult> NameValueMap;
568
569VisitResult ProjectStructField(VisitResult structure,
570 const std::string& fieldname);
571
572class VisitResultVector : public std::vector<VisitResult> {
573 public:
574 VisitResultVector() : std::vector<VisitResult>() {}
575 VisitResultVector(std::initializer_list<VisitResult> init)
576 : std::vector<VisitResult>(init) {}
577 TypeVector GetTypeVector() const {
578 TypeVector result;
579 for (auto& visit_result : *this) {
580 result.push_back(visit_result.type());
581 }
582 return result;
583 }
584};
585
586std::ostream& operator<<(std::ostream& os, const TypeVector& types);
587
588typedef std::vector<NameAndType> NameAndTypeVector;
589
590struct LabelDefinition {
591 std::string name;
592 NameAndTypeVector parameters;
593};
594
595typedef std::vector<LabelDefinition> LabelDefinitionVector;
596
597struct LabelDeclaration {
598 std::string name;
599 TypeVector types;
600};
601
602typedef std::vector<LabelDeclaration> LabelDeclarationVector;
603
604struct ParameterTypes {
605 TypeVector types;
606 bool var_args;
607};
608
609std::ostream& operator<<(std::ostream& os, const ParameterTypes& parameters);
610
611enum class ParameterMode { kProcessImplicit, kIgnoreImplicit };
612
613typedef std::vector<Identifier*> NameVector;
614
615struct Signature {
616 Signature(NameVector n, base::Optional<std::string> arguments_variable,
617 ParameterTypes p, size_t i, const Type* r, LabelDeclarationVector l)
618 : parameter_names(std::move(n)),
619 arguments_variable(arguments_variable),
620 parameter_types(std::move(p)),
621 implicit_count(i),
622 return_type(r),
623 labels(std::move(l)) {}
624 Signature() : implicit_count(0), return_type(nullptr) {}
625 const TypeVector& types() const { return parameter_types.types; }
626 NameVector parameter_names;
627 base::Optional<std::string> arguments_variable;
628 ParameterTypes parameter_types;
629 size_t implicit_count;
630 const Type* return_type;
631 LabelDeclarationVector labels;
632 bool HasSameTypesAs(
633 const Signature& other,
634 ParameterMode mode = ParameterMode::kProcessImplicit) const;
635 TypeVector GetImplicitTypes() const {
636 return TypeVector(parameter_types.types.begin(),
637 parameter_types.types.begin() + implicit_count);
638 }
639 TypeVector GetExplicitTypes() const {
640 return TypeVector(parameter_types.types.begin() + implicit_count,
641 parameter_types.types.end());
642 }
643};
644
645void PrintSignature(std::ostream& os, const Signature& sig, bool with_names);
646std::ostream& operator<<(std::ostream& os, const Signature& sig);
647
648bool IsAssignableFrom(const Type* to, const Type* from);
649
650TypeVector LowerType(const Type* type);
651size_t LoweredSlotCount(const Type* type);
652TypeVector LowerParameterTypes(const TypeVector& parameters);
653TypeVector LowerParameterTypes(const ParameterTypes& parameter_types,
654 size_t vararg_count = 0);
655
656} // namespace torque
657} // namespace internal
658} // namespace v8
659
660#endif // V8_TORQUE_TYPES_H_
661