diff options
Diffstat (limited to 'runtime/dexopt_test.cc')
| -rw-r--r-- | runtime/dexopt_test.cc | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc new file mode 100644 index 0000000000..69c6151d9e --- /dev/null +++ b/runtime/dexopt_test.cc @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <string> +#include <vector> + +#include <backtrace/BacktraceMap.h> +#include <gtest/gtest.h> + +#include "common_runtime_test.h" +#include "compiler_callbacks.h" +#include "dex2oat_environment_test.h" +#include "dexopt_test.h" +#include "gc/space/image_space.h" +#include "mem_map.h" + +namespace art { +void DexoptTest::SetUp() { + ReserveImageSpace(); + Dex2oatEnvironmentTest::SetUp(); +} + +void DexoptTest::PreRuntimeCreate() { + std::string error_msg; + ASSERT_TRUE(PreRelocateImage(GetImageLocation(), &error_msg)) << error_msg; + ASSERT_TRUE(PreRelocateImage(GetImageLocation2(), &error_msg)) << error_msg; + UnreserveImageSpace(); +} + +void DexoptTest::PostRuntimeCreate() { + ReserveImageSpace(); +} + +void DexoptTest::GenerateOatForTest(const std::string& dex_location, + const std::string& oat_location, + CompilerFilter::Filter filter, + bool relocate, + bool pic, + bool with_alternate_image) { + std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA)); + std::string dalvik_cache_tmp = dalvik_cache + ".redirected"; + + if (!relocate) { + // Temporarily redirect the dalvik cache so dex2oat doesn't find the + // relocated image file. + ASSERT_EQ(0, rename(dalvik_cache.c_str(), dalvik_cache_tmp.c_str())) << strerror(errno); + } + + std::vector<std::string> args; + args.push_back("--dex-file=" + dex_location); + args.push_back("--oat-file=" + oat_location); + args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter)); + args.push_back("--runtime-arg"); + + // Use -Xnorelocate regardless of the relocate argument. + // We control relocation by redirecting the dalvik cache when needed + // rather than use this flag. + args.push_back("-Xnorelocate"); + + if (pic) { + args.push_back("--compile-pic"); + } + + std::string image_location = GetImageLocation(); + if (with_alternate_image) { + args.push_back("--boot-image=" + GetImageLocation2()); + } + + std::string error_msg; + ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg; + + if (!relocate) { + // Restore the dalvik cache if needed. + ASSERT_EQ(0, rename(dalvik_cache_tmp.c_str(), dalvik_cache.c_str())) << strerror(errno); + } + + // Verify the odex file was generated as expected. + std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_location.c_str(), + oat_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); + ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; + EXPECT_EQ(pic, odex_file->IsPic()); + EXPECT_EQ(filter, odex_file->GetCompilerFilter()); + + std::unique_ptr<ImageHeader> image_header( + gc::space::ImageSpace::ReadImageHeader(image_location.c_str(), + kRuntimeISA, + &error_msg)); + ASSERT_TRUE(image_header != nullptr) << error_msg; + const OatHeader& oat_header = odex_file->GetOatHeader(); + uint32_t combined_checksum = OatFileAssistant::CalculateCombinedImageChecksum(); + + if (CompilerFilter::DependsOnImageChecksum(filter)) { + if (with_alternate_image) { + EXPECT_NE(combined_checksum, oat_header.GetImageFileLocationOatChecksum()); + } else { + EXPECT_EQ(combined_checksum, oat_header.GetImageFileLocationOatChecksum()); + } + } + + if (!with_alternate_image) { + if (CompilerFilter::IsBytecodeCompilationEnabled(filter)) { + if (relocate) { + EXPECT_EQ(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()), + oat_header.GetImageFileLocationOatDataBegin()); + EXPECT_EQ(image_header->GetPatchDelta(), oat_header.GetImagePatchDelta()); + } else { + EXPECT_NE(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()), + oat_header.GetImageFileLocationOatDataBegin()); + EXPECT_NE(image_header->GetPatchDelta(), oat_header.GetImagePatchDelta()); + } + } + } +} + +void DexoptTest::GenerateOdexForTest(const std::string& dex_location, + const std::string& odex_location, + CompilerFilter::Filter filter) { + GenerateOatForTest(dex_location, + odex_location, + filter, + /*relocate*/false, + /*pic*/false, + /*with_alternate_image*/false); +} + +void DexoptTest::GeneratePicOdexForTest(const std::string& dex_location, + const std::string& odex_location, + CompilerFilter::Filter filter) { + GenerateOatForTest(dex_location, + odex_location, + filter, + /*relocate*/false, + /*pic*/true, + /*with_alternate_image*/false); +} + +void DexoptTest::GenerateOatForTest(const char* dex_location, + CompilerFilter::Filter filter, + bool relocate, + bool pic, + bool with_alternate_image) { + std::string oat_location; + std::string error_msg; + ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename( + dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg; + GenerateOatForTest(dex_location, + oat_location, + filter, + relocate, + pic, + with_alternate_image); +} + +void DexoptTest::GenerateOatForTest(const char* dex_location, CompilerFilter::Filter filter) { + GenerateOatForTest(dex_location, + filter, + /*relocate*/true, + /*pic*/false, + /*with_alternate_image*/false); +} + +bool DexoptTest::PreRelocateImage(const std::string& image_location, std::string* error_msg) { + std::string image; + if (!GetCachedImageFile(image_location, &image, error_msg)) { + return false; + } + + std::string patchoat = GetAndroidRoot(); + patchoat += kIsDebugBuild ? "/bin/patchoatd" : "/bin/patchoat"; + + std::vector<std::string> argv; + argv.push_back(patchoat); + argv.push_back("--input-image-location=" + image_location); + argv.push_back("--output-image-file=" + image); + argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(kRuntimeISA))); + argv.push_back("--base-offset-delta=0x00008000"); + return Exec(argv, error_msg); +} + +void DexoptTest::ReserveImageSpace() { + MemMap::Init(); + + // Ensure a chunk of memory is reserved for the image space. + // The reservation_end includes room for the main space that has to come + // right after the image in case of the GSS collector. + uintptr_t reservation_start = ART_BASE_ADDRESS; + uintptr_t reservation_end = ART_BASE_ADDRESS + 384 * MB; + + std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true)); + ASSERT_TRUE(map.get() != nullptr) << "Failed to build process map"; + for (BacktraceMap::const_iterator it = map->begin(); + reservation_start < reservation_end && it != map->end(); ++it) { + ReserveImageSpaceChunk(reservation_start, std::min(it->start, reservation_end)); + reservation_start = std::max(reservation_start, it->end); + } + ReserveImageSpaceChunk(reservation_start, reservation_end); +} + +void DexoptTest::ReserveImageSpaceChunk(uintptr_t start, uintptr_t end) { + if (start < end) { + std::string error_msg; + image_reservation_.push_back(std::unique_ptr<MemMap>( + MemMap::MapAnonymous("image reservation", + reinterpret_cast<uint8_t*>(start), end - start, + PROT_NONE, false, false, &error_msg))); + ASSERT_TRUE(image_reservation_.back().get() != nullptr) << error_msg; + LOG(INFO) << "Reserved space for image " << + reinterpret_cast<void*>(image_reservation_.back()->Begin()) << "-" << + reinterpret_cast<void*>(image_reservation_.back()->End()); + } +} + +void DexoptTest::UnreserveImageSpace() { + image_reservation_.clear(); +} + +} // namespace art |