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