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