• 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 
AggregateSupertype() const131 base::Optional<const AggregateType*> Type::AggregateSupertype() const {
132   for (const Type* t = this; t != nullptr; t = t->parent()) {
133     if (auto* aggregate_type = AggregateType::DynamicCast(t)) {
134       return aggregate_type;
135     }
136   }
137   return base::nullopt;
138 }
139 
140 // static
CommonSupertype(const Type * a,const Type * b)141 const Type* Type::CommonSupertype(const Type* a, const Type* b) {
142   int diff = a->Depth() - b->Depth();
143   const Type* a_supertype = a;
144   const Type* b_supertype = b;
145   for (; diff > 0; --diff) a_supertype = a_supertype->parent();
146   for (; diff < 0; ++diff) b_supertype = b_supertype->parent();
147   while (a_supertype && b_supertype) {
148     if (a_supertype == b_supertype) return a_supertype;
149     a_supertype = a_supertype->parent();
150     b_supertype = b_supertype->parent();
151   }
152   ReportError("types " + a->ToString() + " and " + b->ToString() +
153               " have no common supertype");
154 }
155 
Depth() const156 int Type::Depth() const {
157   int result = 0;
158   for (const Type* current = parent_; current; current = current->parent_) {
159     ++result;
160   }
161   return result;
162 }
163 
IsAbstractName(const std::string & name) const164 bool Type::IsAbstractName(const std::string& name) const {
165   if (!IsAbstractType()) return false;
166   return AbstractType::cast(this)->name() == name;
167 }
168 
GetGeneratedTypeName() const169 std::string Type::GetGeneratedTypeName() const {
170   std::string result = GetGeneratedTypeNameImpl();
171   if (result.empty() || result == "TNode<>") {
172     ReportError("Generated type is required for type '", ToString(),
173                 "'. Use 'generates' clause in definition.");
174   }
175   return result;
176 }
177 
GetGeneratedTNodeTypeName() const178 std::string Type::GetGeneratedTNodeTypeName() const {
179   std::string result = GetGeneratedTNodeTypeNameImpl();
180   if (result.empty() || IsConstexpr()) {
181     ReportError("Generated TNode type is required for type '", ToString(),
182                 "'. Use 'generates' clause in definition.");
183   }
184   return result;
185 }
186 
GetGeneratedTypeNameImpl() const187 std::string AbstractType::GetGeneratedTypeNameImpl() const {
188   // A special case that is not very well represented by the "generates"
189   // syntax in the .tq files: Lazy<T> represents a std::function that
190   // produces a TNode of the wrapped type.
191   if (base::Optional<const Type*> type_wrapped_in_lazy =
192           Type::MatchUnaryGeneric(this, TypeOracle::GetLazyGeneric())) {
193     DCHECK(!IsConstexpr());
194     return "std::function<" + (*type_wrapped_in_lazy)->GetGeneratedTypeName() +
195            "()>";
196   }
197 
198   if (generated_type_.empty()) {
199     return parent()->GetGeneratedTypeName();
200   }
201   return IsConstexpr() ? generated_type_ : "TNode<" + generated_type_ + ">";
202 }
203 
GetGeneratedTNodeTypeNameImpl() const204 std::string AbstractType::GetGeneratedTNodeTypeNameImpl() const {
205   if (generated_type_.empty()) return parent()->GetGeneratedTNodeTypeName();
206   return generated_type_;
207 }
208 
GetTypeCheckers() const209 std::vector<TypeChecker> AbstractType::GetTypeCheckers() const {
210   if (UseParentTypeChecker()) return parent()->GetTypeCheckers();
211   std::string type_name = name();
212   if (auto strong_type =
213           Type::MatchUnaryGeneric(this, TypeOracle::GetWeakGeneric())) {
214     auto strong_runtime_types = (*strong_type)->GetTypeCheckers();
215     std::vector<TypeChecker> result;
216     for (const TypeChecker& type : strong_runtime_types) {
217       // Generic parameter in Weak<T> should have already been checked to
218       // extend HeapObject, so it couldn't itself be another weak type.
219       DCHECK(type.weak_ref_to.empty());
220       result.push_back({type_name, type.type});
221     }
222     return result;
223   }
224   return {{type_name, ""}};
225 }
226 
ToExplicitString() const227 std::string BuiltinPointerType::ToExplicitString() const {
228   std::stringstream result;
229   result << "builtin (";
230   PrintCommaSeparatedList(result, parameter_types_);
231   result << ") => " << *return_type_;
232   return result.str();
233 }
234 
SimpleNameImpl() const235 std::string BuiltinPointerType::SimpleNameImpl() const {
236   std::stringstream result;
237   result << "BuiltinPointer";
238   for (const Type* t : parameter_types_) {
239     result << "_" << t->SimpleName();
240   }
241   result << "_" << return_type_->SimpleName();
242   return result.str();
243 }
244 
ToExplicitString() const245 std::string UnionType::ToExplicitString() const {
246   std::stringstream result;
247   result << "(";
248   bool first = true;
249   for (const Type* t : types_) {
250     if (!first) {
251       result << " | ";
252     }
253     first = false;
254     result << *t;
255   }
256   result << ")";
257   return result.str();
258 }
259 
SimpleNameImpl() const260 std::string UnionType::SimpleNameImpl() const {
261   std::stringstream result;
262   bool first = true;
263   for (const Type* t : types_) {
264     if (!first) {
265       result << "_OR_";
266     }
267     first = false;
268     result << t->SimpleName();
269   }
270   return result.str();
271 }
272 
GetGeneratedTNodeTypeNameImpl() const273 std::string UnionType::GetGeneratedTNodeTypeNameImpl() const {
274   if (types_.size() <= 3) {
275     std::set<std::string> members;
276     for (const Type* t : types_) {
277       members.insert(t->GetGeneratedTNodeTypeName());
278     }
279     if (members == std::set<std::string>{"Smi", "HeapNumber"}) {
280       return "Number";
281     }
282     if (members == std::set<std::string>{"Smi", "HeapNumber", "BigInt"}) {
283       return "Numeric";
284     }
285   }
286   return parent()->GetGeneratedTNodeTypeName();
287 }
288 
RecomputeParent()289 void UnionType::RecomputeParent() {
290   const Type* parent = nullptr;
291   for (const Type* t : types_) {
292     if (parent == nullptr) {
293       parent = t;
294     } else {
295       parent = CommonSupertype(parent, t);
296     }
297   }
298   set_parent(parent);
299 }
300 
Subtract(const Type * t)301 void UnionType::Subtract(const Type* t) {
302   for (auto it = types_.begin(); it != types_.end();) {
303     if ((*it)->IsSubtypeOf(t)) {
304       it = types_.erase(it);
305     } else {
306       ++it;
307     }
308   }
309   if (types_.size() == 0) types_.insert(TypeOracle::GetNeverType());
310   RecomputeParent();
311 }
312 
SubtractType(const Type * a,const Type * b)313 const Type* SubtractType(const Type* a, const Type* b) {
314   UnionType result = UnionType::FromType(a);
315   result.Subtract(b);
316   return TypeOracle::GetUnionType(result);
317 }
318 
ToExplicitString() const319 std::string BitFieldStructType::ToExplicitString() const {
320   return "bitfield struct " + name();
321 }
322 
LookupField(const std::string & name) const323 const BitField& BitFieldStructType::LookupField(const std::string& name) const {
324   for (const BitField& field : fields_) {
325     if (field.name_and_type.name == name) {
326       return field;
327     }
328   }
329   ReportError("Couldn't find bitfield ", name);
330 }
331 
CheckForDuplicateFields() const332 void AggregateType::CheckForDuplicateFields() const {
333   // Check the aggregate hierarchy and currently defined class for duplicate
334   // field declarations.
335   auto hierarchy = GetHierarchy();
336   std::map<std::string, const AggregateType*> field_names;
337   for (const AggregateType* aggregate_type : hierarchy) {
338     for (const Field& field : aggregate_type->fields()) {
339       const std::string& field_name = field.name_and_type.name;
340       auto i = field_names.find(field_name);
341       if (i != field_names.end()) {
342         CurrentSourcePosition::Scope current_source_position(field.pos);
343         std::string aggregate_type_name =
344             aggregate_type->IsClassType() ? "class" : "struct";
345         if (i->second == this) {
346           ReportError(aggregate_type_name, " '", name(),
347                       "' declares a field with the name '", field_name,
348                       "' more than once");
349         } else {
350           ReportError(aggregate_type_name, " '", name(),
351                       "' declares a field with the name '", field_name,
352                       "' that masks an inherited field from class '",
353                       i->second->name(), "'");
354         }
355       }
356       field_names[field_name] = aggregate_type;
357     }
358   }
359 }
360 
GetHierarchy() const361 std::vector<const AggregateType*> AggregateType::GetHierarchy() const {
362   if (!is_finalized_) Finalize();
363   std::vector<const AggregateType*> hierarchy;
364   const AggregateType* current_container_type = this;
365   while (current_container_type != nullptr) {
366     hierarchy.push_back(current_container_type);
367     current_container_type =
368         current_container_type->IsClassType()
369             ? ClassType::cast(current_container_type)->GetSuperClass()
370             : nullptr;
371   }
372   std::reverse(hierarchy.begin(), hierarchy.end());
373   return hierarchy;
374 }
375 
HasField(const std::string & name) const376 bool AggregateType::HasField(const std::string& name) const {
377   if (!is_finalized_) Finalize();
378   for (auto& field : fields_) {
379     if (field.name_and_type.name == name) return true;
380   }
381   if (parent() != nullptr) {
382     if (auto parent_class = ClassType::DynamicCast(parent())) {
383       return parent_class->HasField(name);
384     }
385   }
386   return false;
387 }
388 
LookupFieldInternal(const std::string & name) const389 const Field& AggregateType::LookupFieldInternal(const std::string& name) const {
390   for (auto& field : fields_) {
391     if (field.name_and_type.name == name) return field;
392   }
393   if (parent() != nullptr) {
394     if (auto parent_class = ClassType::DynamicCast(parent())) {
395       return parent_class->LookupField(name);
396     }
397   }
398   ReportError("no field ", name, " found in ", this->ToString());
399 }
400 
LookupField(const std::string & name) const401 const Field& AggregateType::LookupField(const std::string& name) const {
402   if (!is_finalized_) Finalize();
403   return LookupFieldInternal(name);
404 }
405 
StructType(Namespace * nspace,const StructDeclaration * decl,MaybeSpecializationKey specialized_from)406 StructType::StructType(Namespace* nspace, const StructDeclaration* decl,
407                        MaybeSpecializationKey specialized_from)
408     : AggregateType(Kind::kStructType, nullptr, nspace, decl->name->value,
409                     specialized_from),
410       decl_(decl) {
411   if (decl->flags & StructFlag::kExport) {
412     generated_type_name_ = "TorqueStruct" + name();
413   } else {
414     generated_type_name_ =
415         GlobalContext::MakeUniqueName("TorqueStruct" + SimpleName());
416   }
417 }
418 
GetGeneratedTypeNameImpl() const419 std::string StructType::GetGeneratedTypeNameImpl() const {
420   return generated_type_name_;
421 }
422 
PackedSize() const423 size_t StructType::PackedSize() const {
424   size_t result = 0;
425   for (const Field& field : fields()) {
426     result += std::get<0>(field.GetFieldSizeInformation());
427   }
428   return result;
429 }
430 
ClassifyContents() const431 StructType::Classification StructType::ClassifyContents() const {
432   Classification result = ClassificationFlag::kEmpty;
433   for (const Field& struct_field : fields()) {
434     const Type* field_type = struct_field.name_and_type.type;
435     if (field_type->IsSubtypeOf(TypeOracle::GetStrongTaggedType())) {
436       result |= ClassificationFlag::kStrongTagged;
437     } else if (field_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
438       result |= ClassificationFlag::kWeakTagged;
439     } else if (auto field_as_struct = field_type->StructSupertype()) {
440       result |= (*field_as_struct)->ClassifyContents();
441     } else {
442       result |= ClassificationFlag::kUntagged;
443     }
444   }
445   return result;
446 }
447 
448 // static
ComputeName(const std::string & basename,MaybeSpecializationKey specialized_from)449 std::string Type::ComputeName(const std::string& basename,
450                               MaybeSpecializationKey specialized_from) {
451   if (!specialized_from) return basename;
452   if (specialized_from->generic == TypeOracle::GetConstReferenceGeneric()) {
453     return torque::ToString("const &", *specialized_from->specialized_types[0]);
454   }
455   if (specialized_from->generic == TypeOracle::GetMutableReferenceGeneric()) {
456     return torque::ToString("&", *specialized_from->specialized_types[0]);
457   }
458   std::stringstream s;
459   s << basename << "<";
460   bool first = true;
461   for (auto t : specialized_from->specialized_types) {
462     if (!first) {
463       s << ", ";
464     }
465     s << t->ToString();
466     first = false;
467   }
468   s << ">";
469   return s.str();
470 }
471 
SimpleNameImpl() const472 std::string StructType::SimpleNameImpl() const { return decl_->name->value; }
473 
474 // static
MatchUnaryGeneric(const Type * type,GenericType * generic)475 base::Optional<const Type*> Type::MatchUnaryGeneric(const Type* type,
476                                                     GenericType* generic) {
477   DCHECK_EQ(generic->generic_parameters().size(), 1);
478   if (!type->GetSpecializedFrom()) {
479     return base::nullopt;
480   }
481   auto& key = type->GetSpecializedFrom().value();
482   if (key.generic != generic || key.specialized_types.size() != 1) {
483     return base::nullopt;
484   }
485   return {key.specialized_types[0]};
486 }
487 
Methods(const std::string & name) const488 std::vector<Method*> AggregateType::Methods(const std::string& name) const {
489   if (!is_finalized_) Finalize();
490   std::vector<Method*> result;
491   std::copy_if(methods_.begin(), methods_.end(), std::back_inserter(result),
492                [name](Macro* macro) { return macro->ReadableName() == name; });
493   if (result.empty() && parent() != nullptr) {
494     if (auto aggregate_parent = parent()->AggregateSupertype()) {
495       return (*aggregate_parent)->Methods(name);
496     }
497   }
498   return result;
499 }
500 
ToExplicitString() const501 std::string StructType::ToExplicitString() const { return "struct " + name(); }
502 
Finalize() const503 void StructType::Finalize() const {
504   if (is_finalized_) return;
505   {
506     CurrentScope::Scope scope_activator(nspace());
507     CurrentSourcePosition::Scope position_activator(decl_->pos);
508     TypeVisitor::VisitStructMethods(const_cast<StructType*>(this), decl_);
509   }
510   is_finalized_ = true;
511   CheckForDuplicateFields();
512 }
513 
ClassType(const Type * parent,Namespace * nspace,const std::string & name,ClassFlags flags,const std::string & generates,const ClassDeclaration * decl,const TypeAlias * alias)514 ClassType::ClassType(const Type* parent, Namespace* nspace,
515                      const std::string& name, ClassFlags flags,
516                      const std::string& generates, const ClassDeclaration* decl,
517                      const TypeAlias* alias)
518     : AggregateType(Kind::kClassType, parent, nspace, name),
519       size_(ResidueClass::Unknown()),
520       flags_(flags),
521       generates_(generates),
522       decl_(decl),
523       alias_(alias) {}
524 
GetGeneratedTNodeTypeNameImpl() const525 std::string ClassType::GetGeneratedTNodeTypeNameImpl() const {
526   return generates_;
527 }
528 
GetGeneratedTypeNameImpl() const529 std::string ClassType::GetGeneratedTypeNameImpl() const {
530   return IsConstexpr() ? GetGeneratedTNodeTypeName()
531                        : "TNode<" + GetGeneratedTNodeTypeName() + ">";
532 }
533 
ToExplicitString() const534 std::string ClassType::ToExplicitString() const { return "class " + name(); }
535 
AllowInstantiation() const536 bool ClassType::AllowInstantiation() const {
537   return (!IsExtern() || nspace()->IsDefaultNamespace()) && !IsAbstract();
538 }
539 
Finalize() const540 void ClassType::Finalize() const {
541   if (is_finalized_) return;
542   CurrentScope::Scope scope_activator(alias_->ParentScope());
543   CurrentSourcePosition::Scope position_activator(decl_->pos);
544   TypeVisitor::VisitClassFieldsAndMethods(const_cast<ClassType*>(this),
545                                           this->decl_);
546   is_finalized_ = true;
547   CheckForDuplicateFields();
548 }
549 
ComputeAllFields() const550 std::vector<Field> ClassType::ComputeAllFields() const {
551   std::vector<Field> all_fields;
552   const ClassType* super_class = this->GetSuperClass();
553   if (super_class) {
554     all_fields = super_class->ComputeAllFields();
555   }
556   const std::vector<Field>& fields = this->fields();
557   all_fields.insert(all_fields.end(), fields.begin(), fields.end());
558   return all_fields;
559 }
560 
ComputeHeaderFields() const561 std::vector<Field> ClassType::ComputeHeaderFields() const {
562   std::vector<Field> result;
563   for (Field& field : ComputeAllFields()) {
564     if (field.index) break;
565     DCHECK(*field.offset < header_size());
566     result.push_back(std::move(field));
567   }
568   return result;
569 }
570 
ComputeArrayFields() const571 std::vector<Field> ClassType::ComputeArrayFields() const {
572   std::vector<Field> result;
573   for (Field& field : ComputeAllFields()) {
574     if (!field.index) {
575       DCHECK(*field.offset < header_size());
576       continue;
577     }
578     result.push_back(std::move(field));
579   }
580   return result;
581 }
582 
InitializeInstanceTypes(base::Optional<int> own,base::Optional<std::pair<int,int>> range) const583 void ClassType::InitializeInstanceTypes(
584     base::Optional<int> own, base::Optional<std::pair<int, int>> range) const {
585   DCHECK(!own_instance_type_.has_value());
586   DCHECK(!instance_type_range_.has_value());
587   own_instance_type_ = own;
588   instance_type_range_ = range;
589 }
590 
OwnInstanceType() const591 base::Optional<int> ClassType::OwnInstanceType() const {
592   DCHECK(GlobalContext::IsInstanceTypesInitialized());
593   return own_instance_type_;
594 }
595 
InstanceTypeRange() const596 base::Optional<std::pair<int, int>> ClassType::InstanceTypeRange() const {
597   DCHECK(GlobalContext::IsInstanceTypesInitialized());
598   return instance_type_range_;
599 }
600 
601 namespace {
ComputeSlotKindsHelper(std::vector<ObjectSlotKind> * slots,size_t start_offset,const std::vector<Field> & fields)602 void ComputeSlotKindsHelper(std::vector<ObjectSlotKind>* slots,
603                             size_t start_offset,
604                             const std::vector<Field>& fields) {
605   size_t offset = start_offset;
606   for (const Field& field : fields) {
607     size_t field_size = std::get<0>(field.GetFieldSizeInformation());
608     size_t slot_index = offset / TargetArchitecture::TaggedSize();
609     // Rounding-up division to find the number of slots occupied by all the
610     // fields up to and including the current one.
611     size_t used_slots =
612         (offset + field_size + TargetArchitecture::TaggedSize() - 1) /
613         TargetArchitecture::TaggedSize();
614     while (used_slots > slots->size()) {
615       slots->push_back(ObjectSlotKind::kNoPointer);
616     }
617     const Type* type = field.name_and_type.type;
618     if (auto struct_type = type->StructSupertype()) {
619       ComputeSlotKindsHelper(slots, offset, (*struct_type)->fields());
620     } else {
621       ObjectSlotKind kind;
622       if (type->IsSubtypeOf(TypeOracle::GetObjectType())) {
623         if (field.custom_weak_marking) {
624           kind = ObjectSlotKind::kCustomWeakPointer;
625         } else {
626           kind = ObjectSlotKind::kStrongPointer;
627         }
628       } else if (type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
629         DCHECK(!field.custom_weak_marking);
630         kind = ObjectSlotKind::kMaybeObjectPointer;
631       } else {
632         kind = ObjectSlotKind::kNoPointer;
633       }
634       DCHECK(slots->at(slot_index) == ObjectSlotKind::kNoPointer);
635       slots->at(slot_index) = kind;
636     }
637 
638     offset += field_size;
639   }
640 }
641 }  // namespace
642 
ComputeHeaderSlotKinds() const643 std::vector<ObjectSlotKind> ClassType::ComputeHeaderSlotKinds() const {
644   std::vector<ObjectSlotKind> result;
645   std::vector<Field> header_fields = ComputeHeaderFields();
646   ComputeSlotKindsHelper(&result, 0, header_fields);
647   DCHECK_EQ(std::ceil(static_cast<double>(header_size()) /
648                       TargetArchitecture::TaggedSize()),
649             result.size());
650   return result;
651 }
652 
ComputeArraySlotKind() const653 base::Optional<ObjectSlotKind> ClassType::ComputeArraySlotKind() const {
654   std::vector<ObjectSlotKind> kinds;
655   ComputeSlotKindsHelper(&kinds, 0, ComputeArrayFields());
656   if (kinds.empty()) return base::nullopt;
657   std::sort(kinds.begin(), kinds.end());
658   if (kinds.front() == kinds.back()) return {kinds.front()};
659   if (kinds.front() == ObjectSlotKind::kStrongPointer &&
660       kinds.back() == ObjectSlotKind::kMaybeObjectPointer) {
661     return ObjectSlotKind::kMaybeObjectPointer;
662   }
663   Error("Array fields mix types with different GC visitation requirements.")
664       .Throw();
665 }
666 
HasNoPointerSlots() const667 bool ClassType::HasNoPointerSlots() const {
668   for (ObjectSlotKind slot : ComputeHeaderSlotKinds()) {
669     if (slot != ObjectSlotKind::kNoPointer) return false;
670   }
671   if (auto slot = ComputeArraySlotKind()) {
672     if (*slot != ObjectSlotKind::kNoPointer) return false;
673   }
674   return true;
675 }
676 
HasIndexedFieldsIncludingInParents() const677 bool ClassType::HasIndexedFieldsIncludingInParents() const {
678   for (const auto& field : fields_) {
679     if (field.index.has_value()) return true;
680   }
681   if (const ClassType* parent = GetSuperClass()) {
682     return parent->HasIndexedFieldsIncludingInParents();
683   }
684   return false;
685 }
686 
GetFieldPreceding(size_t field_index) const687 const Field* ClassType::GetFieldPreceding(size_t field_index) const {
688   if (field_index > 0) {
689     return &fields_[field_index - 1];
690   }
691   if (const ClassType* parent = GetSuperClass()) {
692     return parent->GetFieldPreceding(parent->fields_.size());
693   }
694   return nullptr;
695 }
696 
GetClassDeclaringField(const Field & f) const697 const ClassType* ClassType::GetClassDeclaringField(const Field& f) const {
698   for (const Field& field : fields_) {
699     if (f.name_and_type.name == field.name_and_type.name) return this;
700   }
701   return GetSuperClass()->GetClassDeclaringField(f);
702 }
703 
GetSliceMacroName(const Field & field) const704 std::string ClassType::GetSliceMacroName(const Field& field) const {
705   const ClassType* declarer = GetClassDeclaringField(field);
706   return "FieldSlice" + declarer->name() +
707          CamelifyString(field.name_and_type.name);
708 }
709 
GenerateAccessors()710 void ClassType::GenerateAccessors() {
711   bool at_or_after_indexed_field = false;
712   if (const ClassType* parent = GetSuperClass()) {
713     at_or_after_indexed_field = parent->HasIndexedFieldsIncludingInParents();
714   }
715   // For each field, construct AST snippets that implement a CSA accessor
716   // function. The implementation iterator will turn the snippets into code.
717   for (size_t field_index = 0; field_index < fields_.size(); ++field_index) {
718     Field& field = fields_[field_index];
719     if (field.name_and_type.type == TypeOracle::GetVoidType()) {
720       continue;
721     }
722     at_or_after_indexed_field =
723         at_or_after_indexed_field || field.index.has_value();
724     CurrentSourcePosition::Scope position_activator(field.pos);
725 
726     IdentifierExpression* parameter = MakeIdentifierExpression("o");
727     IdentifierExpression* index = MakeIdentifierExpression("i");
728 
729     std::string camel_field_name = CamelifyString(field.name_and_type.name);
730 
731     if (at_or_after_indexed_field) {
732       if (!field.index.has_value()) {
733         // There's no fundamental reason we couldn't generate functions to get
734         // references instead of slices, but it's not yet implemented.
735         ReportError(
736             "Torque doesn't yet support non-indexed fields after indexed "
737             "fields");
738       }
739 
740       GenerateSliceAccessor(field_index);
741     }
742 
743     // For now, only generate indexed accessors for simple types
744     if (field.index.has_value() && field.name_and_type.type->IsStructType()) {
745       continue;
746     }
747 
748     // An explicit index is only used for indexed fields not marked as optional.
749     // Optional fields implicitly load or store item zero.
750     bool use_index = field.index && !field.index->optional;
751 
752     // Load accessor
753     std::string load_macro_name = "Load" + this->name() + camel_field_name;
754     Signature load_signature;
755     load_signature.parameter_names.push_back(MakeNode<Identifier>("o"));
756     load_signature.parameter_types.types.push_back(this);
757     if (use_index) {
758       load_signature.parameter_names.push_back(MakeNode<Identifier>("i"));
759       load_signature.parameter_types.types.push_back(
760           TypeOracle::GetIntPtrType());
761     }
762     load_signature.parameter_types.var_args = false;
763     load_signature.return_type = field.name_and_type.type;
764 
765     Expression* load_expression =
766         MakeFieldAccessExpression(parameter, field.name_and_type.name);
767     if (use_index) {
768       load_expression =
769           MakeNode<ElementAccessExpression>(load_expression, index);
770     }
771     Statement* load_body = MakeNode<ReturnStatement>(load_expression);
772     Declarations::DeclareMacro(load_macro_name, true, base::nullopt,
773                                load_signature, load_body, base::nullopt);
774 
775     // Store accessor
776     if (!field.const_qualified) {
777       IdentifierExpression* value = MakeIdentifierExpression("v");
778       std::string store_macro_name = "Store" + this->name() + camel_field_name;
779       Signature store_signature;
780       store_signature.parameter_names.push_back(MakeNode<Identifier>("o"));
781       store_signature.parameter_types.types.push_back(this);
782       if (use_index) {
783         store_signature.parameter_names.push_back(MakeNode<Identifier>("i"));
784         store_signature.parameter_types.types.push_back(
785             TypeOracle::GetIntPtrType());
786       }
787       store_signature.parameter_names.push_back(MakeNode<Identifier>("v"));
788       store_signature.parameter_types.types.push_back(field.name_and_type.type);
789       store_signature.parameter_types.var_args = false;
790       // TODO(danno): Store macros probably should return their value argument
791       store_signature.return_type = TypeOracle::GetVoidType();
792       Expression* store_expression =
793           MakeFieldAccessExpression(parameter, field.name_and_type.name);
794       if (use_index) {
795         store_expression =
796             MakeNode<ElementAccessExpression>(store_expression, index);
797       }
798       Statement* store_body = MakeNode<ExpressionStatement>(
799           MakeNode<AssignmentExpression>(store_expression, value));
800       Declarations::DeclareMacro(store_macro_name, true, base::nullopt,
801                                  store_signature, store_body, base::nullopt,
802                                  false);
803     }
804   }
805 }
806 
GenerateSliceAccessor(size_t field_index)807 void ClassType::GenerateSliceAccessor(size_t field_index) {
808   // Generate a Torque macro for getting a Slice to this field. This macro can
809   // be called by the dot operator for this field. In Torque, this function for
810   // class "ClassName" and field "field_name" and field type "FieldType" would
811   // be written as one of the following:
812   //
813   // If the field has a known offset (in this example, 16):
814   // FieldSliceClassNameFieldName(o: ClassName) {
815   //   return torque_internal::unsafe::New{Const,Mutable}Slice<FieldType>(
816   //     /*object:*/ o,
817   //     /*offset:*/ 16,
818   //     /*length:*/ torque_internal::%IndexedFieldLength<ClassName>(
819   //                     o, "field_name")
820   //   );
821   // }
822   //
823   // If the field has an unknown offset, and the previous field is named p, is
824   // not const, and is of type PType with size 4:
825   // FieldSliceClassNameFieldName(o: ClassName) {
826   //   const previous = %FieldSlice<ClassName, MutableSlice<PType>>(o, "p");
827   //   return torque_internal::unsafe::New{Const,Mutable}Slice<FieldType>(
828   //     /*object:*/ o,
829   //     /*offset:*/ previous.offset + 4 * previous.length,
830   //     /*length:*/ torque_internal::%IndexedFieldLength<ClassName>(
831   //                     o, "field_name")
832   //   );
833   // }
834   const Field& field = fields_[field_index];
835   std::string macro_name = GetSliceMacroName(field);
836   Signature signature;
837   Identifier* parameter_identifier = MakeNode<Identifier>("o");
838   signature.parameter_names.push_back(parameter_identifier);
839   signature.parameter_types.types.push_back(this);
840   signature.parameter_types.var_args = false;
841   signature.return_type =
842       field.const_qualified
843           ? TypeOracle::GetConstSliceType(field.name_and_type.type)
844           : TypeOracle::GetMutableSliceType(field.name_and_type.type);
845 
846   std::vector<Statement*> statements;
847   Expression* offset_expression = nullptr;
848   IdentifierExpression* parameter =
849       MakeNode<IdentifierExpression>(parameter_identifier);
850 
851   if (field.offset.has_value()) {
852     offset_expression =
853         MakeNode<IntegerLiteralExpression>(IntegerLiteral(*field.offset));
854   } else {
855     const Field* previous = GetFieldPreceding(field_index);
856     DCHECK_NOT_NULL(previous);
857 
858     const Type* previous_slice_type =
859         previous->const_qualified
860             ? TypeOracle::GetConstSliceType(previous->name_and_type.type)
861             : TypeOracle::GetMutableSliceType(previous->name_and_type.type);
862 
863     // %FieldSlice<ClassName, MutableSlice<PType>>(o, "p")
864     Expression* previous_expression = MakeCallExpression(
865         MakeIdentifierExpression(
866             {"torque_internal"}, "%FieldSlice",
867             {MakeNode<PrecomputedTypeExpression>(this),
868              MakeNode<PrecomputedTypeExpression>(previous_slice_type)}),
869         {parameter, MakeNode<StringLiteralExpression>(
870                         StringLiteralQuote(previous->name_and_type.name))});
871 
872     // const previous = %FieldSlice<ClassName, MutableSlice<PType>>(o, "p");
873     Statement* define_previous =
874         MakeConstDeclarationStatement("previous", previous_expression);
875     statements.push_back(define_previous);
876 
877     // 4
878     size_t previous_element_size;
879     std::tie(previous_element_size, std::ignore) =
880         *SizeOf(previous->name_and_type.type);
881     Expression* previous_element_size_expression =
882         MakeNode<IntegerLiteralExpression>(
883             IntegerLiteral(previous_element_size));
884 
885     // previous.length
886     Expression* previous_length_expression = MakeFieldAccessExpression(
887         MakeIdentifierExpression("previous"), "length");
888 
889     // previous.offset
890     Expression* previous_offset_expression = MakeFieldAccessExpression(
891         MakeIdentifierExpression("previous"), "offset");
892 
893     // 4 * previous.length
894     // In contrast to the code used for allocation, we don't need overflow
895     // checks here because we already know all the offsets fit into memory.
896     offset_expression = MakeCallExpression(
897         "*", {previous_element_size_expression, previous_length_expression});
898 
899     // previous.offset + 4 * previous.length
900     offset_expression = MakeCallExpression(
901         "+", {previous_offset_expression, offset_expression});
902   }
903 
904   // torque_internal::%IndexedFieldLength<ClassName>(o, "field_name")
905   Expression* length_expression = MakeCallExpression(
906       MakeIdentifierExpression({"torque_internal"}, "%IndexedFieldLength",
907                                {MakeNode<PrecomputedTypeExpression>(this)}),
908       {parameter, MakeNode<StringLiteralExpression>(
909                       StringLiteralQuote(field.name_and_type.name))});
910 
911   // torque_internal::unsafe::New{Const,Mutable}Slice<FieldType>(
912   //   /*object:*/ o,
913   //   /*offset:*/ <<offset_expression>>,
914   //   /*length:*/ torque_internal::%IndexedFieldLength<ClassName>(
915   //                   o, "field_name")
916   // )
917   IdentifierExpression* new_struct = MakeIdentifierExpression(
918       {"torque_internal", "unsafe"},
919       field.const_qualified ? "NewConstSlice" : "NewMutableSlice",
920       {MakeNode<PrecomputedTypeExpression>(field.name_and_type.type)});
921   Expression* slice_expression = MakeCallExpression(
922       new_struct, {parameter, offset_expression, length_expression});
923 
924   statements.push_back(MakeNode<ReturnStatement>(slice_expression));
925   Statement* block =
926       MakeNode<BlockStatement>(/*deferred=*/false, std::move(statements));
927 
928   Macro* macro = Declarations::DeclareMacro(macro_name, true, base::nullopt,
929                                             signature, block, base::nullopt);
930   GlobalContext::EnsureInCCOutputList(TorqueMacro::cast(macro),
931                                       macro->Position().source);
932 }
933 
HasStaticSize() const934 bool ClassType::HasStaticSize() const {
935   if (IsSubtypeOf(TypeOracle::GetJSObjectType()) && !IsShape()) return false;
936   return size().SingleValue().has_value();
937 }
938 
AttributedToFile() const939 SourceId ClassType::AttributedToFile() const {
940   bool in_test_directory = StringStartsWith(
941       SourceFileMap::PathFromV8Root(GetPosition().source).substr(), "test/");
942   if (!in_test_directory && (IsExtern() || ShouldExport())) {
943     return GetPosition().source;
944   }
945   return SourceFileMap::GetSourceId("src/objects/torque-defined-classes.tq");
946 }
947 
PrintSignature(std::ostream & os,const Signature & sig,bool with_names)948 void PrintSignature(std::ostream& os, const Signature& sig, bool with_names) {
949   os << "(";
950   for (size_t i = 0; i < sig.parameter_types.types.size(); ++i) {
951     if (i == 0 && sig.implicit_count != 0) os << "implicit ";
952     if (sig.implicit_count > 0 && sig.implicit_count == i) {
953       os << ")(";
954     } else {
955       if (i > 0) os << ", ";
956     }
957     if (with_names && !sig.parameter_names.empty()) {
958       if (i < sig.parameter_names.size()) {
959         os << sig.parameter_names[i] << ": ";
960       }
961     }
962     os << *sig.parameter_types.types[i];
963   }
964   if (sig.parameter_types.var_args) {
965     if (sig.parameter_names.size()) os << ", ";
966     os << "...";
967   }
968   os << ")";
969   os << ": " << *sig.return_type;
970 
971   if (sig.labels.empty()) return;
972 
973   os << " labels ";
974   for (size_t i = 0; i < sig.labels.size(); ++i) {
975     if (i > 0) os << ", ";
976     os << sig.labels[i].name;
977     if (sig.labels[i].types.size() > 0) os << "(" << sig.labels[i].types << ")";
978   }
979 }
980 
operator <<(std::ostream & os,const NameAndType & name_and_type)981 std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type) {
982   os << name_and_type.name;
983   os << ": ";
984   os << *name_and_type.type;
985   return os;
986 }
987 
operator <<(std::ostream & os,const Field & field)988 std::ostream& operator<<(std::ostream& os, const Field& field) {
989   os << field.name_and_type;
990   if (field.custom_weak_marking) {
991     os << " (custom weak)";
992   }
993   return os;
994 }
995 
operator <<(std::ostream & os,const Signature & sig)996 std::ostream& operator<<(std::ostream& os, const Signature& sig) {
997   PrintSignature(os, sig, true);
998   return os;
999 }
1000 
operator <<(std::ostream & os,const TypeVector & types)1001 std::ostream& operator<<(std::ostream& os, const TypeVector& types) {
1002   PrintCommaSeparatedList(os, types);
1003   return os;
1004 }
1005 
operator <<(std::ostream & os,const ParameterTypes & p)1006 std::ostream& operator<<(std::ostream& os, const ParameterTypes& p) {
1007   PrintCommaSeparatedList(os, p.types);
1008   if (p.var_args) {
1009     if (p.types.size() > 0) os << ", ";
1010     os << "...";
1011   }
1012   return os;
1013 }
1014 
HasSameTypesAs(const Signature & other,ParameterMode mode) const1015 bool Signature::HasSameTypesAs(const Signature& other,
1016                                ParameterMode mode) const {
1017   auto compare_types = types();
1018   auto other_compare_types = other.types();
1019   if (mode == ParameterMode::kIgnoreImplicit) {
1020     compare_types = GetExplicitTypes();
1021     other_compare_types = other.GetExplicitTypes();
1022   }
1023   if (!(compare_types == other_compare_types &&
1024         parameter_types.var_args == other.parameter_types.var_args &&
1025         return_type == other.return_type)) {
1026     return false;
1027   }
1028   if (labels.size() != other.labels.size()) {
1029     return false;
1030   }
1031   size_t i = 0;
1032   for (const auto& l : labels) {
1033     if (l.types != other.labels[i++].types) {
1034       return false;
1035     }
1036   }
1037   return true;
1038 }
1039 
1040 namespace {
FirstTypeIsContext(const std::vector<const Type * > parameter_types)1041 bool FirstTypeIsContext(const std::vector<const Type*> parameter_types) {
1042   return !parameter_types.empty() &&
1043          parameter_types[0] == TypeOracle::GetContextType();
1044 }
1045 }  // namespace
1046 
HasContextParameter() const1047 bool Signature::HasContextParameter() const {
1048   return FirstTypeIsContext(types());
1049 }
1050 
HasContextParameter() const1051 bool BuiltinPointerType::HasContextParameter() const {
1052   return FirstTypeIsContext(parameter_types());
1053 }
1054 
IsAssignableFrom(const Type * to,const Type * from)1055 bool IsAssignableFrom(const Type* to, const Type* from) {
1056   if (to == from) return true;
1057   if (from->IsSubtypeOf(to)) return true;
1058   return TypeOracle::ImplicitlyConvertableFrom(to, from).has_value();
1059 }
1060 
operator <(const Type & a,const Type & b)1061 bool operator<(const Type& a, const Type& b) { return a.id() < b.id(); }
1062 
ProjectStructField(VisitResult structure,const std::string & fieldname)1063 VisitResult ProjectStructField(VisitResult structure,
1064                                const std::string& fieldname) {
1065   BottomOffset begin = structure.stack_range().begin();
1066 
1067   // Check constructor this super classes for fields.
1068   const StructType* type = *structure.type()->StructSupertype();
1069   auto& fields = type->fields();
1070   for (auto& field : fields) {
1071     BottomOffset end = begin + LoweredSlotCount(field.name_and_type.type);
1072     if (field.name_and_type.name == fieldname) {
1073       return VisitResult(field.name_and_type.type, StackRange{begin, end});
1074     }
1075     begin = end;
1076   }
1077 
1078   ReportError("struct '", type->name(), "' doesn't contain a field '",
1079               fieldname, "'");
1080 }
1081 
1082 namespace {
AppendLoweredTypes(const Type * type,std::vector<const Type * > * result)1083 void AppendLoweredTypes(const Type* type, std::vector<const Type*>* result) {
1084   DCHECK_NE(type, TypeOracle::GetNeverType());
1085   if (type->IsConstexpr()) return;
1086   if (type == TypeOracle::GetVoidType()) return;
1087   if (base::Optional<const StructType*> s = type->StructSupertype()) {
1088     for (const Field& field : (*s)->fields()) {
1089       AppendLoweredTypes(field.name_and_type.type, result);
1090     }
1091   } else {
1092     result->push_back(type);
1093   }
1094 }
1095 }  // namespace
1096 
LowerType(const Type * type)1097 TypeVector LowerType(const Type* type) {
1098   TypeVector result;
1099   AppendLoweredTypes(type, &result);
1100   return result;
1101 }
1102 
LoweredSlotCount(const Type * type)1103 size_t LoweredSlotCount(const Type* type) { return LowerType(type).size(); }
1104 
LowerParameterTypes(const TypeVector & parameters)1105 TypeVector LowerParameterTypes(const TypeVector& parameters) {
1106   std::vector<const Type*> result;
1107   for (const Type* t : parameters) {
1108     AppendLoweredTypes(t, &result);
1109   }
1110   return result;
1111 }
1112 
LowerParameterTypes(const ParameterTypes & parameter_types,size_t arg_count)1113 TypeVector LowerParameterTypes(const ParameterTypes& parameter_types,
1114                                size_t arg_count) {
1115   std::vector<const Type*> result = LowerParameterTypes(parameter_types.types);
1116   for (size_t i = parameter_types.types.size(); i < arg_count; ++i) {
1117     DCHECK(parameter_types.var_args);
1118     AppendLoweredTypes(TypeOracle::GetObjectType(), &result);
1119   }
1120   return result;
1121 }
1122 
NeverResult()1123 VisitResult VisitResult::NeverResult() {
1124   VisitResult result;
1125   result.type_ = TypeOracle::GetNeverType();
1126   return result;
1127 }
1128 
TopTypeResult(std::string top_reason,const Type * from_type)1129 VisitResult VisitResult::TopTypeResult(std::string top_reason,
1130                                        const Type* from_type) {
1131   VisitResult result;
1132   result.type_ = TypeOracle::GetTopType(std::move(top_reason), from_type);
1133   return result;
1134 }
1135 
GetFieldSizeInformation() const1136 std::tuple<size_t, std::string> Field::GetFieldSizeInformation() const {
1137   auto optional = SizeOf(this->name_and_type.type);
1138   if (optional.has_value()) {
1139     return *optional;
1140   }
1141   Error("fields of type ", *name_and_type.type, " are not (yet) supported")
1142       .Position(pos)
1143       .Throw();
1144 }
1145 
AlignmentLog2() const1146 size_t Type::AlignmentLog2() const {
1147   if (parent()) return parent()->AlignmentLog2();
1148   return TargetArchitecture::TaggedSize();
1149 }
1150 
AlignmentLog2() const1151 size_t AbstractType::AlignmentLog2() const {
1152   size_t alignment;
1153   if (this == TypeOracle::GetTaggedType()) {
1154     alignment = TargetArchitecture::TaggedSize();
1155   } else if (this == TypeOracle::GetRawPtrType()) {
1156     alignment = TargetArchitecture::RawPtrSize();
1157   } else if (this == TypeOracle::GetExternalPointerType()) {
1158     alignment = TargetArchitecture::ExternalPointerSize();
1159   } else if (this == TypeOracle::GetVoidType()) {
1160     alignment = 1;
1161   } else if (this == TypeOracle::GetInt8Type()) {
1162     alignment = kUInt8Size;
1163   } else if (this == TypeOracle::GetUint8Type()) {
1164     alignment = kUInt8Size;
1165   } else if (this == TypeOracle::GetInt16Type()) {
1166     alignment = kUInt16Size;
1167   } else if (this == TypeOracle::GetUint16Type()) {
1168     alignment = kUInt16Size;
1169   } else if (this == TypeOracle::GetInt32Type()) {
1170     alignment = kInt32Size;
1171   } else if (this == TypeOracle::GetUint32Type()) {
1172     alignment = kInt32Size;
1173   } else if (this == TypeOracle::GetFloat64Type()) {
1174     alignment = kDoubleSize;
1175   } else if (this == TypeOracle::GetIntPtrType()) {
1176     alignment = TargetArchitecture::RawPtrSize();
1177   } else if (this == TypeOracle::GetUIntPtrType()) {
1178     alignment = TargetArchitecture::RawPtrSize();
1179   } else {
1180     return Type::AlignmentLog2();
1181   }
1182   alignment = std::min(alignment, TargetArchitecture::TaggedSize());
1183   return base::bits::WhichPowerOfTwo(alignment);
1184 }
1185 
AlignmentLog2() const1186 size_t StructType::AlignmentLog2() const {
1187   if (this == TypeOracle::GetFloat64OrHoleType()) {
1188     return TypeOracle::GetFloat64Type()->AlignmentLog2();
1189   }
1190   size_t alignment_log_2 = 0;
1191   for (const Field& field : fields()) {
1192     alignment_log_2 =
1193         std::max(alignment_log_2, field.name_and_type.type->AlignmentLog2());
1194   }
1195   return alignment_log_2;
1196 }
1197 
ValidateAlignment(ResidueClass at_offset) const1198 void Field::ValidateAlignment(ResidueClass at_offset) const {
1199   const Type* type = name_and_type.type;
1200   base::Optional<const StructType*> struct_type = type->StructSupertype();
1201   if (struct_type && struct_type != TypeOracle::GetFloat64OrHoleType()) {
1202     for (const Field& field : (*struct_type)->fields()) {
1203       field.ValidateAlignment(at_offset);
1204       size_t field_size = std::get<0>(field.GetFieldSizeInformation());
1205       at_offset += field_size;
1206     }
1207   } else {
1208     size_t alignment_log_2 = name_and_type.type->AlignmentLog2();
1209     if (at_offset.AlignmentLog2() < alignment_log_2) {
1210       Error("field ", name_and_type.name, " at offset ", at_offset, " is not ",
1211             size_t{1} << alignment_log_2, "-byte aligned.")
1212           .Position(pos);
1213     }
1214   }
1215 }
1216 
SizeOf(const Type * type)1217 base::Optional<std::tuple<size_t, std::string>> SizeOf(const Type* type) {
1218   std::string size_string;
1219   size_t size;
1220   if (type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
1221     size = TargetArchitecture::TaggedSize();
1222     size_string = "kTaggedSize";
1223   } else if (type->IsSubtypeOf(TypeOracle::GetRawPtrType())) {
1224     size = TargetArchitecture::RawPtrSize();
1225     size_string = "kSystemPointerSize";
1226   } else if (type->IsSubtypeOf(TypeOracle::GetExternalPointerType())) {
1227     size = TargetArchitecture::ExternalPointerSize();
1228     size_string = "kExternalPointerSize";
1229   } else if (type->IsSubtypeOf(TypeOracle::GetVoidType())) {
1230     size = 0;
1231     size_string = "0";
1232   } else if (type->IsSubtypeOf(TypeOracle::GetInt8Type())) {
1233     size = kUInt8Size;
1234     size_string = "kUInt8Size";
1235   } else if (type->IsSubtypeOf(TypeOracle::GetUint8Type())) {
1236     size = kUInt8Size;
1237     size_string = "kUInt8Size";
1238   } else if (type->IsSubtypeOf(TypeOracle::GetInt16Type())) {
1239     size = kUInt16Size;
1240     size_string = "kUInt16Size";
1241   } else if (type->IsSubtypeOf(TypeOracle::GetUint16Type())) {
1242     size = kUInt16Size;
1243     size_string = "kUInt16Size";
1244   } else if (type->IsSubtypeOf(TypeOracle::GetInt32Type())) {
1245     size = kInt32Size;
1246     size_string = "kInt32Size";
1247   } else if (type->IsSubtypeOf(TypeOracle::GetUint32Type())) {
1248     size = kInt32Size;
1249     size_string = "kInt32Size";
1250   } else if (type->IsSubtypeOf(TypeOracle::GetFloat64Type())) {
1251     size = kDoubleSize;
1252     size_string = "kDoubleSize";
1253   } else if (type->IsSubtypeOf(TypeOracle::GetIntPtrType())) {
1254     size = TargetArchitecture::RawPtrSize();
1255     size_string = "kIntptrSize";
1256   } else if (type->IsSubtypeOf(TypeOracle::GetUIntPtrType())) {
1257     size = TargetArchitecture::RawPtrSize();
1258     size_string = "kIntptrSize";
1259   } else if (auto struct_type = type->StructSupertype()) {
1260     if (type == TypeOracle::GetFloat64OrHoleType()) {
1261       size = kDoubleSize;
1262       size_string = "kDoubleSize";
1263     } else {
1264       size = (*struct_type)->PackedSize();
1265       size_string = std::to_string(size);
1266     }
1267   } else {
1268     return {};
1269   }
1270   return std::make_tuple(size, size_string);
1271 }
1272 
IsAnyUnsignedInteger(const Type * type)1273 bool IsAnyUnsignedInteger(const Type* type) {
1274   return type == TypeOracle::GetUint32Type() ||
1275          type == TypeOracle::GetUint31Type() ||
1276          type == TypeOracle::GetUint16Type() ||
1277          type == TypeOracle::GetUint8Type() ||
1278          type == TypeOracle::GetUIntPtrType();
1279 }
1280 
IsAllowedAsBitField(const Type * type)1281 bool IsAllowedAsBitField(const Type* type) {
1282   if (type->IsBitFieldStructType()) {
1283     // No nested bitfield structs for now. We could reconsider if there's a
1284     // compelling use case.
1285     return false;
1286   }
1287   // Any integer-ish type, including bools and enums which inherit from integer
1288   // types, are allowed. Note, however, that we always zero-extend during
1289   // decoding regardless of signedness.
1290   return IsPointerSizeIntegralType(type) || Is32BitIntegralType(type);
1291 }
1292 
IsPointerSizeIntegralType(const Type * type)1293 bool IsPointerSizeIntegralType(const Type* type) {
1294   return type->IsSubtypeOf(TypeOracle::GetUIntPtrType()) ||
1295          type->IsSubtypeOf(TypeOracle::GetIntPtrType());
1296 }
1297 
Is32BitIntegralType(const Type * type)1298 bool Is32BitIntegralType(const Type* type) {
1299   return type->IsSubtypeOf(TypeOracle::GetUint32Type()) ||
1300          type->IsSubtypeOf(TypeOracle::GetInt32Type()) ||
1301          type->IsSubtypeOf(TypeOracle::GetBoolType());
1302 }
1303 
ExtractSimpleFieldArraySize(const ClassType & class_type,Expression * array_size)1304 base::Optional<NameAndType> ExtractSimpleFieldArraySize(
1305     const ClassType& class_type, Expression* array_size) {
1306   IdentifierExpression* identifier =
1307       IdentifierExpression::DynamicCast(array_size);
1308   if (!identifier || !identifier->generic_arguments.empty() ||
1309       !identifier->namespace_qualification.empty())
1310     return {};
1311   if (!class_type.HasField(identifier->name->value)) return {};
1312   return class_type.LookupField(identifier->name->value).name_and_type;
1313 }
1314 
GetRuntimeType() const1315 std::string Type::GetRuntimeType() const {
1316   if (IsSubtypeOf(TypeOracle::GetSmiType())) return "Smi";
1317   if (IsSubtypeOf(TypeOracle::GetTaggedType())) {
1318     return GetGeneratedTNodeTypeName();
1319   }
1320   if (base::Optional<const StructType*> struct_type = StructSupertype()) {
1321     std::stringstream result;
1322     result << "std::tuple<";
1323     bool first = true;
1324     for (const Type* field_type : LowerType(*struct_type)) {
1325       if (!first) result << ", ";
1326       first = false;
1327       result << field_type->GetRuntimeType();
1328     }
1329     result << ">";
1330     return result.str();
1331   }
1332   return ConstexprVersion()->GetGeneratedTypeName();
1333 }
1334 
GetDebugType() const1335 std::string Type::GetDebugType() const {
1336   if (IsSubtypeOf(TypeOracle::GetSmiType())) return "uintptr_t";
1337   if (IsSubtypeOf(TypeOracle::GetTaggedType())) {
1338     return "uintptr_t";
1339   }
1340   if (base::Optional<const StructType*> struct_type = StructSupertype()) {
1341     std::stringstream result;
1342     result << "std::tuple<";
1343     bool first = true;
1344     for (const Type* field_type : LowerType(*struct_type)) {
1345       if (!first) result << ", ";
1346       first = false;
1347       result << field_type->GetDebugType();
1348     }
1349     result << ">";
1350     return result.str();
1351   }
1352   return ConstexprVersion()->GetGeneratedTypeName();
1353 }
1354 
1355 }  // namespace torque
1356 }  // namespace internal
1357 }  // namespace v8
1358