diff --git a/vndk/tools/header-checker/Android.bp b/vndk/tools/header-checker/Android.bp index d22ac551d..b56aec68c 100644 --- a/vndk/tools/header-checker/Android.bp +++ b/vndk/tools/header-checker/Android.bp @@ -110,6 +110,7 @@ cc_binary_host { srcs: [ "src/linker/header_abi_linker.cpp", + "src/linker/module_merger.cpp", ], } diff --git a/vndk/tools/header-checker/src/diff/abi_diff.cpp b/vndk/tools/header-checker/src/diff/abi_diff.cpp index 1784a8c88..3136e1ed6 100644 --- a/vndk/tools/header-checker/src/diff/abi_diff.cpp +++ b/vndk/tools/header-checker/src/diff/abi_diff.cpp @@ -14,6 +14,7 @@ #include "diff/abi_diff.h" +#include "repr/ir_reader.h" #include "utils/header_abi_util.h" #include diff --git a/vndk/tools/header-checker/src/linker/header_abi_linker.cpp b/vndk/tools/header-checker/src/linker/header_abi_linker.cpp index 9470ee7dd..2a486d17e 100644 --- a/vndk/tools/header-checker/src/linker/header_abi_linker.cpp +++ b/vndk/tools/header-checker/src/linker/header_abi_linker.cpp @@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "repr/ir_representation.h" +#include "linker/module_merger.h" #include "repr/ir_dumper.h" #include "repr/ir_reader.h" +#include "repr/ir_representation.h" #include "repr/symbol/so_file_parser.h" #include "repr/symbol/version_script_parser.h" #include "utils/command_line_utils.h" @@ -134,7 +135,7 @@ class HeaderAbiLinker { const repr::AbiElementMap &src, const std::function &symbol_filter); - std::unique_ptr ReadInputDumpFiles(); + std::unique_ptr ReadInputDumpFiles(); bool ReadExportedSymbols(); @@ -142,11 +143,13 @@ class HeaderAbiLinker { bool ReadExportedSymbolsFromSharedObjectFile(); - bool LinkTypes(repr::ModuleIR &module, repr::ModuleIR *linked_module); + bool LinkTypes(const repr::ModuleIR &module, repr::ModuleIR *linked_module); - bool LinkFunctions(repr::ModuleIR &module, repr::ModuleIR *linked_module); + bool LinkFunctions(const repr::ModuleIR &module, + repr::ModuleIR *linked_module); - bool LinkGlobalVars(repr::ModuleIR &module, repr::ModuleIR *linked_module); + bool LinkGlobalVars(const repr::ModuleIR &module, + repr::ModuleIR *linked_module); bool LinkExportedSymbols(repr::ModuleIR *linked_module); @@ -181,13 +184,13 @@ class HeaderAbiLinker { std::unique_ptr version_script_symbols_; }; -static void DeDuplicateAbiElementsThread( - const std::vector &dump_files, - const std::set *exported_headers, - repr::IRReader *greader, std::mutex *greader_lock, - std::atomic *cnt) { - std::unique_ptr local_reader = - repr::IRReader::CreateIRReader(input_format, exported_headers); +static void +DeDuplicateAbiElementsThread(const std::vector &dump_files, + const std::set *exported_headers, + repr::ModuleMerger *global_merger, + std::mutex *global_merger_lock, + std::atomic *cnt) { + repr::ModuleMerger local_merger(exported_headers); auto begin_it = dump_files.begin(); std::size_t num_sources = dump_files.size(); @@ -205,18 +208,17 @@ static void DeDuplicateAbiElementsThread( llvm::errs() << "ReadDump failed\n"; ::exit(1); } - local_reader->MergeGraphs(*reader); + local_merger.MergeGraphs(reader->GetModule()); } } - std::lock_guard lock(*greader_lock); - greader->MergeGraphs(*local_reader); + std::lock_guard lock(*global_merger_lock); + global_merger->MergeGraphs(local_merger.GetModule()); } -std::unique_ptr -HeaderAbiLinker::ReadInputDumpFiles() { - std::unique_ptr greader = - repr::IRReader::CreateIRReader(input_format, &exported_headers_); +std::unique_ptr HeaderAbiLinker::ReadInputDumpFiles() { + std::unique_ptr merger( + new repr::ModuleMerger(&exported_headers_)); std::size_t max_threads = std::thread::hardware_concurrency(); std::size_t num_threads = @@ -225,19 +227,18 @@ HeaderAbiLinker::ReadInputDumpFiles() { : 1; std::vector threads; std::atomic cnt(0); - std::mutex greader_lock; + std::mutex merger_lock; for (std::size_t i = 1; i < num_threads; i++) { threads.emplace_back(DeDuplicateAbiElementsThread, dump_files_, - &exported_headers_, greader.get(), &greader_lock, - &cnt); + &exported_headers_, merger.get(), &merger_lock, &cnt); } - DeDuplicateAbiElementsThread(dump_files_, &exported_headers_, greader.get(), - &greader_lock, &cnt); + DeDuplicateAbiElementsThread(dump_files_, &exported_headers_, merger.get(), + &merger_lock, &cnt); for (auto &thread : threads) { thread.join(); } - return greader; + return merger; } bool HeaderAbiLinker::LinkAndDump() { @@ -251,9 +252,9 @@ bool HeaderAbiLinker::LinkAndDump() { exported_headers_ = CollectAllExportedHeaders(exported_header_dirs_); // Read all input ABI dumps. - auto greader = ReadInputDumpFiles(); + auto merger = ReadInputDumpFiles(); - repr::ModuleIR &module = greader->GetModule(); + const repr::ModuleIR &module = merger->GetModule(); // Link input ABI dumps. std::unique_ptr linked_module( @@ -308,7 +309,7 @@ bool HeaderAbiLinker::LinkDecl( return true; } -bool HeaderAbiLinker::LinkTypes(repr::ModuleIR &module, +bool HeaderAbiLinker::LinkTypes(const repr::ModuleIR &module, repr::ModuleIR *linked_module) { auto no_filter = [](const std::string &symbol) { return true; }; return LinkDecl(linked_module, module.GetRecordTypes(), no_filter) && @@ -332,7 +333,7 @@ bool HeaderAbiLinker::IsSymbolExported(const std::string &name) const { return true; } -bool HeaderAbiLinker::LinkFunctions(repr::ModuleIR &module, +bool HeaderAbiLinker::LinkFunctions(const repr::ModuleIR &module, repr::ModuleIR *linked_module) { auto symbol_filter = [this](const std::string &linker_set_key) { return IsSymbolExported(linker_set_key); @@ -340,7 +341,7 @@ bool HeaderAbiLinker::LinkFunctions(repr::ModuleIR &module, return LinkDecl(linked_module, module.GetFunctions(), symbol_filter); } -bool HeaderAbiLinker::LinkGlobalVars(repr::ModuleIR &module, +bool HeaderAbiLinker::LinkGlobalVars(const repr::ModuleIR &module, repr::ModuleIR *linked_module) { auto symbol_filter = [this](const std::string &linker_set_key) { return IsSymbolExported(linker_set_key); diff --git a/vndk/tools/header-checker/src/linker/module_merger.cpp b/vndk/tools/header-checker/src/linker/module_merger.cpp new file mode 100644 index 000000000..85ad5de19 --- /dev/null +++ b/vndk/tools/header-checker/src/linker/module_merger.cpp @@ -0,0 +1,551 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "linker/module_merger.h" +#include "repr/abi_diff_helpers.h" +#include "repr/ir_representation_internal.h" + +#include + +#include + + +namespace header_checker { +namespace repr { + + +MergeStatus ModuleMerger::MergeBuiltinType( + const BuiltinTypeIR *builtin_type, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + std::string linker_set_key = builtin_type->GetLinkerSetKey(); + auto builtin_it = module_->builtin_types_.find(linker_set_key); + if (builtin_it != module_->builtin_types_.end()) { + return MergeStatus(false, builtin_it->second.GetSelfType()); + } + + // Add this builtin type to the parent graph's builtin_types_ map. + const std::string &type_id = builtin_type->GetSelfType(); + auto p = module_->builtin_types_.emplace(linker_set_key, *builtin_type); + module_->type_graph_.emplace(type_id, &p.first->second); + + MergeStatus merge_status(true, type_id); + local_to_global_type_id_map->emplace(type_id, merge_status); + return merge_status; +} + + +MergeStatus ModuleMerger::LookupUserDefinedType( + const TypeIR *ud_type, const ModuleIR &addend, + const std::string &ud_type_unique_id_and_source, + AbiElementMap *local_to_global_type_id_map_) { + auto it = module_->odr_list_map_.find(ud_type_unique_id_and_source); + if (it == module_->odr_list_map_.end()) { + // Calling this an ODR violation even though it means no UD with the same + // name + source combination was seen in the parent graph. The type-id + // passed does not matter since was_newly_added_ is true, the type will get + // allocated a new type id. + return MergeStatus(true, ""); + } + + // Initialize type comparator (which will compare the referenced types + // recursively). + std::set type_cache; + DiffPolicyOptions diff_policy_options(false); + AbiDiffHelper diff_helper(module_->type_graph_, addend.type_graph_, + diff_policy_options, &type_cache, nullptr); + + // Compare each user-defined type with the latest input user-defined type. + // If there is a match, re-use the existing user-defined type. + for (auto &contender_ud : it->second) { + DiffStatus result = diff_helper.CompareAndDumpTypeDiff( + contender_ud->GetSelfType(), ud_type->GetSelfType()); + if (result == DiffStatus::no_diff) { + local_to_global_type_id_map_->emplace( + ud_type->GetSelfType(), + MergeStatus(false, contender_ud->GetSelfType())); + return MergeStatus(false, contender_ud->GetSelfType()); + } + } + +#ifdef DEBUG + llvm::errs() << "ODR violation detected for: " << ud_type->GetName() << "\n"; +#endif + return MergeStatus(true, (*(it->second.begin()))->GetSelfType()); +} + + +MergeStatus ModuleMerger::LookupType( + const TypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + std::string unique_type_id; + switch (addend_node->GetKind()) { + case RecordTypeKind: + unique_type_id = + GetODRListMapKey(static_cast(addend_node)); + break; + case EnumTypeKind: + unique_type_id = + GetODRListMapKey(static_cast(addend_node)); + break; + case FunctionTypeKind: + unique_type_id = + GetODRListMapKey(static_cast(addend_node)); + break; + default: + // Other kinds (e.g. PointerTypeKind, QualifiedTypeKind, ArrayTypeKind, + // LvalueReferenceTypeKind, RvalueReferenceTypeKind, or BuiltinTypeKind) + // should be proactively added by returning MergeStatus with + // was_newly_added_ = true. + return MergeStatus(true, "type-hidden"); + } + + return LookupUserDefinedType( + addend_node, addend, unique_type_id, local_to_global_type_id_map); +} + + +// This method merges the type referenced by 'references_type' into the parent +// graph. It also corrects the referenced_type field in the references_type +// object passed and returns the merge status of the *referenced type*. +MergeStatus ModuleMerger::MergeReferencingTypeInternal( + const ModuleIR &addend, ReferencesOtherType *references_type, + AbiElementMap *local_to_global_type_id_map) { + // First look in the local_to_global_type_id_map for the referenced type's + // id. + const std::string &referenced_type_id = references_type->GetReferencedType(); + auto local_to_global_it = local_to_global_type_id_map->find( + referenced_type_id); + if (local_to_global_it != local_to_global_type_id_map->end()) { + // The type was already added to the parent graph. So change the + // referenced type to the global type id. + references_type->SetReferencedType(local_to_global_it->second.type_id_); + return local_to_global_it->second; + } + + // If that did not go through, look at the addend's type_map_ and get the + // TypeIR* and call MergeType on it. + auto local_type_it = addend.type_graph_.find(referenced_type_id); + if (local_type_it != addend.type_graph_.end()) { + // We don't care about merge_status.was_newly_added since we wouldn't have + // gotten this far if we weren't adding this. + MergeStatus merge_status = + MergeType(local_type_it->second, addend, local_to_global_type_id_map); + const std::string &global_type_id = merge_status.type_id_; + references_type->SetReferencedType(global_type_id); + return merge_status; + } + + // If the referenced type was hidden, create the name reference type in the + // parent module and keep the referenced type_id as-is. + return MergeStatus(true, referenced_type_id); +} + + +void ModuleMerger::MergeRecordFields( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map) { + for (auto &field : added_node->GetFields()) { + MergeReferencingTypeInternal(addend, &field, local_to_global_type_id_map); + } +} + + +void ModuleMerger::MergeRecordCXXBases( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map) { + for (auto &base : added_node->GetBases()) { + MergeReferencingTypeInternal(addend, &base, local_to_global_type_id_map); + } +} + + +void ModuleMerger::MergeRecordTemplateElements( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map) { + for (auto &template_element : added_node->GetTemplateElements()) { + MergeReferencingTypeInternal( + addend, &template_element, local_to_global_type_id_map); + } +} + + +void ModuleMerger::MergeRecordDependencies( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map) { + // First call MergeType on all its fields. + MergeRecordFields(addend, added_node, local_to_global_type_id_map); + + // Call MergeType on CXXBases of the record. + MergeRecordCXXBases(addend, added_node, local_to_global_type_id_map); + + MergeRecordTemplateElements(addend, added_node, local_to_global_type_id_map); +} + + +template +std::pair::iterator> +ModuleMerger::UpdateUDTypeAccounting( + const T *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map, + AbiElementMap *specific_type_map) { + std::string added_type_id = addend_node->GetSelfType(); + auto type_id_it = module_->type_graph_.find(added_type_id); + if (type_id_it != module_->type_graph_.end()) { + added_type_id = AllocateNewTypeId(added_type_id, addend); + } + + // Add the ud-type with type-id to the type_graph_, since if there are generic + // reference types which refer to the record being added, they'll need to find + // it's id in the map. + // Add ud-type to the parent graph. + T added_type_ir = *addend_node; + added_type_ir.SetSelfType(added_type_id); + added_type_ir.SetReferencedType(added_type_id); + auto it = AddToMapAndTypeGraph(std::move(added_type_ir), specific_type_map, + &module_->type_graph_); + // Add to facilitate ODR checking. + const std::string &key = GetODRListMapKey(&(it->second)); + MergeStatus type_merge_status = MergeStatus(true, added_type_id); + module_->AddToODRListMap(key, &(it->second)); + local_to_global_type_id_map->emplace(addend_node->GetSelfType(), + type_merge_status); + return {type_merge_status, it}; +} + + +// This method is necessarily going to have a was_newly_merged_ = true in its +// MergeStatus return. So it necessarily merges a new RecordType. +MergeStatus ModuleMerger::MergeRecordAndDependencies( + const RecordTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + auto p = UpdateUDTypeAccounting( + addend_node, addend, local_to_global_type_id_map, + &module_->record_types_); + MergeRecordDependencies(addend, &p.second->second, + local_to_global_type_id_map); + return p.first; +} + + +void ModuleMerger::MergeEnumDependencies( + const ModuleIR &addend, EnumTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map) { + const std::string underlying_type_id = added_node->GetUnderlyingType(); + // Get the underlying type, it nessarily has to be present in the addend's + // type graph since builtin types can't be hidden. Call MergeType on it and + // change the underlying type to that. + auto it = addend.type_graph_.find(underlying_type_id); + if (it == addend.type_graph_.end()) { + llvm::errs() << "Enum underlying types should not be hidden\n"; + ::exit(1); + } + MergeStatus merge_status = MergeType( + it->second, addend, local_to_global_type_id_map); + added_node->SetUnderlyingType(merge_status.type_id_); +} + + +// This method is necessarily going to have a was_newly_merged_ = true in its +// MergeStatus return. So it necessarily merges a new EnumType. +MergeStatus ModuleMerger::MergeEnumType( + const EnumTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + auto p = UpdateUDTypeAccounting( + addend_node, addend, local_to_global_type_id_map, &module_->enum_types_); + MergeEnumDependencies(addend, &p.second->second, local_to_global_type_id_map); + return p.first; +} + + +MergeStatus ModuleMerger::MergeFunctionType( + const FunctionTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + auto p = UpdateUDTypeAccounting( + addend_node, addend, local_to_global_type_id_map, + &module_->function_types_); + MergeCFunctionLikeDeps(addend, &p.second->second, + local_to_global_type_id_map); + return p.first; +} + + +template +MergeStatus ModuleMerger::MergeReferencingTypeInternalAndUpdateParent( + const ModuleIR &addend, const T *addend_node, + AbiElementMap *local_to_global_type_id_map, + AbiElementMap *parent_map, const std::string &updated_self_type_id) { + MergeStatus merge_status; + uint64_t old_max_type_id = max_type_id_; + + // Create copy of addend_node + T added_node = *addend_node; + added_node.SetSelfType(updated_self_type_id); + + // The merge status returned is the merge status of the referenced type. + merge_status = MergeReferencingTypeInternal(addend, &added_node, + local_to_global_type_id_map); + if (merge_status.was_newly_added_) { + // Emplace to map (type-referenced -> Referencing type) + AddToMapAndTypeGraph(std::move(added_node), parent_map, + &module_->type_graph_); + return MergeStatus(true, updated_self_type_id); + } + + // The type that the added_node references was not newly added to the parent + // graph. However, we still might need to add the added_node to the parent + // graph, since for the particular 'Kind' of the added_node, it may not be + // present in the parent graph. This will be determined by looking at the + // appropriate 'type-referenced' -> TypeElement map in the parent for the + // type-id returned by the MergeStatus. If the map doesn't have an entry for + // the type-id returned by the MergeStatus, the added_type is not present in + // the parent graph and needs to be 'newly' added. We also need to modify the + // global type id in the local_to_global_type_id map. The added_node should + // already have it's self_type and referenced_type fields fixed up. + // We maintain a rollback id to have contiguous type ids. + max_type_id_ = old_max_type_id; + + // Try finding the referenced_type is referred to by any referencing type + // of the same kind in the parent graph. It is safe to call this on the + // added_node, since the referenced_type in the added_node would have been + // modified by the MergeReferencingTypeInternal call. + auto it = parent_map->find(GetReferencedTypeMapKey(added_node)); + if (it == parent_map->end()) { + // There was no counterpart found for the added_node's type Kind referencing + // the referenced type, so we added it to the parent and also updated the + // local_to_global_type_id_map's global_id value. + AddToMapAndTypeGraph(std::move(added_node), parent_map, + &module_->type_graph_); + + merge_status = MergeStatus(true, updated_self_type_id); + return merge_status; + } + + // Update local_to_global_type_id map's MergeStatus.was_newly_added value for + // this key with false since this was node was not newly added. + // We never remove anything from the local_to_global_type_id_map, what's + // the point ? Since you store the decision of whether the type was newly + // added or not. It's global type id is the type-id of the element found + // in the parent map which refers to the added_node's modified + // referenced_type. + merge_status = MergeStatus(false, it->second.GetSelfType()); + (*local_to_global_type_id_map)[addend_node->GetSelfType()] = merge_status; + + return merge_status; +} + + +// This method creates a new node for the addend node in the graph if MergeType +// on the reference returned a MergeStatus with was_newly_added_ = true. +MergeStatus ModuleMerger::MergeReferencingType( + const ModuleIR &addend, const TypeIR *addend_node, + AbiElementMap *local_to_global_type_id_map) { + // First add the type 'pro-actively'. We need to do this since we'll need to + // fill in 'referenced-type' fields in all this type's descendants and + // descendants which are compound types (records), can refer to this type. + std::string added_type_id = addend_node->GetSelfType(); + auto type_id_it = module_->type_graph_.find(added_type_id); + if (type_id_it != module_->type_graph_.end()) { + added_type_id = AllocateNewTypeId(added_type_id, addend); + } + + // Add the added record type to the local_to_global_type_id_map. + local_to_global_type_id_map->emplace(addend_node->GetSelfType(), + MergeStatus(true, added_type_id)); + + // Merge the type. + switch (addend_node->GetKind()) { + case PointerTypeKind: + return MergeReferencingTypeInternalAndUpdateParent( + addend, static_cast(addend_node), + local_to_global_type_id_map, &module_->pointer_types_, + added_type_id); + case QualifiedTypeKind: + return MergeReferencingTypeInternalAndUpdateParent( + addend, static_cast(addend_node), + local_to_global_type_id_map, &module_->qualified_types_, + added_type_id); + case ArrayTypeKind: + return MergeReferencingTypeInternalAndUpdateParent( + addend, static_cast(addend_node), + local_to_global_type_id_map, &module_->array_types_, + added_type_id); + case LvalueReferenceTypeKind: + return MergeReferencingTypeInternalAndUpdateParent( + addend, static_cast(addend_node), + local_to_global_type_id_map, &module_->lvalue_reference_types_, + added_type_id); + case RvalueReferenceTypeKind: + return MergeReferencingTypeInternalAndUpdateParent( + addend, static_cast(addend_node), + local_to_global_type_id_map, &module_->rvalue_reference_types_, + added_type_id); + default: + // Only referencing types + assert(0); + } +} + + +MergeStatus ModuleMerger::MergeTypeInternal( + const TypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + switch (addend_node->GetKind()) { + case BuiltinTypeKind: + return MergeBuiltinType( + static_cast(addend_node), addend, + local_to_global_type_id_map); + case RecordTypeKind: + return MergeRecordAndDependencies( + static_cast(addend_node), addend, + local_to_global_type_id_map); + case EnumTypeKind: + return MergeEnumType( + static_cast(addend_node), addend, + local_to_global_type_id_map); + case FunctionTypeKind: + return MergeFunctionType( + static_cast(addend_node), addend, + local_to_global_type_id_map); + default: + return MergeReferencingType(addend, addend_node, + local_to_global_type_id_map); + } + assert(0); +} + + +MergeStatus ModuleMerger::MergeType( + const TypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + // Check if the addend type is already in the parent graph. Since we're + // going to traverse all the dependencies add whichever ones are not in the + // parent graph. This does not add the node itself though. + auto type_it = local_to_global_type_id_map->find(addend_node->GetSelfType()); + if (type_it != local_to_global_type_id_map->end()) { + return type_it->second; + } + + MergeStatus merge_status = LookupType( + addend_node, addend, local_to_global_type_id_map); + if (!merge_status.was_newly_added_) { + return merge_status; + } + merge_status = MergeTypeInternal( + addend_node, addend, local_to_global_type_id_map); + return merge_status; +} + + +void ModuleMerger::MergeCFunctionLikeDeps( + const ModuleIR &addend, CFunctionLikeIR *cfunction_like_ir, + AbiElementMap *local_to_global_type_id_map) { + // Merge the return type. + auto ret_type_it = + addend.type_graph_.find(cfunction_like_ir->GetReturnType()); + if (ret_type_it != addend.type_graph_.end()) { + // Merge the type if we can find another type in the parent module. + MergeStatus ret_merge_status = MergeType(ret_type_it->second, addend, + local_to_global_type_id_map); + cfunction_like_ir->SetReturnType(ret_merge_status.type_id_); + } + + // Merge the argument types. + for (auto ¶m : cfunction_like_ir->GetParameters()) { + MergeReferencingTypeInternal(addend, ¶m, local_to_global_type_id_map); + } +} + + +void ModuleMerger::MergeFunctionDeps( + FunctionIR *added_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + MergeCFunctionLikeDeps(addend, added_node, local_to_global_type_id_map); + + // Merge the template arguments. + for (auto &template_element : added_node->GetTemplateElements()) { + MergeReferencingTypeInternal(addend, &template_element, + local_to_global_type_id_map); + } +} + + +template +static bool IsLinkableMessagePresent(const LinkableMessageIR *lm, + const AbiElementMap &message_map) { + return (message_map.find(lm->GetLinkerSetKey()) != message_map.end()); +} + + +void ModuleMerger::MergeFunction( + const FunctionIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + const std::string &function_linkage_name = addend_node->GetLinkerSetKey(); + if (IsLinkableMessagePresent(addend_node, module_->functions_)) { + // The functions and all of its dependencies have already been added. + // No two globally visible functions can have the same symbol name. + return; + } + FunctionIR function_ir = *addend_node; + MergeFunctionDeps(&function_ir, addend, local_to_global_type_id_map); + // Add it to the parent's function map. + module_->functions_.emplace(function_linkage_name, std::move(function_ir)); +} + + +std::string ModuleMerger::AllocateNewTypeId(const std::string &addend_type_id, + const ModuleIR &addend_module) { + return addend_type_id + "#ODR:" + addend_module.GetCompilationUnitPath(); +} + + +void ModuleMerger::MergeGlobalVariable( + const GlobalVarIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map) { + const std::string &global_variable_linkage_name = + addend_node->GetLinkerSetKey(); + if (IsLinkableMessagePresent(addend_node, module_->global_variables_)) { + // The global variable and all of its dependencies have already been added. + return; + } + GlobalVarIR global_variable_ir = *addend_node; + MergeReferencingTypeInternal(addend, &global_variable_ir, + local_to_global_type_id_map); + module_->global_variables_.emplace( + global_variable_linkage_name, std::move(global_variable_ir)); +} + + +void ModuleMerger::MergeGraphs(const ModuleIR &addend) { + // Iterate through nodes of addend reader and merge them. + // Keep a merged types cache since if a type is merged, so will all of its + // dependencies which weren't already merged. + AbiElementMap merged_types_cache; + + for (auto &&type_ir : addend.type_graph_) { + MergeType(type_ir.second, addend, &merged_types_cache); + } + + for (auto &&function_ir : addend.functions_) { + MergeFunction(&function_ir.second, addend, &merged_types_cache); + } + + for (auto &&global_var_ir : addend.global_variables_) { + MergeGlobalVariable(&global_var_ir.second, addend, &merged_types_cache); + } +} + + +} // namespace repr +} // namespace header_checker + diff --git a/vndk/tools/header-checker/src/linker/module_merger.h b/vndk/tools/header-checker/src/linker/module_merger.h new file mode 100644 index 000000000..4e21eab8b --- /dev/null +++ b/vndk/tools/header-checker/src/linker/module_merger.h @@ -0,0 +1,158 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "repr/ir_representation.h" + + +namespace header_checker { +namespace repr { + + +class MergeStatus { +public: + MergeStatus(bool was_newly_added, const std::string &type_id) + : was_newly_added_(was_newly_added), type_id_(type_id) {} + + MergeStatus() {} + + // type_id_ always has the global_type_id corresponding to the type this + // MergeStatus corresponds to. For + // generic reference types (pointers, qual types, l(r)value references etc), + // this will be a proactively added type_id, which will be added to the + // parent type_graph if the we decide to add the referencing type to the + // parent post ODR checking. + bool was_newly_added_ = false; + + std::string type_id_; +}; + + +class ModuleMerger { +public: + ModuleMerger(const std::set *exported_headers) + : module_(new ModuleIR(exported_headers)) {} + + const ModuleIR &GetModule() { + return *module_; + } + + void MergeGraphs(const ModuleIR &addend); + +private: + void MergeCFunctionLikeDeps( + const ModuleIR &addend, CFunctionLikeIR *cfunction_like_ir, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeFunctionType( + const FunctionTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeEnumType( + const EnumTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + void MergeEnumDependencies( + const ModuleIR &addend, EnumTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeRecordAndDependencies( + const RecordTypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + void MergeRecordDependencies( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map); + + void MergeRecordFields( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map); + + void MergeRecordCXXBases( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map); + + void MergeRecordTemplateElements( + const ModuleIR &addend, RecordTypeIR *added_node, + AbiElementMap *local_to_global_type_id_map); + + void MergeGlobalVariable( + const GlobalVarIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + void MergeGlobalVariables( + const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + void MergeFunctionDeps( + FunctionIR *added_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + void MergeFunction( + const FunctionIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + template + MergeStatus MergeReferencingTypeInternalAndUpdateParent( + const ModuleIR &addend, const T *addend_node, + AbiElementMap *local_to_global_type_id_map, + AbiElementMap *parent_map, const std::string &updated_self_type_id); + + MergeStatus MergeReferencingTypeInternal( + const ModuleIR &addend, ReferencesOtherType *references_type, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeReferencingType( + const ModuleIR &addend, const TypeIR *addend_node, + AbiElementMap *local_to_global_type_id_map); + + template + std::pair::iterator> + UpdateUDTypeAccounting( + const T *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map, + AbiElementMap *specific_type_map); + + MergeStatus MergeBuiltinType( + const BuiltinTypeIR *builtin_type, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus LookupUserDefinedType( + const TypeIR *ud_type, const ModuleIR &addend, + const std::string &ud_type_unique_id, + AbiElementMap *local_to_global_type_id_map_); + + MergeStatus LookupType( + const TypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeTypeInternal( + const TypeIR *addend_node, const ModuleIR &addend, + AbiElementMap *local_to_global_type_id_map); + + MergeStatus MergeType( + const TypeIR *addend_type, const ModuleIR &addend, + AbiElementMap *merged_types_cache); + + std::string AllocateNewTypeId(const std::string &addend_type_id, + const ModuleIR &addend_module); + +private: + std::unique_ptr module_; + + uint64_t max_type_id_ = 0; +}; + + +} // namespace repr +} // namespace header_checker diff --git a/vndk/tools/header-checker/src/repr/abi_diff_helpers.h b/vndk/tools/header-checker/src/repr/abi_diff_helpers.h index fff7ab430..7b67d2be3 100644 --- a/vndk/tools/header-checker/src/repr/abi_diff_helpers.h +++ b/vndk/tools/header-checker/src/repr/abi_diff_helpers.h @@ -17,7 +17,6 @@ #include "repr/ir_diff_dumper.h" #include "repr/ir_diff_representation.h" -#include "repr/ir_reader.h" #include "repr/ir_representation.h" #include @@ -30,8 +29,6 @@ namespace repr { // Classes which act as middle-men between clang AST parsing routines and // message format specific dumpers. -using MergeStatus = IRReader::MergeStatus; - enum DiffStatus { // There was no diff found while comparing types. no_diff = 0, @@ -83,12 +80,10 @@ class AbiDiffHelper { const AbiElementMap &new_types, const DiffPolicyOptions &diff_policy_options, std::set *type_cache, - IRDiffDumper *ir_diff_dumper = nullptr, - AbiElementMap *local_to_global_type_id_map = nullptr) + IRDiffDumper *ir_diff_dumper = nullptr) : old_types_(old_types), new_types_(new_types), diff_policy_options_(diff_policy_options), type_cache_(type_cache), - ir_diff_dumper_(ir_diff_dumper), - local_to_global_type_id_map_(local_to_global_type_id_map) {} + ir_diff_dumper_(ir_diff_dumper) {} DiffStatus CompareAndDumpTypeDiff( const std::string &old_type_str, const std::string &new_type_str, @@ -214,7 +209,6 @@ class AbiDiffHelper { const DiffPolicyOptions &diff_policy_options_; std::set *type_cache_; IRDiffDumper *ir_diff_dumper_; - AbiElementMap *local_to_global_type_id_map_; }; void ReplaceTypeIdsWithTypeNames( diff --git a/vndk/tools/header-checker/src/repr/ir_reader.cpp b/vndk/tools/header-checker/src/repr/ir_reader.cpp index a47bab4f3..04de74264 100644 --- a/vndk/tools/header-checker/src/repr/ir_reader.cpp +++ b/vndk/tools/header-checker/src/repr/ir_reader.cpp @@ -14,9 +14,7 @@ #include "repr/ir_reader.h" -#include "repr/abi_diff_helpers.h" #include "repr/ir_representation.h" -#include "repr/ir_representation_internal.h" #include "repr/json/api.h" #include "repr/protobuf/api.h" @@ -32,9 +30,6 @@ namespace header_checker { namespace repr { -using MergeStatus = IRReader::MergeStatus; - - std::unique_ptr IRReader::CreateIRReader( TextFormatIR text_format, const std::set *exported_headers) { @@ -56,527 +51,5 @@ bool IRReader::ReadDump(const std::string &dump_file) { } -MergeStatus IRReader::MergeBuiltinType( - const BuiltinTypeIR *builtin_type, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - std::string linker_set_key = builtin_type->GetLinkerSetKey(); - auto builtin_it = module_->builtin_types_.find(linker_set_key); - if (builtin_it != module_->builtin_types_.end()) { - return MergeStatus(false, builtin_it->second.GetSelfType()); - } - - // Add this builtin type to the parent graph's builtin_types_ map. - const std::string &type_id = builtin_type->GetSelfType(); - auto p = module_->builtin_types_.emplace(linker_set_key, *builtin_type); - module_->type_graph_.emplace(type_id, &p.first->second); - - MergeStatus merge_status(true, type_id); - local_to_global_type_id_map->emplace(type_id, merge_status); - return merge_status; -} - - -MergeStatus IRReader::LookupUserDefinedType( - const TypeIR *ud_type, const IRReader &addend, - const std::string &ud_type_unique_id_and_source, - AbiElementMap *local_to_global_type_id_map_) { - auto it = module_->odr_list_map_.find(ud_type_unique_id_and_source); - if (it == module_->odr_list_map_.end()) { - // Calling this an ODR violation even though it means no UD with the same - // name + source combination was seen in the parent graph. The type-id - // passed does not matter since was_newly_added_ is true, the type will get - // allocated a new type id. - return MergeStatus(true, ""); - } - - // Initialize type comparator (which will compare the referenced types - // recursively). - std::set type_cache; - DiffPolicyOptions diff_policy_options(false) ; - AbiDiffHelper diff_helper(module_->type_graph_, addend.module_->type_graph_, - diff_policy_options, &type_cache, - nullptr, local_to_global_type_id_map_); - - // Compare each user-defined type with the latest input user-defined type. - // If there is a match, re-use the existing user-defined type. - for (auto &contender_ud : it->second) { - DiffStatus result = diff_helper.CompareAndDumpTypeDiff( - contender_ud->GetSelfType(), ud_type->GetSelfType()); - if (result == DiffStatus::no_diff) { - local_to_global_type_id_map_->emplace( - ud_type->GetSelfType(), - MergeStatus(false, contender_ud->GetSelfType())); - return MergeStatus(false, contender_ud->GetSelfType()); - } - } - -#ifdef DEBUG - llvm::errs() << "ODR violation detected for: " << ud_type->GetName() << "\n"; -#endif - return MergeStatus(true, (*(it->second.begin()))->GetSelfType()); -} - - -MergeStatus IRReader::LookupType( - const TypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - std::string unique_type_id; - switch (addend_node->GetKind()) { - case RecordTypeKind: - unique_type_id = - GetODRListMapKey(static_cast(addend_node)); - break; - case EnumTypeKind: - unique_type_id = - GetODRListMapKey(static_cast(addend_node)); - break; - case FunctionTypeKind: - unique_type_id = - GetODRListMapKey(static_cast(addend_node)); - break; - default: - // Other kinds (e.g. PointerTypeKind, QualifiedTypeKind, ArrayTypeKind, - // LvalueReferenceTypeKind, RvalueReferenceTypeKind, or BuiltinTypeKind) - // should be proactively added by returning MergeStatus with - // was_newly_added_ = true. - return MergeStatus(true, "type-hidden"); - } - - return LookupUserDefinedType( - addend_node, addend, unique_type_id, local_to_global_type_id_map); -} - - -// This method merges the type referenced by 'references_type' into the parent -// graph. It also corrects the referenced_type field in the references_type -// object passed and returns the merge status of the *referenced type*. -MergeStatus IRReader::MergeReferencingTypeInternal( - const IRReader &addend, ReferencesOtherType *references_type, - AbiElementMap *local_to_global_type_id_map) { - // First look in the local_to_global_type_id_map for the referenced type's - // id. - const std::string &referenced_type_id = references_type->GetReferencedType(); - auto local_to_global_it = local_to_global_type_id_map->find( - referenced_type_id); - if (local_to_global_it != local_to_global_type_id_map->end()) { - // The type was already added to the parent graph. So change the - // referenced type to the global type id. - references_type->SetReferencedType(local_to_global_it->second.type_id_); - return local_to_global_it->second; - } - - // If that did not go through, look at the addend's type_map_ and get the - // TypeIR* and call MergeType on it. - auto local_type_it = addend.module_->type_graph_.find(referenced_type_id); - if (local_type_it != addend.module_->type_graph_.end()) { - // We don't care about merge_status.was_newly_added since we wouldn't have - // gotten this far if we weren't adding this. - MergeStatus merge_status = - MergeType(local_type_it->second, addend, local_to_global_type_id_map); - const std::string &global_type_id = merge_status.type_id_; - references_type->SetReferencedType(global_type_id); - return merge_status; - } - - // If the referenced type was hidden, create the name reference type in the - // parent module and keep the referenced type_id as-is. - return MergeStatus(true, referenced_type_id); -} - - -void IRReader::MergeRecordFields( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map) { - for (auto &field : added_node->GetFields()) { - MergeReferencingTypeInternal(addend, &field, local_to_global_type_id_map); - } -} - - -void IRReader::MergeRecordCXXBases( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map) { - for (auto &base : added_node->GetBases()) { - MergeReferencingTypeInternal(addend, &base, local_to_global_type_id_map); - } -} - - -void IRReader::MergeRecordTemplateElements( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map) { - for (auto &template_element : added_node->GetTemplateElements()) { - MergeReferencingTypeInternal( - addend, &template_element, local_to_global_type_id_map); - } -} - - -void IRReader::MergeRecordDependencies( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map) { - // First call MergeType on all its fields. - MergeRecordFields(addend, added_node, local_to_global_type_id_map); - - // Call MergeType on CXXBases of the record. - MergeRecordCXXBases(addend, added_node, local_to_global_type_id_map); - - MergeRecordTemplateElements(addend, added_node, local_to_global_type_id_map); -} - - -template -std::pair::iterator> -IRReader::UpdateUDTypeAccounting( - const T *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map, - AbiElementMap *specific_type_map) { - std::string added_type_id = addend_node->GetSelfType(); - auto type_id_it = module_->type_graph_.find(added_type_id); - if (type_id_it != module_->type_graph_.end()) { - added_type_id = AllocateNewTypeId(added_type_id, *addend.module_); - } - - // Add the ud-type with type-id to the type_graph_, since if there are generic - // reference types which refer to the record being added, they'll need to find - // it's id in the map. - // Add ud-type to the parent graph. - T added_type_ir = *addend_node; - added_type_ir.SetSelfType(added_type_id); - added_type_ir.SetReferencedType(added_type_id); - auto it = AddToMapAndTypeGraph(std::move(added_type_ir), specific_type_map, - &module_->type_graph_); - // Add to faciliate ODR checking. - const std::string &key = GetODRListMapKey(&(it->second)); - MergeStatus type_merge_status = MergeStatus(true, added_type_id); - module_->AddToODRListMap(key, &(it->second)); - local_to_global_type_id_map->emplace(addend_node->GetSelfType(), - type_merge_status); - return {type_merge_status, it}; -} - - -// This method is necessarily going to have a was_newly_merged_ = true in its -// MergeStatus return. So it necessarily merges a new RecordType. -MergeStatus IRReader::MergeRecordAndDependencies( - const RecordTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - auto p = UpdateUDTypeAccounting( - addend_node, addend, local_to_global_type_id_map, - &module_->record_types_); - MergeRecordDependencies(addend, &p.second->second, - local_to_global_type_id_map); - return p.first; -} - - -void IRReader::MergeEnumDependencies( - const IRReader &addend, EnumTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map) { - const std::string underlying_type_id = added_node->GetUnderlyingType(); - // Get the underlying type, it nessarily has to be present in the addend's - // type graph since builtin types can't be hidden. Call MergeType on it and - // change the underlying type to that. - auto it = addend.module_->type_graph_.find(underlying_type_id); - if (it == addend.module_->type_graph_.end()) { - llvm::errs() << "Enum underlying types should not be hidden\n"; - ::exit(1); - } - MergeStatus merge_status = MergeType( - it->second, addend, local_to_global_type_id_map); - added_node->SetUnderlyingType(merge_status.type_id_); -} - - -// This method is necessarily going to have a was_newly_merged_ = true in its -// MergeStatus return. So it necessarily merges a new EnumType. -MergeStatus IRReader::MergeEnumType( - const EnumTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - auto p = UpdateUDTypeAccounting( - addend_node, addend, local_to_global_type_id_map, &module_->enum_types_); - MergeEnumDependencies(addend, &p.second->second, local_to_global_type_id_map); - return p.first; -} - - -MergeStatus IRReader::MergeFunctionType( - const FunctionTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - auto p = UpdateUDTypeAccounting( - addend_node, addend, local_to_global_type_id_map, - &module_->function_types_); - MergeCFunctionLikeDeps(addend, &p.second->second, - local_to_global_type_id_map); - return p.first; -} - - -template -MergeStatus IRReader::MergeReferencingTypeInternalAndUpdateParent( - const IRReader &addend, const T *addend_node, - AbiElementMap *local_to_global_type_id_map, - AbiElementMap *parent_map, const std::string &updated_self_type_id) { - MergeStatus merge_status; - uint64_t old_max_type_id = max_type_id_; - - // Create copy of addend_node - T added_node = *addend_node; - added_node.SetSelfType(updated_self_type_id); - - // The merge status returned is the merge status of the referenced type. - merge_status = MergeReferencingTypeInternal(addend, &added_node, - local_to_global_type_id_map); - if (merge_status.was_newly_added_) { - // Emplace to map (type-referenced -> Referencing type) - AddToMapAndTypeGraph(std::move(added_node), parent_map, - &module_->type_graph_); - return MergeStatus(true, updated_self_type_id); - } - - // The type that the added_node references was not newly added to the parent - // graph. However, we still might need to add the added_node to the parent - // graph, since for the particular 'Kind' of the added_node, it may not be - // present in the parent graph. This will be determined by looking at the - // appropriate 'type-referenced' -> TypeElement map in the parent for the - // type-id returned by the MergeStatus. If the map doesn't have an entry for - // the type-id returned by the MergeStatus, the added_type is not present in - // the parent graph and needs to be 'newly' added. We also need to modify the - // global type id in the local_to_global_type_id map. The added_node should - // already have it's self_type and referenced_type fields fixed up. - // We maintain a rollback id to have contiguous type ids. - max_type_id_ = old_max_type_id; - - // Try finding the referenced_type is referred to by any referencing type - // of the same kind in the parent graph. It is safe to call this on the - // added_node, since the referenced_type in the added_node would have been - // modified by the MergeReferencingTypeInternal call. - auto it = parent_map->find(GetReferencedTypeMapKey(added_node)); - if (it == parent_map->end()) { - // There was no counterpart found for the added_node's type Kind referencing - // the referenced type, so we added it to the parent and also updated the - // local_to_global_type_id_map's global_id value. - AddToMapAndTypeGraph(std::move(added_node), parent_map, - &module_->type_graph_); - - merge_status = MergeStatus(true, updated_self_type_id); - return merge_status; - } - - // Update local_to_global_type_id map's MergeStatus.was_newly_added value for - // this key with false since this was node was not newly added. - // We never remove anything from the local_to_global_type_id_map, what's - // the point ? Since you store the decision of whether the type was newly - // added or not. It's global type id is the type-id of the element found - // in the parent map which refers to the added_node's modified - // referenced_type. - merge_status = MergeStatus(false, it->second.GetSelfType()); - (*local_to_global_type_id_map)[addend_node->GetSelfType()] = merge_status; - - return merge_status; -} - - -// This method creates a new node for the addend node in the graph if MergeType -// on the reference returned a MergeStatus with was_newly_added_ = true. -MergeStatus IRReader::MergeReferencingType( - const IRReader &addend, const TypeIR *addend_node, - AbiElementMap *local_to_global_type_id_map) { - // First add the type 'pro-actively'. We need to do this since we'll need to - // fill in 'referenced-type' fields in all this type's descendants and - // descendants which are compound types (records), can refer to this type. - std::string added_type_id = addend_node->GetSelfType(); - auto type_id_it = module_->type_graph_.find(added_type_id); - if (type_id_it != module_->type_graph_.end()) { - added_type_id = AllocateNewTypeId(added_type_id, *addend.module_); - } - - // Add the added record type to the local_to_global_type_id_map. - local_to_global_type_id_map->emplace(addend_node->GetSelfType(), - MergeStatus(true, added_type_id)); - - // Merge the type. - switch (addend_node->GetKind()) { - case PointerTypeKind: - return MergeReferencingTypeInternalAndUpdateParent( - addend, static_cast(addend_node), - local_to_global_type_id_map, &module_->pointer_types_, - added_type_id); - case QualifiedTypeKind: - return MergeReferencingTypeInternalAndUpdateParent( - addend, static_cast(addend_node), - local_to_global_type_id_map, &module_->qualified_types_, - added_type_id); - case ArrayTypeKind: - return MergeReferencingTypeInternalAndUpdateParent( - addend, static_cast(addend_node), - local_to_global_type_id_map, &module_->array_types_, - added_type_id); - case LvalueReferenceTypeKind: - return MergeReferencingTypeInternalAndUpdateParent( - addend, static_cast(addend_node), - local_to_global_type_id_map, &module_->lvalue_reference_types_, - added_type_id); - case RvalueReferenceTypeKind: - return MergeReferencingTypeInternalAndUpdateParent( - addend, static_cast(addend_node), - local_to_global_type_id_map, &module_->rvalue_reference_types_, - added_type_id); - default: - // Only referencing types - assert(0); - } -} - - -MergeStatus IRReader::MergeTypeInternal( - const TypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - switch (addend_node->GetKind()) { - case BuiltinTypeKind: - return MergeBuiltinType( - static_cast(addend_node), addend, - local_to_global_type_id_map); - case RecordTypeKind: - return MergeRecordAndDependencies( - static_cast(addend_node), addend, - local_to_global_type_id_map); - case EnumTypeKind: - return MergeEnumType( - static_cast(addend_node), addend, - local_to_global_type_id_map); - case FunctionTypeKind: - return MergeFunctionType( - static_cast(addend_node), addend, - local_to_global_type_id_map); - default: - return MergeReferencingType(addend, addend_node, - local_to_global_type_id_map); - } - assert(0); -} - - -MergeStatus IRReader::MergeType( - const TypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - // Check if the addend type is already in the parent graph. Since we're - // going to traverse all the dependencies add whichever ones are not in the - // parent graph. This does not add the node itself though. - auto type_it = local_to_global_type_id_map->find(addend_node->GetSelfType()); - if (type_it != local_to_global_type_id_map->end()) { - return type_it->second; - } - - MergeStatus merge_status = LookupType( - addend_node, addend, local_to_global_type_id_map); - if (!merge_status.was_newly_added_) { - return merge_status; - } - merge_status = MergeTypeInternal( - addend_node, addend, local_to_global_type_id_map); - return merge_status; -} - - -void IRReader::MergeCFunctionLikeDeps( - const IRReader &addend, CFunctionLikeIR *cfunction_like_ir, - AbiElementMap *local_to_global_type_id_map) { - // Merge the return type. - auto ret_type_it = - addend.module_->type_graph_.find(cfunction_like_ir->GetReturnType()); - if (ret_type_it != addend.module_->type_graph_.end()) { - // Merge the type if we can find another type in the parent module. - MergeStatus ret_merge_status = MergeType(ret_type_it->second, addend, - local_to_global_type_id_map); - cfunction_like_ir->SetReturnType(ret_merge_status.type_id_); - } - - // Merge the argument types. - for (auto ¶m : cfunction_like_ir->GetParameters()) { - MergeReferencingTypeInternal(addend, ¶m, local_to_global_type_id_map); - } -} - - -void IRReader::MergeFunctionDeps( - FunctionIR *added_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - MergeCFunctionLikeDeps(addend, added_node, local_to_global_type_id_map); - - // Merge the template arguments. - for (auto &template_element : added_node->GetTemplateElements()) { - MergeReferencingTypeInternal(addend, &template_element, - local_to_global_type_id_map); - } -} - - -template -static bool IsLinkableMessagePresent(const LinkableMessageIR *lm, - const AbiElementMap &message_map) { - return (message_map.find(lm->GetLinkerSetKey()) != message_map.end()); -} - - -void IRReader::MergeFunction( - const FunctionIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - const std::string &function_linkage_name = addend_node->GetLinkerSetKey(); - if (IsLinkableMessagePresent(addend_node, module_->functions_)) { - // The functions and all of its dependencies have already been added. - // No two globally visible functions can have the same symbol name. - return; - } - FunctionIR function_ir = *addend_node; - MergeFunctionDeps(&function_ir, addend, local_to_global_type_id_map); - // Add it to the parent's function map. - module_->functions_.emplace(function_linkage_name, std::move(function_ir)); -} - - -std::string IRReader::AllocateNewTypeId(const std::string &addend_type_id, - const ModuleIR &addend_module) { - return addend_type_id + "#ODR:" + addend_module.GetCompilationUnitPath(); -} - - -void IRReader::MergeGlobalVariable( - const GlobalVarIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map) { - const std::string &global_variable_linkage_name = - addend_node->GetLinkerSetKey(); - if (IsLinkableMessagePresent(addend_node, module_->global_variables_)) { - // The global variable and all of its dependencies have already been added. - return; - } - GlobalVarIR global_variable_ir = *addend_node; - MergeReferencingTypeInternal(addend, &global_variable_ir, - local_to_global_type_id_map); - module_->global_variables_.emplace( - global_variable_linkage_name, std::move(global_variable_ir)); -} - - -void IRReader::MergeGraphs(const IRReader &addend) { - // Iterate through nodes of addend reader and merge them. - // Keep a merged types cache since if a type is merged, so will all of its - // dependencies which weren't already merged. - AbiElementMap merged_types_cache; - - for (auto &&type_ir : addend.module_->type_graph_) { - MergeType(type_ir.second, addend, &merged_types_cache); - } - - for (auto &&function_ir : addend.module_->functions_) { - MergeFunction(&function_ir.second, addend, &merged_types_cache); - } - - for (auto &&global_var_ir : addend.module_->global_variables_) { - MergeGlobalVariable(&global_var_ir.second, addend, &merged_types_cache); - } -} - - } // namespace repr } // header_checker diff --git a/vndk/tools/header-checker/src/repr/ir_reader.h b/vndk/tools/header-checker/src/repr/ir_reader.h index a35418354..ecd64bbf3 100644 --- a/vndk/tools/header-checker/src/repr/ir_reader.h +++ b/vndk/tools/header-checker/src/repr/ir_reader.h @@ -17,12 +17,9 @@ #include "repr/ir_representation.h" -#include -#include #include #include #include -#include namespace header_checker { @@ -30,24 +27,6 @@ namespace repr { class IRReader { - public: - struct MergeStatus { - MergeStatus(bool was_newly_added, const std::string &type_id) - : was_newly_added_(was_newly_added), type_id_(type_id) {} - - MergeStatus() {} - - // type_id_ always has the global_type_id corresponding to the type this - // MergeStatus corresponds to. For - // generic reference types (pointers, qual types, l(r)value references etc), - // this will be a proactively added type_id, which will be added to the - // parent type_graph if the we decide to add the referencing type to the - // parent post ODR checking. - bool was_newly_added_ = false; - - std::string type_id_; - }; - public: static std::unique_ptr CreateIRReader( TextFormatIR text_format, @@ -68,112 +47,11 @@ class IRReader { return std::move(module_); } - void MergeGraphs(const IRReader &addend); - private: virtual bool ReadDumpImpl(const std::string &dump_file) = 0; - void MergeCFunctionLikeDeps( - const IRReader &addend, CFunctionLikeIR *cfunction_like_ir, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeFunctionType( - const FunctionTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeEnumType( - const EnumTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - void MergeEnumDependencies( - const IRReader &addend, EnumTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeRecordAndDependencies( - const RecordTypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - void MergeRecordDependencies( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map); - - void MergeRecordFields( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map); - - void MergeRecordCXXBases( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map); - - void MergeRecordTemplateElements( - const IRReader &addend, RecordTypeIR *added_node, - AbiElementMap *local_to_global_type_id_map); - - void MergeGlobalVariable( - const GlobalVarIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - void MergeGlobalVariables( - const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - void MergeFunctionDeps( - FunctionIR *added_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - void MergeFunction( - const FunctionIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - template - MergeStatus MergeReferencingTypeInternalAndUpdateParent( - const IRReader &addend, const T *addend_node, - AbiElementMap *local_to_global_type_id_map, - AbiElementMap *parent_map, const std::string &updated_self_type_id); - - MergeStatus MergeReferencingTypeInternal( - const IRReader &addend, ReferencesOtherType *references_type, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeReferencingType( - const IRReader &addend, const TypeIR *addend_node, - AbiElementMap *local_to_global_type_id_map); - - template - std::pair::iterator> - UpdateUDTypeAccounting( - const T *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map, - AbiElementMap *specific_type_map); - - MergeStatus MergeBuiltinType( - const BuiltinTypeIR *builtin_type, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus LookupUserDefinedType( - const TypeIR *ud_type, const IRReader &addend, - const std::string &ud_type_unique_id, - AbiElementMap *local_to_global_type_id_map_); - - MergeStatus LookupType( - const TypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeTypeInternal( - const TypeIR *addend_node, const IRReader &addend, - AbiElementMap *local_to_global_type_id_map); - - MergeStatus MergeType( - const TypeIR *addend_type, const IRReader &addend, - AbiElementMap *merged_types_cache); - - std::string AllocateNewTypeId(const std::string &addend_type_id, - const ModuleIR &addend_module); - protected: std::unique_ptr module_; - - uint64_t max_type_id_ = 0; };