Adding oat_process
- Added oat_process, a version of app_process use to launch frameworks apps
- Added liboat_runtime, a version of libandroid_runtime that uses art instead of dvm
This is just a special makefile, frameworks/base/core/jni code is used for source
- Added support for build a boot.oat with the full BOOTCLASSPATH
The older smaller boat.oat is now core.oat
- Added mem_map code for making sure a requested memory region is available
Moved mem_map code to cc file to make easier to debug with smaller rebuild
- Moved oat base address to 0x6000000 as a work around to host addres conflict
- Added -Xms and -Xmx options to dex2oat to allow build specific memory options
- Fixed miranda method initialization problem found compiling full bootclasspath
- Made compiler.cc tolerant of verification errors found compiling full bootclasspath
- Bumped arena block alloc warning to avoid noise when compiling full bootclasspath
- Marked implicit GC unimplemented to fail fast
- Added --output argument to oatdump
- Made many object asserts tolerate access in IsErroneous state
now that verifier is failing validation of some classes during compilation
- Made runtime tolerate unknown access as short term solution for oat_process
- Workaround SSA issue to restore full bootclasspath compilation
- Added test-art-target-processs to excercise oat_process with "am"
"am" found bug where class_linker was using Method::GetClass and not ::GetDeclaringClass
Change-Id: I1a645a142b163e06bab9e72eb094ae1f1dbfbd97
diff --git a/src/class_linker.cc b/src/class_linker.cc
index de70fa5..a9c2005 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -657,7 +657,7 @@
Thread* self = Thread::Current();
DCHECK(self != NULL);
- CHECK(!self->IsExceptionPending());
+ CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
// Find the class in the loaded classes table.
Class* klass = LookupClass(descriptor, class_loader);
if (klass == NULL) {
@@ -701,7 +701,6 @@
LoadClass(dex_file, dex_class_def, klass, class_loader);
// Check for a pending exception during load
if (self->IsExceptionPending()) {
- // TODO: free native allocations in klass
return NULL;
}
ObjectLock lock(klass);
@@ -711,7 +710,6 @@
if (!success) {
// We may fail to insert if we raced with another thread.
klass->SetClinitThreadId(0);
- // TODO: free native allocations in klass
klass = LookupClass(descriptor, class_loader);
CHECK(klass != NULL);
return klass;
@@ -1230,7 +1228,12 @@
LOG(ERROR) << "Verification failed on class "
<< klass->GetDescriptor()->ToModifiedUtf8();
Object* exception = Thread::Current()->GetException();
- klass->SetVerifyErrorClass(exception->GetClass());
+ // CHECK(exception != NULL) << PrettyClass(klass);
+ if (exception == NULL) {
+ UNIMPLEMENTED(ERROR) << "null verification exception for " << PrettyClass(klass);
+ } else {
+ klass->SetVerifyErrorClass(exception->GetClass());
+ }
klass->SetStatus(Class::kStatusError);
return;
}
@@ -1381,7 +1384,7 @@
for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
const Method* method = interface_entry->GetMethodArray()->Get(j);
if (!HasSameMethodDescriptorClasses(method, interface,
- method->GetClass())) {
+ method->GetDeclaringClass())) {
ThrowLinkageError("Classes resolve differently in interface");
return false;
}
@@ -1394,7 +1397,7 @@
bool ClassLinker::HasSameMethodDescriptorClasses(const Method* method,
const Class* klass1,
const Class* klass2) {
- const DexFile& dex_file = FindDexFile(method->GetClass()->GetDexCache());
+ const DexFile& dex_file = FindDexFile(method->GetDeclaringClass()->GetDexCache());
const DexFile::ProtoId& proto_id = dex_file.GetProtoId(method->GetProtoIdx());
DexFile::ParameterIterator *it;
for (it = dex_file.GetParameterIterator(proto_id); it->HasNext(); it->Next()) {
@@ -1865,8 +1868,9 @@
if (miranda_count != 0) {
int old_method_count = klass->NumVirtualMethods();
int new_method_count = old_method_count + miranda_count;
- klass->SetVirtualMethods(
- klass->GetVirtualMethods()->CopyOf(new_method_count));
+ klass->SetVirtualMethods((old_method_count == 0)
+ ? AllocObjectArray<Method>(new_method_count)
+ : klass->GetVirtualMethods()->CopyOf(new_method_count));
ObjectArray<Method>* vtable = klass->GetVTableDuringLinking();
CHECK(vtable != NULL);
diff --git a/src/common_test.h b/src/common_test.h
index a291976..127cad6 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -2,6 +2,7 @@
#include <dirent.h>
#include <dlfcn.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -104,6 +105,8 @@
Runtime::Options options;
options.push_back(std::make_pair("bootclasspath", &boot_class_path_));
options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL)));
+ options.push_back(std::make_pair("-Xms16m", reinterpret_cast<void*>(NULL)));
+ options.push_back(std::make_pair("-Xmx16m", reinterpret_cast<void*>(NULL)));
runtime_.reset(Runtime::Create(options, false));
ASSERT_TRUE(runtime_.get() != NULL);
class_linker_ = runtime_->GetClassLinker();
diff --git a/src/compiler.cc b/src/compiler.cc
index 71727fd..54793ba 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -2,6 +2,8 @@
#include "compiler.h"
+#include <sys/mman.h>
+
#include "assembler.h"
#include "class_linker.h"
#include "class_loader.h"
@@ -72,7 +74,9 @@
// Class derived values are more complicated, they require the linker and loader.
for (size_t type_idx = 0; type_idx < dex_cache->NumResolvedTypes(); type_idx++) {
Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
- CHECK(klass->IsResolved());
+ if (klass == NULL) {
+ Thread::Current()->ClearException();
+ }
}
// Method and Field are the worst. We can't resolve without either
@@ -172,13 +176,19 @@
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
const char* descriptor = dex_file.GetClassDescriptor(class_def);
Class* klass = class_linker->FindClass(descriptor, class_loader);
- class_linker->EnsureInitialized(klass, false);
+ if (klass != NULL) {
+ class_linker->EnsureInitialized(klass, false);
+ }
+ // clear any class not found or verification exceptions
+ Thread::Current()->ClearException();
}
DexCache* dex_cache = class_linker->FindDexCache(dex_file);
for (size_t type_idx = 0; type_idx < dex_cache->NumResolvedTypes(); type_idx++) {
Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
- if (klass->IsInitialized()) {
+ if (klass == NULL) {
+ Thread::Current()->ClearException();
+ } else if (klass->IsInitialized()) {
dex_cache->GetInitializedStaticStorage()->Set(type_idx, klass);
}
}
@@ -199,8 +209,15 @@
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
const char* descriptor = dex_file.GetClassDescriptor(class_def);
Class* klass = class_linker->FindClass(descriptor, class_loader);
- CHECK(klass != NULL);
- CompileClass(klass);
+ if (klass == NULL) {
+ // previous verification error will cause FindClass to throw
+ Thread* self = Thread::Current();
+ // CHECK(self->IsExceptionPending());
+ UNIMPLEMENTED(WARNING) << "CHECK for verification error after FindClass " << descriptor;
+ self->ClearException();
+ } else {
+ CompileClass(klass);
+ }
}
}
diff --git a/src/compiler/Utility.cc b/src/compiler/Utility.cc
index fbdf62c..7d3a887 100644
--- a/src/compiler/Utility.cc
+++ b/src/compiler/Utility.cc
@@ -78,7 +78,7 @@
currentArena->next = newArena;
currentArena = newArena;
numArenaBlocks++;
- if (numArenaBlocks > 1000) {
+ if (numArenaBlocks > 20000) {
LOG(INFO) << "Total arena pages: " << numArenaBlocks;
}
goto retry;
@@ -373,7 +373,8 @@
bool oatIntersectBitVectors(ArenaBitVector* dest, const ArenaBitVector* src1,
const ArenaBitVector* src2)
{
- if (dest->storageSize != src1->storageSize ||
+ if (src2 == NULL ||
+ dest->storageSize != src1->storageSize ||
dest->storageSize != src2->storageSize ||
dest->expandable != src1->expandable ||
dest->expandable != src2->expandable)
@@ -392,7 +393,8 @@
bool oatUnifyBitVectors(ArenaBitVector* dest, const ArenaBitVector* src1,
const ArenaBitVector* src2)
{
- if (dest->storageSize != src1->storageSize ||
+ if (src2 == NULL ||
+ dest->storageSize != src1->storageSize ||
dest->storageSize != src2->storageSize ||
dest->expandable != src1->expandable ||
dest->expandable != src2->expandable)
diff --git a/src/compiler/codegen/arm/CodegenCommon.cc b/src/compiler/codegen/arm/CodegenCommon.cc
index 40494f3..08da8d8 100644
--- a/src/compiler/codegen/arm/CodegenCommon.cc
+++ b/src/compiler/codegen/arm/CodegenCommon.cc
@@ -280,8 +280,11 @@
int dest, int src1, int src2)
{
ArmLIR* insn = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
- assert(isPseudoOpcode(opcode) ||
- (EncodingMap[opcode].flags & IS_TERTIARY_OP));
+ DCHECK(isPseudoOpcode(opcode) ||
+ (EncodingMap[opcode].flags & IS_TERTIARY_OP))
+ << (int)opcode << " "
+ << PrettyMethod(cUnit->method) << " "
+ << cUnit->currentDalvikOffset;
insn->opcode = opcode;
insn->operands[0] = dest;
insn->operands[1] = src1;
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index f60699c..053575a 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -39,7 +39,7 @@
// TODO: remove this by making boot image contain boot DexFile information?
fprintf(stderr,
" --boot-dex-file=<dex-file>: specifies a .dex file that is part of the boot\n"
- " image specified with --boot. \n"
+ " image specified with --boot. \n"
" Example: --boot-dex-file=/system/framework/core.jar\n"
"\n");
fprintf(stderr,
@@ -48,9 +48,19 @@
"\n");
fprintf(stderr,
" --strip-prefix may be used to strip a path prefix from dex file names in the\n"
- " the generated image to match the target file system layout.\n"
+ " the generated image to match the target file system layout.\n"
" Example: --strip-prefix=out/target/product/crespo\n"
"\n");
+ fprintf(stderr,
+ " -Xms<n> may be used to specify an initial heap size for the runtime used to\n"
+ " run dex2oat\n"
+ " Example: -Xms256m\n"
+ "\n");
+ fprintf(stderr,
+ " -Xmx<n> may be used to specify a maximum heap size for the runtime used to\n"
+ " run dex2oat\n"
+ " Example: -Xmx256m\n"
+ "\n");
exit(EXIT_FAILURE);
}
@@ -71,6 +81,8 @@
std::vector<const char*> boot_dex_filenames;
uintptr_t image_base = 0;
std::string strip_location_prefix;
+ const char* Xms = NULL;
+ const char* Xmx = NULL;
for (int i = 0; i < argc; i++) {
const StringPiece option(argv[i]);
@@ -85,7 +97,7 @@
char* end;
image_base = strtoul(image_base_str, &end, 16);
if (end == image_base_str || *end != '\0') {
- fprintf(stderr, "could not parse hexadecimal value for option %s\n", option.data());
+ fprintf(stderr, "Failed to parse hexadecimal value for option %s\n", option.data());
usage();
}
} else if (option.starts_with("--boot=")) {
@@ -97,6 +109,10 @@
boot_dex_filenames.push_back(option.substr(strlen("--boot-dex-file=")).data());
} else if (option.starts_with("--strip-prefix=")) {
strip_location_prefix = option.substr(strlen("--strip-prefix=")).data();
+ } else if (option.starts_with("-Xms")) {
+ Xms = option.data();
+ } else if (option.starts_with("-Xmx")) {
+ Xmx = option.data();
} else {
fprintf(stderr, "unknown argument %s\n", option.data());
usage();
@@ -138,6 +154,12 @@
options.push_back(std::make_pair("bootclasspath", &boot_dex_files));
options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
}
+ if (Xms != NULL) {
+ options.push_back(std::make_pair(Xms, reinterpret_cast<void*>(NULL)));
+ }
+ if (Xmx != NULL) {
+ options.push_back(std::make_pair(Xmx, reinterpret_cast<void*>(NULL)));
+ }
UniquePtr<Runtime> runtime(Runtime::Create(options, false));
if (runtime.get() == NULL) {
fprintf(stderr, "could not create runtime\n");
diff --git a/src/heap.cc b/src/heap.cc
index 4d8d176..8311944 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -330,6 +330,7 @@
++Runtime::Current()->GetStats()->gc_for_alloc_count;
++Thread::Current()->GetStats()->gc_for_alloc_count;
}
+ UNIMPLEMENTED(FATAL) << "No implicit GC, use larger -Xms -Xmx";
CollectGarbageInternal();
ptr = space->AllocWithoutGrowth(size);
if (ptr != NULL) {
diff --git a/src/heap.h b/src/heap.h
index f39454a..ea05a73 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -35,9 +35,9 @@
class Heap {
public:
- static const size_t kInitialSize = 64 * MB; // TODO: lower to 4
+ static const size_t kInitialSize = 4 * MB;
- static const size_t kMaximumSize = 64 * MB; // TODO: lower to 16
+ static const size_t kMaximumSize = 16 * MB;
typedef void (RootVisitor)(const Object* root, void* arg);
diff --git a/src/mem_map.cc b/src/mem_map.cc
new file mode 100644
index 0000000..e44a894
--- /dev/null
+++ b/src/mem_map.cc
@@ -0,0 +1,163 @@
+#include "mem_map.h"
+
+#include <sys/mman.h>
+
+#include "utils.h"
+
+/*
+ * 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.
+ */
+
+#include "mem_map.h"
+
+#include <sys/mman.h>
+
+namespace art {
+
+size_t ParseHex(const std::string& string) {
+ CHECK_EQ(8U, string.size());
+ const char* str = string.c_str();
+ char* end;
+ size_t value = strtoul(str, &end, 16);
+ CHECK(end != str) << "Failed to parse hexadecimal value from " << string;
+ CHECK(*end == '\0') << "Failed to parse hexadecimal value from " << string;
+ return value;
+}
+
+void CheckMapRequest(byte* addr, size_t length) {
+#ifndef NDEBUG
+ if (addr == NULL) {
+ return;
+ }
+ size_t base = reinterpret_cast<size_t>(addr);
+ size_t limit = base + length;
+
+ std::string maps;
+ bool read = ReadFileToString("/proc/self/maps", &maps);
+ if (!read) {
+ PLOG(FATAL) << "Failed to read /proc/self/maps";
+ }
+ // Quick and dirty parse of output like shown below. We only focus
+ // on grabbing the two 32-bit hex values at the start of each line
+ // and will fail on wider addresses found on 64-bit systems.
+
+ // 00008000-0001f000 r-xp 00000000 b3:01 273 /system/bin/toolbox
+ // 0001f000-00021000 rw-p 00017000 b3:01 273 /system/bin/toolbox
+ // 00021000-00029000 rw-p 00000000 00:00 0 [heap]
+ // 40011000-40053000 r-xp 00000000 b3:01 1050 /system/lib/libc.so
+ // 40053000-40056000 rw-p 00042000 b3:01 1050 /system/lib/libc.so
+ // 40056000-40061000 rw-p 00000000 00:00 0
+ // 40061000-40063000 r-xp 00000000 b3:01 1107 /system/lib/libusbhost.so
+ // 40063000-40064000 rw-p 00002000 b3:01 1107 /system/lib/libusbhost.so
+ // 4009d000-400a0000 r-xp 00000000 b3:01 1022 /system/lib/liblog.so
+ // 400a0000-400a1000 rw-p 00003000 b3:01 1022 /system/lib/liblog.so
+ // 400b7000-400cc000 r-xp 00000000 b3:01 932 /system/lib/libm.so
+ // 400cc000-400cd000 rw-p 00015000 b3:01 932 /system/lib/libm.so
+ // 400cf000-400d0000 r--p 00000000 00:00 0
+ // 400e4000-400ec000 r--s 00000000 00:0b 388 /dev/__properties__ (deleted)
+ // 400ec000-400fa000 r-xp 00000000 b3:01 1101 /system/lib/libcutils.so
+ // 400fa000-400fb000 rw-p 0000e000 b3:01 1101 /system/lib/libcutils.so
+ // 400fb000-4010a000 rw-p 00000000 00:00 0
+ // 4010d000-4010e000 r-xp 00000000 b3:01 929 /system/lib/libstdc++.so
+ // 4010e000-4010f000 rw-p 00001000 b3:01 929 /system/lib/libstdc++.so
+ // b0001000-b0009000 r-xp 00001000 b3:01 1098 /system/bin/linker
+ // b0009000-b000a000 rw-p 00009000 b3:01 1098 /system/bin/linker
+ // b000a000-b0015000 rw-p 00000000 00:00 0
+ // bee35000-bee56000 rw-p 00000000 00:00 0 [stack]
+ // ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
+
+ for (size_t i = 0; i < maps.size(); i++) {
+ size_t remaining = maps.size() - i;
+ if (remaining < 8+1+8) { // 00008000-0001f000
+ LOG(FATAL) << "Failed to parse at pos " << i << "\n" << maps;
+ }
+ std::string start_str = maps.substr(i, 8);
+ std::string end_str = maps.substr(i+1+8, 8);
+ uint32_t start = ParseHex(start_str);
+ uint32_t end = ParseHex(end_str);
+ CHECK(!(base >= start && base < end)
+ && !(limit >= start && limit < end)
+ && !(base <= start && limit > end))
+ << StringPrintf("Requested region %08x-%08x overlaps with existing map %08x-%08x\n",
+ base, limit, start, end)
+ << maps;
+ i += 8+1+8;
+ i = maps.find('\n', i);
+ CHECK(i != std::string::npos) << "Failed to find newline from pos " << i << "\n" << maps;
+ }
+#endif
+}
+
+MemMap* 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);
+ CheckMapRequest(addr, page_aligned_size);
+ 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(actual, length, actual, page_aligned_size);
+}
+
+MemMap* 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_NE(0, flags & (MAP_SHARED | 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 = RoundUp(length + page_offset, kPageSize);
+ CheckMapRequest(addr, page_aligned_size);
+ 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(actual + page_offset, length, actual, page_aligned_size);
+}
+
+MemMap::~MemMap() {
+ if (base_addr_ == NULL && base_length_ == 0) {
+ return;
+ }
+ int result = munmap(base_addr_, base_length_);
+ base_addr_ = NULL;
+ base_length_ = 0;
+ if (result == -1) {
+ PLOG(FATAL) << "munmap failed";
+ }
+}
+
+MemMap::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);
+};
+
+} // namespace art
diff --git a/src/mem_map.h b/src/mem_map.h
index f44939c..3c73613 100644
--- a/src/mem_map.h
+++ b/src/mem_map.h
@@ -17,9 +17,10 @@
#ifndef ART_SRC_MEM_MAP_H_
#define ART_SRC_MEM_MAP_H_
-#include <sys/mman.h>
+#include <stddef.h>
+#include <sys/types.h>
-#include "utils.h"
+#include "globals.h"
namespace art {
@@ -37,22 +38,7 @@
// 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* 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(actual, length, actual, page_aligned_size);
- }
+ static MemMap* Map(byte* addr, size_t length, int prot);
// Map part of a file, taking care of non-page aligned offsets. The
// "start" offset is absolute, not relative.
@@ -67,44 +53,10 @@
// 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 = 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(actual + page_offset, length, actual, page_aligned_size);
- }
+ static MemMap* Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start);
- ~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;
- }
+ // Releases the memory mapping
+ ~MemMap();
byte* GetAddress() const {
return addr_;
@@ -119,13 +71,7 @@
}
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);
- };
+ MemMap(byte* addr, size_t length, void* base_addr, size_t base_length);
byte* addr_; // start of data
size_t length_; // length of data
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 7578fb1..52cddb5 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -3,6 +3,8 @@
#include <stdio.h>
#include <stdlib.h>
+#include <fstream>
+#include <iostream>
#include <string>
#include <vector>
@@ -45,6 +47,10 @@
" the generated image to match the target file system layout.\n"
" Example: --strip-prefix=out/target/product/crespo\n"
"\n");
+ fprintf(stderr,
+ " --output=<file> may be used to send the output to a file.\n"
+ " Example: --output=/tmp/oatdump.txt\n"
+ "\n");
exit(EXIT_FAILURE);
}
@@ -52,15 +58,32 @@
"kJniStubArray",
};
-struct OatDump {
- const Space* dump_space;
+class OatDump {
- bool InDumpSpace(const Object* object) {
- DCHECK(dump_space != NULL);
- const byte* o = reinterpret_cast<const byte*>(object);
- return (o >= dump_space->GetBase() && o < dump_space->GetLimit());
+ public:
+ static void Dump(std::ostream& os, Space& image_space, const ImageHeader& image_header) {
+ os << "MAGIC:\n";
+ os << image_header.GetMagic() << "\n\n";
+
+ os << "ROOTS:\n";
+ for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
+ ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
+ os << StringPrintf("%s: %p\n",
+ image_roots_descriptions_[i], image_header.GetImageRoot(image_root));
+ }
+ os << "\n";
+
+ os << "OBJECTS:\n" << std::flush;
+ OatDump state(image_space, os);
+ HeapBitmap* heap_bitmap = Heap::GetLiveBits();
+ DCHECK(heap_bitmap != NULL);
+ heap_bitmap->Walk(OatDump::Callback, &state);
}
+ private:
+
+ OatDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space_), os_(os) {}
+
static void Callback(Object* obj, void* arg) {
DCHECK(obj != NULL);
DCHECK(arg != NULL);
@@ -106,8 +129,15 @@
}
}
}
- std::cout << summary;
+ state->os_ << summary << std::flush;
}
+
+ bool InDumpSpace(const Object* object) {
+ const byte* o = reinterpret_cast<const byte*>(object);
+ return (o >= dump_space_.GetBase() && o < dump_space_.GetLimit());
+ }
+ const Space& dump_space_;
+ std::ostream& os_;
};
int oatdump(int argc, char** argv) {
@@ -125,6 +155,8 @@
const char* boot_image_filename = NULL;
std::vector<const char*> boot_dex_filenames;
std::string strip_location_prefix;
+ std::ostream* os = &std::cout;
+ UniquePtr<std::ofstream> out;
for (int i = 0; i < argc; i++) {
const StringPiece option(argv[i]);
@@ -138,6 +170,14 @@
boot_dex_filenames.push_back(option.substr(strlen("--boot-dex-file=")).data());
} else if (option.starts_with("--strip-prefix=")) {
strip_location_prefix = option.substr(strlen("--strip-prefix=")).data();
+ } else if (option.starts_with("--output=")) {
+ const char* filename = option.substr(strlen("--output=")).data();
+ out.reset(new std::ofstream(filename));
+ if (!out->good()) {
+ fprintf(stderr, "failed to open output filename %s\n", filename);
+ usage();
+ }
+ os = out.get();
} else {
fprintf(stderr, "unknown argument %s\n", option.data());
usage();
@@ -202,24 +242,7 @@
fprintf(stderr, "invalid image header %s\n", image_filename);
return EXIT_FAILURE;
}
-
- printf("MAGIC:\n");
- printf("%s\n\n", image_header.GetMagic());
-
- printf("ROOTS:\n");
- for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
- ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
- printf("%s: %p\n", image_roots_descriptions_[i], image_header.GetImageRoot(image_root));
- }
- printf("\n");
-
- printf("OBJECTS:\n");
- OatDump state;
- state.dump_space = image_space;
- HeapBitmap* heap_bitmap = Heap::GetLiveBits();
- DCHECK(heap_bitmap != NULL);
- heap_bitmap->Walk(OatDump::Callback, &state);
-
+ OatDump::Dump(*os, *image_space, image_header);
return EXIT_SUCCESS;
}
diff --git a/src/object.cc b/src/object.cc
index 756b8a7..40bc2e2 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -332,7 +332,7 @@
}
Class* Method::GetReturnType() const {
- DCHECK(GetDeclaringClass()->IsResolved());
+ DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
// Short-cut
Class* result = GetDexCacheResolvedTypes()->Get(GetReturnTypeIdx());
if (result == NULL) {
diff --git a/src/object.h b/src/object.h
index 2e3a791..eb11be7 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1536,7 +1536,7 @@
}
uint32_t GetSuperClassTypeIdx() const {
- DCHECK(IsIdxLoaded());
+ DCHECK(IsIdxLoaded() || IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_),
false);
}
@@ -1567,7 +1567,7 @@
void SetDexCache(DexCache* new_dex_cache);
ObjectArray<Method>* GetDirectMethods() const {
- DCHECK(IsLoaded());
+ DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false);
}
@@ -1597,7 +1597,7 @@
}
ObjectArray<Method>* GetVirtualMethods() const {
- DCHECK(IsLoaded());
+ DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), false);
}
@@ -1616,12 +1616,12 @@
}
Method* GetVirtualMethod(uint32_t i) const {
- DCHECK(IsResolved());
+ DCHECK(IsResolved() || IsErroneous());
return GetVirtualMethods()->Get(i);
}
Method* GetVirtualMethodDuringLinking(uint32_t i) const {
- DCHECK(IsLoaded());
+ DCHECK(IsLoaded() || IsErroneous());
return GetVirtualMethods()->Get(i);
}
@@ -1633,13 +1633,13 @@
}
ObjectArray<Method>* GetVTable() const {
- DCHECK(IsResolved());
+ DCHECK(IsResolved() || IsErroneous());
return GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false);
}
ObjectArray<Method>* GetVTableDuringLinking() const {
- DCHECK(IsLoaded());
+ DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Method>*>(
OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false);
}
@@ -1690,14 +1690,14 @@
const StringPiece& signature);
size_t NumInterfaces() const {
- CHECK(IsIdxLoaded()); // used during loading
+ CHECK(IsIdxLoaded() || IsErroneous()); // used during loading
ObjectArray<Class>* interfaces = GetFieldObject<ObjectArray<Class>*>(
OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
return (interfaces != NULL) ? interfaces->GetLength() : 0;
}
IntArray* GetInterfacesTypeIdx() const {
- CHECK(IsIdxLoaded());
+ CHECK(IsIdxLoaded() || IsErroneous());
return GetFieldObject<IntArray*>(
OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_), false);
}
@@ -1705,7 +1705,7 @@
void SetInterfacesTypeIdx(IntArray* new_interfaces_idx);
ObjectArray<Class>* GetInterfaces() const {
- CHECK(IsLoaded());
+ CHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Class>*>(
OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
}
@@ -1739,7 +1739,7 @@
}
ObjectArray<InterfaceEntry>* GetIfTable() const {
- DCHECK(IsResolved());
+ DCHECK(IsResolved() || IsErroneous());
return GetFieldObject<ObjectArray<InterfaceEntry>*>(
OFFSET_OF_OBJECT_MEMBER(Class, iftable_), false);
}
@@ -1750,7 +1750,7 @@
// Get instance fields
ObjectArray<Field>* GetIFields() const {
- DCHECK(IsLoaded());
+ DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Field>*>(
OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
}
@@ -1779,14 +1779,14 @@
// Returns the number of instance fields containing reference types.
size_t NumReferenceInstanceFields() const {
- DCHECK(IsResolved());
+ DCHECK(IsResolved() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
}
size_t NumReferenceInstanceFieldsDuringLinking() const {
- DCHECK(IsLoaded());
+ DCHECK(IsLoaded() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
@@ -1799,7 +1799,7 @@
}
uint32_t GetReferenceInstanceOffsets() const {
- DCHECK(IsResolved());
+ DCHECK(IsResolved() || IsErroneous());
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_), false);
}
@@ -1813,14 +1813,14 @@
// Returns the number of static fields containing reference types.
size_t NumReferenceStaticFields() const {
- DCHECK(IsResolved());
+ DCHECK(IsResolved() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
}
size_t NumReferenceStaticFieldsDuringLinking() const {
- DCHECK(IsLoaded());
+ DCHECK(IsLoaded() || IsErroneous());
DCHECK(sizeof(size_t) == sizeof(int32_t));
return GetField32(
OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
@@ -1833,7 +1833,7 @@
}
ObjectArray<Field>* GetSFields() const {
- DCHECK(IsLoaded());
+ DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<ObjectArray<Field>*>(
OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);
}
@@ -1877,7 +1877,7 @@
Field* FindDeclaredStaticField(const StringPiece& name, Class* type);
pid_t GetClinitThreadId() const {
- DCHECK(IsIdxLoaded());
+ DCHECK(IsIdxLoaded() || IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), false);
}
@@ -2113,7 +2113,7 @@
}
inline void Field::SetOffset(MemberOffset num_bytes) {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
Class* type = GetTypeDuringLinking();
if (type != NULL && (type->IsPrimitiveDouble() || type->IsPrimitiveLong())) {
DCHECK(IsAligned(num_bytes.Uint32Value(), 8));
@@ -2126,7 +2126,7 @@
Class* result = GetFieldObject<Class*>(
OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_), false);
DCHECK(result != NULL);
- DCHECK(result->IsLoaded());
+ DCHECK(result->IsLoaded() || result->IsErroneous());
return result;
}
@@ -2140,7 +2140,7 @@
GetFieldObject<Class*>(
OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_), false);
DCHECK(result != NULL);
- DCHECK(result->IsLoaded());
+ DCHECK(result->IsLoaded() || result->IsErroneous());
return result;
}
@@ -2150,7 +2150,7 @@
}
inline uint32_t Method::GetReturnTypeIdx() const {
- DCHECK(GetDeclaringClass()->IsResolved());
+ DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, java_return_type_idx_),
false);
}
@@ -2442,7 +2442,7 @@
};
inline const String* Field::GetName() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
String* result =
GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Field, name_), false);
DCHECK(result != NULL);
@@ -2455,29 +2455,29 @@
}
inline uint32_t Field::GetAccessFlags() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_), false);
}
inline uint32_t Field::GetTypeIdx() const {
- DCHECK(GetDeclaringClass()->IsIdxLoaded());
+ DCHECK(GetDeclaringClass()->IsIdxLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, type_idx_), false);
}
inline MemberOffset Field::GetOffset() const {
- DCHECK(GetDeclaringClass()->IsResolved());
+ DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
return MemberOffset(
GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
}
inline MemberOffset Field::GetOffsetDuringLinking() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return MemberOffset(
GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
}
inline const String* Method::GetName() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
const String* result =
GetFieldObject<const String*>(
OFFSET_OF_OBJECT_MEMBER(Method, name_), false);
@@ -2512,7 +2512,7 @@
}
inline String* Method::GetShorty() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetFieldObject<String*>(
OFFSET_OF_OBJECT_MEMBER(Method, shorty_), false);
}
@@ -2525,7 +2525,7 @@
}
inline const String* Method::GetSignature() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
const String* result =
GetFieldObject<const String*>(
OFFSET_OF_OBJECT_MEMBER(Method, signature_), false);
@@ -2541,7 +2541,8 @@
inline uint32_t Class::GetAccessFlags() const {
// Check class is loaded or this is java.lang.String that has a
// circularity issue during loading the names of its members
- DCHECK(IsLoaded() || this == String::GetJavaLangString() ||
+ DCHECK(IsLoaded() || IsErroneous() ||
+ this == String::GetJavaLangString() ||
this == Field::GetJavaLangReflectField() ||
this == Method::GetJavaLangReflectMethod()) << PrettyClass(this);
return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false);
@@ -2556,7 +2557,7 @@
}
inline String* Class::GetSourceFile() const {
- DCHECK(IsLoaded());
+ DCHECK(IsLoaded() || IsErroneous());
return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Class, source_file_), false);
}
@@ -2565,32 +2566,32 @@
}
inline uint32_t Method::GetAccessFlags() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), false);
}
inline uint16_t Method::GetMethodIndex() const {
- DCHECK(GetDeclaringClass()->IsResolved());
+ DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_index_), false);
}
inline uint16_t Method::NumRegisters() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_), false);
}
inline uint16_t Method::NumIns() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_), false);
}
inline uint16_t Method::NumOuts() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_), false);
}
inline uint32_t Method::GetProtoIdx() const {
- DCHECK(GetDeclaringClass()->IsLoaded());
+ DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, proto_idx_), false);
}
diff --git a/src/object_bitmap.cc b/src/object_bitmap.cc
index 4b4c5ee..06d86d6 100644
--- a/src/object_bitmap.cc
+++ b/src/object_bitmap.cc
@@ -18,6 +18,7 @@
#include "UniquePtr.h"
#include "logging.h"
+#include "utils.h"
namespace art {
diff --git a/src/runtime.cc b/src/runtime.cc
index 0990851..e6bd6e2 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -300,8 +300,9 @@
} else {
if (!ignore_unrecognized) {
// TODO: print usage via vfprintf
- LOG(FATAL) << "Unrecognized option " << option;
- return NULL;
+ LOG(ERROR) << "Unrecognized option " << option;
+ // TODO: this should exit, but for now tolerate unknown options
+ //return NULL;
}
}
}
@@ -321,7 +322,9 @@
if (parsed->boot_class_path_.empty()) {
if (parsed->boot_class_path_string_ == NULL) {
const char* BOOTCLASSPATH = getenv("BOOTCLASSPATH");
- parsed->boot_class_path_string_ = BOOTCLASSPATH;
+ if (BOOTCLASSPATH != NULL) {
+ parsed->boot_class_path_string_ = BOOTCLASSPATH;
+ }
}
CreateClassPath(parsed->boot_class_path_string_, parsed->boot_class_path_);
}