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