Merge "Generate CFI for stackless methods."
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index 735755f..533f61c 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -22,6 +22,12 @@
"libnativeloader",
"libopenjdkjvm",
"libopenjdkjvmti",
+ // TODO(b/124439236): Clean up the following libraries once "required"
+ // dependencies work with APEX libraries.
+ "libdt_fd_forward",
+ "libdt_socket",
+ "libjdwp",
+ "libnpt",
]
bionic_native_shared_libs = [
"libc",
@@ -126,6 +132,16 @@
private_key: "com.android.runtime.pem",
}
+android_app_certificate {
+ name: "com.android.runtime.debug.certificate",
+ certificate: "com.android.runtime.debug",
+}
+
+android_app_certificate {
+ name: "com.android.runtime.release.certificate",
+ certificate: "com.android.runtime.release",
+}
+
prebuilt_etc {
name: "com.android.runtime.ld.config.txt",
src: "ld.config.txt",
@@ -164,6 +180,7 @@
prebuilts: art_runtime_data_file_prebuilts
+ ["com.android.runtime.ld.config.txt"],
key: "com.android.runtime.key",
+ certificate: ":com.android.runtime.release.certificate",
}
// "Debug" version of the Runtime APEX module (containing both release and
@@ -198,6 +215,7 @@
prebuilts: art_runtime_data_file_prebuilts
+ ["com.android.runtime.ld.config.txt"],
key: "com.android.runtime.key",
+ certificate: ":com.android.runtime.debug.certificate",
}
// TODO: Do this better. art_apex will disable host builds when
diff --git a/build/apex/com.android.runtime.debug.pk8 b/build/apex/com.android.runtime.debug.pk8
new file mode 100644
index 0000000..5eec5d8
--- /dev/null
+++ b/build/apex/com.android.runtime.debug.pk8
Binary files differ
diff --git a/build/apex/com.android.runtime.debug.x509.pem b/build/apex/com.android.runtime.debug.x509.pem
new file mode 100644
index 0000000..73402f5
--- /dev/null
+++ b/build/apex/com.android.runtime.debug.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF0DCCA7igAwIBAgIJALbaJLNNAiRDMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+aWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRyb2lkMRwwGgYDVQQD
+DBNjb20uYW5kcm9pZC5ydW50aW1lMCAXDTE5MDEyNTE3MTQ1NloYDzQ3NTYxMjIx
+MTcxNDU2WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG
+A1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwH
+QW5kcm9pZDEcMBoGA1UEAwwTY29tLmFuZHJvaWQucnVudGltZTCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAN1Ns75c0ZdLKnUvEuEotzJ0xyOLzOHYP3y6
+RzcwFyPf84aADc7rQDtjbmEuf9g9QpJhZAxe7G2Jg/wxqaxMW6wCfkpuElW5CAcj
+XQ0i12hRVtqePs5Z5bjzJ/8C7luWh82Vb/s2YoRPoKNXVWFT16CB4RMnw2nW5Uyo
+RHZ98N4MgFSGilafIc6Z0DImreTTwlEvcyKihVUSuzeyPG8CRjshw0C1Hqxt4a8J
+rxAgfPpd84Xo4etYePpVr2K5+vNAVwLpUdD48Y7q9peOJ0tbL8DSohudkzvZsQUo
+CfEfrVBfZv7aPnt6ZJYhcFo1WRBMYczKP4jWb0KgmF963ee3zliU1pXtIYsNBNth
+Mdvy3ml301tI7CKE5A3Yevm40VVqo+IDt7FNxoV3rKPhnO9vi/YqzX/1xMvAto8E
+9A5NvMTqHmS2P0wt1pt9KSuXXjoIAWaHZOATDkVI+jLjDrYFNdhqXVgbAaVtI60j
+lRaSWxzBr4o+g2W8ks/JgM2mwJ6qaTNoDMzg823MKzy/t3935sxm5GhFs9AY9Qz/
+4B3exqYUEFJLN6dJLCVppCmFCdCONSxN7bXPo+3b9LlZuKAOP17N04+eKcwXVeYz
+Z3a7SfyMzq+DtLhAn/TSliSbbCAVUxiOZnVX1nM0Gs3/BYCs0TUh2tSqO48pwDrx
+Pw7z9+m5AgMBAAGjUzBRMB0GA1UdDgQWBBRT9s/tu4uqtrglUFjQbwY5p+17DjAf
+BgNVHSMEGDAWgBRT9s/tu4uqtrglUFjQbwY5p+17DjAPBgNVHRMBAf8EBTADAQH/
+MA0GCSqGSIb3DQEBCwUAA4ICAQBNY5giwZCM0sE93Dj2zEe8qCRwIaV4bvSe744X
+Y1+405vdrNEHKPUfFn1xLSnhiGU3loZrP15lexmWvxycLNEy0UxZgq3eR7HuW6xp
+GIm9ttYDZEP+pL9hwew3jiR38NRRR1Ur1MsBNkZnCELC1W8RFWIi77Fsb4fj2mGn
+2R+2voBvVS5kjkytW079CEIsZN9RVYfERiKPCfJDa87kk0xduqyh7sDegQl0B2Ot
+R9KnD1dJZjbii2GRkhpJ/Ig17CQH3J8PY/SIt9L+QAchnIEF051sjbBRUJuPK9gL
+eBEkZkwD1JLqGO6fxkcjNx7MIevTnIBjX2Epr8luyRy7eR3TdBT3aRQcCUqBCi3i
+WxAVR5sOZ90INTXftFbztoklitpQ9mxKXgFr+xggL6u3BdJk1Nt9BsYmRzh5Bg+6
+1eMDBumy3JEA7whE8p75X9cSnKTNrDQU3DA5XzpIhmI91XJArBhBfxgqGxaTf0uq
+SfZRDfnaO456ZsZdKUy62mry6Vg/hvzX52x/HxDlSQWbpYp5t03hshaWxtNE376q
+GdqOoGRRWCvyWi/UOYzabp6czTjwV1JH9IU379CsqIO5UNJ2MM2re4TDXofefU1C
+6eiYihy28xDfIiCdretLRlvFYFF/5X5xby/XWsDA9sGlL5OOiXC6o0Pl9vbek2+T
+Ibx3Nw==
+-----END CERTIFICATE-----
diff --git a/build/apex/com.android.runtime.release.pk8 b/build/apex/com.android.runtime.release.pk8
new file mode 100644
index 0000000..c63efb8
--- /dev/null
+++ b/build/apex/com.android.runtime.release.pk8
Binary files differ
diff --git a/build/apex/com.android.runtime.release.x509.pem b/build/apex/com.android.runtime.release.x509.pem
new file mode 100644
index 0000000..4a7607a
--- /dev/null
+++ b/build/apex/com.android.runtime.release.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF0DCCA7igAwIBAgIJAMtsu/wrkZurMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+aWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRyb2lkMRwwGgYDVQQD
+DBNjb20uYW5kcm9pZC5ydW50aW1lMCAXDTE5MDEyNTE3MTU0MFoYDzQ3NTYxMjIx
+MTcxNTQwWjB8MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG
+A1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwH
+QW5kcm9pZDEcMBoGA1UEAwwTY29tLmFuZHJvaWQucnVudGltZTCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAL+aGSc+HU69vV1VbZb6WjXMDrE2Jo+JjXLU
+yVS3o8qlQeqN0RFbsbwnihnwg2xBnM6JiskAcuocz87dDuEt1zUEInC3Hpt/C2eg
+GUZepbq8po+v+b04YlX3aTaYTFqMjU0aQkjOqhnmVxg+KHpvudlvKB3VhH3D61al
+RReQzgM/Q6aUxcr4Z8XwvzV3i0K5NjiSuSt14K2yIaheh2OTbbwtvm3d+0sQDco6
+1gl0l4rM4e+GjxgWVqx8mfKhd4HTS3YIBDWXR6DFPBARzVBIpZu2QK4U6Jdsy2wI
+xg8+d5KWAoNQb7IQK6LQy7Fbw3PNJDo4Ph39G2wNgeMemz8uSQ9FZujc0AgxBom6
+J+ad7zlJBhYFC4UIKBYrRfJCHTN3GLuLvhu0p0jNMfdQXF6Tv/iG9g8JdZ0QjeWm
+/K+h1p6LUAIUV0UP7j8nIdp0j6NqMywkoeRDYlVQV/XdI7BiQe9Z8yNbF5Y3CxWT
+hMfN9iby11ImPilzpgv39ORVjDQdxxcwhJg2Xuu1752cBxcHu3ZcR8AiB7PCksXu
+EpUrjjOH8eVxoG1JJ/na5elUg/H35Or+JYYd8I8Ad1/GRkPrnIBAGzuyntOsNs4t
+2CEnhmV6EkEH8KP8miTdaa5NdPIwFRIHVBHcrqsqdmrINvoJhaVRH7YwmFjv48ak
+N4OyW3oLAgMBAAGjUzBRMB0GA1UdDgQWBBRqVJ0tsEOyqhKiZOrOfRD1+jQFMDAf
+BgNVHSMEGDAWgBRqVJ0tsEOyqhKiZOrOfRD1+jQFMDAPBgNVHRMBAf8EBTADAQH/
+MA0GCSqGSIb3DQEBCwUAA4ICAQAs+I1tRWRPmhA+FqcRdlAcY2Vy7NO12hjWXCT9
+hqenGk1/VnhH8aZT5lXZNaWeKonT5W7XydyrjiF09ndZBGew0rEZh6sMXH+G/drT
+9JxvfHsCQGrmX32V1XgAoRjV1VpUYIb2747fFWHHbl5frowNj955pkfseeKilSnF
+orUl5uGNxr6iNaVEUDfXBWkHwipYVyejAqdHkCQDhLtDBWsiskKpLWmmNKuy2QXQ
+uoyUyfeSR1Y+pT83qgmGb1LFLiOqL9ZKPrsIP+tG4lYB8L4SrYJf4MgfoJaKQ8ed
+2jsd42MegvOB2vdMyLgkf7EM/9DpE4BLpAy2mNd1AccL9YQ+0ezruxh6sYklJWGe
+2bHEbZk0duoNPsA87ZNKfFVV2cNVwSg/22HHjGieMUyPIwyGIzsHId8XiwXpZhLX
+VyacOVRd0SjTWK5Pxj6g21NrrcMXvFeCbveucf2ljKVxBVSbQKt67YlXxd9nLZjN
+zHnJWzDwlWXbyvxheLVVGEo0cqRbhxYMxXd9dM01EXJmIWqS8t0+aw90KKPFITNv
+qpxXnF5JJm1CzeBDtpmfepDupUR1bWansOd0sUuiDF/H1UcDiuBUC643RET1vjhv
+MllsShSeC6KGm3WwE0bhcvA9IdZC8CA3Btzw2J9aJO1gbVZ6vRkH+21cfR07so4N
+yXgprQ==
+-----END CERTIFICATE-----
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h
index bc816da..2fc81c9 100644
--- a/compiler/cfi_test.h
+++ b/compiler/cfi_test.h
@@ -51,14 +51,11 @@
dwarf::WriteCIE(is64bit, dwarf::Reg(8), initial_opcodes, &debug_frame_data_);
std::vector<uintptr_t> debug_frame_patches;
dwarf::WriteFDE(is64bit,
- /* section_address= */ 0,
- /* cie_address= */ 0,
+ /* cie_pointer= */ 0,
/* code_address= */ 0,
actual_asm.size(),
actual_cfi,
- /* buffer_address= */ 0,
- &debug_frame_data_,
- &debug_frame_patches);
+ &debug_frame_data_);
ReformatCfi(Objdump(false, "-W"), &lines);
// Pretty-print assembly.
const uint8_t* asm_base = actual_asm.data();
diff --git a/compiler/debug/dwarf/dwarf_test.cc b/compiler/debug/dwarf/dwarf_test.cc
index 52717c3..212fd63 100644
--- a/compiler/debug/dwarf/dwarf_test.cc
+++ b/compiler/debug/dwarf/dwarf_test.cc
@@ -121,19 +121,13 @@
DebugFrameOpCodeWriter<> initial_opcodes;
WriteCIE(is64bit, Reg(is64bit ? 16 : 8), initial_opcodes, &debug_frame_data_);
- std::vector<uintptr_t> debug_frame_patches;
- std::vector<uintptr_t> expected_patches = { 28 };
WriteFDE(is64bit,
- 0,
- 0,
+ /* cie_pointer= */ 0,
0x01000000,
0x01000000,
ArrayRef<const uint8_t>(*opcodes.data()),
- 0,
- &debug_frame_data_,
- &debug_frame_patches);
+ &debug_frame_data_);
- EXPECT_EQ(expected_patches, debug_frame_patches);
CheckObjdumpOutput(is64bit, "-W");
}
@@ -142,20 +136,14 @@
DebugFrameOpCodeWriter<> initial_opcodes;
WriteCIE(is64bit, Reg(16), initial_opcodes, &debug_frame_data_);
DebugFrameOpCodeWriter<> opcodes;
- std::vector<uintptr_t> debug_frame_patches;
- std::vector<uintptr_t> expected_patches = { 32 };
WriteFDE(is64bit,
- 0,
- 0,
+ /* cie_pointer= */ 0,
0x0100000000000000,
0x0200000000000000,
ArrayRef<const uint8_t>(*opcodes.data()),
- 0,
- &debug_frame_data_,
- &debug_frame_patches);
+ &debug_frame_data_);
DW_CHECK("FDE cie=00000000 pc=100000000000000..300000000000000");
- EXPECT_EQ(expected_patches, debug_frame_patches);
CheckObjdumpOutput(is64bit, "-W");
}
@@ -186,16 +174,12 @@
DW_CHECK_NEXT("DW_CFA_offset: r15 (r15)");
DebugFrameOpCodeWriter<> initial_opcodes;
WriteCIE(is64bit, Reg(16), initial_opcodes, &debug_frame_data_);
- std::vector<uintptr_t> debug_frame_patches;
WriteFDE(is64bit,
- 0,
- 0,
+ /* cie_pointer= */ 0,
0x0100000000000000,
0x0200000000000000,
ArrayRef<const uint8_t>(*opcodes.data()),
- 0,
- &debug_frame_data_,
- &debug_frame_patches);
+ &debug_frame_data_);
CheckObjdumpOutput(is64bit, "-W");
}
@@ -250,12 +234,8 @@
DW_CHECK_NEXT("Entry\tDir\tTime\tSize\tName");
DW_CHECK_NEXT("1\t0\t1000\t2000\tfile.c");
- std::vector<uintptr_t> debug_line_patches;
- std::vector<uintptr_t> expected_patches = { 87 };
- WriteDebugLineTable(include_directories, files, opcodes,
- 0, &debug_line_data_, &debug_line_patches);
+ WriteDebugLineTable(include_directories, files, opcodes, &debug_line_data_);
- EXPECT_EQ(expected_patches, debug_line_patches);
CheckObjdumpOutput(is64bit, "-W");
}
@@ -290,9 +270,7 @@
std::vector<std::string> directories;
std::vector<FileEntry> files = { { "file.c", 0, 1000, 2000 } };
- std::vector<uintptr_t> debug_line_patches;
- WriteDebugLineTable(directories, files, opcodes,
- 0, &debug_line_data_, &debug_line_patches);
+ WriteDebugLineTable(directories, files, opcodes, &debug_line_data_);
CheckObjdumpOutput(is64bit, "-W -WL");
}
@@ -346,12 +324,8 @@
DW_CHECK_NEXT("DW_AT_high_pc DW_FORM_addr");
DW_CHECK("3 DW_TAG_compile_unit [no children]");
- std::vector<uintptr_t> debug_info_patches;
- std::vector<uintptr_t> expected_patches = { 16, 20, 29, 33, 42, 46 };
- dwarf::WriteDebugInfoCU(/* debug_abbrev_offset= */ 0, info,
- 0, &debug_info_data_, &debug_info_patches);
+ dwarf::WriteDebugInfoCU(/* debug_abbrev_offset= */ 0, info, &debug_info_data_);
- EXPECT_EQ(expected_patches, debug_info_patches);
CheckObjdumpOutput(is64bit, "-W");
}
diff --git a/compiler/debug/dwarf/headers.h b/compiler/debug/dwarf/headers.h
index 119bfe9..869a2c2 100644
--- a/compiler/debug/dwarf/headers.h
+++ b/compiler/debug/dwarf/headers.h
@@ -67,26 +67,16 @@
// Write frame description entry (FDE) to .debug_frame or .eh_frame section.
inline
void WriteFDE(bool is64bit,
- uint64_t section_address, // Absolute address of the section.
- uint64_t cie_address, // Absolute address of last CIE.
+ uint64_t cie_pointer, // Offset of relevant CIE in debug_frame setcion.
uint64_t code_address,
uint64_t code_size,
const ArrayRef<const uint8_t>& opcodes,
- uint64_t buffer_address, // Address of buffer in linked application.
- std::vector<uint8_t>* buffer,
- std::vector<uintptr_t>* patch_locations) {
- CHECK_GE(cie_address, section_address);
- CHECK_GE(buffer_address, section_address);
-
+ /*inout*/ std::vector<uint8_t>* buffer) {
Writer<> writer(buffer);
size_t fde_header_start = writer.data()->size();
writer.PushUint32(0); // Length placeholder.
- uint32_t cie_pointer = cie_address - section_address;
writer.PushUint32(cie_pointer);
// Relocate code_address if it has absolute value.
- if (patch_locations != nullptr) {
- patch_locations->push_back(buffer_address + buffer->size() - section_address);
- }
if (is64bit) {
writer.PushUint64(code_address);
writer.PushUint64(code_size);
@@ -128,9 +118,7 @@
template<typename Vector>
void WriteDebugInfoCU(uint32_t debug_abbrev_offset,
const DebugInfoEntryWriter<Vector>& entries,
- size_t debug_info_offset, // offset from start of .debug_info.
- std::vector<uint8_t>* debug_info,
- std::vector<uintptr_t>* debug_info_patches) {
+ std::vector<uint8_t>* debug_info) {
static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
Writer<> writer(debug_info);
@@ -143,10 +131,6 @@
DCHECK_EQ(entries_offset, DebugInfoEntryWriter<Vector>::kCompilationUnitHeaderSize);
writer.PushData(entries.data());
writer.UpdateUint32(start, writer.data()->size() - start - 4);
- // Copy patch locations and make them relative to .debug_info section.
- for (uintptr_t patch_location : entries.GetPatchLocations()) {
- debug_info_patches->push_back(debug_info_offset + entries_offset + patch_location);
- }
}
struct FileEntry {
@@ -161,9 +145,7 @@
void WriteDebugLineTable(const std::vector<std::string>& include_directories,
const std::vector<FileEntry>& files,
const DebugLineOpCodeWriter<Vector>& opcodes,
- size_t debug_line_offset, // offset from start of .debug_line.
- std::vector<uint8_t>* debug_line,
- std::vector<uintptr_t>* debug_line_patches) {
+ std::vector<uint8_t>* debug_line) {
static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
Writer<> writer(debug_line);
@@ -194,13 +176,8 @@
}
writer.PushUint8(0); // Terminate file list.
writer.UpdateUint32(header_length_pos, writer.data()->size() - header_length_pos - 4);
- size_t opcodes_offset = writer.data()->size();
writer.PushData(opcodes.data());
writer.UpdateUint32(header_start, writer.data()->size() - header_start - 4);
- // Copy patch locations and make them relative to .debug_line section.
- for (uintptr_t patch_location : opcodes.GetPatchLocations()) {
- debug_line_patches->push_back(debug_line_offset + opcodes_offset + patch_location);
- }
}
} // namespace dwarf
diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h
index a6bbea4..c5fa647 100644
--- a/compiler/debug/elf_debug_frame_writer.h
+++ b/compiler/debug/elf_debug_frame_writer.h
@@ -169,8 +169,7 @@
template<typename ElfTypes>
void WriteCFISection(linker::ElfBuilder<ElfTypes>* builder,
- const ArrayRef<const MethodDebugInfo>& method_infos,
- bool write_oat_patches) {
+ const ArrayRef<const MethodDebugInfo>& method_infos) {
typedef typename ElfTypes::Addr Elf_Addr;
// The methods can be written in any order.
@@ -197,11 +196,8 @@
});
std::vector<uint32_t> binary_search_table;
- std::vector<uintptr_t> patch_locations;
if (kWriteDebugFrameHdr) {
binary_search_table.reserve(2 * sorted_method_infos.size());
- } else {
- patch_locations.reserve(sorted_method_infos.size());
}
// Write .debug_frame section.
@@ -209,11 +205,9 @@
{
cfi_section->Start();
const bool is64bit = Is64BitInstructionSet(builder->GetIsa());
- Elf_Addr buffer_address = 0;
std::vector<uint8_t> buffer; // Small temporary buffer.
WriteCIE(builder->GetIsa(), &buffer);
cfi_section->WriteFully(buffer.data(), buffer.size());
- buffer_address += buffer.size();
buffer.clear();
for (const MethodDebugInfo* mi : sorted_method_infos) {
DCHECK(!mi->deduped);
@@ -222,19 +216,15 @@
(mi->is_code_address_text_relative ? builder->GetText()->GetAddress() : 0);
if (kWriteDebugFrameHdr) {
binary_search_table.push_back(dchecked_integral_cast<uint32_t>(code_address));
- binary_search_table.push_back(dchecked_integral_cast<uint32_t>(buffer_address));
+ binary_search_table.push_back(cfi_section->GetPosition());
}
dwarf::WriteFDE(is64bit,
- 0,
- 0,
+ /* cie_pointer= */ 0,
code_address,
mi->code_size,
mi->cfi,
- buffer_address,
- &buffer,
- &patch_locations);
+ &buffer);
cfi_section->WriteFully(buffer.data(), buffer.size());
- buffer_address += buffer.size();
buffer.clear();
}
cfi_section->End();
@@ -254,11 +244,6 @@
header_section->WriteFully(header_buffer.data(), header_buffer.size());
header_section->WriteFully(binary_search_table.data(), binary_search_table.size());
header_section->End();
- } else {
- if (write_oat_patches) {
- builder->WritePatches(".debug_frame.oat_patches",
- ArrayRef<const uintptr_t>(patch_locations));
- }
}
}
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index a63f241..05a4a3e 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -68,12 +68,8 @@
builder_->GetDebugInfo()->Start();
}
- void End(bool write_oat_patches) {
+ void End() {
builder_->GetDebugInfo()->End();
- if (write_oat_patches) {
- builder_->WritePatches(".debug_info.oat_patches",
- ArrayRef<const uintptr_t>(debug_info_patches_));
- }
builder_->WriteSection(".debug_abbrev", &debug_abbrev_buffer_);
if (!debug_loc_.empty()) {
builder_->WriteSection(".debug_loc", &debug_loc_);
@@ -85,7 +81,6 @@
private:
linker::ElfBuilder<ElfTypes>* builder_;
- std::vector<uintptr_t> debug_info_patches_;
std::vector<uint8_t> debug_abbrev_buffer_;
dwarf::DebugAbbrevWriter<> debug_abbrev_;
std::vector<uint8_t> debug_loc_;
@@ -281,10 +276,9 @@
CHECK_EQ(info_.Depth(), 0);
std::vector<uint8_t> buffer;
buffer.reserve(info_.data()->size() + KB);
- const size_t offset = owner_->builder_->GetDebugInfo()->GetPosition();
// All compilation units share single table which is at the start of .debug_abbrev.
const size_t debug_abbrev_offset = 0;
- WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
+ WriteDebugInfoCU(debug_abbrev_offset, info_, &buffer);
owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
}
@@ -446,10 +440,9 @@
CHECK_EQ(info_.Depth(), 0);
std::vector<uint8_t> buffer;
buffer.reserve(info_.data()->size() + KB);
- const size_t offset = owner_->builder_->GetDebugInfo()->GetPosition();
// All compilation units share single table which is at the start of .debug_abbrev.
const size_t debug_abbrev_offset = 0;
- WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
+ WriteDebugInfoCU(debug_abbrev_offset, info_, &buffer);
owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
}
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index 0a13a92..f95912a 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -263,23 +263,17 @@
}
std::vector<uint8_t> buffer;
buffer.reserve(opcodes.data()->size() + KB);
- size_t offset = builder_->GetDebugLine()->GetPosition();
- WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches_);
+ WriteDebugLineTable(directories, files, opcodes, &buffer);
builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size());
return buffer.size();
}
- void End(bool write_oat_patches) {
+ void End() {
builder_->GetDebugLine()->End();
- if (write_oat_patches) {
- builder_->WritePatches(".debug_line.oat_patches",
- ArrayRef<const uintptr_t>(debug_line_patches_));
- }
}
private:
linker::ElfBuilder<ElfTypes>* builder_;
- std::vector<uintptr_t> debug_line_patches_;
};
} // namespace debug
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 4bd0eac..fd638b7 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -44,13 +44,12 @@
template <typename ElfTypes>
void WriteDebugInfo(linker::ElfBuilder<ElfTypes>* builder,
- const DebugInfo& debug_info,
- bool write_oat_patches) {
+ const DebugInfo& debug_info) {
// Write .strtab and .symtab.
WriteDebugSymbols(builder, /* mini-debug-info= */ false, debug_info);
// Write .debug_frame.
- WriteCFISection(builder, debug_info.compiled_methods, write_oat_patches);
+ WriteCFISection(builder, debug_info.compiled_methods);
// Group the methods into compilation units based on class.
std::unordered_map<const dex::ClassDef*, ElfCompilationUnit> class_to_compilation_unit;
@@ -95,7 +94,7 @@
for (auto& compilation_unit : compilation_units) {
line_writer.WriteCompilationUnit(compilation_unit);
}
- line_writer.End(write_oat_patches);
+ line_writer.End();
}
// Write .debug_info section.
@@ -106,7 +105,7 @@
ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
cu_writer.Write(compilation_unit);
}
- info_writer.End(write_oat_patches);
+ info_writer.End();
}
}
@@ -136,7 +135,7 @@
WriteDebugSymbols(builder.get(), /* mini-debug-info= */ true, debug_info);
}
if (!debug_info.compiled_methods.empty()) {
- WriteCFISection(builder.get(), debug_info.compiled_methods, /* write_oat_patches= */ false);
+ WriteCFISection(builder.get(), debug_info.compiled_methods);
}
builder->End();
CHECK(builder->Good());
@@ -195,9 +194,9 @@
// The compression is great help for multiple methods but it is not worth it for a
// single method due to the overheads so skip the compression here for performance.
WriteDebugSymbols(builder.get(), /* mini-debug-info= */ true, debug_info);
- WriteCFISection(builder.get(), debug_info.compiled_methods, /* write_oat_patches= */ false);
+ WriteCFISection(builder.get(), debug_info.compiled_methods);
} else {
- WriteDebugInfo(builder.get(), debug_info, /* write_oat_patches= */ false);
+ WriteDebugInfo(builder.get(), debug_info);
}
builder->End();
CHECK(builder->Good());
@@ -283,14 +282,11 @@
return;
}
dwarf::WriteFDE(is64bit,
- /*section_address=*/ 0,
- /*cie_address=*/ 0,
+ /* cie_pointer= */ 0,
addr,
size,
opcodes,
- debug_frame_buffer.size(),
- &debug_frame_buffer,
- /*patch_locations=*/ nullptr);
+ &debug_frame_buffer);
});
}
strtab->End();
@@ -359,7 +355,7 @@
info_writer.Start();
ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
cu_writer.Write(types);
- info_writer.End(/* write_oat_patches= */ false);
+ info_writer.End();
builder->End();
CHECK(builder->Good());
@@ -369,12 +365,10 @@
// Explicit instantiations
template void WriteDebugInfo<ElfTypes32>(
linker::ElfBuilder<ElfTypes32>* builder,
- const DebugInfo& debug_info,
- bool write_oat_patches);
+ const DebugInfo& debug_info);
template void WriteDebugInfo<ElfTypes64>(
linker::ElfBuilder<ElfTypes64>* builder,
- const DebugInfo& debug_info,
- bool write_oat_patches);
+ const DebugInfo& debug_info);
} // namespace debug
} // namespace art
diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h
index d5aa9cd..3cc38a2 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -37,8 +37,7 @@
template <typename ElfTypes>
void WriteDebugInfo(
linker::ElfBuilder<ElfTypes>* builder,
- const DebugInfo& debug_info,
- bool write_oat_patches);
+ const DebugInfo& debug_info);
std::vector<uint8_t> MakeMiniDebugInfo(
InstructionSet isa,
diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc
index d5ceafe..f978cc6 100644
--- a/compiler/exception_test.cc
+++ b/compiler/exception_test.cc
@@ -80,7 +80,7 @@
stack_maps.BeginMethod(4 * sizeof(void*), 0u, 0u, 0u);
stack_maps.BeginStackMapEntry(kDexPc, native_pc_offset);
stack_maps.EndStackMapEntry();
- stack_maps.EndMethod();
+ stack_maps.EndMethod(code_size);
ScopedArenaVector<uint8_t> stack_map = stack_maps.Encode();
const size_t stack_maps_size = stack_map.size();
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h
index 54e07fc..33e1866 100644
--- a/compiler/linker/elf_builder.h
+++ b/compiler/linker/elf_builder.h
@@ -51,14 +51,10 @@
// .strtab - Names for .symtab.
// .symtab - Debug symbols.
// .debug_frame - Unwind information (CFI).
-// .debug_frame.oat_patches - Addresses for relocation.
// .debug_info - Debug information.
-// .debug_info.oat_patches - Addresses for relocation.
// .debug_abbrev - Decoding information for .debug_info.
// .debug_str - Strings for .debug_info.
// .debug_line - Line number tables.
-// .debug_line.oat_patches - Addresses for relocation.
-// .text.oat_patches - Addresses for relocation.
// .shstrtab - Names of ELF sections.
// Elf_Shdr[] - Section headers.
//
@@ -575,29 +571,6 @@
Section* GetDebugInfo() { return &debug_info_; }
Section* GetDebugLine() { return &debug_line_; }
- // Encode patch locations as LEB128 list of deltas between consecutive addresses.
- // (exposed publicly for tests)
- static void EncodeOatPatches(const ArrayRef<const uintptr_t>& locations,
- std::vector<uint8_t>* buffer) {
- buffer->reserve(buffer->size() + locations.size() * 2); // guess 2 bytes per ULEB128.
- uintptr_t address = 0; // relative to start of section.
- for (uintptr_t location : locations) {
- DCHECK_GE(location, address) << "Patch locations are not in sorted order";
- EncodeUnsignedLeb128(buffer, dchecked_integral_cast<uint32_t>(location - address));
- address = location;
- }
- }
-
- void WritePatches(const char* name, const ArrayRef<const uintptr_t>& patch_locations) {
- std::vector<uint8_t> buffer;
- EncodeOatPatches(patch_locations, &buffer);
- std::unique_ptr<Section> s(new Section(this, name, SHT_OAT_PATCH, 0, nullptr, 0, 1, 0));
- s->Start();
- s->WriteFully(buffer.data(), buffer.size());
- s->End();
- other_sections_.push_back(std::move(s));
- }
-
void WriteSection(const char* name, const std::vector<uint8_t>* buffer) {
std::unique_ptr<Section> s(new Section(this, name, SHT_PROGBITS, 0, nullptr, 0, 1, 0));
s->Start();
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 9e2f5cd..122f27b 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -440,7 +440,7 @@
// Finalize instructions in assember;
Finalize(allocator);
- GetStackMapStream()->EndMethod();
+ GetStackMapStream()->EndMethod(GetAssembler()->CodeSize());
}
void CodeGenerator::Finalize(CodeAllocator* allocator) {
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index e8f8d32..4f43b71 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1171,7 +1171,8 @@
}
static ScopedArenaVector<uint8_t> CreateJniStackMap(ScopedArenaAllocator* allocator,
- const JniCompiledMethod& jni_compiled_method) {
+ const JniCompiledMethod& jni_compiled_method,
+ size_t code_size) {
// StackMapStream is quite large, so allocate it using the ScopedArenaAllocator
// to stay clear of the frame size limit.
std::unique_ptr<StackMapStream> stack_map_stream(
@@ -1181,7 +1182,7 @@
jni_compiled_method.GetCoreSpillMask(),
jni_compiled_method.GetFpSpillMask(),
/* num_dex_registers= */ 0);
- stack_map_stream->EndMethod();
+ stack_map_stream->EndMethod(code_size);
return stack_map_stream->Encode();
}
@@ -1239,8 +1240,8 @@
MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kCompiledNativeStub);
ScopedArenaAllocator stack_map_allocator(&arena_stack); // Will hold the stack map.
- ScopedArenaVector<uint8_t> stack_map = CreateJniStackMap(&stack_map_allocator,
- jni_compiled_method);
+ ScopedArenaVector<uint8_t> stack_map = CreateJniStackMap(
+ &stack_map_allocator, jni_compiled_method, jni_compiled_method.GetCode().size());
return CompiledMethod::SwapAllocCompiledMethod(
GetCompilerDriver()->GetCompiledMethodStorage(),
jni_compiled_method.GetInstructionSet(),
@@ -1290,8 +1291,8 @@
ArenaStack arena_stack(runtime->GetJitArenaPool());
// StackMapStream is large and it does not fit into this frame, so we need helper method.
ScopedArenaAllocator stack_map_allocator(&arena_stack); // Will hold the stack map.
- ScopedArenaVector<uint8_t> stack_map = CreateJniStackMap(&stack_map_allocator,
- jni_compiled_method);
+ ScopedArenaVector<uint8_t> stack_map = CreateJniStackMap(
+ &stack_map_allocator, jni_compiled_method, jni_compiled_method.GetCode().size());
uint8_t* stack_map_data = nullptr;
uint8_t* roots_data = nullptr;
uint32_t data_size = code_cache->ReserveData(self,
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index 60ca61c..e87f3c8 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -54,9 +54,10 @@
num_dex_registers_ = num_dex_registers;
}
-void StackMapStream::EndMethod() {
+void StackMapStream::EndMethod(size_t code_size) {
DCHECK(in_method_) << "Mismatched Begin/End calls";
in_method_ = false;
+ packed_code_size_ = StackMap::PackNativePc(code_size, instruction_set_);
// Read the stack masks now. The compiler might have updated them.
for (size_t i = 0; i < lazy_stack_masks_.size(); i++) {
@@ -66,6 +67,10 @@
stack_masks_.Dedup(stack_mask->GetRawStorage(), stack_mask->GetNumberOfBits());
}
}
+
+ for (size_t i = 0; i < stack_maps_.size(); i++) {
+ DCHECK_LE(stack_maps_[i][StackMap::kPackedNativePc], packed_code_size_);
+ }
}
void StackMapStream::BeginStackMapEntry(uint32_t dex_pc,
@@ -296,6 +301,7 @@
ScopedArenaVector<uint8_t> buffer(allocator_->Adapter(kArenaAllocStackMapStream));
BitMemoryWriter<ScopedArenaVector<uint8_t>> out(&buffer);
+ out.WriteVarint(packed_code_size_);
out.WriteVarint(packed_frame_size_);
out.WriteVarint(core_spill_mask_);
out.WriteVarint(fp_spill_mask_);
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 01c6bf9..164e902 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -62,7 +62,7 @@
size_t core_spill_mask,
size_t fp_spill_mask,
uint32_t num_dex_registers);
- void EndMethod();
+ void EndMethod(size_t code_size);
void BeginStackMapEntry(uint32_t dex_pc,
uint32_t native_pc_offset,
@@ -99,6 +99,7 @@
ScopedArenaAllocator* allocator_;
const InstructionSet instruction_set_;
+ uint32_t packed_code_size_ = 0;
uint32_t packed_frame_size_ = 0;
uint32_t core_spill_mask_ = 0;
uint32_t fp_spill_mask_ = 0;
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index d28f09f..cbd844f 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -61,7 +61,7 @@
stream.AddDexRegisterEntry(Kind::kConstant, -2); // Short location.
stream.EndStackMapEntry();
- stream.EndMethod();
+ stream.EndMethod(64 * kPcAlign);
ScopedArenaVector<uint8_t> memory = stream.Encode();
CodeInfo code_info(memory.data());
@@ -147,7 +147,7 @@
stream.AddDexRegisterEntry(Kind::kInFpuRegisterHigh, 1); // Short location.
stream.EndStackMapEntry();
- stream.EndMethod();
+ stream.EndMethod(256 * kPcAlign);
ScopedArenaVector<uint8_t> memory = stream.Encode();
CodeInfo code_info(memory.data());
@@ -317,7 +317,7 @@
stream.EndInlineInfoEntry();
stream.EndStackMapEntry();
- stream.EndMethod();
+ stream.EndMethod(64 * kPcAlign);
ScopedArenaVector<uint8_t> memory = stream.Encode();
CodeInfo code_info(memory.data());
@@ -372,7 +372,7 @@
stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
stream.EndStackMapEntry();
- stream.EndMethod();
+ stream.EndMethod(64 * kPcAlign);
ScopedArenaVector<uint8_t> memory = stream.Encode();
CodeInfo code_info(memory.data());
@@ -431,7 +431,7 @@
stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
stream.EndStackMapEntry();
- stream.EndMethod();
+ stream.EndMethod(66 * kPcAlign);
ScopedArenaVector<uint8_t> memory = stream.Encode();
CodeInfo ci(memory.data());
@@ -479,7 +479,7 @@
stream.AddDexRegisterEntry(Kind::kNone, 0);
stream.EndStackMapEntry();
- stream.EndMethod();
+ stream.EndMethod(68 * kPcAlign);
ScopedArenaVector<uint8_t> memory = stream.Encode();
CodeInfo code_info(memory.data());
@@ -578,7 +578,7 @@
stream.EndStackMapEntry();
- stream.EndMethod();
+ stream.EndMethod(78 * kPcAlign);
ScopedArenaVector<uint8_t> memory = stream.Encode();
CodeInfo ci(memory.data());
@@ -722,7 +722,7 @@
stream.BeginStackMapEntry(0, 8 * kPcAlign, 0x3, &sp_mask);
stream.EndStackMapEntry();
- stream.EndMethod();
+ stream.EndMethod(8 * kPcAlign);
ScopedArenaVector<uint8_t> memory = stream.Encode();
CodeInfo code_info(memory.data());
@@ -746,7 +746,7 @@
stream.AddDexRegisterEntry(Kind::kConstant, -2);
stream.EndStackMapEntry();
- stream.EndMethod();
+ stream.EndMethod(64 * kPcAlign);
ScopedArenaVector<uint8_t> memory = stream.Encode();
std::vector<uint8_t> out;
diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc
index 521bc78..7e0f29d 100644
--- a/dex2oat/linker/elf_writer_quick.cc
+++ b/dex2oat/linker/elf_writer_quick.cc
@@ -281,7 +281,7 @@
// The Strip method expects debug info to be last (mini-debug-info is not stripped).
if (!debug_info.Empty() && compiler_options_.GetGenerateDebugInfo()) {
// Generate all the debug information we can.
- debug::WriteDebugInfo(builder_.get(), debug_info, true /* write_oat_patches */);
+ debug::WriteDebugInfo(builder_.get(), debug_info);
}
}
diff --git a/dex2oat/linker/elf_writer_test.cc b/dex2oat/linker/elf_writer_test.cc
index b381765..e016f29 100644
--- a/dex2oat/linker/elf_writer_test.cc
+++ b/dex2oat/linker/elf_writer_test.cc
@@ -139,43 +139,5 @@
}
}
-TEST_F(ElfWriterTest, EncodeDecodeOatPatches) {
- const std::vector<std::vector<uintptr_t>> test_data {
- { 0, 4, 8, 15, 128, 200 },
- { 8, 8 + 127 },
- { 8, 8 + 128 },
- { },
- };
- for (const auto& patch_locations : test_data) {
- constexpr int32_t delta = 0x11235813;
-
- // Encode patch locations.
- std::vector<uint8_t> oat_patches;
- ElfBuilder<ElfTypes32>::EncodeOatPatches(ArrayRef<const uintptr_t>(patch_locations),
- &oat_patches);
-
- // Create buffer to be patched.
- std::vector<uint8_t> initial_data(256);
- for (size_t i = 0; i < initial_data.size(); i++) {
- initial_data[i] = i;
- }
-
- // Patch manually.
- std::vector<uint8_t> expected = initial_data;
- for (uintptr_t location : patch_locations) {
- using UnalignedAddress __attribute__((__aligned__(1))) = uint32_t;
- *reinterpret_cast<UnalignedAddress*>(expected.data() + location) += delta;
- }
-
- // Decode and apply patch locations.
- std::vector<uint8_t> actual = initial_data;
- ElfFileImpl32::ApplyOatPatches(
- oat_patches.data(), oat_patches.data() + oat_patches.size(), delta,
- actual.data(), actual.data() + actual.size());
-
- EXPECT_EQ(expected, actual);
- }
-}
-
} // namespace linker
} // namespace art
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index feb5e38..2289a9c 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -205,6 +205,8 @@
cc_library_headers {
name: "libdexfile_external_headers",
host_supported: true,
+ vendor_available: true,
+ recovery_available: true,
header_libs: ["libbase_headers"],
export_header_lib_headers: ["libbase_headers"],
export_include_dirs: ["external/include"],
@@ -245,23 +247,37 @@
}
// Support library with a C++ API for accessing the libdexfile API for external
-// (non-ART) users. They should link to their own instance of this (either
-// statically or through linker namespaces).
+// (non-ART) users.
+//
+// This library dlopens libdexfile_external on first use, so there is no build
+// time dependency on dex file logic. It is therefore safe to use from binaries
+// compiled without dex file support, given they won't encounter any dex file
+// stack frames.
cc_library {
name: "libdexfile_support",
host_supported: true,
+ vendor_available: true,
+ recovery_available: true,
srcs: [
"external/dex_file_supp.cc",
],
+ required: ["libdexfile_external"],
+ shared_libs: ["liblog"],
header_libs: ["libdexfile_external_headers"],
- shared_libs: ["libdexfile_external"],
export_header_lib_headers: ["libdexfile_external_headers"],
+ target: {
+ recovery: {
+ cflags: ["-DNO_DEXFILE_SUPPORT"],
+ },
+ vendor: {
+ cflags: ["-DNO_DEXFILE_SUPPORT"],
+ },
+ },
}
art_cc_test {
name: "art_libdexfile_support_tests",
host_supported: true,
- test_per_src: true, // For consistency with other ART gtests.
srcs: [
"external/dex_file_supp_test.cc",
],
@@ -272,3 +288,36 @@
"libdexfile_support",
],
}
+
+cc_library_static {
+ name: "libdexfile_support_static",
+ host_supported: true,
+ defaults: ["libdexfile_static_defaults"],
+ srcs: [
+ "external/dex_file_supp.cc",
+ ],
+ cflags: ["-DSTATIC_LIB"],
+ // Using whole_static_libs here only as a "poor man's transitivity" kludge.
+ whole_static_libs: [
+ "libbase",
+ "libdexfile",
+ "libdexfile_external",
+ "liblog",
+ "libz",
+ "libziparchive",
+ ],
+ header_libs: ["libdexfile_external_headers"],
+ export_header_lib_headers: ["libdexfile_external_headers"],
+}
+
+art_cc_test {
+ name: "art_libdexfile_support_static_tests",
+ host_supported: true,
+ srcs: [
+ "external/dex_file_supp_test.cc",
+ ],
+ static_libs: [
+ "libbase",
+ "libdexfile_support_static",
+ ],
+}
diff --git a/libdexfile/external/dex_file_supp.cc b/libdexfile/external/dex_file_supp.cc
index 5bd25fc..ba684fe 100644
--- a/libdexfile/external/dex_file_supp.cc
+++ b/libdexfile/external/dex_file_supp.cc
@@ -16,10 +16,74 @@
#include "art_api/dex_file_support.h"
+#include <dlfcn.h>
+#include <mutex>
+
+#ifndef STATIC_LIB
+// Not used in the static lib, so avoid a dependency on this header in
+// libdexfile_support_static.
+#include <log/log.h>
+#endif
+
namespace art_api {
namespace dex {
-DexFile::~DexFile() { ExtDexFileFree(ext_dex_file_); }
+#ifdef STATIC_LIB
+#define DEFINE_DLFUNC_PTR(CLASS, DLFUNC) decltype(DLFUNC)* CLASS::g_##DLFUNC = DLFUNC
+#else
+#define DEFINE_DLFUNC_PTR(CLASS, DLFUNC) decltype(DLFUNC)* CLASS::g_##DLFUNC = nullptr
+#endif
+
+DEFINE_DLFUNC_PTR(DexString, ExtDexFileMakeString);
+DEFINE_DLFUNC_PTR(DexString, ExtDexFileGetString);
+DEFINE_DLFUNC_PTR(DexString, ExtDexFileFreeString);
+DEFINE_DLFUNC_PTR(DexFile, ExtDexFileOpenFromMemory);
+DEFINE_DLFUNC_PTR(DexFile, ExtDexFileOpenFromFd);
+DEFINE_DLFUNC_PTR(DexFile, ExtDexFileGetMethodInfoForOffset);
+DEFINE_DLFUNC_PTR(DexFile, ExtDexFileGetAllMethodInfos);
+DEFINE_DLFUNC_PTR(DexFile, ExtDexFileFree);
+
+#undef DEFINE_DLFUNC_PTR
+
+void LoadLibdexfileExternal() {
+#if defined(STATIC_LIB)
+ // Nothing to do here since all function pointers are initialised statically.
+#elif defined(NO_DEXFILE_SUPPORT)
+ LOG_FATAL("Dex file support not available.");
+#else
+ static std::once_flag dlopen_once;
+ std::call_once(dlopen_once, []() {
+ constexpr char kLibdexfileExternalLib[] = "libdexfile_external.so";
+ void* handle =
+ dlopen(kLibdexfileExternalLib, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
+ LOG_ALWAYS_FATAL_IF(handle == nullptr, "Failed to load %s: %s",
+ kLibdexfileExternalLib, dlerror());
+
+#define SET_DLFUNC_PTR(CLASS, DLFUNC) \
+ do { \
+ CLASS::g_##DLFUNC = reinterpret_cast<decltype(DLFUNC)*>(dlsym(handle, #DLFUNC)); \
+ LOG_ALWAYS_FATAL_IF(CLASS::g_##DLFUNC == nullptr, \
+ "Failed to find %s in %s: %s", \
+ #DLFUNC, \
+ kLibdexfileExternalLib, \
+ dlerror()); \
+ } while (0)
+
+ SET_DLFUNC_PTR(DexString, ExtDexFileMakeString);
+ SET_DLFUNC_PTR(DexString, ExtDexFileGetString);
+ SET_DLFUNC_PTR(DexString, ExtDexFileFreeString);
+ SET_DLFUNC_PTR(DexFile, ExtDexFileOpenFromMemory);
+ SET_DLFUNC_PTR(DexFile, ExtDexFileOpenFromFd);
+ SET_DLFUNC_PTR(DexFile, ExtDexFileGetMethodInfoForOffset);
+ SET_DLFUNC_PTR(DexFile, ExtDexFileGetAllMethodInfos);
+ SET_DLFUNC_PTR(DexFile, ExtDexFileFree);
+
+#undef SET_DLFUNC_PTR
+ });
+#endif // !defined(NO_DEXFILE_SUPPORT) && !defined(STATIC_LIB)
+}
+
+DexFile::~DexFile() { g_ExtDexFileFree(ext_dex_file_); }
MethodInfo DexFile::AbsorbMethodInfo(const ExtDexFileMethodInfo& ext_method_info) {
return {ext_method_info.offset, ext_method_info.len, DexString(ext_method_info.name)};
diff --git a/libdexfile/external/include/art_api/dex_file_support.h b/libdexfile/external/include/art_api/dex_file_support.h
index 24222af..a98ff0e 100644
--- a/libdexfile/external/include/art_api/dex_file_support.h
+++ b/libdexfile/external/include/art_api/dex_file_support.h
@@ -33,17 +33,22 @@
namespace art_api {
namespace dex {
+// Loads the libdexfile_external.so library and sets up function pointers.
+// Aborts with a fatal error on any error. For internal use by the classes
+// below.
+void LoadLibdexfileExternal();
+
// Minimal std::string look-alike for a string returned from libdexfile.
class DexString final {
public:
DexString(DexString&& dex_str) noexcept : ext_string_(dex_str.ext_string_) {
- dex_str.ext_string_ = ExtDexFileMakeString("", 0);
+ dex_str.ext_string_ = MakeExtDexFileString("", 0);
}
explicit DexString(const char* str = "")
- : ext_string_(ExtDexFileMakeString(str, std::strlen(str))) {}
+ : ext_string_(MakeExtDexFileString(str, std::strlen(str))) {}
explicit DexString(std::string_view str)
- : ext_string_(ExtDexFileMakeString(str.data(), str.size())) {}
- ~DexString() { ExtDexFileFreeString(ext_string_); }
+ : ext_string_(MakeExtDexFileString(str.data(), str.size())) {}
+ ~DexString() { g_ExtDexFileFreeString(ext_string_); }
DexString& operator=(DexString&& dex_str) noexcept {
std::swap(ext_string_, dex_str.ext_string_);
@@ -52,36 +57,48 @@
const char* data() const {
size_t ignored;
- return ExtDexFileGetString(ext_string_, &ignored);
+ return g_ExtDexFileGetString(ext_string_, &ignored);
}
const char* c_str() const { return data(); }
size_t size() const {
size_t len;
- (void)ExtDexFileGetString(ext_string_, &len);
+ (void)g_ExtDexFileGetString(ext_string_, &len);
return len;
}
size_t length() const { return size(); }
operator std::string_view() const {
size_t len;
- const char* chars = ExtDexFileGetString(ext_string_, &len);
+ const char* chars = g_ExtDexFileGetString(ext_string_, &len);
return std::string_view(chars, len);
}
private:
+ friend void LoadLibdexfileExternal();
friend class DexFile;
friend bool operator==(const DexString&, const DexString&);
explicit DexString(const ExtDexFileString* ext_string) : ext_string_(ext_string) {}
const ExtDexFileString* ext_string_; // Owned instance. Never nullptr.
+ static decltype(ExtDexFileMakeString)* g_ExtDexFileMakeString;
+ static decltype(ExtDexFileGetString)* g_ExtDexFileGetString;
+ static decltype(ExtDexFileFreeString)* g_ExtDexFileFreeString;
+
+ static const struct ExtDexFileString* MakeExtDexFileString(const char* str, size_t size) {
+ if (UNLIKELY(g_ExtDexFileMakeString == nullptr)) {
+ LoadLibdexfileExternal();
+ }
+ return g_ExtDexFileMakeString(str, size);
+ }
+
DISALLOW_COPY_AND_ASSIGN(DexString);
};
inline bool operator==(const DexString& s1, const DexString& s2) {
size_t l1, l2;
- const char* str1 = ExtDexFileGetString(s1.ext_string_, &l1);
- const char* str2 = ExtDexFileGetString(s2.ext_string_, &l2);
+ const char* str1 = DexString::g_ExtDexFileGetString(s1.ext_string_, &l1);
+ const char* str2 = DexString::g_ExtDexFileGetString(s2.ext_string_, &l2);
// Use memcmp to avoid assumption about absence of null characters in the strings.
return l1 == l2 && !std::memcmp(str1, str2, l1);
}
@@ -120,9 +137,14 @@
size_t* size,
const std::string& location,
/*out*/ std::string* error_msg) {
+ if (UNLIKELY(g_ExtDexFileOpenFromMemory == nullptr)) {
+ // Load libdexfile_external.so in this factory function, so instance
+ // methods don't need to check this.
+ LoadLibdexfileExternal();
+ }
ExtDexFile* ext_dex_file;
const ExtDexFileString* ext_error_msg = nullptr;
- if (ExtDexFileOpenFromMemory(addr, size, location.c_str(), &ext_error_msg, &ext_dex_file)) {
+ if (g_ExtDexFileOpenFromMemory(addr, size, location.c_str(), &ext_error_msg, &ext_dex_file)) {
return std::unique_ptr<DexFile>(new DexFile(ext_dex_file));
}
*error_msg = (ext_error_msg == nullptr) ? "" : std::string(DexString(ext_error_msg));
@@ -138,9 +160,14 @@
off_t offset,
const std::string& location,
/*out*/ std::string* error_msg) {
+ if (UNLIKELY(g_ExtDexFileOpenFromFd == nullptr)) {
+ // Load libdexfile_external.so in this factory function, so instance
+ // methods don't need to check this.
+ LoadLibdexfileExternal();
+ }
ExtDexFile* ext_dex_file;
const ExtDexFileString* ext_error_msg = nullptr;
- if (ExtDexFileOpenFromFd(fd, offset, location.c_str(), &ext_error_msg, &ext_dex_file)) {
+ if (g_ExtDexFileOpenFromFd(fd, offset, location.c_str(), &ext_error_msg, &ext_dex_file)) {
return std::unique_ptr<DexFile>(new DexFile(ext_dex_file));
}
*error_msg = std::string(DexString(ext_error_msg));
@@ -154,10 +181,10 @@
// class and method name only.
MethodInfo GetMethodInfoForOffset(int64_t dex_offset, bool with_signature) {
ExtDexFileMethodInfo ext_method_info;
- if (ExtDexFileGetMethodInfoForOffset(ext_dex_file_,
- dex_offset,
- with_signature,
- &ext_method_info)) {
+ if (g_ExtDexFileGetMethodInfoForOffset(ext_dex_file_,
+ dex_offset,
+ with_signature,
+ &ext_method_info)) {
return AbsorbMethodInfo(ext_method_info);
}
return {/*offset=*/0, /*len=*/0, /*name=*/DexString()};
@@ -168,14 +195,15 @@
// gets the class and method name only.
std::vector<MethodInfo> GetAllMethodInfos(bool with_signature) {
MethodInfoVector res;
- ExtDexFileGetAllMethodInfos(ext_dex_file_,
- with_signature,
- AddMethodInfoCallback,
- static_cast<void*>(&res));
+ g_ExtDexFileGetAllMethodInfos(ext_dex_file_,
+ with_signature,
+ AddMethodInfoCallback,
+ static_cast<void*>(&res));
return res;
}
private:
+ friend void LoadLibdexfileExternal();
explicit DexFile(ExtDexFile* ext_dex_file) : ext_dex_file_(ext_dex_file) {}
ExtDexFile* ext_dex_file_; // Owned instance. nullptr only in moved-from zombies.
@@ -184,6 +212,12 @@
static MethodInfo AbsorbMethodInfo(const ExtDexFileMethodInfo& ext_method_info);
static void AddMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info, void* user_data);
+ static decltype(ExtDexFileOpenFromMemory)* g_ExtDexFileOpenFromMemory;
+ static decltype(ExtDexFileOpenFromFd)* g_ExtDexFileOpenFromFd;
+ static decltype(ExtDexFileGetMethodInfoForOffset)* g_ExtDexFileGetMethodInfoForOffset;
+ static decltype(ExtDexFileGetAllMethodInfos)* g_ExtDexFileGetAllMethodInfos;
+ static decltype(ExtDexFileFree)* g_ExtDexFileFree;
+
DISALLOW_COPY_AND_ASSIGN(DexFile);
};
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index b1be646..c3abe6c 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -221,7 +221,7 @@
debug::DebugInfo debug_info{};
debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(method_debug_infos_);
- debug::WriteDebugInfo(builder_.get(), debug_info, /* write_oat_patches= */ true);
+ debug::WriteDebugInfo(builder_.get(), debug_info);
builder_->End();
diff --git a/openjdkjvmti/jvmti_weak_table-inl.h b/openjdkjvmti/jvmti_weak_table-inl.h
index d9b8a84..5b28e45 100644
--- a/openjdkjvmti/jvmti_weak_table-inl.h
+++ b/openjdkjvmti/jvmti_weak_table-inl.h
@@ -77,7 +77,7 @@
}
template <typename T>
-bool JvmtiWeakTable<T>::GetTagSlowPath(art::Thread* self, art::mirror::Object* obj, T* result) {
+bool JvmtiWeakTable<T>::GetTagSlowPath(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, T* result) {
// Under concurrent GC, there is a window between moving objects and sweeping of system
// weaks in which mutators are active. We may receive a to-space object pointer in obj,
// but still have from-space pointers in the table. Explicitly update the table once.
@@ -87,7 +87,7 @@
}
template <typename T>
-bool JvmtiWeakTable<T>::Remove(art::mirror::Object* obj, /* out */ T* tag) {
+bool JvmtiWeakTable<T>::Remove(art::ObjPtr<art::mirror::Object> obj, /* out */ T* tag) {
art::Thread* self = art::Thread::Current();
art::MutexLock mu(self, allow_disallow_lock_);
Wait(self);
@@ -95,7 +95,7 @@
return RemoveLocked(self, obj, tag);
}
template <typename T>
-bool JvmtiWeakTable<T>::RemoveLocked(art::mirror::Object* obj, T* tag) {
+bool JvmtiWeakTable<T>::RemoveLocked(art::ObjPtr<art::mirror::Object> obj, T* tag) {
art::Thread* self = art::Thread::Current();
allow_disallow_lock_.AssertHeld(self);
Wait(self);
@@ -104,7 +104,7 @@
}
template <typename T>
-bool JvmtiWeakTable<T>::RemoveLocked(art::Thread* self, art::mirror::Object* obj, T* tag) {
+bool JvmtiWeakTable<T>::RemoveLocked(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, T* tag) {
auto it = tagged_objects_.find(art::GcRoot<art::mirror::Object>(obj));
if (it != tagged_objects_.end()) {
if (tag != nullptr) {
@@ -132,7 +132,7 @@
}
template <typename T>
-bool JvmtiWeakTable<T>::Set(art::mirror::Object* obj, T new_tag) {
+bool JvmtiWeakTable<T>::Set(art::ObjPtr<art::mirror::Object> obj, T new_tag) {
art::Thread* self = art::Thread::Current();
art::MutexLock mu(self, allow_disallow_lock_);
Wait(self);
@@ -140,7 +140,7 @@
return SetLocked(self, obj, new_tag);
}
template <typename T>
-bool JvmtiWeakTable<T>::SetLocked(art::mirror::Object* obj, T new_tag) {
+bool JvmtiWeakTable<T>::SetLocked(art::ObjPtr<art::mirror::Object> obj, T new_tag) {
art::Thread* self = art::Thread::Current();
allow_disallow_lock_.AssertHeld(self);
Wait(self);
@@ -149,7 +149,7 @@
}
template <typename T>
-bool JvmtiWeakTable<T>::SetLocked(art::Thread* self, art::mirror::Object* obj, T new_tag) {
+bool JvmtiWeakTable<T>::SetLocked(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, T new_tag) {
auto it = tagged_objects_.find(art::GcRoot<art::mirror::Object>(obj));
if (it != tagged_objects_.end()) {
it->second = new_tag;
@@ -362,7 +362,7 @@
}
if (select) {
- art::mirror::Object* obj = pair.first.template Read<art::kWithReadBarrier>();
+ art::ObjPtr<art::mirror::Object> obj = pair.first.template Read<art::kWithReadBarrier>();
if (obj != nullptr) {
count++;
if (object_result_ptr != nullptr) {
@@ -386,14 +386,14 @@
}
template <typename T>
-art::mirror::Object* JvmtiWeakTable<T>::Find(T tag) {
+art::ObjPtr<art::mirror::Object> JvmtiWeakTable<T>::Find(T tag) {
art::Thread* self = art::Thread::Current();
art::MutexLock mu(self, allow_disallow_lock_);
Wait(self);
for (auto& pair : tagged_objects_) {
if (tag == pair.second) {
- art::mirror::Object* obj = pair.first.template Read<art::kWithReadBarrier>();
+ art::ObjPtr<art::mirror::Object> obj = pair.first.template Read<art::kWithReadBarrier>();
if (obj != nullptr) {
return obj;
}
diff --git a/openjdkjvmti/jvmti_weak_table.h b/openjdkjvmti/jvmti_weak_table.h
index cba8ef0..ea0d023 100644
--- a/openjdkjvmti/jvmti_weak_table.h
+++ b/openjdkjvmti/jvmti_weak_table.h
@@ -60,25 +60,25 @@
// Remove the mapping for the given object, returning whether such a mapping existed (and the old
// value).
- ALWAYS_INLINE bool Remove(art::mirror::Object* obj, /* out */ T* tag)
+ ALWAYS_INLINE bool Remove(art::ObjPtr<art::mirror::Object> obj, /* out */ T* tag)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(!allow_disallow_lock_);
- ALWAYS_INLINE bool RemoveLocked(art::mirror::Object* obj, /* out */ T* tag)
+ ALWAYS_INLINE bool RemoveLocked(art::ObjPtr<art::mirror::Object> obj, /* out */ T* tag)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(allow_disallow_lock_);
// Set the mapping for the given object. Returns true if this overwrites an already existing
// mapping.
- ALWAYS_INLINE virtual bool Set(art::mirror::Object* obj, T tag)
+ ALWAYS_INLINE virtual bool Set(art::ObjPtr<art::mirror::Object> obj, T tag)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(!allow_disallow_lock_);
- ALWAYS_INLINE virtual bool SetLocked(art::mirror::Object* obj, T tag)
+ ALWAYS_INLINE virtual bool SetLocked(art::ObjPtr<art::mirror::Object> obj, T tag)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(allow_disallow_lock_);
// Return the value associated with the given object. Returns true if the mapping exists, false
// otherwise.
- bool GetTag(art::mirror::Object* obj, /* out */ T* result)
+ bool GetTag(art::ObjPtr<art::mirror::Object> obj, /* out */ T* result)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(!allow_disallow_lock_) {
art::Thread* self = art::Thread::Current();
@@ -87,7 +87,7 @@
return GetTagLocked(self, obj, result);
}
- bool GetTagLocked(art::mirror::Object* obj, /* out */ T* result)
+ bool GetTagLocked(art::ObjPtr<art::mirror::Object> obj, /* out */ T* result)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(allow_disallow_lock_) {
art::Thread* self = art::Thread::Current();
@@ -118,7 +118,7 @@
ALWAYS_INLINE void Unlock() RELEASE(allow_disallow_lock_);
ALWAYS_INLINE void AssertLocked() ASSERT_CAPABILITY(allow_disallow_lock_);
- ALWAYS_INLINE art::mirror::Object* Find(T tag)
+ ALWAYS_INLINE art::ObjPtr<art::mirror::Object> Find(T tag)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(!allow_disallow_lock_);
@@ -132,16 +132,16 @@
private:
ALWAYS_INLINE
- bool SetLocked(art::Thread* self, art::mirror::Object* obj, T tag)
+ bool SetLocked(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, T tag)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(allow_disallow_lock_);
ALWAYS_INLINE
- bool RemoveLocked(art::Thread* self, art::mirror::Object* obj, /* out */ T* tag)
+ bool RemoveLocked(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, /* out */ T* tag)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(allow_disallow_lock_);
- bool GetTagLocked(art::Thread* self, art::mirror::Object* obj, /* out */ T* result)
+ bool GetTagLocked(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, /* out */ T* result)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(allow_disallow_lock_) {
auto it = tagged_objects_.find(art::GcRoot<art::mirror::Object>(obj));
@@ -165,7 +165,7 @@
// Slow-path for GetTag. We didn't find the object, but we might be storing from-pointers and
// are asked to retrieve with a to-pointer.
ALWAYS_INLINE
- bool GetTagSlowPath(art::Thread* self, art::mirror::Object* obj, /* out */ T* result)
+ bool GetTagSlowPath(art::Thread* self, art::ObjPtr<art::mirror::Object> obj, /* out */ T* result)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(allow_disallow_lock_);
diff --git a/openjdkjvmti/object_tagging.cc b/openjdkjvmti/object_tagging.cc
index 0a51bf2..d52933a 100644
--- a/openjdkjvmti/object_tagging.cc
+++ b/openjdkjvmti/object_tagging.cc
@@ -71,7 +71,7 @@
jvmti_env_, art::Thread::Current(), tag);
}
-bool ObjectTagTable::Set(art::mirror::Object* obj, jlong new_tag) {
+bool ObjectTagTable::Set(art::ObjPtr<art::mirror::Object> obj, jlong new_tag) {
if (new_tag == 0) {
jlong tmp;
return Remove(obj, &tmp);
@@ -79,7 +79,7 @@
return JvmtiWeakTable<jlong>::Set(obj, new_tag);
}
-bool ObjectTagTable::SetLocked(art::mirror::Object* obj, jlong new_tag) {
+bool ObjectTagTable::SetLocked(art::ObjPtr<art::mirror::Object> obj, jlong new_tag) {
if (new_tag == 0) {
jlong tmp;
return RemoveLocked(obj, &tmp);
diff --git a/openjdkjvmti/object_tagging.h b/openjdkjvmti/object_tagging.h
index ca05a05..bd72ce3 100644
--- a/openjdkjvmti/object_tagging.h
+++ b/openjdkjvmti/object_tagging.h
@@ -61,21 +61,21 @@
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(!allow_disallow_lock_);
- bool Set(art::mirror::Object* obj, jlong tag) override
+ bool Set(art::ObjPtr<art::mirror::Object> obj, jlong tag) override
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(!allow_disallow_lock_);
- bool SetLocked(art::mirror::Object* obj, jlong tag) override
+ bool SetLocked(art::ObjPtr<art::mirror::Object> obj, jlong tag) override
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(allow_disallow_lock_);
- jlong GetTagOrZero(art::mirror::Object* obj)
+ jlong GetTagOrZero(art::ObjPtr<art::mirror::Object> obj)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(!allow_disallow_lock_) {
jlong tmp = 0;
GetTag(obj, &tmp);
return tmp;
}
- jlong GetTagOrZeroLocked(art::mirror::Object* obj)
+ jlong GetTagOrZeroLocked(art::ObjPtr<art::mirror::Object> obj)
REQUIRES_SHARED(art::Locks::mutator_lock_)
REQUIRES(allow_disallow_lock_) {
jlong tmp = 0;
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index eb4bada..e51ae4d 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -240,7 +240,7 @@
art::ScopedObjectAccess soa(self);
art::StackHandleScope<1> hs(self);
art::ObjPtr<art::mirror::Object> obj(self->DecodeJObject(klass));
- if (obj.IsNull()) {
+ if (obj.IsNull() || !obj->IsClass()) {
return ERR(INVALID_CLASS);
}
art::Handle<art::mirror::Class> h_klass(hs.NewHandle(obj->AsClass()));
@@ -256,7 +256,7 @@
art::ScopedObjectAccess soa(self);
art::StackHandleScope<1> hs(self);
art::ObjPtr<art::mirror::Object> obj(self->DecodeJObject(klass));
- if (obj.IsNull()) {
+ if (obj.IsNull() || !obj->IsClass()) {
return ERR(INVALID_CLASS);
}
art::Handle<art::mirror::Class> h_klass(hs.NewHandle(obj->AsClass()));
diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc
index a4425ce..150fa78 100644
--- a/runtime/native_stack_dump.cc
+++ b/runtime/native_stack_dump.cc
@@ -44,6 +44,7 @@
#include "arch/instruction_set.h"
#include "base/aborting.h"
+#include "base/bit_utils.h"
#include "base/file_utils.h"
#include "base/memory_tool.h"
#include "base/mutex.h"
@@ -51,6 +52,7 @@
#include "base/unix_file/fd_file.h"
#include "base/utils.h"
#include "class_linker.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
#include "oat_quick_method_header.h"
#include "runtime.h"
#include "thread-current-inl.h"
@@ -299,6 +301,11 @@
class_linker->IsQuickToInterpreterBridge(entry_point)) {
return false;
}
+ // The backtrace library might have heuristically subracted instruction
+ // size from the pc, to pretend the pc is at the calling instruction.
+ if (reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) - pc <= 4) {
+ return false;
+ }
uintptr_t code = reinterpret_cast<uintptr_t>(EntryPointToCodePointer(entry_point));
uintptr_t code_size = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].GetCodeSize();
return code <= pc && pc <= (code + code_size);
diff --git a/runtime/oat.h b/runtime/oat.h
index 88238d9..b824729 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -31,8 +31,8 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- // Last oat version changed reason: Partial boot image.
- static constexpr uint8_t kOatVersion[] = { '1', '6', '6', '\0' };
+ // Last oat version changed reason: Add code size to CodeInfo.
+ static constexpr uint8_t kOatVersion[] = { '1', '6', '7', '\0' };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h
index 8798c69..6c123c4 100644
--- a/runtime/oat_quick_method_header.h
+++ b/runtime/oat_quick_method_header.h
@@ -35,6 +35,8 @@
uint32_t code_size)
: vmap_table_offset_(vmap_table_offset),
code_size_(code_size) {
+ DCHECK_NE(vmap_table_offset, 0u);
+ DCHECK_NE(code_size, 0u);
}
static OatQuickMethodHeader* FromCodePointer(const void* code_ptr) {
@@ -58,7 +60,7 @@
}
bool IsOptimized() const {
- return GetCodeSize() != 0 && vmap_table_offset_ != 0;
+ return (code_size_ & kCodeSizeMask) != 0 && vmap_table_offset_ != 0;
}
const uint8_t* GetOptimizedCodeInfoPtr() const {
@@ -76,7 +78,11 @@
}
uint32_t GetCodeSize() const {
- return code_size_ & kCodeSizeMask;
+ DCHECK(IsOptimized());
+ size_t code_size1 = code_size_ & kCodeSizeMask;
+ size_t code_size2 = CodeInfo::DecodeCodeSize(GetOptimizedCodeInfoPtr());
+ DCHECK_EQ(code_size1, code_size2);
+ return code_size2;
}
const uint32_t* GetCodeSizeAddr() const {
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 62dec15..5d30b77 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -227,6 +227,7 @@
bool verbose,
InstructionSet instruction_set) const {
vios->Stream() << "CodeInfo BitSize=" << size_in_bits_
+ << " CodeSize:" << StackMap::UnpackNativePc(packed_code_size_, instruction_set)
<< " FrameSize:" << packed_frame_size_ * kStackAlignment
<< " CoreSpillMask:" << std::hex << core_spill_mask_
<< " FpSpillMask:" << std::hex << fp_spill_mask_
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 87133cf..59da923 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -438,8 +438,15 @@
// Accumulate code info size statistics into the given Stats tree.
static void CollectSizeStats(const uint8_t* code_info, /*out*/ Stats* parent);
+ ALWAYS_INLINE static size_t DecodeCodeSize(const uint8_t* data,
+ InstructionSet isa = kRuntimeISA) {
+ uint32_t packed_code_size = BitMemoryReader(data).ReadVarint();
+ return StackMap::UnpackNativePc(packed_code_size, isa);
+ }
+
ALWAYS_INLINE static QuickMethodFrameInfo DecodeFrameInfo(const uint8_t* data) {
BitMemoryReader reader(data);
+ reader.ReadVarint(); // Skip code size.
return QuickMethodFrameInfo(
reader.ReadVarint() * kStackAlignment, // Decode packed_frame_size_ and unpack.
reader.ReadVarint(), // core_spill_mask_.
@@ -461,6 +468,7 @@
// Invokes the callback with member pointer of each header field.
template<typename Callback>
ALWAYS_INLINE static void ForEachHeaderField(Callback callback) {
+ callback(&CodeInfo::packed_code_size_);
callback(&CodeInfo::packed_frame_size_);
callback(&CodeInfo::core_spill_mask_);
callback(&CodeInfo::fp_spill_mask_);
@@ -486,6 +494,7 @@
callback(&CodeInfo::dex_register_catalog_);
}
+ uint32_t packed_code_size_ = 0; // The size of native PC range.
uint32_t packed_frame_size_ = 0; // Frame size in kStackAlignment units.
uint32_t core_spill_mask_ = 0;
uint32_t fp_spill_mask_ = 0;
diff --git a/test/905-object-free/expected.txt b/test/905-object-free/expected.txt
index c226df7..dfcd7b6 100644
--- a/test/905-object-free/expected.txt
+++ b/test/905-object-free/expected.txt
@@ -10,4 +10,4 @@
---
[]
---
-Free counts 100000 100000
+Free counts 200000 200000
diff --git a/test/905-object-free/src/art/Test905.java b/test/905-object-free/src/art/Test905.java
index dddd1aa..367da99 100644
--- a/test/905-object-free/src/art/Test905.java
+++ b/test/905-object-free/src/art/Test905.java
@@ -20,6 +20,7 @@
import java.lang.ref.ReferenceQueue;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.function.BiConsumer;
public class Test905 {
// Taken from jdwp tests.
@@ -110,26 +111,59 @@
System.out.println("---");
}
- private static void stressAllocate(int i) {
+ private static void stressAllocate(int i, BiConsumer<Integer, Object> saver) {
Object obj = new Object();
Main.setTag(obj, i);
setTag2(obj, i + 1);
+ saver.accept(i, obj);
}
private static void stress() {
getCollectedTags(0);
getCollectedTags(1);
- // Allocate objects.
- for (int i = 1; i <= 100000; ++i) {
- stressAllocate(i);
+ final int num_obj = 400000;
+ final Object[] saved = new Object[num_obj/2];
+ // Allocate objects, Save every other one. We want to be sure that it's only the deleted objects
+ // that get their tags cleared and non-deleted objects correctly keep track of their tags.
+ for (int i = 1; i <= num_obj; ++i) {
+ stressAllocate(i, (idx, obj) -> {
+ if ((idx.intValue() - 1) % 2 == 0) {
+ saved[(idx.intValue() - 1)/2] = obj;
+ }
+ });
}
gcAndWait();
long[] freedTags1 = getCollectedTags(0);
long[] freedTags2 = getCollectedTags(1);
+ // Sort the freedtags
+ Arrays.sort(freedTags1);
+ Arrays.sort(freedTags2);
+ // Make sure we freed all the ones we expect to and both envs agree on this.
System.out.println("Free counts " + freedTags1.length + " " + freedTags2.length);
for (int i = 0; i < freedTags1.length; ++i) {
if (freedTags1[i] + 1 != freedTags2[i]) {
- System.out.println("Mismatched tags " + freedTags1[i] + " " + freedTags2[i]);
+ System.out.println("Mismatched tags " + (freedTags1[i] + 1) + " " + freedTags2[i]);
+ }
+ }
+ // Make sure the saved-tags aren't present.
+ for (int i = 0; i < saved.length; i++) {
+ // index = (tag - 1)/2 --> (index * 2) + 1 = tag
+ long expectedTag1 = (i * 2) + 1;
+ if (Main.getTag(saved[i]) != expectedTag1) {
+ System.out.println("Saved object has unexpected tag in env 1. Expected "
+ + expectedTag1 + " got " + Main.getTag(saved[i]));
+ }
+ if (getTag2(saved[i]) != 1 + expectedTag1) {
+ System.out.println("Saved object has unexpected tag in env 2. Expected "
+ + (expectedTag1 + 1) + " got " + getTag2(saved[i]));
+ }
+ if (Arrays.binarySearch(freedTags1, expectedTag1) >= 0) {
+ System.out.println("Saved object was marked as deleted in env 1. Object was "
+ + expectedTag1);
+ }
+ if (Arrays.binarySearch(freedTags2, expectedTag1 + 1) >= 0) {
+ System.out.println("Saved object was marked as deleted in env 2. Object was "
+ + (expectedTag1 + 1));
}
}
}
@@ -161,4 +195,5 @@
private static native void enableFreeTracking(boolean enable);
private static native long[] getCollectedTags(int index);
private static native void setTag2(Object o, long tag);
+ private static native long getTag2(Object o);
}
diff --git a/test/905-object-free/tracking_free.cc b/test/905-object-free/tracking_free.cc
index bf86c9a..d85d9d3 100644
--- a/test/905-object-free/tracking_free.cc
+++ b/test/905-object-free/tracking_free.cc
@@ -18,6 +18,7 @@
#include <cstdio>
#include <iostream>
+#include <mutex>
#include <vector>
#include "android-base/logging.h"
@@ -33,17 +34,23 @@
namespace art {
namespace Test905ObjectFree {
+// The ObjectFree functions aren't required to be called on any particular thread so use these
+// mutexs to control access to the collected_tags lists.
+std::mutex ct1_mutex;
static std::vector<jlong> collected_tags1;
+std::mutex ct2_mutex;
static std::vector<jlong> collected_tags2;
jvmtiEnv* jvmti_env2;
static void JNICALL ObjectFree1(jvmtiEnv* ti_env, jlong tag) {
+ std::lock_guard<std::mutex> mu(ct1_mutex);
CHECK_EQ(ti_env, jvmti_env);
collected_tags1.push_back(tag);
}
static void JNICALL ObjectFree2(jvmtiEnv* ti_env, jlong tag) {
+ std::lock_guard<std::mutex> mu(ct2_mutex);
CHECK_EQ(ti_env, jvmti_env2);
collected_tags2.push_back(tag);
}
@@ -84,6 +91,7 @@
extern "C" JNIEXPORT jlongArray JNICALL Java_art_Test905_getCollectedTags(
JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jint index) {
+ std::lock_guard<std::mutex> mu((index == 0) ? ct1_mutex : ct2_mutex);
std::vector<jlong>& tags = (index == 0) ? collected_tags1 : collected_tags2;
jlongArray ret = env->NewLongArray(tags.size());
if (ret == nullptr) {
@@ -96,6 +104,14 @@
return ret;
}
+extern "C" JNIEXPORT jlong JNICALL Java_art_Test905_getTag2(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj) {
+ jlong tag;
+ jvmtiError ret = jvmti_env2->GetTag(obj, &tag);
+ JvmtiErrorToException(env, jvmti_env, ret);
+ return tag;
+}
+
extern "C" JNIEXPORT void JNICALL Java_art_Test905_setTag2(
JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj, jlong tag) {
jvmtiError ret = jvmti_env2->SetTag(obj, tag);
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 5177919..9b0873e 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -234,12 +234,5 @@
"libcore.libcore.icu.TimeZoneIntegrationTest#testTimeZoneDebugInfo",
"libcore.libcore.icu.TimeZoneIntegrationTest#testTzDataSetVersions"
]
-},
-{
- description: "Expected networking failure on host / old systems: we expect 97 (EAFNOSUPPORT), but we get 22 (EINVAL)",
- result: EXEC_FAILED,
- names: [
- "libcore.libcore.io.OsTest#testCrossFamilyBindConnectSendto"
- ]
}
]