Version 3.25.6 (based on bleeding_edge revision r19746)
Replace the recursion in PropagateMinusZeroChecks() with a loop and a worklist (issue 3204).
Reland "Enable Object.observe by default" (issue 2409).
Enable Object.observe by default (issue 2409).
AllocationTracker now maintains a map from address range to stack trace that allocated the range. When snapshot is generated the map is used to find construction stack trace for an object using its address (Chromium issue 277984).
Introduce Runtime_GetAllScopesDetails to get all scopes at once for a frame (Chromium issue 340285).
Reduce heavy runtime calls from debug mirrors (Chromium issue 340285).
Check and clear date cache in DateCurrentTime, DateLocalTimezone and getTimezoneOffset (Chromium issue 142141).
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@19747 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/allocation-tracker.cc b/src/allocation-tracker.cc
index 83e1bb4..a9103a8 100644
--- a/src/allocation-tracker.cc
+++ b/src/allocation-tracker.cc
@@ -36,9 +36,9 @@
namespace internal {
AllocationTraceNode::AllocationTraceNode(
- AllocationTraceTree* tree, SnapshotObjectId shared_function_info_id)
+ AllocationTraceTree* tree, unsigned function_info_index)
: tree_(tree),
- function_id_(shared_function_info_id),
+ function_info_index_(function_info_index),
total_size_(0),
allocation_count_(0),
id_(tree->next_node_id()) {
@@ -50,19 +50,21 @@
}
-AllocationTraceNode* AllocationTraceNode::FindChild(SnapshotObjectId id) {
+AllocationTraceNode* AllocationTraceNode::FindChild(
+ unsigned function_info_index) {
for (int i = 0; i < children_.length(); i++) {
AllocationTraceNode* node = children_[i];
- if (node->function_id() == id) return node;
+ if (node->function_info_index() == function_info_index) return node;
}
return NULL;
}
-AllocationTraceNode* AllocationTraceNode::FindOrAddChild(SnapshotObjectId id) {
- AllocationTraceNode* child = FindChild(id);
+AllocationTraceNode* AllocationTraceNode::FindOrAddChild(
+ unsigned function_info_index) {
+ AllocationTraceNode* child = FindChild(function_info_index);
if (child == NULL) {
- child = new AllocationTraceNode(tree_, id);
+ child = new AllocationTraceNode(tree_, function_info_index);
children_.Add(child);
}
return child;
@@ -78,17 +80,11 @@
void AllocationTraceNode::Print(int indent, AllocationTracker* tracker) {
OS::Print("%10u %10u %*c", total_size_, allocation_count_, indent, ' ');
if (tracker != NULL) {
- const char* name = "<unknown function>";
- if (function_id_ != 0) {
- AllocationTracker::FunctionInfo* info =
- tracker->GetFunctionInfo(function_id_);
- if (info != NULL) {
- name = info->name;
- }
- }
- OS::Print("%s #%u", name, id_);
+ AllocationTracker::FunctionInfo* info =
+ tracker->function_info_list()[function_info_index_];
+ OS::Print("%s #%u", info->name, id_);
} else {
- OS::Print("%u #%u", function_id_, id_);
+ OS::Print("%u #%u", function_info_index_, id_);
}
OS::Print("\n");
indent += 2;
@@ -109,9 +105,9 @@
AllocationTraceNode* AllocationTraceTree::AddPathFromEnd(
- const Vector<SnapshotObjectId>& path) {
+ const Vector<unsigned>& path) {
AllocationTraceNode* node = root();
- for (SnapshotObjectId* entry = path.start() + path.length() - 1;
+ for (unsigned* entry = path.start() + path.length() - 1;
entry != path.start() - 1;
--entry) {
node = node->FindOrAddChild(*entry);
@@ -126,6 +122,7 @@
root()->Print(0, tracker);
}
+
void AllocationTracker::DeleteUnresolvedLocation(
UnresolvedLocation** location) {
delete *location;
@@ -134,6 +131,7 @@
AllocationTracker::FunctionInfo::FunctionInfo()
: name(""),
+ function_id(0),
script_name(""),
script_id(0),
line(-1),
@@ -141,26 +139,103 @@
}
+void AddressToTraceMap::AddRange(Address start, int size,
+ unsigned trace_node_id) {
+ Address end = start + size;
+ RemoveRange(start, end);
+
+ RangeStack new_range(start, trace_node_id);
+ ranges_.insert(RangeMap::value_type(end, new_range));
+}
+
+
+unsigned AddressToTraceMap::GetTraceNodeId(Address addr) {
+ RangeMap::const_iterator it = ranges_.upper_bound(addr);
+ if (it == ranges_.end()) return 0;
+ if (it->second.start <= addr) {
+ return it->second.trace_node_id;
+ }
+ return 0;
+}
+
+
+void AddressToTraceMap::MoveObject(Address from, Address to, int size) {
+ unsigned trace_node_id = GetTraceNodeId(from);
+ if (trace_node_id == 0) return;
+ RemoveRange(from, from + size);
+ AddRange(to, size, trace_node_id);
+}
+
+
+void AddressToTraceMap::Clear() {
+ ranges_.clear();
+}
+
+
+void AddressToTraceMap::Print() {
+ PrintF("[AddressToTraceMap (%" V8PRIuPTR "): \n", ranges_.size());
+ for (RangeMap::iterator it = ranges_.begin(); it != ranges_.end(); ++it) {
+ PrintF("[%p - %p] => %u\n", it->second.start, it->first,
+ it->second.trace_node_id);
+ }
+ PrintF("]\n");
+}
+
+
+void AddressToTraceMap::RemoveRange(Address start, Address end) {
+ RangeMap::iterator it = ranges_.upper_bound(start);
+ if (it == ranges_.end()) return;
+
+ RangeStack prev_range(0, 0);
+
+ RangeMap::iterator to_remove_begin = it;
+ if (it->second.start < start) {
+ prev_range = it->second;
+ }
+ do {
+ if (it->first > end) {
+ if (it->second.start < end) {
+ it->second.start = end;
+ }
+ break;
+ }
+ ++it;
+ }
+ while (it != ranges_.end());
+
+ ranges_.erase(to_remove_begin, it);
+
+ if (prev_range.start != 0) {
+ ranges_.insert(RangeMap::value_type(start, prev_range));
+ }
+}
+
+
static bool AddressesMatch(void* key1, void* key2) {
return key1 == key2;
}
+void AllocationTracker::DeleteFunctionInfo(FunctionInfo** info) {
+ delete *info;
+}
+
+
AllocationTracker::AllocationTracker(
HeapObjectsMap* ids, StringsStorage* names)
: ids_(ids),
names_(names),
- id_to_function_info_(AddressesMatch) {
+ id_to_function_info_index_(AddressesMatch),
+ info_index_for_other_state_(0) {
+ FunctionInfo* info = new FunctionInfo();
+ info->name = "(root)";
+ function_info_list_.Add(info);
}
AllocationTracker::~AllocationTracker() {
unresolved_locations_.Iterate(DeleteUnresolvedLocation);
- for (HashMap::Entry* p = id_to_function_info_.Start();
- p != NULL;
- p = id_to_function_info_.Next(p)) {
- delete reinterpret_cast<AllocationTracker::FunctionInfo* >(p->value);
- }
+ function_info_list_.Iterate(&DeleteFunctionInfo);
}
@@ -193,13 +268,20 @@
SharedFunctionInfo* shared = frame->function()->shared();
SnapshotObjectId id = ids_->FindOrAddEntry(
shared->address(), shared->Size(), false);
- allocation_trace_buffer_[length++] = id;
- AddFunctionInfo(shared, id);
+ allocation_trace_buffer_[length++] = AddFunctionInfo(shared, id);
it.Advance();
}
+ if (length == 0) {
+ unsigned index = functionInfoIndexForVMState(isolate->current_vm_state());
+ if (index != 0) {
+ allocation_trace_buffer_[length++] = index;
+ }
+ }
AllocationTraceNode* top_node = trace_tree_.AddPathFromEnd(
- Vector<SnapshotObjectId>(allocation_trace_buffer_, length));
+ Vector<unsigned>(allocation_trace_buffer_, length));
top_node->AddAllocation(size);
+
+ address_to_trace_.AddRange(addr, size, top_node->id());
}
@@ -209,24 +291,14 @@
}
-AllocationTracker::FunctionInfo* AllocationTracker::GetFunctionInfo(
- SnapshotObjectId id) {
- HashMap::Entry* entry = id_to_function_info_.Lookup(
- reinterpret_cast<void*>(id), SnapshotObjectIdHash(id), false);
- if (entry == NULL) {
- return NULL;
- }
- return reinterpret_cast<FunctionInfo*>(entry->value);
-}
-
-
-void AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared,
- SnapshotObjectId id) {
- HashMap::Entry* entry = id_to_function_info_.Lookup(
+unsigned AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared,
+ SnapshotObjectId id) {
+ HashMap::Entry* entry = id_to_function_info_index_.Lookup(
reinterpret_cast<void*>(id), SnapshotObjectIdHash(id), true);
if (entry->value == NULL) {
FunctionInfo* info = new FunctionInfo();
info->name = names_->GetFunctionName(shared->DebugName());
+ info->function_id = id;
if (shared->script()->IsScript()) {
Script* script = Script::cast(shared->script());
if (script->name()->IsName()) {
@@ -241,8 +313,22 @@
shared->start_position(),
info));
}
- entry->value = info;
+ entry->value = reinterpret_cast<void*>(function_info_list_.length());
+ function_info_list_.Add(info);
}
+ return static_cast<unsigned>(reinterpret_cast<intptr_t>((entry->value)));
+}
+
+
+unsigned AllocationTracker::functionInfoIndexForVMState(StateTag state) {
+ if (state != OTHER) return 0;
+ if (info_index_for_other_state_ == 0) {
+ FunctionInfo* info = new FunctionInfo();
+ info->name = "(V8 API)";
+ info_index_for_other_state_ = function_info_list_.length();
+ function_info_list_.Add(info);
+ }
+ return info_index_for_other_state_;
}