blob: 1852b0d545cfd02f61e4dc694fba587b01927bc7 [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
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070016Space* Space::Create(size_t initial_size, size_t maximum_size, byte* requested_base) {
Elliott Hughes90a33692011-08-30 13:27:07 -070017 UniquePtr<Space> space(new Space());
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070018 bool success = space->Init(initial_size, maximum_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 Hughes90a33692011-08-30 13:27:07 -070028 UniquePtr<Space> space(new Space());
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
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070059bool Space::Init(size_t initial_size, size_t maximum_size, byte* requested_base) {
Brian Carlstrom0a5b14d2011-09-27 13:29:15 -070060 const Runtime* runtime = Runtime::Current();
61 if (runtime->IsVerboseStartup()) {
62 LOG(INFO) << "Space::Init entering"
63 << " initial_size=" << initial_size
64 << " maximum_size=" << maximum_size
65 << " requested_base=" << reinterpret_cast<void*>(requested_base);
66 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070067 if (!(initial_size <= maximum_size)) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070068 LOG(WARNING) << "Failed to create space with initial size > maximum size ("
69 << initial_size << ">" << maximum_size << ")";
Carl Shapiro69759ea2011-07-21 18:13:35 -070070 return false;
71 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070072 size_t length = RoundUp(maximum_size, kPageSize);
Carl Shapiro69759ea2011-07-21 18:13:35 -070073 int prot = PROT_READ | PROT_WRITE;
Elliott Hughes90a33692011-08-30 13:27:07 -070074 UniquePtr<MemMap> mem_map(MemMap::Map(requested_base, length, prot));
75 if (mem_map.get() == NULL) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070076 LOG(WARNING) << "Failed to allocate " << length << " bytes for space";
Carl Shapiro69759ea2011-07-21 18:13:35 -070077 return false;
78 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070079 Init(mem_map.release());
80 maximum_size_ = maximum_size;
81 mspace_ = CreateMallocSpace(base_, initial_size, maximum_size);
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070082 if (mspace_ == NULL) {
83 LOG(WARNING) << "Failed to create mspace for space";
84 return false;
85 }
Brian Carlstrom0a5b14d2011-09-27 13:29:15 -070086 if (runtime->IsVerboseStartup()) {
87 LOG(INFO) << "Space::Init exiting";
88 }
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070089 return true;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070090}
91
92void Space::Init(MemMap* mem_map) {
93 mem_map_.reset(mem_map);
Brian Carlstromdb4d5402011-08-09 12:18:28 -070094 base_ = mem_map_->GetAddress();
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070095 limit_ = base_ + mem_map->GetLength();
96}
97
98
Brian Carlstrom58ae9412011-10-04 00:56:06 -070099bool Space::InitFromImage(const std::string& image_file_name) {
Brian Carlstrom0a5b14d2011-09-27 13:29:15 -0700100 const Runtime* runtime = Runtime::Current();
101 if (runtime->IsVerboseStartup()) {
102 LOG(INFO) << "Space::InitFromImage entering"
103 << " image_file_name=" << image_file_name;
104 }
Brian Carlstrom58ae9412011-10-04 00:56:06 -0700105 UniquePtr<File> file(OS::OpenFile(image_file_name.c_str(), false));
Elliott Hughes90a33692011-08-30 13:27:07 -0700106 if (file.get() == NULL) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700107 LOG(WARNING) << "Failed to open " << image_file_name;
Carl Shapiro69759ea2011-07-21 18:13:35 -0700108 return false;
109 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700110 ImageHeader image_header;
111 bool success = file->ReadFully(&image_header, sizeof(image_header));
112 if (!success || !image_header.IsValid()) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700113 LOG(WARNING) << "Invalid image header " << image_file_name;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700114 return false;
115 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700116 UniquePtr<MemMap> map(MemMap::Map(image_header.GetImageBaseAddr(),
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700117 file->Length(),
118 // TODO: selectively PROT_EXEC when image contains a code space
119 PROT_READ | PROT_WRITE | PROT_EXEC,
120 MAP_PRIVATE | MAP_FIXED,
121 file->Fd(),
122 0));
Elliott Hughes90a33692011-08-30 13:27:07 -0700123 if (map.get() == NULL) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700124 LOG(WARNING) << "Failed to map " << image_file_name;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700125 return false;
126 }
Brian Carlstrome24fa612011-09-29 00:53:55 -0700127 CHECK_EQ(image_header.GetImageBaseAddr(), map->GetAddress());
Brian Carlstroma663ea52011-08-19 23:33:41 -0700128 image_header_ = reinterpret_cast<ImageHeader*>(map->GetAddress());
129 DCHECK_EQ(0, memcmp(&image_header, image_header_, sizeof(ImageHeader)));
130
Brian Carlstrom16192862011-09-12 17:50:06 -0700131 Object* jni_stub_array = image_header.GetImageRoot(ImageHeader::kJniStubArray);
132 Runtime::Current()->SetJniStubArray(down_cast<ByteArray*>(jni_stub_array));
133
Brian Carlstrome24fa612011-09-29 00:53:55 -0700134 Object* ame_stub_array = image_header.GetImageRoot(ImageHeader::kAbstractMethodErrorStubArray);
135 Runtime::Current()->SetAbstractMethodErrorStubArray(down_cast<ByteArray*>(ame_stub_array));
136
Ian Rogersad25ac52011-10-04 19:13:33 -0700137 Object* resolution_stub_array = image_header.GetImageRoot(ImageHeader::kInstanceResolutionStubArray);
138 Runtime::Current()->SetResolutionStubArray(down_cast<ByteArray*>(resolution_stub_array), false);
139 resolution_stub_array = image_header.GetImageRoot(ImageHeader::kStaticResolutionStubArray);
140 Runtime::Current()->SetResolutionStubArray(down_cast<ByteArray*>(resolution_stub_array), true);
141
Ian Rogersff1ed472011-09-20 13:46:24 -0700142 Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
143 Runtime::Current()->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method));
144
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700145 Init(map.release());
Brian Carlstrom0a5b14d2011-09-27 13:29:15 -0700146 if (runtime->IsVerboseStartup()) {
147 LOG(INFO) << "Space::InitFromImage exiting";
148 }
Carl Shapiro69759ea2011-07-21 18:13:35 -0700149 return true;
150}
151
Carl Shapiro69759ea2011-07-21 18:13:35 -0700152Object* Space::AllocWithoutGrowth(size_t num_bytes) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700153 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700154 return reinterpret_cast<Object*>(mspace_calloc(mspace_, 1, num_bytes));
155}
156
157Object* Space::AllocWithGrowth(size_t num_bytes) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700158 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700159 // Grow as much as possible within the mspace.
160 size_t max_allowed = maximum_size_;
161 mspace_set_max_allowed_footprint(mspace_, max_allowed);
162 // Try the allocation.
163 void* ptr = AllocWithoutGrowth(num_bytes);
164 // Shrink back down as small as possible.
165 size_t footprint = mspace_footprint(mspace_);
166 mspace_set_max_allowed_footprint(mspace_, footprint);
167 // Return the new allocation or NULL.
168 return reinterpret_cast<Object*>(ptr);
169}
170
171size_t Space::Free(void* ptr) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700172 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700173 DCHECK(ptr != NULL);
174 size_t num_bytes = mspace_usable_size(mspace_, ptr);
175 mspace_free(mspace_, ptr);
176 return num_bytes;
177}
178
Carl Shapiro58551df2011-07-24 03:09:51 -0700179size_t Space::AllocationSize(const Object* obj) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700180 DCHECK(mspace_ != NULL);
Carl Shapiro58551df2011-07-24 03:09:51 -0700181 return mspace_usable_size(mspace_, obj) + kChunkOverhead;
182}
183
Carl Shapiro69759ea2011-07-21 18:13:35 -0700184void Space::DontNeed(void* start, void* end, void* num_bytes) {
Brian Carlstromb0460ea2011-07-29 10:08:05 -0700185 start = (void*)RoundUp((uintptr_t)start, kPageSize);
186 end = (void*)RoundDown((uintptr_t)end, kPageSize);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700187 if (start >= end) {
188 return;
189 }
190 size_t length = reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start);
191 int result = madvise(start, length, MADV_DONTNEED);
192 if (result == -1) {
193 PLOG(WARNING) << "madvise failed";
194 } else {
195 *reinterpret_cast<size_t*>(num_bytes) += length;
196 }
197}
198
199void Space::Trim() {
200 CHECK(mspace_ != NULL);
201 mspace_trim(mspace_, 0);
202 size_t num_bytes_released = 0;
203 mspace_walk_free_pages(mspace_, DontNeed, &num_bytes_released);
204}
205
206size_t Space::MaxAllowedFootprint() {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700207 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700208 return mspace_max_allowed_footprint(mspace_);
209}
210
211void Space::Grow(size_t new_size) {
Elliott Hughes53b61312011-08-12 18:28:20 -0700212 UNIMPLEMENTED(FATAL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700213}
214
215} // namespace art