Work on heap and space initialization to support image loading
Change-Id: Icab25efa4dee17e4b6c6e97e38f63f5ab8a8a005
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 6fa0293..0f1196a 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -47,6 +47,7 @@
src/file.cc \
src/file_linux.cc \
src/heap.cc \
+ src/image.cc \
src/image_writer.cc \
src/indirect_reference_table.cc \
src/intern_table.cc \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 3437a5a..a7d10f4 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -257,7 +257,7 @@
return down_cast<Method*>(GetClassRoot(kJavaLangReflectMethod)->NewInstance());
}
-// TODO remove once we can use java.lang.Class.getSystemClassLoader
+// TODO: remove once we can use java.lang.Class.getSystemClassLoader
PathClassLoader* ClassLinker::AllocPathClassLoader(std::vector<const DexFile*> dex_files) {
PathClassLoader* cl = down_cast<PathClassLoader*>(GetClassRoot(kDalvikSystemPathClassLoader)->NewInstance());
cl->SetClassPath(dex_files);
@@ -266,7 +266,7 @@
Class* ClassLinker::FindClass(const StringPiece& descriptor,
ClassLoader* class_loader) {
- // TODO remove this contrived parent class loader check when we have a real ClassLoader.
+ // TODO: remove this contrived parent class loader check when we have a real ClassLoader.
if (class_loader != NULL) {
Class* klass = FindClass(descriptor, NULL);
if (klass != NULL) {
@@ -323,7 +323,7 @@
ObjectLock lock(klass);
klass->clinit_thread_id_ = self->GetId();
// Add the newly loaded class to the loaded classes table.
- bool success = InsertClass(klass); // TODO just return collision
+ bool success = InsertClass(klass); // TODO: just return collision
if (!success) {
// We may fail to insert if we raced with another thread.
klass->clinit_thread_id_ = 0;
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 7e93e0d..21c576e 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -394,59 +394,59 @@
scoped_ptr<DexFile> dex(OpenDexFileBase64(kStatics));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Class* statics = class_linker_->FindClass("LStatics;", class_loader);
- // class_linker_->InitializeClass(statics); // TODO uncomment this
+ // class_linker_->InitializeClass(statics); // TODO: uncomment this
EXPECT_EQ(10U, statics->NumStaticFields());
Field* s0 = statics->GetStaticField(0);
EXPECT_EQ("Ljava/lang/reflect/Field;", s0->GetClass()->descriptor_);
EXPECT_EQ('Z', s0->GetType());
-// EXPECT_EQ(true, s0->GetBoolean()); // TODO uncomment this
+// EXPECT_EQ(true, s0->GetBoolean()); // TODO: uncomment this
s0->SetBoolean(false);
Field* s1 = statics->GetStaticField(1);
EXPECT_EQ('B', s1->GetType());
-// EXPECT_EQ(5, s1->GetByte()); // TODO uncomment this
+// EXPECT_EQ(5, s1->GetByte()); // TODO: uncomment this
s1->SetByte(6);
Field* s2 = statics->GetStaticField(2);
EXPECT_EQ('C', s2->GetType());
-// EXPECT_EQ('a', s2->GetChar()); // TODO uncomment this
+// EXPECT_EQ('a', s2->GetChar()); // TODO: uncomment this
s2->SetChar('b');
Field* s3 = statics->GetStaticField(3);
EXPECT_EQ('S', s3->GetType());
-// EXPECT_EQ(65000, s3->GetShort()); // TODO uncomment this
+// EXPECT_EQ(65000, s3->GetShort()); // TODO: uncomment this
s3->SetShort(65001);
Field* s4 = statics->GetStaticField(4);
EXPECT_EQ('I', s4->GetType());
-// EXPECT_EQ(2000000000, s4->GetInt()); // TODO uncomment this
+// EXPECT_EQ(2000000000, s4->GetInt()); // TODO: uncomment this
s4->SetInt(2000000001);
Field* s5 = statics->GetStaticField(5);
EXPECT_EQ('J', s5->GetType());
-// EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong()); // TODO uncomment this
+// EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong()); // TODO: uncomment this
s5->SetLong(0x34567890abcdef12LL);
Field* s6 = statics->GetStaticField(6);
EXPECT_EQ('F', s6->GetType());
-// EXPECT_EQ(0.5, s6->GetFloat()); // TODO uncomment this
+// EXPECT_EQ(0.5, s6->GetFloat()); // TODO: uncomment this
s6->SetFloat(0.75);
Field* s7 = statics->GetStaticField(7);
EXPECT_EQ('D', s7->GetType());
-// EXPECT_EQ(16777217, s7->GetDouble()); // TODO uncomment this
+// EXPECT_EQ(16777217, s7->GetDouble()); // TODO: uncomment this
s7->SetDouble(16777219);
Field* s8 = statics->GetStaticField(8);
EXPECT_EQ('L', s8->GetType());
-// EXPECT_TRUE(down_cast<String*>(s8->GetObject())->Equals("android")); // TODO uncomment this
+// EXPECT_TRUE(down_cast<String*>(s8->GetObject())->Equals("android")); // TODO: uncomment this
s8->SetObject(String::AllocFromAscii("robot"));
Field* s9 = statics->GetStaticField(9);
EXPECT_EQ('[', s9->GetType());
-// EXPECT_EQ(NULL, s9->GetObject()); // TODO uncomment this
+// EXPECT_EQ(NULL, s9->GetObject()); // TODO: uncomment this
s9->SetObject(NULL);
EXPECT_EQ(false, s0->GetBoolean());
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 22e4430..b9ae7e3 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -35,7 +35,7 @@
return ClassPathEntry(dex_file, dex_class_def);
}
}
- // TODO remove reinterpret_cast when issue with -std=gnu++0x host issue resolved
+ // TODO: remove reinterpret_cast when issue with -std=gnu++0x host issue resolved
return ClassPathEntry(reinterpret_cast<const DexFile*>(NULL),
reinterpret_cast<const DexFile::ClassDef*>(NULL));
}
@@ -257,7 +257,7 @@
return NULL;
}
- // TODO restat and check length against zip_entry->GetUncompressedLength()?
+ // TODO: restat and check length against zip_entry->GetUncompressedLength()?
// Compute checksum and compare to zip. If things look okay, rename from tmp.
off_t lseek_result = lseek(fd->GetFd(), 0, SEEK_SET);
diff --git a/src/file.h b/src/file.h
index 680872e..3353602 100644
--- a/src/file.h
+++ b/src/file.h
@@ -33,6 +33,8 @@
// Returns a negative value if position cannot be determined.
virtual off_t Position() = 0;
+ virtual int Fd() = 0;
+
const char* name() const { return name_; }
protected:
diff --git a/src/file_linux.h b/src/file_linux.h
index 7e36ada..3d381d5 100644
--- a/src/file_linux.h
+++ b/src/file_linux.h
@@ -22,6 +22,10 @@
virtual off_t Length();
virtual off_t Position();
+ virtual int Fd() {
+ return fd_;
+ }
+
private:
static const int kClosedFd = -1;
diff --git a/src/file_test.cc b/src/file_test.cc
index a836d83..385b3dd 100644
--- a/src/file_test.cc
+++ b/src/file_test.cc
@@ -44,4 +44,13 @@
EXPECT_EQ(4, file->Position());
}
+
+TEST_F(FileTest, FileFd) {
+ std::string filename = GetLibCoreDexFileName();
+ scoped_ptr<File> file(OS::OpenFile(filename.c_str(), false));
+ ASSERT_TRUE(file != NULL);
+ EXPECT_NE(-1, file->Fd());
+}
+
+
} // namespace art
diff --git a/src/heap.cc b/src/heap.cc
index b9998da..de801ce 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -14,7 +14,7 @@
std::vector<Space*> Heap::spaces_;
-size_t Heap::startup_size_ = 0;
+Space* Heap::alloc_space_ = NULL;
size_t Heap::maximum_size_ = 0;
@@ -28,14 +28,33 @@
HeapBitmap* Heap::live_bitmap_ = NULL;
-bool Heap::Init(size_t startup_size, size_t maximum_size) {
- Space* space = Space::Create(startup_size, maximum_size);
+bool Heap::Init(size_t initial_size, size_t maximum_size, const char* boot_image_file_name) {
+ Space* boot_space;
+ byte* requested_base;
+ if (boot_image_file_name == NULL) {
+ boot_space = NULL;
+ requested_base = NULL;
+ } else {
+ boot_space = Space::Create(boot_image_file_name);
+ if (boot_space == NULL) {
+ return false;
+ }
+ spaces_.push_back(boot_space);
+ requested_base = boot_space->GetBase() + RoundUp(boot_space->Size(), kPageSize);
+ }
+
+ Space* space = Space::Create(initial_size, maximum_size, requested_base);
if (space == NULL) {
return false;
}
- byte* base = space->GetBase();
- size_t num_bytes = space->Size();
+ if (boot_space == NULL) {
+ boot_space = space;
+ }
+ byte* base = std::min(boot_space->GetBase(), space->GetBase());
+ byte* limit = std::max(boot_space->GetLimit(), space->GetLimit());
+ DCHECK_LT(base, limit);
+ size_t num_bytes = limit - base;
// Allocate the initial live bitmap.
scoped_ptr<HeapBitmap> live_bitmap(HeapBitmap::Create(base, num_bytes));
@@ -49,8 +68,8 @@
return false;
}
+ alloc_space_ = space;
spaces_.push_back(space);
- startup_size_ = startup_size;
maximum_size_ = maximum_size;
live_bitmap_ = live_bitmap.release();
mark_bitmap_ = mark_bitmap.release();
@@ -62,8 +81,14 @@
void Heap::Destroy() {
STLDeleteElements(&spaces_);
- delete mark_bitmap_;
- delete live_bitmap_;
+ if (mark_bitmap_ != NULL) {
+ delete mark_bitmap_;
+ mark_bitmap_ = NULL;
+ }
+ if (live_bitmap_ != NULL) {
+ delete live_bitmap_;
+ }
+ live_bitmap_ = NULL;
}
Object* Heap::AllocObject(Class* klass, size_t num_bytes) {
@@ -100,8 +125,8 @@
}
Object* Heap::Allocate(size_t size) {
- CHECK_EQ(spaces_.size(), 1u);
- Space* space = spaces_[0];
+ DCHECK(alloc_space_ != NULL);
+ Space* space = alloc_space_;
Object* obj = Allocate(space, size);
if (obj != NULL) {
RecordAllocation(space, obj);
diff --git a/src/heap.h b/src/heap.h
index 247c6ba..99f6554 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -24,7 +24,9 @@
typedef void (RootVistor)(Object* root, void* arg);
- static bool Init(size_t starting_size, size_t maximum_size);
+ // Create a heap with the requested sizes. optional boot image may
+ // be NULL, otherwise it is an image filename created by ImageWriter.
+ static bool Init(size_t starting_size, size_t maximum_size, const char* boot_image_file_name);
static void Destroy();
@@ -53,10 +55,6 @@
return mark_bitmap_;
}
- static size_t GetMaximumSize() {
- return maximum_size_;
- }
-
private:
// Allocates uninitialized storage.
static Object* Allocate(size_t num_bytes);
@@ -73,13 +71,13 @@
static std::vector<Space*> spaces_;
+ // default Space for allocations
+ static Space* alloc_space_;
+
static HeapBitmap* mark_bitmap_;
static HeapBitmap* live_bitmap_;
- // The startup size of the heap in bytes.
- static size_t startup_size_;
-
// The maximum size of the heap in bytes.
static size_t maximum_size_;
diff --git a/src/image.cc b/src/image.cc
new file mode 100644
index 0000000..a41bf5ba
--- /dev/null
+++ b/src/image.cc
@@ -0,0 +1,10 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "image.h"
+
+namespace art {
+
+const byte ImageHeader::kImageMagic[] = { 'i', 'm', 'g', '\n' };
+const byte ImageHeader::kImageVersion[] = { '0', '0', '1', '\0' };
+
+} // namespace art
diff --git a/src/image.h b/src/image.h
new file mode 100644
index 0000000..c4123e8
--- /dev/null
+++ b/src/image.h
@@ -0,0 +1,47 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_IMAGE_H_
+#define ART_SRC_IMAGE_H_
+
+#include <string.h>
+
+#include "globals.h"
+
+namespace art {
+
+// header of image files written by ImageWriter, read and validated by Space.
+class ImageHeader {
+ public:
+ ImageHeader() {}
+
+ ImageHeader(uint32_t base_addr) : base_addr_(base_addr) {
+ memcpy(magic_, kImageMagic, sizeof(kImageMagic));
+ memcpy(version_, kImageVersion, sizeof(kImageVersion));
+ }
+
+ bool IsValid() {
+ if (memcmp(magic_, kImageMagic, sizeof(kImageMagic) != 0)) {
+ return false;
+ }
+ if (memcmp(version_, kImageVersion, sizeof(kImageVersion) != 0)) {
+ return false;
+ }
+ return true;
+ }
+
+ byte* GetBaseAddr() const {
+ return reinterpret_cast<byte*>(base_addr_);
+ }
+
+ private:
+ static const byte kImageMagic[4];
+ static const byte kImageVersion[4];
+
+ byte magic_[4];
+ byte version_[4];
+ uint32_t base_addr_;
+};
+
+} // namespace art
+
+#endif // ART_SRC_IMAGE_H_
diff --git a/src/image_test.cc b/src/image_test.cc
index 55984f6..6cfa62d 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -1,7 +1,11 @@
// Copyright 2011 Google Inc. All Rights Reserved.
#include "common_test.h"
+#include "file.h"
+#include "image.h"
#include "image_writer.h"
+#include "os.h"
+#include "space.h"
#include "gtest/gtest.h"
@@ -13,16 +17,26 @@
scoped_ptr<DexFile> libcore_dex_file(GetLibCoreDex());
EXPECT_TRUE(libcore_dex_file.get() != NULL);
- // TODO garbage collect before writing
+ // TODO: garbage collect before writing
const std::vector<Space*>& spaces = Heap::GetSpaces();
// can't currently deal with writing a space that might have pointers between spaces
- CHECK_EQ(1U, spaces.size());
+ ASSERT_EQ(1U, spaces.size());
+ Space* space = spaces[0];
ImageWriter writer;
ScratchFile tmp;
const int image_base = 0x5000000;
- bool success = writer.Write(spaces[0], tmp.GetFilename(), reinterpret_cast<byte*>(image_base));
- EXPECT_TRUE(success);
+ bool success = writer.Write(space, tmp.GetFilename(), reinterpret_cast<byte*>(image_base));
+ ASSERT_TRUE(success);
+
+ {
+ scoped_ptr<File> file(OS::OpenFile(tmp.GetFilename(), false));
+ ASSERT_TRUE(file != NULL);
+ ImageHeader image_header;
+ file->ReadFully(&image_header, sizeof(image_header));
+ ASSERT_TRUE(image_header.IsValid());
+ ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->Length()));
+ }
// tear down old runtime and make a new one
delete runtime_.release();
diff --git a/src/image_writer.cc b/src/image_writer.cc
index beb7366..b6625d0 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -8,6 +8,7 @@
#include "file.h"
#include "globals.h"
#include "heap.h"
+#include "image.h"
#include "logging.h"
#include "object.h"
#include "space.h"
@@ -33,11 +34,9 @@
bool ImageWriter::Init(Space* space) {
size_t size = space->Size();
int prot = PROT_READ | PROT_WRITE;
- int flags = MAP_PRIVATE | MAP_ANONYMOUS;
size_t length = RoundUp(size, kPageSize);
- image_.reset(MemMap::Map(length, prot, flags));
+ image_.reset(MemMap::Map(length, prot));
if (image_ == NULL) {
- PLOG(ERROR) << "mmap failed";
return false;
}
return true;
@@ -56,8 +55,9 @@
HeapBitmap* heap_bitmap = Heap::GetLiveBits();
DCHECK(heap_bitmap != NULL);
DCHECK_EQ(0U, image_top_);
- // leave a header, ensures objects have non-zero offset for DCHECKs
- image_top_ += 8; // 64-bit-alignment
+ ImageHeader image_header(reinterpret_cast<uint32_t>(image_base_));
+ memcpy(image_->GetAddress(), &image_header, sizeof(image_header));
+ image_top_ += RoundUp(sizeof(image_header), 8); // 64-bit-alignment
heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this);
DCHECK_LT(image_top_, image_->GetLength());
// Note that top_ is left at end of used space
@@ -88,7 +88,7 @@
DCHECK(orig != NULL);
DCHECK(copy != NULL);
copy->klass_ = down_cast<Class*>(GetImageAddress(orig->klass_));
- // TODO specical case init of pointers to malloc data (or removal of these pointers)
+ // TODO: specical case init of pointers to malloc data (or removal of these pointers)
if (orig->IsObjectArray()) {
FixupObjectArray(orig->AsObjectArray<Object>(), down_cast<ObjectArray<Object>*>(copy));
} else {
diff --git a/src/image_writer.h b/src/image_writer.h
index 0af45c6..003c4e9 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -1,7 +1,7 @@
// Copyright 2011 Google Inc. All Rights Reserved.
-#ifndef ART_SRC_IMAGE_H_
-#define ART_SRC_IMAGE_H_
+#ifndef ART_SRC_IMAGE_WRITER_H_
+#define ART_SRC_IMAGE_WRITER_H_
#include <cstddef>
#include <stdint.h>
@@ -66,4 +66,4 @@
} // namespace art
-#endif // ART_SRC_IMAGE_H_
+#endif // ART_SRC_IMAGE_WRITER_H_
diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc
index f3d13c8..440dda5 100644
--- a/src/jni_compiler.cc
+++ b/src/jni_compiler.cc
@@ -382,9 +382,7 @@
JniCompiler::JniCompiler() {
// TODO: this shouldn't be managed by the JniCompiler, we should have a
// code cache.
- jni_code_.reset(MemMap::Map(kPageSize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_ANONYMOUS | MAP_PRIVATE));
+ jni_code_.reset(MemMap::Map(kPageSize, PROT_READ | PROT_WRITE | PROT_EXEC));
CHECK(jni_code_ != NULL);
jni_code_top_ = jni_code_->GetAddress();
}
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index d4df48a..854df88 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -20,9 +20,7 @@
virtual void SetUp() {
CommonTest::SetUp();
// Create thunk code that performs the native to managed transition
- thunk_code_.reset(MemMap::Map(kPageSize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_ANONYMOUS | MAP_PRIVATE));
+ thunk_code_.reset(MemMap::Map(kPageSize, PROT_READ | PROT_WRITE | PROT_EXEC));
CHECK(thunk_code_ != NULL);
Assembler thk_asm;
// TODO: shouldn't have machine specific code in a general purpose file
diff --git a/src/mark_stack.cc b/src/mark_stack.cc
index 19dc1c1..663cdf7 100644
--- a/src/mark_stack.cc
+++ b/src/mark_stack.cc
@@ -10,9 +10,9 @@
namespace art {
-MarkStack* MarkStack::Create(size_t maximum_size) {
+MarkStack* MarkStack::Create() {
scoped_ptr<MarkStack> mark_stack(new MarkStack());
- bool success = mark_stack->Init(maximum_size);
+ bool success = mark_stack->Init();
if (!success) {
return NULL;
} else {
@@ -20,11 +20,10 @@
}
}
-bool MarkStack::Init(size_t maximum_size) {
+bool MarkStack::Init() {
size_t length = 64 * MB;
- mem_map_.reset(MemMap::Map(length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS));
+ mem_map_.reset(MemMap::Map(length, PROT_READ | PROT_WRITE));
if (mem_map_ == NULL) {
- PLOG(ERROR) << "mmap failed";
return false;
}
byte* addr = mem_map_->GetAddress();
diff --git a/src/mark_stack.h b/src/mark_stack.h
index 38252c2..79026cc 100644
--- a/src/mark_stack.h
+++ b/src/mark_stack.h
@@ -14,7 +14,7 @@
class MarkStack {
public:
- static MarkStack* Create(size_t maximum_size);
+ static MarkStack* Create();
~MarkStack();
@@ -41,7 +41,7 @@
base_(NULL), limit_(NULL), ptr_(NULL) {
}
- bool Init(size_t maximum_size);
+ bool Init();
// Memory mapping of the mark stack.
scoped_ptr<MemMap> mem_map_;
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index 06a1c92..8541f76 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -22,7 +22,7 @@
size_t MarkSweep::finalizer_reference_zombie_offset_ = 0; // TODO
bool MarkSweep::Init() {
- mark_stack_ = MarkStack::Create(Heap::GetMaximumSize());
+ mark_stack_ = MarkStack::Create();
if (mark_stack_ == NULL) {
return false;
}
diff --git a/src/mem_map.h b/src/mem_map.h
index 8645f44..f44939c 100644
--- a/src/mem_map.h
+++ b/src/mem_map.h
@@ -30,18 +30,28 @@
// Request an anonymous region of a specified length.
//
// On success, returns returns a MemMap instance. On failure, returns a NULL;
- static MemMap* Map(size_t length, int prot, int flags) {
+ static MemMap* Map(size_t length, int prot) {
+ return Map(NULL, length, prot);
+ }
+
+ // Request an anonymous region of a specified length and a requested base address.
+ //
+ // On success, returns returns a MemMap instance. On failure, returns a NULL;
+ static MemMap* Map(byte* addr, size_t length, int prot) {
+ CHECK_NE(0U, length);
+ CHECK_NE(0, prot);
size_t page_aligned_size = RoundUp(length, kPageSize);
- byte* addr = reinterpret_cast<byte*>(mmap(NULL,
- page_aligned_size,
- prot,
- MAP_ANONYMOUS | flags,
- -1,
- 0));
- if (addr == MAP_FAILED) {
+ byte* actual = reinterpret_cast<byte*>(mmap(addr,
+ page_aligned_size,
+ prot,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1,
+ 0));
+ if (actual == MAP_FAILED) {
+ PLOG(ERROR) << "mmap failed";
return NULL;
}
- return new MemMap(addr, length, addr, page_aligned_size);
+ return new MemMap(actual, length, actual, page_aligned_size);
}
// Map part of a file, taking care of non-page aligned offsets. The
@@ -49,20 +59,33 @@
//
// On success, returns returns a MemMap instance. On failure, returns a NULL;
static MemMap* Map(size_t length, int prot, int flags, int fd, off_t start) {
+ return Map(NULL, length, prot, flags, fd, start);
+ }
+
+ // Map part of a file, taking care of non-page aligned offsets. The
+ // "start" offset is absolute, not relative. This version allows
+ // requesting a specific address for the base of the mapping.
+ //
+ // On success, returns returns a MemMap instance. On failure, returns a NULL;
+ static MemMap* Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start) {
+ CHECK_NE(0U, length);
+ CHECK_NE(0, prot);
+ CHECK(flags & MAP_SHARED || flags & MAP_PRIVATE);
// adjust to be page-aligned
int page_offset = start % kPageSize;
off_t page_aligned_offset = start - page_offset;
- size_t page_aligned_size = length + page_offset;
- byte* addr = reinterpret_cast<byte*>(mmap(NULL,
- page_aligned_size,
- prot,
- MAP_FILE | flags,
- fd,
- page_aligned_offset));
- if (addr == MAP_FAILED) {
+ size_t page_aligned_size = RoundUp(length + page_offset, kPageSize);
+ byte* actual = reinterpret_cast<byte*>(mmap(addr,
+ page_aligned_size,
+ prot,
+ flags,
+ fd,
+ page_aligned_offset));
+ if (actual == MAP_FAILED) {
+ PLOG(ERROR) << "mmap failed";
return NULL;
}
- return new MemMap(addr+page_offset, length, addr, page_aligned_size);
+ return new MemMap(actual + page_offset, length, actual, page_aligned_size);
}
~MemMap() {
diff --git a/src/object.h b/src/object.h
index da4d6f3..1789ec8 100644
--- a/src/object.h
+++ b/src/object.h
@@ -712,7 +712,7 @@
Object* packages_;
ClassLoader* parent_;
- // TODO remove once we can create a real PathClassLoader
+ // TODO: remove once we can create a real PathClassLoader
std::vector<const DexFile*> class_path_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ClassLoader);
@@ -1293,7 +1293,7 @@
int32_t hash_code) {
String* string = Alloc(GetJavaLangString(),
utf16_length);
- // TODO use 16-bit wide memset variant
+ // TODO: use 16-bit wide memset variant
for (int i = 0; i < utf16_length; i++ ) {
string->array_->Set(i, utf16_data_in[i]);
}
@@ -1435,7 +1435,7 @@
}
bool Equals(const String* that) const {
- // TODO short circuit on hash_code_
+ // TODO: short circuit on hash_code_
if (this->GetLength() != that->GetLength()) {
return false;
}
diff --git a/src/object_bitmap.cc b/src/object_bitmap.cc
index fc3c2ee4..7de4988 100644
--- a/src/object_bitmap.cc
+++ b/src/object_bitmap.cc
@@ -36,9 +36,8 @@
bool HeapBitmap::Init(const byte* base, size_t max_size) {
CHECK(base != NULL);
size_t length = HB_OFFSET_TO_INDEX(max_size) * kWordSize;
- mem_map_.reset(MemMap::Map(length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS));
+ mem_map_.reset(MemMap::Map(length, PROT_READ | PROT_WRITE));
if (mem_map_ == NULL) {
- LOG(ERROR) << "mmap failed";
return false;
}
words_ = reinterpret_cast<word*>(mem_map_->GetAddress());
diff --git a/src/os_linux.cc b/src/os_linux.cc
index 8f5f56a..6d84b51 100644
--- a/src/os_linux.cc
+++ b/src/os_linux.cc
@@ -30,7 +30,7 @@
bool OS::FileExists(const char* name) {
struct stat st;
if (stat(name, &st) == 0) {
- return S_ISREG(st.st_mode); // TODO Deal with symlinks?
+ return S_ISREG(st.st_mode); // TODO: Deal with symlinks?
} else {
return false;
}
diff --git a/src/runtime.cc b/src/runtime.cc
index 6108fe8..43427df 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -22,7 +22,7 @@
Heap::Destroy();
delete thread_list_;
// TODO: acquire a static mutex on Runtime to avoid racing.
- CHECK(instance_ == this);
+ CHECK(instance_ == NULL || instance_ == this);
instance_ = NULL;
}
@@ -231,7 +231,7 @@
if (ignore_unrecognized) {
continue;
}
- // TODO usage
+ // TODO: usage
LOG(FATAL) << "Could not parse " << option;
return NULL;
}
@@ -242,7 +242,7 @@
if (ignore_unrecognized) {
continue;
}
- // TODO usage
+ // TODO: usage
LOG(FATAL) << "Could not parse " << option;
return NULL;
}
@@ -253,7 +253,7 @@
if (ignore_unrecognized) {
continue;
}
- // TODO usage
+ // TODO: usage
LOG(FATAL) << "Could not parse " << option;
return NULL;
}
@@ -329,13 +329,18 @@
stack_size_ = options->stack_size_;
thread_list_ = ThreadList::Create();
- Heap::Init(options->heap_initial_size_,
- options->heap_maximum_size_);
+ if (!Heap::Init(options->heap_initial_size_,
+ options->heap_maximum_size_,
+ options->boot_image_)) {
+ return false;
+ }
bool verbose_jni = options->verbose_.find("jni") != options->verbose_.end();
java_vm_.reset(new JavaVMExt(this, options->check_jni_, verbose_jni));
- Thread::Init();
+ if (!Thread::Init()) {
+ return false;
+ }
Thread* current_thread = Thread::Attach(this);
thread_list_->Register(current_thread);
diff --git a/src/space.cc b/src/space.cc
index c3d763c..8048f29 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -4,16 +4,19 @@
#include <sys/mman.h>
+#include "file.h"
+#include "image.h"
#include "logging.h"
#include "mspace.h"
+#include "os.h"
#include "scoped_ptr.h"
#include "utils.h"
namespace art {
-Space* Space::Create(size_t startup_size, size_t maximum_size) {
- scoped_ptr<Space> space(new Space(startup_size, maximum_size));
- bool success = space->Init();
+Space* Space::Create(size_t initial_size, size_t maximum_size, byte* requested_base) {
+ scoped_ptr<Space> space(new Space());
+ bool success = space->Init(initial_size, maximum_size, requested_base);
if (!success) {
return NULL;
} else {
@@ -21,18 +24,31 @@
}
}
+Space* Space::Create(const char* image_file_name) {
+ CHECK(image_file_name != NULL);
+ scoped_ptr<Space> space(new Space());
+ bool success = space->Init(image_file_name);
+ if (!success) {
+ return NULL;
+ } else {
+ return space.release();
+ }
+}
+
+Space::~Space() {}
+
void* Space::CreateMallocSpace(void* base,
- size_t startup_size,
+ size_t initial_size,
size_t maximum_size) {
errno = 0;
bool is_locked = false;
- size_t commit_size = startup_size / 2;
+ size_t commit_size = initial_size / 2;
void* msp = create_contiguous_mspace_with_base(commit_size, maximum_size,
is_locked, base);
if (msp != NULL) {
// Do not permit the heap grow past the starting size without our
// intervention.
- mspace_set_max_allowed_footprint(msp, startup_size);
+ mspace_set_max_allowed_footprint(msp, initial_size);
} else {
// There is no guarantee that errno has meaning when the call
// fails, but it often does.
@@ -41,35 +57,60 @@
return msp;
}
-bool Space::Init() {
- if (!(startup_size_ <= maximum_size_)) {
+bool Space::Init(size_t initial_size, size_t maximum_size, byte* requested_base) {
+ if (!(initial_size <= maximum_size)) {
return false;
}
- size_t length = RoundUp(maximum_size_, kPageSize);
+ size_t length = RoundUp(maximum_size, kPageSize);
int prot = PROT_READ | PROT_WRITE;
- int flags = MAP_PRIVATE | MAP_ANONYMOUS;
- mem_map_.reset(MemMap::Map(length, prot, flags));
- if (mem_map_ == NULL) {
- PLOG(ERROR) << "mmap failed";
+ scoped_ptr<MemMap> mem_map(MemMap::Map(requested_base, length, prot));
+ if (mem_map == NULL) {
return false;
}
+ Init(mem_map.release());
+ maximum_size_ = maximum_size;
+ mspace_ = CreateMallocSpace(base_, initial_size, maximum_size);
+ return (mspace_ != NULL);
+}
+
+void Space::Init(MemMap* mem_map) {
+ mem_map_.reset(mem_map);
base_ = mem_map_->GetAddress();
- limit_ = base_ + length;
- mspace_ = CreateMallocSpace(base_, startup_size_, maximum_size_);
- if (mspace_ == NULL) {
- mem_map_->Unmap();
+ limit_ = base_ + mem_map->GetLength();
+}
+
+
+bool Space::Init(const char* image_file_name) {
+ scoped_ptr<File> file(OS::OpenFile(image_file_name, false));
+ if (file == NULL) {
return false;
}
+ ImageHeader image_header;
+ bool success = file->ReadFully(&image_header, sizeof(image_header));
+ if (!success || !image_header.IsValid()) {
+ return false;
+ }
+ scoped_ptr<MemMap> map(MemMap::Map(image_header.GetBaseAddr(),
+ file->Length(),
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED,
+ file->Fd(),
+ 0));
+ if (map == NULL) {
+ return false;
+ }
+ CHECK_EQ(image_header.GetBaseAddr(), map->GetAddress());
+ Init(map.release());
return true;
}
-Space::~Space() {}
-
Object* Space::AllocWithoutGrowth(size_t num_bytes) {
+ DCHECK(mspace_ != NULL);
return reinterpret_cast<Object*>(mspace_calloc(mspace_, 1, num_bytes));
}
Object* Space::AllocWithGrowth(size_t num_bytes) {
+ DCHECK(mspace_ != NULL);
// Grow as much as possible within the mspace.
size_t max_allowed = maximum_size_;
mspace_set_max_allowed_footprint(mspace_, max_allowed);
@@ -83,6 +124,7 @@
}
size_t Space::Free(void* ptr) {
+ DCHECK(mspace_ != NULL);
DCHECK(ptr != NULL);
size_t num_bytes = mspace_usable_size(mspace_, ptr);
mspace_free(mspace_, ptr);
@@ -90,6 +132,7 @@
}
size_t Space::AllocationSize(const Object* obj) {
+ DCHECK(mspace_ != NULL);
return mspace_usable_size(mspace_, obj) + kChunkOverhead;
}
@@ -116,6 +159,7 @@
}
size_t Space::MaxAllowedFootprint() {
+ DCHECK(mspace_ != NULL);
return mspace_max_allowed_footprint(mspace_);
}
diff --git a/src/space.h b/src/space.h
index 7b72bba..57f676d 100644
--- a/src/space.h
+++ b/src/space.h
@@ -15,7 +15,11 @@
// A space contains memory allocated for managed objects.
class Space {
public:
- static Space* Create(size_t startup_size, size_t maximum_size);
+ // create a Space with the requested sizes requesting a specific base address.
+ static Space* Create(size_t initial_size, size_t maximum_size, byte* requested_base);
+
+ // create a Space from an image file. cannot be used for future allocation or collected.
+ static Space* Create(const char* image);
~Space();
@@ -53,22 +57,27 @@
// The boundary tag overhead.
static const size_t kChunkOverhead = kWordSize;
- Space(size_t startup_size, size_t maximum_size) :
- mspace_(NULL),
- base_(NULL),
- startup_size_(startup_size),
- maximum_size_(maximum_size) {
- }
+ // create a Space from an existing memory mapping, taking ownership of the address space.
+ static Space* Create(MemMap* mem_map);
+
+ Space() : mspace_(NULL), maximum_size_(0), base_(0), limit_(0) {}
// Initializes the space and underlying storage.
- bool Init();
+ bool Init(size_t initial_size, size_t maximum_size, byte* requested_base);
- void* CreateMallocSpace(void* base, size_t startup_size,
- size_t maximum_size);
+ // Initializes the space from existing storage, taking ownership of the storage.
+ void Init(MemMap* map);
+
+ // Initializes the space from an image file
+ bool Init(const char* image_file_name);
+
+ void* CreateMallocSpace(void* base, size_t initial_size, size_t maximum_size);
static void DontNeed(void* start, void* end, void* num_bytes);
+ // TODO: have a Space subclass for methods that depend on mspace_ and maximum_size_
void* mspace_;
+ size_t maximum_size_;
scoped_ptr<MemMap> mem_map_;
@@ -76,13 +85,9 @@
byte* limit_;
- size_t startup_size_;
+ // bool is_condemned_; // TODO: with IsCondemned
- size_t maximum_size_;
-
- bool is_condemned_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(Space);
+ DISALLOW_COPY_AND_ASSIGN(Space);
};
} // namespace art
diff --git a/src/space_test.cc b/src/space_test.cc
index f3c713b..7384021 100644
--- a/src/space_test.cc
+++ b/src/space_test.cc
@@ -12,23 +12,23 @@
TEST(SpaceTest, Init) {
{
// Less than
- scoped_ptr<Space> space(Space::Create(16 * MB, 32 * MB));
+ scoped_ptr<Space> space(Space::Create(16 * MB, 32 * MB, NULL));
EXPECT_TRUE(space != NULL);
}
{
// Equal to
- scoped_ptr<Space> space(Space::Create(16 * MB, 16 * MB));
+ scoped_ptr<Space> space(Space::Create(16 * MB, 16 * MB, NULL));
EXPECT_TRUE(space != NULL);
}
{
// Greater than
- scoped_ptr<Space> space(Space::Create(32 * MB, 16 * MB));
+ scoped_ptr<Space> space(Space::Create(32 * MB, 16 * MB, NULL));
EXPECT_TRUE(space == NULL);
}
}
TEST(SpaceTest, AllocAndFree) {
- scoped_ptr<Space> space(Space::Create(4 * MB, 16 * MB));
+ scoped_ptr<Space> space(Space::Create(4 * MB, 16 * MB, NULL));
ASSERT_TRUE(space != NULL);
// Succeeds, fits without adjusting the max allowed footprint.
diff --git a/src/thread.cc b/src/thread.cc
index aa3fe95..1001b29 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -55,7 +55,7 @@
Thread* Thread::Create(const Runtime* runtime) {
size_t stack_size = runtime->GetStackSize();
- scoped_ptr<MemMap> stack(MemMap::Map(stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE));
+ scoped_ptr<MemMap> stack(MemMap::Map(stack_size, PROT_READ | PROT_WRITE));
if (stack == NULL) {
LOG(FATAL) << "failed to allocate thread stack";
// notreached
@@ -212,9 +212,9 @@
// Make sure that all threads have exited and unregistered when we
// reach this point. This means that all daemon threads had been
// shutdown cleanly.
- CHECK_EQ(list_.size(), 1U);
+ CHECK_LE(list_.size(), 1U);
// TODO: wait for all other threads to unregister
- CHECK_EQ(list_.front(), Thread::Current());
+ CHECK(list_.size() == 0 || list_.front() == Thread::Current());
// TODO: detach the current thread
delete lock_;
lock_ = NULL;
diff --git a/src/zip_archive.cc b/src/zip_archive.cc
index fe263ba..cccaf82 100644
--- a/src/zip_archive.cc
+++ b/src/zip_archive.cc
@@ -386,7 +386,6 @@
// It all looks good. Create a mapping for the CD.
dir_map_.reset(MemMap::Map(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset));
if (dir_map_ == NULL) {
- LOG(WARNING) << "Zip: cd map failed " << strerror(errno);
return false;
}