Support ES6 Map and Set in heap profiler
Added special handling for Map and Set in the heap snapshot generator. Extracted common base type from JSMap/JSSet similar to JSWeakMap/JSWeakSet. After handling collection specific properties all collections are processed as regular JSObject to make sure all regular properties set on them are present in the heap snapshot. BUG=v8:3368 LOG=Y R=alph@chromium.org, rossberg@chromium.org Committed: https://code.google.com/p/v8/source/detail?r=22311 Review URL: https://codereview.chromium.org/373183002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22316 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
d9d66d02b4
commit
3994880715
@ -1097,11 +1097,16 @@ bool V8HeapExplorer::ExtractReferencesPass1(int entry, HeapObject* obj) {
|
|||||||
ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
|
ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
|
||||||
} else if (obj->IsJSArrayBuffer()) {
|
} else if (obj->IsJSArrayBuffer()) {
|
||||||
ExtractJSArrayBufferReferences(entry, JSArrayBuffer::cast(obj));
|
ExtractJSArrayBufferReferences(entry, JSArrayBuffer::cast(obj));
|
||||||
} else if (obj->IsJSWeakSet()) {
|
|
||||||
ExtractJSWeakCollectionReferences(entry, JSWeakSet::cast(obj));
|
|
||||||
} else if (obj->IsJSWeakMap()) {
|
|
||||||
ExtractJSWeakCollectionReferences(entry, JSWeakMap::cast(obj));
|
|
||||||
} else if (obj->IsJSObject()) {
|
} else if (obj->IsJSObject()) {
|
||||||
|
if (obj->IsJSWeakSet()) {
|
||||||
|
ExtractJSWeakCollectionReferences(entry, JSWeakSet::cast(obj));
|
||||||
|
} else if (obj->IsJSWeakMap()) {
|
||||||
|
ExtractJSWeakCollectionReferences(entry, JSWeakMap::cast(obj));
|
||||||
|
} else if (obj->IsJSSet()) {
|
||||||
|
ExtractJSCollectionReferences(entry, JSSet::cast(obj));
|
||||||
|
} else if (obj->IsJSMap()) {
|
||||||
|
ExtractJSCollectionReferences(entry, JSMap::cast(obj));
|
||||||
|
}
|
||||||
ExtractJSObjectReferences(entry, JSObject::cast(obj));
|
ExtractJSObjectReferences(entry, JSObject::cast(obj));
|
||||||
} else if (obj->IsString()) {
|
} else if (obj->IsString()) {
|
||||||
ExtractStringReferences(entry, String::cast(obj));
|
ExtractStringReferences(entry, String::cast(obj));
|
||||||
@ -1260,6 +1265,13 @@ void V8HeapExplorer::ExtractSymbolReferences(int entry, Symbol* symbol) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void V8HeapExplorer::ExtractJSCollectionReferences(int entry,
|
||||||
|
JSCollection* collection) {
|
||||||
|
SetInternalReference(collection, entry, "table", collection->table(),
|
||||||
|
JSCollection::kTableOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void V8HeapExplorer::ExtractJSWeakCollectionReferences(
|
void V8HeapExplorer::ExtractJSWeakCollectionReferences(
|
||||||
int entry, JSWeakCollection* collection) {
|
int entry, JSWeakCollection* collection) {
|
||||||
MarkAsWeakContainer(collection->table());
|
MarkAsWeakContainer(collection->table());
|
||||||
|
@ -370,6 +370,7 @@ class V8HeapExplorer : public HeapEntriesAllocator {
|
|||||||
void ExtractJSObjectReferences(int entry, JSObject* js_obj);
|
void ExtractJSObjectReferences(int entry, JSObject* js_obj);
|
||||||
void ExtractStringReferences(int entry, String* obj);
|
void ExtractStringReferences(int entry, String* obj);
|
||||||
void ExtractSymbolReferences(int entry, Symbol* symbol);
|
void ExtractSymbolReferences(int entry, Symbol* symbol);
|
||||||
|
void ExtractJSCollectionReferences(int entry, JSCollection* collection);
|
||||||
void ExtractJSWeakCollectionReferences(int entry,
|
void ExtractJSWeakCollectionReferences(int entry,
|
||||||
JSWeakCollection* collection);
|
JSWeakCollection* collection);
|
||||||
void ExtractContextReferences(int entry, Context* context);
|
void ExtractContextReferences(int entry, Context* context);
|
||||||
|
@ -6032,8 +6032,7 @@ void JSProxy::InitializeBody(int object_size, Object* value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ACCESSORS(JSSet, table, Object, kTableOffset)
|
ACCESSORS(JSCollection, table, Object, kTableOffset)
|
||||||
ACCESSORS(JSMap, table, Object, kTableOffset)
|
|
||||||
|
|
||||||
|
|
||||||
#define ORDERED_HASH_TABLE_ITERATOR_ACCESSORS(name, type, offset) \
|
#define ORDERED_HASH_TABLE_ITERATOR_ACCESSORS(name, type, offset) \
|
||||||
|
@ -44,8 +44,9 @@
|
|||||||
// - JSArrayBufferView
|
// - JSArrayBufferView
|
||||||
// - JSTypedArray
|
// - JSTypedArray
|
||||||
// - JSDataView
|
// - JSDataView
|
||||||
// - JSSet
|
// - JSCollection
|
||||||
// - JSMap
|
// - JSSet
|
||||||
|
// - JSMap
|
||||||
// - JSSetIterator
|
// - JSSetIterator
|
||||||
// - JSMapIterator
|
// - JSMapIterator
|
||||||
// - JSWeakCollection
|
// - JSWeakCollection
|
||||||
@ -10078,41 +10079,42 @@ class JSFunctionProxy: public JSProxy {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// The JSSet describes EcmaScript Harmony sets
|
class JSCollection : public JSObject {
|
||||||
class JSSet: public JSObject {
|
|
||||||
public:
|
public:
|
||||||
// [set]: the backing hash set containing keys.
|
// [table]: the backing hash table
|
||||||
DECL_ACCESSORS(table, Object)
|
DECL_ACCESSORS(table, Object)
|
||||||
|
|
||||||
|
static const int kTableOffset = JSObject::kHeaderSize;
|
||||||
|
static const int kSize = kTableOffset + kPointerSize;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DISALLOW_IMPLICIT_CONSTRUCTORS(JSCollection);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// The JSSet describes EcmaScript Harmony sets
|
||||||
|
class JSSet : public JSCollection {
|
||||||
|
public:
|
||||||
DECLARE_CAST(JSSet)
|
DECLARE_CAST(JSSet)
|
||||||
|
|
||||||
// Dispatched behavior.
|
// Dispatched behavior.
|
||||||
DECLARE_PRINTER(JSSet)
|
DECLARE_PRINTER(JSSet)
|
||||||
DECLARE_VERIFIER(JSSet)
|
DECLARE_VERIFIER(JSSet)
|
||||||
|
|
||||||
static const int kTableOffset = JSObject::kHeaderSize;
|
|
||||||
static const int kSize = kTableOffset + kPointerSize;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSSet);
|
DISALLOW_IMPLICIT_CONSTRUCTORS(JSSet);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// The JSMap describes EcmaScript Harmony maps
|
// The JSMap describes EcmaScript Harmony maps
|
||||||
class JSMap: public JSObject {
|
class JSMap : public JSCollection {
|
||||||
public:
|
public:
|
||||||
// [table]: the backing hash table mapping keys to values.
|
|
||||||
DECL_ACCESSORS(table, Object)
|
|
||||||
|
|
||||||
DECLARE_CAST(JSMap)
|
DECLARE_CAST(JSMap)
|
||||||
|
|
||||||
// Dispatched behavior.
|
// Dispatched behavior.
|
||||||
DECLARE_PRINTER(JSMap)
|
DECLARE_PRINTER(JSMap)
|
||||||
DECLARE_VERIFIER(JSMap)
|
DECLARE_VERIFIER(JSMap)
|
||||||
|
|
||||||
static const int kTableOffset = JSObject::kHeaderSize;
|
|
||||||
static const int kSize = kTableOffset + kPointerSize;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSMap);
|
DISALLOW_IMPLICIT_CONSTRUCTORS(JSMap);
|
||||||
};
|
};
|
||||||
|
@ -502,9 +502,10 @@ TEST(HeapSnapshotWeakCollection) {
|
|||||||
v8::HandleScope scope(env->GetIsolate());
|
v8::HandleScope scope(env->GetIsolate());
|
||||||
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
|
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
|
||||||
|
|
||||||
CompileRun("k = {}; v = {};\n"
|
CompileRun(
|
||||||
"ws = new WeakSet(); ws.add(k); ws.add(v);\n"
|
"k = {}; v = {}; s = 'str';\n"
|
||||||
"wm = new WeakMap(); wm.set(k, v);\n");
|
"ws = new WeakSet(); ws.add(k); ws.add(v); ws[s] = s;\n"
|
||||||
|
"wm = new WeakMap(); wm.set(k, v); wm[s] = s;\n");
|
||||||
const v8::HeapSnapshot* snapshot =
|
const v8::HeapSnapshot* snapshot =
|
||||||
heap_profiler->TakeHeapSnapshot(v8_str("WeakCollections"));
|
heap_profiler->TakeHeapSnapshot(v8_str("WeakCollections"));
|
||||||
CHECK(ValidateSnapshot(snapshot));
|
CHECK(ValidateSnapshot(snapshot));
|
||||||
@ -515,6 +516,9 @@ TEST(HeapSnapshotWeakCollection) {
|
|||||||
const v8::HeapGraphNode* v =
|
const v8::HeapGraphNode* v =
|
||||||
GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
|
GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
|
||||||
CHECK_NE(NULL, v);
|
CHECK_NE(NULL, v);
|
||||||
|
const v8::HeapGraphNode* s =
|
||||||
|
GetProperty(global, v8::HeapGraphEdge::kProperty, "s");
|
||||||
|
CHECK_NE(NULL, s);
|
||||||
|
|
||||||
const v8::HeapGraphNode* ws =
|
const v8::HeapGraphNode* ws =
|
||||||
GetProperty(global, v8::HeapGraphEdge::kProperty, "ws");
|
GetProperty(global, v8::HeapGraphEdge::kProperty, "ws");
|
||||||
@ -535,6 +539,10 @@ TEST(HeapSnapshotWeakCollection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CHECK_EQ(1, weak_entries);
|
CHECK_EQ(1, weak_entries);
|
||||||
|
const v8::HeapGraphNode* ws_s =
|
||||||
|
GetProperty(ws, v8::HeapGraphEdge::kProperty, "str");
|
||||||
|
CHECK_NE(NULL, ws_s);
|
||||||
|
CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(ws_s->GetId()));
|
||||||
|
|
||||||
const v8::HeapGraphNode* wm =
|
const v8::HeapGraphNode* wm =
|
||||||
GetProperty(global, v8::HeapGraphEdge::kProperty, "wm");
|
GetProperty(global, v8::HeapGraphEdge::kProperty, "wm");
|
||||||
@ -556,6 +564,85 @@ TEST(HeapSnapshotWeakCollection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CHECK_EQ(2, weak_entries);
|
CHECK_EQ(2, weak_entries);
|
||||||
|
const v8::HeapGraphNode* wm_s =
|
||||||
|
GetProperty(wm, v8::HeapGraphEdge::kProperty, "str");
|
||||||
|
CHECK_NE(NULL, wm_s);
|
||||||
|
CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(wm_s->GetId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(HeapSnapshotCollection) {
|
||||||
|
i::FLAG_harmony_collections = true;
|
||||||
|
|
||||||
|
LocalContext env;
|
||||||
|
v8::HandleScope scope(env->GetIsolate());
|
||||||
|
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
|
||||||
|
|
||||||
|
CompileRun(
|
||||||
|
"k = {}; v = {}; s = 'str';\n"
|
||||||
|
"set = new Set(); set.add(k); set.add(v); set[s] = s;\n"
|
||||||
|
"map = new Map(); map.set(k, v); map[s] = s;\n");
|
||||||
|
const v8::HeapSnapshot* snapshot =
|
||||||
|
heap_profiler->TakeHeapSnapshot(v8_str("Collections"));
|
||||||
|
CHECK(ValidateSnapshot(snapshot));
|
||||||
|
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
|
||||||
|
const v8::HeapGraphNode* k =
|
||||||
|
GetProperty(global, v8::HeapGraphEdge::kProperty, "k");
|
||||||
|
CHECK_NE(NULL, k);
|
||||||
|
const v8::HeapGraphNode* v =
|
||||||
|
GetProperty(global, v8::HeapGraphEdge::kProperty, "v");
|
||||||
|
CHECK_NE(NULL, v);
|
||||||
|
const v8::HeapGraphNode* s =
|
||||||
|
GetProperty(global, v8::HeapGraphEdge::kProperty, "s");
|
||||||
|
CHECK_NE(NULL, s);
|
||||||
|
|
||||||
|
const v8::HeapGraphNode* set =
|
||||||
|
GetProperty(global, v8::HeapGraphEdge::kProperty, "set");
|
||||||
|
CHECK_NE(NULL, set);
|
||||||
|
CHECK_EQ(v8::HeapGraphNode::kObject, set->GetType());
|
||||||
|
CHECK_EQ(v8_str("Set"), set->GetName());
|
||||||
|
|
||||||
|
const v8::HeapGraphNode* set_table =
|
||||||
|
GetProperty(set, v8::HeapGraphEdge::kInternal, "table");
|
||||||
|
CHECK_EQ(v8::HeapGraphNode::kArray, set_table->GetType());
|
||||||
|
CHECK_GT(set_table->GetChildrenCount(), 0);
|
||||||
|
int entries = 0;
|
||||||
|
for (int i = 0, count = set_table->GetChildrenCount(); i < count; ++i) {
|
||||||
|
const v8::HeapGraphEdge* prop = set_table->GetChild(i);
|
||||||
|
const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
|
||||||
|
if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
|
||||||
|
++entries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK_EQ(2, entries);
|
||||||
|
const v8::HeapGraphNode* set_s =
|
||||||
|
GetProperty(set, v8::HeapGraphEdge::kProperty, "str");
|
||||||
|
CHECK_NE(NULL, set_s);
|
||||||
|
CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(set_s->GetId()));
|
||||||
|
|
||||||
|
const v8::HeapGraphNode* map =
|
||||||
|
GetProperty(global, v8::HeapGraphEdge::kProperty, "map");
|
||||||
|
CHECK_NE(NULL, map);
|
||||||
|
CHECK_EQ(v8::HeapGraphNode::kObject, map->GetType());
|
||||||
|
CHECK_EQ(v8_str("Map"), map->GetName());
|
||||||
|
|
||||||
|
const v8::HeapGraphNode* map_table =
|
||||||
|
GetProperty(map, v8::HeapGraphEdge::kInternal, "table");
|
||||||
|
CHECK_EQ(v8::HeapGraphNode::kArray, map_table->GetType());
|
||||||
|
CHECK_GT(map_table->GetChildrenCount(), 0);
|
||||||
|
entries = 0;
|
||||||
|
for (int i = 0, count = map_table->GetChildrenCount(); i < count; ++i) {
|
||||||
|
const v8::HeapGraphEdge* prop = map_table->GetChild(i);
|
||||||
|
const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId();
|
||||||
|
if (to_node_id == k->GetId() || to_node_id == v->GetId()) {
|
||||||
|
++entries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK_EQ(2, entries);
|
||||||
|
const v8::HeapGraphNode* map_s =
|
||||||
|
GetProperty(map, v8::HeapGraphEdge::kProperty, "str");
|
||||||
|
CHECK_NE(NULL, map_s);
|
||||||
|
CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(map_s->GetId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user