summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--cmdline/cmdline.h30
-rw-r--r--compiler/compiled_method.cc4
-rw-r--r--compiler/driver/compiler_options.cc1
-rw-r--r--compiler/driver/compiler_options.h11
-rw-r--r--compiler/driver/compiler_options_map-inl.h7
-rw-r--r--compiler/driver/compiler_options_map.def1
-rw-r--r--compiler/jni/quick/arm/calling_convention_arm.cc2
-rw-r--r--compiler/jni/quick/arm64/calling_convention_arm64.cc2
-rw-r--r--compiler/jni/quick/mips/calling_convention_mips.cc2
-rw-r--r--compiler/jni/quick/mips64/calling_convention_mips64.cc2
-rw-r--r--compiler/jni/quick/x86/calling_convention_x86.cc2
-rw-r--r--compiler/optimizing/code_generator.cc2
-rw-r--r--compiler/optimizing/code_generator_arm64.cc2
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc10
-rw-r--r--compiler/optimizing/code_generator_mips.cc2
-rw-r--r--compiler/optimizing/code_generator_mips64.cc2
-rw-r--r--compiler/optimizing/code_generator_x86.cc4
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc2
-rw-r--r--compiler/optimizing/induction_var_analysis.cc4
-rw-r--r--compiler/optimizing/instruction_simplifier.cc2
-rw-r--r--compiler/optimizing/nodes.cc4
-rw-r--r--dex2oat/dex2oat.cc47
-rw-r--r--dex2oat/linker/image_test.cc19
-rw-r--r--dex2oat/linker/image_test.h40
-rw-r--r--dex2oat/linker/image_write_read_test.cc14
-rw-r--r--dex2oat/linker/image_writer.cc140
-rw-r--r--dex2oat/linker/image_writer.h8
-rw-r--r--dex2oat/linker/oat_writer.cc2
-rw-r--r--dex2oat/linker/oat_writer_test.cc34
-rw-r--r--dexoptanalyzer/dexoptanalyzer.cc18
-rw-r--r--disassembler/disassembler.cc2
-rw-r--r--libartbase/base/file_utils.cc2
-rw-r--r--libartbase/base/zip_archive.cc5
-rw-r--r--libartbase/base/zip_archive.h3
-rw-r--r--libdexfile/dex/dex_instruction.cc2
-rw-r--r--libprofile/profile/profile_compilation_info.cc3
-rw-r--r--oatdump/oatdump.cc2
-rw-r--r--openjdkjvm/OpenjdkJvm.cc23
-rw-r--r--openjdkjvmti/events.cc2
-rw-r--r--runtime/art_method.cc13
-rw-r--r--runtime/class_linker.cc24
-rw-r--r--runtime/class_linker.h7
-rw-r--r--runtime/class_loader_context.cc66
-rw-r--r--runtime/class_loader_context.h10
-rw-r--r--runtime/class_loader_context_test.cc28
-rw-r--r--runtime/common_runtime_test.cc14
-rw-r--r--runtime/common_runtime_test.h7
-rw-r--r--runtime/common_throws.cc2
-rw-r--r--runtime/debugger.cc8
-rw-r--r--runtime/dex/dex_file_annotations.cc2
-rw-r--r--runtime/entrypoints/quick/quick_jni_entrypoints.cc2
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc2
-rw-r--r--runtime/gc/allocator/rosalloc.cc33
-rw-r--r--runtime/gc/collector/garbage_collector.cc5
-rw-r--r--runtime/gc/collector/immune_spaces_test.cc4
-rw-r--r--runtime/gc/heap.cc2
-rw-r--r--runtime/gc/space/image_space.cc55
-rw-r--r--runtime/gc/space/image_space.h6
-rw-r--r--runtime/gc/space/space.cc2
-rw-r--r--runtime/hidden_api.cc6
-rw-r--r--runtime/hprof/hprof.cc2
-rw-r--r--runtime/image.cc43
-rw-r--r--runtime/image.h79
-rw-r--r--runtime/interpreter/interpreter_common.cc2
-rw-r--r--runtime/interpreter/interpreter_common.h2
-rw-r--r--runtime/interpreter/interpreter_switch_impl-inl.h2
-rw-r--r--runtime/interpreter/mterp/mterp.cc8
-rw-r--r--runtime/jdwp/jdwp_event.cc2
-rw-r--r--runtime/jdwp/jdwp_request.cc2
-rw-r--r--runtime/jit/jit-inl.h69
-rw-r--r--runtime/jit/jit.cc54
-rw-r--r--runtime/jit/jit.h15
-rw-r--r--runtime/jni/check_jni.cc6
-rw-r--r--runtime/mirror/object.cc3
-rw-r--r--runtime/monitor.cc10
-rw-r--r--runtime/oat_file.cc2
-rw-r--r--runtime/quick_exception_handler.cc2
-rw-r--r--runtime/runtime.cc3
-rw-r--r--runtime/thread.cc3
-rw-r--r--runtime/thread_list.cc2
-rw-r--r--runtime/transaction.cc11
-rw-r--r--runtime/well_known_classes.cc4
-rw-r--r--test/ti-agent/common_helper.cc3
-rw-r--r--tools/ahat/Android.mk1
-rw-r--r--tools/hiddenapi/hiddenapi.cc7
-rw-r--r--tools/timeout_dumper/timeout_dumper.cc2
-rw-r--r--tools/titrace/instruction_decoder.cc7
88 files changed, 658 insertions, 452 deletions
diff --git a/Android.mk b/Android.mk
index 3388b35aca..ba131c64e7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -474,7 +474,7 @@ endif
define build-art-hiddenapi
$(shell if [ ! -d frameworks/base ]; then \
mkdir -p ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING; \
- touch ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING/hiddenapi-{whitelist,blacklist,dark-greylist,light-greylist}.txt; \
+ touch ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING/hiddenapi-flags.csv; \
fi;)
endef
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h
index 95ab12324c..81a21793d9 100644
--- a/cmdline/cmdline.h
+++ b/cmdline/cmdline.h
@@ -85,7 +85,9 @@ static bool LocationToFilename(const std::string& location, InstructionSet isa,
}
}
-static Runtime* StartRuntime(const char* boot_image_location, InstructionSet instruction_set) {
+static Runtime* StartRuntime(const char* boot_image_location,
+ InstructionSet instruction_set,
+ const std::vector<const char*>& runtime_args) {
CHECK(boot_image_location != nullptr);
RuntimeOptions options;
@@ -101,13 +103,19 @@ static Runtime* StartRuntime(const char* boot_image_location, InstructionSet ins
std::string boot_image_option;
boot_image_option += "-Ximage:";
boot_image_option += boot_image_location;
- options.push_back(std::make_pair(boot_image_option.c_str(), nullptr));
+ options.push_back(std::make_pair(boot_image_option, nullptr));
}
// Instruction set.
options.push_back(
std::make_pair("imageinstructionset",
reinterpret_cast<const void*>(GetInstructionSetString(instruction_set))));
+
+ // Explicit runtime args.
+ for (const char* runtime_arg : runtime_args) {
+ options.push_back(std::make_pair(runtime_arg, nullptr));
+ }
+
// None of the command line tools need sig chain. If this changes we'll need
// to upgrade this option to a proper parameter.
options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
@@ -154,6 +162,14 @@ struct CmdlineArgs {
PrintUsage();
return false;
}
+ } else if (option == "--runtime-arg") {
+ if (i + 1 == argc) {
+ fprintf(stderr, "Missing argument for --runtime-arg\n");
+ PrintUsage();
+ return false;
+ }
+ ++i;
+ runtime_args_.push_back(argv[i]);
} else if (option.starts_with("--output=")) {
output_name_ = option.substr(strlen("--output=")).ToString();
const char* filename = output_name_.c_str();
@@ -209,6 +225,12 @@ struct CmdlineArgs {
" Default: %s\n"
"\n",
GetInstructionSetString(kRuntimeISA));
+ usage +=
+ " --runtime-arg <argument> used to specify various arguments for the runtime\n"
+ " such as initial heap size, maximum heap size, and verbose output.\n"
+ " Use a separate --runtime-arg switch for each argument.\n"
+ " Example: --runtime-arg -Xms256m\n"
+ "\n";
usage += // Optional.
" --output=<file> may be used to send the output to a file.\n"
" Example: --output=/tmp/oatdump.txt\n"
@@ -221,6 +243,8 @@ struct CmdlineArgs {
const char* boot_image_location_ = nullptr;
// Specified by --instruction-set.
InstructionSet instruction_set_ = InstructionSet::kNone;
+ // Runtime arguments specified by --runtime-arg.
+ std::vector<const char*> runtime_args_;
// Specified by --output.
std::ostream* os_ = &std::cout;
std::unique_ptr<std::ofstream> out_; // If something besides cout is used
@@ -383,7 +407,7 @@ struct CmdlineMain {
Runtime* CreateRuntime(CmdlineArgs* args) {
CHECK(args != nullptr);
- return StartRuntime(args->boot_image_location_, args->instruction_set_);
+ return StartRuntime(args->boot_image_location_, args->instruction_set_, args_->runtime_args_);
}
};
} // namespace art
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index ef9d919c75..58f7e4f227 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -73,7 +73,7 @@ size_t CompiledCode::CodeDelta(InstructionSet instruction_set) {
}
default:
LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
- return 0;
+ UNREACHABLE();
}
}
@@ -94,7 +94,7 @@ const void* CompiledCode::CodePointer(const void* code_pointer, InstructionSet i
}
default:
LOG(FATAL) << "Unknown InstructionSet: " << instruction_set;
- return nullptr;
+ UNREACHABLE();
}
}
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index bef5be1c0d..b28c7e0edb 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -71,6 +71,7 @@ CompilerOptions::CompilerOptions()
count_hotness_in_compiled_code_(false),
resolve_startup_const_strings_(false),
check_profiled_methods_(ProfileMethodsCheck::kNone),
+ max_image_block_size_(std::numeric_limits<uint32_t>::max()),
register_allocation_strategy_(RegisterAllocator::kRegisterAllocatorDefault),
passes_to_run_(nullptr) {
}
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index f0970a9e0d..17a779c965 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -335,6 +335,14 @@ class CompilerOptions final {
return check_profiled_methods_;
}
+ uint32_t MaxImageBlockSize() const {
+ return max_image_block_size_;
+ }
+
+ void SetMaxImageBlockSize(uint32_t size) {
+ max_image_block_size_ = size;
+ }
+
private:
bool ParseDumpInitFailures(const std::string& option, std::string* error_msg);
void ParseDumpCfgPasses(const StringPiece& option, UsageFn Usage);
@@ -424,6 +432,9 @@ class CompilerOptions final {
// up compiled and are not punted.
ProfileMethodsCheck check_profiled_methods_;
+ // Maximum solid block size in the generated image.
+ uint32_t max_image_block_size_;
+
RegisterAllocator::Strategy register_allocation_strategy_;
// If not null, specifies optimization passes which will be run instead of defaults.
diff --git a/compiler/driver/compiler_options_map-inl.h b/compiler/driver/compiler_options_map-inl.h
index c7334a72e7..7e2a64b52b 100644
--- a/compiler/driver/compiler_options_map-inl.h
+++ b/compiler/driver/compiler_options_map-inl.h
@@ -84,6 +84,7 @@ inline bool ReadCompilerOptions(Base& map, CompilerOptions* options, std::string
if (map.Exists(Base::CheckProfiledMethods)) {
options->check_profiled_methods_ = *map.Get(Base::CheckProfiledMethods);
}
+ map.AssignIfExists(Base::MaxImageBlockSize, &options->max_image_block_size_);
if (map.Exists(Base::DumpTimings)) {
options->dump_timings_ = true;
@@ -201,7 +202,11 @@ inline void AddCompilerOptionsArgumentParserOptions(Builder& b) {
.Define("--verbose-methods=_")
.template WithType<ParseStringList<','>>()
- .IntoKey(Map::VerboseMethods);
+ .IntoKey(Map::VerboseMethods)
+
+ .Define("--max-image-block-size=_")
+ .template WithType<unsigned int>()
+ .IntoKey(Map::MaxImageBlockSize);
}
#pragma GCC diagnostic pop
diff --git a/compiler/driver/compiler_options_map.def b/compiler/driver/compiler_options_map.def
index c2fac5e017..0a9c873988 100644
--- a/compiler/driver/compiler_options_map.def
+++ b/compiler/driver/compiler_options_map.def
@@ -65,5 +65,6 @@ COMPILER_OPTIONS_KEY (ProfileMethodsCheck, CheckProfiledMethods)
COMPILER_OPTIONS_KEY (Unit, DumpTimings)
COMPILER_OPTIONS_KEY (Unit, DumpPassTimings)
COMPILER_OPTIONS_KEY (Unit, DumpStats)
+COMPILER_OPTIONS_KEY (unsigned int, MaxImageBlockSize)
#undef COMPILER_OPTIONS_KEY
diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc
index 54f193b551..8b4bab722f 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.cc
+++ b/compiler/jni/quick/arm/calling_convention_arm.cc
@@ -173,7 +173,7 @@ bool ArmManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
ManagedRegister ArmManagedRuntimeCallingConvention::CurrentParamRegister() {
LOG(FATAL) << "Should not reach here";
- return ManagedRegister::NoRegister();
+ UNREACHABLE();
}
FrameOffset ArmManagedRuntimeCallingConvention::CurrentParamStackOffset() {
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index 328ecbbc5c..4e6221ef6d 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -181,7 +181,7 @@ bool Arm64ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
ManagedRegister Arm64ManagedRuntimeCallingConvention::CurrentParamRegister() {
LOG(FATAL) << "Should not reach here";
- return ManagedRegister::NoRegister();
+ UNREACHABLE();
}
FrameOffset Arm64ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc
index 5ec1addcb9..d3d489ee36 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.cc
+++ b/compiler/jni/quick/mips/calling_convention_mips.cc
@@ -124,7 +124,7 @@ bool MipsManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
ManagedRegister MipsManagedRuntimeCallingConvention::CurrentParamRegister() {
LOG(FATAL) << "Should not reach here";
- return ManagedRegister::NoRegister();
+ UNREACHABLE();
}
FrameOffset MipsManagedRuntimeCallingConvention::CurrentParamStackOffset() {
diff --git a/compiler/jni/quick/mips64/calling_convention_mips64.cc b/compiler/jni/quick/mips64/calling_convention_mips64.cc
index a7012aefa8..3c7cee6306 100644
--- a/compiler/jni/quick/mips64/calling_convention_mips64.cc
+++ b/compiler/jni/quick/mips64/calling_convention_mips64.cc
@@ -109,7 +109,7 @@ bool Mips64ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
ManagedRegister Mips64ManagedRuntimeCallingConvention::CurrentParamRegister() {
LOG(FATAL) << "Should not reach here";
- return ManagedRegister::NoRegister();
+ UNREACHABLE();
}
FrameOffset Mips64ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc
index ad58e3820d..71e601926b 100644
--- a/compiler/jni/quick/x86/calling_convention_x86.cc
+++ b/compiler/jni/quick/x86/calling_convention_x86.cc
@@ -257,7 +257,7 @@ bool X86JniCallingConvention::IsCurrentParamOnStack() {
ManagedRegister X86JniCallingConvention::CurrentParamRegister() {
LOG(FATAL) << "Should not reach here";
- return ManagedRegister::NoRegister();
+ UNREACHABLE();
}
FrameOffset X86JniCallingConvention::CurrentParamStackOffset() {
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index c2e83cd2c2..2184f99d76 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -1662,7 +1662,7 @@ QuickEntrypointEnum CodeGenerator::GetArrayAllocationEntrypoint(HNewArray* new_a
case 3: return kQuickAllocArrayResolved64;
}
LOG(FATAL) << "Unreachable";
- return kQuickAllocArrayResolved;
+ UNREACHABLE();
}
} // namespace art
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 48b50ea5d6..bbf167d615 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -3046,7 +3046,7 @@ void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction
if (!DataType::IsIntegralType(type)) {
LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
- return;
+ UNREACHABLE();
}
if (value.IsConstant()) {
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index d5b734d55a..dad18134de 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -1037,26 +1037,26 @@ static uint32_t ComputeSRegisterListMask(const SRegisterList& regs) {
size_t CodeGeneratorARMVIXL::SaveCoreRegister(size_t stack_index ATTRIBUTE_UNUSED,
uint32_t reg_id ATTRIBUTE_UNUSED) {
TODO_VIXL32(FATAL);
- return 0;
+ UNREACHABLE();
}
// Restores the register from the stack. Returns the size taken on stack.
size_t CodeGeneratorARMVIXL::RestoreCoreRegister(size_t stack_index ATTRIBUTE_UNUSED,
uint32_t reg_id ATTRIBUTE_UNUSED) {
TODO_VIXL32(FATAL);
- return 0;
+ UNREACHABLE();
}
size_t CodeGeneratorARMVIXL::SaveFloatingPointRegister(size_t stack_index ATTRIBUTE_UNUSED,
uint32_t reg_id ATTRIBUTE_UNUSED) {
TODO_VIXL32(FATAL);
- return 0;
+ UNREACHABLE();
}
size_t CodeGeneratorARMVIXL::RestoreFloatingPointRegister(size_t stack_index ATTRIBUTE_UNUSED,
uint32_t reg_id ATTRIBUTE_UNUSED) {
TODO_VIXL32(FATAL);
- return 0;
+ UNREACHABLE();
}
static void GenerateDataProcInstruction(HInstruction::InstructionKind kind,
@@ -2268,7 +2268,7 @@ Location InvokeDexCallingConventionVisitorARMVIXL::GetNextLocation(DataType::Typ
case DataType::Type::kUint64:
case DataType::Type::kVoid:
LOG(FATAL) << "Unexpected parameter type " << type;
- break;
+ UNREACHABLE();
}
return Location::NoLocation();
}
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index c6d0f3f618..c536dd3db5 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -147,7 +147,7 @@ Location InvokeDexCallingConventionVisitorMIPS::GetNextLocation(DataType::Type t
case DataType::Type::kUint64:
case DataType::Type::kVoid:
LOG(FATAL) << "Unexpected parameter type " << type;
- break;
+ UNREACHABLE();
}
// Space on the stack is reserved for all arguments.
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 039b3ca3ff..016aac791c 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3642,7 +3642,7 @@ void InstructionCodeGeneratorMIPS64::VisitDivZeroCheck(HDivZeroCheck* instructio
if (!DataType::IsIntegralType(type)) {
LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
- return;
+ UNREACHABLE();
}
if (value.IsConstant()) {
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index fba4da63cc..1b74d22a81 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1228,7 +1228,7 @@ Location InvokeDexCallingConventionVisitorX86::GetNextLocation(DataType::Type ty
case DataType::Type::kUint64:
case DataType::Type::kVoid:
LOG(FATAL) << "Unexpected parameter type " << type;
- break;
+ UNREACHABLE();
}
return Location::NoLocation();
}
@@ -2989,7 +2989,7 @@ void LocationsBuilderX86::VisitAdd(HAdd* add) {
default:
LOG(FATAL) << "Unexpected add type " << add->GetResultType();
- break;
+ UNREACHABLE();
}
}
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index e7212cd479..781f2724a5 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -2425,7 +2425,7 @@ Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(DataType::Type
case DataType::Type::kUint64:
case DataType::Type::kVoid:
LOG(FATAL) << "Unexpected parameter type " << type;
- break;
+ UNREACHABLE();
}
return Location::NoLocation();
}
diff --git a/compiler/optimizing/induction_var_analysis.cc b/compiler/optimizing/induction_var_analysis.cc
index a4d638f4c6..3a10d5831d 100644
--- a/compiler/optimizing/induction_var_analysis.cc
+++ b/compiler/optimizing/induction_var_analysis.cc
@@ -1074,8 +1074,8 @@ bool HInductionVarAnalysis::IsTaken(InductionInfo* lower_expr,
&& lower_value >= upper_value;
default:
LOG(FATAL) << "CONDITION UNREACHABLE";
+ UNREACHABLE();
}
- return false; // not certain, may be untaken
}
bool HInductionVarAnalysis::IsFinite(InductionInfo* upper_expr,
@@ -1099,8 +1099,8 @@ bool HInductionVarAnalysis::IsFinite(InductionInfo* upper_expr,
return (IsAtLeast(upper_expr, &value) && value >= (min - stride_value));
default:
LOG(FATAL) << "CONDITION UNREACHABLE";
+ UNREACHABLE();
}
- return false; // not certain, may be infinite
}
bool HInductionVarAnalysis::FitsNarrowerControl(InductionInfo* lower_expr,
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2b6ae2019f..4c6d6bacd8 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -749,8 +749,8 @@ static HCondition* GetOppositeConditionSwapOps(ArenaAllocator* allocator, HInstr
return new (allocator) HBelowOrEqual(rhs, lhs);
default:
LOG(FATAL) << "Unknown ConditionType " << cond->GetKind();
+ UNREACHABLE();
}
- return nullptr;
}
static bool CmpHasBoolType(HInstruction* input, HInstruction* cmp) {
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 3f225f354c..d1fba31792 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1231,7 +1231,7 @@ bool HInstructionList::FoundBefore(const HInstruction* instruction1,
}
}
LOG(FATAL) << "Did not find an order between two instructions of the same block.";
- return true;
+ UNREACHABLE();
}
bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
@@ -1254,7 +1254,7 @@ bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
} else {
// There is no order among phis.
LOG(FATAL) << "There is no dominance between phis of a same block.";
- return false;
+ UNREACHABLE();
}
} else {
// `this` is not a phi.
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 3a24542221..edd61897a9 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -482,6 +482,8 @@ NO_RETURN static void Usage(const char* fmt, ...) {
UsageError(" --resolve-startup-const-strings=true|false: If true, the compiler eagerly");
UsageError(" resolves strings referenced from const-string of startup methods.");
UsageError("");
+ UsageError(" --max-image-block-size=<size>: Maximum solid block size for compressed images.");
+ UsageError("");
UsageError(" Example: --compilation-reason=install");
UsageError("");
std::cerr << "See log for usage error information\n";
@@ -683,7 +685,7 @@ class Dex2Oat final {
}
struct ParserOptions {
- std::vector<const char*> oat_symbols;
+ std::vector<std::string> oat_symbols;
std::string boot_image_filename;
int64_t watch_dog_timeout_in_ms = -1;
bool watch_dog_enabled = true;
@@ -833,9 +835,7 @@ class Dex2Oat final {
}
if (dex_locations_.empty()) {
- for (const char* dex_file_name : dex_filenames_) {
- dex_locations_.push_back(dex_file_name);
- }
+ dex_locations_ = dex_filenames_;
} else if (dex_locations_.size() != dex_filenames_.size()) {
Usage("--dex-location arguments do not match --dex-file arguments");
}
@@ -1254,8 +1254,8 @@ class Dex2Oat final {
// OAT and VDEX file handling
if (oat_fd_ == -1) {
DCHECK(!oat_filenames_.empty());
- for (const char* oat_filename : oat_filenames_) {
- std::unique_ptr<File> oat_file(OS::CreateEmptyFile(oat_filename));
+ for (const std::string& oat_filename : oat_filenames_) {
+ std::unique_ptr<File> oat_file(OS::CreateEmptyFile(oat_filename.c_str()));
if (oat_file == nullptr) {
PLOG(ERROR) << "Failed to create oat file: " << oat_filename;
return false;
@@ -1353,7 +1353,7 @@ class Dex2Oat final {
}
vdex_files_.push_back(std::move(vdex_file));
- oat_filenames_.push_back(oat_location_.c_str());
+ oat_filenames_.push_back(oat_location_);
}
// If we're updating in place a vdex file, be defensive and put an invalid vdex magic in case
@@ -1401,7 +1401,8 @@ class Dex2Oat final {
MemMap input_file = zip_entry->MapDirectlyOrExtract(
VdexFile::kVdexNameInDmFile,
kDexMetadata,
- &error_msg);
+ &error_msg,
+ alignof(VdexFile));
if (!input_file.IsValid()) {
LOG(WARNING) << "Could not open vdex file in DexMetadata archive: " << error_msg;
} else {
@@ -2127,12 +2128,12 @@ class Dex2Oat final {
for (size_t i = 0; i < oat_unstripped_.size(); ++i) {
// If we don't want to strip in place, copy from stripped location to unstripped location.
// We need to strip after image creation because FixupElf needs to use .strtab.
- if (strcmp(oat_unstripped_[i], oat_filenames_[i]) != 0) {
+ if (oat_unstripped_[i] != oat_filenames_[i]) {
DCHECK(oat_files_[i].get() != nullptr && oat_files_[i]->IsOpened());
TimingLogger::ScopedTiming t("dex2oat OatFile copy", timings_);
std::unique_ptr<File>& in = oat_files_[i];
- std::unique_ptr<File> out(OS::CreateEmptyFile(oat_unstripped_[i]));
+ std::unique_ptr<File> out(OS::CreateEmptyFile(oat_unstripped_[i].c_str()));
int64_t in_length = in->GetLength();
if (in_length < 0) {
PLOG(ERROR) << "Failed to get the length of oat file: " << in->GetPath();
@@ -2361,11 +2362,13 @@ class Dex2Oat final {
DCHECK_EQ(dex_filenames_.size(), dex_locations_.size());
size_t kept = 0u;
for (size_t i = 0, size = dex_filenames_.size(); i != size; ++i) {
- if (!OS::FileExists(dex_filenames_[i])) {
+ if (!OS::FileExists(dex_filenames_[i].c_str())) {
LOG(WARNING) << "Skipping non-existent dex file '" << dex_filenames_[i] << "'";
} else {
- dex_filenames_[kept] = dex_filenames_[i];
- dex_locations_[kept] = dex_locations_[i];
+ if (kept != i) {
+ dex_filenames_[kept] = dex_filenames_[i];
+ dex_locations_[kept] = dex_locations_[i];
+ }
++kept;
}
}
@@ -2393,7 +2396,8 @@ class Dex2Oat final {
DCHECK_EQ(oat_writers_.size(), dex_filenames_.size());
DCHECK_EQ(oat_writers_.size(), dex_locations_.size());
for (size_t i = 0, size = oat_writers_.size(); i != size; ++i) {
- if (!oat_writers_[i]->AddDexFileSource(dex_filenames_[i], dex_locations_[i])) {
+ if (!oat_writers_[i]->AddDexFileSource(dex_filenames_[i].c_str(),
+ dex_locations_[i].c_str())) {
return false;
}
}
@@ -2402,7 +2406,8 @@ class Dex2Oat final {
DCHECK_EQ(dex_filenames_.size(), dex_locations_.size());
DCHECK_NE(dex_filenames_.size(), 0u);
for (size_t i = 0; i != dex_filenames_.size(); ++i) {
- if (!oat_writers_[0]->AddDexFileSource(dex_filenames_[i], dex_locations_[i])) {
+ if (!oat_writers_[0]->AddDexFileSource(dex_filenames_[i].c_str(),
+ dex_locations_[i].c_str())) {
return false;
}
}
@@ -2562,7 +2567,7 @@ class Dex2Oat final {
CHECK(image_writer_ != nullptr);
if (!IsBootImage()) {
CHECK(image_filenames_.empty());
- image_filenames_.push_back(app_image_file_name_.c_str());
+ image_filenames_.push_back(app_image_file_name_);
}
if (!image_writer_->Write(app_image_fd_,
image_filenames_,
@@ -2725,8 +2730,8 @@ class Dex2Oat final {
std::vector<std::unique_ptr<File>> oat_files_;
std::vector<std::unique_ptr<File>> vdex_files_;
std::string oat_location_;
- std::vector<const char*> oat_filenames_;
- std::vector<const char*> oat_unstripped_;
+ std::vector<std::string> oat_filenames_;
+ std::vector<std::string> oat_unstripped_;
bool strip_;
int oat_fd_;
int input_vdex_fd_;
@@ -2737,13 +2742,13 @@ class Dex2Oat final {
int dm_fd_;
std::string dm_file_location_;
std::unique_ptr<ZipArchive> dm_file_;
- std::vector<const char*> dex_filenames_;
- std::vector<const char*> dex_locations_;
+ std::vector<std::string> dex_filenames_;
+ std::vector<std::string> dex_locations_;
int zip_fd_;
std::string zip_location_;
std::string boot_image_filename_;
std::vector<const char*> runtime_args_;
- std::vector<const char*> image_filenames_;
+ std::vector<std::string> image_filenames_;
uintptr_t image_base_;
const char* image_classes_zip_filename_;
const char* image_classes_filename_;
diff --git a/dex2oat/linker/image_test.cc b/dex2oat/linker/image_test.cc
index 64b98cdb37..ebd829bc98 100644
--- a/dex2oat/linker/image_test.cc
+++ b/dex2oat/linker/image_test.cc
@@ -32,7 +32,11 @@ TEST_F(ImageTest, TestImageLayout) {
// Compile multi-image with ImageLayoutA being the last image.
{
CompilationHelper helper;
- Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutA", {"LMyClass;"});
+ Compile(ImageHeader::kStorageModeUncompressed,
+ /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
+ helper,
+ "ImageLayoutA",
+ {"LMyClass;"});
image_sizes = helper.GetImageObjectSectionSizes();
}
TearDown();
@@ -41,7 +45,11 @@ TEST_F(ImageTest, TestImageLayout) {
// Compile multi-image with ImageLayoutB being the last image.
{
CompilationHelper helper;
- Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutB", {"LMyClass;"});
+ Compile(ImageHeader::kStorageModeUncompressed,
+ /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
+ helper,
+ "ImageLayoutB",
+ {"LMyClass;"});
image_sizes_extra = helper.GetImageObjectSectionSizes();
}
// Make sure that the new stuff in the clinit in ImageLayoutB is in the last image and not in the
@@ -76,9 +84,8 @@ TEST_F(ImageTest, ImageHeaderIsValid) {
oat_file_end,
/*boot_image_begin=*/ 0u,
/*boot_image_size=*/ 0u,
- sizeof(void*),
- ImageHeader::kDefaultStorageMode,
- /*data_size=*/ 0u);
+ sizeof(void*));
+
ASSERT_TRUE(image_header.IsValid());
ASSERT_TRUE(!image_header.IsAppImage());
@@ -97,6 +104,7 @@ TEST_F(ImageTest, ImageHeaderIsValid) {
TEST_F(ImageTest, TestDefaultMethods) {
CompilationHelper helper;
Compile(ImageHeader::kStorageModeUncompressed,
+ /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
helper,
"DefaultMethods",
{"LIface;", "LImpl;", "LIterableBase;"});
@@ -156,6 +164,7 @@ TEST_F(ImageTest, TestDefaultMethods) {
TEST_F(ImageTest, TestSoftVerificationFailureDuringClassInitialization) {
CompilationHelper helper;
Compile(ImageHeader::kStorageModeUncompressed,
+ /*max_image_block_size=*/std::numeric_limits<uint32_t>::max(),
helper,
"VerifySoftFailDuringClinit",
/*image_classes=*/ {"LClassToInitialize;"},
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index c90eaddb4c..844a72803e 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -77,9 +77,10 @@ class ImageTest : public CommonCompilerTest {
CommonCompilerTest::SetUp();
}
- void TestWriteRead(ImageHeader::StorageMode storage_mode);
+ void TestWriteRead(ImageHeader::StorageMode storage_mode, uint32_t max_image_block_size);
void Compile(ImageHeader::StorageMode storage_mode,
+ uint32_t max_image_block_size,
/*out*/ CompilationHelper& out_helper,
const std::string& extra_dex = "",
const std::initializer_list<std::string>& image_classes = {},
@@ -200,14 +201,6 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode,
}
std::unordered_map<const DexFile*, size_t> dex_file_to_oat_index_map;
- std::vector<const char*> oat_filename_vector;
- for (const std::string& file : oat_filenames) {
- oat_filename_vector.push_back(file.c_str());
- }
- std::vector<const char*> image_filename_vector;
- for (const std::string& file : image_filenames) {
- image_filename_vector.push_back(file.c_str());
- }
size_t image_idx = 0;
for (const DexFile* dex_file : class_path) {
dex_file_to_oat_index_map.emplace(dex_file, image_idx);
@@ -217,7 +210,7 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode,
std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_options_,
kRequestedImageBase,
storage_mode,
- oat_filename_vector,
+ oat_filenames,
dex_file_to_oat_index_map,
/*class_loader=*/ nullptr,
/*dirty_image_objects=*/ nullptr));
@@ -231,15 +224,11 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode,
t.NewTiming("WriteElf");
SafeMap<std::string, std::string> key_value_store;
- std::vector<const char*> dex_filename_vector;
- for (size_t i = 0; i < class_path.size(); ++i) {
- dex_filename_vector.push_back("");
- }
key_value_store.Put(OatHeader::kBootClassPathKey,
gc::space::ImageSpace::GetMultiImageBootClassPath(
- dex_filename_vector,
- oat_filename_vector,
- image_filename_vector));
+ out_helper.dex_file_locations,
+ oat_filenames,
+ image_filenames));
std::vector<std::unique_ptr<ElfWriter>> elf_writers;
std::vector<std::unique_ptr<OatWriter>> oat_writers;
@@ -271,7 +260,7 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode,
bool dex_files_ok = oat_writers[i]->WriteAndOpenDexFiles(
out_helper.vdex_files[i].GetFile(),
rodata.back(),
- &key_value_store,
+ (i == 0u) ? &key_value_store : nullptr,
/* verify */ false, // Dex files may be dex-to-dex-ed, don't verify.
/* update_input_vdex */ false,
/* copy_dex_files */ CopyOption::kOnlyIfCompressed,
@@ -356,8 +345,8 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode,
}
bool success_image = writer->Write(kInvalidFd,
- image_filename_vector,
- oat_filename_vector);
+ image_filenames,
+ oat_filenames);
ASSERT_TRUE(success_image);
for (size_t i = 0, size = oat_filenames.size(); i != size; ++i) {
@@ -374,6 +363,7 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode,
inline void ImageTest::Compile(
ImageHeader::StorageMode storage_mode,
+ uint32_t max_image_block_size,
CompilationHelper& helper,
const std::string& extra_dex,
const std::initializer_list<std::string>& image_classes,
@@ -388,6 +378,7 @@ inline void ImageTest::Compile(
CreateCompilerDriver();
// Set inline filter values.
compiler_options_->SetInlineMaxCodeUnits(CompilerOptions::kDefaultInlineMaxCodeUnits);
+ compiler_options_->SetMaxImageBlockSize(max_image_block_size);
image_classes_.clear();
if (!extra_dex.empty()) {
helper.extra_dex_files = OpenTestDexFiles(extra_dex.c_str());
@@ -411,9 +402,10 @@ inline void ImageTest::Compile(
}
}
-inline void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) {
+inline void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode,
+ uint32_t max_image_block_size) {
CompilationHelper helper;
- Compile(storage_mode, /*out*/ helper);
+ Compile(storage_mode, max_image_block_size, /*out*/ helper);
std::vector<uint64_t> image_file_sizes;
for (ScratchFile& image_file : helper.image_files) {
std::unique_ptr<File> file(OS::OpenFileForReading(image_file.GetFilename().c_str()));
@@ -488,6 +480,10 @@ inline void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) {
} else if (image_file_size > 16 * KB) {
// Compressed, file should be smaller than image. Not really valid for small images.
ASSERT_LE(image_file_size, image_space->GetImageHeader().GetImageSize());
+ // TODO: Actually validate the blocks, this is hard since the blocks are not copied over for
+ // compressed images. Add kPageSize since image_size is rounded up to this.
+ ASSERT_GT(image_space->GetImageHeader().GetBlockCount() * max_image_block_size,
+ image_space->GetImageHeader().GetImageSize() - kPageSize);
}
image_space->VerifyImageAllocations();
diff --git a/dex2oat/linker/image_write_read_test.cc b/dex2oat/linker/image_write_read_test.cc
index 30996b562b..5ddbd0944d 100644
--- a/dex2oat/linker/image_write_read_test.cc
+++ b/dex2oat/linker/image_write_read_test.cc
@@ -20,15 +20,23 @@ namespace art {
namespace linker {
TEST_F(ImageTest, WriteReadUncompressed) {
- TestWriteRead(ImageHeader::kStorageModeUncompressed);
+ TestWriteRead(ImageHeader::kStorageModeUncompressed,
+ /*max_image_block_size=*/std::numeric_limits<uint32_t>::max());
}
TEST_F(ImageTest, WriteReadLZ4) {
- TestWriteRead(ImageHeader::kStorageModeLZ4);
+ TestWriteRead(ImageHeader::kStorageModeLZ4,
+ /*max_image_block_size=*/std::numeric_limits<uint32_t>::max());
}
TEST_F(ImageTest, WriteReadLZ4HC) {
- TestWriteRead(ImageHeader::kStorageModeLZ4HC);
+ TestWriteRead(ImageHeader::kStorageModeLZ4HC,
+ /*max_image_block_size=*/std::numeric_limits<uint32_t>::max());
+}
+
+
+TEST_F(ImageTest, WriteReadLZ4HCKBBlock) {
+ TestWriteRead(ImageHeader::kStorageModeLZ4HC, /*max_image_block_size=*/KB);
}
} // namespace linker
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 75b35556f1..231ac04f8c 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -662,8 +662,8 @@ class ImageWriter::ImageFileGuard {
};
bool ImageWriter::Write(int image_fd,
- const std::vector<const char*>& image_filenames,
- const std::vector<const char*>& oat_filenames) {
+ const std::vector<std::string>& image_filenames,
+ const std::vector<std::string>& oat_filenames) {
// If image_fd or oat_fd are not kInvalidFd then we may have empty strings in image_filenames or
// oat_filenames.
CHECK(!image_filenames.empty());
@@ -715,11 +715,11 @@ bool ImageWriter::Write(int image_fd,
ImageHeader* primary_header = reinterpret_cast<ImageHeader*>(image_infos_[0].image_.Begin());
ImageFileGuard primary_image_file;
for (size_t i = 0; i < image_filenames.size(); ++i) {
- const char* image_filename = image_filenames[i];
+ const std::string& image_filename = image_filenames[i];
ImageInfo& image_info = GetImageInfo(i);
ImageFileGuard image_file;
if (image_fd != kInvalidFd) {
- if (strlen(image_filename) == 0u) {
+ if (image_filename.empty()) {
image_file.reset(new File(image_fd, unix_file::kCheckSafeUsage));
// Empty the file in case it already exists.
if (image_file != nullptr) {
@@ -730,7 +730,7 @@ bool ImageWriter::Write(int image_fd,
LOG(ERROR) << "image fd " << image_fd << " name " << image_filename;
}
} else {
- image_file.reset(OS::CreateEmptyFile(image_filename));
+ image_file.reset(OS::CreateEmptyFile(image_filename.c_str()));
}
if (image_file == nullptr) {
@@ -745,32 +745,93 @@ bool ImageWriter::Write(int image_fd,
// Image data size excludes the bitmap and the header.
ImageHeader* const image_header = reinterpret_cast<ImageHeader*>(image_info.image_.Begin());
- ArrayRef<const uint8_t> raw_image_data(image_info.image_.Begin() + sizeof(ImageHeader),
- image_header->GetImageSize() - sizeof(ImageHeader));
-
- CHECK_EQ(image_header->storage_mode_, image_storage_mode_);
- std::vector<uint8_t> compressed_data;
- ArrayRef<const uint8_t> image_data =
- MaybeCompressData(raw_image_data, image_storage_mode_, &compressed_data);
- image_header->data_size_ = image_data.size(); // Fill in the data size.
-
- // Write out the image + fields + methods.
- if (!image_file->PwriteFully(image_data.data(), image_data.size(), sizeof(ImageHeader))) {
- PLOG(ERROR) << "Failed to write image file data " << image_filename;
- return false;
+
+ // Block sources (from the image).
+ const bool is_compressed = image_storage_mode_ != ImageHeader::kStorageModeUncompressed;
+ std::vector<std::pair<uint32_t, uint32_t>> block_sources;
+ std::vector<ImageHeader::Block> blocks;
+
+ // Add a set of solid blocks such that no block is larger than the maximum size. A solid block
+ // is a block that must be decompressed all at once.
+ auto add_blocks = [&](uint32_t offset, uint32_t size) {
+ while (size != 0u) {
+ const uint32_t cur_size = std::min(size, compiler_options_.MaxImageBlockSize());
+ block_sources.emplace_back(offset, cur_size);
+ offset += cur_size;
+ size -= cur_size;
+ }
+ };
+
+ add_blocks(sizeof(ImageHeader), image_header->GetImageSize() - sizeof(ImageHeader));
+
+ // Checksum of compressed image data and header.
+ uint32_t image_checksum = adler32(0L, Z_NULL, 0);
+ image_checksum = adler32(image_checksum,
+ reinterpret_cast<const uint8_t*>(image_header),
+ sizeof(ImageHeader));
+ // Copy and compress blocks.
+ size_t out_offset = sizeof(ImageHeader);
+ for (const std::pair<uint32_t, uint32_t> block : block_sources) {
+ ArrayRef<const uint8_t> raw_image_data(image_info.image_.Begin() + block.first,
+ block.second);
+ std::vector<uint8_t> compressed_data;
+ ArrayRef<const uint8_t> image_data =
+ MaybeCompressData(raw_image_data, image_storage_mode_, &compressed_data);
+
+ if (!is_compressed) {
+ // For uncompressed, preserve alignment since the image will be directly mapped.
+ out_offset = block.first;
+ }
+
+ // Fill in the compressed location of the block.
+ blocks.emplace_back(ImageHeader::Block(
+ image_storage_mode_,
+ /*data_offset=*/ out_offset,
+ /*data_size=*/ image_data.size(),
+ /*image_offset=*/ block.first,
+ /*image_size=*/ block.second));
+
+ // Write out the image + fields + methods.
+ if (!image_file->PwriteFully(image_data.data(), image_data.size(), out_offset)) {
+ PLOG(ERROR) << "Failed to write image file data " << image_filename;
+ image_file->Erase();
+ return false;
+ }
+ out_offset += image_data.size();
+ image_checksum = adler32(image_checksum, image_data.data(), image_data.size());
+ }
+
+ // Write the block metadata directly after the image sections.
+ // Note: This is not part of the mapped image and is not preserved after decompressing, it's
+ // only used for image loading. For this reason, only write it out for compressed images.
+ if (is_compressed) {
+ // Align up since the compressed data is not necessarily aligned.
+ out_offset = RoundUp(out_offset, alignof(ImageHeader::Block));
+ CHECK(!blocks.empty());
+ const size_t blocks_bytes = blocks.size() * sizeof(blocks[0]);
+ if (!image_file->PwriteFully(&blocks[0], blocks_bytes, out_offset)) {
+ PLOG(ERROR) << "Failed to write image blocks " << image_filename;
+ image_file->Erase();
+ return false;
+ }
+ image_header->blocks_offset_ = out_offset;
+ image_header->blocks_count_ = blocks.size();
+ out_offset += blocks_bytes;
}
- // Write out the image bitmap at the page aligned start of the image end, also uncompressed for
- // convenience.
- const ImageSection& bitmap_section = image_header->GetImageBitmapSection();
+ // Data size includes everything except the bitmap.
+ image_header->data_size_ = out_offset - sizeof(ImageHeader);
+
+ // Update and write the bitmap section. Note that the bitmap section is relative to the
+ // possibly compressed image.
+ ImageSection& bitmap_section = image_header->GetImageSection(ImageHeader::kSectionImageBitmap);
// Align up since data size may be unaligned if the image is compressed.
- size_t bitmap_position_in_file = RoundUp(sizeof(ImageHeader) + image_data.size(), kPageSize);
- if (image_storage_mode_ == ImageHeader::kDefaultStorageMode) {
- CHECK_EQ(bitmap_position_in_file, bitmap_section.Offset());
- }
+ out_offset = RoundUp(out_offset, kPageSize);
+ bitmap_section = ImageSection(out_offset, bitmap_section.Size());
+
if (!image_file->PwriteFully(image_info.image_bitmap_->Begin(),
bitmap_section.Size(),
- bitmap_position_in_file)) {
+ bitmap_section.Offset())) {
PLOG(ERROR) << "Failed to write image file bitmap " << image_filename;
return false;
}
@@ -781,22 +842,17 @@ bool ImageWriter::Write(int image_fd,
return false;
}
- // Calculate the image checksum.
- uint32_t image_checksum = adler32(0L, Z_NULL, 0);
- image_checksum = adler32(image_checksum,
- reinterpret_cast<const uint8_t*>(image_header),
- sizeof(ImageHeader));
- image_checksum = adler32(image_checksum, image_data.data(), image_data.size());
+ // Calculate the image checksum of the remaining data.
image_checksum = adler32(image_checksum,
reinterpret_cast<const uint8_t*>(image_info.image_bitmap_->Begin()),
bitmap_section.Size());
image_header->SetImageChecksum(image_checksum);
if (VLOG_IS_ON(compiler)) {
- size_t separately_written_section_size = bitmap_section.Size() + sizeof(ImageHeader);
-
- size_t total_uncompressed_size = raw_image_data.size() + separately_written_section_size,
- total_compressed_size = image_data.size() + separately_written_section_size;
+ const size_t separately_written_section_size = bitmap_section.Size();
+ const size_t total_uncompressed_size = image_info.image_size_ +
+ separately_written_section_size;
+ const size_t total_compressed_size = out_offset + separately_written_section_size;
VLOG(compiler) << "Dex2Oat:uncompressedImageSize = " << total_uncompressed_size;
if (total_uncompressed_size != total_compressed_size) {
@@ -804,8 +860,8 @@ bool ImageWriter::Write(int image_fd,
}
}
- CHECK_EQ(bitmap_position_in_file + bitmap_section.Size(),
- static_cast<size_t>(image_file->GetLength()));
+ CHECK_EQ(bitmap_section.End(), static_cast<size_t>(image_file->GetLength()))
+ << "Bitmap should be at the end of the file";
// Write header last in case the compiler gets killed in the middle of image writing.
// We do not want to have a corrupted image with a valid header.
@@ -895,7 +951,7 @@ void ImageWriter::SetImageBinSlot(mirror::Object* object, BinSlot bin_slot) {
oss << ". Lock owner:" << lw.ThinLockOwner();
}
LOG(FATAL) << oss.str();
- break;
+ UNREACHABLE();
}
case LockWord::kUnlocked:
// No hash, don't need to save it.
@@ -2574,9 +2630,7 @@ void ImageWriter::CreateHeader(size_t oat_index) {
PointerToLowMemUInt32(oat_file_end),
boot_image_begin,
boot_oat_end - boot_image_begin,
- static_cast<uint32_t>(target_ptr_size_),
- image_storage_mode_,
- /*data_size*/0u);
+ static_cast<uint32_t>(target_ptr_size_));
}
ArtMethod* ImageWriter::GetImageMethodAddress(ArtMethod* method) {
@@ -3454,7 +3508,7 @@ ImageWriter::ImageWriter(
const CompilerOptions& compiler_options,
uintptr_t image_begin,
ImageHeader::StorageMode image_storage_mode,
- const std::vector<const char*>& oat_filenames,
+ const std::vector<std::string>& oat_filenames,
const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map,
jobject class_loader,
const HashSet<std::string>* dirty_image_objects)
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 782bbd2fc2..33bacf8c1b 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -79,7 +79,7 @@ class ImageWriter final {
ImageWriter(const CompilerOptions& compiler_options,
uintptr_t image_begin,
ImageHeader::StorageMode image_storage_mode,
- const std::vector<const char*>& oat_filenames,
+ const std::vector<std::string>& oat_filenames,
const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map,
jobject class_loader,
const HashSet<std::string>* dirty_image_objects);
@@ -142,8 +142,8 @@ class ImageWriter final {
// If oat_fd is not kInvalidFd, then we use that for the oat file. Otherwise we open
// the names in oat_filenames.
bool Write(int image_fd,
- const std::vector<const char*>& image_filenames,
- const std::vector<const char*>& oat_filenames)
+ const std::vector<std::string>& image_filenames,
+ const std::vector<std::string>& oat_filenames)
REQUIRES(!Locks::mutator_lock_);
uintptr_t GetOatDataBegin(size_t oat_index) {
@@ -785,7 +785,7 @@ class ImageWriter final {
const ImageHeader::StorageMode image_storage_mode_;
// The file names of oat files.
- const std::vector<const char*>& oat_filenames_;
+ const std::vector<std::string>& oat_filenames_;
// Map of dex files to the indexes of oat files that they were compiled into.
const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map_;
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 9aaabc49dd..6b17ef6e87 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -3682,7 +3682,7 @@ bool OatWriter::OpenDexFiles(
for (OatDexFile& oat_dex_file : oat_dex_files_) {
std::string error_msg;
maps.emplace_back(oat_dex_file.source_.GetZipEntry()->MapDirectlyOrExtract(
- oat_dex_file.dex_file_location_data_, "zipped dex", &error_msg));
+ oat_dex_file.dex_file_location_data_, "zipped dex", &error_msg, alignof(DexFile)));
MemMap* map = &maps.back();
if (!map->IsValid()) {
LOG(ERROR) << error_msg;
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 7450964fdf..598a0f846b 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -119,7 +119,8 @@ class OatTest : public CommonCompilerTest {
return false;
}
}
- return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify);
+ return DoWriteElf(
+ vdex_file, oat_file, oat_writer, key_value_store, verify, CopyOption::kOnlyIfCompressed);
}
bool WriteElf(File* vdex_file,
@@ -127,6 +128,7 @@ class OatTest : public CommonCompilerTest {
const std::vector<const char*>& dex_filenames,
SafeMap<std::string, std::string>& key_value_store,
bool verify,
+ CopyOption copy,
ProfileCompilationInfo* profile_compilation_info) {
TimingLogger timings("WriteElf", false, false);
ClearBootImageOption();
@@ -139,7 +141,7 @@ class OatTest : public CommonCompilerTest {
return false;
}
}
- return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify);
+ return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify, copy);
}
bool WriteElf(File* vdex_file,
@@ -147,7 +149,8 @@ class OatTest : public CommonCompilerTest {
File&& zip_fd,
const char* location,
SafeMap<std::string, std::string>& key_value_store,
- bool verify) {
+ bool verify,
+ CopyOption copy) {
TimingLogger timings("WriteElf", false, false);
ClearBootImageOption();
OatWriter oat_writer(*compiler_options_,
@@ -157,14 +160,15 @@ class OatTest : public CommonCompilerTest {
if (!oat_writer.AddZippedDexFilesSource(std::move(zip_fd), location)) {
return false;
}
- return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify);
+ return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify, copy);
}
bool DoWriteElf(File* vdex_file,
File* oat_file,
OatWriter& oat_writer,
SafeMap<std::string, std::string>& key_value_store,
- bool verify) {
+ bool verify,
+ CopyOption copy) {
std::unique_ptr<ElfWriter> elf_writer = CreateElfWriterQuick(
compiler_driver_->GetCompilerOptions(),
oat_file);
@@ -178,7 +182,7 @@ class OatTest : public CommonCompilerTest {
&key_value_store,
verify,
/*update_input_vdex=*/ false,
- CopyOption::kOnlyIfCompressed,
+ copy,
&opened_dex_files_maps,
&opened_dex_files)) {
return false;
@@ -257,7 +261,7 @@ class OatTest : public CommonCompilerTest {
}
void TestDexFileInput(bool verify, bool low_4gb, bool use_profile);
- void TestZipFileInput(bool verify);
+ void TestZipFileInput(bool verify, CopyOption copy);
void TestZipFileInputWithEmptyDex();
std::unique_ptr<QuickCompilerCallbacks> callbacks_;
@@ -587,6 +591,7 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) {
input_filenames,
key_value_store,
verify,
+ CopyOption::kOnlyIfCompressed,
profile_compilation_info.get());
// In verify mode, we expect failure.
@@ -663,7 +668,7 @@ TEST_F(OatTest, DexFileFailsVerifierWithLayout) {
TestDexFileInput(/*verify*/true, /*low_4gb*/false, /*use_profile*/true);
}
-void OatTest::TestZipFileInput(bool verify) {
+void OatTest::TestZipFileInput(bool verify, CopyOption copy) {
TimingLogger timings("OatTest::DexFileInput", false, false);
ScratchFile zip_file;
@@ -719,6 +724,7 @@ void OatTest::TestZipFileInput(bool verify) {
input_filenames,
key_value_store,
verify,
+ copy,
/*profile_compilation_info=*/ nullptr);
if (verify) {
@@ -769,7 +775,8 @@ void OatTest::TestZipFileInput(bool verify) {
std::move(zip_fd),
zip_file.GetFilename().c_str(),
key_value_store,
- verify);
+ verify,
+ copy);
if (verify) {
ASSERT_FALSE(success);
} else {
@@ -809,11 +816,15 @@ void OatTest::TestZipFileInput(bool verify) {
}
TEST_F(OatTest, ZipFileInputCheckOutput) {
- TestZipFileInput(false);
+ TestZipFileInput(false, CopyOption::kOnlyIfCompressed);
+}
+
+TEST_F(OatTest, ZipFileInputCheckOutputWithoutCopy) {
+ TestZipFileInput(false, CopyOption::kNever);
}
TEST_F(OatTest, ZipFileInputCheckVerifier) {
- TestZipFileInput(true);
+ TestZipFileInput(true, CopyOption::kOnlyIfCompressed);
}
void OatTest::TestZipFileInputWithEmptyDex() {
@@ -833,6 +844,7 @@ void OatTest::TestZipFileInputWithEmptyDex() {
input_filenames,
key_value_store,
/*verify=*/ false,
+ CopyOption::kOnlyIfCompressed,
profile_compilation_info.get());
ASSERT_FALSE(success);
}
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 2b97fb402a..acf0f94572 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -97,6 +97,11 @@ NO_RETURN static void Usage(const char *fmt, ...) {
UsageError(" oat file is up to date. Defaults to $ANDROID_ROOT/framework/boot.art.");
UsageError(" Example: --image=/system/framework/boot.art");
UsageError("");
+ UsageError(" --runtime-arg <argument>: used to specify various arguments for the runtime,");
+ UsageError(" such as initial heap size, maximum heap size, and verbose output.");
+ UsageError(" Use a separate --runtime-arg switch for each argument.");
+ UsageError(" Example: --runtime-arg -Xms256m");
+ UsageError("");
UsageError(" --android-data=<directory>: optional, the directory which should be used as");
UsageError(" android-data. By default ANDROID_DATA env variable is used.");
UsageError("");
@@ -168,6 +173,12 @@ class DexoptAnalyzer final {
}
} else if (option.starts_with("--image=")) {
image_ = option.substr(strlen("--image=")).ToString();
+ } else if (option == "--runtime-arg") {
+ if (i + 1 == argc) {
+ Usage("Missing argument for --runtime-arg\n");
+ }
+ ++i;
+ runtime_args_.push_back(argv[i]);
} else if (option.starts_with("--android-data=")) {
// Overwrite android-data if needed (oat file assistant relies on a valid directory to
// compute dalvik-cache folder). This is mostly used in tests.
@@ -218,10 +229,14 @@ class DexoptAnalyzer final {
RuntimeOptions options;
// The image could be custom, so make sure we explicitly pass it.
std::string img = "-Ximage:" + image_;
- options.push_back(std::make_pair(img.c_str(), nullptr));
+ options.push_back(std::make_pair(img, nullptr));
// The instruction set of the image should match the instruction set we will test.
const void* isa_opt = reinterpret_cast<const void*>(GetInstructionSetString(isa_));
options.push_back(std::make_pair("imageinstructionset", isa_opt));
+ // Explicit runtime args.
+ for (const char* runtime_arg : runtime_args_) {
+ options.push_back(std::make_pair(runtime_arg, nullptr));
+ }
// Disable libsigchain. We don't don't need it to evaluate DexOptNeeded status.
options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
// Pretend we are a compiler so that we can re-use the same infrastructure to load a different
@@ -289,6 +304,7 @@ class DexoptAnalyzer final {
bool assume_profile_changed_;
bool downgrade_;
std::string image_;
+ std::vector<const char*> runtime_args_;
int oat_fd_ = -1;
int vdex_fd_ = -1;
// File descriptor corresponding to apk, dex_file, or zip.
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index aee690e036..0662334852 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -75,7 +75,7 @@ Disassembler* Disassembler::Create(InstructionSet instruction_set, DisassemblerO
#endif
default:
UNIMPLEMENTED(FATAL) << static_cast<uint32_t>(instruction_set);
- return nullptr;
+ UNREACHABLE();
}
}
diff --git a/libartbase/base/file_utils.cc b/libartbase/base/file_utils.cc
index 1d106b2cdb..f8d6016315 100644
--- a/libartbase/base/file_utils.cc
+++ b/libartbase/base/file_utils.cc
@@ -157,7 +157,7 @@ static const char* GetAndroidDir(const char* env_var, const char* default_dir) {
return dir;
} else {
LOG(FATAL) << error_msg;
- return nullptr;
+ UNREACHABLE();
}
}
diff --git a/libartbase/base/zip_archive.cc b/libartbase/base/zip_archive.cc
index 8ceea83be4..a7f4b28c84 100644
--- a/libartbase/base/zip_archive.cc
+++ b/libartbase/base/zip_archive.cc
@@ -189,8 +189,9 @@ MemMap ZipEntry::MapDirectlyFromFile(const char* zip_filename, std::string* erro
MemMap ZipEntry::MapDirectlyOrExtract(const char* zip_filename,
const char* entry_filename,
- std::string* error_msg) {
- if (IsUncompressed() && GetFileDescriptor(handle_) >= 0) {
+ std::string* error_msg,
+ size_t alignment) {
+ if (IsUncompressed() && IsAlignedTo(alignment) && GetFileDescriptor(handle_) >= 0) {
std::string local_error_msg;
MemMap ret = MapDirectlyFromFile(zip_filename, &local_error_msg);
if (ret.IsValid()) {
diff --git a/libartbase/base/zip_archive.h b/libartbase/base/zip_archive.h
index d326a9e9d7..fc04ec1e91 100644
--- a/libartbase/base/zip_archive.h
+++ b/libartbase/base/zip_archive.h
@@ -59,7 +59,8 @@ class ZipEntry {
MemMap MapDirectlyOrExtract(const char* zip_filename,
const char* entry_filename,
- std::string* error_msg);
+ std::string* error_msg,
+ size_t alignment);
uint32_t GetUncompressedLength();
uint32_t GetCrc32();
diff --git a/libdexfile/dex/dex_instruction.cc b/libdexfile/dex/dex_instruction.cc
index 8378211c43..83663c50e8 100644
--- a/libdexfile/dex/dex_instruction.cc
+++ b/libdexfile/dex/dex_instruction.cc
@@ -85,7 +85,7 @@ int32_t Instruction::GetTargetOffset() const {
default: LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name() <<
" which does not have a target operand.";
}
- return 0;
+ UNREACHABLE();
}
bool Instruction::CanFlowThrough() const {
diff --git a/libprofile/profile/profile_compilation_info.cc b/libprofile/profile/profile_compilation_info.cc
index 6bd49a43eb..02f6344863 100644
--- a/libprofile/profile/profile_compilation_info.cc
+++ b/libprofile/profile/profile_compilation_info.cc
@@ -1197,7 +1197,8 @@ ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::OpenSource(
}
// TODO(calin) pass along file names to assist with debugging.
- MemMap map = zip_entry->MapDirectlyOrExtract(kDexMetadataProfileEntry, "profile file", error);
+ MemMap map = zip_entry->MapDirectlyOrExtract(
+ kDexMetadataProfileEntry, "profile file", error, alignof(ProfileSource));
if (map.IsValid()) {
source->reset(ProfileSource::Create(std::move(map)));
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 51f60084a1..1c74a923e6 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1936,7 +1936,7 @@ class ImageDumper {
stats_.file_bytes = file->GetLength();
// If the image is compressed, adjust to decompressed size.
size_t uncompressed_size = image_header_.GetImageSize() - sizeof(ImageHeader);
- if (image_header_.GetStorageMode() == ImageHeader::kStorageModeUncompressed) {
+ if (image_header_.HasCompressedBlock()) {
DCHECK_EQ(uncompressed_size, data_size) << "Sizes should match for uncompressed image";
}
stats_.file_bytes += uncompressed_size - data_size;
diff --git a/openjdkjvm/OpenjdkJvm.cc b/openjdkjvm/OpenjdkJvm.cc
index 8d0200c346..7a388c9583 100644
--- a/openjdkjvm/OpenjdkJvm.cc
+++ b/openjdkjvm/OpenjdkJvm.cc
@@ -434,36 +434,37 @@ JNIEXPORT void JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring jav
}
}
-JNIEXPORT jint JVM_IHashCode(JNIEnv* env ATTRIBUTE_UNUSED,
+JNIEXPORT __attribute__((noreturn)) jint JVM_IHashCode(JNIEnv* env ATTRIBUTE_UNUSED,
jobject javaObject ATTRIBUTE_UNUSED) {
UNIMPLEMENTED(FATAL) << "JVM_IHashCode is not implemented";
- return 0;
+ UNREACHABLE();
}
-JNIEXPORT jlong JVM_NanoTime(JNIEnv* env ATTRIBUTE_UNUSED, jclass unused ATTRIBUTE_UNUSED) {
+JNIEXPORT __attribute__((noreturn)) jlong JVM_NanoTime(JNIEnv* env ATTRIBUTE_UNUSED, jclass unused ATTRIBUTE_UNUSED) {
UNIMPLEMENTED(FATAL) << "JVM_NanoTime is not implemented";
- return 0L;
+ UNREACHABLE();
}
-JNIEXPORT void JVM_ArrayCopy(JNIEnv* /* env */, jclass /* unused */, jobject /* javaSrc */,
+JNIEXPORT __attribute__((noreturn)) void JVM_ArrayCopy(JNIEnv* /* env */, jclass /* unused */, jobject /* javaSrc */,
jint /* srcPos */, jobject /* javaDst */, jint /* dstPos */,
jint /* length */) {
UNIMPLEMENTED(FATAL) << "JVM_ArrayCopy is not implemented";
+ UNREACHABLE();
}
-JNIEXPORT jint JVM_FindSignal(const char* name ATTRIBUTE_UNUSED) {
+JNIEXPORT __attribute__((noreturn)) jint JVM_FindSignal(const char* name ATTRIBUTE_UNUSED) {
LOG(FATAL) << "JVM_FindSignal is not implemented";
- return 0;
+ UNREACHABLE();
}
-JNIEXPORT void* JVM_RegisterSignal(jint signum ATTRIBUTE_UNUSED, void* handler ATTRIBUTE_UNUSED) {
+JNIEXPORT __attribute__((noreturn)) void* JVM_RegisterSignal(jint signum ATTRIBUTE_UNUSED, void* handler ATTRIBUTE_UNUSED) {
LOG(FATAL) << "JVM_RegisterSignal is not implemented";
- return nullptr;
+ UNREACHABLE();
}
-JNIEXPORT jboolean JVM_RaiseSignal(jint signum ATTRIBUTE_UNUSED) {
+JNIEXPORT __attribute__((noreturn)) jboolean JVM_RaiseSignal(jint signum ATTRIBUTE_UNUSED) {
LOG(FATAL) << "JVM_RaiseSignal is not implemented";
- return JNI_FALSE;
+ UNREACHABLE();
}
JNIEXPORT __attribute__((noreturn)) void JVM_Halt(jint code) {
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index a96436e95a..7fb6a15220 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -960,7 +960,7 @@ static uint32_t GetInstrumentationEventsFor(ArtJvmtiEvent event) {
return art::instrumentation::Instrumentation::kExceptionHandled;
default:
LOG(FATAL) << "Unknown event ";
- return 0;
+ UNREACHABLE();
}
}
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index abfdd5547d..882291f20b 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -70,7 +70,7 @@ ArtMethod* ArtMethod::GetCanonicalMethod(PointerSize pointer_size) {
} else {
ObjPtr<mirror::Class> declaring_class = GetDeclaringClass();
DCHECK(declaring_class->IsInterface());
- ArtMethod* ret = declaring_class->FindInterfaceMethod(declaring_class->GetDexCache(),
+ ArtMethod* ret = declaring_class->FindInterfaceMethod(GetDexCache(),
GetDexMethodIndex(),
pointer_size);
DCHECK(ret != nullptr);
@@ -79,10 +79,11 @@ ArtMethod* ArtMethod::GetCanonicalMethod(PointerSize pointer_size) {
}
ArtMethod* ArtMethod::GetNonObsoleteMethod() {
- DCHECK_EQ(kRuntimePointerSize, Runtime::Current()->GetClassLinker()->GetImagePointerSize());
if (LIKELY(!IsObsolete())) {
return this;
- } else if (IsDirect()) {
+ }
+ DCHECK_EQ(kRuntimePointerSize, Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+ if (IsDirect()) {
return &GetDeclaringClass()->GetDirectMethodsSlice(kRuntimePointerSize)[GetMethodIndex()];
} else {
return GetDeclaringClass()->GetVTableEntry(GetMethodIndex(), kRuntimePointerSize);
@@ -504,10 +505,10 @@ static const OatFile::OatMethod FindOatMethodFor(ArtMethod* method,
<< method->PrettyMethod();
}
DCHECK_EQ(oat_method_index,
- GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(),
+ GetOatMethodIndexFromMethodIndex(declaring_class->GetDexFile(),
method->GetDeclaringClass()->GetDexClassDefIndex(),
method->GetDexMethodIndex()));
- OatFile::OatClass oat_class = OatFile::FindOatClass(*declaring_class->GetDexCache()->GetDexFile(),
+ OatFile::OatClass oat_class = OatFile::FindOatClass(declaring_class->GetDexFile(),
declaring_class->GetDexClassDefIndex(),
found);
if (!(*found)) {
@@ -543,7 +544,7 @@ bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> param
}
ArrayRef<const uint8_t> ArtMethod::GetQuickenedInfo() {
- const DexFile& dex_file = GetDeclaringClass()->GetDexFile();
+ const DexFile& dex_file = *GetDexFile();
const OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) {
return ArrayRef<const uint8_t>();
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 991faa27d3..9b2e1a10e4 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -9116,8 +9116,8 @@ ObjPtr<mirror::ClassLoader> ClassLinker::CreateWellKnownClassLoader(
Thread* self,
const std::vector<const DexFile*>& dex_files,
Handle<mirror::Class> loader_class,
- Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries,
- Handle<mirror::ClassLoader> parent_loader) {
+ Handle<mirror::ClassLoader> parent_loader,
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries) {
StackHandleScope<5> hs(self);
@@ -9246,7 +9246,8 @@ ObjPtr<mirror::ClassLoader> ClassLinker::CreateWellKnownClassLoader(
jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
const std::vector<const DexFile*>& dex_files,
jclass loader_class,
- jobject parent_loader) {
+ jobject parent_loader,
+ jobject shared_libraries) {
CHECK(self->GetJniEnv()->IsSameObject(loader_class,
WellKnownClasses::dalvik_system_PathClassLoader) ||
self->GetJniEnv()->IsSameObject(loader_class,
@@ -9257,24 +9258,21 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
ScopedObjectAccessUnchecked soa(self);
// For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
- StackHandleScope<3> hs(self);
+ StackHandleScope<4> hs(self);
Handle<mirror::Class> h_loader_class =
hs.NewHandle<mirror::Class>(soa.Decode<mirror::Class>(loader_class));
- Handle<mirror::ClassLoader> parent =
- hs.NewHandle<mirror::ClassLoader>(ObjPtr<mirror::ClassLoader>::DownCast(
- (parent_loader != nullptr)
- ? soa.Decode<mirror::ClassLoader>(parent_loader)
- : nullptr));
- Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries =
- hs.NewHandle<mirror::ObjectArray<mirror::ClassLoader>>(nullptr);
+ Handle<mirror::ClassLoader> h_parent =
+ hs.NewHandle<mirror::ClassLoader>(soa.Decode<mirror::ClassLoader>(parent_loader));
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> h_shared_libraries =
+ hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::ClassLoader>>(shared_libraries));
ObjPtr<mirror::ClassLoader> loader = CreateWellKnownClassLoader(
self,
dex_files,
h_loader_class,
- shared_libraries,
- parent);
+ h_parent,
+ h_shared_libraries);
// Make it a global ref and return.
ScopedLocalRef<jobject> local_ref(
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 15a7204dd2..dd5f911330 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -574,7 +574,8 @@ class ClassLinker {
jobject CreateWellKnownClassLoader(Thread* self,
const std::vector<const DexFile*>& dex_files,
jclass loader_class,
- jobject parent_loader)
+ jobject parent_loader,
+ jobject shared_libraries = nullptr)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
@@ -591,8 +592,8 @@ class ClassLinker {
Thread* self,
const std::vector<const DexFile*>& dex_files,
Handle<mirror::Class> loader_class,
- Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries,
- Handle<mirror::ClassLoader> parent_loader)
+ Handle<mirror::ClassLoader> parent_loader,
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 029db7e5c7..c5988f6ce0 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -695,8 +695,8 @@ static ObjPtr<mirror::ClassLoader> CreateClassLoaderInternal(
self,
class_path_files,
loader_class,
- libraries,
- parent);
+ parent,
+ libraries);
if (for_shared_library) {
canonicalized_libraries[FlattenClasspath(info.classpath)] =
map_scope.NewHandle<mirror::ClassLoader>(loader);
@@ -914,10 +914,12 @@ static bool GetDexFilesFromDexElementsArray(
// the classpath.
// This method is recursive (w.r.t. the class loader parent) and will stop once it reaches the
// BootClassLoader. Note that the class loader chain is expected to be short.
-bool ClassLoaderContext::AddInfoToContextFromClassLoader(
+bool ClassLoaderContext::CreateInfoFromClassLoader(
ScopedObjectAccessAlreadyRunnable& soa,
Handle<mirror::ClassLoader> class_loader,
- Handle<mirror::ObjectArray<mirror::Object>> dex_elements)
+ Handle<mirror::ObjectArray<mirror::Object>> dex_elements,
+ ClassLoaderInfo* child_info,
+ bool is_shared_library)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (ClassLinker::IsBootClassLoader(soa, class_loader.Get())) {
// Nothing to do for the boot class loader as we don't add its dex files to the context.
@@ -952,31 +954,52 @@ bool ClassLoaderContext::AddInfoToContextFromClassLoader(
}
ClassLoaderInfo* info = new ClassLoaderContext::ClassLoaderInfo(type);
- if (class_loader_chain_ == nullptr) {
+ // Attach the `ClassLoaderInfo` now, before populating dex files, as only the
+ // `ClassLoaderContext` knows whether these dex files should be deleted or not.
+ if (child_info == nullptr) {
class_loader_chain_.reset(info);
+ } else if (is_shared_library) {
+ child_info->shared_libraries.push_back(std::unique_ptr<ClassLoaderInfo>(info));
} else {
- ClassLoaderInfo* child = class_loader_chain_.get();
- while (child->parent != nullptr) {
- child = child->parent.get();
- }
- child->parent.reset(info);
+ child_info->parent.reset(info);
}
+ // Now that `info` is in the chain, populate dex files.
for (const DexFile* dex_file : dex_files_loaded) {
info->classpath.push_back(dex_file->GetLocation());
info->checksums.push_back(dex_file->GetLocationChecksum());
info->opened_dex_files.emplace_back(dex_file);
}
- // We created the ClassLoaderInfo for the current loader. Move on to its parent.
-
- StackHandleScope<1> hs(Thread::Current());
- Handle<mirror::ClassLoader> parent = hs.NewHandle(class_loader->GetParent());
-
// Note that dex_elements array is null here. The elements are considered to be part of the
// current class loader and are not passed to the parents.
ScopedNullHandle<mirror::ObjectArray<mirror::Object>> null_dex_elements;
- return AddInfoToContextFromClassLoader(soa, parent, null_dex_elements);
+
+ // Add the shared libraries.
+ StackHandleScope<3> hs(Thread::Current());
+ ArtField* field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader.Get());
+ if (raw_shared_libraries != nullptr) {
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries =
+ hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>());
+ MutableHandle<mirror::ClassLoader> temp_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
+ for (int32_t i = 0; i < shared_libraries->GetLength(); ++i) {
+ temp_loader.Assign(shared_libraries->Get(i));
+ if (!CreateInfoFromClassLoader(
+ soa, temp_loader, null_dex_elements, info, /*is_shared_library=*/ true)) {
+ return false;
+ }
+ }
+ }
+
+ // We created the ClassLoaderInfo for the current loader. Move on to its parent.
+ Handle<mirror::ClassLoader> parent = hs.NewHandle(class_loader->GetParent());
+ if (!CreateInfoFromClassLoader(
+ soa, parent, null_dex_elements, info, /*is_shared_library=*/ false)) {
+ return false;
+ }
+ return true;
}
std::unique_ptr<ClassLoaderContext> ClassLoaderContext::CreateContextForClassLoader(
@@ -990,13 +1013,12 @@ std::unique_ptr<ClassLoaderContext> ClassLoaderContext::CreateContextForClassLoa
hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader));
Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements));
-
std::unique_ptr<ClassLoaderContext> result(new ClassLoaderContext(/*owns_the_dex_files=*/ false));
- if (result->AddInfoToContextFromClassLoader(soa, h_class_loader, h_dex_elements)) {
- return result;
- } else {
+ if (!result->CreateInfoFromClassLoader(
+ soa, h_class_loader, h_dex_elements, nullptr, /*is_shared_library=*/ false)) {
return nullptr;
}
+ return result;
}
static bool IsAbsoluteLocation(const std::string& location) {
@@ -1130,8 +1152,8 @@ bool ClassLoaderContext::ClassLoaderInfoMatch(
if (info.shared_libraries.size() != expected_info.shared_libraries.size()) {
LOG(WARNING) << "ClassLoaderContext shared library size mismatch. "
- << "Expected=" << expected_info.classpath.size()
- << ", found=" << info.classpath.size()
+ << "Expected=" << expected_info.shared_libraries.size()
+ << ", found=" << info.shared_libraries.size()
<< " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
return false;
}
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 71f40ac167..5a89c4e95f 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -227,12 +227,14 @@ class ClassLoaderContext {
// of the call.
void CheckDexFilesOpened(const std::string& calling_method) const;
- // Adds the `class_loader` info to the context.
+ // Creates the `ClassLoaderInfo` representing`class_loader` and attach it to `this`.
// The dex file present in `dex_elements` array (if not null) will be added at the end of
// the classpath.
- bool AddInfoToContextFromClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
- Handle<mirror::ClassLoader> class_loader,
- Handle<mirror::ObjectArray<mirror::Object>> dex_elements)
+ bool CreateInfoFromClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
+ Handle<mirror::ClassLoader> class_loader,
+ Handle<mirror::ObjectArray<mirror::Object>> dex_elements,
+ ClassLoaderInfo* child_info,
+ bool is_shared_library)
REQUIRES_SHARED(Locks::mutator_lock_);
// Encodes the context as a string suitable to be passed to dex2oat or to be added to the
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 0756982b65..3c5f1ef95d 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -23,6 +23,7 @@
#include "base/dchecked_vector.h"
#include "base/stl_util.h"
#include "class_linker.h"
+#include "class_root.h"
#include "common_runtime_test.h"
#include "dex/dex_file.h"
#include "handle_scope-inl.h"
@@ -30,6 +31,7 @@
#include "mirror/class.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
+#include "mirror/object_array-alloc-inl.h"
#include "oat_file_assistant.h"
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
@@ -1230,4 +1232,30 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncodingMultide
ClassLoaderContext::VerificationResult::kVerifies);
}
+TEST_F(ClassLoaderContextTest, CreateContextForClassLoaderWithSharedLibraries) {
+ jobject class_loader_a = LoadDexInPathClassLoader("ForClassLoaderA", nullptr);
+
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> libraries = hs.NewHandle(
+ mirror::ObjectArray<mirror::ClassLoader>::Alloc(
+ soa.Self(),
+ GetClassRoot<mirror::ObjectArray<mirror::ClassLoader>>(),
+ 1));
+ libraries->Set(0, soa.Decode<mirror::ClassLoader>(class_loader_a));
+
+ jobject class_loader_b = LoadDexInPathClassLoader(
+ "ForClassLoaderB", nullptr, soa.AddLocalReference<jobject>(libraries.Get()));
+
+ std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader_b);
+ ASSERT_TRUE(context != nullptr);
+ std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("ForClassLoaderB");
+ VerifyClassLoaderPCL(context.get(), 0, dex_files[0]->GetLocation());
+ dex_files = OpenTestDexFiles("ForClassLoaderA");
+ VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 0, dex_files[0]->GetLocation());
+
+ ASSERT_EQ(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")),
+ ClassLoaderContext::VerificationResult::kVerifies);
+}
+
} // namespace art
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index fcf6bb25e3..0300fa155f 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -139,7 +139,7 @@ void CommonRuntimeTestImpl::SetUp() {
PreRuntimeCreate();
if (!Runtime::Create(options, false)) {
LOG(FATAL) << "Failed to create runtime";
- return;
+ UNREACHABLE();
}
PostRuntimeCreate();
runtime_.reset(Runtime::Current());
@@ -273,7 +273,8 @@ jobject CommonRuntimeTestImpl::LoadDex(const char* dex_name) {
jobject CommonRuntimeTestImpl::LoadDexInWellKnownClassLoader(const std::string& dex_name,
jclass loader_class,
- jobject parent_loader) {
+ jobject parent_loader,
+ jobject shared_libraries) {
std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles(dex_name.c_str());
std::vector<const DexFile*> class_path;
CHECK_NE(0U, dex_files.size());
@@ -288,7 +289,8 @@ jobject CommonRuntimeTestImpl::LoadDexInWellKnownClassLoader(const std::string&
self,
class_path,
loader_class,
- parent_loader);
+ parent_loader,
+ shared_libraries);
{
// Verify we build the correct chain.
@@ -315,10 +317,12 @@ jobject CommonRuntimeTestImpl::LoadDexInWellKnownClassLoader(const std::string&
}
jobject CommonRuntimeTestImpl::LoadDexInPathClassLoader(const std::string& dex_name,
- jobject parent_loader) {
+ jobject parent_loader,
+ jobject shared_libraries) {
return LoadDexInWellKnownClassLoader(dex_name,
WellKnownClasses::dalvik_system_PathClassLoader,
- parent_loader);
+ parent_loader,
+ shared_libraries);
}
jobject CommonRuntimeTestImpl::LoadDexInDelegateLastClassLoader(const std::string& dex_name,
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index c48ab3629c..0fee797015 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -115,11 +115,14 @@ class CommonRuntimeTestImpl : public CommonArtTestImpl {
jobject LoadMultiDex(const char* first_dex_name, const char* second_dex_name)
REQUIRES_SHARED(Locks::mutator_lock_);
- jobject LoadDexInPathClassLoader(const std::string& dex_name, jobject parent_loader);
+ jobject LoadDexInPathClassLoader(const std::string& dex_name,
+ jobject parent_loader,
+ jobject shared_libraries = nullptr);
jobject LoadDexInDelegateLastClassLoader(const std::string& dex_name, jobject parent_loader);
jobject LoadDexInWellKnownClassLoader(const std::string& dex_name,
jclass loader_class,
- jobject parent_loader);
+ jobject parent_loader,
+ jobject shared_libraries = nullptr);
std::unique_ptr<Runtime> runtime_;
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 0dc07231b6..62788b14ea 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -717,7 +717,7 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) {
<< instr.DumpString(dex_file)
<< " in "
<< method->PrettyMethod();
- break;
+ UNREACHABLE();
}
}
}
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 4af97f0f35..80140b3aa1 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1228,7 +1228,7 @@ size_t Dbg::GetTagWidth(JDWP::JdwpTag tag) {
return 8;
default:
LOG(FATAL) << "Unknown tag " << tag;
- return -1;
+ UNREACHABLE();
}
}
@@ -2266,7 +2266,7 @@ JDWP::JdwpThreadStatus Dbg::ToJdwpThreadStatus(ThreadState state) {
// Don't add a 'default' here so the compiler can spot incompatible enum changes.
}
LOG(FATAL) << "Unknown thread state: " << state;
- return JDWP::TS_ZOMBIE;
+ UNREACHABLE();
}
JDWP::JdwpError Dbg::GetThreadStatus(JDWP::ObjectId thread_id, JDWP::JdwpThreadStatus* pThreadStatus,
@@ -3155,7 +3155,7 @@ void Dbg::ProcessDeoptimizationRequest(const DeoptimizationRequest& request) {
break;
default:
LOG(FATAL) << "Unsupported deoptimization request kind " << request.GetKind();
- break;
+ UNREACHABLE();
}
}
@@ -3233,7 +3233,7 @@ void Dbg::RequestDeoptimizationLocked(const DeoptimizationRequest& req) {
}
default: {
LOG(FATAL) << "Unknown deoptimization request kind " << req.GetKind();
- break;
+ UNREACHABLE();
}
}
}
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index 6434828298..9127a27bc8 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -240,7 +240,7 @@ bool SkipAnnotationValue(const DexFile& dex_file, const uint8_t** annotation_ptr
break;
default:
LOG(FATAL) << StringPrintf("Bad annotation element value byte 0x%02x", value_type);
- return false;
+ UNREACHABLE();
}
annotation += width;
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 3c41a8c3b5..5c86bbb39e 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -252,7 +252,7 @@ extern uint64_t GenericJniMethodEnd(Thread* self,
return 0;
default:
LOG(FATAL) << "Unexpected return shorty character " << return_shorty_char;
- return 0;
+ UNREACHABLE();
}
}
}
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 8737f3fc28..6deb509427 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -297,7 +297,7 @@ class QuickArgumentVisitor {
case 4: return (6 * GetBytesPerGprSpillLocation(kRuntimeISA));
default:
LOG(FATAL) << "Unexpected GPR index: " << gpr_index;
- return 0;
+ UNREACHABLE();
}
}
#else
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index b90a95d802..d4b9fabd0f 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -286,7 +286,7 @@ void* RosAlloc::AllocPages(Thread* self, size_t num_pages, uint8_t page_map_type
break;
default:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_type);
- break;
+ UNREACHABLE();
}
if (kIsDebugBuild) {
// Clear the first page since it is not madvised due to the magic number.
@@ -325,7 +325,7 @@ size_t RosAlloc::FreePages(Thread* self, void* ptr, bool already_zero) {
LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << " : " << "pm_idx=" << pm_idx << ", pm_type="
<< static_cast<int>(pm_type) << ", ptr=" << std::hex
<< reinterpret_cast<intptr_t>(ptr);
- return 0;
+ UNREACHABLE();
}
// Update the page map and count the number of pages.
size_t num_pages = 1;
@@ -514,7 +514,7 @@ size_t RosAlloc::FreeInternal(Thread* self, void* ptr) {
return FreePages(self, ptr, false);
case kPageMapLargeObjectPart:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
- return 0;
+ UNREACHABLE();
case kPageMapRunPart: {
// Find the beginning of the run.
do {
@@ -529,11 +529,11 @@ size_t RosAlloc::FreeInternal(Thread* self, void* ptr) {
case kPageMapReleased:
case kPageMapEmpty:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
- return 0;
+ UNREACHABLE();
}
default:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
- return 0;
+ UNREACHABLE();
}
}
DCHECK(run != nullptr);
@@ -1307,7 +1307,7 @@ size_t RosAlloc::UsableSize(const void* ptr) {
case kPageMapEmpty:
LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << ": pm_idx=" << pm_idx << ", ptr="
<< std::hex << reinterpret_cast<intptr_t>(ptr);
- break;
+ UNREACHABLE();
case kPageMapLargeObject: {
size_t num_pages = 1;
size_t idx = pm_idx + 1;
@@ -1321,7 +1321,7 @@ size_t RosAlloc::UsableSize(const void* ptr) {
case kPageMapLargeObjectPart:
LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << ": pm_idx=" << pm_idx << ", ptr="
<< std::hex << reinterpret_cast<intptr_t>(ptr);
- break;
+ UNREACHABLE();
case kPageMapRun:
case kPageMapRunPart: {
// Find the beginning of the run.
@@ -1340,10 +1340,9 @@ size_t RosAlloc::UsableSize(const void* ptr) {
}
default: {
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]);
- break;
+ UNREACHABLE();
}
}
- return 0;
}
bool RosAlloc::Trim() {
@@ -1456,7 +1455,7 @@ void RosAlloc::InspectAll(void (*handler)(void* start, void* end, size_t used_by
}
case kPageMapLargeObjectPart:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
- break;
+ UNREACHABLE();
case kPageMapRun: {
// The start of a run.
Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize);
@@ -1476,10 +1475,10 @@ void RosAlloc::InspectAll(void (*handler)(void* start, void* end, size_t used_by
}
case kPageMapRunPart:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
- break;
+ UNREACHABLE();
default:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
- break;
+ UNREACHABLE();
}
}
}
@@ -1809,7 +1808,7 @@ void RosAlloc::Verify() {
}
case kPageMapLargeObjectPart:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap();
- break;
+ UNREACHABLE();
case kPageMapRun: {
// The start of a run.
Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize);
@@ -1837,7 +1836,7 @@ void RosAlloc::Verify() {
// Fall-through.
default:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap();
- break;
+ UNREACHABLE();
}
}
}
@@ -2030,7 +2029,7 @@ size_t RosAlloc::ReleasePages() {
break; // Skip.
default:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm);
- break;
+ UNREACHABLE();
}
}
return reclaimed_bytes;
@@ -2138,7 +2137,7 @@ void RosAlloc::DumpStats(std::ostream& os) {
case kPageMapLargeObjectPart:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl
<< DumpPageMap();
- break;
+ UNREACHABLE();
case kPageMapRun: {
Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize);
size_t idx = run->size_bracket_idx_;
@@ -2157,7 +2156,7 @@ void RosAlloc::DumpStats(std::ostream& os) {
default:
LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl
<< DumpPageMap();
- break;
+ UNREACHABLE();
}
}
os << "RosAlloc stats:\n";
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 0294db7b7e..8477c9de2c 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -234,12 +234,15 @@ void GarbageCollector::DumpPerformanceInfo(std::ostream& os) {
pause_histogram_.PrintConfidenceIntervals(os, 0.99, cumulative_data);
}
}
+ double cpu_seconds = NsToMs(GetTotalCpuTime()) / 1000.0;
os << GetName() << " total time: " << PrettyDuration(total_ns)
<< " mean time: " << PrettyDuration(total_ns / iterations) << "\n"
<< GetName() << " freed: " << freed_objects
<< " objects with total size " << PrettySize(freed_bytes) << "\n"
<< GetName() << " throughput: " << freed_objects / seconds << "/s / "
- << PrettySize(freed_bytes / seconds) << "/s\n";
+ << PrettySize(freed_bytes / seconds) << "/s"
+ << " per cpu-time: "
+ << PrettySize(freed_bytes / cpu_seconds) << "/s\n";
}
} // namespace collector
diff --git a/runtime/gc/collector/immune_spaces_test.cc b/runtime/gc/collector/immune_spaces_test.cc
index 9f98f6c7f0..c29b79c0d4 100644
--- a/runtime/gc/collector/immune_spaces_test.cc
+++ b/runtime/gc/collector/immune_spaces_test.cc
@@ -124,9 +124,7 @@ class ImmuneSpacesTest : public CommonRuntimeTest {
/*oat_file_end=*/ PointerToLowMemUInt32(oat_map.Begin() + oat_size),
/*boot_image_begin=*/ 0u,
/*boot_image_size=*/ 0u,
- /*pointer_size=*/ sizeof(void*),
- ImageHeader::kStorageModeUncompressed,
- /*data_size=*/ 0u);
+ /*pointer_size=*/ sizeof(void*));
return new DummyImageSpace(std::move(image_map),
std::move(live_bitmap),
std::move(oat_file),
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 4359bea421..f767360066 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2169,7 +2169,7 @@ void Heap::TransitionCollector(CollectorType collector_type) {
default: {
LOG(FATAL) << "Attempted to transition to invalid collector type "
<< static_cast<size_t>(collector_type);
- break;
+ UNREACHABLE();
}
}
ChangeCollector(collector_type);
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index bfb37463e5..c772bdab18 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -16,7 +16,6 @@
#include "image_space.h"
-#include <lz4.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <unistd.h>
@@ -466,9 +465,10 @@ class ImageSpace::Loader {
// Check that the file is larger or equal to the header size + data size.
const uint64_t image_file_size = static_cast<uint64_t>(file->GetLength());
if (image_file_size < sizeof(ImageHeader) + image_header->GetDataSize()) {
- *error_msg = StringPrintf("Image file truncated: %" PRIu64 " vs. %" PRIu64 ".",
- image_file_size,
- sizeof(ImageHeader) + image_header->GetDataSize());
+ *error_msg = StringPrintf(
+ "Image file truncated: %" PRIu64 " vs. %" PRIu64 ".",
+ image_file_size,
+ static_cast<uint64_t>(sizeof(ImageHeader) + image_header->GetDataSize()));
return nullptr;
}
@@ -588,8 +588,9 @@ class ImageSpace::Loader {
/*inout*/MemMap* image_reservation,
/*out*/std::string* error_msg) {
TimingLogger::ScopedTiming timing("MapImageFile", logger);
- const ImageHeader::StorageMode storage_mode = image_header.GetStorageMode();
- if (storage_mode == ImageHeader::kStorageModeUncompressed) {
+ std::string temp_error_msg;
+ const bool is_compressed = image_header.HasCompressedBlock();
+ if (!is_compressed) {
uint8_t* address = (image_reservation != nullptr) ? image_reservation->Begin() : nullptr;
return MemMap::MapFileAtAddress(address,
image_header.GetImageSize(),
@@ -604,15 +605,6 @@ class ImageSpace::Loader {
error_msg);
}
- if (storage_mode != ImageHeader::kStorageModeLZ4 &&
- storage_mode != ImageHeader::kStorageModeLZ4HC) {
- if (error_msg != nullptr) {
- *error_msg = StringPrintf("Invalid storage mode in image header %d",
- static_cast<int>(storage_mode));
- }
- return MemMap::Invalid();
- }
-
// Reserve output and decompress into it.
MemMap map = MemMap::MapAnonymous(image_location,
image_header.GetImageSize(),
@@ -622,7 +614,6 @@ class ImageSpace::Loader {
error_msg);
if (map.IsValid()) {
const size_t stored_size = image_header.GetDataSize();
- const size_t decompress_offset = sizeof(ImageHeader); // Skip the header.
MemMap temp_map = MemMap::MapFile(sizeof(ImageHeader) + stored_size,
PROT_READ,
MAP_PRIVATE,
@@ -637,27 +628,20 @@ class ImageSpace::Loader {
}
memcpy(map.Begin(), &image_header, sizeof(ImageHeader));
const uint64_t start = NanoTime();
- // LZ4HC and LZ4 have same internal format, both use LZ4_decompress.
- TimingLogger::ScopedTiming timing2("LZ4 decompress image", logger);
- const size_t decompressed_size = LZ4_decompress_safe(
- reinterpret_cast<char*>(temp_map.Begin()) + sizeof(ImageHeader),
- reinterpret_cast<char*>(map.Begin()) + decompress_offset,
- stored_size,
- map.Size() - decompress_offset);
+ for (const ImageHeader::Block& block : image_header.GetBlocks(temp_map.Begin())) {
+ TimingLogger::ScopedTiming timing2("LZ4 decompress image", logger);
+ if (!block.Decompress(/*out_ptr=*/map.Begin(), /*in_ptr=*/temp_map.Begin(), error_msg)) {
+ if (error_msg != nullptr) {
+ *error_msg = "Failed to decompress image block " + *error_msg;
+ }
+ return MemMap::Invalid();
+ }
+ }
const uint64_t time = NanoTime() - start;
// Add one 1 ns to prevent possible divide by 0.
VLOG(image) << "Decompressing image took " << PrettyDuration(time) << " ("
<< PrettySize(static_cast<uint64_t>(map.Size()) * MsToNs(1000) / (time + 1))
<< "/s)";
- if (decompressed_size + sizeof(ImageHeader) != image_header.GetImageSize()) {
- if (error_msg != nullptr) {
- *error_msg = StringPrintf(
- "Decompressed size does not match expected image size %zu vs %zu",
- decompressed_size + sizeof(ImageHeader),
- image_header.GetImageSize());
- }
- return MemMap::Invalid();
- }
}
return map;
@@ -766,6 +750,7 @@ class ImageSpace::Loader {
ALWAYS_INLINE void operator()(ObjPtr<mirror::Object> obj,
MemberOffset offset,
+
bool is_static ATTRIBUTE_UNUSED) const
NO_THREAD_SAFETY_ANALYSIS {
// There could be overlap between ranges, we must avoid visiting the same reference twice.
@@ -2337,9 +2322,9 @@ void ImageSpace::Dump(std::ostream& os) const {
}
std::string ImageSpace::GetMultiImageBootClassPath(
- const std::vector<const char*>& dex_locations,
- const std::vector<const char*>& oat_filenames,
- const std::vector<const char*>& image_filenames) {
+ const std::vector<std::string>& dex_locations,
+ const std::vector<std::string>& oat_filenames,
+ const std::vector<std::string>& image_filenames) {
DCHECK_GT(oat_filenames.size(), 1u);
// If the image filename was adapted (e.g., for our tests), we need to change this here,
// too, but need to strip all path components (they will be re-established when loading).
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index b940d88de8..aa45ed3952 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -128,9 +128,9 @@ class ImageSpace : public MemMapSpace {
const std::string& boot_classpath,
std::vector<std::string>* image_filenames);
- static std::string GetMultiImageBootClassPath(const std::vector<const char*>& dex_locations,
- const std::vector<const char*>& oat_filenames,
- const std::vector<const char*>& image_filenames);
+ static std::string GetMultiImageBootClassPath(const std::vector<std::string>& dex_locations,
+ const std::vector<std::string>& oat_filenames,
+ const std::vector<std::string>& image_filenames);
// Returns true if the dex checksums in the given oat file match the
// checksums of the original dex files on disk. This is intended to be used
diff --git a/runtime/gc/space/space.cc b/runtime/gc/space/space.cc
index a8bd7b816e..e7961eb256 100644
--- a/runtime/gc/space/space.cc
+++ b/runtime/gc/space/space.cc
@@ -63,7 +63,7 @@ BumpPointerSpace* Space::AsBumpPointerSpace() {
RegionSpace* Space::AsRegionSpace() {
LOG(FATAL) << "Unreachable";
- return nullptr;
+ UNREACHABLE();
}
AllocSpace* Space::AsAllocSpace() {
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index d3df7fd38d..6cdba73c30 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -280,11 +280,15 @@ uint32_t GetDexFlags(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
uint32_t flags = kInvalidDexFlags;
DCHECK(!AreValidDexFlags(flags));
+ // Use the non-obsolete method to avoid DexFile mismatch between
+ // the method index and the declaring class.
+ uint32_t method_index = method->GetNonObsoleteMethod()->GetDexMethodIndex();
+
ClassAccessor accessor(declaring_class->GetDexFile(),
*class_def,
/* parse_hiddenapi_class_data= */ true);
auto fn_visit = [&](const ClassAccessor::Method& dex_method) {
- if (dex_method.GetIndex() == method->GetDexMethodIndex()) {
+ if (dex_method.GetIndex() == method_index) {
flags = dex_method.GetHiddenapiFlags();
}
};
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index 832bacbb3d..3abe4c529a 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -1051,7 +1051,7 @@ void Hprof::MarkRootObject(const mirror::Object* obj, jobject jni_obj, HprofHeap
case HPROF_ROOT_REFERENCE_CLEANUP:
case HPROF_UNREACHABLE:
LOG(FATAL) << "obsolete tag " << static_cast<int>(heap_tag);
- break;
+ UNREACHABLE();
}
++objects_in_segment_;
diff --git a/runtime/image.cc b/runtime/image.cc
index f50c39c3d5..ae3d8e34e6 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -16,6 +16,9 @@
#include "image.h"
+#include <lz4.h>
+#include <sstream>
+
#include "base/bit_utils.h"
#include "base/length_prefixed_array.h"
#include "base/utils.h"
@@ -26,7 +29,7 @@
namespace art {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '7', '0', '\0' }; // Store ImtIndex.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '7', '1', '\0' }; // Add image blocks.
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
@@ -39,9 +42,7 @@ ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t oat_file_end,
uint32_t boot_image_begin,
uint32_t boot_image_size,
- uint32_t pointer_size,
- StorageMode storage_mode,
- size_t data_size)
+ uint32_t pointer_size)
: image_begin_(image_begin),
image_size_(image_size),
image_checksum_(0u),
@@ -53,9 +54,7 @@ ImageHeader::ImageHeader(uint32_t image_begin,
boot_image_begin_(boot_image_begin),
boot_image_size_(boot_image_size),
image_roots_(image_roots),
- pointer_size_(pointer_size),
- storage_mode_(storage_mode),
- data_size_(data_size) {
+ pointer_size_(pointer_size) {
CHECK_EQ(image_begin, RoundUp(image_begin, kPageSize));
CHECK_EQ(oat_file_begin, RoundUp(oat_file_begin, kPageSize));
CHECK_EQ(oat_data_begin, RoundUp(oat_data_begin, kPageSize));
@@ -144,4 +143,34 @@ PointerSize ImageHeader::GetPointerSize() const {
return ConvertToPointerSize(pointer_size_);
}
+bool ImageHeader::Block::Decompress(uint8_t* out_ptr,
+ const uint8_t* in_ptr,
+ std::string* error_msg) const {
+ switch (storage_mode_) {
+ case kStorageModeUncompressed: {
+ CHECK_EQ(image_size_, data_size_);
+ memcpy(out_ptr + image_offset_, in_ptr + data_offset_, data_size_);
+ break;
+ }
+ case kStorageModeLZ4:
+ case kStorageModeLZ4HC: {
+ // LZ4HC and LZ4 have same internal format, both use LZ4_decompress.
+ const size_t decompressed_size = LZ4_decompress_safe(
+ reinterpret_cast<const char*>(in_ptr) + data_offset_,
+ reinterpret_cast<char*>(out_ptr) + image_offset_,
+ data_size_,
+ image_size_);
+ CHECK_EQ(decompressed_size, image_size_);
+ break;
+ }
+ default: {
+ if (error_msg != nullptr) {
+ *error_msg = (std::ostringstream() << "Invalid image format " << storage_mode_).str();
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace art
diff --git a/runtime/image.h b/runtime/image.h
index f33b9b2a2e..76fb3b70c9 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -21,6 +21,7 @@
#include "base/enums.h"
#include "base/globals.h"
+#include "base/iteration_range.h"
#include "mirror/object.h"
namespace art {
@@ -82,8 +83,10 @@ class PACKED(4) ImageSection {
uint32_t size_;
};
-// header of image files written by ImageWriter, read and validated by Space.
-class PACKED(4) ImageHeader {
+// Header of image files written by ImageWriter, read and validated by Space.
+// Packed to object alignment since the first object follows directly after the header.
+static_assert(kObjectAlignment == 8, "Alignment check");
+class PACKED(8) ImageHeader {
public:
enum StorageMode : uint32_t {
kStorageModeUncompressed,
@@ -93,8 +96,40 @@ class PACKED(4) ImageHeader {
};
static constexpr StorageMode kDefaultStorageMode = kStorageModeUncompressed;
- ImageHeader() {}
+ // Solid block of the image. May be compressed or uncompressed.
+ class PACKED(4) Block final {
+ public:
+ Block(StorageMode storage_mode,
+ uint32_t data_offset,
+ uint32_t data_size,
+ uint32_t image_offset,
+ uint32_t image_size)
+ : storage_mode_(storage_mode),
+ data_offset_(data_offset),
+ data_size_(data_size),
+ image_offset_(image_offset),
+ image_size_(image_size) {}
+
+ bool Decompress(uint8_t* out_ptr, const uint8_t* in_ptr, std::string* error_msg) const;
+
+ StorageMode GetStorageMode() const {
+ return storage_mode_;
+ }
+
+ private:
+ // Storage method for the image, the image may be compressed.
+ StorageMode storage_mode_ = kDefaultStorageMode;
+
+ // Compressed offset and size.
+ uint32_t data_offset_ = 0u;
+ uint32_t data_size_ = 0u;
+
+ // Image offset and size (decompressed or mapped location).
+ uint32_t image_offset_ = 0u;
+ uint32_t image_size_ = 0u;
+ };
+ ImageHeader() {}
ImageHeader(uint32_t image_begin,
uint32_t image_size,
ImageSection* sections,
@@ -106,9 +141,7 @@ class PACKED(4) ImageHeader {
uint32_t oat_file_end,
uint32_t boot_image_begin,
uint32_t boot_image_size,
- uint32_t pointer_size,
- StorageMode storage_mode,
- size_t data_size);
+ uint32_t pointer_size);
bool IsValid() const;
const char* GetMagic() const;
@@ -231,6 +264,11 @@ class PACKED(4) ImageHeader {
ArtMethod* GetImageMethod(ImageMethod index) const;
+ ImageSection& GetImageSection(ImageSections index) {
+ DCHECK_LT(static_cast<size_t>(index), kSectionCount);
+ return sections_[index];
+ }
+
const ImageSection& GetImageSection(ImageSections index) const {
DCHECK_LT(static_cast<size_t>(index), kSectionCount);
return sections_[index];
@@ -304,10 +342,6 @@ class PACKED(4) ImageHeader {
return boot_image_size_;
}
- StorageMode GetStorageMode() const {
- return storage_mode_;
- }
-
uint64_t GetDataSize() const {
return data_size_;
}
@@ -345,6 +379,24 @@ class PACKED(4) ImageHeader {
uint8_t* base,
PointerSize pointer_size) const;
+ IterationRange<const Block*> GetBlocks() const {
+ return GetBlocks(GetImageBegin());
+ }
+
+ IterationRange<const Block*> GetBlocks(const uint8_t* image_begin) const {
+ const Block* begin = reinterpret_cast<const Block*>(image_begin + blocks_offset_);
+ return {begin, begin + blocks_count_};
+ }
+
+ // Return true if the image has any compressed blocks.
+ bool HasCompressedBlock() const {
+ return blocks_count_ != 0u;
+ }
+
+ uint32_t GetBlockCount() const {
+ return blocks_count_;
+ }
+
private:
static const uint8_t kImageMagic[4];
static const uint8_t kImageVersion[4];
@@ -404,13 +456,14 @@ class PACKED(4) ImageHeader {
// Image methods, may be inside of the boot image for app images.
uint64_t image_methods_[kImageMethodsCount];
- // Storage method for the image, the image may be compressed.
- StorageMode storage_mode_ = kDefaultStorageMode;
-
// Data size for the image data excluding the bitmap and the header. For compressed images, this
// is the compressed size in the file.
uint32_t data_size_ = 0u;
+ // Image blocks, only used for compressed images.
+ uint32_t blocks_offset_ = 0u;
+ uint32_t blocks_count_ = 0u;
+
friend class linker::ImageWriter;
};
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index fe6154792c..e52a1c90d3 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -1876,7 +1876,7 @@ void RecordArrayElementsInTransaction(ObjPtr<mirror::Array> array, int32_t count
default:
LOG(FATAL) << "Unsupported primitive type " << primitive_component_type
<< " in fill-array-data";
- break;
+ UNREACHABLE();
}
}
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 1c724212f5..bf84227560 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -44,7 +44,7 @@
#include "handle_scope-inl.h"
#include "interpreter_mterp_impl.h"
#include "interpreter_switch_impl.h"
-#include "jit/jit-inl.h"
+#include "jit/jit.h"
#include "mirror/call_site.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache.h"
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index aec2aa2564..94cb3de9f8 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -26,7 +26,7 @@
#include "dex/dex_instruction_list.h"
#include "experimental_flags.h"
#include "interpreter_common.h"
-#include "jit/jit-inl.h"
+#include "jit/jit.h"
#include "jvalue-inl.h"
#include "mirror/string-alloc-inl.h"
#include "nth_caller_visitor.h"
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 0633f5bb21..912c44463f 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -887,11 +887,9 @@ extern "C" ssize_t MterpSetUpHotnessCountdown(ArtMethod* method,
int32_t countdown_value = jit::kJitHotnessDisabled;
jit::Jit* jit = Runtime::Current()->GetJit();
if (jit != nullptr) {
- // We need to add batch size to ensure the threshold gets passed even after rounding.
- constexpr int32_t kBatchSize = jit::kJitSamplesBatchSize;
- int32_t warm_threshold = static_cast<int32_t>(jit->WarmMethodThreshold()) + kBatchSize;
- int32_t hot_threshold = static_cast<int32_t>(jit->HotMethodThreshold()) + kBatchSize;
- int32_t osr_threshold = static_cast<int32_t>(jit->OSRMethodThreshold()) + kBatchSize;
+ int32_t warm_threshold = jit->WarmMethodThreshold();
+ int32_t hot_threshold = jit->HotMethodThreshold();
+ int32_t osr_threshold = jit->OSRMethodThreshold();
if (hotness_count < warm_threshold) {
countdown_value = warm_threshold - hotness_count;
} else if (hotness_count < hot_threshold) {
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index 0353ea7462..7ce70cb3d4 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -554,7 +554,7 @@ static bool ModsMatch(JdwpEvent* pEvent, const ModBasket& basket)
break;
default:
LOG(FATAL) << "unknown mod kind " << pMod->modKind;
- break;
+ UNREACHABLE();
}
}
return true;
diff --git a/runtime/jdwp/jdwp_request.cc b/runtime/jdwp/jdwp_request.cc
index 6af267e674..a77962e2fa 100644
--- a/runtime/jdwp/jdwp_request.cc
+++ b/runtime/jdwp/jdwp_request.cc
@@ -70,7 +70,7 @@ uint64_t Request::ReadValue(size_t width) {
case 2: value = Read2BE(); break;
case 4: value = Read4BE(); break;
case 8: value = Read8BE(); break;
- default: LOG(FATAL) << width; break;
+ default: LOG(FATAL) << width;
}
return value;
}
diff --git a/runtime/jit/jit-inl.h b/runtime/jit/jit-inl.h
deleted file mode 100644
index 80324addcb..0000000000
--- a/runtime/jit/jit-inl.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2018 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_RUNTIME_JIT_JIT_INL_H_
-#define ART_RUNTIME_JIT_JIT_INL_H_
-
-#include "jit/jit.h"
-
-#include "art_method.h"
-#include "base/bit_utils.h"
-#include "thread.h"
-#include "runtime-inl.h"
-
-namespace art {
-namespace jit {
-
-inline bool Jit::ShouldUsePriorityThreadWeight(Thread* self) {
- return self->IsJitSensitiveThread() && Runtime::Current()->InJankPerceptibleProcessState();
-}
-
-inline void Jit::AddSamples(Thread* self,
- ArtMethod* method,
- uint16_t samples,
- bool with_backedges) {
- if (Jit::ShouldUsePriorityThreadWeight(self)) {
- samples *= PriorityThreadWeight();
- }
- uint32_t old_count = method->GetCounter();
- uint32_t new_count = old_count + samples;
-
- // The full check is fairly expensive so we just add to hotness most of the time,
- // and we do the full check only when some of the higher bits of the count change.
- // NB: The method needs to see the transitions of the counter past the thresholds.
- uint32_t old_batch = RoundDown(old_count, kJitSamplesBatchSize); // Clear lower bits.
- uint32_t new_batch = RoundDown(new_count, kJitSamplesBatchSize); // Clear lower bits.
- if (UNLIKELY(old_batch == 0)) {
- // For low sample counts, we check every time (which is important for tests).
- if (!MaybeCompileMethod(self, method, old_count, new_count, with_backedges)) {
- // Tests may check that the counter is 0 for methods that we never compile.
- return; // Ignore the samples for now and retry later.
- }
- } else if (UNLIKELY(old_batch != new_batch)) {
- // For high sample counts, we check only when we move past the batch boundary.
- if (!MaybeCompileMethod(self, method, old_batch, new_batch, with_backedges)) {
- // OSR compilation will ignore the samples if they don't have backedges.
- return; // Ignore the samples for now and retry later.
- }
- }
-
- method->SetCounter(new_count);
-}
-
-} // namespace jit
-} // namespace art
-
-#endif // ART_RUNTIME_JIT_JIT_INL_H_
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 2fc418b7d8..4a3ef07819 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -28,7 +28,6 @@
#include "debugger.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "interpreter/interpreter.h"
-#include "jit-inl.h"
#include "jit_code_cache.h"
#include "jni/java_vm_ext.h"
#include "mirror/method_handle_impl.h"
@@ -150,6 +149,10 @@ JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& opt
return jit_options;
}
+bool Jit::ShouldUsePriorityThreadWeight(Thread* self) {
+ return self->IsJitSensitiveThread() && Runtime::Current()->InJankPerceptibleProcessState();
+}
+
void Jit::DumpInfo(std::ostream& os) {
code_cache_->Dump(os);
cumulative_timings_.Dump(os);
@@ -625,25 +628,21 @@ static bool IgnoreSamplesForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mut
return false;
}
-bool Jit::MaybeCompileMethod(Thread* self,
- ArtMethod* method,
- uint32_t old_count,
- uint32_t new_count,
- bool with_backedges) {
+void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_backedges) {
if (thread_pool_ == nullptr) {
// Should only see this when shutting down, starting up, or in zygote, which doesn't
// have a thread pool.
DCHECK(Runtime::Current()->IsShuttingDown(self) ||
!Runtime::Current()->IsFinishedStarting() ||
Runtime::Current()->IsZygote());
- return false;
+ return;
}
if (IgnoreSamplesForMethod(method)) {
- return false;
+ return;
}
if (HotMethodThreshold() == 0) {
// Tests might request JIT on first use (compiled synchronously in the interpreter).
- return false;
+ return;
}
DCHECK(thread_pool_ != nullptr);
DCHECK_GT(WarmMethodThreshold(), 0);
@@ -652,9 +651,15 @@ bool Jit::MaybeCompileMethod(Thread* self,
DCHECK_GE(PriorityThreadWeight(), 1);
DCHECK_LE(PriorityThreadWeight(), HotMethodThreshold());
- if (old_count < WarmMethodThreshold() && new_count >= WarmMethodThreshold()) {
- // Note: Native method have no "warm" state or profiling info.
- if (!method->IsNative() && method->GetProfilingInfo(kRuntimePointerSize) == nullptr) {
+ uint16_t starting_count = method->GetCounter();
+ if (Jit::ShouldUsePriorityThreadWeight(self)) {
+ count *= PriorityThreadWeight();
+ }
+ uint32_t new_count = starting_count + count;
+ // Note: Native method have no "warm" state or profiling info.
+ if (LIKELY(!method->IsNative()) && starting_count < WarmMethodThreshold()) {
+ if ((new_count >= WarmMethodThreshold()) &&
+ (method->GetProfilingInfo(kRuntimePointerSize) == nullptr)) {
bool success = ProfilingInfo::Create(self, method, /* retry_allocation= */ false);
if (success) {
VLOG(jit) << "Start profiling " << method->PrettyMethod();
@@ -664,7 +669,7 @@ bool Jit::MaybeCompileMethod(Thread* self,
// Calling ProfilingInfo::Create might put us in a suspended state, which could
// lead to the thread pool being deleted when we are shutting down.
DCHECK(Runtime::Current()->IsShuttingDown(self));
- return false;
+ return;
}
if (!success) {
@@ -673,26 +678,31 @@ bool Jit::MaybeCompileMethod(Thread* self,
thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kAllocateProfile));
}
}
- }
- if (UseJitCompilation()) {
- if (old_count < HotMethodThreshold() && new_count >= HotMethodThreshold()) {
- if (!code_cache_->ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
+ // Avoid jumping more than one state at a time.
+ new_count = std::min(new_count, static_cast<uint32_t>(HotMethodThreshold() - 1));
+ } else if (UseJitCompilation()) {
+ if (starting_count < HotMethodThreshold()) {
+ if ((new_count >= HotMethodThreshold()) &&
+ !code_cache_->ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
DCHECK(thread_pool_ != nullptr);
thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompile));
}
- }
- if (old_count < OSRMethodThreshold() && new_count >= OSRMethodThreshold()) {
+ // Avoid jumping more than one state at a time.
+ new_count = std::min(new_count, static_cast<uint32_t>(OSRMethodThreshold() - 1));
+ } else if (starting_count < OSRMethodThreshold()) {
if (!with_backedges) {
- return false;
+ // If the samples don't contain any back edge, we don't increment the hotness.
+ return;
}
DCHECK(!method->IsNative()); // No back edges reported for native methods.
- if (!code_cache_->IsOsrCompiled(method)) {
+ if ((new_count >= OSRMethodThreshold()) && !code_cache_->IsOsrCompiled(method)) {
DCHECK(thread_pool_ != nullptr);
thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompileOsr));
}
}
}
- return true;
+ // Update hotness counter
+ method->SetCounter(new_count);
}
class ScopedSetRuntimeThread {
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 2027719bd9..e12b032feb 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -47,7 +47,6 @@ static constexpr int16_t kJitHotnessDisabled = -2;
// At what priority to schedule jit threads. 9 is the lowest foreground priority on device.
// See android/os/Process.java.
static constexpr int kJitPoolThreadPthreadDefaultPriority = 9;
-static constexpr uint32_t kJitSamplesBatchSize = 32; // Must be power of 2.
class JitOptions {
public:
@@ -218,10 +217,7 @@ class Jit {
void MethodEntered(Thread* thread, ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_);
- ALWAYS_INLINE void AddSamples(Thread* self,
- ArtMethod* method,
- uint16_t samples,
- bool with_backedges)
+ void AddSamples(Thread* self, ArtMethod* method, uint16_t samples, bool with_backedges)
REQUIRES_SHARED(Locks::mutator_lock_);
void InvokeVirtualOrInterface(ObjPtr<mirror::Object> this_object,
@@ -295,15 +291,6 @@ class Jit {
private:
Jit(JitCodeCache* code_cache, JitOptions* options);
- // Compile the method if the number of samples passes a threshold.
- // Returns false if we can not compile now - don't increment the counter and retry later.
- bool MaybeCompileMethod(Thread* self,
- ArtMethod* method,
- uint32_t old_count,
- uint32_t new_count,
- bool with_backedges)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
static bool BindCompilerMethods(std::string* error_msg);
// JIT compiler
diff --git a/runtime/jni/check_jni.cc b/runtime/jni/check_jni.cc
index 48f99815fd..727929930b 100644
--- a/runtime/jni/check_jni.cc
+++ b/runtime/jni/check_jni.cc
@@ -880,7 +880,7 @@ class ScopedCheck {
break;
case kDirectByteBuffer:
UNIMPLEMENTED(FATAL);
- break;
+ UNREACHABLE();
case kString:
okay = obj->GetClass()->IsStringClass();
break;
@@ -2945,7 +2945,7 @@ class CheckJNI {
break;
case Primitive::kPrimVoid:
LOG(FATAL) << "Unexpected type: " << type;
- break;
+ UNREACHABLE();
}
if (sc.Check(soa, false, result_check, &result)) {
return result;
@@ -3031,7 +3031,7 @@ class CheckJNI {
break;
case Primitive::kPrimVoid:
LOG(FATAL) << "Unexpected type: " << type;
- break;
+ UNREACHABLE();
}
JniValueType result;
result.V = nullptr;
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 9b38576fc5..f6adc800e4 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -225,11 +225,10 @@ int32_t Object::IdentityHashCode() {
}
default: {
LOG(FATAL) << "Invalid state during hashcode " << lw.GetState();
- break;
+ UNREACHABLE();
}
}
}
- UNREACHABLE();
}
void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, ObjPtr<Object> new_value) {
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 647928391b..7240357979 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -168,11 +168,11 @@ bool Monitor::Install(Thread* self) {
}
case LockWord::kUnlocked: {
LOG(FATAL) << "Inflating unlocked lock word";
- break;
+ UNREACHABLE();
}
default: {
LOG(FATAL) << "Invalid monitor state " << lw.GetState();
- return false;
+ UNREACHABLE();
}
}
LockWord fat(this, lw.GCState());
@@ -1236,7 +1236,7 @@ bool Monitor::MonitorExit(Thread* self, mirror::Object* obj) {
}
default: {
LOG(FATAL) << "Invalid monitor state " << lock_word.GetState();
- return false;
+ UNREACHABLE();
}
}
}
@@ -1280,7 +1280,7 @@ void Monitor::Wait(Thread* self, mirror::Object *obj, int64_t ms, int32_t ns,
case LockWord::kFatLocked: // Unreachable given the loop condition above. Fall-through.
default: {
LOG(FATAL) << "Invalid monitor state " << lock_word.GetState();
- return;
+ UNREACHABLE();
}
}
}
@@ -1320,7 +1320,7 @@ void Monitor::DoNotify(Thread* self, mirror::Object* obj, bool notify_all) {
}
default: {
LOG(FATAL) << "Invalid monitor state " << lock_word.GetState();
- return;
+ UNREACHABLE();
}
}
}
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index c1ccd33774..5c5523d9c8 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1920,7 +1920,7 @@ OatFile::OatClass::OatClass(const OatFile* oat_file,
}
case kOatClassMax: {
LOG(FATAL) << "Invalid OatClassType " << type_;
- break;
+ UNREACHABLE();
}
}
}
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index d4e3d54a99..0d570c39ae 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -227,7 +227,7 @@ void QuickExceptionHandler::FindCatch(ObjPtr<mirror::Throwable> exception) {
LOG(INFO) << "Handler is upcall";
}
if (handler_method_ != nullptr) {
- const DexFile* dex_file = handler_method_->GetDeclaringClass()->GetDexCache()->GetDexFile();
+ const DexFile* dex_file = handler_method_->GetDexFile();
int line_number = annotations::GetLineNumFromPC(dex_file, handler_method_, handler_dex_pc_);
LOG(INFO) << "Handler: " << handler_method_->PrettyMethod() << " (line: "
<< line_number << ")";
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 9cbbd4172d..ab79b9e1a0 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1241,7 +1241,6 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
}
case JdwpProvider::kUnset: {
LOG(FATAL) << "Illegal jdwp provider " << jdwp_provider_ << " was not filtered out!";
- break;
}
}
callbacks_->AddThreadLifecycleCallback(Dbg::GetThreadLifecycleCallback());
@@ -1856,7 +1855,7 @@ int32_t Runtime::GetStat(int kind) {
return 0; // backward compatibility
default:
LOG(FATAL) << "Unknown statistic " << kind;
- return -1; // unreachable
+ UNREACHABLE();
}
}
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 33cd9bbb67..6c41ae42b7 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1952,8 +1952,7 @@ struct StackDumpVisitor : public MonitorObjectsStackVisitor {
override
REQUIRES_SHARED(Locks::mutator_lock_) {
m = m->GetInterfaceMethodIfProxy(kRuntimePointerSize);
- ObjPtr<mirror::Class> c = m->GetDeclaringClass();
- ObjPtr<mirror::DexCache> dex_cache = c->GetDexCache();
+ ObjPtr<mirror::DexCache> dex_cache = m->GetDexCache();
int line_number = -1;
if (dex_cache != nullptr) { // be tolerant of bad input
const DexFile* dex_file = dex_cache->GetDexFile();
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 23e57a2f21..4bbd81a70d 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -1561,7 +1561,7 @@ uint32_t ThreadList::AllocThreadId(Thread* self) {
}
}
LOG(FATAL) << "Out of internal thread ids";
- return 0;
+ UNREACHABLE();
}
void ThreadList::ReleaseThreadId(Thread* self, uint32_t id) {
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
index e4bf447a6f..62482fd898 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -531,7 +531,7 @@ void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj,
break;
default:
LOG(FATAL) << "Unknown value kind " << static_cast<int>(field_value.kind);
- break;
+ UNREACHABLE();
}
}
@@ -558,7 +558,7 @@ void Transaction::InternStringLog::Undo(InternTable* intern_table) const {
break;
default:
LOG(FATAL) << "Unknown interned string kind";
- break;
+ UNREACHABLE();
}
break;
}
@@ -572,13 +572,13 @@ void Transaction::InternStringLog::Undo(InternTable* intern_table) const {
break;
default:
LOG(FATAL) << "Unknown interned string kind";
- break;
+ UNREACHABLE();
}
break;
}
default:
LOG(FATAL) << "Unknown interned string op";
- break;
+ UNREACHABLE();
}
}
@@ -669,9 +669,10 @@ void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array,
break;
case Primitive::kPrimNot:
LOG(FATAL) << "ObjectArray should be treated as Object";
- break;
+ UNREACHABLE();
default:
LOG(FATAL) << "Unsupported type " << array_type;
+ UNREACHABLE();
}
}
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 5300e2d389..cde885c288 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -276,7 +276,7 @@ ArtMethod* WellKnownClasses::StringInitToStringFactory(ArtMethod* string_init) {
STRING_INIT_LIST(TO_STRING_FACTORY)
#undef TO_STRING_FACTORY
LOG(FATAL) << "Could not find StringFactory method for String.<init>";
- return nullptr;
+ UNREACHABLE();
}
uint32_t WellKnownClasses::StringInitToEntryPoint(ArtMethod* string_init) {
@@ -288,7 +288,7 @@ uint32_t WellKnownClasses::StringInitToEntryPoint(ArtMethod* string_init) {
STRING_INIT_LIST(TO_ENTRY_POINT)
#undef TO_ENTRY_POINT
LOG(FATAL) << "Could not find StringFactory method for String.<init>";
- return 0;
+ UNREACHABLE();
}
#undef STRING_INIT_LIST
diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc
index f5e1e1bc07..3be48a3b80 100644
--- a/test/ti-agent/common_helper.cc
+++ b/test/ti-agent/common_helper.cc
@@ -24,6 +24,7 @@
#include "jvmti.h"
#include "jvmti_helper.h"
+#include "ti_macros.h"
namespace art {
@@ -87,7 +88,7 @@ jobject GetJavaValueByType(JNIEnv* env, char type, jvalue value) {
break;
default:
LOG(FATAL) << "Unable to figure out type!";
- return nullptr;
+ UNREACHABLE();
}
std::ostringstream oss;
oss << "(" << type << ")L" << name << ";";
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index dcd910597d..e27878f6f0 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -115,6 +115,7 @@ endif
# Run ahat-test-dump.jar to generate test-dump.hprof and test-dump-base.hprof
AHAT_TEST_DUMP_DEPENDENCIES := \
$(AHAT_TEST_DALVIKVM_DEP) \
+ $(ART_HOST_SHARED_LIBRARY_DEPENDENCIES) \
$(ART_HOST_SHARED_LIBRARY_DEBUG_DEPENDENCIES) \
$(HOST_OUT_EXECUTABLES)/art \
$(HOST_CORE_IMG_OUT_BASE)$(CORE_IMG_SUFFIX)
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index decbc0179c..3e38b97889 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -952,8 +952,11 @@ class HiddenApi final {
auto fn_shared = [&](const DexMember& boot_member) {
auto it = api_list.find(boot_member.GetApiEntry());
bool api_list_found = (it != api_list.end());
- CHECK(!force_assign_all_ || api_list_found)
- << "Could not find flags for dex entry: " << boot_member.GetApiEntry();
+ // TODO: Fix ART buildbots and turn this into a CHECK.
+ if (force_assign_all_ && !api_list_found) {
+ LOG(WARNING) << "Could not find hiddenapi flags for dex entry: "
+ << boot_member.GetApiEntry();
+ }
builder.WriteFlags(api_list_found ? it->second : hiddenapi::ApiList::Whitelist());
};
auto fn_field = [&](const ClassAccessor::Field& boot_field) {
diff --git a/tools/timeout_dumper/timeout_dumper.cc b/tools/timeout_dumper/timeout_dumper.cc
index 30e194ceda..96d165c5c7 100644
--- a/tools/timeout_dumper/timeout_dumper.cc
+++ b/tools/timeout_dumper/timeout_dumper.cc
@@ -432,7 +432,7 @@ void DumpThread(pid_t pid,
LOG(ERROR) << prefix << "(failed to create Backtrace for thread " << tid << ")";
return;
}
- backtrace->SetSkipFrames(0);
+ backtrace->SetSkipFrames(false);
if (!backtrace->Unwind(0, nullptr)) {
LOG(ERROR) << prefix << "(backtrace::Unwind failed for thread " << tid
<< ": " << backtrace->GetErrorString(backtrace->GetError()) << ")";
diff --git a/tools/titrace/instruction_decoder.cc b/tools/titrace/instruction_decoder.cc
index 89904b32cd..6f497b3c04 100644
--- a/tools/titrace/instruction_decoder.cc
+++ b/tools/titrace/instruction_decoder.cc
@@ -456,9 +456,10 @@ class ClassInstructionDecoder : public InstructionDecoder {
case kBreakpoint: return "breakpoint";
case kImpdep1: return "impdep1";
case kImpdep2: return "impdep2";
- default: LOG(FATAL) << "Unknown opcode " << op;
+ default:
+ LOG(FATAL) << "Unknown opcode " << op;
+ __builtin_unreachable();
}
- return "";
}
};
};
@@ -500,7 +501,7 @@ DEX_INSTRUCTION_LIST(MAKE_ENUM_DEFINITION)
#undef MAKE_ENUM_DEFINITION
default: LOG(FATAL) << "Unknown opcode " << op;
}
- return "";
+ __builtin_unreachable();
}
};
};