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 ¶m : cfunction_like_ir->GetParameters()) {
491 MergeReferencingTypeInternal(addend, ¶m, 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