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