diff options
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(); } }; }; |