summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/dwarf/debug_info_entry_writer.h4
-rw-r--r--compiler/elf_writer_debug.cc128
-rw-r--r--test/449-checker-bce/src/Main.java6
3 files changed, 93 insertions, 45 deletions
diff --git a/compiler/dwarf/debug_info_entry_writer.h b/compiler/dwarf/debug_info_entry_writer.h
index e5bbed3c8e..5e3d2c8dfd 100644
--- a/compiler/dwarf/debug_info_entry_writer.h
+++ b/compiler/dwarf/debug_info_entry_writer.h
@@ -164,6 +164,10 @@ class DebugInfoEntryWriter FINAL : private Writer<Vector> {
this->PushUint8(value ? 1 : 0);
}
+ void WriteFlagPresent(Attribute attrib) {
+ AddAbbrevAttribute(attrib, DW_FORM_flag_present);
+ }
+
void WriteRef4(Attribute attrib, uint32_t cu_offset) {
AddAbbrevAttribute(attrib, DW_FORM_ref4);
this->PushUint32(cu_offset);
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 2e98b69c47..5dbbbc7e96 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -505,7 +505,7 @@ class DebugInfoWriter {
// Enclose the method in correct class definition.
if (last_dex_class_desc != dex_class_desc) {
if (last_dex_class_desc != nullptr) {
- EndClassTag(last_dex_class_desc);
+ EndClassTag();
}
// Write reference tag for the class we are about to declare.
size_t reference_tag_offset = info_.StartTag(DW_TAG_reference_type);
@@ -516,7 +516,7 @@ class DebugInfoWriter {
// Declare the class that owns this method.
size_t class_offset = StartClassTag(dex_class_desc);
info_.UpdateUint32(type_attrib_offset, class_offset);
- info_.WriteFlag(DW_AT_declaration, true);
+ info_.WriteFlagPresent(DW_AT_declaration);
// Check that each class is defined only once.
bool unique = owner_->defined_dex_classes_.insert(dex_class_desc).second;
CHECK(unique) << "Redefinition of " << dex_class_desc;
@@ -542,7 +542,7 @@ class DebugInfoWriter {
if (!is_static) {
info_.StartTag(DW_TAG_formal_parameter);
WriteName("this");
- info_.WriteFlag(DW_AT_artificial, true);
+ info_.WriteFlagPresent(DW_AT_artificial);
WriteLazyType(dex_class_desc);
if (dex_code != nullptr) {
// Write the stack location of the parameter.
@@ -601,11 +601,12 @@ class DebugInfoWriter {
CHECK_EQ(info_.Depth(), start_depth); // Balanced start/end.
}
if (last_dex_class_desc != nullptr) {
- EndClassTag(last_dex_class_desc);
+ EndClassTag();
}
- CHECK_EQ(info_.Depth(), 1);
FinishLazyTypes();
+ CloseNamespacesAboveDepth(0);
info_.EndTag(); // DW_TAG_compile_unit
+ CHECK_EQ(info_.Depth(), 0);
std::vector<uint8_t> buffer;
buffer.reserve(info_.data()->size() + KB);
const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
@@ -620,6 +621,12 @@ class DebugInfoWriter {
info_.WriteStrp(DW_AT_producer, owner_->WriteString("Android dex2oat"));
info_.WriteData1(DW_AT_language, DW_LANG_Java);
+ // Base class references to be patched at the end.
+ std::map<size_t, mirror::Class*> base_class_references;
+
+ // Already written declarations or definitions.
+ std::map<mirror::Class*, size_t> class_declarations;
+
std::vector<uint8_t> expr_buffer;
for (mirror::Class* type : types) {
if (type->IsPrimitive()) {
@@ -633,6 +640,7 @@ class DebugInfoWriter {
uint32_t data_offset = mirror::Array::DataOffset(component_size).Uint32Value();
uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
+ CloseNamespacesAboveDepth(0); // Declare in root namespace.
info_.StartTag(DW_TAG_array_type);
std::string descriptor_string;
WriteLazyType(element_type->GetDescriptor(&descriptor_string));
@@ -650,22 +658,10 @@ class DebugInfoWriter {
// Skip. Variables cannot have an interface as a dynamic type.
// We do not expose the interface information to the debugger in any way.
} else {
- // Declare base class. We can not use the standard WriteLazyType
- // since we want to avoid the DW_TAG_reference_tag wrapping.
- mirror::Class* base_class = type->GetSuperClass();
- size_t base_class_declaration_offset = 0;
- if (base_class != nullptr) {
- std::string tmp_storage;
- const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
- base_class_declaration_offset = StartClassTag(base_class_desc);
- info_.WriteFlag(DW_AT_declaration, true);
- WriteLinkageName(base_class);
- EndClassTag(base_class_desc);
- }
-
std::string descriptor_string;
const char* desc = type->GetDescriptor(&descriptor_string);
- StartClassTag(desc);
+ size_t class_offset = StartClassTag(desc);
+ class_declarations.emplace(type, class_offset);
if (!type->IsVariableSize()) {
info_.WriteUdata(DW_AT_byte_size, type->GetObjectSize());
@@ -680,7 +676,7 @@ class DebugInfoWriter {
info_.StartTag(DW_TAG_member);
WriteName(".dynamic_type");
WriteLazyType(sizeof(uintptr_t) == 8 ? "J" : "I");
- info_.WriteFlag(DW_AT_artificial, true);
+ info_.WriteFlagPresent(DW_AT_artificial);
// Create DWARF expression to get the value of the methods_ field.
Expression expr(&expr_buffer);
// The address of the object has been implicitly pushed on the stack.
@@ -702,9 +698,11 @@ class DebugInfoWriter {
}
// Base class.
+ mirror::Class* base_class = type->GetSuperClass();
if (base_class != nullptr) {
info_.StartTag(DW_TAG_inheritance);
- info_.WriteRef4(DW_AT_type, base_class_declaration_offset);
+ base_class_references.emplace(info_.size(), base_class);
+ info_.WriteRef4(DW_AT_type, 0);
info_.WriteUdata(DW_AT_data_member_location, 0);
info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
info_.EndTag(); // DW_TAG_inheritance.
@@ -743,13 +741,35 @@ class DebugInfoWriter {
info_.EndTag(); // DW_TAG_member.
}
- EndClassTag(desc);
+ EndClassTag();
+ }
+ }
+
+ // Write base class declarations.
+ for (const auto& base_class_reference : base_class_references) {
+ size_t reference_offset = base_class_reference.first;
+ mirror::Class* base_class = base_class_reference.second;
+ const auto& it = class_declarations.find(base_class);
+ if (it != class_declarations.end()) {
+ info_.UpdateUint32(reference_offset, it->second);
+ } else {
+ // Declare base class. We can not use the standard WriteLazyType
+ // since we want to avoid the DW_TAG_reference_tag wrapping.
+ std::string tmp_storage;
+ const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
+ size_t base_class_declaration_offset = StartClassTag(base_class_desc);
+ info_.WriteFlagPresent(DW_AT_declaration);
+ WriteLinkageName(base_class);
+ EndClassTag();
+ class_declarations.emplace(base_class, base_class_declaration_offset);
+ info_.UpdateUint32(reference_offset, base_class_declaration_offset);
}
}
- CHECK_EQ(info_.Depth(), 1);
FinishLazyTypes();
+ CloseNamespacesAboveDepth(0);
info_.EndTag(); // DW_TAG_compile_unit.
+ CHECK_EQ(info_.Depth(), 0);
std::vector<uint8_t> buffer;
buffer.reserve(info_.data()->size() + KB);
const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
@@ -957,8 +977,8 @@ class DebugInfoWriter {
if (desc[0] == 'L') {
// Class type. For example: Lpackage/name;
size_t class_offset = StartClassTag(desc.c_str());
- info_.WriteFlag(DW_AT_declaration, true);
- EndClassTag(desc.c_str());
+ info_.WriteFlagPresent(DW_AT_declaration);
+ EndClassTag();
// Reference to the class type.
offset = info_.StartTag(DW_TAG_reference_type);
info_.WriteRef(DW_AT_type, class_offset);
@@ -966,8 +986,9 @@ class DebugInfoWriter {
} else if (desc[0] == '[') {
// Array type.
size_t element_type = WriteTypeDeclaration(desc.substr(1));
+ CloseNamespacesAboveDepth(0); // Declare in root namespace.
size_t array_type = info_.StartTag(DW_TAG_array_type);
- info_.WriteFlag(DW_AT_declaration, true);
+ info_.WriteFlagPresent(DW_AT_declaration);
info_.WriteRef(DW_AT_type, element_type);
info_.EndTag();
offset = info_.StartTag(DW_TAG_reference_type);
@@ -1028,6 +1049,7 @@ class DebugInfoWriter {
LOG(FATAL) << "Unknown dex type descriptor: \"" << desc << "\"";
UNREACHABLE();
}
+ CloseNamespacesAboveDepth(0); // Declare in root namespace.
offset = info_.StartTag(DW_TAG_base_type);
WriteName(name);
info_.WriteData1(DW_AT_encoding, encoding);
@@ -1042,29 +1064,47 @@ class DebugInfoWriter {
// Start DW_TAG_class_type tag nested in DW_TAG_namespace tags.
// Returns offset of the class tag in the compilation unit.
size_t StartClassTag(const char* desc) {
- DCHECK(desc != nullptr && desc[0] == 'L');
- // Enclose the type in namespace tags.
- const char* end;
- for (desc = desc + 1; (end = strchr(desc, '/')) != nullptr; desc = end + 1) {
- info_.StartTag(DW_TAG_namespace);
- WriteName(std::string(desc, end - desc).c_str());
- }
- // Start the class tag.
+ std::string name = SetNamespaceForClass(desc);
size_t offset = info_.StartTag(DW_TAG_class_type);
- end = strchr(desc, ';');
- CHECK(end != nullptr);
- WriteName(std::string(desc, end - desc).c_str());
+ WriteName(name.c_str());
return offset;
}
- void EndClassTag(const char* desc) {
- DCHECK(desc != nullptr && desc[0] == 'L');
- // End the class tag.
+ void EndClassTag() {
info_.EndTag();
- // Close namespace tags.
- const char* end;
- for (desc = desc + 1; (end = strchr(desc, '/')) != nullptr; desc = end + 1) {
+ }
+
+ // Set the current namespace nesting to one required by the given class.
+ // Returns the class name with namespaces, 'L', and ';' stripped.
+ std::string SetNamespaceForClass(const char* desc) {
+ DCHECK(desc != nullptr && desc[0] == 'L');
+ desc++; // Skip the initial 'L'.
+ size_t depth = 0;
+ for (const char* end; (end = strchr(desc, '/')) != nullptr; desc = end + 1, ++depth) {
+ // Check whether the name at this depth is already what we need.
+ if (depth < current_namespace_.size()) {
+ const std::string& name = current_namespace_[depth];
+ if (name.compare(0, name.size(), desc, end - desc) == 0) {
+ continue;
+ }
+ }
+ // Otherwise we need to open a new namespace tag at this depth.
+ CloseNamespacesAboveDepth(depth);
+ info_.StartTag(DW_TAG_namespace);
+ std::string name(desc, end - desc);
+ WriteName(name.c_str());
+ current_namespace_.push_back(std::move(name));
+ }
+ CloseNamespacesAboveDepth(depth);
+ return std::string(desc, strchr(desc, ';') - desc);
+ }
+
+ // Close namespace tags to reach the given nesting depth.
+ void CloseNamespacesAboveDepth(size_t depth) {
+ DCHECK_LE(depth, current_namespace_.size());
+ while (current_namespace_.size() > depth) {
info_.EndTag();
+ current_namespace_.pop_back();
}
}
@@ -1079,6 +1119,8 @@ class DebugInfoWriter {
// 32-bit references which need to be resolved to a type later.
// Given type may be used multiple times. Therefore we need a multimap.
std::multimap<std::string, size_t> lazy_types_; // type_desc -> patch_offset.
+ // The current set of open namespace tags which are active and not closed yet.
+ std::vector<std::string> current_namespace_;
};
public:
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 06cfd0a606..8f9a32ab3a 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -631,7 +631,8 @@ public class Main {
/// CHECK-DAG: <<Array2>> NullCheck [<<Get1>>] loop:<<InnerLoop>>
/// CHECK-DAG: <<Len2:i\d+>> ArrayLength [<<Array2>>] loop:<<InnerLoop>>
/// CHECK-DAG: <<Bounds2>> BoundsCheck [<<Index2:i\d+>>,<<Len2>>] loop:<<InnerLoop>>
- /// CHECK-DAG: InvokeStaticOrDirect [<<Get2>>] loop:<<InnerLoop>>
+ // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+ /// CHECK-DAG: InvokeStaticOrDirect [<<Get2>>{{(,[ij]\d+)?}}] loop:<<InnerLoop>>
/// CHECK-DAG: <<Index2>> Phi loop:<<InnerLoop>>
/// CHECK-DAG: <<Index1>> Phi loop:<<OuterLoop:B\d+>>
/// CHECK-DAG: <<Field1>> StaticFieldGet loop:none
@@ -644,7 +645,8 @@ public class Main {
/// CHECK-DAG: <<Get1:l\d+>> ArrayGet [<<Array1:l\d+>>,<<Index1:i\d+>>] loop:<<OuterLoop>>
// Array reference ..[j] still in inner loop, with a direct index.
/// CHECK-DAG: <<Get2:i\d+>> ArrayGet [<<Array2:l\d+>>,<<Index2:i\d+>>] loop:<<InnerLoop:B\d+>>
- /// CHECK-DAG: InvokeStaticOrDirect [<<Get2>>] loop:<<InnerLoop>>
+ // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+ /// CHECK-DAG: InvokeStaticOrDirect [<<Get2>>{{(,[ij]\d+)?}}] loop:<<InnerLoop>>
/// CHECK-DAG: <<Index2>> Phi loop:<<InnerLoop>>
/// CHECK-DAG: <<Index1>> Phi loop:<<OuterLoop>>
// Synthetic phi.