immune_spaces_test.cc revision df0a8275abadc96a6363b59f31c64981571d6ed9
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "common_runtime_test.h" 18#include "gc/collector/immune_spaces.h" 19#include "gc/space/image_space.h" 20#include "gc/space/space-inl.h" 21#include "oat_file.h" 22#include "thread-inl.h" 23 24namespace art { 25namespace mirror { 26class Object; 27} // namespace mirror 28namespace gc { 29namespace collector { 30 31class ImmuneSpacesTest : public CommonRuntimeTest {}; 32 33class DummySpace : public space::ContinuousSpace { 34 public: 35 DummySpace(uint8_t* begin, uint8_t* end) 36 : ContinuousSpace("DummySpace", 37 space::kGcRetentionPolicyNeverCollect, 38 begin, 39 end, 40 /*limit*/end) {} 41 42 space::SpaceType GetType() const OVERRIDE { 43 return space::kSpaceTypeMallocSpace; 44 } 45 46 bool CanMoveObjects() const OVERRIDE { 47 return false; 48 } 49 50 accounting::ContinuousSpaceBitmap* GetLiveBitmap() const OVERRIDE { 51 return nullptr; 52 } 53 54 accounting::ContinuousSpaceBitmap* GetMarkBitmap() const OVERRIDE { 55 return nullptr; 56 } 57}; 58 59TEST_F(ImmuneSpacesTest, AppendBasic) { 60 ImmuneSpaces spaces; 61 uint8_t* const base = reinterpret_cast<uint8_t*>(0x1000); 62 DummySpace a(base, base + 45 * KB); 63 DummySpace b(a.Limit(), a.Limit() + 813 * KB); 64 { 65 WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); 66 spaces.AddSpace(&a); 67 spaces.AddSpace(&b); 68 } 69 EXPECT_TRUE(spaces.ContainsSpace(&a)); 70 EXPECT_TRUE(spaces.ContainsSpace(&b)); 71 EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().Begin()), a.Begin()); 72 EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().End()), b.Limit()); 73} 74 75class DummyOatFile : public OatFile { 76 public: 77 DummyOatFile(uint8_t* begin, uint8_t* end) : OatFile("Location", /*is_executable*/ false) { 78 begin_ = begin; 79 end_ = end; 80 } 81}; 82 83class DummyImageSpace : public space::ImageSpace { 84 public: 85 DummyImageSpace(MemMap* map, 86 accounting::ContinuousSpaceBitmap* live_bitmap, 87 std::unique_ptr<DummyOatFile>&& oat_file) 88 : ImageSpace("DummyImageSpace", 89 /*image_location*/"", 90 map, 91 live_bitmap, 92 map->End()) { 93 oat_file_ = std::move(oat_file); 94 oat_file_non_owned_ = oat_file_.get(); 95 } 96 97 // Size is the size of the image space, oat offset is where the oat file is located 98 // after the end of image space. oat_size is the size of the oat file. 99 static DummyImageSpace* Create(size_t size, size_t oat_offset, size_t oat_size) { 100 std::string error_str; 101 std::unique_ptr<MemMap> map(MemMap::MapAnonymous("DummyImageSpace", 102 nullptr, 103 size, 104 PROT_READ | PROT_WRITE, 105 /*low_4gb*/true, 106 /*reuse*/false, 107 &error_str)); 108 if (map == nullptr) { 109 LOG(ERROR) << error_str; 110 return nullptr; 111 } 112 std::unique_ptr<accounting::ContinuousSpaceBitmap> live_bitmap( 113 accounting::ContinuousSpaceBitmap::Create("bitmap", map->Begin(), map->Size())); 114 if (live_bitmap == nullptr) { 115 return nullptr; 116 } 117 // The actual mapped oat file may not be directly after the image for the app image case. 118 std::unique_ptr<DummyOatFile> oat_file(new DummyOatFile(map->End() + oat_offset, 119 map->End() + oat_offset + oat_size)); 120 // Create image header. 121 ImageSection sections[ImageHeader::kSectionCount]; 122 new (map->Begin()) ImageHeader( 123 /*image_begin*/PointerToLowMemUInt32(map->Begin()), 124 /*image_size*/map->Size(), 125 sections, 126 /*image_roots*/PointerToLowMemUInt32(map->Begin()) + 1, 127 /*oat_checksum*/0u, 128 // The oat file data in the header is always right after the image space. 129 /*oat_file_begin*/PointerToLowMemUInt32(map->End()), 130 /*oat_data_begin*/PointerToLowMemUInt32(map->End()), 131 /*oat_data_end*/PointerToLowMemUInt32(map->End() + oat_size), 132 /*oat_file_end*/PointerToLowMemUInt32(map->End() + oat_size), 133 /*boot_image_begin*/0u, 134 /*boot_image_size*/0u, 135 /*boot_oat_begin*/0u, 136 /*boot_oat_size*/0u, 137 /*pointer_size*/sizeof(void*), 138 /*compile_pic*/false, 139 /*is_pic*/false, 140 ImageHeader::kStorageModeUncompressed, 141 /*storage_size*/0u); 142 return new DummyImageSpace(map.release(), live_bitmap.release(), std::move(oat_file)); 143 } 144}; 145 146TEST_F(ImmuneSpacesTest, AppendAfterImage) { 147 ImmuneSpaces spaces; 148 constexpr size_t image_size = 123 * kPageSize; 149 constexpr size_t image_oat_size = 321 * kPageSize; 150 std::unique_ptr<DummyImageSpace> image_space(DummyImageSpace::Create(image_size, 151 0, 152 image_oat_size)); 153 ASSERT_TRUE(image_space != nullptr); 154 const ImageHeader& image_header = image_space->GetImageHeader(); 155 EXPECT_EQ(image_header.GetImageSize(), image_size); 156 EXPECT_EQ(static_cast<size_t>(image_header.GetOatFileEnd() - image_header.GetOatFileBegin()), 157 image_oat_size); 158 DummySpace space(image_header.GetOatFileEnd(), image_header.GetOatFileEnd() + 813 * kPageSize); 159 EXPECT_NE(image_space->Limit(), space.Begin()); 160 { 161 WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); 162 spaces.AddSpace(image_space.get()); 163 spaces.AddSpace(&space); 164 } 165 EXPECT_TRUE(spaces.ContainsSpace(image_space.get())); 166 EXPECT_TRUE(spaces.ContainsSpace(&space)); 167 // CreateLargestImmuneRegion should have coalesced the two spaces since the oat code after the 168 // image prevents gaps. 169 // Check that we have a continuous region. 170 EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().Begin()), 171 image_space->Begin()); 172 EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().End()), space.Limit()); 173 // Check that appending with a gap between the map does not include the oat file. 174 image_space.reset(DummyImageSpace::Create(image_size, kPageSize, image_oat_size)); 175 spaces.Reset(); 176 { 177 WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); 178 spaces.AddSpace(image_space.get()); 179 } 180 EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().Begin()), 181 image_space->Begin()); 182 // Size should be equal, we should not add the oat file since it is not adjacent to the image 183 // space. 184 EXPECT_EQ(spaces.GetLargestImmuneRegion().Size(), image_size); 185} 186 187} // namespace collector 188} // namespace gc 189} // namespace art 190