1 // Copyright (C) 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "linker/module_merger.h"
16 #include "repr/abi_diff_helpers.h"
17 #include "repr/ir_representation_internal.h"
18 
19 #include <cassert>
20 
21 #include <llvm/Support/raw_ostream.h>
22 
23 
24 namespace header_checker {
25 namespace linker {
26 
27 
MergeBuiltinType(const repr::BuiltinTypeIR * builtin_type,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)28 MergeStatus ModuleMerger::MergeBuiltinType(
29     const repr::BuiltinTypeIR *builtin_type, const repr::ModuleIR &addend,
30     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
31   std::string linker_set_key = builtin_type->GetLinkerSetKey();
32   auto builtin_it = module_->builtin_types_.find(linker_set_key);
33   if (builtin_it != module_->builtin_types_.end()) {
34     return MergeStatus(false, builtin_it->second.GetSelfType());
35   }
36 
37   // Add this builtin type to the parent graph's builtin_types_ map.
38   const std::string &type_id = builtin_type->GetSelfType();
39   auto p = module_->builtin_types_.emplace(linker_set_key, *builtin_type);
40   module_->type_graph_.emplace(type_id, &p.first->second);
41 
42   MergeStatus merge_status(true, type_id);
43   local_to_global_type_id_map->emplace(type_id, merge_status);
44   return merge_status;
45 }
46 
47 
LookupUserDefinedType(const repr::TypeIR * ud_type,const repr::ModuleIR & addend,const std::string & ud_type_unique_id_and_source,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map_)48 MergeStatus ModuleMerger::LookupUserDefinedType(
49     const repr::TypeIR *ud_type, const repr::ModuleIR &addend,
50     const std::string &ud_type_unique_id_and_source,
51     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map_) {
52   auto it = module_->odr_list_map_.find(ud_type_unique_id_and_source);
53   if (it == module_->odr_list_map_.end()) {
54     // Calling this an ODR violation even though it means no UD with the same
55     // name + source combination was seen in the parent graph. The type-id
56     // passed does not matter since was_newly_added_ is true, the type will get
57     // allocated a new type id.
58     return MergeStatus(true, "");
59   }
60 
61   // Initialize type comparator (which will compare the referenced types
62   // recursively).
63   std::set<std::string> type_cache;
64   repr::DiffPolicyOptions diff_policy_options(false);
65   repr::AbiDiffHelper diff_helper(module_->type_graph_, addend.type_graph_,
66                                   diff_policy_options, &type_cache, {}, nullptr);
67 
68   // Compare each user-defined type with the latest input user-defined type.
69   // If there is a match, re-use the existing user-defined type.
70   for (auto &definition : it->second) {
71     const repr::TypeIR *contender_ud = definition.type_ir_;
72     repr::DiffStatus result = diff_helper.CompareAndDumpTypeDiff(
73         contender_ud->GetSelfType(), ud_type->GetSelfType());
74     if (!result.HasDiff()) {
75       local_to_global_type_id_map_->emplace(
76           ud_type->GetSelfType(),
77           MergeStatus(false, contender_ud->GetSelfType()));
78       return MergeStatus(false, contender_ud->GetSelfType());
79     }
80   }
81 
82 #ifdef DEBUG
83   llvm::errs() << "ODR violation detected for: " << ud_type->GetName() << "\n";
84 #endif
85   return MergeStatus(true, it->second.begin()->type_ir_->GetSelfType());
86 }
87 
88 
LookupType(const repr::TypeIR * addend_node,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)89 MergeStatus ModuleMerger::LookupType(
90     const repr::TypeIR *addend_node, const repr::ModuleIR &addend,
91     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
92   std::string unique_type_id;
93   switch (addend_node->GetKind()) {
94     case repr::RecordTypeKind:
95       unique_type_id = repr::GetODRListMapKey(
96           static_cast<const repr::RecordTypeIR *>(addend_node));
97       break;
98     case repr::EnumTypeKind:
99       unique_type_id = repr::GetODRListMapKey(
100           static_cast<const repr::EnumTypeIR *>(addend_node));
101       break;
102     case repr::FunctionTypeKind:
103       unique_type_id = repr::GetODRListMapKey(
104           static_cast<const repr::FunctionTypeIR *>(addend_node));
105       break;
106     default:
107       // Other kinds (e.g. PointerTypeKind, QualifiedTypeKind, ArrayTypeKind,
108       // LvalueReferenceTypeKind, RvalueReferenceTypeKind, or BuiltinTypeKind)
109       // should be proactively added by returning MergeStatus with
110       // was_newly_added_ = true.
111       return MergeStatus(true, "type-hidden");
112   }
113 
114   return LookupUserDefinedType(
115       addend_node, addend, unique_type_id, local_to_global_type_id_map);
116 }
117 
118 
119 // This method merges the type referenced by 'references_type' into the parent
120 // graph. It also corrects the referenced_type field in the references_type
121 // object passed and returns the merge status of the *referenced type*.
MergeReferencingTypeInternal(const repr::ModuleIR & addend,repr::ReferencesOtherType * references_type,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)122 MergeStatus ModuleMerger::MergeReferencingTypeInternal(
123     const repr::ModuleIR &addend, repr::ReferencesOtherType *references_type,
124     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
125   // First look in the local_to_global_type_id_map for the referenced type's
126   // id.
127   const std::string &referenced_type_id = references_type->GetReferencedType();
128   auto local_to_global_it = local_to_global_type_id_map->find(
129       referenced_type_id);
130   if (local_to_global_it != local_to_global_type_id_map->end()) {
131     // The type was already added to the parent graph. So change the
132     // referenced type to the global type id.
133     references_type->SetReferencedType(local_to_global_it->second.type_id_);
134     return MergeStatus(false, local_to_global_it->second.type_id_);
135   }
136 
137   // If that did not go through, look at the addend's type_map_ and get the
138   // TypeIR* and call MergeType on it.
139   auto local_type_it = addend.type_graph_.find(referenced_type_id);
140   if (local_type_it != addend.type_graph_.end()) {
141     // We don't care about merge_status.was_newly_added since we wouldn't have
142     // gotten this far if we weren't adding this.
143     MergeStatus merge_status =
144         MergeType(local_type_it->second, addend, local_to_global_type_id_map);
145     const std::string &global_type_id = merge_status.type_id_;
146     references_type->SetReferencedType(global_type_id);
147     return merge_status;
148   }
149 
150   // If the referenced type was hidden, create the name reference type in the
151   // parent module and keep the referenced type_id as-is.
152   return MergeStatus(true, referenced_type_id);
153 }
154 
155 
MergeRecordFields(const repr::ModuleIR & addend,repr::RecordTypeIR * added_node,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)156 void ModuleMerger::MergeRecordFields(
157     const repr::ModuleIR &addend, repr::RecordTypeIR *added_node,
158     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
159   for (auto &field : added_node->GetFields()) {
160     MergeReferencingTypeInternal(addend, &field, local_to_global_type_id_map);
161   }
162 }
163 
164 
MergeRecordCXXBases(const repr::ModuleIR & addend,repr::RecordTypeIR * added_node,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)165 void ModuleMerger::MergeRecordCXXBases(
166     const repr::ModuleIR &addend, repr::RecordTypeIR *added_node,
167     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
168   for (auto &base : added_node->GetBases()) {
169     MergeReferencingTypeInternal(addend, &base, local_to_global_type_id_map);
170   }
171 }
172 
173 
MergeRecordTemplateElements(const repr::ModuleIR & addend,repr::RecordTypeIR * added_node,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)174 void ModuleMerger::MergeRecordTemplateElements(
175     const repr::ModuleIR &addend, repr::RecordTypeIR *added_node,
176     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
177   for (auto &template_element : added_node->GetTemplateElements()) {
178     MergeReferencingTypeInternal(
179         addend, &template_element, local_to_global_type_id_map);
180   }
181 }
182 
183 
MergeRecordDependencies(const repr::ModuleIR & addend,repr::RecordTypeIR * added_node,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)184 void ModuleMerger::MergeRecordDependencies(
185     const repr::ModuleIR &addend, repr::RecordTypeIR *added_node,
186     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
187   // First call MergeType on all its fields.
188   MergeRecordFields(addend, added_node, local_to_global_type_id_map);
189 
190   // Call MergeType on CXXBases of the record.
191   MergeRecordCXXBases(addend, added_node, local_to_global_type_id_map);
192 
193   MergeRecordTemplateElements(addend, added_node, local_to_global_type_id_map);
194 }
195 
196 
197 template <typename T>
198 std::pair<MergeStatus, typename repr::AbiElementMap<T>::iterator>
UpdateUDTypeAccounting(const T * addend_node,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map,repr::AbiElementMap<T> * specific_type_map)199 ModuleMerger::UpdateUDTypeAccounting(
200     const T *addend_node, const repr::ModuleIR &addend,
201     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map,
202     repr::AbiElementMap<T> *specific_type_map) {
203   const std::string addend_compilation_unit_path =
204       addend.GetCompilationUnitPath(addend_node);
205   assert(addend_compilation_unit_path != "");
206   std::string added_type_id = addend_node->GetSelfType();
207   auto type_id_it = module_->type_graph_.find(added_type_id);
208   if (type_id_it != module_->type_graph_.end()) {
209     added_type_id = repr::FormatMultiDefinitionTypeId(
210         added_type_id, addend_compilation_unit_path);
211   }
212 
213   // Add the ud-type with type-id to the type_graph_, since if there are generic
214   // reference types which refer to the record being added, they'll need to find
215   // it's id in the map.
216   // Add ud-type to the parent graph.
217   T added_type_ir = *addend_node;
218   added_type_ir.SetSelfType(added_type_id);
219   added_type_ir.SetReferencedType(added_type_id);
220   auto it = AddToMapAndTypeGraph(std::move(added_type_ir), specific_type_map,
221                                  &module_->type_graph_);
222   // Add to facilitate ODR checking.
223   const std::string &key = GetODRListMapKey(&(it->second));
224   MergeStatus type_merge_status = MergeStatus(true, added_type_id);
225   module_->AddToODRListMap(key, &(it->second), addend_compilation_unit_path);
226   local_to_global_type_id_map->emplace(addend_node->GetSelfType(),
227                                        type_merge_status);
228   return {type_merge_status, it};
229 }
230 
231 
232 // This method is necessarily going to have a was_newly_merged_ = true in its
233 // MergeStatus return. So it necessarily merges a new RecordType.
MergeRecordAndDependencies(const repr::RecordTypeIR * addend_node,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)234 MergeStatus ModuleMerger::MergeRecordAndDependencies(
235     const repr::RecordTypeIR *addend_node, const repr::ModuleIR &addend,
236     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
237   auto p = UpdateUDTypeAccounting(
238       addend_node, addend, local_to_global_type_id_map,
239       &module_->record_types_);
240   MergeRecordDependencies(addend, &p.second->second,
241                           local_to_global_type_id_map);
242   return p.first;
243 }
244 
245 
MergeEnumDependencies(const repr::ModuleIR & addend,repr::EnumTypeIR * added_node,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)246 void ModuleMerger::MergeEnumDependencies(
247     const repr::ModuleIR &addend, repr::EnumTypeIR *added_node,
248     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
249   const std::string underlying_type_id = added_node->GetUnderlyingType();
250   // Get the underlying type, it nessarily has to be present in the addend's
251   // type graph since builtin types can't be hidden. Call MergeType on it and
252   // change the underlying type to that.
253   auto it = addend.type_graph_.find(underlying_type_id);
254   if (it == addend.type_graph_.end()) {
255     llvm::errs() << "Enum underlying types should not be hidden\n";
256     ::exit(1);
257   }
258   MergeStatus merge_status = MergeType(
259       it->second, addend, local_to_global_type_id_map);
260   added_node->SetUnderlyingType(merge_status.type_id_);
261 }
262 
263 
264 // This method is necessarily going to have a was_newly_merged_ = true in its
265 // MergeStatus return. So it necessarily merges a new EnumType.
MergeEnumType(const repr::EnumTypeIR * addend_node,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)266 MergeStatus ModuleMerger::MergeEnumType(
267     const repr::EnumTypeIR *addend_node, const repr::ModuleIR &addend,
268     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
269   auto p = UpdateUDTypeAccounting(
270       addend_node, addend, local_to_global_type_id_map, &module_->enum_types_);
271   MergeEnumDependencies(addend, &p.second->second, local_to_global_type_id_map);
272   return p.first;
273 }
274 
275 
MergeFunctionType(const repr::FunctionTypeIR * addend_node,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)276 MergeStatus ModuleMerger::MergeFunctionType(
277     const repr::FunctionTypeIR *addend_node, const repr::ModuleIR &addend,
278     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
279   auto p = UpdateUDTypeAccounting(
280       addend_node, addend, local_to_global_type_id_map,
281       &module_->function_types_);
282   MergeCFunctionLikeDeps(addend, &p.second->second,
283                          local_to_global_type_id_map);
284   return p.first;
285 }
286 
287 
288 template <typename T>
MergeReferencingTypeInternalAndUpdateParent(const repr::ModuleIR & addend,const T * addend_node,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map,repr::AbiElementMap<T> * parent_map,const std::string & updated_self_type_id)289 MergeStatus ModuleMerger::MergeReferencingTypeInternalAndUpdateParent(
290     const repr::ModuleIR &addend, const T *addend_node,
291     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map,
292     repr::AbiElementMap<T> *parent_map,
293     const std::string &updated_self_type_id) {
294   MergeStatus merge_status;
295 
296   // Create copy of addend_node
297   T added_node = *addend_node;
298   added_node.SetSelfType(updated_self_type_id);
299 
300   // The merge status returned is the merge status of the referenced type.
301   merge_status = MergeReferencingTypeInternal(addend, &added_node,
302                                               local_to_global_type_id_map);
303   if (merge_status.was_newly_added_) {
304     // Emplace to map (type-referenced -> Referencing type)
305     AddToMapAndTypeGraph(std::move(added_node), parent_map,
306                          &module_->type_graph_);
307     return MergeStatus(true, updated_self_type_id);
308   }
309 
310   // Try finding the referenced_type is referred to by any referencing type
311   // of the same kind in the parent graph. It is safe to call this on the
312   // added_node, since the referenced_type in the added_node would have been
313   // modified by the MergeReferencingTypeInternal call.
314   auto it = parent_map->find(GetReferencedTypeMapKey(added_node));
315   if (it == parent_map->end()) {
316     // There was no counterpart found for the added_node's type Kind referencing
317     // the referenced type, so we added it to the parent and also updated the
318     // local_to_global_type_id_map's global_id value.
319     AddToMapAndTypeGraph(std::move(added_node), parent_map,
320                          &module_->type_graph_);
321 
322     merge_status = MergeStatus(true, updated_self_type_id);
323     return merge_status;
324   }
325 
326   // Update local_to_global_type_id map's MergeStatus.was_newly_added value for
327   // this key with false since this was node was not newly added.
328   // We never remove anything from the local_to_global_type_id_map, what's
329   // the point ? Since you store the decision of whether the type was newly
330   // added or not. It's global type id is the type-id of the element found
331   // in the parent map which refers to the added_node's modified
332   // referenced_type.
333   merge_status = MergeStatus(false, it->second.GetSelfType());
334   (*local_to_global_type_id_map)[addend_node->GetSelfType()] = merge_status;
335 
336   return merge_status;
337 }
338 
339 
IsReferencingType(repr::LinkableMessageKind kind)340 static bool IsReferencingType(repr::LinkableMessageKind kind) {
341   switch (kind) {
342     case repr::PointerTypeKind:
343     case repr::QualifiedTypeKind:
344     case repr::ArrayTypeKind:
345     case repr::LvalueReferenceTypeKind:
346     case repr::RvalueReferenceTypeKind:
347       return true;
348     case repr::RecordTypeKind:
349     case repr::EnumTypeKind:
350     case repr::BuiltinTypeKind:
351     case repr::FunctionTypeKind:
352     case repr::FunctionKind:
353     case repr::GlobalVarKind:
354       return false;
355   }
356 }
357 
358 // Trace the referenced type until reaching a RecordTypeIR, EnumTypeIR,
359 // FunctionTypeIR, or BuiltinTypeIR. Return nullptr if the referenced type is
360 // undefined or built-in.
DereferenceType(const repr::ModuleIR & module,const repr::TypeIR * type_ir)361 static const repr::TypeIR *DereferenceType(const repr::ModuleIR &module,
362                                            const repr::TypeIR *type_ir) {
363   auto &type_graph = module.GetTypeGraph();
364   while (IsReferencingType(type_ir->GetKind())) {
365     auto it = type_graph.find(type_ir->GetReferencedType());
366     // The referenced type is undefined in the module.
367     if (it == type_graph.end()) {
368       return nullptr;
369     }
370     type_ir = it->second;
371   }
372   return type_ir;
373 }
374 
375 
376 // This method creates a new node for the addend node in the graph if MergeType
377 // on the reference returned a MergeStatus with was_newly_added_ = true.
MergeReferencingType(const repr::ModuleIR & addend,const repr::TypeIR * addend_node,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)378 MergeStatus ModuleMerger::MergeReferencingType(
379     const repr::ModuleIR &addend, const repr::TypeIR *addend_node,
380     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
381   // First add the type 'pro-actively'. We need to do this since we'll need to
382   // fill in 'referenced-type' fields in all this type's descendants and
383   // descendants which are compound types (records), can refer to this type.
384   std::string added_type_id = addend_node->GetSelfType();
385   auto type_id_it = module_->type_graph_.find(added_type_id);
386   if (type_id_it != module_->type_graph_.end()) {
387     const repr::TypeIR *final_referenced_type =
388         DereferenceType(addend, addend_node);
389     if (final_referenced_type != nullptr) {
390       std::string compilation_unit_path =
391           addend.GetCompilationUnitPath(final_referenced_type);
392       // The path is empty for built-in types.
393       if (compilation_unit_path != "") {
394         added_type_id = repr::FormatMultiDefinitionTypeId(
395             added_type_id, compilation_unit_path);
396       }
397     }
398   }
399 
400   // Add the added record type to the local_to_global_type_id_map.
401   local_to_global_type_id_map->emplace(addend_node->GetSelfType(),
402                                        MergeStatus(true, added_type_id));
403 
404   // Merge the type.
405   switch (addend_node->GetKind()) {
406     case repr::PointerTypeKind:
407       return MergeReferencingTypeInternalAndUpdateParent(
408           addend, static_cast<const repr::PointerTypeIR *>(addend_node),
409           local_to_global_type_id_map, &module_->pointer_types_,
410           added_type_id);
411     case repr::QualifiedTypeKind:
412       return MergeReferencingTypeInternalAndUpdateParent(
413           addend, static_cast<const repr::QualifiedTypeIR *>(addend_node),
414           local_to_global_type_id_map, &module_->qualified_types_,
415           added_type_id);
416     case repr::ArrayTypeKind:
417       return MergeReferencingTypeInternalAndUpdateParent(
418           addend, static_cast<const repr::ArrayTypeIR *>(addend_node),
419           local_to_global_type_id_map, &module_->array_types_,
420           added_type_id);
421     case repr::LvalueReferenceTypeKind:
422       return MergeReferencingTypeInternalAndUpdateParent(
423           addend, static_cast<const repr::LvalueReferenceTypeIR *>(addend_node),
424           local_to_global_type_id_map, &module_->lvalue_reference_types_,
425           added_type_id);
426     case repr::RvalueReferenceTypeKind:
427       return MergeReferencingTypeInternalAndUpdateParent(
428           addend, static_cast<const repr::RvalueReferenceTypeIR *>(addend_node),
429           local_to_global_type_id_map, &module_->rvalue_reference_types_,
430           added_type_id);
431     default:
432       // Only referencing types
433       assert(0);
434   }
435 }
436 
437 
MergeTypeInternal(const repr::TypeIR * addend_node,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)438 MergeStatus ModuleMerger::MergeTypeInternal(
439     const repr::TypeIR *addend_node, const repr::ModuleIR &addend,
440     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
441   switch (addend_node->GetKind()) {
442     case repr::BuiltinTypeKind:
443       return MergeBuiltinType(
444           static_cast<const repr::BuiltinTypeIR *>(addend_node), addend,
445           local_to_global_type_id_map);
446     case repr::RecordTypeKind:
447       return MergeRecordAndDependencies(
448           static_cast<const repr::RecordTypeIR *>(addend_node), addend,
449           local_to_global_type_id_map);
450     case repr::EnumTypeKind:
451       return MergeEnumType(static_cast<const repr::EnumTypeIR *>(addend_node),
452                            addend, local_to_global_type_id_map);
453     case repr::FunctionTypeKind:
454       return MergeFunctionType(
455           static_cast<const repr::FunctionTypeIR *>(addend_node), addend,
456           local_to_global_type_id_map);
457     default:
458       return MergeReferencingType(addend, addend_node,
459                                   local_to_global_type_id_map);
460   }
461   assert(0);
462 }
463 
464 
MergeType(const repr::TypeIR * addend_node,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)465 MergeStatus ModuleMerger::MergeType(
466     const repr::TypeIR *addend_node, const repr::ModuleIR &addend,
467     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
468   // Check if the addend type is already in the parent graph. Since we're
469   // going to traverse all the dependencies add whichever ones are not in the
470   // parent graph. This does not add the node itself though.
471   auto type_it = local_to_global_type_id_map->find(addend_node->GetSelfType());
472   if (type_it != local_to_global_type_id_map->end()) {
473     return MergeStatus(false, type_it->second.type_id_);
474   }
475 
476   MergeStatus merge_status = LookupType(
477       addend_node, addend, local_to_global_type_id_map);
478   if (!merge_status.was_newly_added_) {
479     return merge_status;
480   }
481   merge_status = MergeTypeInternal(
482       addend_node, addend, local_to_global_type_id_map);
483   return merge_status;
484 }
485 
486 
MergeCFunctionLikeDeps(const repr::ModuleIR & addend,repr::CFunctionLikeIR * cfunction_like_ir,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)487 void ModuleMerger::MergeCFunctionLikeDeps(
488     const repr::ModuleIR &addend, repr::CFunctionLikeIR *cfunction_like_ir,
489     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
490   // Merge the return type.
491   auto ret_type_it =
492       addend.type_graph_.find(cfunction_like_ir->GetReturnType());
493   if (ret_type_it != addend.type_graph_.end()) {
494     // Merge the type if we can find another type in the parent module.
495     MergeStatus ret_merge_status = MergeType(ret_type_it->second, addend,
496                                              local_to_global_type_id_map);
497     cfunction_like_ir->SetReturnType(ret_merge_status.type_id_);
498   }
499 
500   // Merge the argument types.
501   for (auto &param : cfunction_like_ir->GetParameters()) {
502     MergeReferencingTypeInternal(addend, &param, local_to_global_type_id_map);
503   }
504 }
505 
506 
MergeFunctionDeps(repr::FunctionIR * added_node,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)507 void ModuleMerger::MergeFunctionDeps(
508     repr::FunctionIR *added_node, const repr::ModuleIR &addend,
509     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
510   MergeCFunctionLikeDeps(addend, added_node, local_to_global_type_id_map);
511 
512   // Merge the template arguments.
513   for (auto &template_element : added_node->GetTemplateElements()) {
514     MergeReferencingTypeInternal(addend, &template_element,
515                                  local_to_global_type_id_map);
516   }
517 }
518 
519 
520 template <typename T>
521 static bool
IsLinkableMessagePresent(const repr::LinkableMessageIR * lm,const repr::AbiElementMap<T> & message_map)522 IsLinkableMessagePresent(const repr::LinkableMessageIR *lm,
523                          const repr::AbiElementMap<T> &message_map) {
524   return (message_map.find(lm->GetLinkerSetKey()) != message_map.end());
525 }
526 
527 
MergeFunction(const repr::FunctionIR * addend_node,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)528 void ModuleMerger::MergeFunction(
529     const repr::FunctionIR *addend_node, const repr::ModuleIR &addend,
530     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
531   const std::string &function_linkage_name = addend_node->GetLinkerSetKey();
532   if (IsLinkableMessagePresent(addend_node, module_->functions_)) {
533     // The functions and all of its dependencies have already been added.
534     // No two globally visible functions can have the same symbol name.
535     return;
536   }
537   repr::FunctionIR function_ir = *addend_node;
538   MergeFunctionDeps(&function_ir, addend, local_to_global_type_id_map);
539   // Add it to the parent's function map.
540   module_->functions_.emplace(function_linkage_name, std::move(function_ir));
541 }
542 
543 
MergeGlobalVariable(const repr::GlobalVarIR * addend_node,const repr::ModuleIR & addend,repr::AbiElementMap<MergeStatus> * local_to_global_type_id_map)544 void ModuleMerger::MergeGlobalVariable(
545     const repr::GlobalVarIR *addend_node, const repr::ModuleIR &addend,
546     repr::AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
547   const std::string &global_variable_linkage_name =
548       addend_node->GetLinkerSetKey();
549   if (IsLinkableMessagePresent(addend_node, module_->global_variables_)) {
550     // The global variable and all of its dependencies have already been added.
551     return;
552   }
553   repr::GlobalVarIR global_variable_ir = *addend_node;
554   MergeReferencingTypeInternal(addend, &global_variable_ir,
555                                local_to_global_type_id_map);
556   module_->global_variables_.emplace(
557       global_variable_linkage_name, std::move(global_variable_ir));
558 }
559 
560 
MergeGraphs(const repr::ModuleIR & addend)561 void ModuleMerger::MergeGraphs(const repr::ModuleIR &addend) {
562   // Iterate through nodes of addend reader and merge them.
563   // Keep a merged types cache since if a type is merged, so will all of its
564   // dependencies which weren't already merged.
565   repr::AbiElementMap<MergeStatus> merged_types_cache;
566 
567   for (auto &&type_ir : addend.type_graph_) {
568     MergeType(type_ir.second, addend, &merged_types_cache);
569   }
570 
571   for (auto &&function_ir : addend.functions_) {
572     MergeFunction(&function_ir.second, addend, &merged_types_cache);
573   }
574 
575   for (auto &&global_var_ir : addend.global_variables_) {
576     MergeGlobalVariable(&global_var_ir.second, addend, &merged_types_cache);
577   }
578 }
579 
580 
581 }  // namespace linker
582 }  // namespace header_checker
583 
584