Merge "Remove typo'd variables"
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index f7ed826..735755f 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -94,7 +94,16 @@
"libartd-disassembler"
]
-// Libcore native libraries.
+// Core Java libraries.
+libcore_java_libs = [
+ "core-oj",
+ "core-libart",
+ "okhttp",
+ "bouncycastle",
+ "apache-xml",
+]
+
+// Native libraries that support the core Java libraries.
libcore_native_shared_libs = [
"libjavacore",
"libopenjdk",
@@ -103,15 +112,6 @@
"libziparchive"
]
-// Java libraries
-libcore_target_java_libs = [
- "core-oj",
- "core-libart",
- "okhttp",
- "bouncycastle",
- "apache-xml",
-]
-
// Temporary library includes for b/123591866 as all libraries are moved into the main art-apex.
art_runtime_libraries_zipapex = [
"libnativebridge",
@@ -143,7 +143,7 @@
name: "com.android.runtime.release",
compile_multilib: "both",
manifest: "manifest.json",
- java_libs: libcore_target_java_libs,
+ java_libs: libcore_java_libs,
native_shared_libs: art_runtime_base_native_shared_libs
+ bionic_native_shared_libs
+ libcore_native_shared_libs,
@@ -173,7 +173,7 @@
name: "com.android.runtime.debug",
compile_multilib: "both",
manifest: "manifest.json",
- java_libs: libcore_target_java_libs,
+ java_libs: libcore_java_libs,
native_shared_libs: art_runtime_base_native_shared_libs
+ art_runtime_debug_native_shared_libs
+ bionic_native_shared_libs
@@ -212,7 +212,7 @@
host_supported: true,
device_supported: false,
manifest: "manifest.json",
- java_libs: libcore_target_java_libs,
+ java_libs: libcore_java_libs,
ignore_system_library_special_case: true,
native_shared_libs: art_runtime_base_native_shared_libs
+ art_runtime_debug_native_shared_libs
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h
index 81a2179..90be30b 100644
--- a/cmdline/cmdline.h
+++ b/cmdline/cmdline.h
@@ -23,13 +23,14 @@
#include <fstream>
#include <iostream>
#include <string>
+#include <string_view>
#include "android-base/stringprintf.h"
#include "base/file_utils.h"
#include "base/logging.h"
#include "base/mutex.h"
-#include "base/stringpiece.h"
+#include "base/string_view_cpp20.h"
#include "noop_compiler_callbacks.h"
#include "runtime.h"
@@ -151,14 +152,15 @@
std::string error_msg;
for (int i = 0; i < argc; i++) {
- const StringPiece option(argv[i]);
- if (option.starts_with("--boot-image=")) {
- boot_image_location_ = option.substr(strlen("--boot-image=")).data();
- } else if (option.starts_with("--instruction-set=")) {
- StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data();
- instruction_set_ = GetInstructionSetFromString(instruction_set_str.data());
+ const char* const raw_option = argv[i];
+ const std::string_view option(raw_option);
+ if (StartsWith(option, "--boot-image=")) {
+ boot_image_location_ = raw_option + strlen("--boot-image=");
+ } else if (StartsWith(option, "--instruction-set=")) {
+ const char* const instruction_set_str = raw_option + strlen("--instruction-set=");
+ instruction_set_ = GetInstructionSetFromString(instruction_set_str);
if (instruction_set_ == InstructionSet::kNone) {
- fprintf(stderr, "Unsupported instruction set %s\n", instruction_set_str.data());
+ fprintf(stderr, "Unsupported instruction set %s\n", instruction_set_str);
PrintUsage();
return false;
}
@@ -170,8 +172,8 @@
}
++i;
runtime_args_.push_back(argv[i]);
- } else if (option.starts_with("--output=")) {
- output_name_ = option.substr(strlen("--output=")).ToString();
+ } else if (StartsWith(option, "--output=")) {
+ output_name_ = std::string(option.substr(strlen("--output=")));
const char* filename = output_name_.c_str();
out_.reset(new std::ofstream(filename));
if (!out_->good()) {
@@ -181,7 +183,7 @@
}
os_ = out_.get();
} else {
- ParseStatus parse_status = ParseCustom(option, &error_msg);
+ ParseStatus parse_status = ParseCustom(raw_option, option.length(), &error_msg);
if (parse_status == kParseUnknownArgument) {
fprintf(stderr, "Unknown argument %s\n", option.data());
@@ -315,7 +317,8 @@
}
protected:
- virtual ParseStatus ParseCustom(const StringPiece& option ATTRIBUTE_UNUSED,
+ virtual ParseStatus ParseCustom(const char* raw_option ATTRIBUTE_UNUSED,
+ size_t raw_option_length ATTRIBUTE_UNUSED,
std::string* error_msg ATTRIBUTE_UNUSED) {
return kParseUnknownArgument;
}
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 2ab4c60..f39d8fc 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1885,10 +1885,10 @@
// Merge all VerifierDeps into the main one.
verifier::VerifierDeps* verifier_deps = Thread::Current()->GetVerifierDeps();
for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) {
- verifier::VerifierDeps* thread_deps = worker->GetThread()->GetVerifierDeps();
- worker->GetThread()->SetVerifierDeps(nullptr);
- verifier_deps->MergeWith(*thread_deps, GetCompilerOptions().GetDexFilesForOatFile());
- delete thread_deps;
+ std::unique_ptr<verifier::VerifierDeps> thread_deps(worker->GetThread()->GetVerifierDeps());
+ worker->GetThread()->SetVerifierDeps(nullptr); // We just took ownership.
+ verifier_deps->MergeWith(std::move(thread_deps),
+ GetCompilerOptions().GetDexFilesForOatFile());
}
Thread::Current()->SetVerifierDeps(nullptr);
}
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 4d7ae9b..2c20b32 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -22,7 +22,7 @@
#include "arch/instruction_set_features.h"
#include "art_method-inl.h"
#include "base/logging.h" // For VLOG
-#include "base/stringpiece.h"
+#include "base/string_view_cpp20.h"
#include "base/systrace.h"
#include "base/time_utils.h"
#include "base/timing_logger.h"
@@ -71,19 +71,19 @@
DCHECK_EQ(instruction_set, kRuntimeISA);
}
std::unique_ptr<const InstructionSetFeatures> instruction_set_features;
- for (const StringPiece option : runtime->GetCompilerOptions()) {
+ for (const std::string& option : runtime->GetCompilerOptions()) {
VLOG(compiler) << "JIT compiler option " << option;
std::string error_msg;
- if (option.starts_with("--instruction-set-variant=")) {
- StringPiece str = option.substr(strlen("--instruction-set-variant=")).data();
+ if (StartsWith(option, "--instruction-set-variant=")) {
+ const char* str = option.c_str() + strlen("--instruction-set-variant=");
VLOG(compiler) << "JIT instruction set variant " << str;
instruction_set_features = InstructionSetFeatures::FromVariant(
- instruction_set, str.as_string(), &error_msg);
+ instruction_set, str, &error_msg);
if (instruction_set_features == nullptr) {
LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
}
- } else if (option.starts_with("--instruction-set-features=")) {
- StringPiece str = option.substr(strlen("--instruction-set-features=")).data();
+ } else if (StartsWith(option, "--instruction-set-features=")) {
+ const char* str = option.c_str() + strlen("--instruction-set-features=");
VLOG(compiler) << "JIT instruction set features " << str;
if (instruction_set_features == nullptr) {
instruction_set_features = InstructionSetFeatures::FromVariant(
@@ -93,7 +93,7 @@
}
}
instruction_set_features =
- instruction_set_features->AddFeaturesFromString(str.as_string(), &error_msg);
+ instruction_set_features->AddFeaturesFromString(str, &error_msg);
if (instruction_set_features == nullptr) {
LOG(WARNING) << "Error parsing " << option << " message=" << error_msg;
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index ad1dda4..1f18172 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -49,7 +49,6 @@
#include "base/os.h"
#include "base/scoped_flock.h"
#include "base/stl_util.h"
-#include "base/stringpiece.h"
#include "base/time_utils.h"
#include "base/timing_logger.h"
#include "base/unix_file/fd_file.h"
diff --git a/dex2oat/linker/arm/relative_patcher_thumb2_test.cc b/dex2oat/linker/arm/relative_patcher_thumb2_test.cc
index d8cbbaf..04a897e 100644
--- a/dex2oat/linker/arm/relative_patcher_thumb2_test.cc
+++ b/dex2oat/linker/arm/relative_patcher_thumb2_test.cc
@@ -140,50 +140,63 @@
| (((diff >> 20) & 1) << 26); // S
}
- bool Create2MethodsWithGap(const ArrayRef<const uint8_t>& method1_code,
- const ArrayRef<const LinkerPatch>& method1_patches,
- const ArrayRef<const uint8_t>& method3_code,
- const ArrayRef<const LinkerPatch>& method3_patches,
- uint32_t distance_without_thunks) {
+ uint32_t Create2MethodsWithGap(const ArrayRef<const uint8_t>& method1_code,
+ const ArrayRef<const LinkerPatch>& method1_patches,
+ const ArrayRef<const uint8_t>& last_method_code,
+ const ArrayRef<const LinkerPatch>& last_method_patches,
+ uint32_t distance_without_thunks) {
CHECK_EQ(distance_without_thunks % kArmAlignment, 0u);
uint32_t method1_offset =
kTrampolineSize + CodeAlignmentSize(kTrampolineSize) + sizeof(OatQuickMethodHeader);
AddCompiledMethod(MethodRef(1u), method1_code, method1_patches);
+ const uint32_t gap_start = method1_offset + method1_code.size();
- // We want to put the method3 at a very precise offset.
- const uint32_t method3_offset = method1_offset + distance_without_thunks;
- CHECK_ALIGNED(method3_offset, kArmAlignment);
+ // We want to put the last method at a very precise offset.
+ const uint32_t last_method_offset = method1_offset + distance_without_thunks;
+ CHECK_ALIGNED(last_method_offset, kArmAlignment);
+ const uint32_t gap_end = last_method_offset - sizeof(OatQuickMethodHeader);
- // Calculate size of method2 so that we put method3 at the correct place.
- const uint32_t method1_end = method1_offset + method1_code.size();
- const uint32_t method2_offset =
- method1_end + CodeAlignmentSize(method1_end) + sizeof(OatQuickMethodHeader);
- const uint32_t method2_size = (method3_offset - sizeof(OatQuickMethodHeader) - method2_offset);
- std::vector<uint8_t> method2_raw_code(method2_size);
- ArrayRef<const uint8_t> method2_code(method2_raw_code);
- AddCompiledMethod(MethodRef(2u), method2_code);
+ // Fill the gap with intermediate methods in chunks of 2MiB and the first in [2MiB, 4MiB).
+ // (This allows deduplicating the small chunks to avoid using 32MiB of memory for +-16MiB
+ // offsets by this test. Making the first chunk bigger makes it easy to give all intermediate
+ // methods the same alignment of the end, so the thunk insertion adds a predictable size as
+ // long as it's after the first chunk.)
+ uint32_t method_idx = 2u;
+ constexpr uint32_t kSmallChunkSize = 2 * MB;
+ std::vector<uint8_t> gap_code;
+ uint32_t gap_size = gap_end - gap_start;
+ uint32_t num_small_chunks = std::max(gap_size / kSmallChunkSize, 1u) - 1u;
+ uint32_t chunk_start = gap_start;
+ uint32_t chunk_size = gap_size - num_small_chunks * kSmallChunkSize;
+ for (uint32_t i = 0; i <= num_small_chunks; ++i) { // num_small_chunks+1 iterations.
+ uint32_t chunk_code_size =
+ chunk_size - CodeAlignmentSize(chunk_start) - sizeof(OatQuickMethodHeader);
+ gap_code.resize(chunk_code_size, 0u);
+ AddCompiledMethod(MethodRef(method_idx), ArrayRef<const uint8_t>(gap_code));
+ method_idx += 1u;
+ chunk_start += chunk_size;
+ chunk_size = kSmallChunkSize; // For all but the first chunk.
+ DCHECK_EQ(CodeAlignmentSize(gap_end), CodeAlignmentSize(chunk_start));
+ }
- AddCompiledMethod(MethodRef(3u), method3_code, method3_patches);
-
+ // Add the last method and link
+ AddCompiledMethod(MethodRef(method_idx), last_method_code, last_method_patches);
Link();
// Check assumptions.
CHECK_EQ(GetMethodOffset(1), method1_offset);
- CHECK_EQ(GetMethodOffset(2), method2_offset);
- auto result3 = method_offset_map_.FindMethodOffset(MethodRef(3));
- CHECK(result3.first);
+ auto last_result = method_offset_map_.FindMethodOffset(MethodRef(method_idx));
+ CHECK(last_result.first);
// There may be a thunk before method2.
- if (result3.second == method3_offset + 1 /* thumb mode */) {
- return false; // No thunk.
- } else {
+ if (last_result.second != last_method_offset + 1 /* thumb mode */) {
+ // Thunk present. Check that there's only one.
uint32_t thunk_end =
- CompiledCode::AlignCode(method3_offset - sizeof(OatQuickMethodHeader),
- InstructionSet::kThumb2) +
- MethodCallThunkSize();
+ CompiledCode::AlignCode(gap_end, InstructionSet::kThumb2) + MethodCallThunkSize();
uint32_t header_offset = thunk_end + CodeAlignmentSize(thunk_end);
- CHECK_EQ(result3.second, header_offset + sizeof(OatQuickMethodHeader) + 1 /* thumb mode */);
- return true; // Thunk present.
+ CHECK_EQ(last_result.second,
+ header_offset + sizeof(OatQuickMethodHeader) + 1 /* thumb mode */);
}
+ return method_idx;
}
uint32_t GetMethodOffset(uint32_t method_idx) {
@@ -447,32 +460,37 @@
TEST_F(Thumb2RelativePatcherTest, CallTrampolineTooFar) {
constexpr uint32_t missing_method_index = 1024u;
- auto method3_raw_code = GenNopsAndBl(3u, kBlPlus0);
- constexpr uint32_t bl_offset_in_method3 = 3u * 2u; // After NOPs.
- ArrayRef<const uint8_t> method3_code(method3_raw_code);
- ASSERT_EQ(bl_offset_in_method3 + 4u, method3_code.size());
- const LinkerPatch method3_patches[] = {
- LinkerPatch::RelativeCodePatch(bl_offset_in_method3, nullptr, missing_method_index),
+ auto last_method_raw_code = GenNopsAndBl(3u, kBlPlus0);
+ constexpr uint32_t bl_offset_in_last_method = 3u * 2u; // After NOPs.
+ ArrayRef<const uint8_t> last_method_code(last_method_raw_code);
+ ASSERT_EQ(bl_offset_in_last_method + 4u, last_method_code.size());
+ const LinkerPatch last_method_patches[] = {
+ LinkerPatch::RelativeCodePatch(bl_offset_in_last_method, nullptr, missing_method_index),
};
constexpr uint32_t just_over_max_negative_disp = 16 * MB + 2 - 4u /* PC adjustment */;
- bool thunk_in_gap = Create2MethodsWithGap(kNopCode,
- ArrayRef<const LinkerPatch>(),
- method3_code,
- ArrayRef<const LinkerPatch>(method3_patches),
- just_over_max_negative_disp - bl_offset_in_method3);
- ASSERT_FALSE(thunk_in_gap); // There should be a thunk but it should be after the method2.
+ uint32_t last_method_idx = Create2MethodsWithGap(
+ kNopCode,
+ ArrayRef<const LinkerPatch>(),
+ last_method_code,
+ ArrayRef<const LinkerPatch>(last_method_patches),
+ just_over_max_negative_disp - bl_offset_in_last_method);
+ uint32_t method1_offset = GetMethodOffset(1u);
+ uint32_t last_method_offset = GetMethodOffset(last_method_idx);
+ ASSERT_EQ(method1_offset,
+ last_method_offset + bl_offset_in_last_method - just_over_max_negative_disp);
ASSERT_FALSE(method_offset_map_.FindMethodOffset(MethodRef(missing_method_index)).first);
// Check linked code.
- uint32_t method3_offset = GetMethodOffset(3u);
- uint32_t thunk_offset = CompiledCode::AlignCode(method3_offset + method3_code.size(),
- InstructionSet::kThumb2);
- uint32_t diff = thunk_offset - (method3_offset + bl_offset_in_method3 + 4u /* PC adjustment */);
- ASSERT_EQ(diff & 1u, 0u);
+ uint32_t thunk_offset = CompiledCode::AlignCode(
+ last_method_offset + last_method_code.size(), InstructionSet::kThumb2);
+ uint32_t diff =
+ thunk_offset - (last_method_offset + bl_offset_in_last_method + 4u /* PC adjustment */);
+ ASSERT_TRUE(IsAligned<2u>(diff));
ASSERT_LT(diff >> 1, 1u << 8); // Simple encoding, (diff >> 1) fits into 8 bits.
auto expected_code = GenNopsAndBl(3u, kBlPlus0 | ((diff >> 1) & 0xffu));
- EXPECT_TRUE(CheckLinkedMethod(MethodRef(3u), ArrayRef<const uint8_t>(expected_code)));
+ EXPECT_TRUE(CheckLinkedMethod(MethodRef(last_method_idx),
+ ArrayRef<const uint8_t>(expected_code)));
EXPECT_TRUE(CheckThunk(thunk_offset));
}
@@ -481,17 +499,18 @@
constexpr uint32_t bl_offset_in_method1 = 3u * 2u; // After NOPs.
ArrayRef<const uint8_t> method1_code(method1_raw_code);
ASSERT_EQ(bl_offset_in_method1 + 4u, method1_code.size());
+ const uint32_t kExpectedLastMethodIdx = 9u; // Based on 2MiB chunks in Create2MethodsWithGap().
const LinkerPatch method1_patches[] = {
- LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, 3u),
+ LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, kExpectedLastMethodIdx),
};
constexpr uint32_t max_positive_disp = 16 * MB - 2u + 4u /* PC adjustment */;
- bool thunk_in_gap = Create2MethodsWithGap(method1_code,
- ArrayRef<const LinkerPatch>(method1_patches),
- kNopCode,
- ArrayRef<const LinkerPatch>(),
- bl_offset_in_method1 + max_positive_disp);
- ASSERT_FALSE(thunk_in_gap); // There should be no thunk.
+ uint32_t last_method_idx = Create2MethodsWithGap(method1_code,
+ ArrayRef<const LinkerPatch>(method1_patches),
+ kNopCode,
+ ArrayRef<const LinkerPatch>(),
+ bl_offset_in_method1 + max_positive_disp);
+ ASSERT_EQ(kExpectedLastMethodIdx, last_method_idx);
// Check linked code.
auto expected_code = GenNopsAndBl(3u, kBlPlusMax);
@@ -499,25 +518,28 @@
}
TEST_F(Thumb2RelativePatcherTest, CallOtherAlmostTooFarBefore) {
- auto method3_raw_code = GenNopsAndBl(2u, kBlPlus0);
- constexpr uint32_t bl_offset_in_method3 = 2u * 2u; // After NOPs.
- ArrayRef<const uint8_t> method3_code(method3_raw_code);
- ASSERT_EQ(bl_offset_in_method3 + 4u, method3_code.size());
- const LinkerPatch method3_patches[] = {
- LinkerPatch::RelativeCodePatch(bl_offset_in_method3, nullptr, 1u),
+ auto last_method_raw_code = GenNopsAndBl(2u, kBlPlus0);
+ constexpr uint32_t bl_offset_in_last_method = 2u * 2u; // After NOPs.
+ ArrayRef<const uint8_t> last_method_code(last_method_raw_code);
+ ASSERT_EQ(bl_offset_in_last_method + 4u, last_method_code.size());
+ const LinkerPatch last_method_patches[] = {
+ LinkerPatch::RelativeCodePatch(bl_offset_in_last_method, nullptr, 1u),
};
- constexpr uint32_t just_over_max_negative_disp = 16 * MB - 4u /* PC adjustment */;
- bool thunk_in_gap = Create2MethodsWithGap(kNopCode,
- ArrayRef<const LinkerPatch>(),
- method3_code,
- ArrayRef<const LinkerPatch>(method3_patches),
- just_over_max_negative_disp - bl_offset_in_method3);
- ASSERT_FALSE(thunk_in_gap); // There should be no thunk.
+ constexpr uint32_t max_negative_disp = 16 * MB - 4u /* PC adjustment */;
+ uint32_t last_method_idx = Create2MethodsWithGap(kNopCode,
+ ArrayRef<const LinkerPatch>(),
+ last_method_code,
+ ArrayRef<const LinkerPatch>(last_method_patches),
+ max_negative_disp - bl_offset_in_last_method);
+ uint32_t method1_offset = GetMethodOffset(1u);
+ uint32_t last_method_offset = GetMethodOffset(last_method_idx);
+ ASSERT_EQ(method1_offset, last_method_offset + bl_offset_in_last_method - max_negative_disp);
// Check linked code.
auto expected_code = GenNopsAndBl(2u, kBlMinusMax);
- EXPECT_TRUE(CheckLinkedMethod(MethodRef(3u), ArrayRef<const uint8_t>(expected_code)));
+ EXPECT_TRUE(CheckLinkedMethod(MethodRef(last_method_idx),
+ ArrayRef<const uint8_t>(expected_code)));
}
TEST_F(Thumb2RelativePatcherTest, CallOtherJustTooFarAfter) {
@@ -525,61 +547,78 @@
constexpr uint32_t bl_offset_in_method1 = 2u * 2u; // After NOPs.
ArrayRef<const uint8_t> method1_code(method1_raw_code);
ASSERT_EQ(bl_offset_in_method1 + 4u, method1_code.size());
+ const uint32_t kExpectedLastMethodIdx = 9u; // Based on 2MiB chunks in Create2MethodsWithGap().
const LinkerPatch method1_patches[] = {
- LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, 3u),
+ LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, kExpectedLastMethodIdx),
};
constexpr uint32_t just_over_max_positive_disp = 16 * MB + 4u /* PC adjustment */;
- bool thunk_in_gap = Create2MethodsWithGap(method1_code,
- ArrayRef<const LinkerPatch>(method1_patches),
- kNopCode,
- ArrayRef<const LinkerPatch>(),
- bl_offset_in_method1 + just_over_max_positive_disp);
- ASSERT_TRUE(thunk_in_gap);
+ uint32_t last_method_idx = Create2MethodsWithGap(
+ method1_code,
+ ArrayRef<const LinkerPatch>(method1_patches),
+ kNopCode,
+ ArrayRef<const LinkerPatch>(),
+ bl_offset_in_method1 + just_over_max_positive_disp);
+ ASSERT_EQ(kExpectedLastMethodIdx, last_method_idx);
+ uint32_t method_after_thunk_idx = last_method_idx;
+ if (sizeof(OatQuickMethodHeader) < kArmAlignment) {
+ // The thunk needs to start on a kArmAlignment-aligned address before the address where the
+ // last method would have been if there was no thunk. If the size of the OatQuickMethodHeader
+ // is at least kArmAlignment, the thunk start shall fit between the previous filler method
+ // and that address. Otherwise, it shall be inserted before that filler method.
+ method_after_thunk_idx -= 1u;
+ }
uint32_t method1_offset = GetMethodOffset(1u);
- uint32_t method3_offset = GetMethodOffset(3u);
- ASSERT_TRUE(IsAligned<kArmAlignment>(method3_offset));
- uint32_t method3_header_offset = method3_offset - sizeof(OatQuickMethodHeader);
+ uint32_t method_after_thunk_offset = GetMethodOffset(method_after_thunk_idx);
+ ASSERT_TRUE(IsAligned<kArmAlignment>(method_after_thunk_offset));
+ uint32_t method_after_thunk_header_offset =
+ method_after_thunk_offset - sizeof(OatQuickMethodHeader);
uint32_t thunk_size = MethodCallThunkSize();
- uint32_t thunk_offset = RoundDown(method3_header_offset - thunk_size, kArmAlignment);
+ uint32_t thunk_offset = RoundDown(method_after_thunk_header_offset - thunk_size, kArmAlignment);
DCHECK_EQ(thunk_offset + thunk_size + CodeAlignmentSize(thunk_offset + thunk_size),
- method3_header_offset);
+ method_after_thunk_header_offset);
ASSERT_TRUE(IsAligned<kArmAlignment>(thunk_offset));
uint32_t diff = thunk_offset - (method1_offset + bl_offset_in_method1 + 4u /* PC adjustment */);
- ASSERT_EQ(diff & 1u, 0u);
- ASSERT_GE(diff, 16 * MB - (1u << 9)); // Simple encoding, unknown bits fit into the low 8 bits.
- auto expected_code = GenNopsAndBl(2u, 0xf3ffd700 | ((diff >> 1) & 0xffu));
+ ASSERT_TRUE(IsAligned<2u>(diff));
+ ASSERT_GE(diff, 16 * MB - (1u << 22)); // Simple encoding, unknown bits fit into imm10:imm11:0.
+ auto expected_code =
+ GenNopsAndBl(2u, 0xf000d000 | ((diff >> 1) & 0x7ffu) | (((diff >> 12) & 0x3ffu) << 16));
EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
CheckThunk(thunk_offset);
}
TEST_F(Thumb2RelativePatcherTest, CallOtherJustTooFarBefore) {
- auto method3_raw_code = GenNopsAndBl(3u, kBlPlus0);
- constexpr uint32_t bl_offset_in_method3 = 3u * 2u; // After NOPs.
- ArrayRef<const uint8_t> method3_code(method3_raw_code);
- ASSERT_EQ(bl_offset_in_method3 + 4u, method3_code.size());
- const LinkerPatch method3_patches[] = {
- LinkerPatch::RelativeCodePatch(bl_offset_in_method3, nullptr, 1u),
+ auto last_method_raw_code = GenNopsAndBl(3u, kBlPlus0);
+ constexpr uint32_t bl_offset_in_last_method = 3u * 2u; // After NOPs.
+ ArrayRef<const uint8_t> last_method_code(last_method_raw_code);
+ ASSERT_EQ(bl_offset_in_last_method + 4u, last_method_code.size());
+ const LinkerPatch last_method_patches[] = {
+ LinkerPatch::RelativeCodePatch(bl_offset_in_last_method, nullptr, 1u),
};
constexpr uint32_t just_over_max_negative_disp = 16 * MB + 2 - 4u /* PC adjustment */;
- bool thunk_in_gap = Create2MethodsWithGap(kNopCode,
- ArrayRef<const LinkerPatch>(),
- method3_code,
- ArrayRef<const LinkerPatch>(method3_patches),
- just_over_max_negative_disp - bl_offset_in_method3);
- ASSERT_FALSE(thunk_in_gap); // There should be a thunk but it should be after the method2.
+ uint32_t last_method_idx = Create2MethodsWithGap(
+ kNopCode,
+ ArrayRef<const LinkerPatch>(),
+ last_method_code,
+ ArrayRef<const LinkerPatch>(last_method_patches),
+ just_over_max_negative_disp - bl_offset_in_last_method);
+ uint32_t method1_offset = GetMethodOffset(1u);
+ uint32_t last_method_offset = GetMethodOffset(last_method_idx);
+ ASSERT_EQ(method1_offset,
+ last_method_offset + bl_offset_in_last_method - just_over_max_negative_disp);
// Check linked code.
- uint32_t method3_offset = GetMethodOffset(3u);
- uint32_t thunk_offset = CompiledCode::AlignCode(method3_offset + method3_code.size(),
- InstructionSet::kThumb2);
- uint32_t diff = thunk_offset - (method3_offset + bl_offset_in_method3 + 4u /* PC adjustment */);
- ASSERT_EQ(diff & 1u, 0u);
+ uint32_t thunk_offset = CompiledCode::AlignCode(
+ last_method_offset + last_method_code.size(), InstructionSet::kThumb2);
+ uint32_t diff =
+ thunk_offset - (last_method_offset + bl_offset_in_last_method + 4u /* PC adjustment */);
+ ASSERT_TRUE(IsAligned<2u>(diff));
ASSERT_LT(diff >> 1, 1u << 8); // Simple encoding, (diff >> 1) fits into 8 bits.
auto expected_code = GenNopsAndBl(3u, kBlPlus0 | ((diff >> 1) & 0xffu));
- EXPECT_TRUE(CheckLinkedMethod(MethodRef(3u), ArrayRef<const uint8_t>(expected_code)));
+ EXPECT_TRUE(CheckLinkedMethod(MethodRef(last_method_idx),
+ ArrayRef<const uint8_t>(expected_code)));
EXPECT_TRUE(CheckThunk(thunk_offset));
}
diff --git a/dex2oat/linker/arm64/relative_patcher_arm64_test.cc b/dex2oat/linker/arm64/relative_patcher_arm64_test.cc
index 678574b..9e54bbf 100644
--- a/dex2oat/linker/arm64/relative_patcher_arm64_test.cc
+++ b/dex2oat/linker/arm64/relative_patcher_arm64_test.cc
@@ -118,7 +118,7 @@
AddCompiledMethod(MethodRef(1u), method1_code, method1_patches);
const uint32_t gap_start = method1_offset + method1_code.size();
- // We want to put the method3 at a very precise offset.
+ // We want to put the last method at a very precise offset.
const uint32_t last_method_offset = method1_offset + distance_without_thunks;
CHECK_ALIGNED(last_method_offset, kArm64Alignment);
const uint32_t gap_end = last_method_offset - sizeof(OatQuickMethodHeader);
@@ -638,7 +638,9 @@
constexpr uint32_t just_over_max_negative_disp = 128 * MB + 4;
uint32_t last_method_idx = Create2MethodsWithGap(
- kNopCode, ArrayRef<const LinkerPatch>(), last_method_code,
+ kNopCode,
+ ArrayRef<const LinkerPatch>(),
+ last_method_code,
ArrayRef<const LinkerPatch>(last_method_patches),
just_over_max_negative_disp - bl_offset_in_last_method);
uint32_t method1_offset = GetMethodOffset(1u);
@@ -651,7 +653,7 @@
uint32_t thunk_offset =
CompiledCode::AlignCode(last_method_offset + last_method_code.size(), InstructionSet::kArm64);
uint32_t diff = thunk_offset - (last_method_offset + bl_offset_in_last_method);
- CHECK_ALIGNED(diff, 4u);
+ ASSERT_TRUE(IsAligned<4u>(diff));
ASSERT_LT(diff, 128 * MB);
auto expected_code = GenNopsAndBl(1u, kBlPlus0 | (diff >> 2));
EXPECT_TRUE(CheckLinkedMethod(MethodRef(last_method_idx),
@@ -664,9 +666,9 @@
constexpr uint32_t bl_offset_in_method1 = 1u * 4u; // After NOPs.
ArrayRef<const uint8_t> method1_code(method1_raw_code);
ASSERT_EQ(bl_offset_in_method1 + 4u, method1_code.size());
- uint32_t expected_last_method_idx = 65; // Based on 2MiB chunks in Create2MethodsWithGap().
+ const uint32_t kExpectedLastMethodIdx = 65u; // Based on 2MiB chunks in Create2MethodsWithGap().
const LinkerPatch method1_patches[] = {
- LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, expected_last_method_idx),
+ LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, kExpectedLastMethodIdx),
};
constexpr uint32_t max_positive_disp = 128 * MB - 4u;
@@ -675,7 +677,7 @@
kNopCode,
ArrayRef<const LinkerPatch>(),
bl_offset_in_method1 + max_positive_disp);
- ASSERT_EQ(expected_last_method_idx, last_method_idx);
+ ASSERT_EQ(kExpectedLastMethodIdx, last_method_idx);
uint32_t method1_offset = GetMethodOffset(1u);
uint32_t last_method_offset = GetMethodOffset(last_method_idx);
@@ -716,9 +718,9 @@
constexpr uint32_t bl_offset_in_method1 = 0u * 4u; // After NOPs.
ArrayRef<const uint8_t> method1_code(method1_raw_code);
ASSERT_EQ(bl_offset_in_method1 + 4u, method1_code.size());
- uint32_t expected_last_method_idx = 65; // Based on 2MiB chunks in Create2MethodsWithGap().
+ const uint32_t kExpectedLastMethodIdx = 65u; // Based on 2MiB chunks in Create2MethodsWithGap().
const LinkerPatch method1_patches[] = {
- LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, expected_last_method_idx),
+ LinkerPatch::RelativeCodePatch(bl_offset_in_method1, nullptr, kExpectedLastMethodIdx),
};
constexpr uint32_t just_over_max_positive_disp = 128 * MB;
@@ -728,7 +730,7 @@
kNopCode,
ArrayRef<const LinkerPatch>(),
bl_offset_in_method1 + just_over_max_positive_disp);
- ASSERT_EQ(expected_last_method_idx, last_method_idx);
+ ASSERT_EQ(kExpectedLastMethodIdx, last_method_idx);
uint32_t method_after_thunk_idx = last_method_idx;
if (sizeof(OatQuickMethodHeader) < kArm64Alignment) {
// The thunk needs to start on a kArm64Alignment-aligned address before the address where the
@@ -747,8 +749,9 @@
uint32_t thunk_offset = RoundDown(method_after_thunk_header_offset - thunk_size, kArm64Alignment);
DCHECK_EQ(thunk_offset + thunk_size + CodeAlignmentSize(thunk_offset + thunk_size),
method_after_thunk_header_offset);
+ ASSERT_TRUE(IsAligned<kArm64Alignment>(thunk_offset));
uint32_t diff = thunk_offset - (method1_offset + bl_offset_in_method1);
- CHECK_ALIGNED(diff, 4u);
+ ASSERT_TRUE(IsAligned<4u>(diff));
ASSERT_LT(diff, 128 * MB);
auto expected_code = GenNopsAndBl(0u, kBlPlus0 | (diff >> 2));
EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
@@ -778,7 +781,7 @@
uint32_t thunk_offset =
CompiledCode::AlignCode(last_method_offset + last_method_code.size(), InstructionSet::kArm64);
uint32_t diff = thunk_offset - (last_method_offset + bl_offset_in_last_method);
- CHECK_ALIGNED(diff, 4u);
+ ASSERT_TRUE(IsAligned<4u>(diff));
ASSERT_LT(diff, 128 * MB);
auto expected_code = GenNopsAndBl(1u, kBlPlus0 | (diff >> 2));
EXPECT_TRUE(CheckLinkedMethod(MethodRef(last_method_idx),
diff --git a/dexlayout/dex_verify.cc b/dexlayout/dex_verify.cc
index 718d66f..83a7c69 100644
--- a/dexlayout/dex_verify.cc
+++ b/dexlayout/dex_verify.cc
@@ -22,6 +22,8 @@
#include <inttypes.h>
+#include <set>
+
#include "android-base/stringprintf.h"
namespace art {
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index 28d4048..ca9018d 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -22,12 +22,14 @@
#include <iostream>
#include <memory>
+#include <string>
+#include <string_view>
#include <vector>
#include "android-base/stringprintf.h"
#include "base/logging.h" // For InitLogging.
-#include "base/stringpiece.h"
+#include "base/string_view_cpp20.h"
#include "dexlayout.h"
#include "dex/dex_file.h"
@@ -462,14 +464,14 @@
std::vector<std::string> name_filters;
// TODO: add option to track usage by class name, etc.
for (int i = 1; i < argc - 1; ++i) {
- const StringPiece option(argv[i]);
+ const std::string_view option(argv[i]);
if (option == "--help") {
Usage(argv[0]);
return EXIT_SUCCESS;
} else if (option == "--verbose") {
g_verbose = true;
- } else if (option.starts_with("--contains=")) {
- std::string contains(option.substr(strlen("--contains=")).data());
+ } else if (StartsWith(option, "--contains=")) {
+ std::string contains(option.substr(strlen("--contains=")));
name_filters.push_back(contains);
} else {
Usage(argv[0]);
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index 535f789..60076bf 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -25,6 +25,8 @@
#include <stdint.h>
#include <stdio.h>
+
+#include <set>
#include <unordered_map>
#include "dex/compact_dex_level.h"
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index a1edd00..5cd77e0 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -1674,23 +1674,27 @@
protected:
using Base = CmdlineArgs;
- ParseStatus ParseCustom(const StringPiece& option, std::string* error_msg) override {
+ ParseStatus ParseCustom(const char* raw_option,
+ size_t raw_option_length,
+ std::string* error_msg) override {
+ DCHECK_EQ(strlen(raw_option), raw_option_length);
{
- ParseStatus base_parse = Base::ParseCustom(option, error_msg);
+ ParseStatus base_parse = Base::ParseCustom(raw_option, raw_option_length, error_msg);
if (base_parse != kParseUnknownArgument) {
return base_parse;
}
}
- if (option.starts_with("--image-diff-pid=")) {
- const char* image_diff_pid = option.substr(strlen("--image-diff-pid=")).data();
+ std::string_view option(raw_option, raw_option_length);
+ if (StartsWith(option, "--image-diff-pid=")) {
+ const char* image_diff_pid = raw_option + strlen("--image-diff-pid=");
if (!android::base::ParseInt(image_diff_pid, &image_diff_pid_)) {
*error_msg = "Image diff pid out of range";
return kParseError;
}
- } else if (option.starts_with("--zygote-diff-pid=")) {
- const char* zygote_diff_pid = option.substr(strlen("--zygote-diff-pid=")).data();
+ } else if (StartsWith(option, "--zygote-diff-pid=")) {
+ const char* zygote_diff_pid = raw_option + strlen("--zygote-diff-pid=");
if (!android::base::ParseInt(zygote_diff_pid, &zygote_diff_pid_)) {
*error_msg = "Zygote diff pid out of range";
diff --git a/libartbase/base/stl_util.h b/libartbase/base/stl_util.h
index 9d944b1..1e071ce 100644
--- a/libartbase/base/stl_util.h
+++ b/libartbase/base/stl_util.h
@@ -18,7 +18,6 @@
#define ART_LIBARTBASE_BASE_STL_UTIL_H_
#include <algorithm>
-#include <set>
#include <sstream>
#include <android-base/logging.h>
@@ -136,12 +135,6 @@
}
};
-// Merge `other` entries into `to_update`.
-template <typename T>
-static inline void MergeSets(std::set<T>& to_update, const std::set<T>& other) {
- to_update.insert(other.begin(), other.end());
-}
-
// Returns a copy of the passed vector that doesn't memory-own its entries.
template <typename T>
static inline std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) {
diff --git a/libartbase/base/stringpiece.h b/libartbase/base/stringpiece.h
deleted file mode 100644
index e8cc2c3..0000000
--- a/libartbase/base/stringpiece.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef ART_LIBARTBASE_BASE_STRINGPIECE_H_
-#define ART_LIBARTBASE_BASE_STRINGPIECE_H_
-
-#include <string.h>
-#include <string>
-
-#include <android-base/logging.h>
-
-namespace art {
-
-// A string-like object that points to a sized piece of memory.
-//
-// Functions or methods may use const StringPiece& parameters to accept either
-// a "const char*" or a "string" value that will be implicitly converted to
-// a StringPiece. The implicit conversion means that it is often appropriate
-// to include this .h file in other files rather than forward-declaring
-// StringPiece as would be appropriate for most other Google classes.
-class StringPiece {
- public:
- // standard STL container boilerplate
- typedef char value_type;
- typedef const char* pointer;
- typedef const char& reference;
- typedef const char& const_reference;
- typedef size_t size_type;
- typedef ptrdiff_t difference_type;
- static constexpr size_type npos = size_type(-1);
- typedef const char* const_iterator;
- typedef const char* iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
- typedef std::reverse_iterator<iterator> reverse_iterator;
-
- // We provide non-explicit singleton constructors so users can pass
- // in a "const char*" or a "string" wherever a "StringPiece" is
- // expected.
- StringPiece() : ptr_(nullptr), length_(0) { }
- StringPiece(const char* str) // NOLINT implicit constructor desired
- : ptr_(str), length_((str == nullptr) ? 0 : strlen(str)) { }
- StringPiece(const std::string& str) // NOLINT implicit constructor desired
- : ptr_(str.data()), length_(str.size()) { }
- StringPiece(const char* offset, size_t len) : ptr_(offset), length_(len) { }
-
- // data() may return a pointer to a buffer with embedded NULs, and the
- // returned buffer may or may not be null terminated. Therefore it is
- // typically a mistake to pass data() to a routine that expects a NUL
- // terminated string.
- const char* data() const { return ptr_; }
- size_type size() const { return length_; }
- size_type length() const { return length_; }
- bool empty() const { return length_ == 0; }
-
- void clear() {
- ptr_ = nullptr;
- length_ = 0;
- }
- void set(const char* data_in, size_type len) {
- ptr_ = data_in;
- length_ = len;
- }
- void set(const char* str) {
- ptr_ = str;
- if (str != nullptr) {
- length_ = strlen(str);
- } else {
- length_ = 0;
- }
- }
- void set(const void* data_in, size_type len) {
- ptr_ = reinterpret_cast<const char*>(data_in);
- length_ = len;
- }
-
- char operator[](size_type i) const {
- DCHECK_LT(i, length_);
- return ptr_[i];
- }
-
- void remove_prefix(size_type n) {
- ptr_ += n;
- length_ -= n;
- }
-
- void remove_suffix(size_type n) {
- length_ -= n;
- }
-
- int compare(const StringPiece& x) const {
- int r = memcmp(ptr_, x.ptr_, std::min(length_, x.length_));
- if (r == 0) {
- if (length_ < x.length_) r = -1;
- else if (length_ > x.length_) r = +1;
- }
- return r;
- }
-
- std::string as_string() const {
- return std::string(data(), size());
- }
- // We also define ToString() here, since many other string-like
- // interfaces name the routine that converts to a C++ string
- // "ToString", and it's confusing to have the method that does that
- // for a StringPiece be called "as_string()". We also leave the
- // "as_string()" method defined here for existing code.
- std::string ToString() const {
- return std::string(data(), size());
- }
-
- void CopyToString(std::string* target) const {
- target->assign(ptr_, length_);
- }
-
- void AppendToString(std::string* target) const;
-
- // Does "this" start with "x"
- bool starts_with(const StringPiece& x) const {
- return ((length_ >= x.length_) &&
- (memcmp(ptr_, x.ptr_, x.length_) == 0));
- }
-
- // Does "this" end with "x"
- bool ends_with(const StringPiece& x) const {
- return ((length_ >= x.length_) &&
- (memcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0));
- }
-
- iterator begin() const { return ptr_; }
- iterator end() const { return ptr_ + length_; }
- const_reverse_iterator rbegin() const {
- return const_reverse_iterator(ptr_ + length_);
- }
- const_reverse_iterator rend() const {
- return const_reverse_iterator(ptr_);
- }
-
- size_type copy(char* buf, size_type n, size_type pos = 0) const {
- size_type ret = std::min(length_ - pos, n);
- memcpy(buf, ptr_ + pos, ret);
- return ret;
- }
-
- size_type find(const StringPiece& s, size_type pos = 0) const {
- if (length_ == 0 || pos > static_cast<size_type>(length_)) {
- return npos;
- }
- const char* result = std::search(ptr_ + pos, ptr_ + length_, s.ptr_, s.ptr_ + s.length_);
- const size_type xpos = result - ptr_;
- return xpos + s.length_ <= length_ ? xpos : npos;
- }
-
- size_type find(char c, size_type pos = 0) const {
- if (length_ == 0 || pos >= length_) {
- return npos;
- }
- const char* result = std::find(ptr_ + pos, ptr_ + length_, c);
- return result != ptr_ + length_ ? result - ptr_ : npos;
- }
-
- size_type rfind(const StringPiece& s, size_type pos = npos) const {
- if (length_ < s.length_) return npos;
- const size_t ulen = length_;
- if (s.length_ == 0) return std::min(ulen, pos);
-
- const char* last = ptr_ + std::min(ulen - s.length_, pos) + s.length_;
- const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
- return result != last ? result - ptr_ : npos;
- }
-
- size_type rfind(char c, size_type pos = npos) const {
- if (length_ == 0) return npos;
- for (int i = std::min(pos, static_cast<size_type>(length_ - 1));
- i >= 0; --i) {
- if (ptr_[i] == c) {
- return i;
- }
- }
- return npos;
- }
-
- StringPiece substr(size_type pos, size_type n = npos) const {
- if (pos > static_cast<size_type>(length_)) pos = length_;
- if (n > length_ - pos) n = length_ - pos;
- return StringPiece(ptr_ + pos, n);
- }
-
- int Compare(const StringPiece& rhs) const {
- const int r = memcmp(data(), rhs.data(), std::min(size(), rhs.size()));
- if (r != 0) {
- return r;
- }
- if (size() < rhs.size()) {
- return -1;
- } else if (size() > rhs.size()) {
- return 1;
- }
- return 0;
- }
-
- private:
- // Pointer to char data, not necessarily zero terminated.
- const char* ptr_;
- // Length of data.
- size_type length_;
-};
-
-// This large function is defined inline so that in a fairly common case where
-// one of the arguments is a literal, the compiler can elide a lot of the
-// following comparisons.
-inline bool operator==(const StringPiece& x, const StringPiece& y) {
- StringPiece::size_type len = x.size();
- if (len != y.size()) {
- return false;
- }
-
- const char* p1 = x.data();
- const char* p2 = y.data();
- if (p1 == p2) {
- return true;
- }
- if (len == 0) {
- return true;
- }
-
- // Test last byte in case strings share large common prefix
- if (p1[len-1] != p2[len-1]) return false;
- if (len == 1) return true;
-
- // At this point we can, but don't have to, ignore the last byte. We use
- // this observation to fold the odd-length case into the even-length case.
- len &= ~1;
-
- return memcmp(p1, p2, len) == 0;
-}
-
-inline bool operator==(const StringPiece& x, const char* y) {
- if (y == nullptr) {
- return x.size() == 0;
- } else {
- return strncmp(x.data(), y, x.size()) == 0 && y[x.size()] == '\0';
- }
-}
-
-inline bool operator!=(const StringPiece& x, const StringPiece& y) {
- return !(x == y);
-}
-
-inline bool operator!=(const StringPiece& x, const char* y) {
- return !(x == y);
-}
-
-inline bool operator<(const StringPiece& x, const StringPiece& y) {
- return x.Compare(y) < 0;
-}
-
-inline bool operator>(const StringPiece& x, const StringPiece& y) {
- return y < x;
-}
-
-inline bool operator<=(const StringPiece& x, const StringPiece& y) {
- return !(x > y);
-}
-
-inline bool operator>=(const StringPiece& x, const StringPiece& y) {
- return !(x < y);
-}
-
-inline std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
- o.write(piece.data(), piece.size());
- return o;
-}
-
-} // namespace art
-
-#endif // ART_LIBARTBASE_BASE_STRINGPIECE_H_
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 89826c6..655c2c9 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -3358,20 +3358,24 @@
protected:
using Base = CmdlineArgs;
- ParseStatus ParseCustom(const StringPiece& option, std::string* error_msg) override {
+ ParseStatus ParseCustom(const char* raw_option,
+ size_t raw_option_length,
+ std::string* error_msg) override {
+ DCHECK_EQ(strlen(raw_option), raw_option_length);
{
- ParseStatus base_parse = Base::ParseCustom(option, error_msg);
+ ParseStatus base_parse = Base::ParseCustom(raw_option, raw_option_length, error_msg);
if (base_parse != kParseUnknownArgument) {
return base_parse;
}
}
- if (option.starts_with("--oat-file=")) {
- oat_filename_ = option.substr(strlen("--oat-file=")).data();
- } else if (option.starts_with("--dex-file=")) {
- dex_filename_ = option.substr(strlen("--dex-file=")).data();
- } else if (option.starts_with("--image=")) {
- image_location_ = option.substr(strlen("--image=")).data();
+ std::string_view option(raw_option, raw_option_length);
+ if (StartsWith(option, "--oat-file=")) {
+ oat_filename_ = raw_option + strlen("--oat-file=");
+ } else if (StartsWith(option, "--dex-file=")) {
+ dex_filename_ = raw_option + strlen("--dex-file=");
+ } else if (StartsWith(option, "--image=")) {
+ image_location_ = raw_option + strlen("--image=");
} else if (option == "--no-dump:vmap") {
dump_vmap_ = false;
} else if (option =="--dump:code_info_stack_maps") {
@@ -3380,32 +3384,32 @@
disassemble_code_ = false;
} else if (option =="--header-only") {
dump_header_only_ = true;
- } else if (option.starts_with("--symbolize=")) {
- oat_filename_ = option.substr(strlen("--symbolize=")).data();
+ } else if (StartsWith(option, "--symbolize=")) {
+ oat_filename_ = raw_option + strlen("--symbolize=");
symbolize_ = true;
- } else if (option.starts_with("--only-keep-debug")) {
+ } else if (StartsWith(option, "--only-keep-debug")) {
only_keep_debug_ = true;
- } else if (option.starts_with("--class-filter=")) {
- class_filter_ = option.substr(strlen("--class-filter=")).data();
- } else if (option.starts_with("--method-filter=")) {
- method_filter_ = option.substr(strlen("--method-filter=")).data();
- } else if (option.starts_with("--list-classes")) {
+ } else if (StartsWith(option, "--class-filter=")) {
+ class_filter_ = raw_option + strlen("--class-filter=");
+ } else if (StartsWith(option, "--method-filter=")) {
+ method_filter_ = raw_option + strlen("--method-filter=");
+ } else if (StartsWith(option, "--list-classes")) {
list_classes_ = true;
- } else if (option.starts_with("--list-methods")) {
+ } else if (StartsWith(option, "--list-methods")) {
list_methods_ = true;
- } else if (option.starts_with("--export-dex-to=")) {
- export_dex_location_ = option.substr(strlen("--export-dex-to=")).data();
- } else if (option.starts_with("--addr2instr=")) {
- if (!android::base::ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) {
+ } else if (StartsWith(option, "--export-dex-to=")) {
+ export_dex_location_ = raw_option + strlen("--export-dex-to=");
+ } else if (StartsWith(option, "--addr2instr=")) {
+ if (!android::base::ParseUint(raw_option + strlen("--addr2instr="), &addr2instr_)) {
*error_msg = "Address conversion failed";
return kParseError;
}
- } else if (option.starts_with("--app-image=")) {
- app_image_ = option.substr(strlen("--app-image=")).data();
- } else if (option.starts_with("--app-oat=")) {
- app_oat_ = option.substr(strlen("--app-oat=")).data();
- } else if (option.starts_with("--dump-imt=")) {
- imt_dump_ = option.substr(strlen("--dump-imt=")).data();
+ } else if (StartsWith(option, "--app-image=")) {
+ app_image_ = raw_option + strlen("--app-image=");
+ } else if (StartsWith(option, "--app-oat=")) {
+ app_oat_ = raw_option + strlen("--app-oat=");
+ } else if (StartsWith(option, "--dump-imt=")) {
+ imt_dump_ = std::string(option.substr(strlen("--dump-imt=")));
} else if (option == "--dump-imt-stats") {
imt_stat_dump_ = true;
} else {
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index 051db4c..1021648 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -47,6 +47,7 @@
#include "mirror/class.h"
#include "mirror/object-inl.h"
#include "mirror/string.h"
+#include "mirror/throwable.h"
#include "nativehelper/scoped_local_ref.h"
#include "nativehelper/scoped_utf_chars.h"
#include "obj_ptr.h"
@@ -83,6 +84,17 @@
}
void ThreadStart(art::Thread* self) override REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ // Needs to be checked first because we might start these threads before we actually send the
+ // VMInit event.
+ if (self->IsSystemDaemon()) {
+ // System daemon threads are things like the finalizer or gc thread. It would be dangerous to
+ // allow agents to get in the way of these threads starting up. These threads include things
+ // like the HeapTaskDaemon and the finalizer daemon.
+ //
+ // This event can happen during the time before VMInit or just after zygote fork. Since the
+ // second is hard to distinguish we unfortunately cannot really check the state here.
+ return;
+ }
if (!started) {
// Runtime isn't started. We only expect at most the signal handler or JIT threads to be
// started here.
@@ -132,16 +144,35 @@
gThreadCallback.Post<ArtJvmtiEvent::kThreadStart>(art::Thread::Current());
}
+
+static void WaitForSystemDaemonStart(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ {
+ art::ScopedThreadStateChange strc(self, art::kNative);
+ JNIEnv* jni = self->GetJniEnv();
+ jni->CallStaticVoidMethod(art::WellKnownClasses::java_lang_Daemons,
+ art::WellKnownClasses::java_lang_Daemons_waitForDaemonStart);
+ }
+ if (self->IsExceptionPending()) {
+ LOG(WARNING) << "Exception occured when waiting for system daemons to start: "
+ << self->GetException()->Dump();
+ self->ClearException();
+ }
+}
+
void ThreadUtil::CacheData() {
// We must have started since it is now safe to cache our data;
gThreadCallback.started = true;
- art::ScopedObjectAccess soa(art::Thread::Current());
+ art::Thread* self = art::Thread::Current();
+ art::ScopedObjectAccess soa(self);
art::ObjPtr<art::mirror::Class> thread_class =
soa.Decode<art::mirror::Class>(art::WellKnownClasses::java_lang_Thread);
CHECK(thread_class != nullptr);
context_class_loader_ = thread_class->FindDeclaredInstanceField("contextClassLoader",
"Ljava/lang/ClassLoader;");
CHECK(context_class_loader_ != nullptr);
+ // Now wait for all required system threads to come up before allowing the rest of loading to
+ // continue.
+ WaitForSystemDaemonStart(self);
}
void ThreadUtil::Unregister() {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1465b14..7ecfdc7 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -869,15 +869,22 @@
GetInstructionSetString(kRuntimeISA));
}
- // Send the initialized phase event. Send it before starting daemons, as otherwise
- // sending thread events becomes complicated.
+ StartDaemonThreads();
+
+ // Make sure the environment is still clean (no lingering local refs from starting daemon
+ // threads).
+ {
+ ScopedObjectAccess soa(self);
+ self->GetJniEnv()->AssertLocalsEmpty();
+ }
+
+ // Send the initialized phase event. Send it after starting the Daemon threads so that agents
+ // cannot delay the daemon threads from starting forever.
{
ScopedObjectAccess soa(self);
callbacks_->NextRuntimePhase(RuntimePhaseCallback::RuntimePhase::kInit);
}
- StartDaemonThreads();
-
{
ScopedObjectAccess soa(self);
self->GetJniEnv()->AssertLocalsEmpty();
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 4828aae..44b45cf 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -4258,4 +4258,12 @@
return priority;
}
+bool Thread::IsSystemDaemon() const {
+ if (GetPeer() == nullptr) {
+ return false;
+ }
+ return jni::DecodeArtField(
+ WellKnownClasses::java_lang_Thread_systemDaemon)->GetBoolean(GetPeer());
+}
+
} // namespace art
diff --git a/runtime/thread.h b/runtime/thread.h
index 7a14fd7..ec276b5 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1230,6 +1230,8 @@
return this == jit_sensitive_thread_;
}
+ bool IsSystemDaemon() const REQUIRES_SHARED(Locks::mutator_lock_);
+
// Returns true if StrictMode events are traced for the current thread.
static bool IsSensitiveThread() {
if (is_sensitive_thread_hook_ != nullptr) {
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index bd98997..6793a0a 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -24,7 +24,6 @@
#include "base/indenter.h"
#include "base/leb128.h"
#include "base/mutex-inl.h"
-#include "base/stl_util.h"
#include "compiler_callbacks.h"
#include "dex/class_accessor-inl.h"
#include "dex/dex_file-inl.h"
@@ -48,21 +47,22 @@
VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files)
: VerifierDeps(dex_files, /*output_only=*/ true) {}
-void VerifierDeps::MergeWith(const VerifierDeps& other,
+void VerifierDeps::MergeWith(std::unique_ptr<VerifierDeps> other,
const std::vector<const DexFile*>& dex_files) {
- DCHECK(dex_deps_.size() == other.dex_deps_.size());
+ DCHECK(other != nullptr);
+ DCHECK_EQ(dex_deps_.size(), other->dex_deps_.size());
for (const DexFile* dex_file : dex_files) {
DexFileDeps* my_deps = GetDexFileDeps(*dex_file);
- const DexFileDeps& other_deps = *other.GetDexFileDeps(*dex_file);
+ DexFileDeps& other_deps = *other->GetDexFileDeps(*dex_file);
// We currently collect extra strings only on the main `VerifierDeps`,
// which should be the one passed as `this` in this method.
DCHECK(other_deps.strings_.empty());
- MergeSets(my_deps->assignable_types_, other_deps.assignable_types_);
- MergeSets(my_deps->unassignable_types_, other_deps.unassignable_types_);
- MergeSets(my_deps->classes_, other_deps.classes_);
- MergeSets(my_deps->fields_, other_deps.fields_);
- MergeSets(my_deps->methods_, other_deps.methods_);
- MergeSets(my_deps->unverified_classes_, other_deps.unverified_classes_);
+ my_deps->assignable_types_.merge(other_deps.assignable_types_);
+ my_deps->unassignable_types_.merge(other_deps.unassignable_types_);
+ my_deps->classes_.merge(other_deps.classes_);
+ my_deps->fields_.merge(other_deps.fields_);
+ my_deps->methods_.merge(other_deps.methods_);
+ my_deps->unverified_classes_.merge(other_deps.unverified_classes_);
}
}
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 7c43a3b..fb4a4bf 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -63,7 +63,7 @@
// Merge `other` into this `VerifierDeps`'. `other` and `this` must be for the
// same set of dex files.
- void MergeWith(const VerifierDeps& other, const std::vector<const DexFile*>& dex_files);
+ void MergeWith(std::unique_ptr<VerifierDeps> other, const std::vector<const DexFile*>& dex_files);
// Record the verification status of the class at `type_idx`.
static void MaybeRecordVerificationStatus(const DexFile& dex_file,
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 955a455..19fbf63 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -92,6 +92,7 @@
jmethodID WellKnownClasses::java_lang_ClassNotFoundException_init;
jmethodID WellKnownClasses::java_lang_Daemons_start;
jmethodID WellKnownClasses::java_lang_Daemons_stop;
+jmethodID WellKnownClasses::java_lang_Daemons_waitForDaemonStart;
jmethodID WellKnownClasses::java_lang_Double_valueOf;
jmethodID WellKnownClasses::java_lang_Float_valueOf;
jmethodID WellKnownClasses::java_lang_Integer_valueOf;
@@ -132,6 +133,7 @@
jfieldID WellKnownClasses::java_lang_Thread_name;
jfieldID WellKnownClasses::java_lang_Thread_priority;
jfieldID WellKnownClasses::java_lang_Thread_nativePeer;
+jfieldID WellKnownClasses::java_lang_Thread_systemDaemon;
jfieldID WellKnownClasses::java_lang_Thread_unparkedBeforeStart;
jfieldID WellKnownClasses::java_lang_ThreadGroup_groups;
jfieldID WellKnownClasses::java_lang_ThreadGroup_ngroups;
@@ -351,6 +353,7 @@
java_lang_Daemons_start = CacheMethod(env, java_lang_Daemons, true, "start", "()V");
java_lang_Daemons_stop = CacheMethod(env, java_lang_Daemons, true, "stop", "()V");
+ java_lang_Daemons_waitForDaemonStart = CacheMethod(env, java_lang_Daemons, true, "waitForDaemonStart", "()V");
java_lang_invoke_MethodHandles_lookup = CacheMethod(env, "java/lang/invoke/MethodHandles", true, "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;");
java_lang_invoke_MethodHandles_Lookup_findConstructor = CacheMethod(env, "java/lang/invoke/MethodHandles$Lookup", false, "findConstructor", "(Ljava/lang/Class;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;");
@@ -385,6 +388,7 @@
java_lang_Thread_name = CacheField(env, java_lang_Thread, false, "name", "Ljava/lang/String;");
java_lang_Thread_priority = CacheField(env, java_lang_Thread, false, "priority", "I");
java_lang_Thread_nativePeer = CacheField(env, java_lang_Thread, false, "nativePeer", "J");
+ java_lang_Thread_systemDaemon = CacheField(env, java_lang_Thread, false, "systemDaemon", "Z");
java_lang_Thread_unparkedBeforeStart = CacheField(env, java_lang_Thread, false, "unparkedBeforeStart", "Z");
java_lang_ThreadGroup_groups = CacheField(env, java_lang_ThreadGroup, false, "groups", "[Ljava/lang/ThreadGroup;");
java_lang_ThreadGroup_ngroups = CacheField(env, java_lang_ThreadGroup, false, "ngroups", "I");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 872b562..3c5144f 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -101,6 +101,7 @@
static jmethodID java_lang_ClassNotFoundException_init;
static jmethodID java_lang_Daemons_start;
static jmethodID java_lang_Daemons_stop;
+ static jmethodID java_lang_Daemons_waitForDaemonStart;
static jmethodID java_lang_Double_valueOf;
static jmethodID java_lang_Float_valueOf;
static jmethodID java_lang_Integer_valueOf;
@@ -141,6 +142,7 @@
static jfieldID java_lang_Thread_name;
static jfieldID java_lang_Thread_priority;
static jfieldID java_lang_Thread_nativePeer;
+ static jfieldID java_lang_Thread_systemDaemon;
static jfieldID java_lang_Thread_unparkedBeforeStart;
static jfieldID java_lang_ThreadGroup_groups;
static jfieldID java_lang_ThreadGroup_ngroups;
diff --git a/tools/art_verifier/art_verifier.cc b/tools/art_verifier/art_verifier.cc
index 0ef6c06..b4aa678 100644
--- a/tools/art_verifier/art_verifier.cc
+++ b/tools/art_verifier/art_verifier.cc
@@ -92,28 +92,32 @@
protected:
using Base = CmdlineArgs;
- ParseStatus ParseCustom(const StringPiece& option, std::string* error_msg) override {
+ ParseStatus ParseCustom(const char* raw_option,
+ size_t raw_option_length,
+ std::string* error_msg) override {
+ DCHECK_EQ(strlen(raw_option), raw_option_length);
{
- ParseStatus base_parse = Base::ParseCustom(option, error_msg);
+ ParseStatus base_parse = Base::ParseCustom(raw_option, raw_option_length, error_msg);
if (base_parse != kParseUnknownArgument) {
return base_parse;
}
}
- if (option.starts_with("--dex-file=")) {
- dex_filename_ = option.substr(strlen("--dex-file=")).data();
+ std::string_view option(raw_option, raw_option_length);
+ if (StartsWith(option, "--dex-file=")) {
+ dex_filename_ = raw_option + strlen("--dex-file=");
} else if (option == "--dex-file-verifier") {
dex_file_verifier_ = true;
} else if (option == "--verbose") {
method_verifier_verbose_ = true;
} else if (option == "--verbose-debug") {
method_verifier_verbose_debug_ = true;
- } else if (option.starts_with("--repetitions=")) {
+ } else if (StartsWith(option, "--repetitions=")) {
char* end;
- repetitions_ = strtoul(option.substr(strlen("--repetitions=")).data(), &end, 10);
- } else if (option.starts_with("--api-level=")) {
+ repetitions_ = strtoul(raw_option + strlen("--repetitions="), &end, 10);
+ } else if (StartsWith(option, "--api-level=")) {
char* end;
- api_level_ = strtoul(option.substr(strlen("--api-level=")).data(), &end, 10);
+ api_level_ = strtoul(raw_option + strlen("--api-level="), &end, 10);
} else {
return kParseUnknownArgument;
}