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