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