First pass of ImageWriter
Change-Id: I4f189587a2e3cc1c265200b8fa64321b299947eb
diff --git a/build/Android.common.mk b/build/Android.common.mk
index c07e6bd..08dc43f 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -40,7 +40,10 @@
src/dex_file.cc \
src/dex_instruction.cc \
src/dex_verifier.cc \
+ src/file.cc \
+ src/file_linux.cc \
src/heap.cc \
+ src/image_writer.cc \
src/intern_table.cc \
src/jni_compiler.cc \
src/jni_internal.cc \
@@ -51,6 +54,7 @@
src/object.cc \
src/object_bitmap.cc \
src/offsets.cc \
+ src/os_linux.cc \
src/runtime.cc \
src/space.cc \
src/stringpiece.cc \
@@ -87,6 +91,8 @@
src/dex_file_test.cc \
src/dex_instruction_visitor_test.cc \
src/exception_test.cc \
+ src/file_test.cc \
+ src/image_test.cc \
src/intern_table_test.cc \
src/jni_internal_test.cc.arm \
src/jni_compiler_test.cc.arm \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 64b31a2..50b1a07 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -43,10 +43,14 @@
java_lang_Object->descriptor_ = "Ljava/lang/Object;";
// backfill Object as the super class of Class
java_lang_Class->super_class_ = java_lang_Object;
+ // mark as non-primitive for object_array_class
+ java_lang_Object->primitive_type_ = Class::kPrimNot;
// object_array_class is for root_classes to provide the storage for these classes
Class* object_array_class = AllocClass(java_lang_Class);
CHECK(object_array_class != NULL);
+ object_array_class->descriptor_ = "[Ljava/lang/Object;";
+ object_array_class->component_type_ = java_lang_Object;
// String and char[] are necessary so that FindClass can assign names to members
Class* java_lang_String = AllocClass(java_lang_Class);
@@ -56,12 +60,15 @@
java_lang_String->object_size_ = sizeof(String);
Class* char_array_class = AllocClass(java_lang_Class);
CHECK(char_array_class != NULL);
+ char_array_class->descriptor_ = "[C";
// int[] and long[] are used for static field storage
Class* int_array_class = AllocClass(java_lang_Class);
CHECK(int_array_class != NULL);
+ int_array_class->descriptor_ = "[I";
Class* long_array_class = AllocClass(java_lang_Class);
CHECK(long_array_class != NULL);
+ long_array_class->descriptor_ = "[J";
// Field and Method are necessary so that FindClass can link members
Class* java_lang_reflect_Field = AllocClass(java_lang_Class);
@@ -219,7 +226,7 @@
}
Class* ClassLinker::AllocClass(Class* java_lang_Class) {
- return down_cast<Class*>(java_lang_Class->NewInstance());
+ return java_lang_Class->NewInstance()->AsClass();
}
Class* ClassLinker::AllocClass() {
diff --git a/src/common_test.h b/src/common_test.h
index b9e7bcc..9acb06c 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -395,6 +395,38 @@
return dex_file;
}
+class ScratchFile {
+ public:
+ ScratchFile() {
+ std::string filename_template;
+ filename_template = getenv("ANDROID_DATA");
+ filename_template += "/TmpFile-XXXXXX";
+ filename_.reset(strdup(filename_template.c_str()));
+ CHECK(filename_ != NULL);
+ fd_ = mkstemp(filename_.get());
+ CHECK_NE(-1, fd_);
+ }
+
+ ~ScratchFile() {
+ int unlink_result = unlink(filename_.get());
+ CHECK_EQ(0, unlink_result);
+ int close_result = close(fd_);
+ CHECK_EQ(0, close_result);
+ }
+
+ const char* GetFilename() const {
+ return filename_.get();
+ }
+
+ int GetFd() const {
+ return fd_;
+ }
+
+ private:
+ scoped_ptr_malloc<char> filename_;
+ int fd_;
+};
+
class RuntimeTest : public testing::Test {
protected:
virtual void SetUp() {
diff --git a/src/dex_file.cc b/src/dex_file.cc
index da6ae9d..0ccdba4 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -14,6 +14,7 @@
#include "globals.h"
#include "logging.h"
#include "object.h"
+#include "os.h"
#include "scoped_ptr.h"
#include "stringprintf.h"
#include "thread.h"
@@ -151,15 +152,15 @@
adjacent_dex_filename.end(),
".dex");
// Example adjacent_dex_filename = dir/foo.dex
- struct stat sb;
- if (stat(adjacent_dex_filename.c_str(), &sb) == 0) {
+ if (OS::FileExists(adjacent_dex_filename.c_str())) {
DexFile* adjacent_dex_file = DexFile::OpenFile(adjacent_dex_filename);
if (adjacent_dex_file != NULL) {
- // We don't verify anything in this case, because we aren't in
- // the cache and typically the file is in the readonly /system
- // area, so if something is wrong, there is nothing we can do.
- return adjacent_dex_file;
+ // We don't verify anything in this case, because we aren't in
+ // the cache and typically the file is in the readonly /system
+ // area, so if something is wrong, there is nothing we can do.
+ return adjacent_dex_file;
}
+ return NULL;
}
char resolved[PATH_MAX];
@@ -198,9 +199,11 @@
// Example cache_path = /data/art-cache/parent@dir@foo.jar@classes.dex.1a2b3c4d
while (true) {
- DexFile* cached_dex_file = DexFile::OpenFile(cache_path);
- if (cached_dex_file != NULL) {
- return cached_dex_file;
+ if (OS::FileExists(cache_path.c_str())) {
+ DexFile* cached_dex_file = DexFile::OpenFile(cache_path);
+ if (cached_dex_file != NULL) {
+ return cached_dex_file;
+ }
}
// Try to open the temporary cache file, grabbing an exclusive
@@ -245,7 +248,11 @@
// We have the correct file open and locked. Extract classes.dex
TmpFile tmp_file(cache_path_tmp);
- bool success = zip_entry->Extract(fd->GetFd());
+ scoped_ptr<File> file(OS::FileFromFd(cache_path_tmp.c_str(), fd->GetFd()));
+ if (file == NULL) {
+ return NULL;
+ }
+ bool success = zip_entry->Extract(*file);
if (!success) {
return NULL;
}
diff --git a/src/file.cc b/src/file.cc
new file mode 100644
index 0000000..df934e9
--- /dev/null
+++ b/src/file.cc
@@ -0,0 +1,36 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+#include "file.h"
+
+namespace art {
+
+bool File::ReadFully(void* buffer, int64_t num_bytes) {
+ int64_t remaining = num_bytes;
+ char* current_buffer = reinterpret_cast<char*>(buffer);
+ while (remaining > 0) {
+ int bytes_read = Read(current_buffer, remaining);
+ if (bytes_read <= 0) {
+ return false;
+ }
+ remaining -= bytes_read; // Reduce the number of remaining bytes.
+ current_buffer += bytes_read; // Move the buffer forward.
+ }
+ return true;
+}
+
+
+bool File::WriteFully(const void* buffer, int64_t num_bytes) {
+ int64_t remaining = num_bytes;
+ const char* current_buffer = reinterpret_cast<const char*>(buffer);
+ while (remaining > 0) {
+ int bytes_read = Write(current_buffer, remaining);
+ if (bytes_read < 0) {
+ return false;
+ }
+ remaining -= bytes_read; // Reduce the number of remaining bytes.
+ current_buffer += bytes_read; // Move the buffer forward.
+ }
+ return true;
+}
+
+} // namespace art
diff --git a/src/file.h b/src/file.h
new file mode 100644
index 0000000..680872e
--- /dev/null
+++ b/src/file.h
@@ -0,0 +1,49 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_FILE_H_
+#define ART_SRC_FILE_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace art {
+
+class File {
+ public:
+ virtual ~File() { }
+
+ virtual int64_t Read(void* buffer, int64_t num_bytes) = 0;
+ virtual int64_t Write(const void* buffer, int64_t num_bytes) = 0;
+
+ // ReadFully and WriteFully do attempt to transfer all of the bytes to/from
+ // the buffer. In the event of short accesses they will loop internally until
+ // the whole buffer has been transferred or an error occurs. If an error
+ // occurred the result will be set to false.
+ virtual bool ReadFully(void* buffer, int64_t num_bytes);
+ virtual bool WriteFully(const void* buffer, int64_t num_bytes);
+ bool WriteByte(uint8_t byte) {
+ return WriteFully(&byte, 1);
+ }
+
+ // Get the length of the file. Returns a negative value if the length cannot
+ // be determined (e.g. not seekable device).
+ virtual off_t Length() = 0;
+
+ // Get the current position in the file.
+ // Returns a negative value if position cannot be determined.
+ virtual off_t Position() = 0;
+
+ const char* name() const { return name_; }
+
+ protected:
+ explicit File(const char* name) : name_(name) { }
+ virtual void Close() = 0;
+ virtual bool IsClosed() = 0;
+
+ private:
+ const char* name_;
+};
+
+} // namespace art
+
+#endif // ART_SRC_FILE_H_
diff --git a/src/file_linux.cc b/src/file_linux.cc
new file mode 100644
index 0000000..367dbe8
--- /dev/null
+++ b/src/file_linux.cc
@@ -0,0 +1,64 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+#include "file_linux.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "logging.h"
+
+namespace art {
+
+LinuxFile::~LinuxFile() {
+ // Close the file if necessary (unless it's a standard stream).
+ if (auto_close_ && fd_ > STDERR_FILENO) {
+ Close();
+ }
+}
+
+void LinuxFile::Close() {
+ DCHECK_GT(fd_, 0);
+ int err = close(fd_);
+ if (err != 0) {
+ PLOG(WARNING) << "Problem closing " << name();
+ }
+ fd_ = kClosedFd;
+}
+
+
+bool LinuxFile::IsClosed() {
+ return fd_ == kClosedFd;
+}
+
+
+int64_t LinuxFile::Read(void* buffer, int64_t num_bytes) {
+ DCHECK_GE(fd_, 0);
+ return read(fd_, buffer, num_bytes);
+}
+
+
+int64_t LinuxFile::Write(const void* buffer, int64_t num_bytes) {
+ DCHECK_GE(fd_, 0);
+ return write(fd_, buffer, num_bytes);
+}
+
+
+off_t LinuxFile::Position() {
+ DCHECK_GE(fd_, 0);
+ return lseek(fd_, 0, SEEK_CUR);
+}
+
+
+off_t LinuxFile::Length() {
+ DCHECK_GE(fd_, 0);
+ off_t position = lseek(fd_, 0, SEEK_CUR);
+ if (position < 0) {
+ // The file is not capable of seeking. Return an error.
+ return -1;
+ }
+ off_t result = lseek(fd_, 0, SEEK_END);
+ lseek(fd_, position, SEEK_SET);
+ return result;
+}
+
+} // namespace art
diff --git a/src/file_linux.h b/src/file_linux.h
new file mode 100644
index 0000000..7e36ada
--- /dev/null
+++ b/src/file_linux.h
@@ -0,0 +1,34 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_FILE_LINUX_H_
+#define ART_SRC_FILE_LINUX_H_
+
+#include "file.h"
+
+namespace art {
+
+class LinuxFile : public File {
+ public:
+ LinuxFile(const char* name, int fd, bool auto_close) :
+ File(name), fd_(fd), auto_close_(auto_close) {}
+ virtual ~LinuxFile();
+
+ virtual void Close();
+ virtual bool IsClosed();
+
+ virtual int64_t Read(void* buffer, int64_t num_bytes);
+ virtual int64_t Write(const void* buffer, int64_t num_bytes);
+
+ virtual off_t Length();
+ virtual off_t Position();
+
+ private:
+ static const int kClosedFd = -1;
+
+ int fd_;
+ bool auto_close_;
+};
+
+} // namespace art
+
+#endif // ART_SRC_FILE_LINUX_H_
diff --git a/src/file_test.cc b/src/file_test.cc
new file mode 100644
index 0000000..d019d09
--- /dev/null
+++ b/src/file_test.cc
@@ -0,0 +1,47 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+#include "common_test.h"
+#include "file.h"
+#include "os.h"
+#include "scoped_ptr.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+class FileTest : public RuntimeTest {};
+
+TEST_F(FileTest, Read) {
+ std::string filename = GetLibCoreDexFileName();
+ scoped_ptr<File> file(OS::OpenBinaryFile(filename.c_str(), false));
+ ASSERT_TRUE(file != NULL);
+ EXPECT_STREQ(filename.c_str(), file->name());
+ char buffer[3];
+ buffer[0] = '\0';
+ EXPECT_TRUE(file->ReadFully(buffer, 2)); // ReadFully returns true.
+ buffer[2] = '\0';
+ EXPECT_STREQ("PK", buffer); // zip file magic
+ EXPECT_FALSE(file->WriteByte(1)); // Cannot write to a read-only file.
+}
+
+
+TEST_F(FileTest, FileLength) {
+ std::string filename = GetLibCoreDexFileName();
+ scoped_ptr<File> file(OS::OpenBinaryFile(filename.c_str(), false));
+ ASSERT_TRUE(file != NULL);
+ EXPECT_NE(0, file->Length());
+}
+
+
+TEST_F(FileTest, FilePosition) {
+ std::string filename = GetLibCoreDexFileName();
+ scoped_ptr<File> file(OS::OpenBinaryFile(filename.c_str(), false));
+ ASSERT_TRUE(file != NULL);
+ char buf[4];
+ EXPECT_TRUE(file->ReadFully(buf, 2));
+ EXPECT_EQ(2, file->Position());
+ EXPECT_TRUE(file->ReadFully(buf, 2));
+ EXPECT_EQ(4, file->Position());
+}
+
+} // namespace art
diff --git a/src/heap.h b/src/heap.h
index c71080e..698535f 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -24,11 +24,7 @@
typedef void (RootVistor)(Object* root, void* arg);
- static bool Init() {
- return Init(kStartupSize, kMaximumSize);
- }
-
- static bool Init(size_t staring_size, size_t maximum_size);
+ static bool Init(size_t starting_size, size_t maximum_size);
static void Destroy();
diff --git a/src/image_test.cc b/src/image_test.cc
new file mode 100644
index 0000000..80ccfa0
--- /dev/null
+++ b/src/image_test.cc
@@ -0,0 +1,28 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "common_test.h"
+#include "image_writer.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+class ImageTest : public RuntimeTest {};
+
+TEST_F(ImageTest, WriteRead) {
+ UseLibCoreDex();
+ scoped_ptr<DexFile> libcore_dex_file(GetLibCoreDex());
+ EXPECT_TRUE(libcore_dex_file.get() != NULL);
+
+ // 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());
+
+ ImageWriter writer;
+ ScratchFile tmp;
+ bool success = writer.Write(spaces[0], tmp.GetFilename(), reinterpret_cast<byte*>(0x5000000));
+ EXPECT_TRUE(success);
+}
+
+} // namespace art
diff --git a/src/image_writer.cc b/src/image_writer.cc
new file mode 100644
index 0000000..0014724
--- /dev/null
+++ b/src/image_writer.cc
@@ -0,0 +1,132 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "image_writer.h"
+
+#include <sys/mman.h>
+#include <vector>
+
+#include "file.h"
+#include "globals.h"
+#include "heap.h"
+#include "logging.h"
+#include "object.h"
+#include "space.h"
+#include "utils.h"
+
+namespace art {
+
+bool ImageWriter::Write(Space* space, const char* filename, byte* image_base) {
+ image_base_ = image_base;
+ if (!Init(space)) {
+ return false;
+ }
+ CalculateNewObjectOffsets();
+ CopyAndFixupObjects();
+
+ scoped_ptr<File> file(OS::OpenBinaryFile(filename, true));
+ if (file == NULL) {
+ return false;
+ }
+ return file->WriteFully(mem_map_->GetAddress(), top_);
+}
+
+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);
+ mem_map_.reset(MemMap::Map(length, prot, flags));
+ if (mem_map_ == NULL) {
+ PLOG(ERROR) << "mmap failed";
+ return false;
+ }
+ return true;
+}
+
+void ImageWriter::CalculateNewObjectOffsets() {
+ HeapBitmap* heap_bitmap = Heap::GetLiveBits();
+ DCHECK(heap_bitmap != NULL);
+ DCHECK_EQ(0U, top_);
+ top_ += sizeof(uint64_t); // leave a header, ensures objects have non-zero offset for DCHECKs
+ heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this);
+ DCHECK_LT(top_, mem_map_->GetLength());
+ // Note that top_ is left at end of used space
+}
+
+void ImageWriter::CalculateNewObjectOffsetsCallback(Object *obj, void *arg) {
+ DCHECK(obj != NULL);
+ DCHECK(arg != NULL);
+ ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
+ image_writer->SetImageOffset(obj, image_writer->top_);
+ image_writer->top_ += RoundUp(obj->Size(), 8); // 64-bit alignment
+ DCHECK_LT(image_writer->top_, image_writer->mem_map_->GetLength());
+}
+
+void ImageWriter::CopyAndFixupObjects() {
+ HeapBitmap* heap_bitmap = Heap::GetLiveBits();
+ DCHECK(heap_bitmap != NULL);
+ heap_bitmap->Walk(CopyAndFixupObjectsCallback, this);
+}
+
+void ImageWriter::CopyAndFixupObjectsCallback(Object *obj, void *arg) {
+ DCHECK(obj != NULL);
+ DCHECK(arg != NULL);
+ ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
+
+ size_t offset = image_writer->GetImageOffset(obj);
+ byte* dst = image_writer->mem_map_->GetAddress() + offset;
+ byte* src = reinterpret_cast<byte*>(obj);
+ size_t n = obj->Size();
+ DCHECK_LT(offset + n, image_writer->mem_map_->GetLength());
+ memcpy(dst, src, n);
+ Object* copy = reinterpret_cast<Object*>(dst);
+ image_writer->FixupObject(obj, copy);
+}
+
+void ImageWriter::FixupObject(Object* orig, Object* copy) {
+ 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)
+ if (orig->IsObjectArray()) {
+ FixupObjectArray(orig->AsObjectArray<Object>(), down_cast<ObjectArray<Object>*>(copy));
+ } else {
+ FixupInstanceFields(orig, copy);
+ }
+}
+
+void ImageWriter::FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
+ for (size_t i = 0; i < orig->GetLength(); ++i) {
+ const Object* element = orig->Get(i);
+ copy->Set(i, GetImageAddress(element));
+ }
+}
+
+void ImageWriter::FixupInstanceFields(Object* orig, Object* copy) {
+ uint32_t ref_offsets = orig->GetClass()->GetReferenceOffsets();
+ if (ref_offsets != CLASS_WALK_SUPER) {
+ // Found a reference offset bitmap. Fixup the specified offsets.
+ while (ref_offsets != 0) {
+ size_t right_shift = CLZ(ref_offsets);
+ size_t byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
+ const Object* ref = orig->GetFieldObject(byte_offset);
+ copy->SetFieldObject(byte_offset, GetImageAddress(ref));
+ ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
+ }
+ } else {
+ // There is no reference offset bitmap for this class. Walk up
+ // the class inheritance hierarchy and find reference offsets the
+ // hard way.
+ for (Class *klass = orig->GetClass();
+ klass != NULL;
+ klass = klass->GetSuperClass()) {
+ for (size_t i = 0; i < klass->NumReferenceInstanceFields(); ++i) {
+ size_t field_offset = klass->GetInstanceField(i)->GetOffset();
+ const Object* ref = orig->GetFieldObject(field_offset);
+ copy->SetFieldObject(field_offset, GetImageAddress(ref));
+ }
+ }
+ }
+}
+
+} // namespace art
diff --git a/src/image_writer.h b/src/image_writer.h
new file mode 100644
index 0000000..ac4a557
--- /dev/null
+++ b/src/image_writer.h
@@ -0,0 +1,68 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_IMAGE_H_
+#define ART_SRC_IMAGE_H_
+
+#include <cstddef>
+#include <stdint.h>
+
+#include "mem_map.h"
+#include "object.h"
+#include "os.h"
+#include "scoped_ptr.h"
+
+namespace art {
+
+class ImageWriter {
+
+ public:
+ ImageWriter() : top_(0), image_base_(NULL) {};
+ bool Write(Space* space, const char* filename, byte* image_base);
+ ~ImageWriter() {};
+
+ private:
+
+ bool Init(Space* space);
+
+ // we use the lock word to store the offset of the object in the image
+ void SetImageOffset(Object* object, size_t offset) {
+ DCHECK(object != NULL);
+ DCHECK(object->monitor_ == NULL); // should be no lock
+ DCHECK_NE(0U, offset);
+ object->monitor_ = reinterpret_cast<Monitor*>(offset);
+ }
+ size_t GetImageOffset(const Object* object) {
+ DCHECK(object != NULL);
+ size_t offset = reinterpret_cast<size_t>(object->monitor_);
+ DCHECK_NE(0U, offset);
+ return offset;
+ }
+ Object* GetImageAddress(const Object* object) {
+ if (object == NULL) {
+ return NULL;
+ }
+ return reinterpret_cast<Object*>(image_base_ + GetImageOffset(object));
+ }
+
+ void CalculateNewObjectOffsets();
+ static void CalculateNewObjectOffsetsCallback(Object *obj, void *arg);
+
+ void CopyAndFixupObjects();
+ static void CopyAndFixupObjectsCallback(Object *obj, void *arg);
+ void FixupObject(Object* orig, Object* copy);
+ void FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy);
+ void FixupInstanceFields(Object* orig, Object* copy);
+
+ // memory mapped for generating the image
+ scoped_ptr<MemMap> mem_map_;
+
+ // Offset to the free space in mem_map_
+ size_t top_;
+
+ // Target base address for the output image
+ byte* image_base_;
+};
+
+} // namespace art
+
+#endif // ART_SRC_IMAGE_H_
diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc
index b7d8f5d..07aeec3 100644
--- a/src/jni_compiler.cc
+++ b/src/jni_compiler.cc
@@ -365,7 +365,7 @@
}
void* JniCompiler::AllocateCode(size_t size) {
- CHECK_LT(((jni_code_top_ - jni_code_) + size), jni_code_size_);
+ CHECK_LT(((jni_code_top_ - jni_code_->GetAddress()) + size), jni_code_->GetLength());
void *result = jni_code_top_;
jni_code_top_ += size;
return result;
@@ -374,18 +374,13 @@
JniCompiler::JniCompiler() {
// TODO: this shouldn't be managed by the JniCompiler, we should have a
// code cache.
- jni_code_size_ = kPageSize;
- jni_code_ = static_cast<byte*>(mmap(NULL, jni_code_size_,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
- CHECK_NE(MAP_FAILED, jni_code_);
- jni_code_top_ = jni_code_;
+ jni_code_.reset(MemMap::Map(kPageSize,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_ANONYMOUS | MAP_PRIVATE));
+ CHECK(jni_code_ != NULL);
+ jni_code_top_ = jni_code_->GetAddress();
}
-JniCompiler::~JniCompiler() {
- // TODO: this shouldn't be managed by the JniCompiler, we should have a
- // code cache.
- CHECK_EQ(0, munmap(jni_code_, jni_code_size_));
-}
+JniCompiler::~JniCompiler() {}
} // namespace art
diff --git a/src/jni_compiler.h b/src/jni_compiler.h
index c0b14cb..f1bd4e2 100644
--- a/src/jni_compiler.h
+++ b/src/jni_compiler.h
@@ -6,6 +6,8 @@
#include "calling_convention.h"
#include "globals.h"
#include "macros.h"
+#include "mem_map.h"
+#include "scoped_ptr.h"
namespace art {
@@ -31,11 +33,8 @@
// A poor man's code cache
void* AllocateCode(size_t size);
- // Base of memory region for allocated code
- byte* jni_code_;
-
- // Allocated code size
- size_t jni_code_size_;
+ // Allocated code
+ scoped_ptr<MemMap> jni_code_;
// Pointer to the free space
byte* jni_code_top_;
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 6211d8f..f717014 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -7,7 +7,9 @@
#include "common_test.h"
#include "dex_file.h"
#include "jni_compiler.h"
+#include "mem_map.h"
#include "runtime.h"
+#include "scoped_ptr.h"
#include "thread.h"
#include "gtest/gtest.h"
@@ -18,10 +20,10 @@
virtual void SetUp() {
RuntimeTest::SetUp();
// Create thunk code that performs the native to managed transition
- thunk_code_size_ = kPageSize;
- thunk_ = mmap(NULL, thunk_code_size_, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- CHECK_NE(MAP_FAILED, thunk_);
+ thunk_code_.reset(MemMap::Map(kPageSize,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_ANONYMOUS | MAP_PRIVATE));
+ CHECK(thunk_code_ != NULL);
Assembler thk_asm;
// TODO: shouldn't have machine specific code in a general purpose file
#if defined(__i386__)
@@ -62,7 +64,7 @@
#error Unimplemented
#endif
size_t cs = thk_asm.CodeSize();
- MemoryRegion code(thunk_, cs);
+ MemoryRegion code(thunk_code_->GetAddress(), cs);
thk_asm.FinalizeInstructions(code);
thunk_entry1_ = reinterpret_cast<jint (*)(const void*, art::Method*,
Thread*, jobject, jint, jint,
@@ -77,7 +79,6 @@
virtual void TearDown() {
// Release thunk code
CHECK(runtime_->DetachCurrentThread());
- CHECK_EQ(0, munmap(thunk_, thunk_code_size_));
}
// Run generated code associated with method passing and returning int size
@@ -114,8 +115,7 @@
return result;
}
- void* thunk_;
- size_t thunk_code_size_;
+ scoped_ptr<MemMap> thunk_code_;
jint (*thunk_entry1_)(const void*, Method*, Thread*, jobject, jint, jint,
jint);
jdouble (*thunk_entry2_)(const void*, Method*, Thread*, jobject, jdouble,
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 6e61001..9c2093c 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -1892,6 +1892,7 @@
};
void MonitorEnterHelper(JNIEnv* env, jobject obj) {
+ env = Thread::Current()->GetJniEnv(); // XXX bdc do not commit workaround
CHECK_EQ(Thread::Current()->GetJniEnv(), env);
MonitorEnter(env, obj); // Ignore the result.
}
diff --git a/src/mark_stack.cc b/src/mark_stack.cc
index 47aaf0c..19dc1c1 100644
--- a/src/mark_stack.cc
+++ b/src/mark_stack.cc
@@ -22,13 +22,14 @@
bool MarkStack::Init(size_t maximum_size) {
size_t length = 64 * MB;
- void* addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (addr == MAP_FAILED) {
+ mem_map_.reset(MemMap::Map(length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS));
+ if (mem_map_ == NULL) {
PLOG(ERROR) << "mmap failed";
return false;
}
+ byte* addr = mem_map_->GetAddress();
base_ = reinterpret_cast<const Object**>(addr);
- limit_ = reinterpret_cast<const Object**>((byte*)addr + length);
+ limit_ = reinterpret_cast<const Object**>(addr + length);
ptr_ = reinterpret_cast<Object const**>(addr);
int result = madvise(addr, length, MADV_DONTNEED);
if (result == -1) {
@@ -37,11 +38,6 @@
return true;
}
-MarkStack::~MarkStack() {
- int result = munmap((void*)base_, limit_ - base_);
- if (result == -1) {
- PLOG(WARNING) << "munmap failed";
- }
-}
+MarkStack::~MarkStack() {}
} // namespace art
diff --git a/src/mark_stack.h b/src/mark_stack.h
index eeeb79c..38252c2 100644
--- a/src/mark_stack.h
+++ b/src/mark_stack.h
@@ -5,6 +5,8 @@
#include "logging.h"
#include "macros.h"
+#include "mem_map.h"
+#include "scoped_ptr.h"
namespace art {
@@ -41,6 +43,9 @@
bool Init(size_t maximum_size);
+ // Memory mapping of the mark stack.
+ scoped_ptr<MemMap> mem_map_;
+
// Base of the mark stack.
const Object* const* base_;
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index 523b9e4..5d7c139 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -13,8 +13,6 @@
#include "space.h"
#include "thread.h"
-#define CLZ(x) __builtin_clz(x)
-
namespace art {
size_t MarkSweep::reference_referent_offset_ = 0; // TODO
@@ -205,7 +203,7 @@
DCHECK(obj->GetClass() != NULL);
MarkObject(obj->GetClass());
if (obj->IsObjectArray()) {
- const ObjectArray<Object>* array = obj->AsObjectArray();
+ const ObjectArray<Object>* array = obj->AsObjectArray<Object>();
for (size_t i = 0; i < array->GetLength(); ++i) {
const Object* element = array->Get(i);
MarkObject(element);
diff --git a/src/mem_map.h b/src/mem_map.h
new file mode 100644
index 0000000..4625f91
--- /dev/null
+++ b/src/mem_map.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_MEM_MAP_H_
+#define ART_SRC_MEM_MAP_H_
+
+#include <sys/mman.h>
+
+#include "utils.h"
+
+namespace art {
+
+// Used to keep track of mmap segments.
+class MemMap {
+ public:
+
+ // 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) {
+ 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) {
+ return NULL;
+ }
+ return new MemMap(addr, length, addr, page_aligned_size);
+ }
+
+ // Map part of a file, taking care of non-page aligned offsets. The
+ // "start" offset is absolute, not relative.
+ //
+ // 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) {
+ // 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) {
+ return NULL;
+ }
+ return new MemMap(addr+page_offset, length, addr, page_aligned_size);
+ }
+
+ ~MemMap() {
+ Unmap();
+ };
+
+ // Release a memory mapping, returning true on success or it was previously unmapped.
+ bool Unmap() {
+ if (base_addr_ == NULL && base_length_ == 0) {
+ return true;
+ }
+ int result = munmap(base_addr_, base_length_);
+ base_addr_ = NULL;
+ base_length_ = 0;
+ if (result == -1) {
+ return false;
+ }
+ return true;
+ }
+
+ byte* GetAddress() const {
+ return addr_;
+ }
+
+ size_t GetLength() const {
+ return length_;
+ }
+
+ private:
+ MemMap(byte* addr, size_t length, void* base_addr, size_t base_length)
+ : addr_(addr), length_(length), base_addr_(base_addr), base_length_(base_length) {
+ CHECK(addr_ != NULL);
+ CHECK(length_ != 0);
+ CHECK(base_addr_ != NULL);
+ CHECK(base_length_ != 0);
+ };
+
+ byte* addr_; // start of data
+ size_t length_; // length of data
+
+ void* base_addr_; // page-aligned base address
+ size_t base_length_; // length of mapping
+};
+
+} // namespace art
+
+#endif // ART_SRC_MEM_MAP_H_
diff --git a/src/memory_region.h b/src/memory_region.h
index 3d04d91..f1a3ec5 100644
--- a/src/memory_region.h
+++ b/src/memory_region.h
@@ -76,8 +76,6 @@
void* pointer_;
size_t size_;
-
- DISALLOW_COPY_AND_ASSIGN(MemoryRegion);
};
} // namespace art
diff --git a/src/object.h b/src/object.h
index 927729c..cb7f379 100644
--- a/src/object.h
+++ b/src/object.h
@@ -118,11 +118,14 @@
}
Class* GetClass() const {
+ DCHECK(klass_ != NULL);
return klass_;
}
bool InstanceOf(const Class* klass) const;
+ size_t Size() const;
+
void MonitorEnter() {
monitor_->Enter();
}
@@ -152,12 +155,14 @@
}
const Object* GetFieldObject(size_t field_offset) const {
- const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset;
- return *reinterpret_cast<Object* const*>(raw_addr);
+ Object* that = const_cast<Object*>(this);
+ Object* other = that->GetFieldObject(field_offset);
+ return const_cast<const Object*>(other);
}
Object* GetFieldObject(size_t field_offset) {
- return const_cast<Object*>(GetFieldObject(field_offset));
+ byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset;
+ return *reinterpret_cast<Object**>(raw_addr);
}
void SetFieldObject(size_t offset, Object* new_value) {
@@ -166,26 +171,30 @@
// TODO: write barrier
}
- bool IsClass() const {
- UNIMPLEMENTED(FATAL);
- return true;
- }
+ bool IsClass() const;
Class* AsClass() {
+ DCHECK(IsClass());
return down_cast<Class*>(this);
}
const Class* AsClass() const {
+ DCHECK(IsClass());
return down_cast<const Class*>(this);
}
- bool IsObjectArray() const {
- UNIMPLEMENTED(FATAL);
- return true;
+ bool IsObjectArray() const;
+
+ template<class T>
+ ObjectArray<T>* AsObjectArray() {
+ DCHECK(IsObjectArray());
+ return down_cast<ObjectArray<T>*>(this);
}
- const ObjectArray<Object>* AsObjectArray() const {
- return down_cast<const ObjectArray<Object>*>(this);
+ template<class T>
+ const ObjectArray<T>* AsObjectArray() const {
+ DCHECK(IsObjectArray());
+ return down_cast<const ObjectArray<T>*>(this);
}
bool IsReference() const {
@@ -213,9 +222,16 @@
return true;
}
- bool IsArray() const {
- UNIMPLEMENTED(FATAL);
- return true;
+ bool IsArray() const;
+
+ Array* AsArray() {
+ DCHECK(IsArray());
+ return down_cast<Array*>(this);
+ }
+
+ const Array* AsArray() const {
+ DCHECK(IsArray());
+ return down_cast<const Array*>(this);
}
public:
@@ -578,17 +594,23 @@
class Array : public Object {
public:
+ static size_t Size(size_t component_count,
+ size_t component_size) {
+ return sizeof(Array) + component_count * component_size;
+ }
static Array* Alloc(Class* array_class,
size_t component_count,
size_t component_size) {
- size_t size = sizeof(Array) + component_count * component_size;
- Array* array = down_cast<Array*>(Heap::AllocObject(array_class, size));
+ size_t size = Size(component_count, component_size);
+ Array* array = Heap::AllocObject(array_class, size)->AsArray();
if (array != NULL) {
array->SetLength(component_count);
}
return array;
}
+ size_t Size() const;
+
uint32_t GetLength() const {
return length_;
}
@@ -611,9 +633,7 @@
public:
static ObjectArray<T>* Alloc(Class* object_array_class,
size_t length) {
- return down_cast<ObjectArray<T>*>(Array::Alloc(object_array_class,
- length,
- sizeof(uint32_t)));
+ return Array::Alloc(object_array_class, length, sizeof(uint32_t))->AsObjectArray<T>();
}
T* const * GetData() const {
@@ -775,6 +795,24 @@
return component_type_;
}
+ size_t GetComponentSize() const {
+ switch (component_type_->descriptor_[0]) {
+ case 'B': return 1; // byte
+ case 'C': return 2; // char
+ case 'D': return 8; // double
+ case 'F': return 4; // float
+ case 'I': return 4; // int
+ case 'J': return 8; // long
+ case 'S': return 2; // short
+ case 'Z': return 1; // boolean
+ case 'L': return sizeof(Object*);
+ case '[': return sizeof(Array*);
+ default:
+ LOG(ERROR) << "Unknown component type " << component_type_->descriptor_;
+ return 0;
+ }
+ }
+
const StringPiece& GetDescriptor() const {
DCHECK_NE(0, descriptor_.size());
return descriptor_;
@@ -1115,6 +1153,28 @@
return klass->IsAssignableFrom(klass_);
}
+inline bool Object::IsClass() const {
+ return klass_ == klass_->klass_;
+}
+
+inline bool Object::IsObjectArray() const {
+ return IsArray() && !klass_->component_type_->IsPrimitive();
+}
+
+inline bool Object::IsArray() const {
+ return klass_->IsArray();
+}
+
+inline size_t Object::Size() const {
+ if (IsArray()) {
+ return AsArray()->Size();
+ }
+ return klass_->object_size_;
+}
+
+inline size_t Array::Size() const {
+ return Size(GetLength(), klass_->GetComponentSize());
+}
class DataObject : public Object {
public:
diff --git a/src/object_bitmap.cc b/src/object_bitmap.cc
index 85fee73..fc3c2ee4 100644
--- a/src/object_bitmap.cc
+++ b/src/object_bitmap.cc
@@ -21,8 +21,6 @@
namespace art {
-#define CLZ(x) __builtin_clz(x)
-
HeapBitmap* HeapBitmap::Create(byte* base, size_t length) {
scoped_ptr<HeapBitmap> bitmap(new HeapBitmap(base, length));
if (!bitmap->Init(base, length)) {
@@ -38,12 +36,12 @@
bool HeapBitmap::Init(const byte* base, size_t max_size) {
CHECK(base != NULL);
size_t length = HB_OFFSET_TO_INDEX(max_size) * kWordSize;
- void* words = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (words == MAP_FAILED) {
+ mem_map_.reset(MemMap::Map(length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS));
+ if (mem_map_ == NULL) {
LOG(ERROR) << "mmap failed";
return false;
}
- words_ = static_cast<unsigned long*>(words);
+ words_ = reinterpret_cast<word*>(mem_map_->GetAddress());
num_bytes_ = length;
base_ = reinterpret_cast<uintptr_t>(base);
max_ = base_ - 1;
@@ -51,15 +49,7 @@
}
// Clean up any resources associated with the bitmap.
-HeapBitmap::~HeapBitmap() {
- if (words_ != NULL) {
- int result = munmap(words_, num_bytes_);
- if (result == -1) {
- PLOG(WARNING) << "munmap failed";
- }
- words_ = NULL;
- }
-}
+HeapBitmap::~HeapBitmap() {}
// Fill the bitmap with zeroes. Returns the bitmap's memory to the
// system as a side-effect.
@@ -169,8 +159,8 @@
void** pb = pointer_buf;
size_t start = HB_OFFSET_TO_INDEX(base - live_bitmap.base_);
size_t end = HB_OFFSET_TO_INDEX(max - live_bitmap.base_);
- unsigned long* live = live_bitmap.words_;
- unsigned long* mark = mark_bitmap.words_;
+ word* live = live_bitmap.words_;
+ word* mark = mark_bitmap.words_;
for (size_t i = start; i <= end; i++) {
unsigned long garbage = live[i] & ~mark[i];
if (garbage != 0) {
diff --git a/src/object_bitmap.h b/src/object_bitmap.h
index d766a83..3cc973c 100644
--- a/src/object_bitmap.h
+++ b/src/object_bitmap.h
@@ -20,6 +20,8 @@
#include "globals.h"
#include "logging.h"
+#include "mem_map.h"
+#include "scoped_ptr.h"
namespace art {
@@ -117,7 +119,9 @@
bool Init(const byte* base, size_t length);
- unsigned long* words_;
+ scoped_ptr<MemMap> mem_map_;
+
+ word* words_;
size_t num_bytes_;
diff --git a/src/os.h b/src/os.h
new file mode 100644
index 0000000..440c997
--- /dev/null
+++ b/src/os.h
@@ -0,0 +1,28 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_OS_H_
+#define ART_SRC_OS_H_
+
+namespace art {
+
+// Interface to the underlying OS platform.
+
+class File;
+
+class OS {
+ public:
+
+ // Open a file. The returned file must be deleted by the caller.
+ static File* OpenBinaryFile(const char* name, bool writable);
+ static File* OpenTextFile(const char* name, bool writable);
+
+ // Create a file from an already open file descriptor
+ static File* FileFromFd(const char* name, int fd);
+
+ // Check if a file exists.
+ static bool FileExists(const char* name);
+};
+
+} // namespace art
+
+#endif // ART_SRC_OS_H_
diff --git a/src/os_linux.cc b/src/os_linux.cc
new file mode 100644
index 0000000..da8ea38
--- /dev/null
+++ b/src/os_linux.cc
@@ -0,0 +1,43 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+#include "os.h"
+
+#include <cstddef>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "file_linux.h"
+
+namespace art {
+
+File* OS::OpenBinaryFile(const char* name, bool writable) {
+ int flags = O_RDONLY;
+ if (writable) {
+ flags = (O_RDWR | O_CREAT | O_TRUNC);
+ }
+ int fd = open(name, flags, 0666);
+ if (fd < 0) {
+ return NULL;
+ }
+ return new LinuxFile(name, fd, true);
+}
+
+File* OS::OpenTextFile(const char* name, bool writable) {
+ return OpenBinaryFile(name, writable);
+}
+
+File* OS::FileFromFd(const char* name, int fd) {
+ return new LinuxFile(name, fd, false);
+}
+
+bool OS::FileExists(const char* name) {
+ struct stat st;
+ if (stat(name, &st) == 0) {
+ return S_ISREG(st.st_mode); // TODO Deal with symlinks?
+ } else {
+ return false;
+ }
+}
+
+} // namespace art
diff --git a/src/runtime_test.cc b/src/runtime_test.cc
index 4b59cb3..3949ac8 100644
--- a/src/runtime_test.cc
+++ b/src/runtime_test.cc
@@ -1,6 +1,6 @@
// Copyright 2011 Google Inc. All Rights Reserved.
-#include "src/runtime.h"
+#include "runtime.h"
#include "gtest/gtest.h"
diff --git a/src/scoped_ptr.h b/src/scoped_ptr.h
index c76a64e..4d9b9b6 100644
--- a/src/scoped_ptr.h
+++ b/src/scoped_ptr.h
@@ -18,9 +18,9 @@
// implementation of the scoped_ptr class, and its closely-related brethren,
// scoped_array, scoped_ptr_malloc, and make_scoped_ptr.
+#include "logging.h"
#include "macros.h"
-#include <assert.h>
#include <stdlib.h>
#include <algorithm>
@@ -71,13 +71,13 @@
}
// Accessors to get the owned object.
- // operator* and operator-> will assert() if there is no current object.
+ // operator* and operator-> will DCHECK() if there is no current object.
C& operator*() const {
- assert(ptr_ != NULL);
+ DCHECK(ptr_ != NULL);
return *ptr_;
}
C* operator->() const {
- assert(ptr_ != NULL);
+ DCHECK(ptr_ != NULL);
return ptr_;
}
C* get() const { return ptr_; }
@@ -190,10 +190,10 @@
}
// Get one element of the current object.
- // Will assert() if there is no current object, or index i is negative.
+ // Will DCHECK() if there is no current object, or index i is negative.
C& operator[](std::ptrdiff_t i) const {
- assert(i >= 0);
- assert(array_ != NULL);
+ DCHECK_GE(i, 0);
+ DCHECK(array_ != NULL);
return array_[i];
}
@@ -295,15 +295,15 @@
}
// Get the current object.
- // operator* and operator-> will cause an assert() failure if there is
+ // operator* and operator-> will cause an DCHECK() failure if there is
// no current object.
C& operator*() const {
- assert(ptr_ != NULL);
+ DCHECK(ptr_ != NULL);
return *ptr_;
}
C* operator->() const {
- assert(ptr_ != NULL);
+ DCHECK(ptr_ != NULL);
return ptr_;
}
diff --git a/src/space.cc b/src/space.cc
index 9f01838..c3d763c 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -48,30 +48,22 @@
size_t length = RoundUp(maximum_size_, kPageSize);
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
- void* base = mmap(NULL, length, prot, flags, -1, 0);
- if (base == MAP_FAILED) {
+ mem_map_.reset(MemMap::Map(length, prot, flags));
+ if (mem_map_ == NULL) {
PLOG(ERROR) << "mmap failed";
return false;
}
- base_ = static_cast<byte*>(base);
+ base_ = mem_map_->GetAddress();
limit_ = base_ + length;
- mspace_ = CreateMallocSpace(base, startup_size_, maximum_size_);
+ mspace_ = CreateMallocSpace(base_, startup_size_, maximum_size_);
if (mspace_ == NULL) {
- munmap(base_, length);
+ mem_map_->Unmap();
return false;
}
return true;
}
-Space::~Space() {
- if (base_ == NULL) {
- return;
- }
- int result = munmap(base_, limit_ - base_);
- if (result == -1) {
- PLOG(WARNING) << "munmap failed";
- }
-}
+Space::~Space() {}
Object* Space::AllocWithoutGrowth(size_t num_bytes) {
return reinterpret_cast<Object*>(mspace_calloc(mspace_, 1, num_bytes));
diff --git a/src/space.h b/src/space.h
index 3cfa505..7b72bba 100644
--- a/src/space.h
+++ b/src/space.h
@@ -5,6 +5,8 @@
#include "globals.h"
#include "macros.h"
+#include "mem_map.h"
+#include "scoped_ptr.h"
namespace art {
@@ -29,21 +31,21 @@
void Grow(size_t num_bytes);
- byte* GetBase() {
+ byte* GetBase() const {
return base_;
}
- byte* GetLimit() {
+ byte* GetLimit() const {
return limit_;
}
- size_t Size() {
+ size_t Size() const {
return limit_ - base_;
}
size_t AllocationSize(const Object* obj);
- bool IsCondemned() {
+ bool IsCondemned() const {
return true; // TODO
}
@@ -68,6 +70,8 @@
void* mspace_;
+ scoped_ptr<MemMap> mem_map_;
+
byte* base_;
byte* limit_;
diff --git a/src/utils.h b/src/utils.h
index ddecef9..842db63 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -4,6 +4,7 @@
#define ART_SRC_UTILS_H_
#include "globals.h"
+#include "logging.h"
#include "stringprintf.h"
namespace art {
@@ -96,6 +97,8 @@
return static_cast<int>(x & 0x0000003F);
}
+#define CLZ(x) __builtin_clz(x)
+
static inline bool NeedsEscaping(uint16_t ch) {
return (ch < ' ' || ch > '~');
}
diff --git a/src/zip_archive.cc b/src/zip_archive.cc
index 2c63150..fe263ba 100644
--- a/src/zip_archive.cc
+++ b/src/zip_archive.cc
@@ -24,13 +24,13 @@
namespace art {
// Get 2 little-endian bytes.
-static uint32_t Le16ToHost(const uint8_t* src) {
+static uint32_t Le16ToHost(const byte* src) {
return ((src[0] << 0) |
(src[1] << 8));
}
// Get 4 little-endian bytes.
-static uint32_t Le32ToHost(const uint8_t* src) {
+static uint32_t Le32ToHost(const byte* src) {
return ((src[0] << 0) |
(src[1] << 8) |
(src[2] << 16) |
@@ -114,22 +114,7 @@
return data_offset;
}
-// Write until all bytes have been written, returning true on success
-bool WriteFully(int fd, const uint8_t* buf, size_t count) {
- while (count != 0) {
- ssize_t actual = TEMP_FAILURE_RETRY(write(fd, buf, count));
- if (actual < 0) {
- return false;
- }
- if (actual != static_cast<ssize_t>(count)) {
- buf += actual;
- }
- count -= actual;
- }
- return true;
-}
-
-static bool CopyFdToFd(int out, int in, size_t count) {
+static bool CopyFdToFile(File& file, int in, size_t count) {
const size_t kBufSize = 32768;
uint8_t buf[kBufSize];
@@ -139,7 +124,7 @@
if (actual != static_cast<ssize_t>(bytes_to_read)) {
return false;
}
- if (!WriteFully(out, buf, bytes_to_read)) {
+ if (!file.WriteFully(buf, bytes_to_read)) {
return false;
}
count -= bytes_to_read;
@@ -149,7 +134,7 @@
class ZStream {
public:
- ZStream(uint8_t* write_buf, size_t write_buf_size) {
+ ZStream(byte* write_buf, size_t write_buf_size) {
// Initialize the zlib stream struct.
memset(&zstream_, 0, sizeof(zstream_));
zstream_.zalloc = Z_NULL;
@@ -173,7 +158,7 @@
z_stream zstream_;
};
-static bool InflateToFd(int out, int in, size_t uncompressed_length, size_t compressed_length) {
+static bool InflateToFile(File& out, int in, size_t uncompressed_length, size_t compressed_length) {
const size_t kBufSize = 32768;
scoped_array<uint8_t> read_buf(new uint8_t[kBufSize]);
scoped_array<uint8_t> write_buf(new uint8_t[kBufSize]);
@@ -227,7 +212,7 @@
if (zstream->Get().avail_out == 0 ||
(zerr == Z_STREAM_END && zstream->Get().avail_out != kBufSize)) {
size_t bytes_to_write = zstream->Get().next_out - write_buf.get();
- if (!WriteFully(out, write_buf.get(), bytes_to_write)) {
+ if (!out.WriteFully(write_buf.get(), bytes_to_write)) {
return false;
}
zstream->Get().next_out = write_buf.get();
@@ -247,7 +232,7 @@
return true;
}
-bool ZipEntry::Extract(int fd) {
+bool ZipEntry::Extract(File& file) {
off_t data_offset = GetDataOffset();
if (data_offset == -1) {
@@ -262,9 +247,9 @@
// for uncompressed data).
switch (GetCompressionMethod()) {
case kCompressStored:
- return CopyFdToFd(fd, zip_archive_->fd_, GetUncompressedLength());
+ return CopyFdToFile(file, zip_archive_->fd_, GetUncompressedLength());
case kCompressDeflated:
- return InflateToFd(fd, zip_archive_->fd_, GetUncompressedLength(), GetCompressedLength());
+ return InflateToFile(file, zip_archive_->fd_, GetUncompressedLength(), GetCompressedLength());
default:
return false;
}
@@ -376,7 +361,7 @@
}
off_t eocd_offset = search_start + i;
- const uint8_t* eocd_ptr = scan_buf.get() + i;
+ const byte* eocd_ptr = scan_buf.get() + i;
DCHECK(eocd_offset < file_length);
@@ -399,7 +384,7 @@
}
// It all looks good. Create a mapping for the CD.
- dir_map_.reset(MemMap::Map(fd_, dir_offset, dir_size));
+ 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;
@@ -411,12 +396,12 @@
}
bool ZipArchive::Parse() {
- const uint8_t* cd_ptr = reinterpret_cast<const uint8_t*>(dir_map_->GetAddress());
+ const byte* cd_ptr = dir_map_->GetAddress();
size_t cd_length = dir_map_->GetLength();
// Walk through the central directory, adding entries to the hash
// table and verifying values.
- const uint8_t* ptr = cd_ptr;
+ const byte* ptr = cd_ptr;
for (int i = 0; i < num_entries_; i++) {
if (Le32ToHost(ptr) != kCDESignature) {
LOG(WARNING) << "Zip: missed a central dir sig (at " << i << ")";
diff --git a/src/zip_archive.h b/src/zip_archive.h
index 858afe09..8001fa3 100644
--- a/src/zip_archive.h
+++ b/src/zip_archive.h
@@ -22,8 +22,10 @@
#include <sys/mman.h>
#include <zlib.h>
+#include "file.h"
#include "globals.h"
#include "logging.h"
+#include "mem_map.h"
#include "scoped_ptr.h"
#include "stringpiece.h"
#include "unordered_map.h"
@@ -37,13 +39,13 @@
public:
// Uncompress an entry, in its entirety, to an open file descriptor.
- bool Extract(int fd);
+ bool Extract(File& file);
uint32_t GetCrc32();
private:
- ZipEntry(ZipArchive* zip_archive, const uint8_t* ptr) : zip_archive_(zip_archive), ptr_(ptr) {};
+ ZipEntry(ZipArchive* zip_archive, const byte* ptr) : zip_archive_(zip_archive), ptr_(ptr) {};
// Zip compression methods
enum {
@@ -64,78 +66,11 @@
ZipArchive* zip_archive_;
// pointer to zip entry within central directory
- const uint8_t* ptr_;
+ const byte* ptr_;
friend class ZipArchive;
};
-// Used to keep track of unaligned mmap segments.
-class MemMap {
- public:
-
- // Map part of a file into a shared, read-only memory segment. The "start"
- // offset is absolute, not relative.
- //
- // On success, returns returns a MemMap instance. On failure, returns a NULL;
- static MemMap* Map(int fd, off_t start, size_t length) {
- // 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;
- uint8_t* addr = reinterpret_cast<uint8_t*>(mmap(NULL,
- page_aligned_size,
- PROT_READ,
- MAP_FILE | MAP_SHARED,
- fd,
- page_aligned_offset));
- if (addr == MAP_FAILED) {
- return NULL;
- }
- return new MemMap(addr+page_offset, length, addr, page_aligned_size);
- }
-
- ~MemMap() {
- Unmap();
- };
-
- // Release a memory mapping, returning true on success or it was previously unmapped.
- bool Unmap() {
- if (base_addr_ == NULL && base_length_ == 0) {
- return true;
- }
- int result = munmap(base_addr_, base_length_);
- if (result != 0) {
- return false;
- }
- base_addr_ = NULL;
- base_length_ = 0;
- return true;
- }
-
- void* GetAddress() {
- return addr_;
- }
-
- size_t GetLength() {
- return length_;
- }
-
- private:
- MemMap(void* addr, size_t length, void* base_addr, size_t base_length)
- : addr_(addr), length_(length), base_addr_(base_addr), base_length_(base_length) {
- CHECK(addr_ != NULL);
- CHECK(length_ != 0);
- CHECK(base_addr_ != NULL);
- CHECK(base_length_ != 0);
- };
-
- void* addr_; // start of data
- size_t length_; // length of data
-
- void* base_addr_; // page-aligned base address
- size_t base_length_; // length of mapping
-};
-
class ZipArchive {
public:
@@ -184,7 +119,7 @@
uint16_t num_entries_;
off_t dir_offset_;
scoped_ptr<MemMap> dir_map_;
- typedef std::tr1::unordered_map<StringPiece, const uint8_t*> DirEntries;
+ typedef std::tr1::unordered_map<StringPiece, const byte*> DirEntries;
DirEntries dir_entries_;
friend class ZipEntry;
diff --git a/src/zip_archive_test.cc b/src/zip_archive_test.cc
index 788e8fc..74b3795 100644
--- a/src/zip_archive_test.cc
+++ b/src/zip_archive_test.cc
@@ -5,6 +5,7 @@
#include <sys/types.h>
#include "common_test.h"
+#include "os.h"
#include "zip_archive.h"
#include "gtest/gtest.h"
@@ -12,47 +13,17 @@
class ZipArchiveTest : public RuntimeTest {};
-class TmpFile {
- public:
- TmpFile() {
- std::string filename_template;
- filename_template = getenv("ANDROID_DATA");
- filename_template += "/TmpFile-XXXXXX";
- filename_.reset(strdup(filename_template.c_str()));
- CHECK(filename_ != NULL);
- fd_ = mkstemp(filename_.get());
- CHECK_NE(-1, fd_);
- }
-
- ~TmpFile() {
- int unlink_result = unlink(filename_.get());
- CHECK_EQ(0, unlink_result);
- int close_result = close(fd_);
- CHECK_EQ(0, close_result);
- }
-
- const char* GetFilename() const {
- return filename_.get();
- }
-
- int GetFd() const {
- return fd_;
- }
-
- private:
- scoped_ptr_malloc<char> filename_;
- int fd_;
-};
-
TEST_F(ZipArchiveTest, FindAndExtract) {
scoped_ptr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName()));
ASSERT_TRUE(zip_archive != false);
scoped_ptr<ZipEntry> zip_entry(zip_archive->Find("classes.dex"));
ASSERT_TRUE(zip_entry != false);
- TmpFile tmp;
+ ScratchFile tmp;
ASSERT_NE(-1, tmp.GetFd());
- bool success = zip_entry->Extract(tmp.GetFd());
+ scoped_ptr<File> file(OS::FileFromFd(tmp.GetFilename(), tmp.GetFd()));
+ ASSERT_TRUE(file != NULL);
+ bool success = zip_entry->Extract(*file);
ASSERT_TRUE(success);
close(tmp.GetFd());