Merge "Determine struct extensions before calling IRDiffDumper" am: 25a02ee161

Original change: https://android-review.googlesource.com/c/platform/development/+/2363619

Change-Id: I008131f0e8f256fac8176385bf3d474b22357ffc
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Hsin-Yi Chen
2022-12-30 10:48:28 +00:00
committed by Automerger Merge Worker
5 changed files with 135 additions and 201 deletions

View File

@@ -143,7 +143,6 @@ cc_library_host_static {
srcs: [
"src/repr/abi_diff_helpers.cpp",
"src/repr/ir_diff_dumper.cpp",
"src/repr/ir_diff_representation.cpp",
"src/repr/ir_dumper.cpp",
"src/repr/ir_reader.cpp",
"src/repr/ir_representation.cpp",

View File

@@ -220,9 +220,8 @@ static std::string RemoveThunkInfoFromMangledName(const std::string &name) {
return "_Z" + name.substr(base_name_pos);
}
bool AbiDiffHelper::CompareVTableComponents(
const VTableComponentIR &old_component,
const VTableComponentIR &new_component) {
static bool CompareVTableComponents(const VTableComponentIR &old_component,
const VTableComponentIR &new_component) {
// Vtable components in prebuilts/abi-dumps/vndk/28 don't have thunk info.
if (old_component.GetName() != new_component.GetName()) {
if (RemoveThunkInfoFromMangledName(old_component.GetName()) ==
@@ -238,14 +237,9 @@ bool AbiDiffHelper::CompareVTableComponents(
old_component.GetKind() == new_component.GetKind();
}
bool AbiDiffHelper::CompareVTables(
const RecordTypeIR *old_record,
const RecordTypeIR *new_record) {
const std::vector<VTableComponentIR> &old_components =
old_record->GetVTableLayout().GetVTableComponents();
const std::vector<VTableComponentIR> &new_components =
new_record->GetVTableLayout().GetVTableComponents();
static bool CompareVTables(
const std::vector<VTableComponentIR> &old_components,
const std::vector<VTableComponentIR> &new_components) {
if (old_components.size() != new_components.size()) {
return false;
}
@@ -257,6 +251,97 @@ bool AbiDiffHelper::CompareVTables(
return true;
}
static inline bool IsVOffset(VTableComponentIR::Kind kind) {
return kind == VTableComponentIR::VBaseOffset ||
kind == VTableComponentIR::VCallOffset;
}
static inline bool IsFunctionPointer(VTableComponentIR::Kind kind) {
return kind == VTableComponentIR::FunctionPointer ||
kind == VTableComponentIR::CompleteDtorPointer ||
kind == VTableComponentIR::DeletingDtorPointer;
}
// A Vtable consists of one or more sub-vtables. Each sub-vtable is a sequence
// of components in the following order:
// Zero or more VCallOffset or VBaseOffset.
// One OffsetToTop.
// One RTTI.
// Zero or more FunctionPointer, CompleteDtorPointer, or DeletingDtorPointer.
//
// An object's vtable pointer points to the next component of the RTTI
// component. Hence, new components can be appended or prepended to sub-vtables
// without breaking compatibility.
static bool IsVTableExtended(
const std::vector<VTableComponentIR> &old_components,
const std::vector<VTableComponentIR> &new_components) {
const auto old_end = old_components.end();
const auto new_end = new_components.end();
auto old_it = old_components.begin();
auto new_it = new_components.begin();
bool is_extended = false;
while (old_it != old_end) {
const auto old_begin = old_it;
const auto new_begin = new_it;
// Iterate VCallOffset and VBaseOffset.
while (old_it != old_end && IsVOffset(old_it->GetKind())) {
old_it++;
}
while (new_it != new_end && IsVOffset(new_it->GetKind())) {
new_it++;
}
// Compare VCallOffset and VBaseOffset.
auto old_back_it = old_it;
auto new_back_it = new_it;
while (old_back_it != old_begin) {
if (new_back_it == new_begin) {
return false;
}
old_back_it--;
new_back_it--;
if (old_back_it->GetKind() != new_back_it->GetKind()) {
return false;
}
}
// The new sub-vtable has additional VOffsets at the beginning.
if (new_back_it != new_begin) {
is_extended = true;
}
// Compare OffsetToTop.
if (old_it == old_end || new_it == new_end ||
old_it->GetKind() != VTableComponentIR::OffsetToTop ||
new_it->GetKind() != VTableComponentIR::OffsetToTop) {
return false;
}
old_it++;
new_it++;
// Compare RTTI.
if (old_it == old_end || new_it == new_end ||
old_it->GetKind() != VTableComponentIR::RTTI ||
new_it->GetKind() != VTableComponentIR::RTTI ||
old_it->GetName() != new_it->GetName()) {
return false;
}
old_it++;
new_it++;
// Compare function pointers.
while (old_it != old_end && IsFunctionPointer(old_it->GetKind())) {
if (new_it == new_end || old_it->GetKind() != new_it->GetKind() ||
old_it->GetName() != new_it->GetName()) {
return false;
}
old_it++;
new_it++;
}
// The new sub-vtable has additional function pointers at the end.
while (new_it != new_end && IsFunctionPointer(new_it->GetKind())) {
is_extended = true;
new_it++;
}
}
return new_it == new_end ? is_extended : false;
}
bool AbiDiffHelper::AreOpaqueTypesEqual(const std::string &old_type_id,
const std::string &new_type_id) const {
// b/253095767: In T, some dump files contain opaque types whose IDs end with
@@ -391,13 +476,18 @@ AbiDiffHelper::CompareRecordFields(
std::move(*(diffed_field_ptr.second.release())));
}
}
DiffStatus &diff_status = diffed_removed_added_fields.diff_status_;
diff_status = DiffStatus::kNoDiff;
if (diffed_removed_added_fields.diffed_fields_.size() != 0 ||
diffed_removed_added_fields.removed_fields_.size() != 0) {
diffed_removed_added_fields.diff_status_ = DiffStatus::kDirectDiff;
} else if (common_field_diff_exists) {
diffed_removed_added_fields.diff_status_ = DiffStatus::kIndirectDiff;
} else {
diffed_removed_added_fields.diff_status_ = DiffStatus::kNoDiff;
diff_status.CombineWith(DiffStatus::kDirectDiff);
}
if (diffed_removed_added_fields.added_fields_.size() != 0) {
diff_status.CombineWith(DiffStatus::kDirectExt);
}
if (common_field_diff_exists) {
diff_status.CombineWith(DiffStatus::kIndirectDiff);
}
return diffed_removed_added_fields;
}
@@ -533,44 +623,58 @@ DiffStatus AbiDiffHelper::CompareRecordTypes(
DiffStatus final_diff_status = DiffStatus::kNoDiff;
record_type_diff_ir->SetName(old_type->GetName());
record_type_diff_ir->SetLinkerSetKey(old_type->GetLinkerSetKey());
if (IsAccessDowngraded(old_type->GetAccess(), new_type->GetAccess())) {
final_diff_status.CombineWith(DiffStatus::kIndirectDiff);
final_diff_status.CombineWith(DiffStatus::kDirectDiff);
record_type_diff_ir->SetAccessDiff(
std::make_unique<AccessSpecifierDiffIR>(
old_type->GetAccess(), new_type->GetAccess()));
}
if (!CompareSizeAndAlignment(old_type, new_type)) {
final_diff_status.CombineWith(DiffStatus::kIndirectDiff);
if (old_type->GetSize() < new_type->GetSize() &&
old_type->GetAlignment() == new_type->GetAlignment()) {
final_diff_status.CombineWith(DiffStatus::kDirectExt);
} else {
final_diff_status.CombineWith(DiffStatus::kDirectDiff);
}
record_type_diff_ir->SetTypeDiff(
std::make_unique<TypeDiffIR>(
std::make_pair(old_type->GetSize(), new_type->GetSize()),
std::make_pair(old_type->GetAlignment(),
new_type->GetAlignment())));
}
if (!CompareVTables(old_type, new_type)) {
final_diff_status.CombineWith(DiffStatus::kIndirectDiff);
const std::vector<VTableComponentIR> &old_vtable =
old_type->GetVTableLayout().GetVTableComponents();
const std::vector<VTableComponentIR> &new_vtable =
new_type->GetVTableLayout().GetVTableComponents();
if (!CompareVTables(old_vtable, new_vtable)) {
if (IsVTableExtended(old_vtable, new_vtable)) {
final_diff_status.CombineWith(DiffStatus::kDirectExt);
} else {
final_diff_status.CombineWith(DiffStatus::kDirectDiff);
}
record_type_diff_ir->SetVTableLayoutDiff(
std::make_unique<VTableLayoutDiffIR>(
old_type->GetVTableLayout(), new_type->GetVTableLayout()));
}
auto &old_fields_dup = old_type->GetFields();
auto &new_fields_dup = new_type->GetFields();
auto field_status_and_diffs = CompareRecordFields(
old_fields_dup, new_fields_dup, type_queue, diff_kind);
// TODO: Combine this with base class diffs as well.
final_diff_status.CombineWith(field_status_and_diffs.diff_status_);
std::vector<CXXBaseSpecifierIR> old_bases = old_type->GetBases();
std::vector<CXXBaseSpecifierIR> new_bases = new_type->GetBases();
if (!CompareBaseSpecifiers(old_bases, new_bases, type_queue, diff_kind) &&
ir_diff_dumper_) {
final_diff_status.CombineWith(DiffStatus::kDirectDiff);
ReplaceReferencesOtherTypeIdWithName(old_types_, old_bases);
ReplaceReferencesOtherTypeIdWithName(new_types_, new_bases);
record_type_diff_ir->SetBaseSpecifierDiffs (
std::make_unique<CXXBaseSpecifierDiffIR>(old_bases,
new_bases));
record_type_diff_ir->SetBaseSpecifierDiffs(
std::make_unique<CXXBaseSpecifierDiffIR>(old_bases, new_bases));
}
if (ir_diff_dumper_) {
// Make copies of the fields removed and diffed, since we have to change
@@ -596,8 +700,9 @@ DiffStatus AbiDiffHelper::CompareRecordTypes(
record_type_diff_ir->SetFieldDiffs(std::move(field_diffs_fixed));
record_type_diff_ir->SetFieldsRemoved(std::move(fields_removed_fixed));
record_type_diff_ir->SetFieldsAdded(std::move(fields_added_fixed));
record_type_diff_ir->SetExtended(final_diff_status.IsExtension());
if (record_type_diff_ir->DiffExists() &&
if (final_diff_status.IsDirectDiff() &&
!ir_diff_dumper_->AddDiffMessageIR(record_type_diff_ir.get(),
Unwind(type_queue), diff_kind)) {
llvm::errs() << "AddDiffMessage on record type failed\n";

View File

@@ -197,13 +197,6 @@ class AbiDiffHelper {
std::deque<std::string> *type_queue,
IRDiffDumper::DiffKind diff_kind);
bool CompareVTables(const RecordTypeIR *old_record,
const RecordTypeIR *new_record);
bool CompareVTableComponents(
const VTableComponentIR &old_component,
const VTableComponentIR &new_component);
DiffStatus CompareFunctionParameters(
const std::vector<ParamIR> &old_parameters,
const std::vector<ParamIR> &new_parameters,

View File

@@ -1,157 +0,0 @@
// Copyright (C) 2022 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_diff_representation.h"
namespace header_checker {
namespace repr {
static inline bool IsVOffset(VTableComponentIR::Kind kind) {
return kind == VTableComponentIR::VBaseOffset ||
kind == VTableComponentIR::VCallOffset;
}
static inline bool IsFunctionPointer(VTableComponentIR::Kind kind) {
return kind == VTableComponentIR::FunctionPointer ||
kind == VTableComponentIR::CompleteDtorPointer ||
kind == VTableComponentIR::DeletingDtorPointer;
}
// A Vtable consists of one or more sub-vtables. Each sub-vtable is a sequence
// of components in the following order:
// Zero or more VCallOffset or VBaseOffset.
// One OffsetToTop.
// One RTTI.
// Zero or more FunctionPointer, CompleteDtorPointer, or DeletingDtorPointer.
//
// An object's vtable pointer points to the next component of the RTTI
// component. Hence, new components can be appended or prepended to sub-vtables
// without breaking compatibility.
bool VTableLayoutDiffIR::IsExtended() const {
const std::vector<VTableComponentIR> &old_components =
old_layout_.GetVTableComponents();
const std::vector<VTableComponentIR> &new_components =
new_layout_.GetVTableComponents();
const auto old_end = old_components.end();
const auto new_end = new_components.end();
auto old_it = old_components.begin();
auto new_it = new_components.begin();
bool is_extended = false;
while (old_it != old_end) {
const auto old_begin = old_it;
const auto new_begin = new_it;
// Iterate VCallOffset and VBaseOffset.
while (old_it != old_end && IsVOffset(old_it->GetKind())) {
old_it++;
}
while (new_it != new_end && IsVOffset(new_it->GetKind())) {
new_it++;
}
// Compare VCallOffset and VBaseOffset.
auto old_back_it = old_it;
auto new_back_it = new_it;
while (old_back_it != old_begin) {
if (new_back_it == new_begin) {
return false;
}
old_back_it--;
new_back_it--;
if (old_back_it->GetKind() != new_back_it->GetKind()) {
return false;
}
}
// The new sub-vtable has additional VOffsets at the beginning.
if (new_back_it != new_begin) {
is_extended = true;
}
// Compare OffsetToTop.
if (old_it == old_end || new_it == new_end ||
old_it->GetKind() != VTableComponentIR::OffsetToTop ||
new_it->GetKind() != VTableComponentIR::OffsetToTop) {
return false;
}
old_it++;
new_it++;
// Compare RTTI.
if (old_it == old_end || new_it == new_end ||
old_it->GetKind() != VTableComponentIR::RTTI ||
new_it->GetKind() != VTableComponentIR::RTTI ||
old_it->GetName() != new_it->GetName()) {
return false;
}
old_it++;
new_it++;
// Compare function pointers.
while (old_it != old_end && IsFunctionPointer(old_it->GetKind())) {
if (new_it == new_end || old_it->GetKind() != new_it->GetKind() ||
old_it->GetName() != new_it->GetName()) {
return false;
}
old_it++;
new_it++;
}
// The new sub-vtable has additional function pointers at the end.
while (new_it != new_end && IsFunctionPointer(new_it->GetKind())) {
is_extended = true;
new_it++;
}
}
return new_it == new_end ? is_extended : false;
}
bool RecordTypeDiffIR::IsExtended() const {
bool is_extended = false;
if (type_diff_ != nullptr) {
auto sizes = type_diff_->GetSizes();
if (sizes.first < sizes.second) {
is_extended = true;
}
if (sizes.first > sizes.second) {
return false;
}
auto alignments = type_diff_->GetAlignments();
if (alignments.first != alignments.second) {
return false;
}
}
if (access_diff_ != nullptr) {
if (IsAccessDowngraded(access_diff_->GetOldAccess(),
access_diff_->GetNewAccess())) {
return false;
}
is_extended = true;
}
if (base_specifier_diffs_ != nullptr) {
return false;
}
if (vtable_diffs_ != nullptr) {
if (!vtable_diffs_->IsExtended()) {
return false;
}
is_extended = true;
}
// This function skips comparing the access specifiers of field_diffs_
// because AbiDiffHelper::CompareCommonRecordFields does not report
// upgraded access specifiers as ABI difference.
if (field_diffs_.size() != 0 || fields_removed_.size() != 0) {
return false;
}
if (fields_added_.size() != 0) {
is_extended = true;
}
return is_extended;
}
} // namespace repr
} // namespace header_checker

View File

@@ -102,8 +102,6 @@ class VTableLayoutDiffIR {
return new_layout_;
}
bool IsExtended() const;
protected:
const VTableLayoutIR &old_layout_;
const VTableLayoutIR &new_layout_;
@@ -199,14 +197,7 @@ class RecordTypeDiffIR : public DiffMessageIR {
linker_set_key_ = std::move(linker_set_key);
}
bool DiffExists() const {
return (type_diff_ != nullptr) || (vtable_diffs_ != nullptr) ||
(field_diffs_.size() != 0) || (fields_removed_.size() != 0) ||
(fields_added_.size() != 0) || (access_diff_ != nullptr) ||
(base_specifier_diffs_ != nullptr);
}
bool IsExtended() const;
void SetExtended(bool is_extended) { is_extended_ = is_extended; }
const TypeDiffIR *GetTypeDiff() const {
return type_diff_.get();
@@ -222,6 +213,8 @@ class RecordTypeDiffIR : public DiffMessageIR {
const std::string &GetLinkerSetKey() const { return linker_set_key_; }
bool IsExtended() const { return is_extended_; }
protected:
// optional implemented with vector / std::unique_ptr.
std::unique_ptr<TypeDiffIR> type_diff_;
@@ -232,6 +225,7 @@ class RecordTypeDiffIR : public DiffMessageIR {
std::unique_ptr<AccessSpecifierDiffIR> access_diff_;
std::unique_ptr<CXXBaseSpecifierDiffIR> base_specifier_diffs_;
std::string linker_set_key_;
bool is_extended_ = false;
};
class EnumFieldDiffIR {