• 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 #include "src/torque/types.h"
6 
7 #include <cmath>
8 #include <iostream>
9 
10 #include "src/base/bits.h"
11 #include "src/base/optional.h"
12 #include "src/torque/ast.h"
13 #include "src/torque/declarable.h"
14 #include "src/torque/global-context.h"
15 #include "src/torque/source-positions.h"
16 #include "src/torque/type-oracle.h"
17 #include "src/torque/type-visitor.h"
18 
19 namespace v8 {
20 namespace internal {
21 namespace torque {
22 
23 // This custom copy constructor doesn't copy aliases_ and id_ because they
24 // should be distinct for each type.
Type(const Type & other)25 Type::Type(const Type& other) V8_NOEXCEPT
26     : TypeBase(other),
27       parent_(other.parent_),
28       aliases_(),
29       id_(TypeOracle::FreshTypeId()),
30       constexpr_version_(other.constexpr_version_) {}
Type(TypeBase::Kind kind,const Type * parent,MaybeSpecializationKey specialized_from)31 Type::Type(TypeBase::Kind kind, const Type* parent,
32            MaybeSpecializationKey specialized_from)
33     : TypeBase(kind),
34       parent_(parent),
35       id_(TypeOracle::FreshTypeId()),
36       specialized_from_(specialized_from),
37       constexpr_version_(nullptr) {}
38 
ToString() const39 std::string Type::ToString() const {
40   if (aliases_.size() == 0)
41     return ComputeName(ToExplicitString(), GetSpecializedFrom());
42   if (aliases_.size() == 1) return *aliases_.begin();
43   std::stringstream result;
44   int i = 0;
45   for (const std::string& alias : aliases_) {
46     if (i == 0) {
47       result << alias << " (aka. ";
48     } else if (i == 1) {
49       result << alias;
50     } else {
51       result << ", " << alias;
52     }
53     ++i;
54   }
55   result << ")";
56   return result.str();
57 }
58 
SimpleName() const59 std::string Type::SimpleName() const {
60   if (aliases_.empty()) {
61     std::stringstream result;
62     result << SimpleNameImpl();
63     if (GetSpecializedFrom()) {
64       for (const Type* t : GetSpecializedFrom()->specialized_types) {
65         result << "_" << t->SimpleName();
66       }
67     }
68     return result.str();
69   }
70   return *aliases_.begin();
71 }
72 
73 // TODO(danno): HandlifiedCppTypeName should be used universally in Torque
74 // where the C++ type of a Torque object is required.
HandlifiedCppTypeName() const75 std::string Type::HandlifiedCppTypeName() const {
76   if (IsSubtypeOf(TypeOracle::GetSmiType())) return "int";
77   if (IsSubtypeOf(TypeOracle::GetTaggedType())) {
78     return "Handle<" + UnhandlifiedCppTypeName() + ">";
79   } else {
80     return UnhandlifiedCppTypeName();
81   }
82 }
83 
UnhandlifiedCppTypeName() const84 std::string Type::UnhandlifiedCppTypeName() const {
85   if (IsSubtypeOf(TypeOracle::GetSmiType())) return "int";
86   if (this == TypeOracle::GetObjectType()) return "Object";
87   return GetConstexprGeneratedTypeName();
88 }
89 
IsSubtypeOf(const Type * supertype) const90 bool Type::IsSubtypeOf(const Type* supertype) const {
91   if (supertype->IsTopType()) return true;
92   if (IsNever()) return true;
93   if (const UnionType* union_type = UnionType::DynamicCast(supertype)) {
94     return union_type->IsSupertypeOf(this);
95   }
96   const Type* subtype = this;
97   while (subtype != nullptr) {
98     if (subtype == supertype) return true;
99     subtype = subtype->parent();
100   }
101   return false;
102 }
103 
GetConstexprGeneratedTypeName() const104 std::string Type::GetConstexprGeneratedTypeName() const {
105   const Type* constexpr_version = ConstexprVersion();
106   if (constexpr_version == nullptr) {
107     Error("Type '", ToString(), "' requires a constexpr representation");
108     return "";
109   }
110   return constexpr_version->GetGeneratedTypeName();
111 }
112 
ClassSupertype() const113 base::Optional<const ClassType*> Type::ClassSupertype() const {
114   for (const Type* t = this; t != nullptr; t = t->parent()) {
115     if (auto* class_type = ClassType::DynamicCast(t)) {
116       return class_type;
117     }
118   }
119   return base::nullopt;
120 }
121 
StructSupertype() const122 base::Optional<const StructType*> Type::StructSupertype() const {
123   for (const Type* t = this; t != nullptr; t = t->parent()) {
124     if (auto* struct_type = StructType::DynamicCast(t)) {
125       return struct_type;
126     }
127   }
128   return base::nullopt;
129 }
130 
131 // static
CommonSupertype(const Type * a,const Type * b)132 const Type* Type::CommonSupertype(const Type* a, const Type* b) {
133   int diff = a->Depth() - b->Depth();
134   const Type* a_supertype = a;
135   const Type* b_supertype = b;
136   for (; diff > 0; --diff) a_supertype = a_supertype->parent();
137   for (; diff < 0; ++diff) b_supertype = b_supertype->parent();
138   while (a_supertype && b_supertype) {
139     if (a_supertype == b_supertype) return a_supertype;
140     a_supertype = a_supertype->parent();
141     b_supertype = b_supertype->parent();
142   }
143   ReportError("types " + a->ToString() + " and " + b->ToString() +
144               " have no common supertype");
145 }
146 
Depth() const147 int Type::Depth() const {
148   int result = 0;
149   for (const Type* current = parent_; current; current = current->parent_) {
150     ++result;
151   }
152   return result;
153 }
154 
IsAbstractName(const std::string & name) const155 bool Type::IsAbstractName(const std::string& name) const {
156   if (!IsAbstractType()) return false;
157   return AbstractType::cast(this)->name() == name;
158 }
159 
GetGeneratedTypeName() const160 std::string Type::GetGeneratedTypeName() const {
161   std::string result = GetGeneratedTypeNameImpl();
162   if (result.empty() || result == "TNode<>") {
163     ReportError("Generated type is required for type '", ToString(),
164                 "'. Use 'generates' clause in definition.");
165   }
166   return result;
167 }
168 
GetGeneratedTNodeTypeName() const169 std::string Type::GetGeneratedTNodeTypeName() const {
170   std::string result = GetGeneratedTNodeTypeNameImpl();
171   if (result.empty() || IsConstexpr()) {
172     ReportError("Generated TNode type is required for type '", ToString(),
173                 "'. Use 'generates' clause in definition.");
174   }
175   return result;
176 }
177 
GetGeneratedTNodeTypeNameImpl() const178 std::string AbstractType::GetGeneratedTNodeTypeNameImpl() const {
179   if (generated_type_.empty()) return parent()->GetGeneratedTNodeTypeName();
180   return generated_type_;
181 }
182 
GetTypeCheckers() const183 std::vector<TypeChecker> AbstractType::GetTypeCheckers() const {
184   if (UseParentTypeChecker()) return parent()->GetTypeCheckers();
185   std::string type_name = name();
186   if (auto strong_type =
187           Type::MatchUnaryGeneric(this, TypeOracle::GetWeakGeneric())) {
188     auto strong_runtime_types = (*strong_type)->GetTypeCheckers();
189     std::vector<TypeChecker> result;
190     for (const TypeChecker& type : strong_runtime_types) {
191       // Generic parameter in Weak<T> should have already been checked to
192       // extend HeapObject, so it couldn't itself be another weak type.
193       DCHECK(type.weak_ref_to.empty());
194       result.push_back({type_name, type.type});
195     }
196     return result;
197   }
198   return {{type_name, ""}};
199 }
200 
ToExplicitString() const201 std::string BuiltinPointerType::ToExplicitString() const {
202   std::stringstream result;
203   result << "builtin (";
204   PrintCommaSeparatedList(result, parameter_types_);
205   result << ") => " << *return_type_;
206   return result.str();
207 }
208 
SimpleNameImpl() const209 std::string BuiltinPointerType::SimpleNameImpl() const {
210   std::stringstream result;
211   result << "BuiltinPointer";
212   for (const Type* t : parameter_types_) {
213     result << "_" << t->SimpleName();
214   }
215   result << "_" << return_type_->SimpleName();
216   return result.str();
217 }
218 
ToExplicitString() const219 std::string UnionType::ToExplicitString() const {
220   std::stringstream result;
221   result << "(";
222   bool first = true;
223   for (const Type* t : types_) {
224     if (!first) {
225       result << " | ";
226     }
227     first = false;
228     result << *t;
229   }
230   result << ")";
231   return result.str();
232 }
233 
SimpleNameImpl() const234 std::string UnionType::SimpleNameImpl() const {
235   std::stringstream result;
236   bool first = true;
237   for (const Type* t : types_) {
238     if (!first) {
239       result << "_OR_";
240     }
241     first = false;
242     result << t->SimpleName();
243   }
244   return result.str();
245 }
246 
GetGeneratedTNodeTypeNameImpl() const247 std::string UnionType::GetGeneratedTNodeTypeNameImpl() const {
248   if (types_.size() <= 3) {
249     std::set<std::string> members;
250     for (const Type* t : types_) {
251       members.insert(t->GetGeneratedTNodeTypeName());
252     }
253     if (members == std::set<std::string>{"Smi", "HeapNumber"}) {
254       return "Number";
255     }
256     if (members == std::set<std::string>{"Smi", "HeapNumber", "BigInt"}) {
257       return "Numeric";
258     }
259   }
260   return parent()->GetGeneratedTNodeTypeName();
261 }
262 
RecomputeParent()263 void UnionType::RecomputeParent() {
264   const Type* parent = nullptr;
265   for (const Type* t : types_) {
266     if (parent == nullptr) {
267       parent = t;
268     } else {
269       parent = CommonSupertype(parent, t);
270     }
271   }
272   set_parent(parent);
273 }
274 
Subtract(const Type * t)275 void UnionType::Subtract(const Type* t) {
276   for (auto it = types_.begin(); it != types_.end();) {
277     if ((*it)->IsSubtypeOf(t)) {
278       it = types_.erase(it);
279     } else {
280       ++it;
281     }
282   }
283   if (types_.size() == 0) types_.insert(TypeOracle::GetNeverType());
284   RecomputeParent();
285 }
286 
SubtractType(const Type * a,const Type * b)287 const Type* SubtractType(const Type* a, const Type* b) {
288   UnionType result = UnionType::FromType(a);
289   result.Subtract(b);
290   return TypeOracle::GetUnionType(result);
291 }
292 
ToExplicitString() const293 std::string BitFieldStructType::ToExplicitString() const {
294   return "bitfield struct " + name();
295 }
296 
LookupField(const std::string & name) const297 const BitField& BitFieldStructType::LookupField(const std::string& name) const {
298   for (const BitField& field : fields_) {
299     if (field.name_and_type.name == name) {
300       return field;
301     }
302   }
303   ReportError("Couldn't find bitfield ", name);
304 }
305 
CheckForDuplicateFields() const306 void AggregateType::CheckForDuplicateFields() const {
307   // Check the aggregate hierarchy and currently defined class for duplicate
308   // field declarations.
309   auto hierarchy = GetHierarchy();
310   std::map<std::string, const AggregateType*> field_names;
311   for (const AggregateType* aggregate_type : hierarchy) {
312     for (const Field& field : aggregate_type->fields()) {
313       const std::string& field_name = field.name_and_type.name;
314       auto i = field_names.find(field_name);
315       if (i != field_names.end()) {
316         CurrentSourcePosition::Scope current_source_position(field.pos);
317         std::string aggregate_type_name =
318             aggregate_type->IsClassType() ? "class" : "struct";
319         if (i->second == this) {
320           ReportError(aggregate_type_name, " '", name(),
321                       "' declares a field with the name '", field_name,
322                       "' more than once");
323         } else {
324           ReportError(aggregate_type_name, " '", name(),
325                       "' declares a field with the name '", field_name,
326                       "' that masks an inherited field from class '",
327                       i->second->name(), "'");
328         }
329       }
330       field_names[field_name] = aggregate_type;
331     }
332   }
333 }
334 
GetHierarchy() const335 std::vector<const AggregateType*> AggregateType::GetHierarchy() const {
336   if (!is_finalized_) Finalize();
337   std::vector<const AggregateType*> hierarchy;
338   const AggregateType* current_container_type = this;
339   while (current_container_type != nullptr) {
340     hierarchy.push_back(current_container_type);
341     current_container_type =
342         current_container_type->IsClassType()
343             ? ClassType::cast(current_container_type)->GetSuperClass()
344             : nullptr;
345   }
346   std::reverse(hierarchy.begin(), hierarchy.end());
347   return hierarchy;
348 }
349 
HasField(const std::string & name) const350 bool AggregateType::HasField(const std::string& name) const {
351   if (!is_finalized_) Finalize();
352   for (auto& field : fields_) {
353     if (field.name_and_type.name == name) return true;
354   }
355   if (parent() != nullptr) {
356     if (auto parent_class = ClassType::DynamicCast(parent())) {
357       return parent_class->HasField(name);
358     }
359   }
360   return false;
361 }
362 
LookupFieldInternal(const std::string & name) const363 const Field& AggregateType::LookupFieldInternal(const std::string& name) const {
364   for (auto& field : fields_) {
365     if (field.name_and_type.name == name) return field;
366   }
367   if (parent() != nullptr) {
368     if (auto parent_class = ClassType::DynamicCast(parent())) {
369       return parent_class->LookupField(name);
370     }
371   }
372   ReportError("no field ", name, " found in ", this->ToString());
373 }
374 
LookupField(const std::string & name) const375 const Field& AggregateType::LookupField(const std::string& name) const {
376   if (!is_finalized_) Finalize();
377   return LookupFieldInternal(name);
378 }
379 
StructType(Namespace * nspace,const StructDeclaration * decl,MaybeSpecializationKey specialized_from)380 StructType::StructType(Namespace* nspace, const StructDeclaration* decl,
381                        MaybeSpecializationKey specialized_from)
382     : AggregateType(Kind::kStructType, nullptr, nspace, decl->name->value,
383                     specialized_from),
384       decl_(decl) {
385   if (decl->flags & StructFlag::kExport) {
386     generated_type_name_ = "TorqueStruct" + name();
387   } else {
388     generated_type_name_ =
389         GlobalContext::MakeUniqueName("TorqueStruct" + SimpleName());
390   }
391 }
392 
GetGeneratedTypeNameImpl() const393 std::string StructType::GetGeneratedTypeNameImpl() const {
394   return generated_type_name_;
395 }
396 
PackedSize() const397 size_t StructType::PackedSize() const {
398   size_t result = 0;
399   for (const Field& field : fields()) {
400     result += std::get<0>(field.GetFieldSizeInformation());
401   }
402   return result;
403 }
404 
ClassifyContents() const405 StructType::Classification StructType::ClassifyContents() const {
406   Classification result = ClassificationFlag::kEmpty;
407   for (const Field& struct_field : fields()) {
408     const Type* field_type = struct_field.name_and_type.type;
409     if (field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
410       result |= ClassificationFlag::kTagged;
411     } else if (auto field_as_struct = field_type->StructSupertype()) {
412       result |= (*field_as_struct)->ClassifyContents();
413     } else {
414       result |= ClassificationFlag::kUntagged;
415     }
416   }
417   return result;
418 }
419 
420 // static
ComputeName(const std::string & basename,MaybeSpecializationKey specialized_from)421 std::string Type::ComputeName(const std::string& basename,
422                               MaybeSpecializationKey specialized_from) {
423   if (!specialized_from) return basename;
424   if (specialized_from->generic == TypeOracle::GetConstReferenceGeneric()) {
425     return torque::ToString("const &", *specialized_from->specialized_types[0]);
426   }
427   if (specialized_from->generic == TypeOracle::GetMutableReferenceGeneric()) {
428     return torque::ToString("&", *specialized_from->specialized_types[0]);
429   }
430   std::stringstream s;
431   s << basename << "<";
432   bool first = true;
433   for (auto t : specialized_from->specialized_types) {
434     if (!first) {
435       s << ", ";
436     }
437     s << t->ToString();
438     first = false;
439   }
440   s << ">";
441   return s.str();
442 }
443 
SimpleNameImpl() const444 std::string StructType::SimpleNameImpl() const { return decl_->name->value; }
445 
446 // static
MatchUnaryGeneric(const Type * type,GenericType * generic)447 base::Optional<const Type*> Type::MatchUnaryGeneric(const Type* type,
448                                                     GenericType* generic) {
449   DCHECK_EQ(generic->generic_parameters().size(), 1);
450   if (!type->GetSpecializedFrom()) {
451     return base::nullopt;
452   }
453   auto& key = type->GetSpecializedFrom().value();
454   if (key.generic != generic || key.specialized_types.size() != 1) {
455     return base::nullopt;
456   }
457   return {key.specialized_types[0]};
458 }
459 
Methods(const std::string & name) const460 std::vector<Method*> AggregateType::Methods(const std::string& name) const {
461   if (!is_finalized_) Finalize();
462   std::vector<Method*> result;
463   std::copy_if(methods_.begin(), methods_.end(), std::back_inserter(result),
464                [name](Macro* macro) { return macro->ReadableName() == name; });
465   return result;
466 }
467 
ToExplicitString() const468 std::string StructType::ToExplicitString() const { return "struct " + name(); }
469 
Finalize() const470 void StructType::Finalize() const {
471   if (is_finalized_) return;
472   {
473     CurrentScope::Scope scope_activator(nspace());
474     CurrentSourcePosition::Scope position_activator(decl_->pos);
475     TypeVisitor::VisitStructMethods(const_cast<StructType*>(this), decl_);
476   }
477   is_finalized_ = true;
478   CheckForDuplicateFields();
479 }
480 
ClassType(const Type * parent,Namespace * nspace,const std::string & name,ClassFlags flags,const std::string & generates,const ClassDeclaration * decl,const TypeAlias * alias)481 ClassType::ClassType(const Type* parent, Namespace* nspace,
482                      const std::string& name, ClassFlags flags,
483                      const std::string& generates, const ClassDeclaration* decl,
484                      const TypeAlias* alias)
485     : AggregateType(Kind::kClassType, parent, nspace, name),
486       size_(ResidueClass::Unknown()),
487       flags_(flags),
488       generates_(generates),
489       decl_(decl),
490       alias_(alias) {}
491 
GetGeneratedTNodeTypeNameImpl() const492 std::string ClassType::GetGeneratedTNodeTypeNameImpl() const {
493   return generates_;
494 }
495 
GetGeneratedTypeNameImpl() const496 std::string ClassType::GetGeneratedTypeNameImpl() const {
497   return IsConstexpr() ? GetGeneratedTNodeTypeName()
498                        : "TNode<" + GetGeneratedTNodeTypeName() + ">";
499 }
500 
ToExplicitString() const501 std::string ClassType::ToExplicitString() const { return "class " + name(); }
502 
AllowInstantiation() const503 bool ClassType::AllowInstantiation() const {
504   return (!IsExtern() || nspace()->IsDefaultNamespace()) && !IsAbstract();
505 }
506 
Finalize() const507 void ClassType::Finalize() const {
508   if (is_finalized_) return;
509   CurrentScope::Scope scope_activator(alias_->ParentScope());
510   CurrentSourcePosition::Scope position_activator(decl_->pos);
511   TypeVisitor::VisitClassFieldsAndMethods(const_cast<ClassType*>(this),
512                                           this->decl_);
513   is_finalized_ = true;
514   if (GenerateCppClassDefinitions() || !IsExtern()) {
515     for (const Field& f : fields()) {
516       if (f.is_weak) {
517         Error("Generation of C++ class for Torque class ", name(),
518               " is not supported yet, because field ", f.name_and_type.name,
519               ": ", *f.name_and_type.type, " is a weak field.")
520             .Position(f.pos);
521       }
522     }
523   }
524   CheckForDuplicateFields();
525 }
526 
ComputeAllFields() const527 std::vector<Field> ClassType::ComputeAllFields() const {
528   std::vector<Field> all_fields;
529   const ClassType* super_class = this->GetSuperClass();
530   if (super_class) {
531     all_fields = super_class->ComputeAllFields();
532   }
533   const std::vector<Field>& fields = this->fields();
534   all_fields.insert(all_fields.end(), fields.begin(), fields.end());
535   return all_fields;
536 }
537 
ComputeHeaderFields() const538 std::vector<Field> ClassType::ComputeHeaderFields() const {
539   std::vector<Field> result;
540   for (Field& field : ComputeAllFields()) {
541     if (field.index) break;
542     DCHECK(*field.offset < header_size());
543     result.push_back(std::move(field));
544   }
545   return result;
546 }
547 
ComputeArrayFields() const548 std::vector<Field> ClassType::ComputeArrayFields() const {
549   std::vector<Field> result;
550   for (Field& field : ComputeAllFields()) {
551     if (!field.index) {
552       DCHECK(*field.offset < header_size());
553       continue;
554     }
555     result.push_back(std::move(field));
556   }
557   return result;
558 }
559 
InitializeInstanceTypes(base::Optional<int> own,base::Optional<std::pair<int,int>> range) const560 void ClassType::InitializeInstanceTypes(
561     base::Optional<int> own, base::Optional<std::pair<int, int>> range) const {
562   DCHECK(!own_instance_type_.has_value());
563   DCHECK(!instance_type_range_.has_value());
564   own_instance_type_ = own;
565   instance_type_range_ = range;
566 }
567 
OwnInstanceType() const568 base::Optional<int> ClassType::OwnInstanceType() const {
569   DCHECK(GlobalContext::IsInstanceTypesInitialized());
570   return own_instance_type_;
571 }
572 
InstanceTypeRange() const573 base::Optional<std::pair<int, int>> ClassType::InstanceTypeRange() const {
574   DCHECK(GlobalContext::IsInstanceTypesInitialized());
575   return instance_type_range_;
576 }
577 
578 namespace {
ComputeSlotKindsHelper(std::vector<ObjectSlotKind> * slots,size_t start_offset,const std::vector<Field> & fields)579 void ComputeSlotKindsHelper(std::vector<ObjectSlotKind>* slots,
580                             size_t start_offset,
581                             const std::vector<Field>& fields) {
582   size_t offset = start_offset;
583   for (const Field& field : fields) {
584     size_t field_size = std::get<0>(field.GetFieldSizeInformation());
585     size_t slot_index = offset / TargetArchitecture::TaggedSize();
586     // Rounding-up division to find the number of slots occupied by all the
587     // fields up to and including the current one.
588     size_t used_slots =
589         (offset + field_size + TargetArchitecture::TaggedSize() - 1) /
590         TargetArchitecture::TaggedSize();
591     while (used_slots > slots->size()) {
592       slots->push_back(ObjectSlotKind::kNoPointer);
593     }
594     const Type* type = field.name_and_type.type;
595     if (auto struct_type = type->StructSupertype()) {
596       ComputeSlotKindsHelper(slots, offset, (*struct_type)->fields());
597     } else {
598       ObjectSlotKind kind;
599       if (type->IsSubtypeOf(TypeOracle::GetObjectType())) {
600         if (field.is_weak) {
601           kind = ObjectSlotKind::kCustomWeakPointer;
602         } else {
603           kind = ObjectSlotKind::kStrongPointer;
604         }
605       } else if (type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
606         DCHECK(!field.is_weak);
607         kind = ObjectSlotKind::kMaybeObjectPointer;
608       } else {
609         kind = ObjectSlotKind::kNoPointer;
610       }
611       DCHECK(slots->at(slot_index) == ObjectSlotKind::kNoPointer);
612       slots->at(slot_index) = kind;
613     }
614 
615     offset += field_size;
616   }
617 }
618 }  // namespace
619 
ComputeHeaderSlotKinds() const620 std::vector<ObjectSlotKind> ClassType::ComputeHeaderSlotKinds() const {
621   std::vector<ObjectSlotKind> result;
622   std::vector<Field> header_fields = ComputeHeaderFields();
623   ComputeSlotKindsHelper(&result, 0, header_fields);
624   DCHECK_EQ(std::ceil(static_cast<double>(header_size()) /
625                       TargetArchitecture::TaggedSize()),
626             result.size());
627   return result;
628 }
629 
ComputeArraySlotKind() const630 base::Optional<ObjectSlotKind> ClassType::ComputeArraySlotKind() const {
631   std::vector<ObjectSlotKind> kinds;
632   ComputeSlotKindsHelper(&kinds, 0, ComputeArrayFields());
633   if (kinds.empty()) return base::nullopt;
634   std::sort(kinds.begin(), kinds.end());
635   if (kinds.front() == kinds.back()) return {kinds.front()};
636   if (kinds.front() == ObjectSlotKind::kStrongPointer &&
637       kinds.back() == ObjectSlotKind::kMaybeObjectPointer) {
638     return ObjectSlotKind::kMaybeObjectPointer;
639   }
640   Error("Array fields mix types with different GC visitation requirements.")
641       .Throw();
642 }
643 
HasNoPointerSlots() const644 bool ClassType::HasNoPointerSlots() const {
645   for (ObjectSlotKind slot : ComputeHeaderSlotKinds()) {
646     if (slot != ObjectSlotKind::kNoPointer) return false;
647   }
648   if (auto slot = ComputeArraySlotKind()) {
649     if (*slot != ObjectSlotKind::kNoPointer) return false;
650   }
651   return true;
652 }
653 
HasIndexedFieldsIncludingInParents() const654 bool ClassType::HasIndexedFieldsIncludingInParents() const {
655   for (const auto& field : fields_) {
656     if (field.index.has_value()) return true;
657   }
658   if (const ClassType* parent = GetSuperClass()) {
659     return parent->HasIndexedFieldsIncludingInParents();
660   }
661   return false;
662 }
663 
GetFieldPreceding(size_t field_index) const664 const Field* ClassType::GetFieldPreceding(size_t field_index) const {
665   if (field_index > 0) {
666     return &fields_[field_index - 1];
667   }
668   if (const ClassType* parent = GetSuperClass()) {
669     return parent->GetFieldPreceding(parent->fields_.size());
670   }
671   return nullptr;
672 }
673 
GetClassDeclaringField(const Field & f) const674 const ClassType* ClassType::GetClassDeclaringField(const Field& f) const {
675   for (const Field& field : fields_) {
676     if (f.name_and_type.name == field.name_and_type.name) return this;
677   }
678   return GetSuperClass()->GetClassDeclaringField(f);
679 }
680 
GetSliceMacroName(const Field & field) const681 std::string ClassType::GetSliceMacroName(const Field& field) const {
682   const ClassType* declarer = GetClassDeclaringField(field);
683   return "FieldSlice" + declarer->name() +
684          CamelifyString(field.name_and_type.name);
685 }
686 
GenerateAccessors()687 void ClassType::GenerateAccessors() {
688   bool at_or_after_indexed_field = false;
689   if (const ClassType* parent = GetSuperClass()) {
690     at_or_after_indexed_field = parent->HasIndexedFieldsIncludingInParents();
691   }
692   // For each field, construct AST snippets that implement a CSA accessor
693   // function. The implementation iterator will turn the snippets into code.
694   for (size_t field_index = 0; field_index < fields_.size(); ++field_index) {
695     Field& field = fields_[field_index];
696     if (field.name_and_type.type == TypeOracle::GetVoidType()) {
697       continue;
698     }
699     at_or_after_indexed_field =
700         at_or_after_indexed_field || field.index.has_value();
701     CurrentSourcePosition::Scope position_activator(field.pos);
702 
703     IdentifierExpression* parameter = MakeIdentifierExpression("o");
704     IdentifierExpression* index = MakeIdentifierExpression("i");
705 
706     std::string camel_field_name = CamelifyString(field.name_and_type.name);
707 
708     if (at_or_after_indexed_field) {
709       if (!field.index.has_value()) {
710         // There's no fundamental reason we couldn't generate functions to get
711         // references instead of slices, but it's not yet implemented.
712         ReportError(
713             "Torque doesn't yet support non-indexed fields after indexed "
714             "fields");
715       }
716 
717       GenerateSliceAccessor(field_index);
718     }
719 
720     // For now, only generate indexed accessors for simple types
721     if (field.index.has_value() && field.name_and_type.type->IsStructType()) {
722       continue;
723     }
724 
725     // Load accessor
726     std::string load_macro_name = "Load" + this->name() + camel_field_name;
727     Signature load_signature;
728     load_signature.parameter_names.push_back(MakeNode<Identifier>("o"));
729     load_signature.parameter_types.types.push_back(this);
730     if (field.index) {
731       load_signature.parameter_names.push_back(MakeNode<Identifier>("i"));
732       load_signature.parameter_types.types.push_back(
733           TypeOracle::GetIntPtrType());
734     }
735     load_signature.parameter_types.var_args = false;
736     load_signature.return_type = field.name_and_type.type;
737 
738     Expression* load_expression =
739         MakeFieldAccessExpression(parameter, field.name_and_type.name);
740     if (field.index) {
741       load_expression =
742           MakeNode<ElementAccessExpression>(load_expression, index);
743     }
744     Statement* load_body = MakeNode<ReturnStatement>(load_expression);
745     Declarations::DeclareMacro(load_macro_name, true, base::nullopt,
746                                load_signature, load_body, base::nullopt);
747 
748     // Store accessor
749     if (!field.const_qualified) {
750       IdentifierExpression* value = MakeIdentifierExpression("v");
751       std::string store_macro_name = "Store" + this->name() + camel_field_name;
752       Signature store_signature;
753       store_signature.parameter_names.push_back(MakeNode<Identifier>("o"));
754       store_signature.parameter_types.types.push_back(this);
755       if (field.index) {
756         store_signature.parameter_names.push_back(MakeNode<Identifier>("i"));
757         store_signature.parameter_types.types.push_back(
758             TypeOracle::GetIntPtrType());
759       }
760       store_signature.parameter_names.push_back(MakeNode<Identifier>("v"));
761       store_signature.parameter_types.types.push_back(field.name_and_type.type);
762       store_signature.parameter_types.var_args = false;
763       // TODO(danno): Store macros probably should return their value argument
764       store_signature.return_type = TypeOracle::GetVoidType();
765       Expression* store_expression =
766           MakeFieldAccessExpression(parameter, field.name_and_type.name);
767       if (field.index) {
768         store_expression =
769             MakeNode<ElementAccessExpression>(store_expression, index);
770       }
771       Statement* store_body = MakeNode<ExpressionStatement>(
772           MakeNode<AssignmentExpression>(store_expression, value));
773       Declarations::DeclareMacro(store_macro_name, true, base::nullopt,
774                                  store_signature, store_body, base::nullopt,
775                                  false);
776     }
777   }
778 }
779 
GenerateSliceAccessor(size_t field_index)780 void ClassType::GenerateSliceAccessor(size_t field_index) {
781   // Generate a Torque macro for getting a Slice to this field. This macro can
782   // be called by the dot operator for this field. In Torque, this function for
783   // class "ClassName" and field "field_name" and field type "FieldType" would
784   // be written as one of the following:
785   //
786   // If the field has a known offset (in this example, 16):
787   // FieldSliceClassNameFieldName(o: ClassName) {
788   //   return torque_internal::Slice<FieldType> {
789   //     object: o,
790   //     offset: 16,
791   //     length: torque_internal::%IndexedFieldLength<ClassName>(
792   //                 o, "field_name")),
793   //     unsafeMarker: torque_internal::Unsafe {}
794   //   };
795   // }
796   //
797   // If the field has an unknown offset, and the previous field is named p, and
798   // an item in the previous field has size 4:
799   // FieldSliceClassNameFieldName(o: ClassName) {
800   //   const previous = &o.p;
801   //   return torque_internal::Slice<FieldType> {
802   //     object: o,
803   //     offset: previous.offset + 4 * previous.length,
804   //     length: torque_internal::%IndexedFieldLength<ClassName>(
805   //                 o, "field_name")),
806   //     unsafeMarker: torque_internal::Unsafe {}
807   //   };
808   // }
809   const Field& field = fields_[field_index];
810   std::string macro_name = GetSliceMacroName(field);
811   Signature signature;
812   Identifier* parameter_identifier = MakeNode<Identifier>("o");
813   signature.parameter_names.push_back(parameter_identifier);
814   signature.parameter_types.types.push_back(this);
815   signature.parameter_types.var_args = false;
816   signature.return_type = TypeOracle::GetSliceType(field.name_and_type.type);
817 
818   std::vector<Statement*> statements;
819   Expression* offset_expression = nullptr;
820   IdentifierExpression* parameter =
821       MakeNode<IdentifierExpression>(parameter_identifier);
822 
823   if (field.offset.has_value()) {
824     offset_expression =
825         MakeNode<NumberLiteralExpression>(static_cast<double>(*field.offset));
826   } else {
827     const Field* previous = GetFieldPreceding(field_index);
828     DCHECK_NOT_NULL(previous);
829 
830     // o.p
831     Expression* previous_expression =
832         MakeFieldAccessExpression(parameter, previous->name_and_type.name);
833 
834     // &o.p
835     previous_expression = MakeCallExpression("&", {previous_expression});
836 
837     // const previous = &o.p;
838     Statement* define_previous =
839         MakeConstDeclarationStatement("previous", previous_expression);
840     statements.push_back(define_previous);
841 
842     // 4
843     size_t previous_element_size;
844     std::tie(previous_element_size, std::ignore) =
845         *SizeOf(previous->name_and_type.type);
846     Expression* previous_element_size_expression =
847         MakeNode<NumberLiteralExpression>(
848             static_cast<double>(previous_element_size));
849 
850     // previous.length
851     Expression* previous_length_expression = MakeFieldAccessExpression(
852         MakeIdentifierExpression("previous"), "length");
853 
854     // previous.offset
855     Expression* previous_offset_expression = MakeFieldAccessExpression(
856         MakeIdentifierExpression("previous"), "offset");
857 
858     // 4 * previous.length
859     // In contrast to the code used for allocation, we don't need overflow
860     // checks here because we already know all the offsets fit into memory.
861     offset_expression = MakeCallExpression(
862         "*", {previous_element_size_expression, previous_length_expression});
863 
864     // previous.offset + 4 * previous.length
865     offset_expression = MakeCallExpression(
866         "+", {previous_offset_expression, offset_expression});
867   }
868 
869   // torque_internal::%IndexedFieldLength<ClassName>(o, "field_name")
870   Expression* length_expression = MakeCallExpression(
871       MakeIdentifierExpression({"torque_internal"}, "%IndexedFieldLength",
872                                {MakeNode<PrecomputedTypeExpression>(this)}),
873       {parameter, MakeNode<StringLiteralExpression>(
874                       StringLiteralQuote(field.name_and_type.name))});
875 
876   // torque_internal::Unsafe {}
877   Expression* unsafe_expression = MakeStructExpression(
878       MakeBasicTypeExpression({"torque_internal"}, "Unsafe"), {});
879 
880   // torque_internal::Slice<FieldType> {
881   //   object: o,
882   //   offset: <<offset_expression>>,
883   //   length: torque_internal::%IndexedFieldLength<ClassName>(
884   //               o, "field_name")),
885   //   unsafeMarker: torque_internal::Unsafe {}
886   // }
887   Expression* slice_expression = MakeStructExpression(
888       MakeBasicTypeExpression(
889           {"torque_internal"}, "Slice",
890           {MakeNode<PrecomputedTypeExpression>(field.name_and_type.type)}),
891       {{MakeNode<Identifier>("object"), parameter},
892        {MakeNode<Identifier>("offset"), offset_expression},
893        {MakeNode<Identifier>("length"), length_expression},
894        {MakeNode<Identifier>("unsafeMarker"), unsafe_expression}});
895 
896   statements.push_back(MakeNode<ReturnStatement>(slice_expression));
897   Statement* block =
898       MakeNode<BlockStatement>(/*deferred=*/false, std::move(statements));
899 
900   Macro* macro = Declarations::DeclareMacro(macro_name, true, base::nullopt,
901                                             signature, block, base::nullopt);
902   GlobalContext::EnsureInCCOutputList(TorqueMacro::cast(macro));
903 }
904 
HasStaticSize() const905 bool ClassType::HasStaticSize() const {
906   // Abstract classes don't have instances directly, so asking this question
907   // doesn't make sense.
908   DCHECK(!IsAbstract());
909   if (IsSubtypeOf(TypeOracle::GetJSObjectType()) && !IsShape()) return false;
910   return size().SingleValue().has_value();
911 }
912 
AttributedToFile() const913 SourceId ClassType::AttributedToFile() const {
914   bool in_test_directory = StringStartsWith(
915       SourceFileMap::PathFromV8Root(GetPosition().source).substr(), "test/");
916   if (!in_test_directory && (IsExtern() || ShouldExport())) {
917     return GetPosition().source;
918   }
919   return SourceFileMap::GetSourceId("src/objects/torque-defined-classes.tq");
920 }
921 
PrintSignature(std::ostream & os,const Signature & sig,bool with_names)922 void PrintSignature(std::ostream& os, const Signature& sig, bool with_names) {
923   os << "(";
924   for (size_t i = 0; i < sig.parameter_types.types.size(); ++i) {
925     if (i == 0 && sig.implicit_count != 0) os << "implicit ";
926     if (sig.implicit_count > 0 && sig.implicit_count == i) {
927       os << ")(";
928     } else {
929       if (i > 0) os << ", ";
930     }
931     if (with_names && !sig.parameter_names.empty()) {
932       if (i < sig.parameter_names.size()) {
933         os << sig.parameter_names[i] << ": ";
934       }
935     }
936     os << *sig.parameter_types.types[i];
937   }
938   if (sig.parameter_types.var_args) {
939     if (sig.parameter_names.size()) os << ", ";
940     os << "...";
941   }
942   os << ")";
943   os << ": " << *sig.return_type;
944 
945   if (sig.labels.empty()) return;
946 
947   os << " labels ";
948   for (size_t i = 0; i < sig.labels.size(); ++i) {
949     if (i > 0) os << ", ";
950     os << sig.labels[i].name;
951     if (sig.labels[i].types.size() > 0) os << "(" << sig.labels[i].types << ")";
952   }
953 }
954 
operator <<(std::ostream & os,const NameAndType & name_and_type)955 std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type) {
956   os << name_and_type.name;
957   os << ": ";
958   os << *name_and_type.type;
959   return os;
960 }
961 
operator <<(std::ostream & os,const Field & field)962 std::ostream& operator<<(std::ostream& os, const Field& field) {
963   os << field.name_and_type;
964   if (field.is_weak) {
965     os << " (weak)";
966   }
967   return os;
968 }
969 
operator <<(std::ostream & os,const Signature & sig)970 std::ostream& operator<<(std::ostream& os, const Signature& sig) {
971   PrintSignature(os, sig, true);
972   return os;
973 }
974 
operator <<(std::ostream & os,const TypeVector & types)975 std::ostream& operator<<(std::ostream& os, const TypeVector& types) {
976   PrintCommaSeparatedList(os, types);
977   return os;
978 }
979 
operator <<(std::ostream & os,const ParameterTypes & p)980 std::ostream& operator<<(std::ostream& os, const ParameterTypes& p) {
981   PrintCommaSeparatedList(os, p.types);
982   if (p.var_args) {
983     if (p.types.size() > 0) os << ", ";
984     os << "...";
985   }
986   return os;
987 }
988 
HasSameTypesAs(const Signature & other,ParameterMode mode) const989 bool Signature::HasSameTypesAs(const Signature& other,
990                                ParameterMode mode) const {
991   auto compare_types = types();
992   auto other_compare_types = other.types();
993   if (mode == ParameterMode::kIgnoreImplicit) {
994     compare_types = GetExplicitTypes();
995     other_compare_types = other.GetExplicitTypes();
996   }
997   if (!(compare_types == other_compare_types &&
998         parameter_types.var_args == other.parameter_types.var_args &&
999         return_type == other.return_type)) {
1000     return false;
1001   }
1002   if (labels.size() != other.labels.size()) {
1003     return false;
1004   }
1005   size_t i = 0;
1006   for (const auto& l : labels) {
1007     if (l.types != other.labels[i++].types) {
1008       return false;
1009     }
1010   }
1011   return true;
1012 }
1013 
1014 namespace {
FirstTypeIsContext(const std::vector<const Type * > parameter_types)1015 bool FirstTypeIsContext(const std::vector<const Type*> parameter_types) {
1016   return !parameter_types.empty() &&
1017          parameter_types[0] == TypeOracle::GetContextType();
1018 }
1019 }  // namespace
1020 
HasContextParameter() const1021 bool Signature::HasContextParameter() const {
1022   return FirstTypeIsContext(types());
1023 }
1024 
HasContextParameter() const1025 bool BuiltinPointerType::HasContextParameter() const {
1026   return FirstTypeIsContext(parameter_types());
1027 }
1028 
IsAssignableFrom(const Type * to,const Type * from)1029 bool IsAssignableFrom(const Type* to, const Type* from) {
1030   if (to == from) return true;
1031   if (from->IsSubtypeOf(to)) return true;
1032   return TypeOracle::ImplicitlyConvertableFrom(to, from).has_value();
1033 }
1034 
operator <(const Type & a,const Type & b)1035 bool operator<(const Type& a, const Type& b) { return a.id() < b.id(); }
1036 
ProjectStructField(VisitResult structure,const std::string & fieldname)1037 VisitResult ProjectStructField(VisitResult structure,
1038                                const std::string& fieldname) {
1039   BottomOffset begin = structure.stack_range().begin();
1040 
1041   // Check constructor this super classes for fields.
1042   const StructType* type = *structure.type()->StructSupertype();
1043   auto& fields = type->fields();
1044   for (auto& field : fields) {
1045     BottomOffset end = begin + LoweredSlotCount(field.name_and_type.type);
1046     if (field.name_and_type.name == fieldname) {
1047       return VisitResult(field.name_and_type.type, StackRange{begin, end});
1048     }
1049     begin = end;
1050   }
1051 
1052   ReportError("struct '", type->name(), "' doesn't contain a field '",
1053               fieldname, "'");
1054 }
1055 
1056 namespace {
AppendLoweredTypes(const Type * type,std::vector<const Type * > * result)1057 void AppendLoweredTypes(const Type* type, std::vector<const Type*>* result) {
1058   DCHECK_NE(type, TypeOracle::GetNeverType());
1059   if (type->IsConstexpr()) return;
1060   if (type == TypeOracle::GetVoidType()) return;
1061   if (base::Optional<const StructType*> s = type->StructSupertype()) {
1062     for (const Field& field : (*s)->fields()) {
1063       AppendLoweredTypes(field.name_and_type.type, result);
1064     }
1065   } else {
1066     result->push_back(type);
1067   }
1068 }
1069 }  // namespace
1070 
LowerType(const Type * type)1071 TypeVector LowerType(const Type* type) {
1072   TypeVector result;
1073   AppendLoweredTypes(type, &result);
1074   return result;
1075 }
1076 
LoweredSlotCount(const Type * type)1077 size_t LoweredSlotCount(const Type* type) { return LowerType(type).size(); }
1078 
LowerParameterTypes(const TypeVector & parameters)1079 TypeVector LowerParameterTypes(const TypeVector& parameters) {
1080   std::vector<const Type*> result;
1081   for (const Type* t : parameters) {
1082     AppendLoweredTypes(t, &result);
1083   }
1084   return result;
1085 }
1086 
LowerParameterTypes(const ParameterTypes & parameter_types,size_t arg_count)1087 TypeVector LowerParameterTypes(const ParameterTypes& parameter_types,
1088                                size_t arg_count) {
1089   std::vector<const Type*> result = LowerParameterTypes(parameter_types.types);
1090   for (size_t i = parameter_types.types.size(); i < arg_count; ++i) {
1091     DCHECK(parameter_types.var_args);
1092     AppendLoweredTypes(TypeOracle::GetObjectType(), &result);
1093   }
1094   return result;
1095 }
1096 
NeverResult()1097 VisitResult VisitResult::NeverResult() {
1098   VisitResult result;
1099   result.type_ = TypeOracle::GetNeverType();
1100   return result;
1101 }
1102 
TopTypeResult(std::string top_reason,const Type * from_type)1103 VisitResult VisitResult::TopTypeResult(std::string top_reason,
1104                                        const Type* from_type) {
1105   VisitResult result;
1106   result.type_ = TypeOracle::GetTopType(std::move(top_reason), from_type);
1107   return result;
1108 }
1109 
GetFieldSizeInformation() const1110 std::tuple<size_t, std::string> Field::GetFieldSizeInformation() const {
1111   auto optional = SizeOf(this->name_and_type.type);
1112   if (optional.has_value()) {
1113     return *optional;
1114   }
1115   Error("fields of type ", *name_and_type.type, " are not (yet) supported")
1116       .Position(pos);
1117   return std::make_tuple(0, "#no size");
1118 }
1119 
AlignmentLog2() const1120 size_t Type::AlignmentLog2() const {
1121   if (parent()) return parent()->AlignmentLog2();
1122   return TargetArchitecture::TaggedSize();
1123 }
1124 
AlignmentLog2() const1125 size_t AbstractType::AlignmentLog2() const {
1126   size_t alignment;
1127   if (this == TypeOracle::GetTaggedType()) {
1128     alignment = TargetArchitecture::TaggedSize();
1129   } else if (this == TypeOracle::GetRawPtrType()) {
1130     alignment = TargetArchitecture::RawPtrSize();
1131   } else if (this == TypeOracle::GetExternalPointerType()) {
1132     alignment = TargetArchitecture::ExternalPointerSize();
1133   } else if (this == TypeOracle::GetVoidType()) {
1134     alignment = 1;
1135   } else if (this == TypeOracle::GetInt8Type()) {
1136     alignment = kUInt8Size;
1137   } else if (this == TypeOracle::GetUint8Type()) {
1138     alignment = kUInt8Size;
1139   } else if (this == TypeOracle::GetInt16Type()) {
1140     alignment = kUInt16Size;
1141   } else if (this == TypeOracle::GetUint16Type()) {
1142     alignment = kUInt16Size;
1143   } else if (this == TypeOracle::GetInt32Type()) {
1144     alignment = kInt32Size;
1145   } else if (this == TypeOracle::GetUint32Type()) {
1146     alignment = kInt32Size;
1147   } else if (this == TypeOracle::GetFloat64Type()) {
1148     alignment = kDoubleSize;
1149   } else if (this == TypeOracle::GetIntPtrType()) {
1150     alignment = TargetArchitecture::RawPtrSize();
1151   } else if (this == TypeOracle::GetUIntPtrType()) {
1152     alignment = TargetArchitecture::RawPtrSize();
1153   } else {
1154     return Type::AlignmentLog2();
1155   }
1156   alignment = std::min(alignment, TargetArchitecture::TaggedSize());
1157   return base::bits::WhichPowerOfTwo(alignment);
1158 }
1159 
AlignmentLog2() const1160 size_t StructType::AlignmentLog2() const {
1161   if (this == TypeOracle::GetFloat64OrHoleType()) {
1162     return TypeOracle::GetFloat64Type()->AlignmentLog2();
1163   }
1164   size_t alignment_log_2 = 0;
1165   for (const Field& field : fields()) {
1166     alignment_log_2 =
1167         std::max(alignment_log_2, field.name_and_type.type->AlignmentLog2());
1168   }
1169   return alignment_log_2;
1170 }
1171 
ValidateAlignment(ResidueClass at_offset) const1172 void Field::ValidateAlignment(ResidueClass at_offset) const {
1173   const Type* type = name_and_type.type;
1174   base::Optional<const StructType*> struct_type = type->StructSupertype();
1175   if (struct_type && struct_type != TypeOracle::GetFloat64OrHoleType()) {
1176     for (const Field& field : (*struct_type)->fields()) {
1177       field.ValidateAlignment(at_offset);
1178       size_t field_size = std::get<0>(field.GetFieldSizeInformation());
1179       at_offset += field_size;
1180     }
1181   } else {
1182     size_t alignment_log_2 = name_and_type.type->AlignmentLog2();
1183     if (at_offset.AlignmentLog2() < alignment_log_2) {
1184       Error("field ", name_and_type.name, " at offset ", at_offset, " is not ",
1185             size_t{1} << alignment_log_2, "-byte aligned.")
1186           .Position(pos);
1187     }
1188   }
1189 }
1190 
SizeOf(const Type * type)1191 base::Optional<std::tuple<size_t, std::string>> SizeOf(const Type* type) {
1192   std::string size_string;
1193   size_t size;
1194   if (type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
1195     size = TargetArchitecture::TaggedSize();
1196     size_string = "kTaggedSize";
1197   } else if (type->IsSubtypeOf(TypeOracle::GetRawPtrType())) {
1198     size = TargetArchitecture::RawPtrSize();
1199     size_string = "kSystemPointerSize";
1200   } else if (type->IsSubtypeOf(TypeOracle::GetExternalPointerType())) {
1201     size = TargetArchitecture::ExternalPointerSize();
1202     size_string = "kExternalPointerSize";
1203   } else if (type->IsSubtypeOf(TypeOracle::GetVoidType())) {
1204     size = 0;
1205     size_string = "0";
1206   } else if (type->IsSubtypeOf(TypeOracle::GetInt8Type())) {
1207     size = kUInt8Size;
1208     size_string = "kUInt8Size";
1209   } else if (type->IsSubtypeOf(TypeOracle::GetUint8Type())) {
1210     size = kUInt8Size;
1211     size_string = "kUInt8Size";
1212   } else if (type->IsSubtypeOf(TypeOracle::GetInt16Type())) {
1213     size = kUInt16Size;
1214     size_string = "kUInt16Size";
1215   } else if (type->IsSubtypeOf(TypeOracle::GetUint16Type())) {
1216     size = kUInt16Size;
1217     size_string = "kUInt16Size";
1218   } else if (type->IsSubtypeOf(TypeOracle::GetInt32Type())) {
1219     size = kInt32Size;
1220     size_string = "kInt32Size";
1221   } else if (type->IsSubtypeOf(TypeOracle::GetUint32Type())) {
1222     size = kInt32Size;
1223     size_string = "kInt32Size";
1224   } else if (type->IsSubtypeOf(TypeOracle::GetFloat64Type())) {
1225     size = kDoubleSize;
1226     size_string = "kDoubleSize";
1227   } else if (type->IsSubtypeOf(TypeOracle::GetIntPtrType())) {
1228     size = TargetArchitecture::RawPtrSize();
1229     size_string = "kIntptrSize";
1230   } else if (type->IsSubtypeOf(TypeOracle::GetUIntPtrType())) {
1231     size = TargetArchitecture::RawPtrSize();
1232     size_string = "kIntptrSize";
1233   } else if (auto struct_type = type->StructSupertype()) {
1234     if (type == TypeOracle::GetFloat64OrHoleType()) {
1235       size = kDoubleSize;
1236       size_string = "kDoubleSize";
1237     } else {
1238       size = (*struct_type)->PackedSize();
1239       size_string = std::to_string(size);
1240     }
1241   } else {
1242     return {};
1243   }
1244   return std::make_tuple(size, size_string);
1245 }
1246 
IsAnyUnsignedInteger(const Type * type)1247 bool IsAnyUnsignedInteger(const Type* type) {
1248   return type == TypeOracle::GetUint32Type() ||
1249          type == TypeOracle::GetUint31Type() ||
1250          type == TypeOracle::GetUint16Type() ||
1251          type == TypeOracle::GetUint8Type() ||
1252          type == TypeOracle::GetUIntPtrType();
1253 }
1254 
IsAllowedAsBitField(const Type * type)1255 bool IsAllowedAsBitField(const Type* type) {
1256   if (type->IsBitFieldStructType()) {
1257     // No nested bitfield structs for now. We could reconsider if there's a
1258     // compelling use case.
1259     return false;
1260   }
1261   // Any integer-ish type, including bools and enums which inherit from integer
1262   // types, are allowed. Note, however, that we always zero-extend during
1263   // decoding regardless of signedness.
1264   return IsPointerSizeIntegralType(type) || Is32BitIntegralType(type);
1265 }
1266 
IsPointerSizeIntegralType(const Type * type)1267 bool IsPointerSizeIntegralType(const Type* type) {
1268   return type->IsSubtypeOf(TypeOracle::GetUIntPtrType()) ||
1269          type->IsSubtypeOf(TypeOracle::GetIntPtrType());
1270 }
1271 
Is32BitIntegralType(const Type * type)1272 bool Is32BitIntegralType(const Type* type) {
1273   return type->IsSubtypeOf(TypeOracle::GetUint32Type()) ||
1274          type->IsSubtypeOf(TypeOracle::GetInt32Type()) ||
1275          type->IsSubtypeOf(TypeOracle::GetBoolType());
1276 }
1277 
ExtractSimpleFieldArraySize(const ClassType & class_type,Expression * array_size)1278 base::Optional<NameAndType> ExtractSimpleFieldArraySize(
1279     const ClassType& class_type, Expression* array_size) {
1280   IdentifierExpression* identifier =
1281       IdentifierExpression::DynamicCast(array_size);
1282   if (!identifier || !identifier->generic_arguments.empty() ||
1283       !identifier->namespace_qualification.empty())
1284     return {};
1285   if (!class_type.HasField(identifier->name->value)) return {};
1286   return class_type.LookupField(identifier->name->value).name_and_type;
1287 }
1288 
GetRuntimeType() const1289 std::string Type::GetRuntimeType() const {
1290   if (IsSubtypeOf(TypeOracle::GetSmiType())) return "Smi";
1291   if (IsSubtypeOf(TypeOracle::GetTaggedType())) {
1292     return GetGeneratedTNodeTypeName();
1293   }
1294   if (base::Optional<const StructType*> struct_type = StructSupertype()) {
1295     std::stringstream result;
1296     result << "std::tuple<";
1297     bool first = true;
1298     for (const Type* field_type : LowerType(*struct_type)) {
1299       if (!first) result << ", ";
1300       first = false;
1301       result << field_type->GetRuntimeType();
1302     }
1303     result << ">";
1304     return result.str();
1305   }
1306   return ConstexprVersion()->GetGeneratedTypeName();
1307 }
1308 
1309 }  // namespace torque
1310 }  // namespace internal
1311 }  // namespace v8
1312