blob: 08d758a1080e28588a6eb511e08ec74422b011c0 [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"
11#include "mspace.h"
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070012#include "os.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070013#include "utils.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -070014
15namespace art {
16
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070017Space* Space::Create(size_t initial_size, size_t maximum_size, byte* requested_base) {
Elliott Hughes90a33692011-08-30 13:27:07 -070018 UniquePtr<Space> space(new Space());
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070019 bool success = space->Init(initial_size, maximum_size, requested_base);
Carl Shapiro69759ea2011-07-21 18:13:35 -070020 if (!success) {
21 return NULL;
22 } else {
23 return space.release();
24 }
25}
26
Brian Carlstrom58ae9412011-10-04 00:56:06 -070027Space* Space::CreateFromImage(const std::string& image_file_name) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070028 CHECK(image_file_name != NULL);
Elliott Hughes90a33692011-08-30 13:27:07 -070029 UniquePtr<Space> space(new Space());
Brian Carlstrom0a5b14d2011-09-27 13:29:15 -070030 bool success = space->InitFromImage(image_file_name);
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070031 if (!success) {
32 return NULL;
33 } else {
34 return space.release();
35 }
36}
37
38Space::~Space() {}
39
Carl Shapiro69759ea2011-07-21 18:13:35 -070040void* Space::CreateMallocSpace(void* base,
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070041 size_t initial_size,
Carl Shapiro69759ea2011-07-21 18:13:35 -070042 size_t maximum_size) {
43 errno = 0;
44 bool is_locked = false;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070045 size_t commit_size = initial_size / 2;
Carl Shapiro69759ea2011-07-21 18:13:35 -070046 void* msp = create_contiguous_mspace_with_base(commit_size, maximum_size,
47 is_locked, base);
48 if (msp != NULL) {
49 // Do not permit the heap grow past the starting size without our
50 // intervention.
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070051 mspace_set_max_allowed_footprint(msp, initial_size);
Carl Shapiro69759ea2011-07-21 18:13:35 -070052 } else {
53 // There is no guarantee that errno has meaning when the call
54 // fails, but it often does.
55 PLOG(ERROR) << "create_contiguous_mspace_with_base failed";
56 }
57 return msp;
58}
59
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070060bool Space::Init(size_t initial_size, size_t maximum_size, byte* requested_base) {
Brian Carlstrom0a5b14d2011-09-27 13:29:15 -070061 const Runtime* runtime = Runtime::Current();
62 if (runtime->IsVerboseStartup()) {
63 LOG(INFO) << "Space::Init entering"
64 << " initial_size=" << initial_size
65 << " maximum_size=" << maximum_size
66 << " requested_base=" << reinterpret_cast<void*>(requested_base);
67 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070068 if (!(initial_size <= maximum_size)) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070069 LOG(WARNING) << "Failed to create space with initial size > maximum size ("
70 << initial_size << ">" << maximum_size << ")";
Carl Shapiro69759ea2011-07-21 18:13:35 -070071 return false;
72 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070073 size_t length = RoundUp(maximum_size, kPageSize);
Carl Shapiro69759ea2011-07-21 18:13:35 -070074 int prot = PROT_READ | PROT_WRITE;
Elliott Hughes90a33692011-08-30 13:27:07 -070075 UniquePtr<MemMap> mem_map(MemMap::Map(requested_base, length, prot));
76 if (mem_map.get() == NULL) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070077 LOG(WARNING) << "Failed to allocate " << length << " bytes for space";
Carl Shapiro69759ea2011-07-21 18:13:35 -070078 return false;
79 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070080 Init(mem_map.release());
81 maximum_size_ = maximum_size;
82 mspace_ = CreateMallocSpace(base_, initial_size, maximum_size);
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070083 if (mspace_ == NULL) {
84 LOG(WARNING) << "Failed to create mspace for space";
85 return false;
86 }
Brian Carlstrom0a5b14d2011-09-27 13:29:15 -070087 if (runtime->IsVerboseStartup()) {
88 LOG(INFO) << "Space::Init exiting";
89 }
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070090 return true;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070091}
92
93void Space::Init(MemMap* mem_map) {
94 mem_map_.reset(mem_map);
Brian Carlstromdb4d5402011-08-09 12:18:28 -070095 base_ = mem_map_->GetAddress();
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070096 limit_ = base_ + mem_map->GetLength();
97}
98
99
Brian Carlstrom58ae9412011-10-04 00:56:06 -0700100bool Space::InitFromImage(const std::string& image_file_name) {
Brian Carlstrom0a5b14d2011-09-27 13:29:15 -0700101 const Runtime* runtime = Runtime::Current();
102 if (runtime->IsVerboseStartup()) {
103 LOG(INFO) << "Space::InitFromImage entering"
104 << " image_file_name=" << image_file_name;
105 }
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(),
119 // TODO: selectively PROT_EXEC when image contains a code space
120 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);
133 Runtime::Current()->SetJniStubArray(down_cast<ByteArray*>(jni_stub_array));
134
Brian Carlstrome24fa612011-09-29 00:53:55 -0700135 Object* ame_stub_array = image_header.GetImageRoot(ImageHeader::kAbstractMethodErrorStubArray);
136 Runtime::Current()->SetAbstractMethodErrorStubArray(down_cast<ByteArray*>(ame_stub_array));
137
Ian Rogersff1ed472011-09-20 13:46:24 -0700138 Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
139 Runtime::Current()->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method));
140
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700141 Init(map.release());
Brian Carlstrom0a5b14d2011-09-27 13:29:15 -0700142 if (runtime->IsVerboseStartup()) {
143 LOG(INFO) << "Space::InitFromImage exiting";
144 }
Carl Shapiro69759ea2011-07-21 18:13:35 -0700145 return true;
146}
147
Carl Shapiro69759ea2011-07-21 18:13:35 -0700148Object* Space::AllocWithoutGrowth(size_t num_bytes) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700149 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700150 return reinterpret_cast<Object*>(mspace_calloc(mspace_, 1, num_bytes));
151}
152
153Object* Space::AllocWithGrowth(size_t num_bytes) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700154 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700155 // Grow as much as possible within the mspace.
156 size_t max_allowed = maximum_size_;
157 mspace_set_max_allowed_footprint(mspace_, max_allowed);
158 // Try the allocation.
159 void* ptr = AllocWithoutGrowth(num_bytes);
160 // Shrink back down as small as possible.
161 size_t footprint = mspace_footprint(mspace_);
162 mspace_set_max_allowed_footprint(mspace_, footprint);
163 // Return the new allocation or NULL.
164 return reinterpret_cast<Object*>(ptr);
165}
166
167size_t Space::Free(void* ptr) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700168 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700169 DCHECK(ptr != NULL);
170 size_t num_bytes = mspace_usable_size(mspace_, ptr);
171 mspace_free(mspace_, ptr);
172 return num_bytes;
173}
174
Carl Shapiro58551df2011-07-24 03:09:51 -0700175size_t Space::AllocationSize(const Object* obj) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700176 DCHECK(mspace_ != NULL);
Carl Shapiro58551df2011-07-24 03:09:51 -0700177 return mspace_usable_size(mspace_, obj) + kChunkOverhead;
178}
179
Carl Shapiro69759ea2011-07-21 18:13:35 -0700180void Space::DontNeed(void* start, void* end, void* num_bytes) {
Brian Carlstromb0460ea2011-07-29 10:08:05 -0700181 start = (void*)RoundUp((uintptr_t)start, kPageSize);
182 end = (void*)RoundDown((uintptr_t)end, kPageSize);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700183 if (start >= end) {
184 return;
185 }
186 size_t length = reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start);
187 int result = madvise(start, length, MADV_DONTNEED);
188 if (result == -1) {
189 PLOG(WARNING) << "madvise failed";
190 } else {
191 *reinterpret_cast<size_t*>(num_bytes) += length;
192 }
193}
194
195void Space::Trim() {
196 CHECK(mspace_ != NULL);
197 mspace_trim(mspace_, 0);
198 size_t num_bytes_released = 0;
199 mspace_walk_free_pages(mspace_, DontNeed, &num_bytes_released);
200}
201
202size_t Space::MaxAllowedFootprint() {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700203 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700204 return mspace_max_allowed_footprint(mspace_);
205}
206
207void Space::Grow(size_t new_size) {
Elliott Hughes53b61312011-08-12 18:28:20 -0700208 UNIMPLEMENTED(FATAL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700209}
210
211} // namespace art