• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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/implementation-visitor.h"
6 
7 namespace v8 {
8 namespace internal {
9 namespace torque {
10 
11 namespace {
12 
13 // Contains all necessary state for a single class type during the process of
14 // assigning instance types, and provides a convenient way to access the list of
15 // types that inherit from this one.
16 struct InstanceTypeTree {
InstanceTypeTreev8::internal::torque::__anone292b3c20111::InstanceTypeTree17   explicit InstanceTypeTree(const ClassType* type)
18       : type(type),
19         start(INT_MAX),
20         end(INT_MIN),
21         value(-1),
22         num_values(0),
23         num_own_values(0) {}
24   const ClassType* type;
25   std::vector<std::unique_ptr<InstanceTypeTree>> children;
26   int start;  // Start of range for this and subclasses, or INT_MAX.
27   int end;    // End of range for this and subclasses, or INT_MIN.
28   int value;  // Assigned value for this class itself, or -1 when unassigned.
29   int num_values;      // Number of values assigned for this and subclasses.
30   int num_own_values;  // How many values this needs (not including subclasses).
31 };
32 
33 // Assembles all class types into a tree, but doesn't yet attempt to assign
34 // instance types for them.
BuildInstanceTypeTree()35 std::unique_ptr<InstanceTypeTree> BuildInstanceTypeTree() {
36   // First, build InstanceTypeTree instances for every class but don't try to
37   // attach them to their subclasses yet.
38   std::unordered_map<const ClassType*, InstanceTypeTree*> map_by_type;
39   std::vector<std::unique_ptr<InstanceTypeTree>> unparented_types;
40   for (auto& p : GlobalContext::AllDeclarables()) {
41     if (const TypeAlias* alias = TypeAlias::DynamicCast(p.get())) {
42       const Type* type = alias->type();
43       const ClassType* class_type = ClassType::DynamicCast(type);
44       if (class_type == nullptr) {
45         continue;
46       }
47       auto& map_slot = map_by_type[class_type];
48       if (map_slot != nullptr) {
49         continue;  // We already encountered this type.
50       }
51       std::unique_ptr<InstanceTypeTree> type_tree =
52           std::make_unique<InstanceTypeTree>(class_type);
53       map_slot = type_tree.get();
54       unparented_types.push_back(std::move(type_tree));
55     }
56   }
57 
58   // Second, assemble them all into a tree following the inheritance hierarchy.
59   std::unique_ptr<InstanceTypeTree> root;
60   for (auto& type_tree : unparented_types) {
61     const ClassType* parent = type_tree->type->GetSuperClass();
62     if (parent == nullptr) {
63       if (root != nullptr)
64         Error("Expected only one root class type. Found: ", root->type->name(),
65               " and ", type_tree->type->name())
66             .Position(type_tree->type->GetPosition());
67       root = std::move(type_tree);
68     } else {
69       map_by_type[parent]->children.push_back(std::move(type_tree));
70     }
71   }
72   return root;
73 }
74 
75 // Propagates constraints about instance types from children to their parents.
PropagateInstanceTypeConstraints(InstanceTypeTree * root)76 void PropagateInstanceTypeConstraints(InstanceTypeTree* root) {
77   for (auto& child : root->children) {
78     PropagateInstanceTypeConstraints(child.get());
79     if (child->start < root->start) root->start = child->start;
80     if (child->end > root->end) root->end = child->end;
81     root->num_values += child->num_values;
82   }
83   const InstanceTypeConstraints& constraints =
84       root->type->GetInstanceTypeConstraints();
85   if (!root->type->IsAbstract() && !root->type->HasSameInstanceTypeAsParent()) {
86     root->num_own_values = 1;
87   }
88   root->num_values += root->num_own_values;
89   if (constraints.num_flags_bits != -1) {
90     // Children won't get any types assigned; must be done manually in C++.
91     root->children.clear();
92     root->num_values = 1 << constraints.num_flags_bits;
93     root->num_own_values = root->num_values;
94     root->start = 0;
95     root->end = root->num_values - 1;
96   }
97   if (constraints.value != -1) {
98     if (root->num_own_values != 1) {
99       Error("Instance type value requested for abstract class ",
100             root->type->name())
101           .Position(root->type->GetPosition());
102     }
103     root->value = constraints.value;
104     if (constraints.value < root->start) root->start = constraints.value;
105     if (constraints.value > root->end) root->end = constraints.value;
106   }
107 }
108 
109 // Assigns values for the type itself, not including any children. Returns the
110 // next available value.
SelectOwnValues(InstanceTypeTree * root,int start_value)111 int SelectOwnValues(InstanceTypeTree* root, int start_value) {
112   if (root->value == -1) {
113     root->value = start_value;
114   } else if (root->value < start_value) {
115     Error("Failed to assign instance type ", root->value, " to ",
116           root->type->name())
117         .Position(root->type->GetPosition());
118   }
119   return root->value + root->num_own_values;
120 }
121 
122 // Sorting function for types that don't have specific values they must include.
123 // Prioritizes bigger type ranges (those with more subtypes) first, and
124 // then sorts alphabetically within each size category.
125 struct CompareUnconstrainedTypes {
operator ()v8::internal::torque::__anone292b3c20111::CompareUnconstrainedTypes126   constexpr bool operator()(const InstanceTypeTree* a,
127                             const InstanceTypeTree* b) const {
128     return (a->num_values > b->num_values)
129                ? true
130                : (a->num_values < b->num_values)
131                      ? false
132                      : std::less<std::string>()(a->type->name(),
133                                                 b->type->name());
134   }
135 };
136 
137 // Assigns concrete values for every instance type range, and sorts the children
138 // at each layer of the tree into increasing order. Appends the newly-assigned
139 // tree to the destination vector. Returns the first unassigned value after
140 // those that have been used.
SolveInstanceTypeConstraints(std::unique_ptr<InstanceTypeTree> root,int start_value,std::vector<std::unique_ptr<InstanceTypeTree>> * destination)141 int SolveInstanceTypeConstraints(
142     std::unique_ptr<InstanceTypeTree> root, int start_value,
143     std::vector<std::unique_ptr<InstanceTypeTree>>* destination) {
144   if (root->start < start_value) {
145     Error("Failed to assign instance type ", root->start, " to ",
146           root->type->name())
147         .Position(root->type->GetPosition());
148   }
149 
150   // First, separate the children into four groups:
151   // - The one child that must go first, if it exists;
152   // - Children with specific value requirements ("constrained");
153   // - Children without specific value requirements ("unconstrained");
154   // - The one child that must go last, if it exists.
155   std::unique_ptr<InstanceTypeTree> lowest_child;
156   std::unique_ptr<InstanceTypeTree> highest_child;
157   std::multimap<int, std::unique_ptr<InstanceTypeTree>>
158       constrained_children_by_start;
159   // Using std::map because you can't std::move out of a std::set until C++17.
160   std::map<InstanceTypeTree*, std::unique_ptr<InstanceTypeTree>,
161            CompareUnconstrainedTypes>
162       unconstrained_children_by_size;
163   for (auto& child : root->children) {
164     if (child->type->IsHighestInstanceTypeWithinParent()) {
165       if (highest_child) {
166         Error("Two classes requested to be the highest instance type: ",
167               highest_child->type->name(), " and ", child->type->name(),
168               " within range for parent class ", root->type->name())
169             .Position(child->type->GetPosition());
170       }
171       if (child->type->IsLowestInstanceTypeWithinParent()) {
172         Error(
173             "Class requested to be both highest and lowest instance type "
174             "within its parent range: ",
175             child->type->name())
176             .Position(child->type->GetPosition());
177       }
178       highest_child = std::move(child);
179     } else if (child->type->IsLowestInstanceTypeWithinParent()) {
180       if (lowest_child) {
181         Error("Two classes requested to be the lowest instance type: ",
182               lowest_child->type->name(), " and ", child->type->name(),
183               " within range for parent class ", root->type->name())
184             .Position(child->type->GetPosition());
185       }
186       lowest_child = std::move(child);
187     } else if (child->start > child->end) {
188       unconstrained_children_by_size.insert(
189           std::make_pair(child.get(), std::move(child)));
190     } else {
191       constrained_children_by_start.insert(
192           std::make_pair(child->start, std::move(child)));
193     }
194   }
195   root->children.clear();
196 
197   bool own_type_pending = root->num_own_values > 0;
198 
199   // Second, iterate and place the children in ascending order.
200   if (lowest_child != nullptr) {
201     start_value = SolveInstanceTypeConstraints(std::move(lowest_child),
202                                                start_value, &root->children);
203   }
204   for (auto& constrained_child_pair : constrained_children_by_start) {
205     // Select the next constrained child type in ascending order.
206     std::unique_ptr<InstanceTypeTree> constrained_child =
207         std::move(constrained_child_pair.second);
208 
209     // Try to place the root type before the constrained child type if it fits.
210     if (own_type_pending) {
211       if ((root->value != -1 && root->value < constrained_child->start) ||
212           (root->value == -1 &&
213            start_value + root->num_own_values <= constrained_child->start)) {
214         start_value = SelectOwnValues(root.get(), start_value);
215         own_type_pending = false;
216       }
217     }
218 
219     // Try to find any unconstrained children that fit before the constrained
220     // one. This simple greedy algorithm just puts the biggest unconstrained
221     // children in first, which might not fill the space as efficiently as
222     // possible but is good enough for our needs.
223     for (auto it = unconstrained_children_by_size.begin();
224          it != unconstrained_children_by_size.end();) {
225       if (it->second->num_values + start_value <= constrained_child->start) {
226         start_value = SolveInstanceTypeConstraints(
227             std::move(it->second), start_value, &root->children);
228         it = unconstrained_children_by_size.erase(it);
229       } else {
230         ++it;
231       }
232     }
233 
234     // Place the constrained child type.
235     start_value = SolveInstanceTypeConstraints(std::move(constrained_child),
236                                                start_value, &root->children);
237   }
238   if (own_type_pending) {
239     start_value = SelectOwnValues(root.get(), start_value);
240     own_type_pending = false;
241   }
242   for (auto& child_pair : unconstrained_children_by_size) {
243     start_value = SolveInstanceTypeConstraints(std::move(child_pair.second),
244                                                start_value, &root->children);
245   }
246   if (highest_child != nullptr) {
247     start_value = SolveInstanceTypeConstraints(std::move(highest_child),
248                                                start_value, &root->children);
249   }
250 
251   // Finally, set the range for this class to include all placed subclasses.
252   root->end = start_value - 1;
253   root->start =
254       root->children.empty() ? start_value : root->children.front()->start;
255   if (root->value != -1 && root->value < root->start) {
256     root->start = root->value;
257   }
258   root->num_values = root->end - root->start + 1;
259   root->type->InitializeInstanceTypes(
260       root->value == -1 ? base::Optional<int>{} : root->value,
261       std::make_pair(root->start, root->end));
262 
263   if (root->num_values > 0) {
264     destination->push_back(std::move(root));
265   }
266   return start_value;
267 }
268 
SolveInstanceTypeConstraints(std::unique_ptr<InstanceTypeTree> root)269 std::unique_ptr<InstanceTypeTree> SolveInstanceTypeConstraints(
270     std::unique_ptr<InstanceTypeTree> root) {
271   std::vector<std::unique_ptr<InstanceTypeTree>> destination;
272   SolveInstanceTypeConstraints(std::move(root), 0, &destination);
273   return destination.empty() ? nullptr : std::move(destination.front());
274 }
275 
AssignInstanceTypes()276 std::unique_ptr<InstanceTypeTree> AssignInstanceTypes() {
277   std::unique_ptr<InstanceTypeTree> root = BuildInstanceTypeTree();
278   if (root != nullptr) {
279     PropagateInstanceTypeConstraints(root.get());
280     root = SolveInstanceTypeConstraints(std::move(root));
281   }
282   return root;
283 }
284 
285 // Prints items in macro lists for the given type and its descendants.
286 // - definitions: This list is pairs of instance type name and assigned value,
287 //   such as V(ODDBALL_TYPE, 67). It includes FIRST_* and LAST_* items for each
288 //   type that has more than one associated InstanceType. Items within those
289 //   ranges are indented for readability.
290 // - values: This list is just instance type names, like V(ODDBALL_TYPE). It
291 //   does not include any FIRST_* and LAST_* range markers.
292 // - fully_defined_single_instance_types: This list is pairs of class name and
293 //   instance type, for classes which have defined layouts and a single
294 //   corresponding instance type.
295 // - fully_defined_multiple_instance_types: This list is pairs of class name and
296 //   instance type, for classes which have defined layouts and subclasses.
297 // - only_declared_single_instance_types: This list is pairs of class name and
298 //   instance type, for classes which have a single corresponding instance type
299 //   and do not have layout definitions in Torque.
300 // - only_declared_multiple_instance_types: This list is pairs of class name and
301 //   instance type, for classes which have subclasses but also have a single
302 //   corresponding instance type, and do not have layout definitions in Torque.
303 // - fully_defined_range_instance_types: This list is triples of class name,
304 //   first instance type, and last instance type, for classes which have defined
305 //   layouts and multiple corresponding instance types.
306 // - only_declared_range_instance_types: This list is triples of class name,
307 //   first instance type, and last instance type, for classes which have
308 //   multiple corresponding instance types and do not have layout definitions in
309 //   Torque.
PrintInstanceTypes(InstanceTypeTree * root,std::ostream & definitions,std::ostream & values,std::ostream & fully_defined_single_instance_types,std::ostream & fully_defined_multiple_instance_types,std::ostream & only_declared_single_instance_types,std::ostream & only_declared_multiple_instance_types,std::ostream & fully_defined_range_instance_types,std::ostream & only_declared_range_instance_types,const std::string & indent)310 void PrintInstanceTypes(InstanceTypeTree* root, std::ostream& definitions,
311                         std::ostream& values,
312                         std::ostream& fully_defined_single_instance_types,
313                         std::ostream& fully_defined_multiple_instance_types,
314                         std::ostream& only_declared_single_instance_types,
315                         std::ostream& only_declared_multiple_instance_types,
316                         std::ostream& fully_defined_range_instance_types,
317                         std::ostream& only_declared_range_instance_types,
318                         const std::string& indent) {
319   std::string type_name =
320       CapifyStringWithUnderscores(root->type->name()) + "_TYPE";
321   std::string inner_indent = indent;
322 
323   if (root->num_values > 1) {
324     definitions << indent << "V(FIRST_" << type_name << ", " << root->start
325                 << ") \\\n";
326     inner_indent += "  ";
327   }
328   if (root->num_own_values == 1) {
329     definitions << inner_indent << "V(" << type_name << ", " << root->value
330                 << ") /* " << root->type->GetPosition() << " */\\\n";
331     values << "  V(" << type_name << ") /* " << root->type->GetPosition()
332            << " */\\\n";
333     std::ostream& type_checker_list =
334         root->type->HasUndefinedLayout()
335             ? (root->num_values == 1 ? only_declared_single_instance_types
336                                      : only_declared_multiple_instance_types)
337             : (root->num_values == 1 ? fully_defined_single_instance_types
338                                      : fully_defined_multiple_instance_types);
339     type_checker_list << "  V(" << root->type->name() << ", " << type_name
340                       << ") /* " << root->type->GetPosition() << " */ \\\n";
341   }
342   for (auto& child : root->children) {
343     PrintInstanceTypes(child.get(), definitions, values,
344                        fully_defined_single_instance_types,
345                        fully_defined_multiple_instance_types,
346                        only_declared_single_instance_types,
347                        only_declared_multiple_instance_types,
348                        fully_defined_range_instance_types,
349                        only_declared_range_instance_types, inner_indent);
350   }
351   if (root->num_values > 1) {
352     // We can't emit LAST_STRING_TYPE because it's not a valid flags
353     // combination. So if the class type has multiple own values, which only
354     // happens when using ANNOTATION_RESERVE_BITS_IN_INSTANCE_TYPE, then omit
355     // the end marker.
356     if (root->num_own_values <= 1) {
357       definitions << indent << "V(LAST_" << type_name << ", " << root->end
358                   << ") \\\n";
359     }
360 
361     // Only output the instance type range for things other than the root type.
362     if (root->type->GetSuperClass() != nullptr) {
363       std::ostream& range_instance_types =
364           root->type->HasUndefinedLayout() ? only_declared_range_instance_types
365                                            : fully_defined_range_instance_types;
366       range_instance_types << "  V(" << root->type->name() << ", FIRST_"
367                            << type_name << ", LAST_" << type_name << ") \\\n";
368     }
369   }
370 }
371 
372 }  // namespace
373 
GenerateInstanceTypes(const std::string & output_directory)374 void ImplementationVisitor::GenerateInstanceTypes(
375     const std::string& output_directory) {
376   std::stringstream header;
377   std::string file_name = "instance-types.h";
378   {
379     IncludeGuardScope guard(header, file_name);
380 
381     header << "// Instance types for all classes except for those that use "
382               "InstanceType as flags.\n";
383     header << "#define TORQUE_ASSIGNED_INSTANCE_TYPES(V) \\\n";
384     std::unique_ptr<InstanceTypeTree> instance_types = AssignInstanceTypes();
385     std::stringstream values_list;
386     std::stringstream fully_defined_single_instance_types;
387     std::stringstream fully_defined_multiple_instance_types;
388     std::stringstream only_declared_single_instance_types;
389     std::stringstream only_declared_multiple_instance_types;
390     std::stringstream fully_defined_range_instance_types;
391     std::stringstream only_declared_range_instance_types;
392     if (instance_types != nullptr) {
393       PrintInstanceTypes(instance_types.get(), header, values_list,
394                          fully_defined_single_instance_types,
395                          fully_defined_multiple_instance_types,
396                          only_declared_single_instance_types,
397                          only_declared_multiple_instance_types,
398                          fully_defined_range_instance_types,
399                          only_declared_range_instance_types, "  ");
400     }
401     header << "\n";
402 
403     header << "// Instance types for all classes except for those that use\n";
404     header << "// InstanceType as flags.\n";
405     header << "#define TORQUE_ASSIGNED_INSTANCE_TYPE_LIST(V) \\\n";
406     header << values_list.str();
407     header << "\n";
408 
409     header << "// Pairs of (ClassName, INSTANCE_TYPE) for classes that have\n";
410     header << "// full Torque definitions.\n";
411     header << "#define TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(V) \\\n";
412     header << fully_defined_single_instance_types.str();
413     header << "\n";
414 
415     header << "// Pairs of (ClassName, INSTANCE_TYPE) for classes that have\n";
416     header << "// full Torque definitions and subclasses.\n";
417     header << "#define TORQUE_INSTANCE_CHECKERS_MULTIPLE_FULLY_DEFINED(V) \\\n";
418     header << fully_defined_multiple_instance_types.str();
419     header << "\n";
420 
421     header << "// Pairs of (ClassName, INSTANCE_TYPE) for classes that are\n";
422     header << "// declared but not defined in Torque. These classes may\n";
423     header << "// correspond with actual C++ classes, but they are not\n";
424     header << "// guaranteed to.\n";
425     header << "#define TORQUE_INSTANCE_CHECKERS_SINGLE_ONLY_DECLARED(V) \\\n";
426     header << only_declared_single_instance_types.str();
427     header << "\n";
428 
429     header << "// Pairs of (ClassName, INSTANCE_TYPE) for classes that are\n";
430     header << "// declared but not defined in Torque, and have subclasses.\n";
431     header << "// These classes may correspond with actual C++ classes, but\n";
432     header << "// they are not guaranteed to.\n";
433     header << "#define TORQUE_INSTANCE_CHECKERS_MULTIPLE_ONLY_DECLARED(V) \\\n";
434     header << only_declared_multiple_instance_types.str();
435     header << "\n";
436 
437     header << "// Triples of (ClassName, FIRST_TYPE, LAST_TYPE) for classes\n";
438     header << "// that have full Torque definitions.\n";
439     header << "#define TORQUE_INSTANCE_CHECKERS_RANGE_FULLY_DEFINED(V) \\\n";
440     header << fully_defined_range_instance_types.str();
441     header << "\n";
442 
443     header << "// Triples of (ClassName, FIRST_TYPE, LAST_TYPE) for classes\n";
444     header << "// that are declared but not defined in Torque. These classes\n";
445     header << "// may correspond with actual C++ classes, but they are not\n";
446     header << "// guaranteed to.\n";
447     header << "#define TORQUE_INSTANCE_CHECKERS_RANGE_ONLY_DECLARED(V) \\\n";
448     header << only_declared_range_instance_types.str();
449     header << "\n";
450 
451     std::stringstream torque_defined_class_list;
452     std::stringstream torque_defined_varsize_instance_type_list;
453     std::stringstream torque_defined_fixed_instance_type_list;
454     std::stringstream torque_defined_map_csa_list;
455     std::stringstream torque_defined_map_root_list;
456 
457     for (const ClassType* type : TypeOracle::GetClasses()) {
458       std::string upper_case_name = type->name();
459       std::string lower_case_name = SnakeifyString(type->name());
460       std::string instance_type_name =
461           CapifyStringWithUnderscores(type->name()) + "_TYPE";
462 
463       if (!type->IsExtern()) {
464         torque_defined_class_list << "  V(" << upper_case_name << ") \\\n";
465       }
466 
467       if (type->ShouldGenerateUniqueMap()) {
468         torque_defined_map_csa_list << "  V(_, " << upper_case_name << "Map, "
469                                     << lower_case_name << "_map, "
470                                     << upper_case_name << ") \\\n";
471         torque_defined_map_root_list << "  V(Map, " << lower_case_name
472                                      << "_map, " << upper_case_name
473                                      << "Map) \\\n";
474         std::stringstream& list =
475             type->HasStaticSize() ? torque_defined_fixed_instance_type_list
476                                   : torque_defined_varsize_instance_type_list;
477         list << "  V(" << instance_type_name << ", " << upper_case_name << ", "
478              << lower_case_name << ") \\\n";
479       }
480     }
481 
482     header << "// Fully Torque-defined classes (both internal and exported).\n";
483     header << "#define TORQUE_DEFINED_CLASS_LIST(V) \\\n";
484     header << torque_defined_class_list.str();
485     header << "\n";
486     header << "#define TORQUE_DEFINED_VARSIZE_INSTANCE_TYPE_LIST(V) \\\n";
487     header << torque_defined_varsize_instance_type_list.str();
488     header << "\n";
489     header << "#define TORQUE_DEFINED_FIXED_INSTANCE_TYPE_LIST(V) \\\n";
490     header << torque_defined_fixed_instance_type_list.str();
491     header << "\n";
492     header << "#define TORQUE_DEFINED_INSTANCE_TYPE_LIST(V) \\\n";
493     header << "  TORQUE_DEFINED_VARSIZE_INSTANCE_TYPE_LIST(V) \\\n";
494     header << "  TORQUE_DEFINED_FIXED_INSTANCE_TYPE_LIST(V) \\\n";
495     header << "\n";
496     header << "#define TORQUE_DEFINED_MAP_CSA_LIST_GENERATOR(V, _) \\\n";
497     header << torque_defined_map_csa_list.str();
498     header << "\n";
499     header << "#define TORQUE_DEFINED_MAP_ROOT_LIST(V) \\\n";
500     header << torque_defined_map_root_list.str();
501     header << "\n";
502   }
503   std::string output_header_path = output_directory + "/" + file_name;
504   WriteFile(output_header_path, header.str());
505 
506   GlobalContext::SetInstanceTypesInitialized();
507 }
508 
509 }  // namespace torque
510 }  // namespace internal
511 }  // namespace v8
512