diff options
71 files changed, 2542 insertions, 649 deletions
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk index a93d8a882a..43e1457a50 100644 --- a/build/Android.common_build.mk +++ b/build/Android.common_build.mk @@ -206,6 +206,7 @@ ART_CPP_EXTENSION := .cc ART_C_INCLUDES := \ external/gtest/include \ external/icu/icu4c/source/common \ + external/lz4/lib \ external/valgrind/include \ external/valgrind \ external/vixl/src \ diff --git a/compiler/Android.mk b/compiler/Android.mk index 348eabdde5..bdd9a84433 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -258,9 +258,9 @@ define build-libart-compiler ifeq ($$(art_ndebug_or_debug),ndebug) LOCAL_MODULE := libart-compiler ifeq ($$(art_static_or_shared), static) - LOCAL_STATIC_LIBRARIES += libart + LOCAL_STATIC_LIBRARIES += libart liblz4 else - LOCAL_SHARED_LIBRARIES += libart + LOCAL_SHARED_LIBRARIES += libart liblz4 endif ifeq ($$(art_target_or_host),target) LOCAL_FDO_SUPPORT := true @@ -268,9 +268,9 @@ define build-libart-compiler else # debug LOCAL_MODULE := libartd-compiler ifeq ($$(art_static_or_shared), static) - LOCAL_STATIC_LIBRARIES += libartd + LOCAL_STATIC_LIBRARIES += libartd liblz4 else - LOCAL_SHARED_LIBRARIES += libartd + LOCAL_SHARED_LIBRARIES += libartd liblz4 endif endif diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index e6cc50cc5e..638b897eea 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -189,17 +189,29 @@ void CommonCompilerTest::SetUp() { } timer_.reset(new CumulativeLogger("Compilation times")); - compiler_driver_.reset(new CompilerDriver(compiler_options_.get(), - verification_results_.get(), - method_inliner_map_.get(), - compiler_kind_, instruction_set, - instruction_set_features_.get(), - true, - GetImageClasses(), - GetCompiledClasses(), - GetCompiledMethods(), - 2, true, true, "", false, timer_.get(), -1, "")); + CreateCompilerDriver(compiler_kind_, instruction_set); } +} + +void CommonCompilerTest::CreateCompilerDriver(Compiler::Kind kind, InstructionSet isa) { + compiler_driver_.reset(new CompilerDriver(compiler_options_.get(), + verification_results_.get(), + method_inliner_map_.get(), + kind, + isa, + instruction_set_features_.get(), + true, + GetImageClasses(), + GetCompiledClasses(), + GetCompiledMethods(), + 2, + true, + true, + "", + false, + timer_.get(), + -1, + "")); // We typically don't generate an image in unit tests, disable this optimization by default. compiler_driver_->SetSupportBootImageFixup(false); } diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h index 1b57b7d1d2..b491946dc3 100644 --- a/compiler/common_compiler_test.h +++ b/compiler/common_compiler_test.h @@ -90,6 +90,8 @@ class CommonCompilerTest : public CommonRuntimeTest { const char* method_name, const char* signature) SHARED_REQUIRES(Locks::mutator_lock_); + void CreateCompilerDriver(Compiler::Kind kind, InstructionSet isa); + void ReserveImageSpace(); void UnreserveImageSpace(); diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc index eaf2408763..f48947d537 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -50,6 +50,23 @@ static constexpr bool kIntrinsicIsStatic[] = { true, // kIntrinsicMinMaxLong true, // kIntrinsicMinMaxFloat true, // kIntrinsicMinMaxDouble + true, // kIntrinsicCos + true, // kIntrinsicSin + true, // kIntrinsicAcos + true, // kIntrinsicAsin + true, // kIntrinsicAtan + true, // kIntrinsicAtan2 + true, // kIntrinsicCbrt + true, // kIntrinsicCosh + true, // kIntrinsicExp + true, // kIntrinsicExpm1 + true, // kIntrinsicHypot + true, // kIntrinsicLog + true, // kIntrinsicLog10 + true, // kIntrinsicNextAfter + true, // kIntrinsicSinh + true, // kIntrinsicTan + true, // kIntrinsicTanh true, // kIntrinsicSqrt true, // kIntrinsicCeil true, // kIntrinsicFloor @@ -95,6 +112,23 @@ static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxInt], "MinMaxInt must be static static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxLong], "MinMaxLong_must_be_static"); static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], "MinMaxFloat_must_be_static"); static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], "MinMaxDouble_must_be_static"); +static_assert(kIntrinsicIsStatic[kIntrinsicCos], "Cos must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicSin], "Sin must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicAcos], "Acos must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicAsin], "Asin must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicAtan], "Atan must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicAtan2], "Atan2 must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicCbrt], "Cbrt must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicCosh], "Cosh must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicExp], "Exp must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicExpm1], "Expm1 must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicHypot], "Hypot must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicLog], "Log must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicLog10], "Log10 must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicNextAfter], "NextAfter must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicSinh], "Sinh must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicTan], "Tan must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicTanh], "Tanh must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicSqrt], "Sqrt must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicCeil], "Ceil must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicFloor], "Floor must be static"); @@ -196,6 +230,23 @@ const char* const DexFileMethodInliner::kNameCacheNames[] = { "abs", // kNameCacheAbs "max", // kNameCacheMax "min", // kNameCacheMin + "cos", // kNameCacheCos + "sin", // kNameCacheSin + "acos", // kNameCacheAcos + "asin", // kNameCacheAsin + "atan", // kNameCacheAtan + "atan2", // kNameCacheAtan2 + "cbrt", // kNameCacheCbrt + "cosh", // kNameCacheCosh + "exp", // kNameCacheExp + "expm1", // kNameCacheExpm1 + "hypot", // kNameCacheHypot + "log", // kNameCacheLog + "log10", // kNameCacheLog10 + "nextAfter", // kNameCacheNextAfter + "sinh", // kNameCacheSinh + "tan", // kNameCacheTan + "tanh", // kNameCacheTanh "sqrt", // kNameCacheSqrt "ceil", // kNameCacheCeil "floor", // kNameCacheFloor @@ -425,6 +476,23 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods INTRINSIC(JavaLangMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax), INTRINSIC(JavaLangStrictMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax), + INTRINSIC(JavaLangMath, Cos, D_D, kIntrinsicCos, 0), + INTRINSIC(JavaLangMath, Sin, D_D, kIntrinsicSin, 0), + INTRINSIC(JavaLangMath, Acos, D_D, kIntrinsicAcos, 0), + INTRINSIC(JavaLangMath, Asin, D_D, kIntrinsicAsin, 0), + INTRINSIC(JavaLangMath, Atan, D_D, kIntrinsicAtan, 0), + INTRINSIC(JavaLangMath, Atan2, DD_D, kIntrinsicAtan2, 0), + INTRINSIC(JavaLangMath, Cbrt, D_D, kIntrinsicCbrt, 0), + INTRINSIC(JavaLangMath, Cosh, D_D, kIntrinsicCosh, 0), + INTRINSIC(JavaLangMath, Exp, D_D, kIntrinsicExp, 0), + INTRINSIC(JavaLangMath, Expm1, D_D, kIntrinsicExpm1, 0), + INTRINSIC(JavaLangMath, Hypot, DD_D, kIntrinsicHypot, 0), + INTRINSIC(JavaLangMath, Log, D_D, kIntrinsicLog, 0), + INTRINSIC(JavaLangMath, Log10, D_D, kIntrinsicLog10, 0), + INTRINSIC(JavaLangMath, NextAfter, DD_D, kIntrinsicNextAfter, 0), + INTRINSIC(JavaLangMath, Sinh, D_D, kIntrinsicSinh, 0), + INTRINSIC(JavaLangMath, Tan, D_D, kIntrinsicTan, 0), + INTRINSIC(JavaLangMath, Tanh, D_D, kIntrinsicTanh, 0), INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0), INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0), @@ -603,6 +671,25 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, false /* is_double */); case kIntrinsicMinMaxDouble: return backend->GenInlinedMinMaxFP(info, intrinsic.d.data & kIntrinsicFlagMin, true /* is_double */); + case kIntrinsicCos: + case kIntrinsicSin: + case kIntrinsicAcos: + case kIntrinsicAsin: + case kIntrinsicAtan: + case kIntrinsicAtan2: + case kIntrinsicCbrt: + case kIntrinsicCosh: + case kIntrinsicExp: + case kIntrinsicExpm1: + case kIntrinsicHypot: + case kIntrinsicLog: + case kIntrinsicLog10: + case kIntrinsicNextAfter: + case kIntrinsicSinh: + case kIntrinsicTan: + case kIntrinsicTanh: + // Not implemented in Quick. + return false; case kIntrinsicSqrt: return backend->GenInlinedSqrt(info); case kIntrinsicCeil: diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h index 5ce110c120..ac70577b48 100644 --- a/compiler/dex/quick/dex_file_method_inliner.h +++ b/compiler/dex/quick/dex_file_method_inliner.h @@ -162,6 +162,23 @@ class DexFileMethodInliner { kNameCacheAbs, kNameCacheMax, kNameCacheMin, + kNameCacheCos, + kNameCacheSin, + kNameCacheAcos, + kNameCacheAsin, + kNameCacheAtan, + kNameCacheAtan2, + kNameCacheCbrt, + kNameCacheCosh, + kNameCacheExp, + kNameCacheExpm1, + kNameCacheHypot, + kNameCacheLog, + kNameCacheLog10, + kNameCacheNextAfter, + kNameCacheSinh, + kNameCacheTan, + kNameCacheTanh, kNameCacheSqrt, kNameCacheCeil, kNameCacheFloor, diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc index 03bda78498..2532bda632 100644 --- a/compiler/dex/quick_compiler_callbacks.cc +++ b/compiler/dex/quick_compiler_callbacks.cc @@ -22,14 +22,10 @@ namespace art { -bool QuickCompilerCallbacks::MethodVerified(verifier::MethodVerifier* verifier) { - bool result = verification_results_->ProcessVerifiedMethod(verifier); - if (result) { - MethodReference ref = verifier->GetMethodReference(); - method_inliner_map_->GetMethodInliner(ref.dex_file) - ->AnalyseMethodCode(verifier); - } - return result; +void QuickCompilerCallbacks::MethodVerified(verifier::MethodVerifier* verifier) { + verification_results_->ProcessVerifiedMethod(verifier); + MethodReference ref = verifier->GetMethodReference(); + method_inliner_map_->GetMethodInliner(ref.dex_file)->AnalyseMethodCode(verifier); } void QuickCompilerCallbacks::ClassRejected(ClassReference ref) { diff --git a/compiler/dex/quick_compiler_callbacks.h b/compiler/dex/quick_compiler_callbacks.h index 03bf57bded..4f5ea766d8 100644 --- a/compiler/dex/quick_compiler_callbacks.h +++ b/compiler/dex/quick_compiler_callbacks.h @@ -37,7 +37,7 @@ class QuickCompilerCallbacks FINAL : public CompilerCallbacks { ~QuickCompilerCallbacks() { } - bool MethodVerified(verifier::MethodVerifier* verifier) + void MethodVerified(verifier::MethodVerifier* verifier) SHARED_REQUIRES(Locks::mutator_lock_) OVERRIDE; void ClassRejected(ClassReference ref) OVERRIDE; diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc index 65b0ad6400..dd24220e0e 100644 --- a/compiler/dex/verification_results.cc +++ b/compiler/dex/verification_results.cc @@ -44,14 +44,14 @@ VerificationResults::~VerificationResults() { } } -bool VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) { +void VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) { DCHECK(method_verifier != nullptr); MethodReference ref = method_verifier->GetMethodReference(); bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags()); const VerifiedMethod* verified_method = VerifiedMethod::Create(method_verifier, compile); if (verified_method == nullptr) { - // Do not report an error to the verifier. We'll just punt this later. - return true; + // We'll punt this later. + return; } WriterMutexLock mu(Thread::Current(), verified_methods_lock_); @@ -69,11 +69,10 @@ bool VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method // is unsafe to replace the existing one since the JIT may be using it to generate a // native GC map. delete verified_method; - return true; + return; } verified_methods_.Put(ref, verified_method); DCHECK(verified_methods_.find(ref) != verified_methods_.end()); - return true; } const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) { diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h index 9934f6b13b..da80bf07db 100644 --- a/compiler/dex/verification_results.h +++ b/compiler/dex/verification_results.h @@ -42,7 +42,7 @@ class VerificationResults { explicit VerificationResults(const CompilerOptions* compiler_options); ~VerificationResults(); - bool ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) + void ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!verified_methods_lock_); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index a1a92aa7a4..76b57dd3cf 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2043,6 +2043,7 @@ class VerifyClassVisitor : public CompilationVisitor { dex_cache, class_loader, &class_def, + Runtime::Current()->GetCompilerCallbacks(), true /* allow soft failures */, true /* log hard failures */, &error_msg) == diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 1347b37fa0..5c5a63dd84 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -161,16 +161,11 @@ class CompilerDriver { } // Generate the trampolines that are invoked by unresolved direct methods. - const std::vector<uint8_t>* CreateJniDlsymLookup() const - SHARED_REQUIRES(Locks::mutator_lock_); - const std::vector<uint8_t>* CreateQuickGenericJniTrampoline() const - SHARED_REQUIRES(Locks::mutator_lock_); - const std::vector<uint8_t>* CreateQuickImtConflictTrampoline() const - SHARED_REQUIRES(Locks::mutator_lock_); - const std::vector<uint8_t>* CreateQuickResolutionTrampoline() const - SHARED_REQUIRES(Locks::mutator_lock_); - const std::vector<uint8_t>* CreateQuickToInterpreterBridge() const - SHARED_REQUIRES(Locks::mutator_lock_); + const std::vector<uint8_t>* CreateJniDlsymLookup() const; + const std::vector<uint8_t>* CreateQuickGenericJniTrampoline() const; + const std::vector<uint8_t>* CreateQuickImtConflictTrampoline() const; + const std::vector<uint8_t>* CreateQuickResolutionTrampoline() const; + const std::vector<uint8_t>* CreateQuickToInterpreterBridge() const; CompiledClass* GetCompiledClass(ClassReference ref) const REQUIRES(!compiled_classes_lock_); diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc index 7696b9413e..c5c0f1308b 100644 --- a/compiler/elf_writer_debug.cc +++ b/compiler/elf_writer_debug.cc @@ -416,6 +416,13 @@ namespace { return variable_locations; } + + bool IsFromOptimizingCompiler(const MethodDebugInfo* method_info) { + return method_info->compiled_method_->GetQuickCode().size() > 0 && + method_info->compiled_method_->GetVmapTable().size() > 0 && + method_info->compiled_method_->GetGcMap().size() == 0 && + method_info->code_item_ != nullptr; + } } // namespace // Helper class to write .debug_info and its supporting sections. @@ -558,11 +565,7 @@ class DebugInfoWriter { uint32_t dex_pc_low = 0, uint32_t dex_pc_high = 0xFFFFFFFF) { using Kind = DexRegisterLocation::Kind; - bool is_optimizing = method_info->compiled_method_->GetQuickCode().size() > 0 && - method_info->compiled_method_->GetVmapTable().size() > 0 && - method_info->compiled_method_->GetGcMap().size() == 0 && - method_info->code_item_ != nullptr; - if (!is_optimizing) { + if (!IsFromOptimizingCompiler(method_info)) { return; } @@ -940,10 +943,6 @@ class DebugLineWriter { break; } DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits_); - opcodes.SetAddress(text_address + compilation_unit.low_pc_); - if (dwarf_isa != -1) { - opcodes.SetISA(dwarf_isa); - } for (const MethodDebugInfo* mi : compilation_unit.methods_) { // Ignore function if we have already generated line table for the same address. // It would confuse the debugger and the DWARF specification forbids it. @@ -951,6 +950,32 @@ class DebugLineWriter { continue; } + ArrayRef<const SrcMapElem> src_mapping_table; + std::vector<SrcMapElem> src_mapping_table_from_stack_maps; + if (IsFromOptimizingCompiler(mi)) { + // Use stack maps to create mapping table from pc to dex. + const CodeInfo code_info(mi->compiled_method_->GetVmapTable().data()); + const StackMapEncoding encoding = code_info.ExtractEncoding(); + for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) { + StackMap stack_map = code_info.GetStackMapAt(s, encoding); + DCHECK(stack_map.IsValid()); + const uint32_t pc = stack_map.GetNativePcOffset(encoding); + const int32_t dex = stack_map.GetDexPc(encoding); + src_mapping_table_from_stack_maps.push_back({pc, dex}); + } + std::sort(src_mapping_table_from_stack_maps.begin(), + src_mapping_table_from_stack_maps.end()); + src_mapping_table = ArrayRef<const SrcMapElem>(src_mapping_table_from_stack_maps); + } else { + // Use the mapping table provided by the quick compiler. + src_mapping_table = mi->compiled_method_->GetSrcMappingTable(); + } + + if (src_mapping_table.empty()) { + continue; + } + + // Create mapping table from dex to source line. struct DebugInfoCallbacks { static bool NewPosition(void* ctx, uint32_t address, uint32_t line) { auto* context = static_cast<DebugInfoCallbacks*>(ctx); @@ -972,6 +997,15 @@ class DebugLineWriter { &debug_info_callbacks); } + if (debug_info_callbacks.dex2line_.empty()) { + continue; + } + + opcodes.SetAddress(method_address); + if (dwarf_isa != -1) { + opcodes.SetISA(dwarf_isa); + } + // Get and deduplicate directory and filename. int file_index = 0; // 0 - primary source file of the compilation. auto& dex_class_def = dex->GetClassDef(mi->class_def_index_); @@ -1021,7 +1055,7 @@ class DebugLineWriter { const DefaultSrcMap& dex2line_map = debug_info_callbacks.dex2line_; if (file_index != 0 && !dex2line_map.empty()) { bool first = true; - for (SrcMapElem pc2dex : mi->compiled_method_->GetSrcMappingTable()) { + for (SrcMapElem pc2dex : src_mapping_table) { uint32_t pc = pc2dex.from_; int dex_pc = pc2dex.to_; auto dex2line = dex2line_map.Find(static_cast<uint32_t>(dex_pc)); @@ -1048,9 +1082,10 @@ class DebugLineWriter { // line 0 - instruction cannot be attributed to any source line. opcodes.AddRow(method_address, 0); } + + opcodes.AdvancePC(text_address + mi->high_pc_); + opcodes.EndSequence(); } - opcodes.AdvancePC(text_address + compilation_unit.high_pc_); - opcodes.EndSequence(); std::vector<uint8_t> buffer; buffer.reserve(opcodes.data()->size() + KB); size_t offset = builder_->GetDebugLine()->GetSize(); diff --git a/compiler/image_test.cc b/compiler/image_test.cc index cda6240bd4..15812dc3f3 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -43,10 +43,17 @@ class ImageTest : public CommonCompilerTest { ReserveImageSpace(); CommonCompilerTest::SetUp(); } + void TestWriteRead(ImageHeader::StorageMode storage_mode); }; -TEST_F(ImageTest, WriteRead) { - TEST_DISABLED_FOR_NON_PIC_COMPILING_WITH_OPTIMIZING(); +void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { + // TODO: Test does not currently work with optimizing. + CreateCompilerDriver(Compiler::kQuick, kRuntimeISA); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + // Enable write for dex2dex. + for (const DexFile* dex_file : class_linker->GetBootClassPath()) { + dex_file->EnableWrite(); + } // Create a generic location tmp file, to be the base of the .art and .oat temporary files. ScratchFile location; ScratchFile image_location(location, ".art"); @@ -68,17 +75,14 @@ TEST_F(ImageTest, WriteRead) { std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_driver_, requested_image_base, /*compile_pic*/false, - /*compile_app_image*/false)); + /*compile_app_image*/false, + storage_mode)); // TODO: compile_pic should be a test argument. { { jobject class_loader = nullptr; - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); TimingLogger timings("ImageTest::WriteRead", false, false); TimingLogger::ScopedTiming t("CompileAll", &timings); - for (const DexFile* dex_file : class_linker->GetBootClassPath()) { - dex_file->EnableWrite(); - } compiler_driver_->SetDexFilesForOatFile(class_linker->GetBootClassPath()); compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings); @@ -113,14 +117,9 @@ TEST_F(ImageTest, WriteRead) { elf_writer->EndText(text); elf_writer->SetBssSize(oat_writer.GetBssSize()); - elf_writer->WriteDynamicSection(); - - ArrayRef<const dwarf::MethodDebugInfo> method_infos(oat_writer.GetMethodDebugInfo()); - elf_writer->WriteDebugInfo(method_infos); - - ArrayRef<const uintptr_t> patch_locations(oat_writer.GetAbsolutePatchLocations()); - elf_writer->WritePatchLocations(patch_locations); + elf_writer->WriteDebugInfo(oat_writer.GetMethodDebugInfo()); + elf_writer->WritePatchLocations(oat_writer.GetAbsolutePatchLocations()); success = elf_writer->End(); @@ -209,7 +208,13 @@ TEST_F(ImageTest, WriteRead) { gc::space::ImageSpace* image_space = heap->GetBootImageSpace(); ASSERT_TRUE(image_space != nullptr); - ASSERT_LE(image_space->Size(), image_file_size); + if (storage_mode == ImageHeader::kStorageModeUncompressed) { + // Uncompressed, image should be smaller than file. + ASSERT_LE(image_space->Size(), image_file_size); + } else { + // Compressed, file should be smaller than image. + ASSERT_LE(image_file_size, image_space->Size()); + } image_space->VerifyImageAllocations(); uint8_t* image_begin = image_space->Begin(); @@ -237,6 +242,14 @@ TEST_F(ImageTest, WriteRead) { CHECK_EQ(0, rmdir_result); } +TEST_F(ImageTest, WriteReadUncompressed) { + TestWriteRead(ImageHeader::kStorageModeUncompressed); +} + +TEST_F(ImageTest, WriteReadLZ4) { + TestWriteRead(ImageHeader::kStorageModeLZ4); +} + TEST_F(ImageTest, ImageHeaderIsValid) { uint32_t image_begin = ART_BASE_ADDRESS; uint32_t image_size_ = 16 * KB; @@ -257,7 +270,9 @@ TEST_F(ImageTest, ImageHeaderIsValid) { oat_data_end, oat_file_end, sizeof(void*), - /*compile_pic*/false); + /*compile_pic*/false, + ImageHeader::kDefaultStorageMode, + /*data_size*/0u); ASSERT_TRUE(image_header.IsValid()); char* magic = const_cast<char*>(image_header.GetMagic()); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index bf1fcdd5f5..f9f0eb8154 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -17,6 +17,7 @@ #include "image_writer.h" #include <sys/stat.h> +#include <lz4.h> #include <memory> #include <numeric> @@ -225,27 +226,72 @@ bool ImageWriter::Write(int image_fd, return EXIT_FAILURE; } - // Write out the image + fields + methods. + std::unique_ptr<char[]> compressed_data; + // Image data size excludes the bitmap and the header. ImageHeader* const image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); - const auto write_count = image_header->GetImageSize(); - if (!image_file->WriteFully(image_->Begin(), write_count)) { - PLOG(ERROR) << "Failed to write image file " << image_filename; + const size_t image_data_size = image_header->GetImageSize() - sizeof(ImageHeader); + char* image_data = reinterpret_cast<char*>(image_->Begin()) + sizeof(ImageHeader); + size_t data_size; + const char* image_data_to_write; + + CHECK_EQ(image_header->storage_mode_, image_storage_mode_); + switch (image_storage_mode_) { + case ImageHeader::kStorageModeLZ4: { + size_t compressed_max_size = LZ4_compressBound(image_data_size); + compressed_data.reset(new char[compressed_max_size]); + data_size = LZ4_compress( + reinterpret_cast<char*>(image_->Begin()) + sizeof(ImageHeader), + &compressed_data[0], + image_data_size); + image_data_to_write = &compressed_data[0]; + VLOG(compiler) << "Compressed from " << image_data_size << " to " << data_size; + break; + } + case ImageHeader::kStorageModeUncompressed: { + data_size = image_data_size; + image_data_to_write = image_data; + break; + } + default: { + LOG(FATAL) << "Unsupported"; + UNREACHABLE(); + } + } + + // Write header first, as uncompressed. + image_header->data_size_ = data_size; + if (!image_file->WriteFully(image_->Begin(), sizeof(ImageHeader))) { + PLOG(ERROR) << "Failed to write image file header " << image_filename; + image_file->Erase(); + return false; + } + + // Write out the image + fields + methods. + const bool is_compressed = compressed_data != nullptr; + if (!image_file->WriteFully(image_data_to_write, data_size)) { + PLOG(ERROR) << "Failed to write image file data " << image_filename; image_file->Erase(); return false; } - // Write out the image bitmap at the page aligned start of the image end. + // Write out the image bitmap at the page aligned start of the image end, also uncompressed for + // convenience. const ImageSection& bitmap_section = image_header->GetImageSection( ImageHeader::kSectionImageBitmap); - CHECK_ALIGNED(bitmap_section.Offset(), kPageSize); + // Align up since data size may be unaligned if the image is compressed. + size_t bitmap_position_in_file = RoundUp(sizeof(ImageHeader) + data_size, kPageSize); + if (!is_compressed) { + CHECK_EQ(bitmap_position_in_file, bitmap_section.Offset()); + } if (!image_file->Write(reinterpret_cast<char*>(image_bitmap_->Begin()), - bitmap_section.Size(), bitmap_section.Offset())) { + bitmap_section.Size(), + bitmap_position_in_file)) { PLOG(ERROR) << "Failed to write image file " << image_filename; image_file->Erase(); return false; } - - CHECK_EQ(bitmap_section.End(), static_cast<size_t>(image_file->GetLength())); + CHECK_EQ(bitmap_position_in_file + bitmap_section.Size(), + static_cast<size_t>(image_file->GetLength())); if (image_file->FlushCloseOrErase() != 0) { PLOG(ERROR) << "Failed to flush and close image file " << image_filename; return false; @@ -1247,7 +1293,8 @@ void ImageWriter::CreateHeader(size_t oat_loaded_size, size_t oat_data_offset) { } CHECK_EQ(AlignUp(image_begin_ + image_end, kPageSize), oat_file_begin) << "Oat file should be right after the image."; - // Create the header. + // Create the header, leave 0 for data size since we will fill this in as we are writing the + // image. new (image_->Begin()) ImageHeader(PointerToLowMemUInt32(image_begin_), image_end, sections, @@ -1258,7 +1305,9 @@ void ImageWriter::CreateHeader(size_t oat_loaded_size, size_t oat_data_offset) { PointerToLowMemUInt32(oat_data_end), PointerToLowMemUInt32(oat_file_end), target_ptr_size_, - compile_pic_); + compile_pic_, + image_storage_mode_, + /*data_size*/0u); } ArtMethod* ImageWriter::GetImageMethodAddress(ArtMethod* method) { diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 386838fde0..c20d83639a 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -30,6 +30,7 @@ #include "base/macros.h" #include "driver/compiler_driver.h" #include "gc/space/space.h" +#include "image.h" #include "length_prefixed_array.h" #include "lock_word.h" #include "mem_map.h" @@ -54,7 +55,8 @@ class ImageWriter FINAL { ImageWriter(const CompilerDriver& compiler_driver, uintptr_t image_begin, bool compile_pic, - bool compile_app_image) + bool compile_app_image, + ImageHeader::StorageMode image_storage_mode) : compiler_driver_(compiler_driver), image_begin_(reinterpret_cast<uint8_t*>(image_begin)), image_end_(0), @@ -73,7 +75,8 @@ class ImageWriter FINAL { image_method_array_(ImageHeader::kImageMethodsCount), dirty_methods_(0u), clean_methods_(0u), - class_table_bytes_(0u) { + class_table_bytes_(0u), + image_storage_mode_(image_storage_mode) { CHECK_NE(image_begin, 0U); std::fill_n(image_methods_, arraysize(image_methods_), nullptr); std::fill_n(oat_address_offsets_, arraysize(oat_address_offsets_), 0); @@ -460,6 +463,9 @@ class ImageWriter FINAL { // Number of image class table bytes. size_t class_table_bytes_; + // Which mode the image is stored as, see image.h + const ImageHeader::StorageMode image_storage_mode_; + friend class ContainsBootClassLoaderNonImageClassVisitor; friend class FixupClassVisitor; friend class FixupRootVisitor; diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index b8610d0a7a..a2b29a30a9 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -157,14 +157,9 @@ class OatTest : public CommonCompilerTest { elf_writer->EndText(text); elf_writer->SetBssSize(oat_writer.GetBssSize()); - elf_writer->WriteDynamicSection(); - - ArrayRef<const dwarf::MethodDebugInfo> method_infos(oat_writer.GetMethodDebugInfo()); - elf_writer->WriteDebugInfo(method_infos); - - ArrayRef<const uintptr_t> patch_locations(oat_writer.GetAbsolutePatchLocations()); - elf_writer->WritePatchLocations(patch_locations); + elf_writer->WriteDebugInfo(oat_writer.GetMethodDebugInfo()); + elf_writer->WritePatchLocations(oat_writer.GetAbsolutePatchLocations()); return elf_writer->End(); } @@ -260,7 +255,7 @@ TEST_F(OatTest, OatHeaderSizeCheck) { EXPECT_EQ(72U, sizeof(OatHeader)); EXPECT_EQ(4U, sizeof(OatMethodOffsets)); EXPECT_EQ(28U, sizeof(OatQuickMethodHeader)); - EXPECT_EQ(114 * GetInstructionSetPointerSize(kRuntimeISA), sizeof(QuickEntryPoints)); + EXPECT_EQ(131 * GetInstructionSetPointerSize(kRuntimeISA), sizeof(QuickEntryPoints)); } TEST_F(OatTest, OatHeaderIsValid) { @@ -269,14 +264,9 @@ TEST_F(OatTest, OatHeaderIsValid) { std::unique_ptr<const InstructionSetFeatures> insn_features( InstructionSetFeatures::FromVariant(insn_set, "default", &error_msg)); ASSERT_TRUE(insn_features.get() != nullptr) << error_msg; - std::vector<const DexFile*> dex_files; - uint32_t image_file_location_oat_checksum = 0; - uint32_t image_file_location_oat_begin = 0; std::unique_ptr<OatHeader> oat_header(OatHeader::Create(insn_set, insn_features.get(), - &dex_files, - image_file_location_oat_checksum, - image_file_location_oat_begin, + 0u, nullptr)); ASSERT_NE(oat_header.get(), nullptr); ASSERT_TRUE(oat_header->IsValid()); diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index e8e775f2c8..2b2f0e8c26 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -52,6 +52,97 @@ namespace art { +class OatWriter::OatClass { + public: + OatClass(size_t offset, + const dchecked_vector<CompiledMethod*>& compiled_methods, + uint32_t num_non_null_compiled_methods, + mirror::Class::Status status); + OatClass(OatClass&& src) = default; + size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const; + size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const; + size_t SizeOf() const; + bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const; + + CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const { + return compiled_methods_[class_def_method_index]; + } + + // Offset of start of OatClass from beginning of OatHeader. It is + // used to validate file position when writing. + size_t offset_; + + // CompiledMethods for each class_def_method_index, or null if no method is available. + dchecked_vector<CompiledMethod*> compiled_methods_; + + // Offset from OatClass::offset_ to the OatMethodOffsets for the + // class_def_method_index. If 0, it means the corresponding + // CompiledMethod entry in OatClass::compiled_methods_ should be + // null and that the OatClass::type_ should be kOatClassBitmap. + dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_; + + // Data to write. + + static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits"); + int16_t status_; + + static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits"); + uint16_t type_; + + uint32_t method_bitmap_size_; + + // bit vector indexed by ClassDef method index. When + // OatClassType::type_ is kOatClassBitmap, a set bit indicates the + // method has an OatMethodOffsets in methods_offsets_, otherwise + // the entry was ommited to save space. If OatClassType::type_ is + // not is kOatClassBitmap, the bitmap will be null. + std::unique_ptr<BitVector> method_bitmap_; + + // OatMethodOffsets and OatMethodHeaders for each CompiledMethod + // present in the OatClass. Note that some may be missing if + // OatClass::compiled_methods_ contains null values (and + // oat_method_offsets_offsets_from_oat_class_ should contain 0 + // values in this case). + dchecked_vector<OatMethodOffsets> method_offsets_; + dchecked_vector<OatQuickMethodHeader> method_headers_; + + private: + size_t GetMethodOffsetsRawSize() const { + return method_offsets_.size() * sizeof(method_offsets_[0]); + } + + DISALLOW_COPY_AND_ASSIGN(OatClass); +}; + +class OatWriter::OatDexFile { + public: + OatDexFile(size_t offset, const DexFile& dex_file); + OatDexFile(OatDexFile&& src) = default; + + size_t SizeOf() const; + bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const; + + // Offset of start of OatDexFile from beginning of OatHeader. It is + // used to validate file position when writing. + size_t offset_; + + // Data to write. + uint32_t dex_file_location_size_; + const uint8_t* dex_file_location_data_; + uint32_t dex_file_location_checksum_; + uint32_t dex_file_offset_; + uint32_t lookup_table_offset_; + TypeLookupTable* lookup_table_; // Owned by the dex file. + dchecked_vector<uint32_t> class_offsets_; + + private: + size_t GetClassOffsetsRawSize() const { + return class_offsets_.size() * sizeof(class_offsets_[0]); + } + + DISALLOW_COPY_AND_ASSIGN(OatDexFile); +}; + #define DCHECK_OFFSET() \ DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \ << "file_offset=" << file_offset << " relative_offset=" << relative_offset @@ -106,14 +197,14 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, size_oat_dex_file_location_data_(0), size_oat_dex_file_location_checksum_(0), size_oat_dex_file_offset_(0), - size_oat_dex_file_methods_offsets_(0), + size_oat_dex_file_lookup_table_offset_(0), + size_oat_dex_file_class_offsets_(0), + size_oat_lookup_table_alignment_(0), + size_oat_lookup_table_(0), size_oat_class_type_(0), size_oat_class_status_(0), size_oat_class_method_bitmaps_(0), size_oat_class_method_offsets_(0), - size_oat_lookup_table_alignment_(0), - size_oat_lookup_table_offset_(0), - size_oat_lookup_table_(0), method_offset_map_() { CHECK(key_value_store != nullptr); if (compiling_boot_image) { @@ -180,9 +271,6 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, } OatWriter::~OatWriter() { - delete oat_header_; - STLDeleteElements(&oat_dex_files_); - STLDeleteElements(&oat_classes_); } struct OatWriter::GcMapDataAccess { @@ -326,6 +414,11 @@ class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { : DexMethodVisitor(writer, offset), compiled_methods_(), num_non_null_compiled_methods_(0u) { + size_t num_classes = 0u; + for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) { + num_classes += oat_dex_file.class_offsets_.size(); + } + writer_->oat_classes_.reserve(num_classes); compiled_methods_.reserve(256u); } @@ -364,16 +457,16 @@ class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { status = mirror::Class::kStatusNotReady; } - OatClass* oat_class = new OatClass(offset_, compiled_methods_, - num_non_null_compiled_methods_, status); - writer_->oat_classes_.push_back(oat_class); - oat_class->UpdateChecksum(writer_->oat_header_); - offset_ += oat_class->SizeOf(); + writer_->oat_classes_.emplace_back(offset_, + compiled_methods_, + num_non_null_compiled_methods_, + status); + offset_ += writer_->oat_classes_.back().SizeOf(); return DexMethodVisitor::EndClass(); } private: - std::vector<CompiledMethod*> compiled_methods_; + dchecked_vector<CompiledMethod*> compiled_methods_; size_t num_non_null_compiled_methods_; }; @@ -396,7 +489,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) SHARED_REQUIRES(Locks::mutator_lock_) { - OatClass* oat_class = writer_->oat_classes_[oat_class_index_]; + OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); if (compiled_method != nullptr) { @@ -583,7 +676,7 @@ class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor { bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED) SHARED_REQUIRES(Locks::mutator_lock_) { - OatClass* oat_class = writer_->oat_classes_[oat_class_index_]; + OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); if (compiled_method != nullptr) { @@ -600,7 +693,6 @@ class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor { DataAccess::SetOffset(oat_class, method_offsets_index_, offset_); dedupe_map_.PutBefore(lb, map.data(), offset_); offset_ += map_size; - writer_->oat_header_->UpdateChecksum(&map[0], map_size); } } ++method_offsets_index_; @@ -624,7 +716,7 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) SHARED_REQUIRES(Locks::mutator_lock_) { - OatClass* oat_class = writer_->oat_classes_[oat_class_index_]; + OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); OatMethodOffsets offsets(0u); @@ -715,7 +807,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) SHARED_REQUIRES(Locks::mutator_lock_) { - OatClass* oat_class = writer_->oat_classes_[oat_class_index_]; + OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); // No thread suspension since dex_cache_ that may get invalidated if that occurs. @@ -752,8 +844,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { << PrettyMethod(it.GetMemberIndex(), *dex_file_); const OatQuickMethodHeader& method_header = oat_class->method_headers_[method_offsets_index_]; - writer_->oat_header_->UpdateChecksum(&method_header, sizeof(method_header)); - if (!out->WriteFully(&method_header, sizeof(method_header))) { + if (!writer_->WriteData(out, &method_header, sizeof(method_header))) { ReportWriteFailure("method header", it); return false; } @@ -790,8 +881,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } } - writer_->oat_header_->UpdateChecksum(quick_code.data(), code_size); - if (!out->WriteFully(quick_code.data(), code_size)) { + if (!writer_->WriteData(out, quick_code.data(), code_size)) { ReportWriteFailure("method code", it); return false; } @@ -945,7 +1035,7 @@ class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor { } bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) { - OatClass* oat_class = writer_->oat_classes_[oat_class_index_]; + OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); if (compiled_method != nullptr) { // ie. not an abstract method @@ -963,7 +1053,7 @@ class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor { << map_size << " " << map_offset << " " << offset_ << " " << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " for " << DataAccess::Name(); if (map_size != 0u && map_offset == offset_) { - if (UNLIKELY(!out->WriteFully(&map[0], map_size))) { + if (UNLIKELY(!writer_->WriteData(out, map.data(), map_size))) { ReportWriteFailure(it); return false; } @@ -1028,12 +1118,12 @@ bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) { } size_t OatWriter::InitOatHeader() { - oat_header_ = OatHeader::Create(compiler_driver_->GetInstructionSet(), - compiler_driver_->GetInstructionSetFeatures(), - dex_files_, - image_file_location_oat_checksum_, - image_file_location_oat_begin_, - key_value_store_); + oat_header_.reset(OatHeader::Create(compiler_driver_->GetInstructionSet(), + compiler_driver_->GetInstructionSetFeatures(), + dchecked_integral_cast<uint32_t>(dex_files_->size()), + key_value_store_)); + oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum_); + oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin_); return oat_header_->GetHeaderSize(); } @@ -1043,9 +1133,8 @@ size_t OatWriter::InitOatDexFiles(size_t offset) { for (size_t i = 0; i != dex_files_->size(); ++i) { const DexFile* dex_file = (*dex_files_)[i]; CHECK(dex_file != nullptr); - OatDexFile* oat_dex_file = new OatDexFile(offset, *dex_file); - oat_dex_files_.push_back(oat_dex_file); - offset += oat_dex_file->SizeOf(); + oat_dex_files_.emplace_back(offset, *dex_file); + offset += oat_dex_files_.back().SizeOf(); } return offset; } @@ -1059,12 +1148,12 @@ size_t OatWriter::InitDexFiles(size_t offset) { size_dex_file_alignment_ += offset - original_offset; // set offset in OatDexFile to DexFile - oat_dex_files_[i]->dex_file_offset_ = offset; + oat_dex_files_[i].dex_file_offset_ = offset; const DexFile* dex_file = (*dex_files_)[i]; // Initialize type lookup table - oat_dex_files_[i]->lookup_table_ = dex_file->GetTypeLookupTable(); + oat_dex_files_[i].lookup_table_ = dex_file->GetTypeLookupTable(); offset += dex_file->GetHeader().file_size_; } @@ -1072,14 +1161,14 @@ size_t OatWriter::InitDexFiles(size_t offset) { } size_t OatWriter::InitLookupTables(size_t offset) { - for (OatDexFile* oat_dex_file : oat_dex_files_) { - if (oat_dex_file->lookup_table_ != nullptr) { + for (OatDexFile& oat_dex_file : oat_dex_files_) { + if (oat_dex_file.lookup_table_ != nullptr) { uint32_t aligned_offset = RoundUp(offset, 4); - oat_dex_file->lookup_table_offset_ = aligned_offset; + oat_dex_file.lookup_table_offset_ = aligned_offset; size_oat_lookup_table_alignment_ += aligned_offset - offset; - offset = aligned_offset + oat_dex_file->lookup_table_->RawDataLength(); + offset = aligned_offset + oat_dex_file.lookup_table_->RawDataLength(); } else { - oat_dex_file->lookup_table_offset_ = 0; + oat_dex_file.lookup_table_offset_ = 0; } } return offset; @@ -1094,13 +1183,12 @@ size_t OatWriter::InitOatClasses(size_t offset) { // Update oat_dex_files_. auto oat_class_it = oat_classes_.begin(); - for (OatDexFile* oat_dex_file : oat_dex_files_) { - for (uint32_t& method_offset : oat_dex_file->methods_offsets_) { + for (OatDexFile& oat_dex_file : oat_dex_files_) { + for (uint32_t& class_offset : oat_dex_file.class_offsets_) { DCHECK(oat_class_it != oat_classes_.end()); - method_offset = (*oat_class_it)->offset_; + class_offset = oat_class_it->offset_; ++oat_class_it; } - oat_dex_file->UpdateChecksum(oat_header_); } CHECK(oat_class_it == oat_classes_.end()); @@ -1184,17 +1272,14 @@ size_t OatWriter::InitOatCodeDexFiles(size_t offset) { } bool OatWriter::WriteRodata(OutputStream* out) { - const off_t raw_file_offset = out->Seek(0, kSeekCurrent); - if (raw_file_offset == (off_t) -1) { - LOG(ERROR) << "Failed to get file offset in " << out->GetLocation(); + if (!GetOatDataOffset(out)) { return false; } - const size_t file_offset = static_cast<size_t>(raw_file_offset); - oat_data_offset_ = file_offset; + const size_t file_offset = oat_data_offset_; // Reserve space for header. It will be written last - after updating the checksum. size_t header_size = oat_header_->GetHeaderSize(); - if (out->Seek(header_size, kSeekCurrent) == (off_t) -1) { + if (out->Seek(header_size, kSeekCurrent) == static_cast<off_t>(-1)) { PLOG(ERROR) << "Failed to reserve space for oat header in " << out->GetLocation(); return false; } @@ -1207,7 +1292,7 @@ bool OatWriter::WriteRodata(OutputStream* out) { } off_t tables_end_offset = out->Seek(0, kSeekCurrent); - if (tables_end_offset == (off_t) -1) { + if (tables_end_offset == static_cast<off_t>(-1)) { LOG(ERROR) << "Failed to seek to oat code position in " << out->GetLocation(); return false; } @@ -1252,7 +1337,7 @@ bool OatWriter::WriteCode(OutputStream* out) { } const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent); - if (oat_end_file_offset == (off_t) -1) { + if (oat_end_file_offset == static_cast<off_t>(-1)) { LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation(); return false; } @@ -1288,14 +1373,14 @@ bool OatWriter::WriteCode(OutputStream* out) { DO_STAT(size_oat_dex_file_location_data_); DO_STAT(size_oat_dex_file_location_checksum_); DO_STAT(size_oat_dex_file_offset_); - DO_STAT(size_oat_dex_file_methods_offsets_); + DO_STAT(size_oat_dex_file_lookup_table_offset_); + DO_STAT(size_oat_dex_file_class_offsets_); + DO_STAT(size_oat_lookup_table_alignment_); + DO_STAT(size_oat_lookup_table_); DO_STAT(size_oat_class_type_); DO_STAT(size_oat_class_status_); DO_STAT(size_oat_class_method_bitmaps_); DO_STAT(size_oat_class_method_offsets_); - DO_STAT(size_oat_lookup_table_alignment_); - DO_STAT(size_oat_lookup_table_offset_); - DO_STAT(size_oat_lookup_table_); #undef DO_STAT VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \ @@ -1306,17 +1391,20 @@ bool OatWriter::WriteCode(OutputStream* out) { CHECK_EQ(file_offset + size_, static_cast<size_t>(oat_end_file_offset)); CHECK_EQ(size_, relative_offset); + // Finalize the header checksum. + oat_header_->UpdateChecksumWithHeaderData(); + // Write the header now that the checksum is final. - if (out->Seek(file_offset, kSeekSet) == (off_t) -1) { + if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) { PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation(); return false; } DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent))); - if (!out->WriteFully(oat_header_, header_size)) { + if (!out->WriteFully(oat_header_.get(), header_size)) { PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation(); return false; } - if (out->Seek(oat_end_file_offset, kSeekSet) == (off_t) -1) { + if (out->Seek(oat_end_file_offset, kSeekSet) == static_cast<off_t>(-1)) { PLOG(ERROR) << "Failed to seek to end after writing oat header to " << out->GetLocation(); return false; } @@ -1327,13 +1415,13 @@ bool OatWriter::WriteCode(OutputStream* out) { bool OatWriter::WriteTables(OutputStream* out, const size_t file_offset) { for (size_t i = 0; i != oat_dex_files_.size(); ++i) { - if (!oat_dex_files_[i]->Write(this, out, file_offset)) { + if (!oat_dex_files_[i].Write(this, out, file_offset)) { PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation(); return false; } } for (size_t i = 0; i != oat_dex_files_.size(); ++i) { - uint32_t expected_offset = file_offset + oat_dex_files_[i]->dex_file_offset_; + uint32_t expected_offset = file_offset + oat_dex_files_[i].dex_file_offset_; off_t actual_offset = out->Seek(expected_offset, kSeekSet); if (static_cast<uint32_t>(actual_offset) != expected_offset) { const DexFile* dex_file = (*dex_files_)[i]; @@ -1353,7 +1441,7 @@ bool OatWriter::WriteTables(OutputStream* out, const size_t file_offset) { return false; } for (size_t i = 0; i != oat_classes_.size(); ++i) { - if (!oat_classes_[i]->Write(this, out, file_offset)) { + if (!oat_classes_[i].Write(this, out, file_offset)) { PLOG(ERROR) << "Failed to write oat methods information to " << out->GetLocation(); return false; } @@ -1363,8 +1451,8 @@ bool OatWriter::WriteTables(OutputStream* out, const size_t file_offset) { bool OatWriter::WriteLookupTables(OutputStream* out, const size_t file_offset) { for (size_t i = 0; i < oat_dex_files_.size(); ++i) { - const uint32_t lookup_table_offset = oat_dex_files_[i]->lookup_table_offset_; - const TypeLookupTable* table = oat_dex_files_[i]->lookup_table_; + const uint32_t lookup_table_offset = oat_dex_files_[i].lookup_table_offset_; + const TypeLookupTable* table = oat_dex_files_[i].lookup_table_; DCHECK_EQ(lookup_table_offset == 0, table == nullptr); if (lookup_table_offset == 0) { continue; @@ -1378,7 +1466,7 @@ bool OatWriter::WriteLookupTables(OutputStream* out, const size_t file_offset) { return false; } if (table != nullptr) { - if (!out->WriteFully(table->RawData(), table->RawDataLength())) { + if (!WriteData(out, table->RawData(), table->RawDataLength())) { const DexFile* dex_file = (*dex_files_)[i]; PLOG(ERROR) << "Failed to write lookup table for " << dex_file->GetLocation() << " to " << out->GetLocation(); @@ -1427,7 +1515,7 @@ size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t uint32_t alignment_padding = aligned_offset - relative_offset; \ out->Seek(alignment_padding, kSeekCurrent); \ size_trampoline_alignment_ += alignment_padding; \ - if (!out->WriteFully(&(*field)[0], field->size())) { \ + if (!WriteData(out, field->data(), field->size())) { \ PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \ return false; \ } \ @@ -1469,6 +1557,17 @@ size_t OatWriter::WriteCodeDexFiles(OutputStream* out, return relative_offset; } +bool OatWriter::GetOatDataOffset(OutputStream* out) { + // Get the elf file offset of the oat file. + const off_t raw_file_offset = out->Seek(0, kSeekCurrent); + if (raw_file_offset == static_cast<off_t>(-1)) { + LOG(ERROR) << "Failed to get file offset in " << out->GetLocation(); + return false; + } + oat_data_offset_ = static_cast<size_t>(raw_file_offset); + return true; +} + bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) { static const uint8_t kPadding[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u @@ -1481,6 +1580,11 @@ bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delt return true; } +bool OatWriter::WriteData(OutputStream* out, const void* data, size_t size) { + oat_header_->UpdateChecksum(data, size); + return out->WriteFully(data, size); +} + std::pair<bool, uint32_t> OatWriter::MethodOffsetMap::FindMethodOffset(MethodReference ref) { auto it = map.find(ref); if (it == map.end()) { @@ -1498,7 +1602,7 @@ OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) { dex_file_location_checksum_ = dex_file.GetLocationChecksum(); dex_file_offset_ = 0; lookup_table_offset_ = 0; - methods_offsets_.resize(dex_file.NumClassDefs()); + class_offsets_.resize(dex_file.NumClassDefs()); } size_t OatWriter::OatDexFile::SizeOf() const { @@ -1507,63 +1611,50 @@ size_t OatWriter::OatDexFile::SizeOf() const { + sizeof(dex_file_location_checksum_) + sizeof(dex_file_offset_) + sizeof(lookup_table_offset_) - + (sizeof(methods_offsets_[0]) * methods_offsets_.size()); -} - -void OatWriter::OatDexFile::UpdateChecksum(OatHeader* oat_header) const { - oat_header->UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_)); - oat_header->UpdateChecksum(dex_file_location_data_, dex_file_location_size_); - oat_header->UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_)); - oat_header->UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_)); - oat_header->UpdateChecksum(&lookup_table_offset_, sizeof(lookup_table_offset_)); - if (lookup_table_ != nullptr) { - oat_header->UpdateChecksum(lookup_table_->RawData(), lookup_table_->RawDataLength()); - } - oat_header->UpdateChecksum(&methods_offsets_[0], - sizeof(methods_offsets_[0]) * methods_offsets_.size()); + + (sizeof(class_offsets_[0]) * class_offsets_.size()); } bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const { DCHECK_OFFSET_(); - if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) { + if (!oat_writer->WriteData(out, &dex_file_location_size_, sizeof(dex_file_location_size_))) { PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation(); return false; } oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_); - if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) { + if (!oat_writer->WriteData(out, dex_file_location_data_, dex_file_location_size_)) { PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation(); return false; } oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_; - if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) { + if (!oat_writer->WriteData(out, + &dex_file_location_checksum_, + sizeof(dex_file_location_checksum_))) { PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation(); return false; } oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_); - if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) { + if (!oat_writer->WriteData(out, &dex_file_offset_, sizeof(dex_file_offset_))) { PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation(); return false; } oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_); - if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) { + if (!oat_writer->WriteData(out, &lookup_table_offset_, sizeof(lookup_table_offset_))) { PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation(); return false; } - oat_writer->size_oat_lookup_table_offset_ += sizeof(lookup_table_offset_); - if (!out->WriteFully(&methods_offsets_[0], - sizeof(methods_offsets_[0]) * methods_offsets_.size())) { + oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_); + if (!oat_writer->WriteData(out, class_offsets_.data(), GetClassOffsetsRawSize())) { PLOG(ERROR) << "Failed to write methods offsets to " << out->GetLocation(); return false; } - oat_writer->size_oat_dex_file_methods_offsets_ += - sizeof(methods_offsets_[0]) * methods_offsets_.size(); + oat_writer->size_oat_dex_file_class_offsets_ += GetClassOffsetsRawSize(); return true; } OatWriter::OatClass::OatClass(size_t offset, - const std::vector<CompiledMethod*>& compiled_methods, + const dchecked_vector<CompiledMethod*>& compiled_methods, uint32_t num_non_null_compiled_methods, mirror::Class::Status status) : compiled_methods_(compiled_methods) { @@ -1593,7 +1684,7 @@ OatWriter::OatClass::OatClass(size_t offset, uint32_t oat_method_offsets_offset_from_oat_class = sizeof(type_) + sizeof(status_); if (type_ == kOatClassSomeCompiled) { - method_bitmap_ = new BitVector(num_methods, false, Allocator::GetMallocAllocator()); + method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator())); method_bitmap_size_ = method_bitmap_->GetSizeOf(); oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_); oat_method_offsets_offset_from_oat_class += method_bitmap_size_; @@ -1616,10 +1707,6 @@ OatWriter::OatClass::OatClass(size_t offset, } } -OatWriter::OatClass::~OatClass() { - delete method_bitmap_; -} - size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader( size_t class_def_method_index_) const { uint32_t method_offset = GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_); @@ -1642,51 +1729,42 @@ size_t OatWriter::OatClass::SizeOf() const { + (sizeof(method_offsets_[0]) * method_offsets_.size()); } -void OatWriter::OatClass::UpdateChecksum(OatHeader* oat_header) const { - oat_header->UpdateChecksum(&status_, sizeof(status_)); - oat_header->UpdateChecksum(&type_, sizeof(type_)); - if (method_bitmap_size_ != 0) { - CHECK_EQ(kOatClassSomeCompiled, type_); - oat_header->UpdateChecksum(&method_bitmap_size_, sizeof(method_bitmap_size_)); - oat_header->UpdateChecksum(method_bitmap_->GetRawStorage(), method_bitmap_size_); - } - oat_header->UpdateChecksum(&method_offsets_[0], - sizeof(method_offsets_[0]) * method_offsets_.size()); -} - bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const { DCHECK_OFFSET_(); - if (!out->WriteFully(&status_, sizeof(status_))) { + if (!oat_writer->WriteData(out, &status_, sizeof(status_))) { PLOG(ERROR) << "Failed to write class status to " << out->GetLocation(); return false; } oat_writer->size_oat_class_status_ += sizeof(status_); - if (!out->WriteFully(&type_, sizeof(type_))) { + + if (!oat_writer->WriteData(out, &type_, sizeof(type_))) { PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation(); return false; } oat_writer->size_oat_class_type_ += sizeof(type_); + if (method_bitmap_size_ != 0) { CHECK_EQ(kOatClassSomeCompiled, type_); - if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) { + if (!oat_writer->WriteData(out, &method_bitmap_size_, sizeof(method_bitmap_size_))) { PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation(); return false; } oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_); - if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) { + + if (!oat_writer->WriteData(out, method_bitmap_->GetRawStorage(), method_bitmap_size_)) { PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation(); return false; } oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_; } - if (!out->WriteFully(&method_offsets_[0], - sizeof(method_offsets_[0]) * method_offsets_.size())) { + + if (!oat_writer->WriteData(out, method_offsets_.data(), GetMethodOffsetsRawSize())) { PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation(); return false; } - oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size(); + oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize(); return true; } diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 6c46ebc4ec..5feb5fc516 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -21,12 +21,14 @@ #include <cstddef> #include <memory> +#include "base/dchecked_vector.h" #include "linker/relative_patcher.h" // For linker::RelativePatcherTargetProvider. #include "mem_map.h" #include "method_reference.h" #include "mirror/class.h" #include "oat.h" #include "safe_map.h" +#include "utils/array_ref.h" namespace art { @@ -124,8 +126,8 @@ class OatWriter { return bss_size_; } - const std::vector<uintptr_t>& GetAbsolutePatchLocations() const { - return absolute_patch_locations_; + ArrayRef<const uintptr_t> GetAbsolutePatchLocations() const { + return ArrayRef<const uintptr_t>(absolute_patch_locations_); } bool WriteRodata(OutputStream* out); @@ -133,8 +135,8 @@ class OatWriter { ~OatWriter(); - const std::vector<dwarf::MethodDebugInfo>& GetMethodDebugInfo() const { - return method_info_; + ArrayRef<const dwarf::MethodDebugInfo> GetMethodDebugInfo() const { + return ArrayRef<const dwarf::MethodDebugInfo>(method_info_); } const CompilerDriver* GetCompilerDriver() { @@ -142,6 +144,9 @@ class OatWriter { } private: + class OatClass; + class OatDexFile; + // The DataAccess classes are helper classes that provide access to members related to // a given map, i.e. GC map, mapping table or vmap table. By abstracting these away // we can share a lot of code for processing the maps with template classes below. @@ -175,10 +180,8 @@ class OatWriter { size_t InitDexFiles(size_t offset); size_t InitOatClasses(size_t offset); size_t InitOatMaps(size_t offset); - size_t InitOatCode(size_t offset) - SHARED_REQUIRES(Locks::mutator_lock_); - size_t InitOatCodeDexFiles(size_t offset) - SHARED_REQUIRES(Locks::mutator_lock_); + size_t InitOatCode(size_t offset); + size_t InitOatCodeDexFiles(size_t offset); bool WriteTables(OutputStream* out, const size_t file_offset); bool WriteLookupTables(OutputStream* out, const size_t file_offset); @@ -186,93 +189,11 @@ class OatWriter { size_t WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset); size_t WriteCodeDexFiles(OutputStream* out, const size_t file_offset, size_t relative_offset); + bool GetOatDataOffset(OutputStream* out); bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta); + bool WriteData(OutputStream* out, const void* data, size_t size); - class OatDexFile { - public: - OatDexFile(size_t offset, const DexFile& dex_file); - size_t SizeOf() const; - void UpdateChecksum(OatHeader* oat_header) const; - bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const; - - // Offset of start of OatDexFile from beginning of OatHeader. It is - // used to validate file position when writing. - size_t offset_; - - // data to write - uint32_t dex_file_location_size_; - const uint8_t* dex_file_location_data_; - uint32_t dex_file_location_checksum_; - uint32_t dex_file_offset_; - uint32_t lookup_table_offset_; - TypeLookupTable* lookup_table_; // Owned by the dex file. - std::vector<uint32_t> methods_offsets_; - - private: - DISALLOW_COPY_AND_ASSIGN(OatDexFile); - }; - - class OatClass { - public: - OatClass(size_t offset, - const std::vector<CompiledMethod*>& compiled_methods, - uint32_t num_non_null_compiled_methods, - mirror::Class::Status status); - ~OatClass(); - size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const; - size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const; - size_t SizeOf() const; - void UpdateChecksum(OatHeader* oat_header) const; - bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const; - - CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const { - DCHECK_LT(class_def_method_index, compiled_methods_.size()); - return compiled_methods_[class_def_method_index]; - } - - // Offset of start of OatClass from beginning of OatHeader. It is - // used to validate file position when writing. - size_t offset_; - - // CompiledMethods for each class_def_method_index, or null if no method is available. - std::vector<CompiledMethod*> compiled_methods_; - - // Offset from OatClass::offset_ to the OatMethodOffsets for the - // class_def_method_index. If 0, it means the corresponding - // CompiledMethod entry in OatClass::compiled_methods_ should be - // null and that the OatClass::type_ should be kOatClassBitmap. - std::vector<uint32_t> oat_method_offsets_offsets_from_oat_class_; - - // data to write - - static_assert(mirror::Class::Status::kStatusMax < (2 ^ 16), "class status won't fit in 16bits"); - int16_t status_; - - static_assert(OatClassType::kOatClassMax < (2 ^ 16), "oat_class type won't fit in 16bits"); - uint16_t type_; - - uint32_t method_bitmap_size_; - - // bit vector indexed by ClassDef method index. When - // OatClassType::type_ is kOatClassBitmap, a set bit indicates the - // method has an OatMethodOffsets in methods_offsets_, otherwise - // the entry was ommited to save space. If OatClassType::type_ is - // not is kOatClassBitmap, the bitmap will be null. - BitVector* method_bitmap_; - - // OatMethodOffsets and OatMethodHeaders for each CompiledMethod - // present in the OatClass. Note that some may be missing if - // OatClass::compiled_methods_ contains null values (and - // oat_method_offsets_offsets_from_oat_class_ should contain 0 - // values in this case). - std::vector<OatMethodOffsets> method_offsets_; - std::vector<OatQuickMethodHeader> method_headers_; - - private: - DISALLOW_COPY_AND_ASSIGN(OatClass); - }; - - std::vector<dwarf::MethodDebugInfo> method_info_; + dchecked_vector<dwarf::MethodDebugInfo> method_info_; const CompilerDriver* const compiler_driver_; ImageWriter* const image_writer_; @@ -301,9 +222,9 @@ class OatWriter { // data to write SafeMap<std::string, std::string>* key_value_store_; - OatHeader* oat_header_; - std::vector<OatDexFile*> oat_dex_files_; - std::vector<OatClass*> oat_classes_; + std::unique_ptr<OatHeader> oat_header_; + dchecked_vector<OatDexFile> oat_dex_files_; + dchecked_vector<OatClass> oat_classes_; std::unique_ptr<const std::vector<uint8_t>> jni_dlsym_lookup_; std::unique_ptr<const std::vector<uint8_t>> quick_generic_jni_trampoline_; std::unique_ptr<const std::vector<uint8_t>> quick_imt_conflict_trampoline_; @@ -336,14 +257,14 @@ class OatWriter { uint32_t size_oat_dex_file_location_data_; uint32_t size_oat_dex_file_location_checksum_; uint32_t size_oat_dex_file_offset_; - uint32_t size_oat_dex_file_methods_offsets_; + uint32_t size_oat_dex_file_lookup_table_offset_; + uint32_t size_oat_dex_file_class_offsets_; + uint32_t size_oat_lookup_table_alignment_; + uint32_t size_oat_lookup_table_; uint32_t size_oat_class_type_; uint32_t size_oat_class_status_; uint32_t size_oat_class_method_bitmaps_; uint32_t size_oat_class_method_offsets_; - uint32_t size_oat_lookup_table_alignment_; - uint32_t size_oat_lookup_table_offset_; - uint32_t size_oat_lookup_table_; std::unique_ptr<linker::RelativePatcher> relative_patcher_; diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 0baa0e30dc..53d3615a41 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -246,10 +246,7 @@ void CodeGenerator::CompileInternal(CodeAllocator* allocator, bool is_baseline) InitLocationsBaseline(current); } DCHECK(CheckTypeConsistency(current)); - uintptr_t native_pc_begin = GetAssembler()->CodeSize(); current->Accept(instruction_visitor); - uintptr_t native_pc_end = GetAssembler()->CodeSize(); - RecordNativeDebugInfo(current->GetDexPc(), native_pc_begin, native_pc_end); } } @@ -926,17 +923,6 @@ void CodeGenerator::BuildStackMaps(MemoryRegion region) { stack_map_stream_.FillIn(region); } -void CodeGenerator::RecordNativeDebugInfo(uint32_t dex_pc, - uintptr_t native_pc_begin, - uintptr_t native_pc_end) { - if (compiler_options_.GetGenerateDebugInfo() && - dex_pc != kNoDexPc && - native_pc_begin != native_pc_end) { - src_map_.push_back(SrcMapElem({static_cast<uint32_t>(native_pc_begin), - static_cast<int32_t>(dex_pc)})); - } -} - void CodeGenerator::RecordPcInfo(HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path) { diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 114d97be94..eade05d7b6 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -269,8 +269,6 @@ class CodeGenerator { // Record native to dex mapping for a suspend point. Required by runtime. void RecordPcInfo(HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path = nullptr); - // Record additional native to dex mappings for native debugging/profiling tools. - void RecordNativeDebugInfo(uint32_t dex_pc, uintptr_t native_pc_begin, uintptr_t native_pc_end); bool CanMoveNullCheckToUser(HNullCheck* null_check); void MaybeRecordImplicitNullCheck(HInstruction* instruction); @@ -452,10 +450,6 @@ class CodeGenerator { // Copy the result of a call into the given target. virtual void MoveFromReturnRegister(Location trg, Primitive::Type type) = 0; - const ArenaVector<SrcMapElem>& GetSrcMappingTable() const { - return src_map_; - } - protected: // Method patch info used for recording locations of required linker patches and // target methods. The target method can be used for various purposes, whether for @@ -498,7 +492,6 @@ class CodeGenerator { stats_(stats), graph_(graph), compiler_options_(compiler_options), - src_map_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), slow_paths_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), current_slow_path_(nullptr), current_block_index_(0), @@ -616,8 +609,6 @@ class CodeGenerator { HGraph* const graph_; const CompilerOptions& compiler_options_; - // Native to dex_pc map used for native debugging/profiling tools. - ArenaVector<SrcMapElem> src_map_; ArenaVector<SlowPathCode*> slow_paths_; // The current slow path that we're generating code for. diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 145b1f33b4..7351fed0fa 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -47,6 +47,12 @@ static constexpr FloatRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1 }; static constexpr size_t kRuntimeParameterFpuRegistersLength = arraysize(kRuntimeParameterFpuRegisters); +// These XMM registers are non-volatile in ART ABI, but volatile in native ABI. +// If the ART ABI changes, this list must be updated. It is used to ensure that +// these are not clobbered by any direct call to native code (such as math intrinsics). +static constexpr FloatRegister non_volatile_xmm_regs[] = { XMM12, XMM13, XMM14, XMM15 }; + + class InvokeRuntimeCallingConvention : public CallingConvention<Register, FloatRegister> { public: InvokeRuntimeCallingConvention() diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 834081188b..7127215c51 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -189,6 +189,42 @@ static Intrinsics GetIntrinsic(InlineMethod method) { return ((method.d.data & kIntrinsicFlagMin) == 0) ? Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong; + // More math builtins. + case kIntrinsicCos: + return Intrinsics::kMathCos; + case kIntrinsicSin: + return Intrinsics::kMathSin; + case kIntrinsicAcos: + return Intrinsics::kMathAcos; + case kIntrinsicAsin: + return Intrinsics::kMathAsin; + case kIntrinsicAtan: + return Intrinsics::kMathAtan; + case kIntrinsicAtan2: + return Intrinsics::kMathAtan2; + case kIntrinsicCbrt: + return Intrinsics::kMathCbrt; + case kIntrinsicCosh: + return Intrinsics::kMathCosh; + case kIntrinsicExp: + return Intrinsics::kMathExp; + case kIntrinsicExpm1: + return Intrinsics::kMathExpm1; + case kIntrinsicHypot: + return Intrinsics::kMathHypot; + case kIntrinsicLog: + return Intrinsics::kMathLog; + case kIntrinsicLog10: + return Intrinsics::kMathLog10; + case kIntrinsicNextAfter: + return Intrinsics::kMathNextAfter; + case kIntrinsicSinh: + return Intrinsics::kMathSinh; + case kIntrinsicTan: + return Intrinsics::kMathTan; + case kIntrinsicTanh: + return Intrinsics::kMathTanh; + // Misc math. case kIntrinsicSqrt: return Intrinsics::kMathSqrt; diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 5329b5c1b7..9820c5de0a 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -1718,6 +1718,23 @@ UNIMPLEMENTED_INTRINSIC(UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) +UNIMPLEMENTED_INTRINSIC(MathCos) +UNIMPLEMENTED_INTRINSIC(MathSin) +UNIMPLEMENTED_INTRINSIC(MathAcos) +UNIMPLEMENTED_INTRINSIC(MathAsin) +UNIMPLEMENTED_INTRINSIC(MathAtan) +UNIMPLEMENTED_INTRINSIC(MathAtan2) +UNIMPLEMENTED_INTRINSIC(MathCbrt) +UNIMPLEMENTED_INTRINSIC(MathCosh) +UNIMPLEMENTED_INTRINSIC(MathExp) +UNIMPLEMENTED_INTRINSIC(MathExpm1) +UNIMPLEMENTED_INTRINSIC(MathHypot) +UNIMPLEMENTED_INTRINSIC(MathLog) +UNIMPLEMENTED_INTRINSIC(MathLog10) +UNIMPLEMENTED_INTRINSIC(MathNextAfter) +UNIMPLEMENTED_INTRINSIC(MathSinh) +UNIMPLEMENTED_INTRINSIC(MathTan) +UNIMPLEMENTED_INTRINSIC(MathTanh) #undef UNIMPLEMENTED_INTRINSIC diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 962c4d5167..2e5b022444 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -1532,6 +1532,24 @@ UNIMPLEMENTED_INTRINSIC(SystemArrayCopy) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) +UNIMPLEMENTED_INTRINSIC(MathCos) +UNIMPLEMENTED_INTRINSIC(MathSin) +UNIMPLEMENTED_INTRINSIC(MathAcos) +UNIMPLEMENTED_INTRINSIC(MathAsin) +UNIMPLEMENTED_INTRINSIC(MathAtan) +UNIMPLEMENTED_INTRINSIC(MathAtan2) +UNIMPLEMENTED_INTRINSIC(MathCbrt) +UNIMPLEMENTED_INTRINSIC(MathCosh) +UNIMPLEMENTED_INTRINSIC(MathExp) +UNIMPLEMENTED_INTRINSIC(MathExpm1) +UNIMPLEMENTED_INTRINSIC(MathHypot) +UNIMPLEMENTED_INTRINSIC(MathLog) +UNIMPLEMENTED_INTRINSIC(MathLog10) +UNIMPLEMENTED_INTRINSIC(MathNextAfter) +UNIMPLEMENTED_INTRINSIC(MathSinh) +UNIMPLEMENTED_INTRINSIC(MathTan) +UNIMPLEMENTED_INTRINSIC(MathTanh) + #undef UNIMPLEMENTED_INTRINSIC #undef __ diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h index 8f1d5e1c4d..96f43a0f74 100644 --- a/compiler/optimizing/intrinsics_list.h +++ b/compiler/optimizing/intrinsics_list.h @@ -51,6 +51,23 @@ V(MathMaxFloatFloat, kStatic, kNeedsEnvironmentOrCache) \ V(MathMaxLongLong, kStatic, kNeedsEnvironmentOrCache) \ V(MathMaxIntInt, kStatic, kNeedsEnvironmentOrCache) \ + V(MathCos, kStatic, kNeedsEnvironmentOrCache) \ + V(MathSin, kStatic, kNeedsEnvironmentOrCache) \ + V(MathAcos, kStatic, kNeedsEnvironmentOrCache) \ + V(MathAsin, kStatic, kNeedsEnvironmentOrCache) \ + V(MathAtan, kStatic, kNeedsEnvironmentOrCache) \ + V(MathAtan2, kStatic, kNeedsEnvironmentOrCache) \ + V(MathCbrt, kStatic, kNeedsEnvironmentOrCache) \ + V(MathCosh, kStatic, kNeedsEnvironmentOrCache) \ + V(MathExp, kStatic, kNeedsEnvironmentOrCache) \ + V(MathExpm1, kStatic, kNeedsEnvironmentOrCache) \ + V(MathHypot, kStatic, kNeedsEnvironmentOrCache) \ + V(MathLog, kStatic, kNeedsEnvironmentOrCache) \ + V(MathLog10, kStatic, kNeedsEnvironmentOrCache) \ + V(MathNextAfter, kStatic, kNeedsEnvironmentOrCache) \ + V(MathSinh, kStatic, kNeedsEnvironmentOrCache) \ + V(MathTan, kStatic, kNeedsEnvironmentOrCache) \ + V(MathTanh, kStatic, kNeedsEnvironmentOrCache) \ V(MathSqrt, kStatic, kNeedsEnvironmentOrCache) \ V(MathCeil, kStatic, kNeedsEnvironmentOrCache) \ V(MathFloor, kStatic, kNeedsEnvironmentOrCache) \ diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index 9ecce0e93a..06fab616ad 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -989,6 +989,23 @@ UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(SystemArrayCopy) +UNIMPLEMENTED_INTRINSIC(MathCos) +UNIMPLEMENTED_INTRINSIC(MathSin) +UNIMPLEMENTED_INTRINSIC(MathAcos) +UNIMPLEMENTED_INTRINSIC(MathAsin) +UNIMPLEMENTED_INTRINSIC(MathAtan) +UNIMPLEMENTED_INTRINSIC(MathAtan2) +UNIMPLEMENTED_INTRINSIC(MathCbrt) +UNIMPLEMENTED_INTRINSIC(MathCosh) +UNIMPLEMENTED_INTRINSIC(MathExp) +UNIMPLEMENTED_INTRINSIC(MathExpm1) +UNIMPLEMENTED_INTRINSIC(MathHypot) +UNIMPLEMENTED_INTRINSIC(MathLog) +UNIMPLEMENTED_INTRINSIC(MathLog10) +UNIMPLEMENTED_INTRINSIC(MathNextAfter) +UNIMPLEMENTED_INTRINSIC(MathSinh) +UNIMPLEMENTED_INTRINSIC(MathTan) +UNIMPLEMENTED_INTRINSIC(MathTanh) #undef UNIMPLEMENTED_INTRINSIC #undef __ diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index 36e1b20e4e..8aa7d9ff6f 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -1730,6 +1730,24 @@ UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(SystemArrayCopy) +UNIMPLEMENTED_INTRINSIC(MathCos) +UNIMPLEMENTED_INTRINSIC(MathSin) +UNIMPLEMENTED_INTRINSIC(MathAcos) +UNIMPLEMENTED_INTRINSIC(MathAsin) +UNIMPLEMENTED_INTRINSIC(MathAtan) +UNIMPLEMENTED_INTRINSIC(MathAtan2) +UNIMPLEMENTED_INTRINSIC(MathCbrt) +UNIMPLEMENTED_INTRINSIC(MathCosh) +UNIMPLEMENTED_INTRINSIC(MathExp) +UNIMPLEMENTED_INTRINSIC(MathExpm1) +UNIMPLEMENTED_INTRINSIC(MathHypot) +UNIMPLEMENTED_INTRINSIC(MathLog) +UNIMPLEMENTED_INTRINSIC(MathLog10) +UNIMPLEMENTED_INTRINSIC(MathNextAfter) +UNIMPLEMENTED_INTRINSIC(MathSinh) +UNIMPLEMENTED_INTRINSIC(MathTan) +UNIMPLEMENTED_INTRINSIC(MathTanh) + #undef UNIMPLEMENTED_INTRINSIC #undef __ diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 5b67cdefa3..3370e7301b 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -788,6 +788,195 @@ void IntrinsicCodeGeneratorX86::VisitMathRoundFloat(HInvoke* invoke) { __ Bind(&done); } +static void CreateFPToFPCallLocations(ArenaAllocator* arena, + HInvoke* invoke) { + LocationSummary* locations = new (arena) LocationSummary(invoke, + LocationSummary::kCall, + kIntrinsified); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0))); + locations->SetOut(Location::FpuRegisterLocation(XMM0)); +} + +static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorX86* codegen, QuickEntrypointEnum entry) { + LocationSummary* locations = invoke->GetLocations(); + DCHECK(locations->WillCall()); + DCHECK(invoke->IsInvokeStaticOrDirect()); + X86Assembler* assembler = codegen->GetAssembler(); + + // We need some place to pass the parameters. + __ subl(ESP, Immediate(16)); + __ cfi().AdjustCFAOffset(16); + + // Pass the parameters at the bottom of the stack. + __ movsd(Address(ESP, 0), XMM0); + + // If we have a second parameter, pass it next. + if (invoke->GetNumberOfArguments() == 2) { + __ movsd(Address(ESP, 8), XMM1); + } + + // Now do the actual call. + __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(entry))); + + // Extract the return value from the FP stack. + __ fstpl(Address(ESP, 0)); + __ movsd(XMM0, Address(ESP, 0)); + + // And clean up the stack. + __ addl(ESP, Immediate(16)); + __ cfi().AdjustCFAOffset(-16); + + codegen->RecordPcInfo(invoke, invoke->GetDexPc()); +} + +void IntrinsicLocationsBuilderX86::VisitMathCos(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathCos(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickCos); +} + +void IntrinsicLocationsBuilderX86::VisitMathSin(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathSin(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickSin); +} + +void IntrinsicLocationsBuilderX86::VisitMathAcos(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathAcos(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickAcos); +} + +void IntrinsicLocationsBuilderX86::VisitMathAsin(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathAsin(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickAsin); +} + +void IntrinsicLocationsBuilderX86::VisitMathAtan(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathAtan(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickAtan); +} + +void IntrinsicLocationsBuilderX86::VisitMathCbrt(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathCbrt(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickCbrt); +} + +void IntrinsicLocationsBuilderX86::VisitMathCosh(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathCosh(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickCosh); +} + +void IntrinsicLocationsBuilderX86::VisitMathExp(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathExp(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickExp); +} + +void IntrinsicLocationsBuilderX86::VisitMathExpm1(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathExpm1(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickExpm1); +} + +void IntrinsicLocationsBuilderX86::VisitMathLog(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathLog(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickLog); +} + +void IntrinsicLocationsBuilderX86::VisitMathLog10(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathLog10(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickLog10); +} + +void IntrinsicLocationsBuilderX86::VisitMathSinh(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathSinh(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickSinh); +} + +void IntrinsicLocationsBuilderX86::VisitMathTan(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathTan(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickTan); +} + +void IntrinsicLocationsBuilderX86::VisitMathTanh(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathTanh(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickTanh); +} + +static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, + HInvoke* invoke) { + LocationSummary* locations = new (arena) LocationSummary(invoke, + LocationSummary::kCall, + kIntrinsified); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0))); + locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1))); + locations->SetOut(Location::FpuRegisterLocation(XMM0)); +} + +void IntrinsicLocationsBuilderX86::VisitMathAtan2(HInvoke* invoke) { + CreateFPFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathAtan2(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickAtan2); +} + +void IntrinsicLocationsBuilderX86::VisitMathHypot(HInvoke* invoke) { + CreateFPFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathHypot(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickHypot); +} + +void IntrinsicLocationsBuilderX86::VisitMathNextAfter(HInvoke* invoke) { + CreateFPFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86::VisitMathNextAfter(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickNextAfter); +} + void IntrinsicLocationsBuilderX86::VisitStringCharAt(HInvoke* invoke) { // The inputs plus one temp. LocationSummary* locations = new (arena_) LocationSummary(invoke, diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index ecd129f31e..e862573b65 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -703,6 +703,188 @@ void IntrinsicCodeGeneratorX86_64::VisitMathRoundDouble(HInvoke* invoke) { __ Bind(&done); } +static void CreateFPToFPCallLocations(ArenaAllocator* arena, + HInvoke* invoke) { + LocationSummary* locations = new (arena) LocationSummary(invoke, + LocationSummary::kCall, + kIntrinsified); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0))); + locations->SetOut(Location::FpuRegisterLocation(XMM0)); + + // We have to ensure that the native code doesn't clobber the XMM registers which are + // non-volatile for ART, but volatile for Native calls. This will ensure that they are + // saved in the prologue and properly restored. + for (auto fp_reg : non_volatile_xmm_regs) { + locations->AddTemp(Location::FpuRegisterLocation(fp_reg)); + } +} + +static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorX86_64* codegen, + QuickEntrypointEnum entry) { + LocationSummary* locations = invoke->GetLocations(); + DCHECK(locations->WillCall()); + DCHECK(invoke->IsInvokeStaticOrDirect()); + X86_64Assembler* assembler = codegen->GetAssembler(); + + __ gs()->call(Address::Absolute(GetThreadOffset<kX86_64WordSize>(entry), true)); + codegen->RecordPcInfo(invoke, invoke->GetDexPc()); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathCos(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathCos(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickCos); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathSin(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathSin(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickSin); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathAcos(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathAcos(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickAcos); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathAsin(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathAsin(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickAsin); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathAtan(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathAtan(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickAtan); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathCbrt(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathCbrt(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickCbrt); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathCosh(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathCosh(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickCosh); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathExp(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathExp(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickExp); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathExpm1(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathExpm1(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickExpm1); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathLog(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathLog(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickLog); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathLog10(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathLog10(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickLog10); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathSinh(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathSinh(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickSinh); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathTan(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathTan(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickTan); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathTanh(HInvoke* invoke) { + CreateFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathTanh(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickTanh); +} + +static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, + HInvoke* invoke) { + LocationSummary* locations = new (arena) LocationSummary(invoke, + LocationSummary::kCall, + kIntrinsified); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0))); + locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1))); + locations->SetOut(Location::FpuRegisterLocation(XMM0)); + + // We have to ensure that the native code doesn't clobber the XMM registers which are + // non-volatile for ART, but volatile for Native calls. This will ensure that they are + // saved in the prologue and properly restored. + for (auto fp_reg : non_volatile_xmm_regs) { + locations->AddTemp(Location::FpuRegisterLocation(fp_reg)); + } +} + +void IntrinsicLocationsBuilderX86_64::VisitMathAtan2(HInvoke* invoke) { + CreateFPFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathAtan2(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickAtan2); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathHypot(HInvoke* invoke) { + CreateFPFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathHypot(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickHypot); +} + +void IntrinsicLocationsBuilderX86_64::VisitMathNextAfter(HInvoke* invoke) { + CreateFPFPToFPCallLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorX86_64::VisitMathNextAfter(HInvoke* invoke) { + GenFPToFPCall(invoke, codegen_, kQuickNextAfter); +} + void IntrinsicLocationsBuilderX86_64::VisitStringCharAt(HInvoke* invoke) { // The inputs plus one temp. LocationSummary* locations = new (arena_) LocationSummary(invoke, diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 389ada7504..adde00464b 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -335,16 +335,24 @@ class HeapLocationCollector : public HGraphVisitor { return true; } - ReferenceInfo* GetOrCreateReferenceInfo(HInstruction* ref) { - ReferenceInfo* ref_info = FindReferenceInfoOf(ref); + ReferenceInfo* GetOrCreateReferenceInfo(HInstruction* instruction) { + ReferenceInfo* ref_info = FindReferenceInfoOf(instruction); if (ref_info == nullptr) { size_t pos = ref_info_array_.size(); - ref_info = new (GetGraph()->GetArena()) ReferenceInfo(ref, pos); + ref_info = new (GetGraph()->GetArena()) ReferenceInfo(instruction, pos); ref_info_array_.push_back(ref_info); } return ref_info; } + void CreateReferenceInfoForReferenceType(HInstruction* instruction) { + if (instruction->GetType() != Primitive::kPrimNot) { + return; + } + DCHECK(FindReferenceInfoOf(instruction) == nullptr); + GetOrCreateReferenceInfo(instruction); + } + HeapLocation* GetOrCreateHeapLocation(HInstruction* ref, size_t offset, HInstruction* index, @@ -378,6 +386,7 @@ class HeapLocationCollector : public HGraphVisitor { void VisitInstanceFieldGet(HInstanceFieldGet* instruction) OVERRIDE { VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo()); + CreateReferenceInfoForReferenceType(instruction); } void VisitInstanceFieldSet(HInstanceFieldSet* instruction) OVERRIDE { @@ -387,6 +396,7 @@ class HeapLocationCollector : public HGraphVisitor { void VisitStaticFieldGet(HStaticFieldGet* instruction) OVERRIDE { VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo()); + CreateReferenceInfoForReferenceType(instruction); } void VisitStaticFieldSet(HStaticFieldSet* instruction) OVERRIDE { @@ -399,6 +409,7 @@ class HeapLocationCollector : public HGraphVisitor { void VisitArrayGet(HArrayGet* instruction) OVERRIDE { VisitArrayAccess(instruction->InputAt(0), instruction->InputAt(1)); + CreateReferenceInfoForReferenceType(instruction); } void VisitArraySet(HArraySet* instruction) OVERRIDE { @@ -408,7 +419,23 @@ class HeapLocationCollector : public HGraphVisitor { void VisitNewInstance(HNewInstance* new_instance) OVERRIDE { // Any references appearing in the ref_info_array_ so far cannot alias with new_instance. - GetOrCreateReferenceInfo(new_instance); + CreateReferenceInfoForReferenceType(new_instance); + } + + void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* instruction) OVERRIDE { + CreateReferenceInfoForReferenceType(instruction); + } + + void VisitInvokeVirtual(HInvokeVirtual* instruction) OVERRIDE { + CreateReferenceInfoForReferenceType(instruction); + } + + void VisitInvokeInterface(HInvokeInterface* instruction) OVERRIDE { + CreateReferenceInfoForReferenceType(instruction); + } + + void VisitParameterValue(HParameterValue* instruction) OVERRIDE { + CreateReferenceInfoForReferenceType(instruction); } void VisitDeoptimize(HDeoptimize* instruction ATTRIBUTE_UNUSED) OVERRIDE { diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 4643aed9cc..831b626c4f 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -614,7 +614,7 @@ CompiledMethod* OptimizingCompiler::EmitOptimized(ArenaAllocator* arena, codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(), codegen->GetCoreSpillMask(), codegen->GetFpuSpillMask(), - ArrayRef<const SrcMapElem>(codegen->GetSrcMappingTable()), + ArrayRef<const SrcMapElem>(), ArrayRef<const uint8_t>(), // mapping_table. ArrayRef<const uint8_t>(stack_map), ArrayRef<const uint8_t>(), // native_gc_map. @@ -648,7 +648,7 @@ CompiledMethod* OptimizingCompiler::EmitBaseline( codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(), codegen->GetCoreSpillMask(), codegen->GetFpuSpillMask(), - ArrayRef<const SrcMapElem>(codegen->GetSrcMappingTable()), + ArrayRef<const SrcMapElem>(), AlignVectorSize(mapping_table), AlignVectorSize(vmap_table), AlignVectorSize(gc_map), diff --git a/compiler/trampolines/trampoline_compiler.h b/compiler/trampolines/trampoline_compiler.h index 9fb22452ea..66d5ac3b53 100644 --- a/compiler/trampolines/trampoline_compiler.h +++ b/compiler/trampolines/trampoline_compiler.h @@ -25,12 +25,12 @@ namespace art { // Create code that will invoke the function held in thread local storage. -const std::vector<uint8_t>* CreateTrampoline32(InstructionSet isa, EntryPointCallingConvention abi, - ThreadOffset<4> entry_point_offset) - SHARED_REQUIRES(Locks::mutator_lock_); -const std::vector<uint8_t>* CreateTrampoline64(InstructionSet isa, EntryPointCallingConvention abi, - ThreadOffset<8> entry_point_offset) - SHARED_REQUIRES(Locks::mutator_lock_); +const std::vector<uint8_t>* CreateTrampoline32(InstructionSet isa, + EntryPointCallingConvention abi, + ThreadOffset<4> entry_point_offset); +const std::vector<uint8_t>* CreateTrampoline64(InstructionSet isa, + EntryPointCallingConvention abi, + ThreadOffset<8> entry_point_offset); } // namespace art diff --git a/dex2oat/Android.mk b/dex2oat/Android.mk index f10acf9d7b..77f8d6cd9f 100644 --- a/dex2oat/Android.mk +++ b/dex2oat/Android.mk @@ -57,18 +57,18 @@ endif # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target. ifeq ($(ART_BUILD_HOST_NDEBUG),true) - $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler libsigchain libziparchive-host,art/compiler,host,ndebug,$(dex2oat_host_arch))) + $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler libsigchain libziparchive-host liblz4,art/compiler,host,ndebug,$(dex2oat_host_arch))) ifeq ($(ART_BUILD_HOST_STATIC),true) $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libart libart-compiler libart libziparchive-host libnativehelper libnativebridge libsigchain_dummy libvixl liblog libz \ - libbacktrace libLLVMObject libLLVMBitReader libLLVMMC libLLVMMCParser libLLVMCore libLLVMSupport libcutils libunwindbacktrace libutils libbase,art/compiler,host,ndebug,$(dex2oat_host_arch),static)) + libbacktrace libLLVMObject libLLVMBitReader libLLVMMC libLLVMMCParser libLLVMCore libLLVMSupport libcutils libunwindbacktrace libutils libbase liblz4,art/compiler,host,ndebug,$(dex2oat_host_arch),static)) endif endif ifeq ($(ART_BUILD_HOST_DEBUG),true) - $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler libsigchain libziparchive-host,art/compiler,host,debug,$(dex2oat_host_arch))) + $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler libsigchain libziparchive-host liblz4,art/compiler,host,debug,$(dex2oat_host_arch))) ifeq ($(ART_BUILD_HOST_STATIC),true) $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libartd libartd-compiler libartd libziparchive-host libnativehelper libnativebridge libsigchain_dummy libvixld liblog libz \ - libbacktrace libLLVMObject libLLVMBitReader libLLVMMC libLLVMMCParser libLLVMCore libLLVMSupport libcutils libunwindbacktrace libutils libbase,art/compiler,host,debug,$(dex2oat_host_arch),static)) + libbacktrace libLLVMObject libLLVMBitReader libLLVMMC libLLVMMCParser libLLVMCore libLLVMSupport libcutils libunwindbacktrace libutils libbase liblz4,art/compiler,host,debug,$(dex2oat_host_arch),static)) endif endif diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 2aa4085fb1..6fae8e4109 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -71,6 +71,7 @@ #include "oat_writer.h" #include "os.h" #include "runtime.h" +#include "runtime_options.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" #include "utils.h" @@ -208,6 +209,11 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(" --image=<file.art>: specifies the output image filename."); UsageError(" Example: --image=/system/framework/boot.art"); UsageError(""); + UsageError(" --image-format=(uncompressed|lz4):"); + UsageError(" Which format to store the image."); + UsageError(" Example: --image-format=lz4"); + UsageError(" Default: uncompressed"); + UsageError(""); UsageError(" --image-classes=<classname-file>: specifies classes to include in an image."); UsageError(" Example: --image=frameworks/base/preloaded-classes"); UsageError(""); @@ -490,6 +496,7 @@ class Dex2Oat FINAL { image_base_(0U), image_classes_zip_filename_(nullptr), image_classes_filename_(nullptr), + image_storage_mode_(ImageHeader::kStorageModeUncompressed), compiled_classes_zip_filename_(nullptr), compiled_classes_filename_(nullptr), compiled_methods_zip_filename_(nullptr), @@ -621,6 +628,19 @@ class Dex2Oat FINAL { } } + void ParseImageFormat(const StringPiece& option) { + const StringPiece substr("--image-format="); + DCHECK(option.starts_with(substr)); + const StringPiece format_str = option.substr(substr.length()); + if (format_str == "lz4") { + image_storage_mode_ = ImageHeader::kStorageModeLZ4; + } else if (format_str == "uncompressed") { + image_storage_mode_ = ImageHeader::kStorageModeUncompressed; + } else { + Usage("Unknown image format: %s", format_str.data()); + } + } + void ProcessOptions(ParserOptions* parser_options) { boot_image_ = !image_filename_.empty(); app_image_ = app_image_fd_ != -1 || !app_image_file_name_.empty(); @@ -667,15 +687,14 @@ class Dex2Oat FINAL { parser_options->boot_image_filename += "/framework/boot.art"; } if (!parser_options->boot_image_filename.empty()) { - boot_image_option_ += "-Ximage:"; - boot_image_option_ += parser_options->boot_image_filename; + boot_image_filename_ = parser_options->boot_image_filename; } if (image_classes_filename_ != nullptr && !IsBootImage()) { Usage("--image-classes should only be used with --image"); } - if (image_classes_filename_ != nullptr && !boot_image_option_.empty()) { + if (image_classes_filename_ != nullptr && !boot_image_filename_.empty()) { Usage("--image-classes should not be used with --boot-image"); } @@ -687,7 +706,7 @@ class Dex2Oat FINAL { Usage("--compiled-classes should only be used with --image"); } - if (compiled_classes_filename_ != nullptr && !boot_image_option_.empty()) { + if (compiled_classes_filename_ != nullptr && !boot_image_filename_.empty()) { Usage("--compiled-classes should not be used with --boot-image"); } @@ -719,7 +738,7 @@ class Dex2Oat FINAL { Usage("--zip-location should be supplied with --zip-fd"); } - if (boot_image_option_.empty()) { + if (boot_image_filename_.empty()) { if (image_base_ == 0) { Usage("Non-zero --base not specified"); } @@ -877,6 +896,8 @@ class Dex2Oat FINAL { image_classes_filename_ = option.substr(strlen("--image-classes=")).data(); } else if (option.starts_with("--image-classes-zip=")) { image_classes_zip_filename_ = option.substr(strlen("--image-classes-zip=")).data(); + } else if (option.starts_with("--image-format=")) { + ParseImageFormat(option); } else if (option.starts_with("--compiled-classes=")) { compiled_classes_filename_ = option.substr(strlen("--compiled-classes=")).data(); } else if (option.starts_with("--compiled-classes-zip=")) { @@ -1014,20 +1035,10 @@ class Dex2Oat FINAL { // boot class path. bool Setup() { TimingLogger::ScopedTiming t("dex2oat Setup", timings_); - RuntimeOptions runtime_options; art::MemMap::Init(); // For ZipEntry::ExtractToMemMap. - if (boot_image_option_.empty()) { - std::string boot_class_path = "-Xbootclasspath:"; - boot_class_path += Join(dex_filenames_, ':'); - runtime_options.push_back(std::make_pair(boot_class_path, nullptr)); - std::string boot_class_path_locations = "-Xbootclasspath-locations:"; - boot_class_path_locations += Join(dex_locations_, ':'); - runtime_options.push_back(std::make_pair(boot_class_path_locations, nullptr)); - } else { - runtime_options.push_back(std::make_pair(boot_image_option_, nullptr)); - } - for (size_t i = 0; i < runtime_args_.size(); i++) { - runtime_options.push_back(std::make_pair(runtime_args_[i], nullptr)); + + if (!PrepareImageClasses() || !PrepareCompiledClasses() || !PrepareCompiledMethods()) { + return false; } verification_results_.reset(new VerificationResults(compiler_options_.get())); @@ -1037,23 +1048,15 @@ class Dex2Oat FINAL { IsBootImage() ? CompilerCallbacks::CallbackMode::kCompileBootImage : CompilerCallbacks::CallbackMode::kCompileApp)); - runtime_options.push_back(std::make_pair("compilercallbacks", callbacks_.get())); - runtime_options.push_back( - std::make_pair("imageinstructionset", GetInstructionSetString(instruction_set_))); - // Only allow no boot image for the runtime if we're compiling one. When we compile an app, - // we don't want fallback mode, it will abort as we do not push a boot classpath (it might - // have been stripped in preopting, anyways). - if (!IsBootImage()) { - runtime_options.push_back(std::make_pair("-Xno-dex-file-fallback", nullptr)); + RuntimeArgumentMap runtime_options; + if (!PrepareRuntimeOptions(&runtime_options)) { + return false; } - // Disable libsigchain. We don't don't need it during compilation and it prevents us - // from getting a statically linked version of dex2oat (because of dlsym and RTLD_NEXT). - runtime_options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); { TimingLogger::ScopedTiming t_runtime("Create runtime", timings_); - if (!CreateRuntime(runtime_options)) { + if (!CreateRuntime(std::move(runtime_options))) { return false; } } @@ -1068,66 +1071,8 @@ class Dex2Oat FINAL { // Whilst we're in native take the opportunity to initialize well known classes. WellKnownClasses::Init(self->GetJniEnv()); - // If --image-classes was specified, calculate the full list of classes to include in the image - if (image_classes_filename_ != nullptr) { - std::string error_msg; - if (image_classes_zip_filename_ != nullptr) { - image_classes_.reset(ReadImageClassesFromZip(image_classes_zip_filename_, - image_classes_filename_, - &error_msg)); - } else { - image_classes_.reset(ReadImageClassesFromFile(image_classes_filename_)); - } - if (image_classes_.get() == nullptr) { - LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename_ << - "': " << error_msg; - return false; - } - } else if (IsBootImage()) { - image_classes_.reset(new std::unordered_set<std::string>); - } - // If --compiled-classes was specified, calculate the full list of classes to compile in the - // image. - if (compiled_classes_filename_ != nullptr) { - std::string error_msg; - if (compiled_classes_zip_filename_ != nullptr) { - compiled_classes_.reset(ReadImageClassesFromZip(compiled_classes_zip_filename_, - compiled_classes_filename_, - &error_msg)); - } else { - compiled_classes_.reset(ReadImageClassesFromFile(compiled_classes_filename_)); - } - if (compiled_classes_.get() == nullptr) { - LOG(ERROR) << "Failed to create list of compiled classes from '" - << compiled_classes_filename_ << "': " << error_msg; - return false; - } - } else { - compiled_classes_.reset(nullptr); // By default compile everything. - } - // If --compiled-methods was specified, read the methods to compile from the given file(s). - if (compiled_methods_filename_ != nullptr) { - std::string error_msg; - if (compiled_methods_zip_filename_ != nullptr) { - compiled_methods_.reset(ReadCommentedInputFromZip(compiled_methods_zip_filename_, - compiled_methods_filename_, - nullptr, // No post-processing. - &error_msg)); - } else { - compiled_methods_.reset(ReadCommentedInputFromFile(compiled_methods_filename_, - nullptr)); // No post-processing. - } - if (compiled_methods_.get() == nullptr) { - LOG(ERROR) << "Failed to create list of compiled methods from '" - << compiled_methods_filename_ << "': " << error_msg; - return false; - } - } else { - compiled_methods_.reset(nullptr); // By default compile everything. - } - ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); - if (boot_image_option_.empty()) { + if (boot_image_filename_.empty()) { dex_files_ = class_linker->GetBootClassPath(); } else { TimingLogger::ScopedTiming t_dex("Opening dex files", timings_); @@ -1164,22 +1109,7 @@ class Dex2Oat FINAL { constexpr bool kSaveDexInput = false; if (kSaveDexInput) { - for (size_t i = 0; i < dex_files_.size(); ++i) { - const DexFile* dex_file = dex_files_[i]; - std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", - getpid(), i)); - std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str())); - if (tmp_file.get() == nullptr) { - PLOG(ERROR) << "Failed to open file " << tmp_file_name - << ". Try: adb shell chmod 777 /data/local/tmp"; - continue; - } - // This is just dumping files for debugging. Ignore errors, and leave remnants. - UNUSED(tmp_file->WriteFully(dex_file->Begin(), dex_file->Size())); - UNUSED(tmp_file->Flush()); - UNUSED(tmp_file->Close()); - LOG(INFO) << "Wrote input to " << tmp_file_name; - } + SaveDexInput(); } } // Ensure opened dex files are writable for dex-to-dex transformations. Also ensure that @@ -1238,16 +1168,13 @@ class Dex2Oat FINAL { jobject class_path_class_loader = nullptr; Thread* self = Thread::Current(); - if (!boot_image_option_.empty()) { + if (!boot_image_filename_.empty()) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); OpenClassPathFiles(runtime_->GetClassPathString(), dex_files_, &class_path_files_); ScopedObjectAccess soa(self); // Classpath: first the class-path given. - std::vector<const DexFile*> class_path_files; - for (auto& class_path_file : class_path_files_) { - class_path_files.push_back(class_path_file.get()); - } + std::vector<const DexFile*> class_path_files = MakeNonOwningPointerVector(class_path_files_); // Store the classpath we have right now. key_value_store_->Put(OatHeader::kClassPathKey, @@ -1432,14 +1359,9 @@ class Dex2Oat FINAL { elf_writer->EndText(text); elf_writer->SetBssSize(oat_writer->GetBssSize()); - elf_writer->WriteDynamicSection(); - - ArrayRef<const dwarf::MethodDebugInfo> method_infos(oat_writer->GetMethodDebugInfo()); - elf_writer->WriteDebugInfo(method_infos); - - ArrayRef<const uintptr_t> patch_locations(oat_writer->GetAbsolutePatchLocations()); - elf_writer->WritePatchLocations(patch_locations); + elf_writer->WriteDebugInfo(oat_writer->GetMethodDebugInfo()); + elf_writer->WritePatchLocations(oat_writer->GetAbsolutePatchLocations()); if (!elf_writer->End()) { LOG(ERROR) << "Failed to write ELF file " << oat_file_->GetPath(); @@ -1552,6 +1474,16 @@ class Dex2Oat FINAL { } private: + template <typename T> + static std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) { + std::vector<T*> result; + result.reserve(src.size()); + for (const std::unique_ptr<T>& t : src) { + result.push_back(t.get()); + } + return result; + } + static size_t OpenDexFiles(const std::vector<const char*>& dex_filenames, const std::vector<const char*>& dex_locations, std::vector<std::unique_ptr<const DexFile>>* dex_files) { @@ -1612,10 +1544,138 @@ class Dex2Oat FINAL { } } + bool PrepareImageClasses() { + // If --image-classes was specified, calculate the full list of classes to include in the image. + if (image_classes_filename_ != nullptr) { + image_classes_ = + ReadClasses(image_classes_zip_filename_, image_classes_filename_, "image"); + if (image_classes_ == nullptr) { + return false; + } + } else if (IsBootImage()) { + image_classes_.reset(new std::unordered_set<std::string>); + } + return true; + } + + bool PrepareCompiledClasses() { + // If --compiled-classes was specified, calculate the full list of classes to compile in the + // image. + if (compiled_classes_filename_ != nullptr) { + compiled_classes_ = + ReadClasses(compiled_classes_zip_filename_, compiled_classes_filename_, "compiled"); + if (compiled_classes_ == nullptr) { + return false; + } + } else { + compiled_classes_.reset(nullptr); // By default compile everything. + } + return true; + } + + static std::unique_ptr<std::unordered_set<std::string>> ReadClasses(const char* zip_filename, + const char* classes_filename, + const char* tag) { + std::unique_ptr<std::unordered_set<std::string>> classes; + std::string error_msg; + if (zip_filename != nullptr) { + classes.reset(ReadImageClassesFromZip(zip_filename, classes_filename, &error_msg)); + } else { + classes.reset(ReadImageClassesFromFile(classes_filename)); + } + if (classes == nullptr) { + LOG(ERROR) << "Failed to create list of " << tag << " classes from '" + << classes_filename << "': " << error_msg; + } + return classes; + } + + bool PrepareCompiledMethods() { + // If --compiled-methods was specified, read the methods to compile from the given file(s). + if (compiled_methods_filename_ != nullptr) { + std::string error_msg; + if (compiled_methods_zip_filename_ != nullptr) { + compiled_methods_.reset(ReadCommentedInputFromZip(compiled_methods_zip_filename_, + compiled_methods_filename_, + nullptr, // No post-processing. + &error_msg)); + } else { + compiled_methods_.reset(ReadCommentedInputFromFile(compiled_methods_filename_, + nullptr)); // No post-processing. + } + if (compiled_methods_.get() == nullptr) { + LOG(ERROR) << "Failed to create list of compiled methods from '" + << compiled_methods_filename_ << "': " << error_msg; + return false; + } + } else { + compiled_methods_.reset(nullptr); // By default compile everything. + } + return true; + } + + void SaveDexInput() { + for (size_t i = 0; i < dex_files_.size(); ++i) { + const DexFile* dex_file = dex_files_[i]; + std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", + getpid(), i)); + std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str())); + if (tmp_file.get() == nullptr) { + PLOG(ERROR) << "Failed to open file " << tmp_file_name + << ". Try: adb shell chmod 777 /data/local/tmp"; + continue; + } + // This is just dumping files for debugging. Ignore errors, and leave remnants. + UNUSED(tmp_file->WriteFully(dex_file->Begin(), dex_file->Size())); + UNUSED(tmp_file->Flush()); + UNUSED(tmp_file->Close()); + LOG(INFO) << "Wrote input to " << tmp_file_name; + } + } + + bool PrepareRuntimeOptions(RuntimeArgumentMap* runtime_options) { + RuntimeOptions raw_options; + if (boot_image_filename_.empty()) { + std::string boot_class_path = "-Xbootclasspath:"; + boot_class_path += Join(dex_filenames_, ':'); + raw_options.push_back(std::make_pair(boot_class_path, nullptr)); + std::string boot_class_path_locations = "-Xbootclasspath-locations:"; + boot_class_path_locations += Join(dex_locations_, ':'); + raw_options.push_back(std::make_pair(boot_class_path_locations, nullptr)); + } else { + std::string boot_image_option = "-Ximage:"; + boot_image_option += boot_image_filename_; + raw_options.push_back(std::make_pair(boot_image_option, nullptr)); + } + for (size_t i = 0; i < runtime_args_.size(); i++) { + raw_options.push_back(std::make_pair(runtime_args_[i], nullptr)); + } + + raw_options.push_back(std::make_pair("compilercallbacks", callbacks_.get())); + raw_options.push_back( + std::make_pair("imageinstructionset", GetInstructionSetString(instruction_set_))); + + // Only allow no boot image for the runtime if we're compiling one. When we compile an app, + // we don't want fallback mode, it will abort as we do not push a boot classpath (it might + // have been stripped in preopting, anyways). + if (!IsBootImage()) { + raw_options.push_back(std::make_pair("-Xno-dex-file-fallback", nullptr)); + } + // Disable libsigchain. We don't don't need it during compilation and it prevents us + // from getting a statically linked version of dex2oat (because of dlsym and RTLD_NEXT). + raw_options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); + + if (!Runtime::ParseOptions(raw_options, false, runtime_options)) { + LOG(ERROR) << "Failed to parse runtime options"; + return false; + } + return true; + } + // Create a runtime necessary for compilation. - bool CreateRuntime(const RuntimeOptions& runtime_options) + bool CreateRuntime(RuntimeArgumentMap&& runtime_options) SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) { - if (!Runtime::Create(runtime_options, false)) { + if (!Runtime::Create(std::move(runtime_options))) { LOG(ERROR) << "Failed to create runtime"; return false; } @@ -1643,7 +1703,8 @@ class Dex2Oat FINAL { image_writer_.reset(new ImageWriter(*driver_, image_base, compiler_options_->GetCompilePic(), - IsAppImage())); + IsAppImage(), + image_storage_mode_)); } // Let the ImageWriter write the image file. If we do not compile PIC, also fix up the oat file. @@ -1812,12 +1873,13 @@ class Dex2Oat FINAL { std::vector<const char*> dex_locations_; int zip_fd_; std::string zip_location_; - std::string boot_image_option_; + std::string boot_image_filename_; std::vector<const char*> runtime_args_; std::string image_filename_; uintptr_t image_base_; const char* image_classes_zip_filename_; const char* image_classes_filename_; + ImageHeader::StorageMode image_storage_mode_; const char* compiled_classes_zip_filename_; const char* compiled_classes_filename_; const char* compiled_methods_zip_filename_; diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index 52e6c023fe..d38772659b 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -27,7 +27,6 @@ * Differences between XML output and the "current.xml" file: * - classes in same package are not all grouped together; nothing is sorted * - no "deprecated" on fields and methods - * - no "value" on fields * - no parameter names * - no generic signatures on parameters, e.g. type="java.lang.Class<?>" * - class shows declared fields and methods; does not show inherited fields @@ -1019,9 +1018,126 @@ static void dumpMethod(const DexFile* pDexFile, u4 idx, u4 flags, } /* + * Dumps a string value with some escape characters. + */ +static void dumpEscapedString(const char* p) { + for (; *p; p++) { + switch (*p) { + case '\\': + fputs("\\\\", gOutFile); + break; + case '\"': + fputs("\\\"", gOutFile); + break; + case '\t': + fputs("\\t", gOutFile); + break; + case '\n': + fputs("\\n", gOutFile); + break; + case '\r': + fputs("\\r", gOutFile); + break; + default: + putc(*p, gOutFile); + } + } +} + +/* + * Dumps an XML attribute value between double-quotes. + */ +static void dumpXmlAttribute(const char* p) { + for (; *p; p++) { + switch (*p) { + case '&': + fputs("&", gOutFile); + break; + case '<': + fputs("<", gOutFile); + break; + case '"': + fputs(""", gOutFile); + break; + case '\t': + fputs("	", gOutFile); + break; + case '\n': + fputs("
", gOutFile); + break; + case '\r': + fputs("
", gOutFile); + break; + default: + putc(*p, gOutFile); + } + } +} + +/* + * Dumps a value of static (class) field. + */ +static void dumpSFieldValue(const DexFile* pDexFile, + EncodedStaticFieldValueIterator::ValueType valueType, + const jvalue* pValue) { + switch (valueType) { + case EncodedStaticFieldValueIterator::kByte: + fprintf(gOutFile, "%" PRIu8, pValue->b); + break; + case EncodedStaticFieldValueIterator::kShort: + fprintf(gOutFile, "%" PRId16, pValue->s); + break; + case EncodedStaticFieldValueIterator::kChar: + fprintf(gOutFile, "%" PRIu16, pValue->c); + break; + case EncodedStaticFieldValueIterator::kInt: + fprintf(gOutFile, "%" PRId32, pValue->i); + break; + case EncodedStaticFieldValueIterator::kLong: + fprintf(gOutFile, "%" PRId64, pValue->j); + break; + case EncodedStaticFieldValueIterator::kFloat: + fprintf(gOutFile, "%f", pValue->f); + break; + case EncodedStaticFieldValueIterator::kDouble: + fprintf(gOutFile, "%f", pValue->d); + break; + case EncodedStaticFieldValueIterator::kString: { + const char* str = + pDexFile->GetStringData(pDexFile->GetStringId(pValue->i)); + if (gOptions.outputFormat == OUTPUT_PLAIN) { + fputs("\"", gOutFile); + dumpEscapedString(str); + fputs("\"", gOutFile); + } else { + dumpXmlAttribute(str); + } + break; + } + case EncodedStaticFieldValueIterator::kNull: + fputs("null", gOutFile); + break; + case EncodedStaticFieldValueIterator::kBoolean: + fputs(pValue->z ? "true" : "false", gOutFile); + break; + + case EncodedStaticFieldValueIterator::kAnnotation: + case EncodedStaticFieldValueIterator::kArray: + case EncodedStaticFieldValueIterator::kEnum: + case EncodedStaticFieldValueIterator::kField: + case EncodedStaticFieldValueIterator::kMethod: + case EncodedStaticFieldValueIterator::kType: + default: + fprintf(gOutFile, "Unexpected static field type: %d", valueType); + } +} + +/* * Dumps a static (class) field. */ -static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i) { +static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i, + EncodedStaticFieldValueIterator::ValueType valueType, + const jvalue* pValue) { // Bail for anything private if export only requested. if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) { return; @@ -1038,6 +1154,11 @@ static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i) { fprintf(gOutFile, " name : '%s'\n", name); fprintf(gOutFile, " type : '%s'\n", typeDescriptor); fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr); + if (pValue != nullptr) { + fputs(" value : ", gOutFile); + dumpSFieldValue(pDexFile, valueType, pValue); + fputs("\n", gOutFile); + } } else if (gOptions.outputFormat == OUTPUT_XML) { fprintf(gOutFile, "<field name=\"%s\"\n", name); char *tmp = descriptorToDot(typeDescriptor); @@ -1050,7 +1171,12 @@ static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i) { fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0)); // The "deprecated=" is not knowable w/o parsing annotations. fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags)); - fprintf(gOutFile, ">\n</field>\n"); + if (pValue != nullptr) { + fputs(" value=\"", gOutFile); + dumpSFieldValue(pDexFile, valueType, pValue); + fputs("\"\n", gOutFile); + } + fputs(">\n</field>\n", gOutFile); } free(accessStr); @@ -1060,7 +1186,8 @@ static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i) { * Dumps an instance field. */ static void dumpIField(const DexFile* pDexFile, u4 idx, u4 flags, int i) { - dumpSField(pDexFile, idx, flags, i); + dumpSField(pDexFile, idx, flags, i, + EncodedStaticFieldValueIterator::kByte, nullptr); } /* @@ -1222,10 +1349,23 @@ static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) { if (gOptions.outputFormat == OUTPUT_PLAIN) { fprintf(gOutFile, " Static fields -\n"); } + EncodedStaticFieldValueIterator staticFieldValues(*pDexFile, pClassDef); for (int i = 0; pClassData.HasNextStaticField(); i++, pClassData.Next()) { + EncodedStaticFieldValueIterator::ValueType valueType = + EncodedStaticFieldValueIterator::kByte; + const jvalue* pValue = nullptr; + if (staticFieldValues.HasNext()) { + valueType = staticFieldValues.GetValueType(); + pValue = &staticFieldValues.GetJavaValue(); + } dumpSField(pDexFile, pClassData.GetMemberIndex(), - pClassData.GetRawMemberAccessFlags(), i); + pClassData.GetRawMemberAccessFlags(), i, + valueType, pValue); + if (staticFieldValues.HasNext()) { + staticFieldValues.Next(); + } } // for + DCHECK(!staticFieldValues.HasNext()); if (gOptions.outputFormat == OUTPUT_PLAIN) { fprintf(gOutFile, " Instance fields -\n"); } diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 723bb1762d..46ab34bea3 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -153,6 +153,12 @@ bool PatchOat::Patch(const std::string& image_location, off_t delta, return false; } + if (image_header.GetStorageMode() != ImageHeader::kStorageModeUncompressed) { + LOG(ERROR) << "Patchoat is not supported with compressed image files " + << input_image->GetPath(); + return false; + } + /*bool is_image_pic = */IsImagePic(image_header, input_image->GetPath()); // Nothing special to do right now since the image always needs to get patched. // Perhaps in some far-off future we may have images with relative addresses that are true-PIC. diff --git a/runtime/Android.mk b/runtime/Android.mk index 74cc89911d..36c81fb078 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -491,9 +491,9 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT LOCAL_C_INCLUDES += art ifeq ($$(art_static_or_shared),static) - LOCAL_STATIC_LIBRARIES := libnativehelper libnativebridge libsigchain_dummy libbacktrace + LOCAL_STATIC_LIBRARIES := libnativehelper libnativebridge libsigchain_dummy libbacktrace liblz4 else - LOCAL_SHARED_LIBRARIES := libnativehelper libnativebridge libsigchain libbacktrace + LOCAL_SHARED_LIBRARIES := libnativehelper libnativebridge libsigchain libbacktrace liblz4 endif ifeq ($$(art_target_or_host),target) diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc index e20001864d..aca49ccc50 100644 --- a/runtime/arch/x86/entrypoints_init_x86.cc +++ b/runtime/arch/x86/entrypoints_init_x86.cc @@ -93,6 +93,25 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { qpoints->pLockObject = art_quick_lock_object; qpoints->pUnlockObject = art_quick_unlock_object; + // More math. + qpoints->pCos = cos; + qpoints->pSin = sin; + qpoints->pAcos = acos; + qpoints->pAsin = asin; + qpoints->pAtan = atan; + qpoints->pAtan2 = atan2; + qpoints->pCbrt = cbrt; + qpoints->pCosh = cosh; + qpoints->pExp = exp; + qpoints->pExpm1 = expm1; + qpoints->pHypot = hypot; + qpoints->pLog = log; + qpoints->pLog10 = log10; + qpoints->pNextAfter = nextafter; + qpoints->pSinh = sinh; + qpoints->pTan = tan; + qpoints->pTanh = tanh; + // Math qpoints->pD2l = art_quick_d2l; qpoints->pF2l = art_quick_f2l; diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc index 2b38c9db35..ebe6d40572 100644 --- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc +++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc @@ -98,6 +98,25 @@ void InitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) { qpoints->pLockObject = art_quick_lock_object; qpoints->pUnlockObject = art_quick_unlock_object; + // More math. + qpoints->pCos = cos; + qpoints->pSin = sin; + qpoints->pAcos = acos; + qpoints->pAsin = asin; + qpoints->pAtan = atan; + qpoints->pAtan2 = atan2; + qpoints->pCbrt = cbrt; + qpoints->pCosh = cosh; + qpoints->pExp = exp; + qpoints->pExpm1 = expm1; + qpoints->pHypot = hypot; + qpoints->pLog = log; + qpoints->pLog10 = log10; + qpoints->pNextAfter = nextafter; + qpoints->pSinh = sinh; + qpoints->pTan = tan; + qpoints->pTanh = tanh; + // Math qpoints->pD2l = art_d2l; qpoints->pF2l = art_f2l; diff --git a/runtime/asm_support.h b/runtime/asm_support.h index b548dfb639..29c8232ea3 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -122,7 +122,7 @@ ADD_TEST_EQ(THREAD_SELF_OFFSET, art::Thread::SelfOffset<__SIZEOF_POINTER__>().Int32Value()) // Offset of field Thread::tlsPtr_.thread_local_pos. -#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 151 * __SIZEOF_POINTER__) +#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 168 * __SIZEOF_POINTER__) ADD_TEST_EQ(THREAD_LOCAL_POS_OFFSET, art::Thread::ThreadLocalPosOffset<__SIZEOF_POINTER__>().Int32Value()) // Offset of field Thread::tlsPtr_.thread_local_end. diff --git a/runtime/base/dchecked_vector.h b/runtime/base/dchecked_vector.h index 2bd12df2c3..51dfba87eb 100644 --- a/runtime/base/dchecked_vector.h +++ b/runtime/base/dchecked_vector.h @@ -33,7 +33,7 @@ namespace art { // but we do not use exceptions, so this accessor is deliberately hidden. // Note: The common pattern &v[0] used to retrieve pointer to the data is not // valid for an empty dchecked_vector<>. Use data() to avoid checking empty(). -template <typename T, typename Alloc> +template <typename T, typename Alloc = std::allocator<T>> class dchecked_vector : private std::vector<T, Alloc> { private: // std::vector<> has a slightly different specialization for bool. We don't provide that. diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 0a37f26135..f5085ed417 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3056,10 +3056,12 @@ void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass) { verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure; std::string error_msg; if (!preverified) { + Runtime* runtime = Runtime::Current(); verifier_failure = verifier::MethodVerifier::VerifyClass(self, klass.Get(), - Runtime::Current()->IsAotCompiler(), - Runtime::Current()->IsAotCompiler(), + runtime->GetCompilerCallbacks(), + runtime->IsAotCompiler(), + runtime->IsAotCompiler(), &error_msg); } if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) { diff --git a/runtime/compiler_callbacks.h b/runtime/compiler_callbacks.h index af7b04f62e..a39d6822aa 100644 --- a/runtime/compiler_callbacks.h +++ b/runtime/compiler_callbacks.h @@ -37,8 +37,8 @@ class CompilerCallbacks { virtual ~CompilerCallbacks() { } - virtual bool MethodVerified(verifier::MethodVerifier* verifier) - SHARED_REQUIRES(Locks::mutator_lock_) = 0; + virtual void MethodVerified(verifier::MethodVerifier* verifier) + SHARED_REQUIRES(Locks::mutator_lock_) = 0; virtual void ClassRejected(ClassReference ref) = 0; // Return true if we should attempt to relocate to a random base address if we have not already diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 30d921afe6..4e15e808f2 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -2208,14 +2208,24 @@ void ClassDataItemIterator::ReadClassDataMethod() { } EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator( + const DexFile& dex_file, + const DexFile::ClassDef& class_def) + : EncodedStaticFieldValueIterator(dex_file, nullptr, nullptr, + nullptr, class_def) { +} + +EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator( const DexFile& dex_file, Handle<mirror::DexCache>* dex_cache, Handle<mirror::ClassLoader>* class_loader, ClassLinker* linker, const DexFile::ClassDef& class_def) - : dex_file_(dex_file), dex_cache_(dex_cache), class_loader_(class_loader), linker_(linker), - array_size_(), pos_(-1), type_(kByte) { - DCHECK(dex_cache != nullptr); - DCHECK(class_loader != nullptr); - ptr_ = dex_file.GetEncodedStaticFieldValuesArray(class_def); + : dex_file_(dex_file), + dex_cache_(dex_cache), + class_loader_(class_loader), + linker_(linker), + array_size_(), + pos_(-1), + type_(kByte) { + ptr_ = dex_file_.GetEncodedStaticFieldValuesArray(class_def); if (ptr_ == nullptr) { array_size_ = 0; } else { @@ -2288,6 +2298,8 @@ void EncodedStaticFieldValueIterator::Next() { template<bool kTransactionActive> void EncodedStaticFieldValueIterator::ReadValueToField(ArtField* field) const { + DCHECK(dex_cache_ != nullptr); + DCHECK(class_loader_ != nullptr); switch (type_) { case kBoolean: field->SetBoolean<kTransactionActive>(field->GetDeclaringClass(), jval_.z); break; diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 1e44f509f1..6b019f1140 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -1510,6 +1510,12 @@ class ClassDataItemIterator { class EncodedStaticFieldValueIterator { public: + // A constructor for static tools. You cannot call + // ReadValueToField() for an object created by this. + EncodedStaticFieldValueIterator(const DexFile& dex_file, + const DexFile::ClassDef& class_def); + + // A constructor meant to be called from runtime code. EncodedStaticFieldValueIterator(const DexFile& dex_file, Handle<mirror::DexCache>* dex_cache, Handle<mirror::ClassLoader>* class_loader, ClassLinker* linker, const DexFile::ClassDef& class_def) @@ -1541,6 +1547,9 @@ class EncodedStaticFieldValueIterator { kBoolean = 0x1f }; + ValueType GetValueType() const { return type_; } + const jvalue& GetJavaValue() const { return jval_; } + private: static constexpr uint8_t kEncodedValueTypeMask = 0x1f; // 0b11111 static constexpr uint8_t kEncodedValueArgShift = 5; diff --git a/runtime/entrypoints/quick/quick_entrypoints_list.h b/runtime/entrypoints/quick/quick_entrypoints_list.h index ee7b986094..3eea723275 100644 --- a/runtime/entrypoints/quick/quick_entrypoints_list.h +++ b/runtime/entrypoints/quick/quick_entrypoints_list.h @@ -86,6 +86,23 @@ V(CmpgFloat, int32_t, float, float) \ V(CmplDouble, int32_t, double, double) \ V(CmplFloat, int32_t, float, float) \ + V(Cos, double, double) \ + V(Sin, double, double) \ + V(Acos, double, double) \ + V(Asin, double, double) \ + V(Atan, double, double) \ + V(Atan2, double, double, double) \ + V(Cbrt, double, double) \ + V(Cosh, double, double) \ + V(Exp, double, double) \ + V(Expm1, double, double) \ + V(Hypot, double, double, double) \ + V(Log, double, double) \ + V(Log10, double, double) \ + V(NextAfter, double, double, double) \ + V(Sinh, double, double) \ + V(Tan, double, double) \ + V(Tanh, double, double) \ V(Fmod, double, double, double) \ V(L2d, double, int64_t) \ V(Fmodf, float, float, float) \ diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc index 8587edee54..391eb72e1c 100644 --- a/runtime/entrypoints_order_test.cc +++ b/runtime/entrypoints_order_test.cc @@ -223,7 +223,24 @@ class EntrypointsOrderTest : public CommonRuntimeTest { EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmpgDouble, pCmpgFloat, sizeof(void*)); EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmpgFloat, pCmplDouble, sizeof(void*)); EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmplDouble, pCmplFloat, sizeof(void*)); - EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmplFloat, pFmod, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCmplFloat, pCos, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCos, pSin, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSin, pAcos, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAcos, pAsin, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAsin, pAtan, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAtan, pAtan2, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pAtan2, pCbrt, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCbrt, pCosh, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pCosh, pExp, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pExp, pExpm1, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pExpm1, pHypot, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pHypot, pLog, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLog, pLog10, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pLog10, pNextAfter, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pNextAfter, pSinh, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pSinh, pTan, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pTan, pTanh, sizeof(void*)); + EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pTanh, pFmod, sizeof(void*)); EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pFmod, pL2d, sizeof(void*)); EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pL2d, pFmodf, sizeof(void*)); EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pFmodf, pL2f, sizeof(void*)); diff --git a/runtime/gc/collector/immune_spaces_test.cc b/runtime/gc/collector/immune_spaces_test.cc index f741117bc1..4884e668c2 100644 --- a/runtime/gc/collector/immune_spaces_test.cc +++ b/runtime/gc/collector/immune_spaces_test.cc @@ -113,7 +113,9 @@ class DummyImageSpace : public space::ImageSpace { /*oat_data_end*/PointerToLowMemUInt32(map->End() + oat_size), /*oat_file_end*/PointerToLowMemUInt32(map->End() + oat_size), /*pointer_size*/sizeof(void*), - /*compile_pic*/false); + /*compile_pic*/false, + ImageHeader::kStorageModeUncompressed, + /*storage_size*/0u); return new DummyImageSpace(map.release(), live_bitmap.release()); } }; diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index e2b2431054..8f67c213a6 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -17,12 +17,12 @@ #include "image_space.h" #include <dirent.h> +#include <lz4.h> +#include <random> #include <sys/statvfs.h> #include <sys/types.h> #include <unistd.h> -#include <random> - #include "art_method.h" #include "base/macros.h" #include "base/stl_util.h" @@ -677,11 +677,12 @@ ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_locat *error_msg = StringPrintf("Invalid image header in '%s'", image_filename); return nullptr; } - // Check that the file is large enough. - uint64_t image_file_size = static_cast<uint64_t>(file->GetLength()); - if (image_header.GetImageSize() > image_file_size) { - *error_msg = StringPrintf("Image file too small for image heap: %" PRIu64 " vs. %zu.", - image_file_size, image_header.GetImageSize()); + // 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, + image_header.GetDataSize()); return nullptr; } @@ -697,7 +698,11 @@ ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_locat } const auto& bitmap_section = image_header.GetImageSection(ImageHeader::kSectionImageBitmap); - auto end_of_bitmap = static_cast<size_t>(bitmap_section.End()); + // The location we want to map from is the first aligned page after the end of the stored + // (possibly compressed) data. + const size_t image_bitmap_offset = RoundUp(sizeof(image_header) + image_header.GetDataSize(), + kPageSize); + const size_t end_of_bitmap = image_bitmap_offset + bitmap_section.Size(); if (end_of_bitmap != image_file_size) { *error_msg = StringPrintf( "Image file size does not equal end of bitmap: size=%" PRIu64 " vs. %zu.", image_file_size, @@ -706,16 +711,60 @@ ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_locat } // Note: The image header is part of the image due to mmap page alignment required of offset. - std::unique_ptr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(), - image_header.GetImageSize(), - PROT_READ | PROT_WRITE, + std::unique_ptr<MemMap> map; + if (image_header.GetStorageMode() == ImageHeader::kStorageModeUncompressed) { + map.reset(MemMap::MapFileAtAddress(image_header.GetImageBegin(), + image_header.GetImageSize(), + PROT_READ | PROT_WRITE, + MAP_PRIVATE, + file->Fd(), + 0, + /*low_4gb*/false, + /*reuse*/false, + image_filename, + error_msg)); + } else { + // Reserve output and decompress into it. + map.reset(MemMap::MapAnonymous(image_location, + image_header.GetImageBegin(), + image_header.GetImageSize(), + PROT_READ | PROT_WRITE, + /*low_4gb*/false, + /*reuse*/false, + error_msg)); + if (map != nullptr) { + const size_t stored_size = image_header.GetDataSize(); + const size_t write_offset = sizeof(image_header); // Skip the header. + std::unique_ptr<MemMap> temp_map(MemMap::MapFile(sizeof(ImageHeader) + stored_size, + PROT_READ, MAP_PRIVATE, file->Fd(), - 0, + /*offset*/0, /*low_4gb*/false, - /*reuse*/false, image_filename, error_msg)); + if (temp_map == nullptr) { + DCHECK(!error_msg->empty()); + return nullptr; + } + memcpy(map->Begin(), &image_header, sizeof(image_header)); + const uint64_t start = NanoTime(); + const size_t decompressed_size = LZ4_decompress_safe( + reinterpret_cast<char*>(temp_map->Begin()) + sizeof(ImageHeader), + reinterpret_cast<char*>(map->Begin()) + write_offset, + stored_size, + map->Size()); + // TODO: VLOG(image) + VLOG(class_linker) << "Decompressing image took " << PrettyDuration(NanoTime() - start); + if (decompressed_size + sizeof(ImageHeader) != image_header.GetImageSize()) { + *error_msg = StringPrintf("Decompressed size does not match expected image size %zu vs %zu", + decompressed_size + sizeof(ImageHeader), + image_header.GetImageSize()); + return nullptr; + } + } + } + if (map == nullptr) { DCHECK(!error_msg->empty()); return nullptr; @@ -723,16 +772,16 @@ ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_locat CHECK_EQ(image_header.GetImageBegin(), map->Begin()); DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader))); - std::unique_ptr<MemMap> image_map(MemMap::MapFileAtAddress(nullptr, - bitmap_section.Size(), - PROT_READ, MAP_PRIVATE, - file->Fd(), - bitmap_section.Offset(), - /*low_4gb*/false, - /*reuse*/false, - image_filename, - error_msg)); - if (image_map.get() == nullptr) { + std::unique_ptr<MemMap> image_bitmap_map(MemMap::MapFileAtAddress(nullptr, + bitmap_section.Size(), + PROT_READ, MAP_PRIVATE, + file->Fd(), + image_bitmap_offset, + /*low_4gb*/false, + /*reuse*/false, + image_filename, + error_msg)); + if (image_bitmap_map == nullptr) { *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str()); return nullptr; } @@ -741,9 +790,11 @@ ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_locat bitmap_index)); std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap( accounting::ContinuousSpaceBitmap::CreateFromMemMap( - bitmap_name, image_map.release(), reinterpret_cast<uint8_t*>(map->Begin()), + bitmap_name, + image_bitmap_map.release(), + reinterpret_cast<uint8_t*>(map->Begin()), accounting::ContinuousSpaceBitmap::ComputeHeapSize(bitmap_section.Size()))); - if (bitmap.get() == nullptr) { + if (bitmap == nullptr) { *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str()); return nullptr; } diff --git a/runtime/image.cc b/runtime/image.cc index 2eac3fb873..7d2ef75c06 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -24,7 +24,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '3', '\0' }; +const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '4', '\0' }; ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, @@ -36,7 +36,9 @@ ImageHeader::ImageHeader(uint32_t image_begin, uint32_t oat_data_end, uint32_t oat_file_end, uint32_t pointer_size, - bool compile_pic) + bool compile_pic, + StorageMode storage_mode, + size_t data_size) : image_begin_(image_begin), image_size_(image_size), oat_checksum_(oat_checksum), @@ -47,7 +49,9 @@ ImageHeader::ImageHeader(uint32_t image_begin, patch_delta_(0), image_roots_(image_roots), pointer_size_(pointer_size), - compile_pic_(compile_pic) { + compile_pic_(compile_pic), + storage_mode_(storage_mode), + data_size_(data_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)); diff --git a/runtime/image.h b/runtime/image.h index a16f3c98fb..3032bebc18 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -78,10 +78,27 @@ class PACKED(4) ImageSection { // header of image files written by ImageWriter, read and validated by Space. class PACKED(4) ImageHeader { public: + enum StorageMode : uint32_t { + kStorageModeUncompressed, + kStorageModeLZ4, + kStorageModeCount, // Number of elements in enum. + }; + static constexpr StorageMode kDefaultStorageMode = kStorageModeUncompressed; + ImageHeader() - : image_begin_(0U), image_size_(0U), oat_checksum_(0U), oat_file_begin_(0U), - oat_data_begin_(0U), oat_data_end_(0U), oat_file_end_(0U), patch_delta_(0), - image_roots_(0U), pointer_size_(0U), compile_pic_(0) {} + : image_begin_(0U), + image_size_(0U), + oat_checksum_(0U), + oat_file_begin_(0U), + oat_data_begin_(0U), + oat_data_end_(0U), + oat_file_end_(0U), + patch_delta_(0), + image_roots_(0U), + pointer_size_(0U), + compile_pic_(0), + storage_mode_(kDefaultStorageMode), + data_size_(0) {} ImageHeader(uint32_t image_begin, uint32_t image_size, @@ -93,7 +110,9 @@ class PACKED(4) ImageHeader { uint32_t oat_data_end, uint32_t oat_file_end, uint32_t pointer_size, - bool compile_pic); + bool compile_pic, + StorageMode storage_mode, + size_t data_size); bool IsValid() const; const char* GetMagic() const; @@ -194,6 +213,14 @@ class PACKED(4) ImageHeader { return compile_pic_ != 0; } + StorageMode GetStorageMode() const { + return storage_mode_; + } + + uint64_t GetDataSize() const { + return data_size_; + } + private: static const uint8_t kImageMagic[4]; static const uint8_t kImageVersion[4]; @@ -241,6 +268,13 @@ class PACKED(4) ImageHeader { // Image methods. uint64_t image_methods_[kImageMethodsCount]; + // Storage method for the image, the image may be compressed. + StorageMode storage_mode_; + + // 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_; + friend class ImageWriter; }; @@ -248,6 +282,7 @@ std::ostream& operator<<(std::ostream& os, const ImageHeader::ImageMethod& polic std::ostream& operator<<(std::ostream& os, const ImageHeader::ImageRoot& policy); std::ostream& operator<<(std::ostream& os, const ImageHeader::ImageSections& section); std::ostream& operator<<(std::ostream& os, const ImageSection& section); +std::ostream& operator<<(std::ostream& os, const ImageHeader::StorageMode& mode); } // namespace art diff --git a/runtime/noop_compiler_callbacks.h b/runtime/noop_compiler_callbacks.h index 1cbf2bbda4..02081cbb60 100644 --- a/runtime/noop_compiler_callbacks.h +++ b/runtime/noop_compiler_callbacks.h @@ -26,8 +26,7 @@ class NoopCompilerCallbacks FINAL : public CompilerCallbacks { NoopCompilerCallbacks() : CompilerCallbacks(CompilerCallbacks::CallbackMode::kCompileApp) {} ~NoopCompilerCallbacks() {} - bool MethodVerified(verifier::MethodVerifier* verifier ATTRIBUTE_UNUSED) OVERRIDE { - return true; + void MethodVerified(verifier::MethodVerifier* verifier ATTRIBUTE_UNUSED) OVERRIDE { } void ClassRejected(ClassReference ref ATTRIBUTE_UNUSED) OVERRIDE {} diff --git a/runtime/oat.cc b/runtime/oat.cc index 40aca0d249..c787b9adb1 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -45,9 +45,7 @@ static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* vari OatHeader* OatHeader::Create(InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, - const std::vector<const DexFile*>* dex_files, - uint32_t image_file_location_oat_checksum, - uint32_t image_file_location_oat_data_begin, + uint32_t dex_file_count, const SafeMap<std::string, std::string>* variable_data) { // Estimate size of optional data. size_t needed_size = ComputeOatHeaderSize(variable_data); @@ -58,18 +56,29 @@ OatHeader* OatHeader::Create(InstructionSet instruction_set, // Create the OatHeader in-place. return new (memory) OatHeader(instruction_set, instruction_set_features, - dex_files, - image_file_location_oat_checksum, - image_file_location_oat_data_begin, + dex_file_count, variable_data); } OatHeader::OatHeader(InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, - const std::vector<const DexFile*>* dex_files, - uint32_t image_file_location_oat_checksum, - uint32_t image_file_location_oat_data_begin, - const SafeMap<std::string, std::string>* variable_data) { + uint32_t dex_file_count, + const SafeMap<std::string, std::string>* variable_data) + : adler32_checksum_(adler32(0L, Z_NULL, 0)), + instruction_set_(instruction_set), + instruction_set_features_bitmap_(instruction_set_features->AsBitmap()), + dex_file_count_(dex_file_count), + executable_offset_(0), + interpreter_to_interpreter_bridge_offset_(0), + interpreter_to_compiled_code_bridge_offset_(0), + jni_dlsym_lookup_offset_(0), + quick_generic_jni_trampoline_offset_(0), + quick_imt_conflict_trampoline_offset_(0), + quick_resolution_trampoline_offset_(0), + quick_to_interpreter_bridge_offset_(0), + image_patch_delta_(0), + image_file_location_oat_checksum_(0), + image_file_location_oat_data_begin_(0) { // Don't want asserts in header as they would be checked in each file that includes it. But the // fields are private, so we check inside a method. static_assert(sizeof(magic_) == sizeof(kOatMagic), @@ -79,46 +88,11 @@ OatHeader::OatHeader(InstructionSet instruction_set, memcpy(magic_, kOatMagic, sizeof(kOatMagic)); memcpy(version_, kOatVersion, sizeof(kOatVersion)); - executable_offset_ = 0; - image_patch_delta_ = 0; - - adler32_checksum_ = adler32(0L, Z_NULL, 0); CHECK_NE(instruction_set, kNone); - instruction_set_ = instruction_set; - UpdateChecksum(&instruction_set_, sizeof(instruction_set_)); - - instruction_set_features_bitmap_ = instruction_set_features->AsBitmap(); - UpdateChecksum(&instruction_set_features_bitmap_, sizeof(instruction_set_features_bitmap_)); - - dex_file_count_ = dex_files->size(); - UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_)); - - image_file_location_oat_checksum_ = image_file_location_oat_checksum; - UpdateChecksum(&image_file_location_oat_checksum_, sizeof(image_file_location_oat_checksum_)); - - CHECK_ALIGNED(image_file_location_oat_data_begin, kPageSize); - image_file_location_oat_data_begin_ = image_file_location_oat_data_begin; - UpdateChecksum(&image_file_location_oat_data_begin_, sizeof(image_file_location_oat_data_begin_)); // Flatten the map. Will also update variable_size_data_size_. Flatten(variable_data); - - // Update checksum for variable data size. - UpdateChecksum(&key_value_store_size_, sizeof(key_value_store_size_)); - - // Update for data, if existing. - if (key_value_store_size_ > 0U) { - UpdateChecksum(&key_value_store_, key_value_store_size_); - } - - interpreter_to_interpreter_bridge_offset_ = 0; - interpreter_to_compiled_code_bridge_offset_ = 0; - jni_dlsym_lookup_offset_ = 0; - quick_generic_jni_trampoline_offset_ = 0; - quick_imt_conflict_trampoline_offset_ = 0; - quick_resolution_trampoline_offset_ = 0; - quick_to_interpreter_bridge_offset_ = 0; } bool OatHeader::IsValid() const { @@ -175,6 +149,37 @@ uint32_t OatHeader::GetChecksum() const { return adler32_checksum_; } +void OatHeader::UpdateChecksumWithHeaderData() { + UpdateChecksum(&instruction_set_, sizeof(instruction_set_)); + UpdateChecksum(&instruction_set_features_bitmap_, sizeof(instruction_set_features_bitmap_)); + UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_)); + UpdateChecksum(&image_file_location_oat_checksum_, sizeof(image_file_location_oat_checksum_)); + UpdateChecksum(&image_file_location_oat_data_begin_, sizeof(image_file_location_oat_data_begin_)); + + // Update checksum for variable data size. + UpdateChecksum(&key_value_store_size_, sizeof(key_value_store_size_)); + + // Update for data, if existing. + if (key_value_store_size_ > 0U) { + UpdateChecksum(&key_value_store_, key_value_store_size_); + } + + UpdateChecksum(&executable_offset_, sizeof(executable_offset_)); + UpdateChecksum(&interpreter_to_interpreter_bridge_offset_, + sizeof(interpreter_to_interpreter_bridge_offset_)); + UpdateChecksum(&interpreter_to_compiled_code_bridge_offset_, + sizeof(interpreter_to_compiled_code_bridge_offset_)); + UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(jni_dlsym_lookup_offset_)); + UpdateChecksum(&quick_generic_jni_trampoline_offset_, + sizeof(quick_generic_jni_trampoline_offset_)); + UpdateChecksum(&quick_imt_conflict_trampoline_offset_, + sizeof(quick_imt_conflict_trampoline_offset_)); + UpdateChecksum(&quick_resolution_trampoline_offset_, + sizeof(quick_resolution_trampoline_offset_)); + UpdateChecksum(&quick_to_interpreter_bridge_offset_, + sizeof(quick_to_interpreter_bridge_offset_)); +} + void OatHeader::UpdateChecksum(const void* data, size_t length) { DCHECK(IsValid()); const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data); @@ -205,7 +210,6 @@ void OatHeader::SetExecutableOffset(uint32_t executable_offset) { DCHECK_EQ(executable_offset_, 0U); executable_offset_ = executable_offset; - UpdateChecksum(&executable_offset_, sizeof(executable_offset)); } const void* OatHeader::GetInterpreterToInterpreterBridge() const { @@ -225,7 +229,6 @@ void OatHeader::SetInterpreterToInterpreterBridgeOffset(uint32_t offset) { DCHECK_EQ(interpreter_to_interpreter_bridge_offset_, 0U) << offset; interpreter_to_interpreter_bridge_offset_ = offset; - UpdateChecksum(&interpreter_to_interpreter_bridge_offset_, sizeof(offset)); } const void* OatHeader::GetInterpreterToCompiledCodeBridge() const { @@ -244,7 +247,6 @@ void OatHeader::SetInterpreterToCompiledCodeBridgeOffset(uint32_t offset) { DCHECK_EQ(interpreter_to_compiled_code_bridge_offset_, 0U) << offset; interpreter_to_compiled_code_bridge_offset_ = offset; - UpdateChecksum(&interpreter_to_compiled_code_bridge_offset_, sizeof(offset)); } const void* OatHeader::GetJniDlsymLookup() const { @@ -263,7 +265,6 @@ void OatHeader::SetJniDlsymLookupOffset(uint32_t offset) { DCHECK_EQ(jni_dlsym_lookup_offset_, 0U) << offset; jni_dlsym_lookup_offset_ = offset; - UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(offset)); } const void* OatHeader::GetQuickGenericJniTrampoline() const { @@ -282,7 +283,6 @@ void OatHeader::SetQuickGenericJniTrampolineOffset(uint32_t offset) { DCHECK_EQ(quick_generic_jni_trampoline_offset_, 0U) << offset; quick_generic_jni_trampoline_offset_ = offset; - UpdateChecksum(&quick_generic_jni_trampoline_offset_, sizeof(offset)); } const void* OatHeader::GetQuickImtConflictTrampoline() const { @@ -301,7 +301,6 @@ void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) { DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset; quick_imt_conflict_trampoline_offset_ = offset; - UpdateChecksum(&quick_imt_conflict_trampoline_offset_, sizeof(offset)); } const void* OatHeader::GetQuickResolutionTrampoline() const { @@ -320,7 +319,6 @@ void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) { DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset; quick_resolution_trampoline_offset_ = offset; - UpdateChecksum(&quick_resolution_trampoline_offset_, sizeof(offset)); } const void* OatHeader::GetQuickToInterpreterBridge() const { @@ -339,7 +337,6 @@ void OatHeader::SetQuickToInterpreterBridgeOffset(uint32_t offset) { DCHECK_EQ(quick_to_interpreter_bridge_offset_, 0U) << offset; quick_to_interpreter_bridge_offset_ = offset; - UpdateChecksum(&quick_to_interpreter_bridge_offset_, sizeof(offset)); } int32_t OatHeader::GetImagePatchDelta() const { @@ -367,11 +364,22 @@ uint32_t OatHeader::GetImageFileLocationOatChecksum() const { return image_file_location_oat_checksum_; } +void OatHeader::SetImageFileLocationOatChecksum(uint32_t image_file_location_oat_checksum) { + CHECK(IsValid()); + image_file_location_oat_checksum_ = image_file_location_oat_checksum; +} + uint32_t OatHeader::GetImageFileLocationOatDataBegin() const { CHECK(IsValid()); return image_file_location_oat_data_begin_; } +void OatHeader::SetImageFileLocationOatDataBegin(uint32_t image_file_location_oat_data_begin) { + CHECK(IsValid()); + CHECK_ALIGNED(image_file_location_oat_data_begin, kPageSize); + image_file_location_oat_data_begin_ = image_file_location_oat_data_begin; +} + uint32_t OatHeader::GetKeyValueStoreSize() const { CHECK(IsValid()); return key_value_store_size_; diff --git a/runtime/oat.h b/runtime/oat.h index 5b780c38f8..5ed197715d 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -31,7 +31,7 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - static constexpr uint8_t kOatVersion[] = { '0', '7', '3', '\0' }; + static constexpr uint8_t kOatVersion[] = { '0', '7', '4', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; @@ -45,15 +45,14 @@ class PACKED(4) OatHeader { static OatHeader* Create(InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, - const std::vector<const DexFile*>* dex_files, - uint32_t image_file_location_oat_checksum, - uint32_t image_file_location_oat_data_begin, + uint32_t dex_file_count, const SafeMap<std::string, std::string>* variable_data); bool IsValid() const; std::string GetValidationErrorMessage() const; const char* GetMagic() const; uint32_t GetChecksum() const; + void UpdateChecksumWithHeaderData(); void UpdateChecksum(const void* data, size_t length); uint32_t GetDexFileCount() const { DCHECK(IsValid()); @@ -92,8 +91,11 @@ class PACKED(4) OatHeader { InstructionSet GetInstructionSet() const; uint32_t GetInstructionSetFeaturesBitmap() const; + uint32_t GetImageFileLocationOatChecksum() const; + void SetImageFileLocationOatChecksum(uint32_t image_file_location_oat_checksum); uint32_t GetImageFileLocationOatDataBegin() const; + void SetImageFileLocationOatDataBegin(uint32_t image_file_location_oat_data_begin); uint32_t GetKeyValueStoreSize() const; const uint8_t* GetKeyValueStore() const; @@ -107,9 +109,7 @@ class PACKED(4) OatHeader { private: OatHeader(InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, - const std::vector<const DexFile*>* dex_files, - uint32_t image_file_location_oat_checksum, - uint32_t image_file_location_oat_data_begin, + uint32_t dex_file_count, const SafeMap<std::string, std::string>* variable_data); // Returns true if the value of the given key is "true", false otherwise. diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h index 837662d879..6cea90219e 100644 --- a/runtime/quick/inline_method_analyser.h +++ b/runtime/quick/inline_method_analyser.h @@ -51,6 +51,23 @@ enum InlineMethodOpcode : uint16_t { kIntrinsicMinMaxLong, kIntrinsicMinMaxFloat, kIntrinsicMinMaxDouble, + kIntrinsicCos, + kIntrinsicSin, + kIntrinsicAcos, + kIntrinsicAsin, + kIntrinsicAtan, + kIntrinsicAtan2, + kIntrinsicCbrt, + kIntrinsicCosh, + kIntrinsicExp, + kIntrinsicExpm1, + kIntrinsicHypot, + kIntrinsicLog, + kIntrinsicLog10, + kIntrinsicNextAfter, + kIntrinsicSinh, + kIntrinsicTan, + kIntrinsicTanh, kIntrinsicSqrt, kIntrinsicCeil, kIntrinsicFloor, diff --git a/runtime/runtime.cc b/runtime/runtime.cc index dedc110b00..291b9a0b1b 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1293,6 +1293,11 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { } void Runtime::DumpForSigQuit(std::ostream& os) { + // Dumping for SIGQIT may cause deadlocks if the the debugger is active. b/26118154 + if (Dbg::IsDebuggerActive()) { + LOG(INFO) << "Skipping DumpForSigQuit due to active debugger"; + return; + } GetClassLinker()->DumpForSigQuit(os); GetInternTable()->DumpForSigQuit(os); GetJavaVM()->DumpForSigQuit(os); diff --git a/runtime/thread.cc b/runtime/thread.cc index 90539b479f..8a8c02f993 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -2478,6 +2478,23 @@ void Thread::DumpThreadOffset(std::ostream& os, uint32_t offset) { QUICK_ENTRY_POINT_INFO(pCmpgFloat) QUICK_ENTRY_POINT_INFO(pCmplDouble) QUICK_ENTRY_POINT_INFO(pCmplFloat) + QUICK_ENTRY_POINT_INFO(pCos) + QUICK_ENTRY_POINT_INFO(pSin) + QUICK_ENTRY_POINT_INFO(pAcos) + QUICK_ENTRY_POINT_INFO(pAsin) + QUICK_ENTRY_POINT_INFO(pAtan) + QUICK_ENTRY_POINT_INFO(pAtan2) + QUICK_ENTRY_POINT_INFO(pCbrt) + QUICK_ENTRY_POINT_INFO(pCosh) + QUICK_ENTRY_POINT_INFO(pExp) + QUICK_ENTRY_POINT_INFO(pExpm1) + QUICK_ENTRY_POINT_INFO(pHypot) + QUICK_ENTRY_POINT_INFO(pLog) + QUICK_ENTRY_POINT_INFO(pLog10) + QUICK_ENTRY_POINT_INFO(pNextAfter) + QUICK_ENTRY_POINT_INFO(pSinh) + QUICK_ENTRY_POINT_INFO(pTan) + QUICK_ENTRY_POINT_INFO(pTanh) QUICK_ENTRY_POINT_INFO(pFmod) QUICK_ENTRY_POINT_INFO(pL2d) QUICK_ENTRY_POINT_INFO(pFmodf) diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index cf27ff2f60..d75587b52c 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -116,6 +116,7 @@ static void SafelyMarkAllRegistersAsConflicts(MethodVerifier* verifier, Register MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self, mirror::Class* klass, + CompilerCallbacks* callbacks, bool allow_soft_failures, bool log_hard_failures, std::string* error) { @@ -140,9 +141,9 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self, } if (early_failure) { *error = "Verifier rejected class " + PrettyDescriptor(klass) + failure_message; - if (Runtime::Current()->IsAotCompiler()) { + if (callbacks != nullptr) { ClassReference ref(&dex_file, klass->GetDexClassDefIndex()); - Runtime::Current()->GetCompilerCallbacks()->ClassRejected(ref); + callbacks->ClassRejected(ref); } return kHardFailure; } @@ -154,6 +155,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self, dex_cache, class_loader, class_def, + callbacks, allow_soft_failures, log_hard_failures, error); @@ -172,6 +174,7 @@ void MethodVerifier::VerifyMethods(Thread* self, ClassDataItemIterator* it, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, + CompilerCallbacks* callbacks, bool allow_soft_failures, bool log_hard_failures, bool need_precise_constants, @@ -212,6 +215,7 @@ void MethodVerifier::VerifyMethods(Thread* self, it->GetMethodCodeItem(), method, it->GetMethodAccessFlags(), + callbacks, allow_soft_failures, log_hard_failures, need_precise_constants, @@ -241,6 +245,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexFile::ClassDef* class_def, + CompilerCallbacks* callbacks, bool allow_soft_failures, bool log_hard_failures, std::string* error) { @@ -274,6 +279,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self, &it, dex_cache, class_loader, + callbacks, allow_soft_failures, log_hard_failures, false /* need precise constants */, @@ -288,6 +294,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self, &it, dex_cache, class_loader, + callbacks, allow_soft_failures, log_hard_failures, false /* need precise constants */, @@ -322,6 +329,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self, const DexFile::CodeItem* code_item, ArtMethod* method, uint32_t method_access_flags, + CompilerCallbacks* callbacks, bool allow_soft_failures, bool log_hard_failures, bool need_precise_constants, @@ -336,6 +344,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self, // Verification completed, however failures may be pending that didn't cause the verification // to hard fail. CHECK(!verifier.have_pending_hard_failure_); + + if (code_item != nullptr && callbacks != nullptr) { + // Let the interested party know that the method was verified. + callbacks->MethodVerified(&verifier); + } + if (verifier.failures_.size() != 0) { if (VLOG_IS_ON(verifier)) { verifier.DumpFailures(VLOG_STREAM(verifier) << "Soft verification failures in " @@ -363,8 +377,14 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self, verifier.failure_messages_[verifier.failure_messages_.size() - 1]->str(); } result = kHardFailure; + + if (callbacks != nullptr) { + // Let the interested party know that we failed the class. + ClassReference ref(dex_file, dex_file->GetIndexForClassDef(*class_def)); + callbacks->ClassRejected(ref); + } } - if (kDebugVerify) { + if (VLOG_IS_ON(verifier)) { std::cout << "\n" << verifier.info_messages_.str(); verifier.Dump(std::cout); } @@ -408,13 +428,18 @@ MethodVerifier* MethodVerifier::VerifyMethodAndDump(Thread* self, } MethodVerifier::MethodVerifier(Thread* self, - const DexFile* dex_file, Handle<mirror::DexCache> dex_cache, + const DexFile* dex_file, + Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexFile::ClassDef* class_def, - const DexFile::CodeItem* code_item, uint32_t dex_method_idx, - ArtMethod* method, uint32_t method_access_flags, - bool can_load_classes, bool allow_soft_failures, - bool need_precise_constants, bool verify_to_dump, + const DexFile::CodeItem* code_item, + uint32_t dex_method_idx, + ArtMethod* method, + uint32_t method_access_flags, + bool can_load_classes, + bool allow_soft_failures, + bool need_precise_constants, + bool verify_to_dump, bool allow_thread_suspension) : self_(self), arena_stack_(Runtime::Current()->GetArenaPool()), @@ -739,10 +764,7 @@ bool MethodVerifier::Verify() { result = result && VerifyInstructions(); // Perform code-flow analysis and return. result = result && VerifyCodeFlow(); - // Compute information for compiler. - if (result && runtime->IsCompiler()) { - result = runtime->GetCompilerCallbacks()->MethodVerified(this); - } + return result; } @@ -802,10 +824,6 @@ std::ostream& MethodVerifier::Fail(VerifyError error) { // Hard verification failures at compile time will still fail at runtime, so the class is // marked as rejected to prevent it from being compiled. case VERIFY_ERROR_BAD_CLASS_HARD: { - if (Runtime::Current()->IsAotCompiler()) { - ClassReference ref(dex_file_, dex_file_->GetIndexForClassDef(*class_def_)); - Runtime::Current()->GetCompilerCallbacks()->ClassRejected(ref); - } have_pending_hard_failure_ = true; if (VLOG_IS_ON(verifier) && kDumpRegLinesOnHardFailureIfVLOG) { ScopedObjectAccess soa(Thread::Current()); @@ -3639,30 +3657,8 @@ ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess( auto* cl = Runtime::Current()->GetClassLinker(); auto pointer_size = cl->GetImagePointerSize(); - // Check that interface methods are static or match interface classes. - // We only allow statics if we don't have default methods enabled. - if (klass->IsInterface()) { - Runtime* runtime = Runtime::Current(); - const bool default_methods_supported = - runtime == nullptr || - runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods); - if (method_type != METHOD_INTERFACE && - (!default_methods_supported || method_type != METHOD_STATIC)) { - Fail(VERIFY_ERROR_CLASS_CHANGE) - << "non-interface method " << PrettyMethod(dex_method_idx, *dex_file_) - << " is in an interface class " << PrettyClass(klass); - return nullptr; - } - } else { - if (method_type == METHOD_INTERFACE) { - Fail(VERIFY_ERROR_CLASS_CHANGE) - << "interface method " << PrettyMethod(dex_method_idx, *dex_file_) - << " is in a non-interface class " << PrettyClass(klass); - return nullptr; - } - } - ArtMethod* res_method = dex_cache_->GetResolvedMethod(dex_method_idx, pointer_size); + bool stash_method = false; if (res_method == nullptr) { const char* name = dex_file_->GetMethodName(method_id); const Signature signature = dex_file_->GetMethodSignature(method_id); @@ -3675,7 +3671,7 @@ ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess( res_method = klass->FindVirtualMethod(name, signature, pointer_size); } if (res_method != nullptr) { - dex_cache_->SetResolvedMethod(dex_method_idx, res_method, pointer_size); + stash_method = true; } else { // If a virtual or interface method wasn't found with the expected type, look in // the direct methods. This can happen when the wrong invoke type is used or when @@ -3704,6 +3700,38 @@ ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess( << PrettyMethod(res_method); return nullptr; } + + // Check that interface methods are static or match interface classes. + // We only allow statics if we don't have default methods enabled. + // + // Note: this check must be after the initializer check, as those are required to fail a class, + // while this check implies an IncompatibleClassChangeError. + if (klass->IsInterface()) { + Runtime* runtime = Runtime::Current(); + const bool default_methods_supported = + runtime == nullptr || + runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods); + if (method_type != METHOD_INTERFACE && + (!default_methods_supported || method_type != METHOD_STATIC)) { + Fail(VERIFY_ERROR_CLASS_CHANGE) + << "non-interface method " << PrettyMethod(dex_method_idx, *dex_file_) + << " is in an interface class " << PrettyClass(klass); + return nullptr; + } + } else { + if (method_type == METHOD_INTERFACE) { + Fail(VERIFY_ERROR_CLASS_CHANGE) + << "interface method " << PrettyMethod(dex_method_idx, *dex_file_) + << " is in a non-interface class " << PrettyClass(klass); + return nullptr; + } + } + + // Only stash after the above passed. Otherwise the method wasn't guaranteed to be correct. + if (stash_method) { + dex_cache_->SetResolvedMethod(dex_method_idx, res_method, pointer_size); + } + // Check if access is allowed. if (!referrer.CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) { Fail(VERIFY_ERROR_ACCESS_METHOD) << "illegal method access (call " << PrettyMethod(res_method) diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 719f0d7d40..79db576993 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -33,6 +33,7 @@ namespace art { +class CompilerCallbacks; class Instruction; struct ReferenceMap2Visitor; class Thread; @@ -141,6 +142,7 @@ class MethodVerifier { /* Verify a class. Returns "kNoFailure" on success. */ static FailureKind VerifyClass(Thread* self, mirror::Class* klass, + CompilerCallbacks* callbacks, bool allow_soft_failures, bool log_hard_failures, std::string* error) @@ -150,6 +152,7 @@ class MethodVerifier { Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexFile::ClassDef* class_def, + CompilerCallbacks* callbacks, bool allow_soft_failures, bool log_hard_failures, std::string* error) @@ -216,16 +219,34 @@ class MethodVerifier { return can_load_classes_; } - MethodVerifier(Thread* self, const DexFile* dex_file, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexFile::ClassDef* class_def, - const DexFile::CodeItem* code_item, uint32_t method_idx, + MethodVerifier(Thread* self, + const DexFile* dex_file, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + const DexFile::ClassDef* class_def, + const DexFile::CodeItem* code_item, + uint32_t method_idx, ArtMethod* method, - uint32_t access_flags, bool can_load_classes, bool allow_soft_failures, - bool need_precise_constants, bool allow_thread_suspension) + uint32_t access_flags, + bool can_load_classes, + bool allow_soft_failures, + bool need_precise_constants, + bool allow_thread_suspension) SHARED_REQUIRES(Locks::mutator_lock_) - : MethodVerifier(self, dex_file, dex_cache, class_loader, class_def, code_item, method_idx, - method, access_flags, can_load_classes, allow_soft_failures, - need_precise_constants, false, allow_thread_suspension) {} + : MethodVerifier(self, + dex_file, + dex_cache, + class_loader, + class_def, + code_item, + method_idx, + method, + access_flags, + can_load_classes, + allow_soft_failures, + need_precise_constants, + false, + allow_thread_suspension) {} ~MethodVerifier(); @@ -299,12 +320,20 @@ class MethodVerifier { } // Private constructor for dumping. - MethodVerifier(Thread* self, const DexFile* dex_file, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexFile::ClassDef* class_def, - const DexFile::CodeItem* code_item, uint32_t method_idx, - ArtMethod* method, uint32_t access_flags, - bool can_load_classes, bool allow_soft_failures, bool need_precise_constants, - bool verify_to_dump, bool allow_thread_suspension) + MethodVerifier(Thread* self, + const DexFile* dex_file, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + const DexFile::ClassDef* class_def, + const DexFile::CodeItem* code_item, + uint32_t method_idx, + ArtMethod* method, + uint32_t access_flags, + bool can_load_classes, + bool allow_soft_failures, + bool need_precise_constants, + bool verify_to_dump, + bool allow_thread_suspension) SHARED_REQUIRES(Locks::mutator_lock_); // Adds the given string to the beginning of the last failure message. @@ -323,6 +352,7 @@ class MethodVerifier { ClassDataItemIterator* it, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, + CompilerCallbacks* callbacks, bool allow_soft_failures, bool log_hard_failures, bool need_precise_constants, @@ -350,6 +380,7 @@ class MethodVerifier { const DexFile::CodeItem* code_item, ArtMethod* method, uint32_t method_access_flags, + CompilerCallbacks* callbacks, bool allow_soft_failures, bool log_hard_failures, bool need_precise_constants, diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index c4123d5f52..946f842fd0 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -37,8 +37,8 @@ class MethodVerifierTest : public CommonRuntimeTest { // Verify the class std::string error_msg; - ASSERT_TRUE(MethodVerifier::VerifyClass(self, klass, true, true, &error_msg) == MethodVerifier::kNoFailure) - << error_msg; + ASSERT_TRUE(MethodVerifier::VerifyClass(self, klass, nullptr, true, true, &error_msg) + == MethodVerifier::kNoFailure) << error_msg; } void VerifyDexFile(const DexFile& dex) diff --git a/test/123-inline-execute2/expected.txt b/test/123-inline-execute2/expected.txt new file mode 100644 index 0000000000..aa74fa3757 --- /dev/null +++ b/test/123-inline-execute2/expected.txt @@ -0,0 +1,299 @@ +Math.sin(0.0) = 0.000000000000 +Math.sinh(0.0) = 0.000000000000 +Math.asin(0.0) = 0.000000000000 +Math.cos(0.0) = 1.000000000000 +Math.cosh(0.0) = 1.000000000000 +Math.acos(0.0) = 1.570796326795 +Math.tan(0.0) = 0.000000000000 +Math.tanh(0.0) = 0.000000000000 +Math.atan(0.0) = 0.000000000000 +Math.atan2(0.0, 1.0) = 0.000000000000 +Math.sin(0.7853981633974483) = 0.707106781187 +Math.sinh(0.7853981633974483) = 0.868670961486 +Math.asin(0.7853981633974483) = 0.903339110767 +Math.cos(0.7853981633974483) = 0.707106781187 +Math.cosh(0.7853981633974483) = 1.324609089252 +Math.acos(0.7853981633974483) = 0.667457216028 +Math.tan(0.7853981633974483) = 1.000000000000 +Math.tanh(0.7853981633974483) = 0.655794202633 +Math.atan(0.7853981633974483) = 0.665773750028 +Math.atan2(0.7853981633974483, 1.7853981633974483) = 0.414423800577 +Math.sin(1.5707963267948966) = 1.000000000000 +Math.sinh(1.5707963267948966) = 2.301298902307 +Math.asin(1.5707963267948966) = NaN +Math.cos(1.5707963267948966) = 0.000000000000 +Math.cosh(1.5707963267948966) = 2.509178478658 +Math.acos(1.5707963267948966) = NaN +Math.tanh(1.5707963267948966) = 0.917152335667 +Math.atan(1.5707963267948966) = 1.003884821854 +Math.atan2(1.5707963267948966, 2.5707963267948966) = 0.548479764417 +Math.sin(2.356194490192345) = 0.707106781187 +Math.sinh(2.356194490192345) = 5.227971924678 +Math.asin(2.356194490192345) = NaN +Math.cos(2.356194490192345) = -0.707106781187 +Math.cosh(2.356194490192345) = 5.322752149520 +Math.acos(2.356194490192345) = NaN +Math.tan(2.356194490192345) = -1.000000000000 +Math.tanh(2.356194490192345) = 0.982193380007 +Math.atan(2.356194490192345) = 1.169422824816 +Math.atan2(2.356194490192345, 3.356194490192345) = 0.612096117380 +Math.sin(3.141592653589793) = 0.000000000000 +Math.sinh(3.141592653589793) = 11.548739357258 +Math.asin(3.141592653589793) = NaN +Math.cos(3.141592653589793) = -1.000000000000 +Math.cosh(3.141592653589793) = 11.591953275522 +Math.acos(3.141592653589793) = NaN +Math.tan(3.141592653589793) = -0.000000000000 +Math.tanh(3.141592653589793) = 0.996272076221 +Math.atan(3.141592653589793) = 1.262627255679 +Math.atan2(3.141592653589793, 4.141592653589793) = 0.648948780815 +Math.sin(3.9269908169872414) = -0.707106781187 +Math.sinh(3.9269908169872414) = 25.367158319374 +Math.asin(3.9269908169872414) = NaN +Math.cos(3.9269908169872414) = -0.707106781187 +Math.cosh(3.9269908169872414) = 25.386861192361 +Math.acos(3.9269908169872414) = NaN +Math.tan(3.9269908169872414) = 1.000000000000 +Math.tanh(3.9269908169872414) = 0.999223894879 +Math.atan(3.9269908169872414) = 1.321447967784 +Math.atan2(3.9269908169872414, 4.926990816987241) = 0.672931229191 +Math.sin(4.71238898038469) = -1.000000000000 +Math.sinh(4.71238898038469) = 55.654397599418 +Math.asin(4.71238898038469) = NaN +Math.cos(4.71238898038469) = -0.000000000000 +Math.cosh(4.71238898038469) = 55.663380890439 +Math.acos(4.71238898038469) = NaN +Math.tanh(4.71238898038469) = 0.999838613989 +Math.atan(4.71238898038469) = 1.361691682971 +Math.atan2(4.71238898038469, 5.71238898038469) = 0.689765469251 +Math.sin(5.497787143782138) = -0.707106781187 +Math.sinh(5.497787143782138) = 122.073483514693 +Math.asin(5.497787143782138) = NaN +Math.cos(5.497787143782138) = 0.707106781187 +Math.cosh(5.497787143782138) = 122.077579339582 +Math.acos(5.497787143782138) = NaN +Math.tan(5.497787143782138) = -1.000000000000 +Math.tanh(5.497787143782138) = 0.999966449000 +Math.atan(5.497787143782138) = 1.390871988014 +Math.atan2(5.497787143782138, 6.497787143782138) = 0.702226398171 +Math.sin(6.283185307179586) = -0.000000000000 +Math.sinh(6.283185307179586) = 267.744894041016 +Math.asin(6.283185307179586) = NaN +Math.cos(6.283185307179586) = 1.000000000000 +Math.cosh(6.283185307179586) = 267.746761483748 +Math.acos(6.283185307179586) = NaN +Math.tan(6.283185307179586) = -0.000000000000 +Math.tanh(6.283185307179586) = 0.999993025340 +Math.atan(6.283185307179586) = 1.412965136507 +Math.atan2(6.283185307179586, 7.283185307179586) = 0.711819549590 +Math.cbrt(-3.0) = -1.442249570307 +Math.log(-3.0) = NaN +Math.log10(-3.0) = NaN +Math.log1p(-3.0) = NaN +Math.exp(-3.0) = 0.049787068368 +Math.expm1(-3.0) = -0.950212931632 +Math.pow(-3.0, -2.0) = 0.111111111111 +Math.hypot(-3.0, -2.0) = 3.605551275464 +Math.cbrt(-2.0) = -1.259921049895 +Math.log(-2.0) = NaN +Math.log10(-2.0) = NaN +Math.log1p(-2.0) = NaN +Math.exp(-2.0) = 0.135335283237 +Math.expm1(-2.0) = -0.864664716763 +Math.pow(-2.0, -1.0) = -0.500000000000 +Math.hypot(-2.0, -1.0) = 2.236067977500 +Math.cbrt(-1.0) = -1.000000000000 +Math.log(-1.0) = NaN +Math.log10(-1.0) = NaN +Math.log1p(-1.0) = -Infinity +Math.exp(-1.0) = 0.367879441171 +Math.expm1(-1.0) = -0.632120558829 +Math.pow(-1.0, 0.0) = 1.000000000000 +Math.hypot(-1.0, 0.0) = 1.000000000000 +Math.cbrt(0.0) = 0.000000000000 +Math.log(0.0) = -Infinity +Math.log10(0.0) = -Infinity +Math.log1p(0.0) = 0.000000000000 +Math.exp(0.0) = 1.000000000000 +Math.expm1(0.0) = 0.000000000000 +Math.pow(0.0, 1.0) = 0.000000000000 +Math.hypot(0.0, 1.0) = 1.000000000000 +Math.cbrt(1.0) = 1.000000000000 +Math.log(1.0) = 0.000000000000 +Math.log10(1.0) = 0.000000000000 +Math.log1p(1.0) = 0.693147180560 +Math.exp(1.0) = 2.718281828459 +Math.expm1(1.0) = 1.718281828459 +Math.pow(1.0, 2.0) = 1.000000000000 +Math.hypot(1.0, 2.0) = 2.236067977500 +Math.cbrt(2.0) = 1.259921049895 +Math.log(2.0) = 0.693147180560 +Math.log10(2.0) = 0.301029995664 +Math.log1p(2.0) = 1.098612288668 +Math.exp(2.0) = 7.389056098931 +Math.expm1(2.0) = 6.389056098931 +Math.pow(2.0, 3.0) = 8.000000000000 +Math.hypot(2.0, 3.0) = 3.605551275464 +Math.cbrt(3.0) = 1.442249570307 +Math.log(3.0) = 1.098612288668 +Math.log10(3.0) = 0.477121254720 +Math.log1p(3.0) = 1.386294361120 +Math.exp(3.0) = 20.085536923188 +Math.expm1(3.0) = 19.085536923188 +Math.pow(3.0, 4.0) = 81.000000000000 +Math.hypot(3.0, 4.0) = 5.000000000000 +Math.ceil(0.0001) = 1.000000000000 +Math.floor(0.0001) = 0.000000000000 +Math.nextAfter(1.0, 2.0) = 1.000000000000 +Math.nextAfter(2.0, 1.0) = 2.000000000000 +Math.rint(0.5000001) = 1.000000000000 +StrictMath.sin(0.0) = 0.0 +StrictMath.sinh(0.0) = 0.0 +StrictMath.asin(0.0) = 0.0 +StrictMath.cos(0.0) = 1.0 +StrictMath.cosh(0.0) = 1.0 +StrictMath.acos(0.0) = 1.5707963267948966 +StrictMath.tan(0.0) = 0.0 +StrictMath.tanh(0.0) = 0.0 +StrictMath.atan(0.0) = 0.0 +StrictMath.atan2(0.0, 1.0) = 0.0 +StrictMath.sin(0.7853981633974483) = 0.7071067811865475 +StrictMath.sinh(0.7853981633974483) = 0.8686709614860095 +StrictMath.asin(0.7853981633974483) = 0.9033391107665127 +StrictMath.cos(0.7853981633974483) = 0.7071067811865476 +StrictMath.cosh(0.7853981633974483) = 1.3246090892520057 +StrictMath.acos(0.7853981633974483) = 0.6674572160283838 +StrictMath.tan(0.7853981633974483) = 0.9999999999999999 +StrictMath.tanh(0.7853981633974483) = 0.6557942026326724 +StrictMath.atan(0.7853981633974483) = 0.6657737500283538 +StrictMath.atan2(0.7853981633974483, 1.7853981633974483) = 0.41442380057704103 +StrictMath.sin(1.5707963267948966) = 1.0 +StrictMath.sinh(1.5707963267948966) = 2.3012989023072947 +StrictMath.asin(1.5707963267948966) = NaN +StrictMath.cos(1.5707963267948966) = 6.123233995736766E-17 +StrictMath.cosh(1.5707963267948966) = 2.5091784786580567 +StrictMath.acos(1.5707963267948966) = NaN +StrictMath.tan(1.5707963267948966) = 1.633123935319537E16 +StrictMath.tanh(1.5707963267948966) = 0.9171523356672744 +StrictMath.atan(1.5707963267948966) = 1.0038848218538872 +StrictMath.atan2(1.5707963267948966, 2.5707963267948966) = 0.5484797644174059 +StrictMath.sin(2.356194490192345) = 0.7071067811865476 +StrictMath.sinh(2.356194490192345) = 5.227971924677803 +StrictMath.asin(2.356194490192345) = NaN +StrictMath.cos(2.356194490192345) = -0.7071067811865475 +StrictMath.cosh(2.356194490192345) = 5.322752149519959 +StrictMath.acos(2.356194490192345) = NaN +StrictMath.tan(2.356194490192345) = -1.0000000000000002 +StrictMath.tanh(2.356194490192345) = 0.9821933800072388 +StrictMath.atan(2.356194490192345) = 1.1694228248157563 +StrictMath.atan2(2.356194490192345, 3.356194490192345) = 0.6120961173796371 +StrictMath.sin(3.141592653589793) = 1.2246467991473532E-16 +StrictMath.sinh(3.141592653589793) = 11.548739357257748 +StrictMath.asin(3.141592653589793) = NaN +StrictMath.cos(3.141592653589793) = -1.0 +StrictMath.cosh(3.141592653589793) = 11.591953275521519 +StrictMath.acos(3.141592653589793) = NaN +StrictMath.tan(3.141592653589793) = -1.2246467991473532E-16 +StrictMath.tanh(3.141592653589793) = 0.99627207622075 +StrictMath.atan(3.141592653589793) = 1.2626272556789115 +StrictMath.atan2(3.141592653589793, 4.141592653589793) = 0.6489487808147751 +StrictMath.sin(3.9269908169872414) = -0.7071067811865475 +StrictMath.sinh(3.9269908169872414) = 25.367158319374152 +StrictMath.asin(3.9269908169872414) = NaN +StrictMath.cos(3.9269908169872414) = -0.7071067811865477 +StrictMath.cosh(3.9269908169872414) = 25.386861192360772 +StrictMath.acos(3.9269908169872414) = NaN +StrictMath.tan(3.9269908169872414) = 0.9999999999999997 +StrictMath.tanh(3.9269908169872414) = 0.9992238948786412 +StrictMath.atan(3.9269908169872414) = 1.3214479677837223 +StrictMath.atan2(3.9269908169872414, 4.926990816987241) = 0.6729312291908799 +StrictMath.sin(4.71238898038469) = -1.0 +StrictMath.sinh(4.71238898038469) = 55.65439759941754 +StrictMath.asin(4.71238898038469) = NaN +StrictMath.cos(4.71238898038469) = -1.8369701987210297E-16 +StrictMath.cosh(4.71238898038469) = 55.66338089043867 +StrictMath.acos(4.71238898038469) = NaN +StrictMath.tan(4.71238898038469) = 5.443746451065123E15 +StrictMath.tanh(4.71238898038469) = 0.9998386139886326 +StrictMath.atan(4.71238898038469) = 1.3616916829711636 +StrictMath.atan2(4.71238898038469, 5.71238898038469) = 0.6897654692509959 +StrictMath.sin(5.497787143782138) = -0.7071067811865477 +StrictMath.sinh(5.497787143782138) = 122.07348351469281 +StrictMath.asin(5.497787143782138) = NaN +StrictMath.cos(5.497787143782138) = 0.7071067811865474 +StrictMath.cosh(5.497787143782138) = 122.07757933958217 +StrictMath.acos(5.497787143782138) = NaN +StrictMath.tan(5.497787143782138) = -1.0000000000000004 +StrictMath.tanh(5.497787143782138) = 0.9999664489997958 +StrictMath.atan(5.497787143782138) = 1.390871988014422 +StrictMath.atan2(5.497787143782138, 6.497787143782138) = 0.7022263981709682 +StrictMath.sin(6.283185307179586) = -2.4492935982947064E-16 +StrictMath.sinh(6.283185307179586) = 267.74489404101644 +StrictMath.asin(6.283185307179586) = NaN +StrictMath.cos(6.283185307179586) = 1.0 +StrictMath.cosh(6.283185307179586) = 267.7467614837482 +StrictMath.acos(6.283185307179586) = NaN +StrictMath.tan(6.283185307179586) = -2.4492935982947064E-16 +StrictMath.tanh(6.283185307179586) = 0.9999930253396107 +StrictMath.atan(6.283185307179586) = 1.4129651365067377 +StrictMath.atan2(6.283185307179586, 7.283185307179586) = 0.7118195495895945 +StrictMath.cbrt(-3.0) = -1.4422495703074083 +StrictMath.log(-3.0) = NaN +StrictMath.log10(-3.0) = NaN +StrictMath.log1p(-3.0) = NaN +StrictMath.exp(-3.0) = 0.049787068367863944 +StrictMath.expm1(-3.0) = -0.950212931632136 +StrictMath.pow(-3.0, -2.0) = 0.1111111111111111 +StrictMath.hypot(-3.0, -2.0) = 3.605551275463989 +StrictMath.cbrt(-2.0) = -1.2599210498948732 +StrictMath.log(-2.0) = NaN +StrictMath.log10(-2.0) = NaN +StrictMath.log1p(-2.0) = NaN +StrictMath.exp(-2.0) = 0.1353352832366127 +StrictMath.expm1(-2.0) = -0.8646647167633873 +StrictMath.pow(-2.0, -1.0) = -0.5 +StrictMath.hypot(-2.0, -1.0) = 2.23606797749979 +StrictMath.cbrt(-1.0) = -1.0 +StrictMath.log(-1.0) = NaN +StrictMath.log10(-1.0) = NaN +StrictMath.log1p(-1.0) = -Infinity +StrictMath.exp(-1.0) = 0.36787944117144233 +StrictMath.expm1(-1.0) = -0.6321205588285577 +StrictMath.pow(-1.0, 0.0) = 1.0 +StrictMath.hypot(-1.0, 0.0) = 1.0 +StrictMath.cbrt(0.0) = 0.0 +StrictMath.log(0.0) = -Infinity +StrictMath.log10(0.0) = -Infinity +StrictMath.log1p(0.0) = 0.0 +StrictMath.exp(0.0) = 1.0 +StrictMath.expm1(0.0) = 0.0 +StrictMath.pow(0.0, 1.0) = 0.0 +StrictMath.hypot(0.0, 1.0) = 1.0 +StrictMath.cbrt(1.0) = 1.0 +StrictMath.log(1.0) = 0.0 +StrictMath.log10(1.0) = 0.0 +StrictMath.log1p(1.0) = 0.6931471805599453 +StrictMath.exp(1.0) = 2.7182818284590455 +StrictMath.expm1(1.0) = 1.718281828459045 +StrictMath.pow(1.0, 2.0) = 1.0 +StrictMath.hypot(1.0, 2.0) = 2.23606797749979 +StrictMath.cbrt(2.0) = 1.2599210498948732 +StrictMath.log(2.0) = 0.6931471805599453 +StrictMath.log10(2.0) = 0.3010299956639812 +StrictMath.log1p(2.0) = 1.0986122886681096 +StrictMath.exp(2.0) = 7.38905609893065 +StrictMath.expm1(2.0) = 6.38905609893065 +StrictMath.pow(2.0, 3.0) = 8.0 +StrictMath.hypot(2.0, 3.0) = 3.605551275463989 +StrictMath.cbrt(3.0) = 1.4422495703074083 +StrictMath.log(3.0) = 1.0986122886681096 +StrictMath.log10(3.0) = 0.47712125471966244 +StrictMath.log1p(3.0) = 1.3862943611198906 +StrictMath.exp(3.0) = 20.085536923187668 +StrictMath.expm1(3.0) = 19.085536923187668 +StrictMath.pow(3.0, 4.0) = 81.0 +StrictMath.hypot(3.0, 4.0) = 5.0 +StrictMath.ceil(0.0001) = 1.0 +StrictMath.floor(0.0001) = 0.0 +StrictMath.nextAfter(1.0, 2.0) = 1.0000000000000002 +StrictMath.rint(0.5000001) = 1.0 diff --git a/test/123-inline-execute2/info.txt b/test/123-inline-execute2/info.txt new file mode 100644 index 0000000000..4a728a7f03 --- /dev/null +++ b/test/123-inline-execute2/info.txt @@ -0,0 +1 @@ +Sanity checks for added InlineNative methods. diff --git a/test/123-inline-execute2/src/Main.java b/test/123-inline-execute2/src/Main.java new file mode 100644 index 0000000000..9fadcfdbb7 --- /dev/null +++ b/test/123-inline-execute2/src/Main.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 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. + */ + +import java.util.Locale; + +public class Main { + public static void main(String args[]) { + for (int i = 0; i <= 360; i += 45) { + double d = i * (Math.PI / 180.0); + System.out.println("Math.sin(" + d + ") = " + + String.format(Locale.US, "%.12f", Math.sin(d))); + + System.out.println("Math.sinh(" + d + ") = " + + String.format(Locale.US, "%.12f", Math.sinh(d))); + System.out.println("Math.asin(" + d + ") = " + + String.format(Locale.US, "%.12f", Math.asin(d))); + System.out.println("Math.cos(" + d + ") = " + + String.format(Locale.US, "%.12f", Math.cos(d))); + System.out.println("Math.cosh(" + d + ") = " + + String.format(Locale.US, "%.12f", Math.cosh(d))); + System.out.println("Math.acos(" + d + ") = " + + String.format(Locale.US, "%.12f", Math.acos(d))); + if ((i + 90) % 180 != 0) { + System.out.println("Math.tan(" + d + ") = " + + String.format(Locale.US, "%.12f", Math.tan(d))); + } + System.out.println("Math.tanh(" + d + ") = " + + String.format(Locale.US, "%.12f", Math.tanh(d))); + System.out.println("Math.atan(" + d + ") = " + + String.format(Locale.US, "%.12f", Math.atan(d))); + System.out.println("Math.atan2(" + d + ", " + (d + 1.0) + ") = " + + String.format(Locale.US, "%.12f", Math.atan2(d, d + 1.0))); + } + + for (int j = -3; j <= 3; j++) { + double e = (double) j; + System.out.println("Math.cbrt(" + e + ") = " + + String.format(Locale.US, "%.12f", Math.cbrt(e))); + System.out.println("Math.log(" + e + ") = " + + String.format(Locale.US, "%.12f", Math.log(e))); + System.out.println("Math.log10(" + e + ") = " + + String.format(Locale.US, "%.12f", Math.log10(e))); + System.out.println("Math.log1p(" + e + ") = " + + String.format(Locale.US, "%.12f", Math.log1p(e))); + System.out.println("Math.exp(" + e + ") = " + + String.format(Locale.US, "%.12f", Math.exp(e))); + System.out.println("Math.expm1(" + e + ") = " + + String.format(Locale.US, "%.12f", Math.expm1(e))); + System.out.println("Math.pow(" + e + ", " + (e + 1.0) + ") = " + + String.format(Locale.US, "%.12f", Math.pow(e, e + 1.0))); + System.out.println("Math.hypot(" + e + ", " + (e + 1.0) + ") = " + + String.format(Locale.US, "%.12f", Math.hypot(e, e + 1.0))); + } + + System.out.println("Math.ceil(0.0001) = " + + String.format(Locale.US, "%.12f", Math.ceil(0.0001))); + System.out.println("Math.floor(0.0001) = " + + String.format(Locale.US, "%.12f", Math.floor(0.0001))); + System.out.println("Math.nextAfter(1.0, 2.0) = " + + String.format(Locale.US, "%.12f", Math.nextAfter(1.0, 2.0))); + System.out.println("Math.nextAfter(2.0, 1.0) = " + + String.format(Locale.US, "%.12f", Math.nextAfter(2.0, 1.0))); + System.out.println("Math.rint(0.5000001) = " + + String.format(Locale.US, "%.12f", Math.rint(0.5000001))); + + for (int i = 0; i <= 360; i += 45) { + double d = i * (StrictMath.PI / 180.0); + System.out.println("StrictMath.sin(" + d + ") = " + StrictMath.sin(d)); + System.out.println("StrictMath.sinh(" + d + ") = " + StrictMath.sinh(d)); + System.out.println("StrictMath.asin(" + d + ") = " + StrictMath.asin(d)); + System.out.println("StrictMath.cos(" + d + ") = " + StrictMath.cos(d)); + System.out.println("StrictMath.cosh(" + d + ") = " + StrictMath.cosh(d)); + System.out.println("StrictMath.acos(" + d + ") = " + StrictMath.acos(d)); + System.out.println("StrictMath.tan(" + d + ") = " + StrictMath.tan(d)); + System.out.println("StrictMath.tanh(" + d + ") = " + StrictMath.tanh(d)); + System.out.println("StrictMath.atan(" + d + ") = " + StrictMath.atan(d)); + System.out.println("StrictMath.atan2(" + d + ", " + (d + 1.0) + ") = " + + StrictMath.atan2(d, d + 1.0)); + } + + for (int j = -3; j <= 3; j++) { + double e = (double) j; + System.out.println("StrictMath.cbrt(" + e + ") = " + StrictMath.cbrt(e)); + System.out.println("StrictMath.log(" + e + ") = " + StrictMath.log(e)); + System.out.println("StrictMath.log10(" + e + ") = " + StrictMath.log10(e)); + System.out.println("StrictMath.log1p(" + e + ") = " + StrictMath.log1p(e)); + System.out.println("StrictMath.exp(" + e + ") = " + StrictMath.exp(e)); + System.out.println("StrictMath.expm1(" + e + ") = " + StrictMath.expm1(e)); + System.out.println("StrictMath.pow(" + e + ", " + (e + 1.0) + ") = " + + StrictMath.pow(e, e + 1.0)); + System.out.println("StrictMath.hypot(" + e + ", " + (e + 1.0) + ") = " + + StrictMath.hypot(e, e + 1.0)); + } + + System.out.println("StrictMath.ceil(0.0001) = " + StrictMath.ceil(0.0001)); + System.out.println("StrictMath.floor(0.0001) = " + StrictMath.floor(0.0001)); + System.out.println("StrictMath.nextAfter(1.0, 2.0) = " + StrictMath.nextAfter(1.0, 2.0)); + System.out.println("StrictMath.rint(0.5000001) = " + StrictMath.rint(0.5000001)); + } + +} diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java index 17e88ceb21..98251e4af3 100644 --- a/test/530-checker-lse/src/Main.java +++ b/test/530-checker-lse/src/Main.java @@ -25,6 +25,9 @@ class Circle { } class TestClass { + static { + sTestClassObj = new TestClass(-1, -2); + } TestClass() { } TestClass(int i, int j) { @@ -37,6 +40,7 @@ class TestClass { TestClass next; String str; static int si; + static TestClass sTestClassObj; } class SubTestClass extends TestClass { @@ -115,10 +119,11 @@ public class Main { } /// CHECK-START: int Main.test3(TestClass) load_store_elimination (before) + /// CHECK: NewInstance + /// CHECK: StaticFieldGet + /// CHECK: NewInstance /// CHECK: InstanceFieldSet - /// CHECK: InstanceFieldGet /// CHECK: InstanceFieldSet - /// CHECK: NewInstance /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldGet @@ -127,24 +132,31 @@ public class Main { /// CHECK: InstanceFieldGet /// CHECK-START: int Main.test3(TestClass) load_store_elimination (after) + /// CHECK: NewInstance + /// CHECK: StaticFieldGet + /// CHECK: NewInstance + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldSet - /// CHECK: InstanceFieldGet /// CHECK: InstanceFieldSet - /// CHECK: NewInstance - /// CHECK-NOT: InstanceFieldSet /// CHECK-NOT: InstanceFieldGet + /// CHECK-NOT: StaticFieldGet - // A new allocation shouldn't alias with pre-existing values. + // A new allocation (even non-singleton) shouldn't alias with pre-existing values. static int test3(TestClass obj) { // Do an allocation here to avoid the HLoadClass and HClinitCheck // at the second allocation. new TestClass(); + TestClass obj1 = TestClass.sTestClassObj; + TestClass obj2 = new TestClass(); // Cannot alias with obj or obj1 which pre-exist. + obj.next = obj2; // Make obj2 a non-singleton. + // All stores below need to stay since obj/obj1/obj2 are not singletons. obj.i = 1; - obj.next.j = 2; - TestClass obj2 = new TestClass(); + obj1.j = 2; + // Following stores won't kill values of obj.i and obj1.j. obj2.i = 3; obj2.j = 4; - return obj.i + obj.next.j + obj2.i + obj2.j; + return obj.i + obj1.j + obj2.i + obj2.j; } /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (before) diff --git a/test/dexdump/bytecodes.txt b/test/dexdump/bytecodes.txt index d14c47c886..4c8b79b7dd 100755 --- a/test/dexdump/bytecodes.txt +++ b/test/dexdump/bytecodes.txt @@ -196,6 +196,7 @@ Class #4 - name : 'icon' type : 'I' access : 0x0019 (PUBLIC STATIC FINAL) + value : 2130837504 Instance fields - Direct methods - #0 : (in Lcom/google/android/test/R$drawable;) diff --git a/test/dexdump/bytecodes.xml b/test/dexdump/bytecodes.xml index 0581677f6a..8e54dd33ce 100755 --- a/test/dexdump/bytecodes.xml +++ b/test/dexdump/bytecodes.xml @@ -97,6 +97,7 @@ static="true" final="true" visibility="public" + value="2130837504" > </field> <constructor name="R.drawable" diff --git a/test/dexdump/staticfields.dex b/test/dexdump/staticfields.dex Binary files differnew file mode 100644 index 0000000000..a07c46ef59 --- /dev/null +++ b/test/dexdump/staticfields.dex diff --git a/test/dexdump/staticfields.lst b/test/dexdump/staticfields.lst new file mode 100644 index 0000000000..5375b8e0dc --- /dev/null +++ b/test/dexdump/staticfields.lst @@ -0,0 +1,2 @@ +#staticfields.dex +0x000001bc 8 StaticFields <init> ()V StaticFields.java 24 diff --git a/test/dexdump/staticfields.txt b/test/dexdump/staticfields.txt new file mode 100644 index 0000000000..022605f90d --- /dev/null +++ b/test/dexdump/staticfields.txt @@ -0,0 +1,126 @@ +Processing 'staticfields.dex'... +Opened 'staticfields.dex', DEX version '035' +DEX file header: +magic : 'dex\n035\0' +checksum : 52d4fc6d +signature : 6e82...2f27 +file_size : 1264 +header_size : 112 +link_size : 0 +link_off : 0 (0x000000) +string_ids_size : 28 +string_ids_off : 112 (0x000070) +type_ids_size : 12 +type_ids_off : 224 (0x0000e0) +proto_ids_size : 1 +proto_ids_off : 272 (0x000110) +field_ids_size : 12 +field_ids_off : 284 (0x00011c) +method_ids_size : 2 +method_ids_off : 380 (0x00017c) +class_defs_size : 1 +class_defs_off : 396 (0x00018c) +data_size : 836 +data_off : 428 (0x0001ac) + +Class #0 header: +class_idx : 6 +access_flags : 1 (0x0001) +superclass_idx : 7 +interfaces_off : 0 (0x000000) +source_file_idx : 11 +annotations_off : 0 (0x000000) +class_data_off : 1067 (0x00042b) +static_fields_size : 12 +instance_fields_size: 0 +direct_methods_size : 1 +virtual_methods_size: 0 + +Class #0 - + Class descriptor : 'LStaticFields;' + Access flags : 0x0001 (PUBLIC) + Superclass : 'Ljava/lang/Object;' + Interfaces - + Static fields - + #0 : (in LStaticFields;) + name : 'test00_public_static_final_byte_42' + type : 'B' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 42 + #1 : (in LStaticFields;) + name : 'test01_public_static_final_short_43' + type : 'S' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 43 + #2 : (in LStaticFields;) + name : 'test02_public_static_final_char_X' + type : 'C' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 88 + #3 : (in LStaticFields;) + name : 'test03_public_static_final_int_44' + type : 'I' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 44 + #4 : (in LStaticFields;) + name : 'test04_public_static_final_long_45' + type : 'J' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 45 + #5 : (in LStaticFields;) + name : 'test05_public_static_final_float_46_47' + type : 'F' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 46.470001 + #6 : (in LStaticFields;) + name : 'test06_public_static_final_double_48_49' + type : 'D' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 48.490000 + #7 : (in LStaticFields;) + name : 'test07_public_static_final_string' + type : 'Ljava/lang/String;' + access : 0x0019 (PUBLIC STATIC FINAL) + value : "abc \\><\"'&\t\r\n" + #8 : (in LStaticFields;) + name : 'test08_public_static_final_object_null' + type : 'Ljava/lang/Object;' + access : 0x0019 (PUBLIC STATIC FINAL) + value : null + #9 : (in LStaticFields;) + name : 'test09_public_static_final_boolean_true' + type : 'Z' + access : 0x0019 (PUBLIC STATIC FINAL) + value : true + #10 : (in LStaticFields;) + name : 'test10_private_static_final_int_50' + type : 'I' + access : 0x001a (PRIVATE STATIC FINAL) + value : 50 + #11 : (in LStaticFields;) + name : 'test99_empty_value' + type : 'I' + access : 0x0019 (PUBLIC STATIC FINAL) + Instance fields - + Direct methods - + #0 : (in LStaticFields;) + name : '<init>' + type : '()V' + access : 0x10001 (PUBLIC CONSTRUCTOR) + code - + registers : 1 + ins : 1 + outs : 1 + insns size : 4 16-bit code units +0001ac: |[0001ac] StaticFields.<init>:()V +0001bc: 7010 0100 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0001 +0001c2: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=24 + locals : + 0x0000 - 0x0004 reg=0 this LStaticFields; + + Virtual methods - + source_file_idx : 11 (StaticFields.java) + diff --git a/test/dexdump/staticfields.xml b/test/dexdump/staticfields.xml new file mode 100644 index 0000000000..6cff71b69f --- /dev/null +++ b/test/dexdump/staticfields.xml @@ -0,0 +1,129 @@ +<api> +<package name="" +> +<class name="StaticFields" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + visibility="public" +> +<field name="test00_public_static_final_byte_42" + type="byte" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="42" +> +</field> +<field name="test01_public_static_final_short_43" + type="short" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="43" +> +</field> +<field name="test02_public_static_final_char_X" + type="char" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="88" +> +</field> +<field name="test03_public_static_final_int_44" + type="int" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="44" +> +</field> +<field name="test04_public_static_final_long_45" + type="long" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="45" +> +</field> +<field name="test05_public_static_final_float_46_47" + type="float" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="46.470001" +> +</field> +<field name="test06_public_static_final_double_48_49" + type="double" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="48.490000" +> +</field> +<field name="test07_public_static_final_string" + type="java.lang.String" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="abc \><"'&	
" +> +</field> +<field name="test08_public_static_final_object_null" + type="java.lang.Object" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="null" +> +</field> +<field name="test09_public_static_final_boolean_true" + type="boolean" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="true" +> +</field> +<field name="test99_empty_value" + type="int" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" +> +</field> +<constructor name="StaticFields" + type="StaticFields" + static="false" + final="false" + visibility="public" +> +</constructor> +</class> +</package> +</api> |