blob: 14731f125e4b11891e5df2c57ac0c83c928c9db5 [file] [log] [blame]
Carl Shapiro69759ea2011-07-21 18:13:35 -07001// Copyright 2011 Google Inc. All Rights Reserved.
Carl Shapiro69759ea2011-07-21 18:13:35 -07002
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07003#include "space.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -07004
5#include <sys/mman.h>
6
Elliott Hughes90a33692011-08-30 13:27:07 -07007#include "UniquePtr.h"
Brian Carlstrom4a289ed2011-08-16 17:17:49 -07008#include "file.h"
9#include "image.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070010#include "logging.h"
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070011#include "os.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070012#include "utils.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -070013
14namespace art {
15
jeffhaoc1160702011-10-27 15:48:45 -070016Space* Space::Create(const std::string& name, size_t initial_size, size_t maximum_size, size_t growth_size, byte* requested_base) {
Elliott Hughes307f75d2011-10-12 18:04:40 -070017 UniquePtr<Space> space(new Space(name));
jeffhaoc1160702011-10-27 15:48:45 -070018 bool success = space->Init(initial_size, maximum_size, growth_size, requested_base);
Carl Shapiro69759ea2011-07-21 18:13:35 -070019 if (!success) {
20 return NULL;
21 } else {
22 return space.release();
23 }
24}
25
Brian Carlstrom58ae9412011-10-04 00:56:06 -070026Space* Space::CreateFromImage(const std::string& image_file_name) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070027 CHECK(image_file_name != NULL);
Elliott Hughes307f75d2011-10-12 18:04:40 -070028 UniquePtr<Space> space(new Space(image_file_name));
Brian Carlstrom0a5b14d2011-09-27 13:29:15 -070029 bool success = space->InitFromImage(image_file_name);
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070030 if (!success) {
31 return NULL;
32 } else {
33 return space.release();
34 }
35}
36
37Space::~Space() {}
38
Carl Shapiro69759ea2011-07-21 18:13:35 -070039void* Space::CreateMallocSpace(void* base,
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070040 size_t initial_size,
Carl Shapiro69759ea2011-07-21 18:13:35 -070041 size_t maximum_size) {
42 errno = 0;
43 bool is_locked = false;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070044 size_t commit_size = initial_size / 2;
Carl Shapiro69759ea2011-07-21 18:13:35 -070045 void* msp = create_contiguous_mspace_with_base(commit_size, maximum_size,
46 is_locked, base);
47 if (msp != NULL) {
48 // Do not permit the heap grow past the starting size without our
49 // intervention.
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070050 mspace_set_max_allowed_footprint(msp, initial_size);
Carl Shapiro69759ea2011-07-21 18:13:35 -070051 } else {
52 // There is no guarantee that errno has meaning when the call
53 // fails, but it often does.
54 PLOG(ERROR) << "create_contiguous_mspace_with_base failed";
55 }
56 return msp;
57}
58
jeffhaoc1160702011-10-27 15:48:45 -070059bool Space::Init(size_t initial_size, size_t maximum_size, size_t growth_size, byte* requested_base) {
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -080060 VLOG(startup) << "Space::Init entering " << name_
61 << " initial_size=" << initial_size
62 << " maximum_size=" << maximum_size
63 << " growth_size=" << growth_size
64 << " requested_base=" << reinterpret_cast<void*>(requested_base);
jeffhaoc1160702011-10-27 15:48:45 -070065 if (initial_size > growth_size) {
66 LOG(ERROR) << "Failed to create space with initial size > growth size ("
Elliott Hughes6c9c06d2011-11-07 16:43:47 -080067 << initial_size << ">" << growth_size << "): " << name_;
jeffhaoc1160702011-10-27 15:48:45 -070068 return false;
69 }
70 if (growth_size > maximum_size) {
71 LOG(ERROR) << "Failed to create space with growth size > maximum size ("
Elliott Hughes6c9c06d2011-11-07 16:43:47 -080072 << growth_size << ">" << maximum_size << "): " << name_;
Carl Shapiro69759ea2011-07-21 18:13:35 -070073 return false;
74 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070075 size_t length = RoundUp(maximum_size, kPageSize);
Carl Shapiro69759ea2011-07-21 18:13:35 -070076 int prot = PROT_READ | PROT_WRITE;
Elliott Hughes6c9c06d2011-11-07 16:43:47 -080077 UniquePtr<MemMap> mem_map(MemMap::Map(name_.c_str(), requested_base, length, prot));
Elliott Hughes90a33692011-08-30 13:27:07 -070078 if (mem_map.get() == NULL) {
Elliott Hughes6c9c06d2011-11-07 16:43:47 -080079 LOG(WARNING) << "Failed to allocate " << length << " bytes for space: " << name_;
Carl Shapiro69759ea2011-07-21 18:13:35 -070080 return false;
81 }
Elliott Hughes6c9c06d2011-11-07 16:43:47 -080082 InitFromMemMap(mem_map.release());
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070083 maximum_size_ = maximum_size;
jeffhaoc1160702011-10-27 15:48:45 -070084 size_t growth_length = RoundUp(growth_size, kPageSize);
85 growth_size_ = growth_size;
86 growth_limit_ = base_ + growth_length;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070087 mspace_ = CreateMallocSpace(base_, initial_size, maximum_size);
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070088 if (mspace_ == NULL) {
Elliott Hughes6c9c06d2011-11-07 16:43:47 -080089 LOG(WARNING) << "Failed to create mspace for space: " << name_;
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070090 return false;
91 }
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -080092 VLOG(startup) << "Space::Init exiting";
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070093 return true;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070094}
95
Elliott Hughes6c9c06d2011-11-07 16:43:47 -080096void Space::InitFromMemMap(MemMap* mem_map) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070097 mem_map_.reset(mem_map);
Brian Carlstromdb4d5402011-08-09 12:18:28 -070098 base_ = mem_map_->GetAddress();
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070099 limit_ = base_ + mem_map->GetLength();
100}
101
Brian Carlstrom58ae9412011-10-04 00:56:06 -0700102bool Space::InitFromImage(const std::string& image_file_name) {
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700103 Runtime* runtime = Runtime::Current();
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800104 VLOG(startup) << "Space::InitFromImage entering"
105 << " image_file_name=" << image_file_name;
Brian Carlstrom58ae9412011-10-04 00:56:06 -0700106 UniquePtr<File> file(OS::OpenFile(image_file_name.c_str(), false));
Elliott Hughes90a33692011-08-30 13:27:07 -0700107 if (file.get() == NULL) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700108 LOG(WARNING) << "Failed to open " << image_file_name;
Carl Shapiro69759ea2011-07-21 18:13:35 -0700109 return false;
110 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700111 ImageHeader image_header;
112 bool success = file->ReadFully(&image_header, sizeof(image_header));
113 if (!success || !image_header.IsValid()) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700114 LOG(WARNING) << "Invalid image header " << image_file_name;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700115 return false;
116 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700117 UniquePtr<MemMap> map(MemMap::Map(image_header.GetImageBaseAddr(),
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700118 file->Length(),
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700119 // TODO: selectively PROT_EXEC an image subset containing stubs
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700120 PROT_READ | PROT_WRITE | PROT_EXEC,
121 MAP_PRIVATE | MAP_FIXED,
122 file->Fd(),
123 0));
Elliott Hughes90a33692011-08-30 13:27:07 -0700124 if (map.get() == NULL) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700125 LOG(WARNING) << "Failed to map " << image_file_name;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700126 return false;
127 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700128 CHECK_EQ(image_header.GetImageBaseAddr(), map->GetAddress());
Brian Carlstroma663ea52011-08-19 23:33:41 -0700129 image_header_ = reinterpret_cast<ImageHeader*>(map->GetAddress());
130 DCHECK_EQ(0, memcmp(&image_header, image_header_, sizeof(ImageHeader)));
131
Brian Carlstrom16192862011-09-12 17:50:06 -0700132 Object* jni_stub_array = image_header.GetImageRoot(ImageHeader::kJniStubArray);
Ian Rogers169c9a72011-11-13 20:13:17 -0800133 runtime->SetJniDlsymLookupStub(down_cast<ByteArray*>(jni_stub_array));
Brian Carlstrom16192862011-09-12 17:50:06 -0700134
Brian Carlstrome24fa612011-09-29 00:53:55 -0700135 Object* ame_stub_array = image_header.GetImageRoot(ImageHeader::kAbstractMethodErrorStubArray);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700136 runtime->SetAbstractMethodErrorStubArray(down_cast<ByteArray*>(ame_stub_array));
Brian Carlstrome24fa612011-09-29 00:53:55 -0700137
Ian Rogersad25ac52011-10-04 19:13:33 -0700138 Object* resolution_stub_array = image_header.GetImageRoot(ImageHeader::kInstanceResolutionStubArray);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700139 runtime->SetResolutionStubArray(
Ian Rogers1cb0a1d2011-10-06 15:24:35 -0700140 down_cast<ByteArray*>(resolution_stub_array), Runtime::kInstanceMethod);
Ian Rogersad25ac52011-10-04 19:13:33 -0700141 resolution_stub_array = image_header.GetImageRoot(ImageHeader::kStaticResolutionStubArray);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700142 runtime->SetResolutionStubArray(
Ian Rogers1cb0a1d2011-10-06 15:24:35 -0700143 down_cast<ByteArray*>(resolution_stub_array), Runtime::kStaticMethod);
144 resolution_stub_array = image_header.GetImageRoot(ImageHeader::kUnknownMethodResolutionStubArray);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700145 runtime->SetResolutionStubArray(
Ian Rogers1cb0a1d2011-10-06 15:24:35 -0700146 down_cast<ByteArray*>(resolution_stub_array), Runtime::kUnknownMethod);
Ian Rogersad25ac52011-10-04 19:13:33 -0700147
Ian Rogersff1ed472011-09-20 13:46:24 -0700148 Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700149 runtime->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method), Runtime::kSaveAll);
150 callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
151 runtime->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method), Runtime::kRefsOnly);
152 callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
153 runtime->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method), Runtime::kRefsAndArgs);
Ian Rogersff1ed472011-09-20 13:46:24 -0700154
Elliott Hughes6c9c06d2011-11-07 16:43:47 -0800155 InitFromMemMap(map.release());
jeffhaoc1160702011-10-27 15:48:45 -0700156 growth_limit_ = limit_;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800157 VLOG(startup) << "Space::InitFromImage exiting";
Carl Shapiro69759ea2011-07-21 18:13:35 -0700158 return true;
159}
160
Carl Shapiro69759ea2011-07-21 18:13:35 -0700161Object* Space::AllocWithoutGrowth(size_t num_bytes) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700162 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700163 return reinterpret_cast<Object*>(mspace_calloc(mspace_, 1, num_bytes));
164}
165
166Object* Space::AllocWithGrowth(size_t num_bytes) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700167 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700168 // Grow as much as possible within the mspace.
jeffhaoc1160702011-10-27 15:48:45 -0700169 size_t max_allowed = growth_size_;
Carl Shapiro69759ea2011-07-21 18:13:35 -0700170 mspace_set_max_allowed_footprint(mspace_, max_allowed);
171 // Try the allocation.
172 void* ptr = AllocWithoutGrowth(num_bytes);
173 // Shrink back down as small as possible.
174 size_t footprint = mspace_footprint(mspace_);
175 mspace_set_max_allowed_footprint(mspace_, footprint);
176 // Return the new allocation or NULL.
177 return reinterpret_cast<Object*>(ptr);
178}
179
180size_t Space::Free(void* ptr) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700181 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700182 DCHECK(ptr != NULL);
183 size_t num_bytes = mspace_usable_size(mspace_, ptr);
184 mspace_free(mspace_, ptr);
185 return num_bytes;
186}
187
Ian Rogers5d76c432011-10-31 21:42:49 -0700188size_t Space::FreeList(size_t num_ptrs, void** ptrs) {
189 DCHECK(mspace_ != NULL);
190 DCHECK(ptrs != NULL);
191 void* merged = ptrs[0];
192 size_t num_bytes = 0;
193 for (size_t i = 1; i < num_ptrs; i++) {
194 num_bytes += mspace_usable_size(mspace_, ptrs[i]);
195 if (mspace_merge_objects(mspace_, merged, ptrs[i]) == NULL) {
196 mspace_free(mspace_, merged);
197 merged = ptrs[i];
198 }
199 }
200 CHECK(merged != NULL);
201 mspace_free(mspace_, merged);
202 return num_bytes;
203}
204
Carl Shapiro58551df2011-07-24 03:09:51 -0700205size_t Space::AllocationSize(const Object* obj) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700206 DCHECK(mspace_ != NULL);
Carl Shapiro58551df2011-07-24 03:09:51 -0700207 return mspace_usable_size(mspace_, obj) + kChunkOverhead;
208}
209
Carl Shapiro69759ea2011-07-21 18:13:35 -0700210void Space::DontNeed(void* start, void* end, void* num_bytes) {
Brian Carlstromb0460ea2011-07-29 10:08:05 -0700211 start = (void*)RoundUp((uintptr_t)start, kPageSize);
212 end = (void*)RoundDown((uintptr_t)end, kPageSize);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700213 if (start >= end) {
214 return;
215 }
216 size_t length = reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start);
217 int result = madvise(start, length, MADV_DONTNEED);
218 if (result == -1) {
219 PLOG(WARNING) << "madvise failed";
220 } else {
221 *reinterpret_cast<size_t*>(num_bytes) += length;
222 }
223}
224
225void Space::Trim() {
226 CHECK(mspace_ != NULL);
227 mspace_trim(mspace_, 0);
228 size_t num_bytes_released = 0;
229 mspace_walk_free_pages(mspace_, DontNeed, &num_bytes_released);
230}
231
Elliott Hughes6a5bd492011-10-28 14:33:57 -0700232void Space::Walk(void(*callback)(const void*, size_t, const void*, size_t, void*), void* arg) {
233 if (mspace_ != NULL) {
234 mspace_walk_heap(mspace_, callback, arg);
235 }
236}
237
Shih-wei Liao7f1caab2011-10-06 12:11:04 -0700238size_t Space::GetMaxAllowedFootprint() {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700239 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700240 return mspace_max_allowed_footprint(mspace_);
241}
242
Elliott Hughes6a5bd492011-10-28 14:33:57 -0700243void Space::SetMaxAllowedFootprint(size_t limit) {
Shih-wei Liao7f1caab2011-10-06 12:11:04 -0700244 DCHECK(mspace_ != NULL);
245
246 // Compare against the actual footprint, rather than the
247 // max_allowed, because the heap may not have grown all the
248 // way to the allowed size yet.
249 //
250 size_t current_space_size = mspace_footprint(mspace_);
251 if (limit < current_space_size) {
252 // Don't let the space grow any more.
253 mspace_set_max_allowed_footprint(mspace_, current_space_size);
254 } else {
255 // Let the heap grow to the requested limit.
256 mspace_set_max_allowed_footprint(mspace_, limit);
257 }
258}
259
Carl Shapiro69759ea2011-07-21 18:13:35 -0700260void Space::Grow(size_t new_size) {
Elliott Hughes53b61312011-08-12 18:28:20 -0700261 UNIMPLEMENTED(FATAL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700262}
263
264} // namespace art