blob: 38c5720b17af7af977d464ea982f5b09a1676dc1 [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 Carlstrom4a289ed2011-08-16 17:17:49 -070027Space* Space::Create(const char* image_file_name) {
28 CHECK(image_file_name != NULL);
Elliott Hughes90a33692011-08-30 13:27:07 -070029 UniquePtr<Space> space(new Space());
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070030 bool success = space->Init(image_file_name);
31 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) {
61 if (!(initial_size <= maximum_size)) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070062 LOG(WARNING) << "Failed to create space with initial size > maximum size ("
63 << initial_size << ">" << maximum_size << ")";
Carl Shapiro69759ea2011-07-21 18:13:35 -070064 return false;
65 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070066 size_t length = RoundUp(maximum_size, kPageSize);
Carl Shapiro69759ea2011-07-21 18:13:35 -070067 int prot = PROT_READ | PROT_WRITE;
Elliott Hughes90a33692011-08-30 13:27:07 -070068 UniquePtr<MemMap> mem_map(MemMap::Map(requested_base, length, prot));
69 if (mem_map.get() == NULL) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070070 LOG(WARNING) << "Failed to allocate " << length << " bytes for space";
Carl Shapiro69759ea2011-07-21 18:13:35 -070071 return false;
72 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070073 Init(mem_map.release());
74 maximum_size_ = maximum_size;
75 mspace_ = CreateMallocSpace(base_, initial_size, maximum_size);
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070076 if (mspace_ == NULL) {
77 LOG(WARNING) << "Failed to create mspace for space";
78 return false;
79 }
80 return true;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070081}
82
83void Space::Init(MemMap* mem_map) {
84 mem_map_.reset(mem_map);
Brian Carlstromdb4d5402011-08-09 12:18:28 -070085 base_ = mem_map_->GetAddress();
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070086 limit_ = base_ + mem_map->GetLength();
87}
88
89
90bool Space::Init(const char* image_file_name) {
Elliott Hughes90a33692011-08-30 13:27:07 -070091 UniquePtr<File> file(OS::OpenFile(image_file_name, false));
92 if (file.get() == NULL) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070093 LOG(WARNING) << "Failed to open " << image_file_name;
Carl Shapiro69759ea2011-07-21 18:13:35 -070094 return false;
95 }
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070096 ImageHeader image_header;
97 bool success = file->ReadFully(&image_header, sizeof(image_header));
98 if (!success || !image_header.IsValid()) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -070099 LOG(WARNING) << "Invalid image header " << image_file_name;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700100 return false;
101 }
Elliott Hughes90a33692011-08-30 13:27:07 -0700102 UniquePtr<MemMap> map(MemMap::Map(image_header.GetBaseAddr(),
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700103 file->Length(),
104 // TODO: selectively PROT_EXEC when image contains a code space
105 PROT_READ | PROT_WRITE | PROT_EXEC,
106 MAP_PRIVATE | MAP_FIXED,
107 file->Fd(),
108 0));
Elliott Hughes90a33692011-08-30 13:27:07 -0700109 if (map.get() == NULL) {
Brian Carlstrom69b15fb2011-09-03 12:25:21 -0700110 LOG(WARNING) << "Failed to map " << image_file_name;
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700111 return false;
112 }
113 CHECK_EQ(image_header.GetBaseAddr(), map->GetAddress());
Brian Carlstroma663ea52011-08-19 23:33:41 -0700114 image_header_ = reinterpret_cast<ImageHeader*>(map->GetAddress());
115 DCHECK_EQ(0, memcmp(&image_header, image_header_, sizeof(ImageHeader)));
116
Brian Carlstrom16192862011-09-12 17:50:06 -0700117 Object* jni_stub_array = image_header.GetImageRoot(ImageHeader::kJniStubArray);
118 Runtime::Current()->SetJniStubArray(down_cast<ByteArray*>(jni_stub_array));
119
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700120 Init(map.release());
Carl Shapiro69759ea2011-07-21 18:13:35 -0700121 return true;
122}
123
Carl Shapiro69759ea2011-07-21 18:13:35 -0700124Object* Space::AllocWithoutGrowth(size_t num_bytes) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700125 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700126 return reinterpret_cast<Object*>(mspace_calloc(mspace_, 1, num_bytes));
127}
128
129Object* Space::AllocWithGrowth(size_t num_bytes) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700130 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700131 // Grow as much as possible within the mspace.
132 size_t max_allowed = maximum_size_;
133 mspace_set_max_allowed_footprint(mspace_, max_allowed);
134 // Try the allocation.
135 void* ptr = AllocWithoutGrowth(num_bytes);
136 // Shrink back down as small as possible.
137 size_t footprint = mspace_footprint(mspace_);
138 mspace_set_max_allowed_footprint(mspace_, footprint);
139 // Return the new allocation or NULL.
140 return reinterpret_cast<Object*>(ptr);
141}
142
143size_t Space::Free(void* ptr) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700144 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700145 DCHECK(ptr != NULL);
146 size_t num_bytes = mspace_usable_size(mspace_, ptr);
147 mspace_free(mspace_, ptr);
148 return num_bytes;
149}
150
Carl Shapiro58551df2011-07-24 03:09:51 -0700151size_t Space::AllocationSize(const Object* obj) {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700152 DCHECK(mspace_ != NULL);
Carl Shapiro58551df2011-07-24 03:09:51 -0700153 return mspace_usable_size(mspace_, obj) + kChunkOverhead;
154}
155
Carl Shapiro69759ea2011-07-21 18:13:35 -0700156void Space::DontNeed(void* start, void* end, void* num_bytes) {
Brian Carlstromb0460ea2011-07-29 10:08:05 -0700157 start = (void*)RoundUp((uintptr_t)start, kPageSize);
158 end = (void*)RoundDown((uintptr_t)end, kPageSize);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700159 if (start >= end) {
160 return;
161 }
162 size_t length = reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start);
163 int result = madvise(start, length, MADV_DONTNEED);
164 if (result == -1) {
165 PLOG(WARNING) << "madvise failed";
166 } else {
167 *reinterpret_cast<size_t*>(num_bytes) += length;
168 }
169}
170
171void Space::Trim() {
172 CHECK(mspace_ != NULL);
173 mspace_trim(mspace_, 0);
174 size_t num_bytes_released = 0;
175 mspace_walk_free_pages(mspace_, DontNeed, &num_bytes_released);
176}
177
178size_t Space::MaxAllowedFootprint() {
Brian Carlstrom4a289ed2011-08-16 17:17:49 -0700179 DCHECK(mspace_ != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700180 return mspace_max_allowed_footprint(mspace_);
181}
182
183void Space::Grow(size_t new_size) {
Elliott Hughes53b61312011-08-12 18:28:20 -0700184 UNIMPLEMENTED(FATAL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700185}
186
187} // namespace art