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