Merge changes If6b35e94,I72a9502b,I0c1ce9d4,I73f12b2d
* changes: Look up referenced types' compilation unit paths when linking ABI dumps Store the sdump path for each type definition when linking ABI dumps Move the merge functions from IRReader to a new class Add a test case for merging multiple definitions
This commit is contained in:
@@ -110,6 +110,7 @@ cc_binary_host {
|
|||||||
|
|
||||||
srcs: [
|
srcs: [
|
||||||
"src/linker/header_abi_linker.cpp",
|
"src/linker/header_abi_linker.cpp",
|
||||||
|
"src/linker/module_merger.cpp",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "diff/abi_diff.h"
|
#include "diff/abi_diff.h"
|
||||||
|
|
||||||
|
#include "repr/ir_reader.h"
|
||||||
#include "utils/header_abi_util.h"
|
#include "utils/header_abi_util.h"
|
||||||
|
|
||||||
#include <llvm/Support/raw_ostream.h>
|
#include <llvm/Support/raw_ostream.h>
|
||||||
@@ -112,7 +113,7 @@ HeaderAbiDiff::ExtractUserDefinedTypes(const repr::ModuleIR &tu) {
|
|||||||
if (odr_list.size() != 1) {
|
if (odr_list.size() != 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const repr::TypeIR *type = *(odr_list.begin());
|
const repr::TypeIR *type = odr_list.begin()->type_ir_;
|
||||||
const repr::RecordTypeIR *record_type = nullptr;
|
const repr::RecordTypeIR *record_type = nullptr;
|
||||||
switch (type->GetKind()) {
|
switch (type->GetKind()) {
|
||||||
case repr::RecordTypeKind:
|
case repr::RecordTypeKind:
|
||||||
|
|||||||
@@ -12,9 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "repr/ir_representation.h"
|
#include "linker/module_merger.h"
|
||||||
#include "repr/ir_dumper.h"
|
#include "repr/ir_dumper.h"
|
||||||
#include "repr/ir_reader.h"
|
#include "repr/ir_reader.h"
|
||||||
|
#include "repr/ir_representation.h"
|
||||||
#include "repr/symbol/so_file_parser.h"
|
#include "repr/symbol/so_file_parser.h"
|
||||||
#include "repr/symbol/version_script_parser.h"
|
#include "repr/symbol/version_script_parser.h"
|
||||||
#include "utils/command_line_utils.h"
|
#include "utils/command_line_utils.h"
|
||||||
@@ -42,8 +43,6 @@ using header_checker::utils::CollectAllExportedHeaders;
|
|||||||
using header_checker::utils::HideIrrelevantCommandLineOptions;
|
using header_checker::utils::HideIrrelevantCommandLineOptions;
|
||||||
|
|
||||||
|
|
||||||
static constexpr std::size_t kSourcesPerBatchThread = 7;
|
|
||||||
|
|
||||||
static llvm::cl::OptionCategory header_linker_category(
|
static llvm::cl::OptionCategory header_linker_category(
|
||||||
"header-abi-linker options");
|
"header-abi-linker options");
|
||||||
|
|
||||||
@@ -104,6 +103,12 @@ static llvm::cl::opt<TextFormatIR> output_format(
|
|||||||
llvm::cl::init(TextFormatIR::Json),
|
llvm::cl::init(TextFormatIR::Json),
|
||||||
llvm::cl::cat(header_linker_category));
|
llvm::cl::cat(header_linker_category));
|
||||||
|
|
||||||
|
static llvm::cl::opt<std::size_t> sources_per_thread(
|
||||||
|
"sources-per-thread",
|
||||||
|
llvm::cl::desc("Specify number of input dump files each thread parses, for "
|
||||||
|
"debugging merging types"),
|
||||||
|
llvm::cl::init(7), llvm::cl::Hidden);
|
||||||
|
|
||||||
class HeaderAbiLinker {
|
class HeaderAbiLinker {
|
||||||
public:
|
public:
|
||||||
HeaderAbiLinker(
|
HeaderAbiLinker(
|
||||||
@@ -130,7 +135,7 @@ class HeaderAbiLinker {
|
|||||||
const repr::AbiElementMap<T> &src,
|
const repr::AbiElementMap<T> &src,
|
||||||
const std::function<bool(const std::string &)> &symbol_filter);
|
const std::function<bool(const std::string &)> &symbol_filter);
|
||||||
|
|
||||||
std::unique_ptr<repr::IRReader> ReadInputDumpFiles();
|
std::unique_ptr<repr::ModuleMerger> ReadInputDumpFiles();
|
||||||
|
|
||||||
bool ReadExportedSymbols();
|
bool ReadExportedSymbols();
|
||||||
|
|
||||||
@@ -138,11 +143,13 @@ class HeaderAbiLinker {
|
|||||||
|
|
||||||
bool ReadExportedSymbolsFromSharedObjectFile();
|
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);
|
bool LinkExportedSymbols(repr::ModuleIR *linked_module);
|
||||||
|
|
||||||
@@ -177,22 +184,22 @@ class HeaderAbiLinker {
|
|||||||
std::unique_ptr<repr::ExportedSymbolSet> version_script_symbols_;
|
std::unique_ptr<repr::ExportedSymbolSet> version_script_symbols_;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void DeDuplicateAbiElementsThread(
|
static void
|
||||||
const std::vector<std::string> &dump_files,
|
DeDuplicateAbiElementsThread(const std::vector<std::string> &dump_files,
|
||||||
const std::set<std::string> *exported_headers,
|
const std::set<std::string> *exported_headers,
|
||||||
repr::IRReader *greader, std::mutex *greader_lock,
|
repr::ModuleMerger *global_merger,
|
||||||
std::atomic<std::size_t> *cnt) {
|
std::mutex *global_merger_lock,
|
||||||
std::unique_ptr<repr::IRReader> local_reader =
|
std::atomic<std::size_t> *cnt) {
|
||||||
repr::IRReader::CreateIRReader(input_format, exported_headers);
|
repr::ModuleMerger local_merger(exported_headers);
|
||||||
|
|
||||||
auto begin_it = dump_files.begin();
|
auto begin_it = dump_files.begin();
|
||||||
std::size_t num_sources = dump_files.size();
|
std::size_t num_sources = dump_files.size();
|
||||||
while (1) {
|
while (1) {
|
||||||
std::size_t i = cnt->fetch_add(kSourcesPerBatchThread);
|
std::size_t i = cnt->fetch_add(sources_per_thread);
|
||||||
if (i >= num_sources) {
|
if (i >= num_sources) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::size_t end = std::min(i + kSourcesPerBatchThread, num_sources);
|
std::size_t end = std::min(i + sources_per_thread, num_sources);
|
||||||
for (auto it = begin_it + i; it != begin_it + end; it++) {
|
for (auto it = begin_it + i; it != begin_it + end; it++) {
|
||||||
std::unique_ptr<repr::IRReader> reader =
|
std::unique_ptr<repr::IRReader> reader =
|
||||||
repr::IRReader::CreateIRReader(input_format, exported_headers);
|
repr::IRReader::CreateIRReader(input_format, exported_headers);
|
||||||
@@ -201,37 +208,37 @@ static void DeDuplicateAbiElementsThread(
|
|||||||
llvm::errs() << "ReadDump failed\n";
|
llvm::errs() << "ReadDump failed\n";
|
||||||
::exit(1);
|
::exit(1);
|
||||||
}
|
}
|
||||||
local_reader->MergeGraphs(*reader);
|
local_merger.MergeGraphs(reader->GetModule());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(*greader_lock);
|
std::lock_guard<std::mutex> lock(*global_merger_lock);
|
||||||
greader->MergeGraphs(*local_reader);
|
global_merger->MergeGraphs(local_merger.GetModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<repr::IRReader>
|
std::unique_ptr<repr::ModuleMerger> HeaderAbiLinker::ReadInputDumpFiles() {
|
||||||
HeaderAbiLinker::ReadInputDumpFiles() {
|
std::unique_ptr<repr::ModuleMerger> merger(
|
||||||
std::unique_ptr<repr::IRReader> greader =
|
new repr::ModuleMerger(&exported_headers_));
|
||||||
repr::IRReader::CreateIRReader(input_format, &exported_headers_);
|
|
||||||
|
|
||||||
std::size_t max_threads = std::thread::hardware_concurrency();
|
std::size_t max_threads = std::thread::hardware_concurrency();
|
||||||
std::size_t num_threads = kSourcesPerBatchThread < dump_files_.size() ?
|
std::size_t num_threads =
|
||||||
std::min(dump_files_.size() / kSourcesPerBatchThread, max_threads) : 0;
|
sources_per_thread < dump_files_.size()
|
||||||
|
? std::min(dump_files_.size() / sources_per_thread, max_threads)
|
||||||
|
: 1;
|
||||||
std::vector<std::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
std::atomic<std::size_t> cnt(0);
|
std::atomic<std::size_t> cnt(0);
|
||||||
std::mutex greader_lock;
|
std::mutex merger_lock;
|
||||||
for (std::size_t i = 1; i < num_threads; i++) {
|
for (std::size_t i = 1; i < num_threads; i++) {
|
||||||
threads.emplace_back(DeDuplicateAbiElementsThread, dump_files_,
|
threads.emplace_back(DeDuplicateAbiElementsThread, dump_files_,
|
||||||
&exported_headers_, greader.get(), &greader_lock,
|
&exported_headers_, merger.get(), &merger_lock, &cnt);
|
||||||
&cnt);
|
|
||||||
}
|
}
|
||||||
DeDuplicateAbiElementsThread(dump_files_, &exported_headers_, greader.get(),
|
DeDuplicateAbiElementsThread(dump_files_, &exported_headers_, merger.get(),
|
||||||
&greader_lock, &cnt);
|
&merger_lock, &cnt);
|
||||||
for (auto &thread : threads) {
|
for (auto &thread : threads) {
|
||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
return greader;
|
return merger;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HeaderAbiLinker::LinkAndDump() {
|
bool HeaderAbiLinker::LinkAndDump() {
|
||||||
@@ -245,9 +252,9 @@ bool HeaderAbiLinker::LinkAndDump() {
|
|||||||
exported_headers_ = CollectAllExportedHeaders(exported_header_dirs_);
|
exported_headers_ = CollectAllExportedHeaders(exported_header_dirs_);
|
||||||
|
|
||||||
// Read all input ABI dumps.
|
// 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.
|
// Link input ABI dumps.
|
||||||
std::unique_ptr<repr::ModuleIR> linked_module(
|
std::unique_ptr<repr::ModuleIR> linked_module(
|
||||||
@@ -302,7 +309,7 @@ bool HeaderAbiLinker::LinkDecl(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HeaderAbiLinker::LinkTypes(repr::ModuleIR &module,
|
bool HeaderAbiLinker::LinkTypes(const repr::ModuleIR &module,
|
||||||
repr::ModuleIR *linked_module) {
|
repr::ModuleIR *linked_module) {
|
||||||
auto no_filter = [](const std::string &symbol) { return true; };
|
auto no_filter = [](const std::string &symbol) { return true; };
|
||||||
return LinkDecl(linked_module, module.GetRecordTypes(), no_filter) &&
|
return LinkDecl(linked_module, module.GetRecordTypes(), no_filter) &&
|
||||||
@@ -326,7 +333,7 @@ bool HeaderAbiLinker::IsSymbolExported(const std::string &name) const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HeaderAbiLinker::LinkFunctions(repr::ModuleIR &module,
|
bool HeaderAbiLinker::LinkFunctions(const repr::ModuleIR &module,
|
||||||
repr::ModuleIR *linked_module) {
|
repr::ModuleIR *linked_module) {
|
||||||
auto symbol_filter = [this](const std::string &linker_set_key) {
|
auto symbol_filter = [this](const std::string &linker_set_key) {
|
||||||
return IsSymbolExported(linker_set_key);
|
return IsSymbolExported(linker_set_key);
|
||||||
@@ -334,7 +341,7 @@ bool HeaderAbiLinker::LinkFunctions(repr::ModuleIR &module,
|
|||||||
return LinkDecl(linked_module, module.GetFunctions(), symbol_filter);
|
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) {
|
repr::ModuleIR *linked_module) {
|
||||||
auto symbol_filter = [this](const std::string &linker_set_key) {
|
auto symbol_filter = [this](const std::string &linker_set_key) {
|
||||||
return IsSymbolExported(linker_set_key);
|
return IsSymbolExported(linker_set_key);
|
||||||
|
|||||||
594
vndk/tools/header-checker/src/linker/module_merger.cpp
Normal file
594
vndk/tools/header-checker/src/linker/module_merger.cpp
Normal file
@@ -0,0 +1,594 @@
|
|||||||
|
// 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 <cassert>
|
||||||
|
|
||||||
|
#include <llvm/Support/raw_ostream.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace header_checker {
|
||||||
|
namespace repr {
|
||||||
|
|
||||||
|
|
||||||
|
MergeStatus ModuleMerger::MergeBuiltinType(
|
||||||
|
const BuiltinTypeIR *builtin_type, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *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<MergeStatus> *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<std::string> 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 &definition : it->second) {
|
||||||
|
const TypeIR *contender_ud = definition.type_ir_;
|
||||||
|
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()->type_ir_->GetSelfType());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MergeStatus ModuleMerger::LookupType(
|
||||||
|
const TypeIR *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
|
||||||
|
std::string unique_type_id;
|
||||||
|
switch (addend_node->GetKind()) {
|
||||||
|
case RecordTypeKind:
|
||||||
|
unique_type_id =
|
||||||
|
GetODRListMapKey(static_cast<const RecordTypeIR *>(addend_node));
|
||||||
|
break;
|
||||||
|
case EnumTypeKind:
|
||||||
|
unique_type_id =
|
||||||
|
GetODRListMapKey(static_cast<const EnumTypeIR *>(addend_node));
|
||||||
|
break;
|
||||||
|
case FunctionTypeKind:
|
||||||
|
unique_type_id =
|
||||||
|
GetODRListMapKey(static_cast<const FunctionTypeIR *>(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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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 <typename T>
|
||||||
|
std::pair<MergeStatus, typename AbiElementMap<T>::iterator>
|
||||||
|
ModuleMerger::UpdateUDTypeAccounting(
|
||||||
|
const T *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
|
||||||
|
AbiElementMap<T> *specific_type_map) {
|
||||||
|
const std::string addend_compilation_unit_path =
|
||||||
|
addend.GetCompilationUnitPath(addend_node);
|
||||||
|
assert(addend_compilation_unit_path != "");
|
||||||
|
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 = added_type_id + "#ODR:" + addend_compilation_unit_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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), addend_compilation_unit_path);
|
||||||
|
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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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 <typename T>
|
||||||
|
MergeStatus ModuleMerger::MergeReferencingTypeInternalAndUpdateParent(
|
||||||
|
const ModuleIR &addend, const T *addend_node,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
|
||||||
|
AbiElementMap<T> *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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool IsReferencingType(LinkableMessageKind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case PointerTypeKind:
|
||||||
|
case QualifiedTypeKind:
|
||||||
|
case ArrayTypeKind:
|
||||||
|
case LvalueReferenceTypeKind:
|
||||||
|
case RvalueReferenceTypeKind:
|
||||||
|
return true;
|
||||||
|
case RecordTypeKind:
|
||||||
|
case EnumTypeKind:
|
||||||
|
case BuiltinTypeKind:
|
||||||
|
case FunctionTypeKind:
|
||||||
|
case FunctionKind:
|
||||||
|
case GlobalVarKind:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Trace the referenced type until reaching a RecordTypeIR, EnumTypeIR,
|
||||||
|
// FunctionTypeIR, or BuiltinTypeIR. Return nullptr if the referenced type is
|
||||||
|
// undefined or built-in.
|
||||||
|
static const TypeIR *DereferenceType(const ModuleIR &module,
|
||||||
|
const TypeIR *type_ir) {
|
||||||
|
auto &type_graph = module.GetTypeGraph();
|
||||||
|
while (IsReferencingType(type_ir->GetKind())) {
|
||||||
|
auto it = type_graph.find(type_ir->GetReferencedType());
|
||||||
|
// The referenced type is undefined in the module.
|
||||||
|
if (it == type_graph.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
type_ir = it->second;
|
||||||
|
}
|
||||||
|
return type_ir;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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<MergeStatus> *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()) {
|
||||||
|
const TypeIR *final_referenced_type = DereferenceType(addend, addend_node);
|
||||||
|
if (final_referenced_type != nullptr) {
|
||||||
|
std::string compilation_unit_path =
|
||||||
|
addend.GetCompilationUnitPath(final_referenced_type);
|
||||||
|
// The path is empty for built-in types.
|
||||||
|
if (compilation_unit_path != "") {
|
||||||
|
added_type_id = added_type_id + "#ODR:" + compilation_unit_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<const PointerTypeIR *>(addend_node),
|
||||||
|
local_to_global_type_id_map, &module_->pointer_types_,
|
||||||
|
added_type_id);
|
||||||
|
case QualifiedTypeKind:
|
||||||
|
return MergeReferencingTypeInternalAndUpdateParent(
|
||||||
|
addend, static_cast<const QualifiedTypeIR *>(addend_node),
|
||||||
|
local_to_global_type_id_map, &module_->qualified_types_,
|
||||||
|
added_type_id);
|
||||||
|
case ArrayTypeKind:
|
||||||
|
return MergeReferencingTypeInternalAndUpdateParent(
|
||||||
|
addend, static_cast<const ArrayTypeIR *>(addend_node),
|
||||||
|
local_to_global_type_id_map, &module_->array_types_,
|
||||||
|
added_type_id);
|
||||||
|
case LvalueReferenceTypeKind:
|
||||||
|
return MergeReferencingTypeInternalAndUpdateParent(
|
||||||
|
addend, static_cast<const LvalueReferenceTypeIR *>(addend_node),
|
||||||
|
local_to_global_type_id_map, &module_->lvalue_reference_types_,
|
||||||
|
added_type_id);
|
||||||
|
case RvalueReferenceTypeKind:
|
||||||
|
return MergeReferencingTypeInternalAndUpdateParent(
|
||||||
|
addend, static_cast<const RvalueReferenceTypeIR *>(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<MergeStatus> *local_to_global_type_id_map) {
|
||||||
|
switch (addend_node->GetKind()) {
|
||||||
|
case BuiltinTypeKind:
|
||||||
|
return MergeBuiltinType(
|
||||||
|
static_cast<const BuiltinTypeIR *>(addend_node), addend,
|
||||||
|
local_to_global_type_id_map);
|
||||||
|
case RecordTypeKind:
|
||||||
|
return MergeRecordAndDependencies(
|
||||||
|
static_cast<const RecordTypeIR *>(addend_node), addend,
|
||||||
|
local_to_global_type_id_map);
|
||||||
|
case EnumTypeKind:
|
||||||
|
return MergeEnumType(
|
||||||
|
static_cast<const EnumTypeIR *>(addend_node), addend,
|
||||||
|
local_to_global_type_id_map);
|
||||||
|
case FunctionTypeKind:
|
||||||
|
return MergeFunctionType(
|
||||||
|
static_cast<const FunctionTypeIR *>(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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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 <typename T>
|
||||||
|
static bool IsLinkableMessagePresent(const LinkableMessageIR *lm,
|
||||||
|
const AbiElementMap<T> &message_map) {
|
||||||
|
return (message_map.find(lm->GetLinkerSetKey()) != message_map.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ModuleMerger::MergeFunction(
|
||||||
|
const FunctionIR *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ModuleMerger::MergeGlobalVariable(
|
||||||
|
const GlobalVarIR *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *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<MergeStatus> 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
|
||||||
|
|
||||||
155
vndk/tools/header-checker/src/linker/module_merger.h
Normal file
155
vndk/tools/header-checker/src/linker/module_merger.h
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
// 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<std::string> *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<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
MergeStatus MergeFunctionType(
|
||||||
|
const FunctionTypeIR *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
MergeStatus MergeEnumType(
|
||||||
|
const EnumTypeIR *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
void MergeEnumDependencies(
|
||||||
|
const ModuleIR &addend, EnumTypeIR *added_node,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
MergeStatus MergeRecordAndDependencies(
|
||||||
|
const RecordTypeIR *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
void MergeRecordDependencies(
|
||||||
|
const ModuleIR &addend, RecordTypeIR *added_node,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
void MergeRecordFields(
|
||||||
|
const ModuleIR &addend, RecordTypeIR *added_node,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
void MergeRecordCXXBases(
|
||||||
|
const ModuleIR &addend, RecordTypeIR *added_node,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
void MergeRecordTemplateElements(
|
||||||
|
const ModuleIR &addend, RecordTypeIR *added_node,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
void MergeGlobalVariable(
|
||||||
|
const GlobalVarIR *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
void MergeGlobalVariables(
|
||||||
|
const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
void MergeFunctionDeps(
|
||||||
|
FunctionIR *added_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
void MergeFunction(
|
||||||
|
const FunctionIR *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
MergeStatus MergeReferencingTypeInternalAndUpdateParent(
|
||||||
|
const ModuleIR &addend, const T *addend_node,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
|
||||||
|
AbiElementMap<T> *parent_map, const std::string &updated_self_type_id);
|
||||||
|
|
||||||
|
MergeStatus MergeReferencingTypeInternal(
|
||||||
|
const ModuleIR &addend, ReferencesOtherType *references_type,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
MergeStatus MergeReferencingType(
|
||||||
|
const ModuleIR &addend, const TypeIR *addend_node,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::pair<MergeStatus, typename AbiElementMap<T>::iterator>
|
||||||
|
UpdateUDTypeAccounting(
|
||||||
|
const T *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
|
||||||
|
AbiElementMap<T> *specific_type_map);
|
||||||
|
|
||||||
|
MergeStatus MergeBuiltinType(
|
||||||
|
const BuiltinTypeIR *builtin_type, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
MergeStatus LookupUserDefinedType(
|
||||||
|
const TypeIR *ud_type, const ModuleIR &addend,
|
||||||
|
const std::string &ud_type_unique_id,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map_);
|
||||||
|
|
||||||
|
MergeStatus LookupType(
|
||||||
|
const TypeIR *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
MergeStatus MergeTypeInternal(
|
||||||
|
const TypeIR *addend_node, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
||||||
|
|
||||||
|
MergeStatus MergeType(
|
||||||
|
const TypeIR *addend_type, const ModuleIR &addend,
|
||||||
|
AbiElementMap<MergeStatus> *merged_types_cache);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<ModuleIR> module_;
|
||||||
|
|
||||||
|
uint64_t max_type_id_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace repr
|
||||||
|
} // namespace header_checker
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
#include "repr/ir_diff_dumper.h"
|
#include "repr/ir_diff_dumper.h"
|
||||||
#include "repr/ir_diff_representation.h"
|
#include "repr/ir_diff_representation.h"
|
||||||
#include "repr/ir_reader.h"
|
|
||||||
#include "repr/ir_representation.h"
|
#include "repr/ir_representation.h"
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
@@ -30,8 +29,6 @@ namespace repr {
|
|||||||
// Classes which act as middle-men between clang AST parsing routines and
|
// Classes which act as middle-men between clang AST parsing routines and
|
||||||
// message format specific dumpers.
|
// message format specific dumpers.
|
||||||
|
|
||||||
using MergeStatus = IRReader::MergeStatus;
|
|
||||||
|
|
||||||
enum DiffStatus {
|
enum DiffStatus {
|
||||||
// There was no diff found while comparing types.
|
// There was no diff found while comparing types.
|
||||||
no_diff = 0,
|
no_diff = 0,
|
||||||
@@ -83,12 +80,10 @@ class AbiDiffHelper {
|
|||||||
const AbiElementMap<const TypeIR *> &new_types,
|
const AbiElementMap<const TypeIR *> &new_types,
|
||||||
const DiffPolicyOptions &diff_policy_options,
|
const DiffPolicyOptions &diff_policy_options,
|
||||||
std::set<std::string> *type_cache,
|
std::set<std::string> *type_cache,
|
||||||
IRDiffDumper *ir_diff_dumper = nullptr,
|
IRDiffDumper *ir_diff_dumper = nullptr)
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map = nullptr)
|
|
||||||
: old_types_(old_types), new_types_(new_types),
|
: old_types_(old_types), new_types_(new_types),
|
||||||
diff_policy_options_(diff_policy_options), type_cache_(type_cache),
|
diff_policy_options_(diff_policy_options), type_cache_(type_cache),
|
||||||
ir_diff_dumper_(ir_diff_dumper),
|
ir_diff_dumper_(ir_diff_dumper) {}
|
||||||
local_to_global_type_id_map_(local_to_global_type_id_map) {}
|
|
||||||
|
|
||||||
DiffStatus CompareAndDumpTypeDiff(
|
DiffStatus CompareAndDumpTypeDiff(
|
||||||
const std::string &old_type_str, const std::string &new_type_str,
|
const std::string &old_type_str, const std::string &new_type_str,
|
||||||
@@ -214,7 +209,6 @@ class AbiDiffHelper {
|
|||||||
const DiffPolicyOptions &diff_policy_options_;
|
const DiffPolicyOptions &diff_policy_options_;
|
||||||
std::set<std::string> *type_cache_;
|
std::set<std::string> *type_cache_;
|
||||||
IRDiffDumper *ir_diff_dumper_;
|
IRDiffDumper *ir_diff_dumper_;
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void ReplaceTypeIdsWithTypeNames(
|
void ReplaceTypeIdsWithTypeNames(
|
||||||
|
|||||||
@@ -14,9 +14,7 @@
|
|||||||
|
|
||||||
#include "repr/ir_reader.h"
|
#include "repr/ir_reader.h"
|
||||||
|
|
||||||
#include "repr/abi_diff_helpers.h"
|
|
||||||
#include "repr/ir_representation.h"
|
#include "repr/ir_representation.h"
|
||||||
#include "repr/ir_representation_internal.h"
|
|
||||||
#include "repr/json/api.h"
|
#include "repr/json/api.h"
|
||||||
#include "repr/protobuf/api.h"
|
#include "repr/protobuf/api.h"
|
||||||
|
|
||||||
@@ -32,9 +30,6 @@ namespace header_checker {
|
|||||||
namespace repr {
|
namespace repr {
|
||||||
|
|
||||||
|
|
||||||
using MergeStatus = IRReader::MergeStatus;
|
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<IRReader>
|
std::unique_ptr<IRReader>
|
||||||
IRReader::CreateIRReader(
|
IRReader::CreateIRReader(
|
||||||
TextFormatIR text_format, const std::set<std::string> *exported_headers) {
|
TextFormatIR text_format, const std::set<std::string> *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<MergeStatus> *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<MergeStatus> *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<std::string> 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<MergeStatus> *local_to_global_type_id_map) {
|
|
||||||
std::string unique_type_id;
|
|
||||||
switch (addend_node->GetKind()) {
|
|
||||||
case RecordTypeKind:
|
|
||||||
unique_type_id =
|
|
||||||
GetODRListMapKey(static_cast<const RecordTypeIR *>(addend_node));
|
|
||||||
break;
|
|
||||||
case EnumTypeKind:
|
|
||||||
unique_type_id =
|
|
||||||
GetODRListMapKey(static_cast<const EnumTypeIR *>(addend_node));
|
|
||||||
break;
|
|
||||||
case FunctionTypeKind:
|
|
||||||
unique_type_id =
|
|
||||||
GetODRListMapKey(static_cast<const FunctionTypeIR *>(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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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 <typename T>
|
|
||||||
std::pair<MergeStatus, typename AbiElementMap<T>::iterator>
|
|
||||||
IRReader::UpdateUDTypeAccounting(
|
|
||||||
const T *addend_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
|
|
||||||
AbiElementMap<T> *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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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 <typename T>
|
|
||||||
MergeStatus IRReader::MergeReferencingTypeInternalAndUpdateParent(
|
|
||||||
const IRReader &addend, const T *addend_node,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
|
|
||||||
AbiElementMap<T> *parent_map, const std::string &updated_self_type_id) {
|
|
||||||
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<MergeStatus> *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<const PointerTypeIR *>(addend_node),
|
|
||||||
local_to_global_type_id_map, &module_->pointer_types_,
|
|
||||||
added_type_id);
|
|
||||||
case QualifiedTypeKind:
|
|
||||||
return MergeReferencingTypeInternalAndUpdateParent(
|
|
||||||
addend, static_cast<const QualifiedTypeIR *>(addend_node),
|
|
||||||
local_to_global_type_id_map, &module_->qualified_types_,
|
|
||||||
added_type_id);
|
|
||||||
case ArrayTypeKind:
|
|
||||||
return MergeReferencingTypeInternalAndUpdateParent(
|
|
||||||
addend, static_cast<const ArrayTypeIR *>(addend_node),
|
|
||||||
local_to_global_type_id_map, &module_->array_types_,
|
|
||||||
added_type_id);
|
|
||||||
case LvalueReferenceTypeKind:
|
|
||||||
return MergeReferencingTypeInternalAndUpdateParent(
|
|
||||||
addend, static_cast<const LvalueReferenceTypeIR *>(addend_node),
|
|
||||||
local_to_global_type_id_map, &module_->lvalue_reference_types_,
|
|
||||||
added_type_id);
|
|
||||||
case RvalueReferenceTypeKind:
|
|
||||||
return MergeReferencingTypeInternalAndUpdateParent(
|
|
||||||
addend, static_cast<const RvalueReferenceTypeIR *>(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<MergeStatus> *local_to_global_type_id_map) {
|
|
||||||
switch (addend_node->GetKind()) {
|
|
||||||
case BuiltinTypeKind:
|
|
||||||
return MergeBuiltinType(
|
|
||||||
static_cast<const BuiltinTypeIR *>(addend_node), addend,
|
|
||||||
local_to_global_type_id_map);
|
|
||||||
case RecordTypeKind:
|
|
||||||
return MergeRecordAndDependencies(
|
|
||||||
static_cast<const RecordTypeIR *>(addend_node), addend,
|
|
||||||
local_to_global_type_id_map);
|
|
||||||
case EnumTypeKind:
|
|
||||||
return MergeEnumType(
|
|
||||||
static_cast<const EnumTypeIR *>(addend_node), addend,
|
|
||||||
local_to_global_type_id_map);
|
|
||||||
case FunctionTypeKind:
|
|
||||||
return MergeFunctionType(
|
|
||||||
static_cast<const FunctionTypeIR *>(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<MergeStatus> *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<MergeStatus> *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<MergeStatus> *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 <typename T>
|
|
||||||
static bool IsLinkableMessagePresent(const LinkableMessageIR *lm,
|
|
||||||
const AbiElementMap<T> &message_map) {
|
|
||||||
return (message_map.find(lm->GetLinkerSetKey()) != message_map.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void IRReader::MergeFunction(
|
|
||||||
const FunctionIR *addend_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *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<MergeStatus> *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<MergeStatus> 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
|
} // namespace repr
|
||||||
} // header_checker
|
} // header_checker
|
||||||
|
|||||||
@@ -17,12 +17,9 @@
|
|||||||
|
|
||||||
#include "repr/ir_representation.h"
|
#include "repr/ir_representation.h"
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <list>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
|
|
||||||
namespace header_checker {
|
namespace header_checker {
|
||||||
@@ -30,24 +27,6 @@ namespace repr {
|
|||||||
|
|
||||||
|
|
||||||
class IRReader {
|
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:
|
public:
|
||||||
static std::unique_ptr<IRReader> CreateIRReader(
|
static std::unique_ptr<IRReader> CreateIRReader(
|
||||||
TextFormatIR text_format,
|
TextFormatIR text_format,
|
||||||
@@ -68,112 +47,11 @@ class IRReader {
|
|||||||
return std::move(module_);
|
return std::move(module_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MergeGraphs(const IRReader &addend);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool ReadDumpImpl(const std::string &dump_file) = 0;
|
virtual bool ReadDumpImpl(const std::string &dump_file) = 0;
|
||||||
|
|
||||||
void MergeCFunctionLikeDeps(
|
|
||||||
const IRReader &addend, CFunctionLikeIR *cfunction_like_ir,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
MergeStatus MergeFunctionType(
|
|
||||||
const FunctionTypeIR *addend_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
MergeStatus MergeEnumType(
|
|
||||||
const EnumTypeIR *addend_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
void MergeEnumDependencies(
|
|
||||||
const IRReader &addend, EnumTypeIR *added_node,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
MergeStatus MergeRecordAndDependencies(
|
|
||||||
const RecordTypeIR *addend_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
void MergeRecordDependencies(
|
|
||||||
const IRReader &addend, RecordTypeIR *added_node,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
void MergeRecordFields(
|
|
||||||
const IRReader &addend, RecordTypeIR *added_node,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
void MergeRecordCXXBases(
|
|
||||||
const IRReader &addend, RecordTypeIR *added_node,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
void MergeRecordTemplateElements(
|
|
||||||
const IRReader &addend, RecordTypeIR *added_node,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
void MergeGlobalVariable(
|
|
||||||
const GlobalVarIR *addend_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
void MergeGlobalVariables(
|
|
||||||
const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
void MergeFunctionDeps(
|
|
||||||
FunctionIR *added_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
void MergeFunction(
|
|
||||||
const FunctionIR *addend_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
MergeStatus MergeReferencingTypeInternalAndUpdateParent(
|
|
||||||
const IRReader &addend, const T *addend_node,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
|
|
||||||
AbiElementMap<T> *parent_map, const std::string &updated_self_type_id);
|
|
||||||
|
|
||||||
MergeStatus MergeReferencingTypeInternal(
|
|
||||||
const IRReader &addend, ReferencesOtherType *references_type,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
MergeStatus MergeReferencingType(
|
|
||||||
const IRReader &addend, const TypeIR *addend_node,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
std::pair<MergeStatus, typename AbiElementMap<T>::iterator>
|
|
||||||
UpdateUDTypeAccounting(
|
|
||||||
const T *addend_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map,
|
|
||||||
AbiElementMap<T> *specific_type_map);
|
|
||||||
|
|
||||||
MergeStatus MergeBuiltinType(
|
|
||||||
const BuiltinTypeIR *builtin_type, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
MergeStatus LookupUserDefinedType(
|
|
||||||
const TypeIR *ud_type, const IRReader &addend,
|
|
||||||
const std::string &ud_type_unique_id,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map_);
|
|
||||||
|
|
||||||
MergeStatus LookupType(
|
|
||||||
const TypeIR *addend_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
MergeStatus MergeTypeInternal(
|
|
||||||
const TypeIR *addend_node, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *local_to_global_type_id_map);
|
|
||||||
|
|
||||||
MergeStatus MergeType(
|
|
||||||
const TypeIR *addend_type, const IRReader &addend,
|
|
||||||
AbiElementMap<MergeStatus> *merged_types_cache);
|
|
||||||
|
|
||||||
std::string AllocateNewTypeId(const std::string &addend_type_id,
|
|
||||||
const ModuleIR &addend_module);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<ModuleIR> module_;
|
std::unique_ptr<ModuleIR> module_;
|
||||||
|
|
||||||
uint64_t max_type_id_ = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ void ModuleIR::AddRecordType(RecordTypeIR &&record_type) {
|
|||||||
auto it = AddToMapAndTypeGraph(
|
auto it = AddToMapAndTypeGraph(
|
||||||
std::move(record_type), &record_types_, &type_graph_);
|
std::move(record_type), &record_types_, &type_graph_);
|
||||||
const std::string &key = GetODRListMapKey(&(it->second));
|
const std::string &key = GetODRListMapKey(&(it->second));
|
||||||
AddToODRListMap(key, &(it->second));
|
AddToODRListMap(key, &(it->second), compilation_unit_path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ void ModuleIR::AddFunctionType(FunctionTypeIR &&function_type) {
|
|||||||
auto it = AddToMapAndTypeGraph(
|
auto it = AddToMapAndTypeGraph(
|
||||||
std::move(function_type), &function_types_, &type_graph_);
|
std::move(function_type), &function_types_, &type_graph_);
|
||||||
const std::string &key = GetODRListMapKey(&(it->second));
|
const std::string &key = GetODRListMapKey(&(it->second));
|
||||||
AddToODRListMap(key, &(it->second));
|
AddToODRListMap(key, &(it->second), compilation_unit_path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ void ModuleIR::AddEnumType(EnumTypeIR &&enum_type) {
|
|||||||
auto it = AddToMapAndTypeGraph(
|
auto it = AddToMapAndTypeGraph(
|
||||||
std::move(enum_type), &enum_types_, &type_graph_);
|
std::move(enum_type), &enum_types_, &type_graph_);
|
||||||
const std::string &key = GetODRListMapKey(&(it->second));
|
const std::string &key = GetODRListMapKey(&(it->second));
|
||||||
AddToODRListMap(key, (&it->second));
|
AddToODRListMap(key, (&it->second), compilation_unit_path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -197,6 +197,34 @@ void ModuleIR::AddElfObject(ElfObjectIR &&elf_object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string ModuleIR::GetCompilationUnitPath(const TypeIR *type_ir) const {
|
||||||
|
std::string key;
|
||||||
|
switch (type_ir->GetKind()) {
|
||||||
|
case RecordTypeKind:
|
||||||
|
key = GetODRListMapKey(static_cast<const RecordTypeIR *>(type_ir));
|
||||||
|
break;
|
||||||
|
case EnumTypeKind:
|
||||||
|
key = GetODRListMapKey(static_cast<const EnumTypeIR *>(type_ir));
|
||||||
|
break;
|
||||||
|
case FunctionTypeKind:
|
||||||
|
key = GetODRListMapKey(static_cast<const FunctionTypeIR *>(type_ir));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
auto it = odr_list_map_.find(key);
|
||||||
|
if (it == odr_list_map_.end()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
for (const auto &definition : it->second) {
|
||||||
|
if (definition.type_ir_ == type_ir) {
|
||||||
|
return definition.compilation_unit_path_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ModuleIR::IsLinkableMessageInExportedHeaders(
|
bool ModuleIR::IsLinkableMessageInExportedHeaders(
|
||||||
const LinkableMessageIR *linkable_message) const {
|
const LinkableMessageIR *linkable_message) const {
|
||||||
if (exported_headers_ == nullptr || exported_headers_->empty()) {
|
if (exported_headers_ == nullptr || exported_headers_->empty()) {
|
||||||
|
|||||||
@@ -37,9 +37,6 @@ using AbiElementMap = std::map<std::string, T>;
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
using AbiElementUnorderedMap = std::unordered_map<std::string, T>;
|
using AbiElementUnorderedMap = std::unordered_map<std::string, T>;
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using AbiElementList = std::list<T>;
|
|
||||||
|
|
||||||
enum TextFormatIR {
|
enum TextFormatIR {
|
||||||
ProtobufTextFormat = 0,
|
ProtobufTextFormat = 0,
|
||||||
Json = 1,
|
Json = 1,
|
||||||
@@ -759,6 +756,16 @@ class ElfObjectIR : public ElfSymbolIR {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TypeDefinition {
|
||||||
|
public:
|
||||||
|
TypeDefinition(const TypeIR *type_ir,
|
||||||
|
const std::string *compilation_unit_path)
|
||||||
|
: type_ir_(type_ir), compilation_unit_path_(*compilation_unit_path) {}
|
||||||
|
|
||||||
|
const TypeIR *type_ir_;
|
||||||
|
const std::string &compilation_unit_path_;
|
||||||
|
};
|
||||||
|
|
||||||
class ModuleIR {
|
class ModuleIR {
|
||||||
public:
|
public:
|
||||||
ModuleIR(const std::set<std::string> *exported_headers)
|
ModuleIR(const std::set<std::string> *exported_headers)
|
||||||
@@ -828,7 +835,7 @@ class ModuleIR {
|
|||||||
return type_graph_;
|
return type_graph_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AbiElementUnorderedMap<std::list<const TypeIR *>> &
|
const AbiElementUnorderedMap<std::list<TypeDefinition>> &
|
||||||
GetODRListMap() const {
|
GetODRListMap() const {
|
||||||
return odr_list_map_;
|
return odr_list_map_;
|
||||||
}
|
}
|
||||||
@@ -864,10 +871,19 @@ class ModuleIR {
|
|||||||
|
|
||||||
void AddElfObject(ElfObjectIR &&elf_object);
|
void AddElfObject(ElfObjectIR &&elf_object);
|
||||||
|
|
||||||
void AddToODRListMap(const std::string &key, const TypeIR *value) {
|
// Find the compilation unit path of a RecordTypeIR, FunctionTypeIR, or
|
||||||
|
// EnumTypeIR in odr_list_map_. Return an empty string if the type is not in
|
||||||
|
// the map.
|
||||||
|
std::string GetCompilationUnitPath(const TypeIR *type_ir) const;
|
||||||
|
|
||||||
|
void AddToODRListMap(const std::string &key, const TypeIR *type_ir,
|
||||||
|
const std::string &compilation_unit_path) {
|
||||||
|
auto compilation_unit_path_it =
|
||||||
|
compilation_unit_paths_.emplace(compilation_unit_path).first;
|
||||||
auto map_it = odr_list_map_.find(key);
|
auto map_it = odr_list_map_.find(key);
|
||||||
|
TypeDefinition value(type_ir, &*compilation_unit_path_it);
|
||||||
if (map_it == odr_list_map_.end()) {
|
if (map_it == odr_list_map_.end()) {
|
||||||
odr_list_map_.emplace(key, std::list<const TypeIR *>({value}));
|
odr_list_map_.emplace(key, std::list<TypeDefinition>({value}));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
odr_list_map_[key].emplace_back(value);
|
odr_list_map_[key].emplace_back(value);
|
||||||
@@ -883,7 +899,6 @@ class ModuleIR {
|
|||||||
// File path to the compilation unit (*.sdump)
|
// File path to the compilation unit (*.sdump)
|
||||||
std::string compilation_unit_path_;
|
std::string compilation_unit_path_;
|
||||||
|
|
||||||
AbiElementList<RecordTypeIR> record_types_list_;
|
|
||||||
AbiElementMap<FunctionIR> functions_;
|
AbiElementMap<FunctionIR> functions_;
|
||||||
AbiElementMap<GlobalVarIR> global_variables_;
|
AbiElementMap<GlobalVarIR> global_variables_;
|
||||||
AbiElementMap<RecordTypeIR> record_types_;
|
AbiElementMap<RecordTypeIR> record_types_;
|
||||||
@@ -904,8 +919,13 @@ class ModuleIR {
|
|||||||
AbiElementMap<ElfObjectIR> elf_objects_;
|
AbiElementMap<ElfObjectIR> elf_objects_;
|
||||||
// type-id -> LinkableMessageIR * map
|
// type-id -> LinkableMessageIR * map
|
||||||
AbiElementMap<const TypeIR *> type_graph_;
|
AbiElementMap<const TypeIR *> type_graph_;
|
||||||
// maps unique_id + source_file -> const TypeIR *
|
// maps unique_id + source_file -> TypeDefinition
|
||||||
AbiElementUnorderedMap<std::list<const TypeIR *>> odr_list_map_;
|
AbiElementUnorderedMap<std::list<TypeDefinition>> odr_list_map_;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The compilation unit paths referenced by odr_list_map_;
|
||||||
|
std::set<std::string> compilation_unit_paths_;
|
||||||
const std::set<std::string> *exported_headers_;
|
const std::set<std::string> *exported_headers_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extern char var;
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
|
Struct *member1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Opaque;
|
||||||
|
|
||||||
|
void func(const struct Struct *, const struct Opaque *);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
extern int var;
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
|
Struct *member2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Opaque;
|
||||||
|
|
||||||
|
void func(const struct Opaque *, const struct Struct *);
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
libmerge_multi_definitions {
|
||||||
|
global:
|
||||||
|
func;
|
||||||
|
var;
|
||||||
|
};
|
||||||
@@ -9,7 +9,6 @@ import_path = os.path.abspath(os.path.join(import_path, 'utils'))
|
|||||||
sys.path.insert(1, import_path)
|
sys.path.insert(1, import_path)
|
||||||
|
|
||||||
from utils import run_header_abi_dumper
|
from utils import run_header_abi_dumper
|
||||||
from utils import run_header_abi_dumper_on_file
|
|
||||||
from utils import run_header_abi_linker
|
from utils import run_header_abi_linker
|
||||||
from utils import SOURCE_ABI_DUMP_EXT
|
from utils import SOURCE_ABI_DUMP_EXT
|
||||||
|
|
||||||
@@ -125,13 +124,15 @@ class LsdumpModule(Module):
|
|||||||
output_path = os.path.join(tmp,
|
output_path = os.path.join(tmp,
|
||||||
os.path.basename(src) + '.sdump')
|
os.path.basename(src) + '.sdump')
|
||||||
dumps_to_link.append(output_path)
|
dumps_to_link.append(output_path)
|
||||||
run_header_abi_dumper_on_file(
|
content = run_header_abi_dumper(
|
||||||
src, output_path, self.export_include_dirs,
|
src, self.cflags + self.arch_cflags,
|
||||||
self.cflags + self.arch_cflags,
|
self.export_include_dirs, self.dumper_flags)
|
||||||
self.dumper_flags)
|
with open(output_path, 'w') as dump_file:
|
||||||
|
dump_file.write(content)
|
||||||
return run_header_abi_linker(output_lsdump, dumps_to_link,
|
return run_header_abi_linker(output_lsdump, dumps_to_link,
|
||||||
self.version_script, self.api,
|
self.version_script, self.api,
|
||||||
self.arch, self.linker_flags)
|
self.arch, self.linker_flags,
|
||||||
|
input_dir=tmp)
|
||||||
|
|
||||||
def mutate_for_arch(self, target_arch):
|
def mutate_for_arch(self, target_arch):
|
||||||
return LsdumpModule(self.name, self.srcs, self.version_script,
|
return LsdumpModule(self.name, self.srcs, self.version_script,
|
||||||
@@ -642,6 +643,17 @@ TEST_MODULES = [
|
|||||||
export_include_dirs=['integration/cpp/anonymous_enum/include'],
|
export_include_dirs=['integration/cpp/anonymous_enum/include'],
|
||||||
linker_flags=['-output-format', 'Json'],
|
linker_flags=['-output-format', 'Json'],
|
||||||
),
|
),
|
||||||
|
LsdumpModule(
|
||||||
|
name='libmerge_multi_definitions',
|
||||||
|
arch='arm64',
|
||||||
|
srcs=[
|
||||||
|
'integration/merge_multi_definitions/include/def1.h',
|
||||||
|
'integration/merge_multi_definitions/include/def2.h',
|
||||||
|
],
|
||||||
|
version_script='integration/merge_multi_definitions/map.txt',
|
||||||
|
export_include_dirs=['integration/merge_multi_definitions/include'],
|
||||||
|
linker_flags=['-output-format', 'Json', '-sources-per-thread', '1'],
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
TEST_MODULES = {m.name: m for m in TEST_MODULES}
|
TEST_MODULES = {m.name: m for m in TEST_MODULES}
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
{
|
||||||
|
"array_types" : [],
|
||||||
|
"builtin_types" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"alignment" : 1,
|
||||||
|
"is_integral" : true,
|
||||||
|
"is_unsigned" : true,
|
||||||
|
"linker_set_key" : "_ZTIc",
|
||||||
|
"name" : "char",
|
||||||
|
"referenced_type" : "_ZTIc",
|
||||||
|
"self_type" : "_ZTIc",
|
||||||
|
"size" : 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alignment" : 4,
|
||||||
|
"is_integral" : true,
|
||||||
|
"linker_set_key" : "_ZTIi",
|
||||||
|
"name" : "int",
|
||||||
|
"referenced_type" : "_ZTIi",
|
||||||
|
"self_type" : "_ZTIi",
|
||||||
|
"size" : 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"linker_set_key" : "_ZTIv",
|
||||||
|
"name" : "void",
|
||||||
|
"referenced_type" : "_ZTIv",
|
||||||
|
"self_type" : "_ZTIv"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"elf_functions" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name" : "func"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "var"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"elf_objects" : [],
|
||||||
|
"enum_types" : [],
|
||||||
|
"function_types" : [],
|
||||||
|
"functions" : [],
|
||||||
|
"global_vars" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"linker_set_key" : "var",
|
||||||
|
"name" : "var",
|
||||||
|
"referenced_type" : "_ZTIc",
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lvalue_reference_types" : [],
|
||||||
|
"pointer_types" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"alignment" : 8,
|
||||||
|
"linker_set_key" : "_ZTIP6Struct",
|
||||||
|
"name" : "Struct *",
|
||||||
|
"referenced_type" : "_ZTI6Struct",
|
||||||
|
"self_type" : "_ZTIP6Struct",
|
||||||
|
"size" : 8,
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alignment" : 8,
|
||||||
|
"linker_set_key" : "_ZTIP6Struct",
|
||||||
|
"name" : "Struct *",
|
||||||
|
"referenced_type" : "_ZTI6Struct#ODR:/def2.h.sdump",
|
||||||
|
"self_type" : "_ZTIP6Struct#ODR:/def2.h.sdump",
|
||||||
|
"size" : 8,
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alignment" : 8,
|
||||||
|
"linker_set_key" : "_ZTIPK6Opaque",
|
||||||
|
"name" : "const Opaque *",
|
||||||
|
"referenced_type" : "_ZTIK6Opaque",
|
||||||
|
"self_type" : "_ZTIPK6Opaque",
|
||||||
|
"size" : 8,
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alignment" : 8,
|
||||||
|
"linker_set_key" : "_ZTIPK6Struct",
|
||||||
|
"name" : "const Struct *",
|
||||||
|
"referenced_type" : "_ZTIK6Struct",
|
||||||
|
"self_type" : "_ZTIPK6Struct",
|
||||||
|
"size" : 8,
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alignment" : 8,
|
||||||
|
"linker_set_key" : "_ZTIPK6Struct",
|
||||||
|
"name" : "const Struct *",
|
||||||
|
"referenced_type" : "_ZTIK6Struct#ODR:/def2.h.sdump",
|
||||||
|
"self_type" : "_ZTIPK6Struct#ODR:/def2.h.sdump",
|
||||||
|
"size" : 8,
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"qualified_types" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"is_const" : true,
|
||||||
|
"linker_set_key" : "_ZTIK6Opaque",
|
||||||
|
"name" : "const Opaque",
|
||||||
|
"referenced_type" : "_ZTI6Opaque",
|
||||||
|
"self_type" : "_ZTIK6Opaque",
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alignment" : 8,
|
||||||
|
"is_const" : true,
|
||||||
|
"linker_set_key" : "_ZTIK6Struct",
|
||||||
|
"name" : "const Struct",
|
||||||
|
"referenced_type" : "_ZTI6Struct#ODR:/def2.h.sdump",
|
||||||
|
"self_type" : "_ZTIK6Struct#ODR:/def2.h.sdump",
|
||||||
|
"size" : 8,
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alignment" : 8,
|
||||||
|
"is_const" : true,
|
||||||
|
"linker_set_key" : "_ZTIK6Struct",
|
||||||
|
"name" : "const Struct",
|
||||||
|
"referenced_type" : "_ZTI6Struct",
|
||||||
|
"self_type" : "_ZTIK6Struct",
|
||||||
|
"size" : 8,
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"record_types" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"alignment" : 8,
|
||||||
|
"fields" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"field_name" : "member1",
|
||||||
|
"referenced_type" : "_ZTIP6Struct"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"linker_set_key" : "_ZTI6Struct",
|
||||||
|
"name" : "Struct",
|
||||||
|
"referenced_type" : "_ZTI6Struct",
|
||||||
|
"self_type" : "_ZTI6Struct",
|
||||||
|
"size" : 8,
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def1.h"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alignment" : 8,
|
||||||
|
"fields" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"field_name" : "member2",
|
||||||
|
"referenced_type" : "_ZTIP6Struct#ODR:/def2.h.sdump"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"linker_set_key" : "_ZTI6Struct",
|
||||||
|
"name" : "Struct",
|
||||||
|
"referenced_type" : "_ZTI6Struct#ODR:/def2.h.sdump",
|
||||||
|
"self_type" : "_ZTI6Struct#ODR:/def2.h.sdump",
|
||||||
|
"size" : 8,
|
||||||
|
"source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rvalue_reference_types" : []
|
||||||
|
}
|
||||||
@@ -376,6 +376,10 @@ class HeaderCheckerTest(unittest.TestCase):
|
|||||||
self.prepare_and_absolute_diff_all_archs(
|
self.prepare_and_absolute_diff_all_archs(
|
||||||
"libifunc", "libifunc")
|
"libifunc", "libifunc")
|
||||||
|
|
||||||
|
def test_merge_multi_definitions(self):
|
||||||
|
self.prepare_and_absolute_diff_all_archs(
|
||||||
|
"libmerge_multi_definitions", "libmerge_multi_definitions")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@@ -109,14 +109,14 @@ def run_header_abi_dumper(input_path, cflags=tuple(),
|
|||||||
output."""
|
output."""
|
||||||
with tempfile.TemporaryDirectory() as tmp:
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
output_path = os.path.join(tmp, os.path.basename(input_path)) + '.dump'
|
output_path = os.path.join(tmp, os.path.basename(input_path)) + '.dump'
|
||||||
run_header_abi_dumper_on_file(input_path, output_path,
|
_run_header_abi_dumper_on_file(input_path, output_path,
|
||||||
export_include_dirs, cflags, flags)
|
export_include_dirs, cflags, flags)
|
||||||
return read_output_content(output_path, AOSP_DIR)
|
return read_output_content(output_path, AOSP_DIR)
|
||||||
|
|
||||||
|
|
||||||
def run_header_abi_dumper_on_file(input_path, output_path,
|
def _run_header_abi_dumper_on_file(input_path, output_path,
|
||||||
export_include_dirs=tuple(), cflags=tuple(),
|
export_include_dirs=tuple(), cflags=tuple(),
|
||||||
flags=tuple()):
|
flags=tuple()):
|
||||||
"""Run header-abi-dumper to dump ABI from `input_path` and the output is
|
"""Run header-abi-dumper to dump ABI from `input_path` and the output is
|
||||||
written to `output_path`."""
|
written to `output_path`."""
|
||||||
input_ext = os.path.splitext(input_path)[1]
|
input_ext = os.path.splitext(input_path)[1]
|
||||||
@@ -144,7 +144,7 @@ def run_header_abi_dumper_on_file(input_path, output_path,
|
|||||||
|
|
||||||
|
|
||||||
def run_header_abi_linker(output_path, inputs, version_script, api, arch,
|
def run_header_abi_linker(output_path, inputs, version_script, api, arch,
|
||||||
flags=tuple()):
|
flags=tuple(), input_dir=AOSP_DIR):
|
||||||
"""Link inputs, taking version_script into account"""
|
"""Link inputs, taking version_script into account"""
|
||||||
cmd = ['header-abi-linker', '-o', output_path, '-v', version_script,
|
cmd = ['header-abi-linker', '-o', output_path, '-v', version_script,
|
||||||
'-api', api, '-arch', arch]
|
'-api', api, '-arch', arch]
|
||||||
@@ -155,7 +155,7 @@ def run_header_abi_linker(output_path, inputs, version_script, api, arch,
|
|||||||
cmd += ['-output-format', DEFAULT_FORMAT]
|
cmd += ['-output-format', DEFAULT_FORMAT]
|
||||||
cmd += inputs
|
cmd += inputs
|
||||||
subprocess.check_call(cmd)
|
subprocess.check_call(cmd)
|
||||||
return read_output_content(output_path, AOSP_DIR)
|
return read_output_content(output_path, input_dir)
|
||||||
|
|
||||||
|
|
||||||
def make_targets(product, variant, targets):
|
def make_targets(product, variant, targets):
|
||||||
|
|||||||
Reference in New Issue
Block a user