Merge "Let dalvikvm default based on persist.sys.dalvik.vm.lib" into dalvik-dev
diff --git a/src/compiler/dex/mir_dataflow.cc b/src/compiler/dex/mir_dataflow.cc
index 3b2c1a6..c3680d6 100644
--- a/src/compiler/dex/mir_dataflow.cc
+++ b/src/compiler/dex/mir_dataflow.cc
@@ -373,7 +373,7 @@
DF_FORMAT_35C | DF_UMS,
// 72 INVOKE_INTERFACE {vD, vE, vF, vG, vA}
- DF_FORMAT_35C | DF_UMS,
+ DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
// 73 UNUSED_73
DF_NOP,
@@ -391,7 +391,7 @@
DF_FORMAT_3RC | DF_UMS,
// 78 INVOKE_INTERFACE_RANGE {vCCCC .. vNNNN}
- DF_FORMAT_3RC | DF_UMS,
+ DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
// 79 UNUSED_79
DF_NOP,
diff --git a/src/compiler/sea_ir/instruction_tools.cc b/src/compiler/sea_ir/instruction_tools.cc
index 68be589..5433591 100644
--- a/src/compiler/sea_ir/instruction_tools.cc
+++ b/src/compiler/sea_ir/instruction_tools.cc
@@ -369,7 +369,7 @@
DF_FORMAT_35C | DF_UMS,
// 72 INVOKE_INTERFACE {vD, vE, vF, vG, vA}
- DF_FORMAT_35C | DF_UMS,
+ DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS,
// 73 UNUSED_73
DF_NOP,
@@ -387,7 +387,7 @@
DF_FORMAT_3RC | DF_UMS,
// 78 INVOKE_INTERFACE_RANGE {vCCCC .. vNNNN}
- DF_FORMAT_3RC | DF_UMS,
+ DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS,
// 79 UNUSED_79
DF_NOP,
diff --git a/src/debugger.cc b/src/debugger.cc
index f2a10f0..4e89838 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -20,6 +20,7 @@
#include <set>
+#include "cutils/properties.h"
#include "class_linker.h"
#include "class_linker-inl.h"
#include "dex_file-inl.h"
@@ -53,7 +54,7 @@
namespace art {
static const size_t kMaxAllocRecordStackDepth = 16; // Max 255.
-static const size_t kNumAllocRecords = 512; // Must be a power of 2.
+static const size_t kDefaultNumAllocRecords = 64*1024; // Must be a power of 2.
struct AllocRecordStackTraceElement {
mirror::AbstractMethod* method;
@@ -183,6 +184,7 @@
// Recent allocation tracking.
static Mutex gAllocTrackerLock DEFAULT_MUTEX_ACQUIRED_AFTER ("AllocTracker lock");
AllocRecord* Dbg::recent_allocation_records_ PT_GUARDED_BY(gAllocTrackerLock) = NULL; // TODO: CircularBuffer<AllocRecord>
+static size_t gAllocRecordMax GUARDED_BY(gAllocTrackerLock) = 0;
static size_t gAllocRecordHead GUARDED_BY(gAllocTrackerLock) = 0;
static size_t gAllocRecordCount GUARDED_BY(gAllocTrackerLock) = 0;
@@ -3437,15 +3439,38 @@
Dbg::DdmSendChunk(native ? CHUNK_TYPE("NHEN") : CHUNK_TYPE("HPEN"), sizeof(heap_id), heap_id);
}
+static size_t GetAllocTrackerMax() {
+#ifdef HAVE_ANDROID_OS
+ // Check whether there's a system property overriding the number of records.
+ const char* propertyName = "dalvik.vm.allocTrackerMax";
+ char allocRecordMaxString[PROPERTY_VALUE_MAX];
+ if (property_get(propertyName, allocRecordMaxString, "") > 0) {
+ char* end;
+ size_t value = strtoul(allocRecordMaxString, &end, 10);
+ if (*end != '\0') {
+ ALOGE("Ignoring %s '%s' --- invalid", propertyName, allocRecordMaxString);
+ return kDefaultNumAllocRecords;
+ }
+ if (!IsPowerOfTwo(value)) {
+ ALOGE("Ignoring %s '%s' --- not power of two", propertyName, allocRecordMaxString);
+ return kDefaultNumAllocRecords;
+ }
+ return value;
+ }
+#endif
+ return kDefaultNumAllocRecords;
+}
+
void Dbg::SetAllocTrackingEnabled(bool enabled) {
MutexLock mu(Thread::Current(), gAllocTrackerLock);
if (enabled) {
if (recent_allocation_records_ == NULL) {
- LOG(INFO) << "Enabling alloc tracker (" << kNumAllocRecords << " entries, "
- << kMaxAllocRecordStackDepth << " frames --> "
- << (sizeof(AllocRecord) * kNumAllocRecords) << " bytes)";
+ gAllocRecordMax = GetAllocTrackerMax();
+ LOG(INFO) << "Enabling alloc tracker (" << gAllocRecordMax << " entries of "
+ << kMaxAllocRecordStackDepth << " frames, taking "
+ << PrettySize(sizeof(AllocRecord) * gAllocRecordMax) << ")";
gAllocRecordHead = gAllocRecordCount = 0;
- recent_allocation_records_ = new AllocRecord[kNumAllocRecords];
+ recent_allocation_records_ = new AllocRecord[gAllocRecordMax];
CHECK(recent_allocation_records_ != NULL);
}
} else {
@@ -3496,7 +3521,7 @@
}
// Advance and clip.
- if (++gAllocRecordHead == kNumAllocRecords) {
+ if (++gAllocRecordHead == gAllocRecordMax) {
gAllocRecordHead = 0;
}
@@ -3510,7 +3535,7 @@
AllocRecordStackVisitor visitor(self, record);
visitor.WalkStack();
- if (gAllocRecordCount < kNumAllocRecords) {
+ if (gAllocRecordCount < gAllocRecordMax) {
++gAllocRecordCount;
}
}
@@ -3522,9 +3547,9 @@
// from it.
//
// We need to handle underflow in our circular buffer, so we add
-// kNumAllocRecords and then mask it back down.
+// gAllocRecordMax and then mask it back down.
static inline int HeadIndex() EXCLUSIVE_LOCKS_REQUIRED(gAllocTrackerLock) {
- return (gAllocRecordHead+1 + kNumAllocRecords - gAllocRecordCount) & (kNumAllocRecords-1);
+ return (gAllocRecordHead+1 + gAllocRecordMax - gAllocRecordCount) & (gAllocRecordMax-1);
}
void Dbg::DumpRecentAllocations() {
@@ -3560,7 +3585,7 @@
usleep(40000);
}
- i = (i + 1) & (kNumAllocRecords-1);
+ i = (i + 1) & (gAllocRecordMax-1);
}
}
@@ -3632,7 +3657,7 @@
* followed by UTF-16 data.
*
* We send up 16-bit unsigned indexes into string tables. In theory there
- * can be (kMaxAllocRecordStackDepth * kNumAllocRecords) unique strings in
+ * can be (kMaxAllocRecordStackDepth * gAllocRecordMax) unique strings in
* each table, but in practice there should be far fewer.
*
* The chief reason for using a string table here is to keep the size of
@@ -3650,111 +3675,111 @@
}
Thread* self = Thread::Current();
- MutexLock mu(self, gAllocTrackerLock);
-
- //
- // Part 1: generate string tables.
- //
- StringTable class_names;
- StringTable method_names;
- StringTable filenames;
-
- int count = gAllocRecordCount;
- int idx = HeadIndex();
- while (count--) {
- AllocRecord* record = &recent_allocation_records_[idx];
-
- class_names.Add(ClassHelper(record->type).GetDescriptor());
-
- MethodHelper mh;
- for (size_t i = 0; i < kMaxAllocRecordStackDepth; i++) {
- mirror::AbstractMethod* m = record->stack[i].method;
- if (m != NULL) {
- mh.ChangeMethod(m);
- class_names.Add(mh.GetDeclaringClassDescriptor());
- method_names.Add(mh.GetName());
- filenames.Add(mh.GetDeclaringClassSourceFile());
- }
- }
-
- idx = (idx + 1) & (kNumAllocRecords-1);
- }
-
- LOG(INFO) << "allocation records: " << gAllocRecordCount;
-
- //
- // Part 2: allocate a buffer and generate the output.
- //
std::vector<uint8_t> bytes;
+ {
+ MutexLock mu(self, gAllocTrackerLock);
+ //
+ // Part 1: generate string tables.
+ //
+ StringTable class_names;
+ StringTable method_names;
+ StringTable filenames;
- // (1b) message header len (to allow future expansion); includes itself
- // (1b) entry header len
- // (1b) stack frame len
- const int kMessageHeaderLen = 15;
- const int kEntryHeaderLen = 9;
- const int kStackFrameLen = 8;
- JDWP::Append1BE(bytes, kMessageHeaderLen);
- JDWP::Append1BE(bytes, kEntryHeaderLen);
- JDWP::Append1BE(bytes, kStackFrameLen);
+ int count = gAllocRecordCount;
+ int idx = HeadIndex();
+ while (count--) {
+ AllocRecord* record = &recent_allocation_records_[idx];
- // (2b) number of entries
- // (4b) offset to string table from start of message
- // (2b) number of class name strings
- // (2b) number of method name strings
- // (2b) number of source file name strings
- JDWP::Append2BE(bytes, gAllocRecordCount);
- size_t string_table_offset = bytes.size();
- JDWP::Append4BE(bytes, 0); // We'll patch this later...
- JDWP::Append2BE(bytes, class_names.Size());
- JDWP::Append2BE(bytes, method_names.Size());
- JDWP::Append2BE(bytes, filenames.Size());
+ class_names.Add(ClassHelper(record->type).GetDescriptor());
- count = gAllocRecordCount;
- idx = HeadIndex();
- ClassHelper kh;
- while (count--) {
- // For each entry:
- // (4b) total allocation size
- // (2b) thread id
- // (2b) allocated object's class name index
- // (1b) stack depth
- AllocRecord* record = &recent_allocation_records_[idx];
- size_t stack_depth = record->GetDepth();
- kh.ChangeClass(record->type);
- size_t allocated_object_class_name_index = class_names.IndexOf(kh.GetDescriptor());
- JDWP::Append4BE(bytes, record->byte_count);
- JDWP::Append2BE(bytes, record->thin_lock_id);
- JDWP::Append2BE(bytes, allocated_object_class_name_index);
- JDWP::Append1BE(bytes, stack_depth);
+ MethodHelper mh;
+ for (size_t i = 0; i < kMaxAllocRecordStackDepth; i++) {
+ mirror::AbstractMethod* m = record->stack[i].method;
+ if (m != NULL) {
+ mh.ChangeMethod(m);
+ class_names.Add(mh.GetDeclaringClassDescriptor());
+ method_names.Add(mh.GetName());
+ filenames.Add(mh.GetDeclaringClassSourceFile());
+ }
+ }
- MethodHelper mh;
- for (size_t stack_frame = 0; stack_frame < stack_depth; ++stack_frame) {
- // For each stack frame:
- // (2b) method's class name
- // (2b) method name
- // (2b) method source file
- // (2b) line number, clipped to 32767; -2 if native; -1 if no source
- mh.ChangeMethod(record->stack[stack_frame].method);
- size_t class_name_index = class_names.IndexOf(mh.GetDeclaringClassDescriptor());
- size_t method_name_index = method_names.IndexOf(mh.GetName());
- size_t file_name_index = filenames.IndexOf(mh.GetDeclaringClassSourceFile());
- JDWP::Append2BE(bytes, class_name_index);
- JDWP::Append2BE(bytes, method_name_index);
- JDWP::Append2BE(bytes, file_name_index);
- JDWP::Append2BE(bytes, record->stack[stack_frame].LineNumber());
+ idx = (idx + 1) & (gAllocRecordMax-1);
}
- idx = (idx + 1) & (kNumAllocRecords-1);
+ LOG(INFO) << "allocation records: " << gAllocRecordCount;
+
+ //
+ // Part 2: Generate the output and store it in the buffer.
+ //
+
+ // (1b) message header len (to allow future expansion); includes itself
+ // (1b) entry header len
+ // (1b) stack frame len
+ const int kMessageHeaderLen = 15;
+ const int kEntryHeaderLen = 9;
+ const int kStackFrameLen = 8;
+ JDWP::Append1BE(bytes, kMessageHeaderLen);
+ JDWP::Append1BE(bytes, kEntryHeaderLen);
+ JDWP::Append1BE(bytes, kStackFrameLen);
+
+ // (2b) number of entries
+ // (4b) offset to string table from start of message
+ // (2b) number of class name strings
+ // (2b) number of method name strings
+ // (2b) number of source file name strings
+ JDWP::Append2BE(bytes, gAllocRecordCount);
+ size_t string_table_offset = bytes.size();
+ JDWP::Append4BE(bytes, 0); // We'll patch this later...
+ JDWP::Append2BE(bytes, class_names.Size());
+ JDWP::Append2BE(bytes, method_names.Size());
+ JDWP::Append2BE(bytes, filenames.Size());
+
+ count = gAllocRecordCount;
+ idx = HeadIndex();
+ ClassHelper kh;
+ while (count--) {
+ // For each entry:
+ // (4b) total allocation size
+ // (2b) thread id
+ // (2b) allocated object's class name index
+ // (1b) stack depth
+ AllocRecord* record = &recent_allocation_records_[idx];
+ size_t stack_depth = record->GetDepth();
+ kh.ChangeClass(record->type);
+ size_t allocated_object_class_name_index = class_names.IndexOf(kh.GetDescriptor());
+ JDWP::Append4BE(bytes, record->byte_count);
+ JDWP::Append2BE(bytes, record->thin_lock_id);
+ JDWP::Append2BE(bytes, allocated_object_class_name_index);
+ JDWP::Append1BE(bytes, stack_depth);
+
+ MethodHelper mh;
+ for (size_t stack_frame = 0; stack_frame < stack_depth; ++stack_frame) {
+ // For each stack frame:
+ // (2b) method's class name
+ // (2b) method name
+ // (2b) method source file
+ // (2b) line number, clipped to 32767; -2 if native; -1 if no source
+ mh.ChangeMethod(record->stack[stack_frame].method);
+ size_t class_name_index = class_names.IndexOf(mh.GetDeclaringClassDescriptor());
+ size_t method_name_index = method_names.IndexOf(mh.GetName());
+ size_t file_name_index = filenames.IndexOf(mh.GetDeclaringClassSourceFile());
+ JDWP::Append2BE(bytes, class_name_index);
+ JDWP::Append2BE(bytes, method_name_index);
+ JDWP::Append2BE(bytes, file_name_index);
+ JDWP::Append2BE(bytes, record->stack[stack_frame].LineNumber());
+ }
+
+ idx = (idx + 1) & (gAllocRecordMax-1);
+ }
+
+ // (xb) class name strings
+ // (xb) method name strings
+ // (xb) source file strings
+ JDWP::Set4BE(&bytes[string_table_offset], bytes.size());
+ class_names.WriteTo(bytes);
+ method_names.WriteTo(bytes);
+ filenames.WriteTo(bytes);
}
-
- // (xb) class name strings
- // (xb) method name strings
- // (xb) source file strings
- JDWP::Set4BE(&bytes[string_table_offset], bytes.size());
- class_names.WriteTo(bytes);
- method_names.WriteTo(bytes);
- filenames.WriteTo(bytes);
-
JNIEnv* env = self->GetJniEnv();
jbyteArray result = env->NewByteArray(bytes.size());
if (result != NULL) {