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