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 "immune_spaces.h"
18 
19 #include <tuple>
20 #include <vector>
21 
22 #include "base/logging.h"  // For VLOG.
23 #include "gc/space/space-inl.h"
24 #include "mirror/object.h"
25 #include "oat/oat_file.h"
26 
27 namespace art HIDDEN {
28 namespace gc {
29 namespace collector {
30 
Reset()31 void ImmuneSpaces::Reset() {
32   spaces_.clear();
33   largest_immune_region_.Reset();
34 }
35 
CreateLargestImmuneRegion()36 void ImmuneSpaces::CreateLargestImmuneRegion() {
37   uintptr_t best_begin = 0u;
38   uintptr_t best_end = 0u;
39   uintptr_t best_heap_size = 0u;
40   uintptr_t cur_begin = 0u;
41   uintptr_t cur_end = 0u;
42   uintptr_t cur_heap_size = 0u;
43   using Interval = std::tuple</*start*/uintptr_t, /*end*/uintptr_t, /*is_heap*/bool>;
44   std::vector<Interval> intervals;
45   for (space::ContinuousSpace* space : GetSpaces()) {
46     uintptr_t space_begin = reinterpret_cast<uintptr_t>(space->Begin());
47     uintptr_t space_end = reinterpret_cast<uintptr_t>(space->Limit());
48     if (space->IsImageSpace()) {
49       // For the boot image, the boot oat file is always directly after. For app images it may not
50       // be if the app image was mapped at a random address.
51       space::ImageSpace* image_space = space->AsImageSpace();
52       // Update the end to include the other non-heap sections.
53       space_end = RoundUp(reinterpret_cast<uintptr_t>(image_space->GetImageEnd()),
54                           kElfSegmentAlignment);
55       // For the app image case, GetOatFileBegin is where the oat file was mapped during image
56       // creation, the actual oat file could be somewhere else.
57       const OatFile* const image_oat_file = image_space->GetOatFile();
58       if (image_oat_file != nullptr) {
59         intervals.push_back(Interval(reinterpret_cast<uintptr_t>(image_oat_file->Begin()),
60                                      reinterpret_cast<uintptr_t>(image_oat_file->End()),
61                                      /*image=*/false));
62       }
63     }
64     intervals.push_back(Interval(space_begin, space_end, /*is_heap*/true));
65   }
66   std::sort(intervals.begin(), intervals.end());
67   // Intervals are already sorted by begin, if a new interval begins at the end of the current
68   // region then we append, otherwise we restart the current interval. To prevent starting an
69   // interval on an oat file, ignore oat files that are not extending an existing interval.
70   // If the total number of image bytes in the current interval is larger than the current best
71   // one, then we set the best one to be the current one.
72   for (const Interval& interval : intervals) {
73     const uintptr_t begin = std::get<0>(interval);
74     const uintptr_t end = std::get<1>(interval);
75     const bool is_heap = std::get<2>(interval);
76     VLOG(collector) << "Interval " << reinterpret_cast<const void*>(begin) << "-"
77                     << reinterpret_cast<const void*>(end) << " is_heap=" << is_heap;
78     DCHECK_GE(end, begin);
79     DCHECK_GE(begin, cur_end);
80     // New interval is not at the end of the current one, start a new interval if we are a heap
81     // interval. Otherwise continue since we never start a new region with non image intervals.
82     if (begin != cur_end) {
83       if (!is_heap) {
84         continue;
85       }
86       // Not extending, reset the region.
87       cur_begin = begin;
88       cur_heap_size = 0;
89     }
90     cur_end = end;
91     if (is_heap) {
92       // Only update if the total number of image bytes is greater than the current best one.
93       // We don't want to count the oat file bytes since these contain no java objects.
94       cur_heap_size += end - begin;
95       if (cur_heap_size > best_heap_size) {
96         best_begin = cur_begin;
97         best_end = cur_end;
98         best_heap_size = cur_heap_size;
99       }
100     }
101   }
102   largest_immune_region_.SetBegin(reinterpret_cast<mirror::Object*>(best_begin));
103   largest_immune_region_.SetEnd(reinterpret_cast<mirror::Object*>(best_end));
104   VLOG(collector) << "Immune region " << largest_immune_region_.Begin() << "-"
105                   << largest_immune_region_.End();
106 }
107 
AddSpace(space::ContinuousSpace * space)108 void ImmuneSpaces::AddSpace(space::ContinuousSpace* space) {
109   DCHECK(spaces_.find(space) == spaces_.end()) << *space;
110   // Bind live to mark bitmap if necessary.
111   if (space->GetLiveBitmap() != nullptr && !space->HasBoundBitmaps()) {
112     CHECK(space->IsContinuousMemMapAllocSpace());
113     space->AsContinuousMemMapAllocSpace()->BindLiveToMarkBitmap();
114   }
115   spaces_.insert(space);
116   CreateLargestImmuneRegion();
117 }
118 
operator ()(space::ContinuousSpace * a,space::ContinuousSpace * b) const119 bool ImmuneSpaces::CompareByBegin::operator()(space::ContinuousSpace* a, space::ContinuousSpace* b)
120     const {
121   return a->Begin() < b->Begin();
122 }
123 
ContainsSpace(space::ContinuousSpace * space) const124 bool ImmuneSpaces::ContainsSpace(space::ContinuousSpace* space) const {
125   return spaces_.find(space) != spaces_.end();
126 }
127 
128 }  // namespace collector
129 }  // namespace gc
130 }  // namespace art
131