[api] Mark functions related to object grouping as DEPRECATE_SOON
Embedders should use the EmbedderHeapTracer API. BUG=v8:5828 Review-Url: https://codereview.chromium.org/2628893003 Cr-Commit-Position: refs/heads/master@{#42269}
This commit is contained in:
parent
9cd0de73dc
commit
e00eae9e89
18
include/v8.h
18
include/v8.h
@ -6779,8 +6779,10 @@ class V8_EXPORT Isolate {
|
||||
* garbage collection types it is sufficient to provide object groups
|
||||
* for partially dependent handles only.
|
||||
*/
|
||||
template<typename T> void SetObjectGroupId(const Persistent<T>& object,
|
||||
UniqueId id);
|
||||
template <typename T>
|
||||
V8_DEPRECATE_SOON("Use EmbedderHeapTracer",
|
||||
void SetObjectGroupId(const Persistent<T>& object,
|
||||
UniqueId id));
|
||||
|
||||
/**
|
||||
* Allows the host application to declare implicit references from an object
|
||||
@ -6789,8 +6791,10 @@ class V8_EXPORT Isolate {
|
||||
* are removed. It is intended to be used in the before-garbage-collection
|
||||
* callback function.
|
||||
*/
|
||||
template<typename T> void SetReferenceFromGroup(UniqueId id,
|
||||
const Persistent<T>& child);
|
||||
template <typename T>
|
||||
V8_DEPRECATE_SOON("Use EmbedderHeapTracer",
|
||||
void SetReferenceFromGroup(UniqueId id,
|
||||
const Persistent<T>& child));
|
||||
|
||||
/**
|
||||
* Allows the host application to declare implicit references from an object
|
||||
@ -6798,8 +6802,10 @@ class V8_EXPORT Isolate {
|
||||
* too. After each garbage collection, all implicit references are removed. It
|
||||
* is intended to be used in the before-garbage-collection callback function.
|
||||
*/
|
||||
template<typename T, typename S>
|
||||
void SetReference(const Persistent<T>& parent, const Persistent<S>& child);
|
||||
template <typename T, typename S>
|
||||
V8_DEPRECATE_SOON("Use EmbedderHeapTracer",
|
||||
void SetReference(const Persistent<T>& parent,
|
||||
const Persistent<S>& child));
|
||||
|
||||
typedef void (*GCCallback)(Isolate* isolate, GCType type,
|
||||
GCCallbackFlags flags);
|
||||
|
@ -6200,44 +6200,6 @@ TEST(SharedFunctionInfoIterator) {
|
||||
CHECK_EQ(0, sfi_count);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static UniqueId MakeUniqueId(const Persistent<T>& p) {
|
||||
return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
|
||||
}
|
||||
|
||||
|
||||
TEST(Regress519319) {
|
||||
if (!FLAG_incremental_marking) return;
|
||||
CcTest::InitializeVM();
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
Heap* heap = CcTest::heap();
|
||||
LocalContext context;
|
||||
|
||||
v8::Persistent<Value> parent;
|
||||
v8::Persistent<Value> child;
|
||||
|
||||
parent.Reset(isolate, v8::Object::New(isolate));
|
||||
child.Reset(isolate, v8::Object::New(isolate));
|
||||
|
||||
heap::SimulateFullSpace(heap->old_space());
|
||||
CcTest::CollectGarbage(OLD_SPACE);
|
||||
{
|
||||
UniqueId id = MakeUniqueId(parent);
|
||||
isolate->SetObjectGroupId(parent, id);
|
||||
isolate->SetReferenceFromGroup(id, child);
|
||||
}
|
||||
// The CollectGarbage call above starts sweeper threads.
|
||||
// The crash will happen if the following two functions
|
||||
// are called before sweeping finishes.
|
||||
heap->StartIncrementalMarking(i::Heap::kNoGCFlags,
|
||||
i::GarbageCollectionReason::kTesting);
|
||||
heap->FinalizeIncrementalMarkingIfComplete(
|
||||
i::GarbageCollectionReason::kTesting);
|
||||
}
|
||||
|
||||
|
||||
HEAP_TEST(Regress587004) {
|
||||
FLAG_concurrent_sweeping = false;
|
||||
#ifdef VERIFY_HEAP
|
||||
|
@ -4483,335 +4483,6 @@ static void WeakPointerCallback(
|
||||
data.GetParameter()->handle.Reset();
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static UniqueId MakeUniqueId(const Persistent<T>& p) {
|
||||
return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(ApiObjectGroups) {
|
||||
LocalContext env;
|
||||
v8::Isolate* iso = env->GetIsolate();
|
||||
HandleScope scope(iso);
|
||||
|
||||
WeakCallCounter counter(1234);
|
||||
|
||||
WeakCallCounterAndPersistent<Value> g1s1(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g1s2(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g1c1(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g2s1(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g2s2(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g2c1(&counter);
|
||||
|
||||
{
|
||||
HandleScope scope(iso);
|
||||
g1s1.handle.Reset(iso, Object::New(iso));
|
||||
g1s2.handle.Reset(iso, Object::New(iso));
|
||||
g1c1.handle.Reset(iso, Object::New(iso));
|
||||
g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
|
||||
g2s1.handle.Reset(iso, Object::New(iso));
|
||||
g2s2.handle.Reset(iso, Object::New(iso));
|
||||
g2c1.handle.Reset(iso, Object::New(iso));
|
||||
g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
}
|
||||
|
||||
WeakCallCounterAndPersistent<Value> root(&counter);
|
||||
root.handle.Reset(iso, g1s1.handle); // make a root.
|
||||
|
||||
// Connect group 1 and 2, make a cycle.
|
||||
{
|
||||
HandleScope scope(iso);
|
||||
CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())
|
||||
->Set(env.local(), 0, Local<Value>::New(iso, g2s2.handle))
|
||||
.FromJust());
|
||||
CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())
|
||||
->Set(env.local(), 0, Local<Value>::New(iso, g1s1.handle))
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
{
|
||||
UniqueId id1 = MakeUniqueId(g1s1.handle);
|
||||
UniqueId id2 = MakeUniqueId(g2s2.handle);
|
||||
iso->SetObjectGroupId(g1s1.handle, id1);
|
||||
iso->SetObjectGroupId(g1s2.handle, id1);
|
||||
iso->SetReferenceFromGroup(id1, g1c1.handle);
|
||||
iso->SetObjectGroupId(g2s1.handle, id2);
|
||||
iso->SetObjectGroupId(g2s2.handle, id2);
|
||||
iso->SetReferenceFromGroup(id2, g2c1.handle);
|
||||
}
|
||||
// Do a single full GC, ensure incremental marking is stopped.
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
|
||||
// All object should be alive.
|
||||
CHECK_EQ(0, counter.NumberOfWeakCalls());
|
||||
|
||||
// Weaken the root.
|
||||
root.handle.SetWeak(&root, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
// But make children strong roots---all the objects (except for children)
|
||||
// should be collectable now.
|
||||
g1c1.handle.ClearWeak();
|
||||
g2c1.handle.ClearWeak();
|
||||
|
||||
// Groups are deleted, rebuild groups.
|
||||
{
|
||||
UniqueId id1 = MakeUniqueId(g1s1.handle);
|
||||
UniqueId id2 = MakeUniqueId(g2s2.handle);
|
||||
iso->SetObjectGroupId(g1s1.handle, id1);
|
||||
iso->SetObjectGroupId(g1s2.handle, id1);
|
||||
iso->SetReferenceFromGroup(id1, g1c1.handle);
|
||||
iso->SetObjectGroupId(g2s1.handle, id2);
|
||||
iso->SetObjectGroupId(g2s2.handle, id2);
|
||||
iso->SetReferenceFromGroup(id2, g2c1.handle);
|
||||
}
|
||||
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
|
||||
// All objects should be gone. 5 global handles in total.
|
||||
CHECK_EQ(5, counter.NumberOfWeakCalls());
|
||||
|
||||
// And now make children weak again and collect them.
|
||||
g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
CHECK_EQ(7, counter.NumberOfWeakCalls());
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(ApiObjectGroupsForSubtypes) {
|
||||
LocalContext env;
|
||||
v8::Isolate* iso = env->GetIsolate();
|
||||
HandleScope scope(iso);
|
||||
|
||||
WeakCallCounter counter(1234);
|
||||
|
||||
WeakCallCounterAndPersistent<Object> g1s1(&counter);
|
||||
WeakCallCounterAndPersistent<String> g1s2(&counter);
|
||||
WeakCallCounterAndPersistent<String> g1c1(&counter);
|
||||
WeakCallCounterAndPersistent<Object> g2s1(&counter);
|
||||
WeakCallCounterAndPersistent<String> g2s2(&counter);
|
||||
WeakCallCounterAndPersistent<String> g2c1(&counter);
|
||||
|
||||
{
|
||||
HandleScope scope(iso);
|
||||
g1s1.handle.Reset(iso, Object::New(iso));
|
||||
g1s2.handle.Reset(iso, v8_str("foo1"));
|
||||
g1c1.handle.Reset(iso, v8_str("foo2"));
|
||||
g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
|
||||
g2s1.handle.Reset(iso, Object::New(iso));
|
||||
g2s2.handle.Reset(iso, v8_str("foo3"));
|
||||
g2c1.handle.Reset(iso, v8_str("foo4"));
|
||||
g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
}
|
||||
|
||||
WeakCallCounterAndPersistent<Value> root(&counter);
|
||||
root.handle.Reset(iso, g1s1.handle); // make a root.
|
||||
|
||||
// Connect group 1 and 2, make a cycle.
|
||||
{
|
||||
HandleScope scope(iso);
|
||||
CHECK(Local<Object>::New(iso, g1s1.handle)
|
||||
->Set(env.local(), 0, Local<Object>::New(iso, g2s1.handle))
|
||||
.FromJust());
|
||||
CHECK(Local<Object>::New(iso, g2s1.handle)
|
||||
->Set(env.local(), 0, Local<Object>::New(iso, g1s1.handle))
|
||||
.FromJust());
|
||||
}
|
||||
|
||||
{
|
||||
UniqueId id1 = MakeUniqueId(g1s1.handle);
|
||||
UniqueId id2 = MakeUniqueId(g2s2.handle);
|
||||
iso->SetObjectGroupId(g1s1.handle, id1);
|
||||
iso->SetObjectGroupId(g1s2.handle, id1);
|
||||
iso->SetReference(g1s1.handle, g1c1.handle);
|
||||
iso->SetObjectGroupId(g2s1.handle, id2);
|
||||
iso->SetObjectGroupId(g2s2.handle, id2);
|
||||
iso->SetReferenceFromGroup(id2, g2c1.handle);
|
||||
}
|
||||
// Do a single full GC, ensure incremental marking is stopped.
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
|
||||
// All object should be alive.
|
||||
CHECK_EQ(0, counter.NumberOfWeakCalls());
|
||||
|
||||
// Weaken the root.
|
||||
root.handle.SetWeak(&root, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
// But make children strong roots---all the objects (except for children)
|
||||
// should be collectable now.
|
||||
g1c1.handle.ClearWeak();
|
||||
g2c1.handle.ClearWeak();
|
||||
|
||||
// Groups are deleted, rebuild groups.
|
||||
{
|
||||
UniqueId id1 = MakeUniqueId(g1s1.handle);
|
||||
UniqueId id2 = MakeUniqueId(g2s2.handle);
|
||||
iso->SetObjectGroupId(g1s1.handle, id1);
|
||||
iso->SetObjectGroupId(g1s2.handle, id1);
|
||||
iso->SetReference(g1s1.handle, g1c1.handle);
|
||||
iso->SetObjectGroupId(g2s1.handle, id2);
|
||||
iso->SetObjectGroupId(g2s2.handle, id2);
|
||||
iso->SetReferenceFromGroup(id2, g2c1.handle);
|
||||
}
|
||||
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
|
||||
// All objects should be gone. 5 global handles in total.
|
||||
CHECK_EQ(5, counter.NumberOfWeakCalls());
|
||||
|
||||
// And now make children weak again and collect them.
|
||||
g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
CHECK_EQ(7, counter.NumberOfWeakCalls());
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(ApiObjectGroupsCycle) {
|
||||
LocalContext env;
|
||||
v8::Isolate* iso = env->GetIsolate();
|
||||
HandleScope scope(iso);
|
||||
|
||||
WeakCallCounter counter(1234);
|
||||
|
||||
WeakCallCounterAndPersistent<Value> g1s1(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g1s2(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g2s1(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g2s2(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g3s1(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g3s2(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g4s1(&counter);
|
||||
WeakCallCounterAndPersistent<Value> g4s2(&counter);
|
||||
|
||||
{
|
||||
HandleScope scope(iso);
|
||||
g1s1.handle.Reset(iso, Object::New(iso));
|
||||
g1s2.handle.Reset(iso, Object::New(iso));
|
||||
g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
CHECK(g1s1.handle.IsWeak());
|
||||
CHECK(g1s2.handle.IsWeak());
|
||||
|
||||
g2s1.handle.Reset(iso, Object::New(iso));
|
||||
g2s2.handle.Reset(iso, Object::New(iso));
|
||||
g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
CHECK(g2s1.handle.IsWeak());
|
||||
CHECK(g2s2.handle.IsWeak());
|
||||
|
||||
g3s1.handle.Reset(iso, Object::New(iso));
|
||||
g3s2.handle.Reset(iso, Object::New(iso));
|
||||
g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
CHECK(g3s1.handle.IsWeak());
|
||||
CHECK(g3s2.handle.IsWeak());
|
||||
|
||||
g4s1.handle.Reset(iso, Object::New(iso));
|
||||
g4s2.handle.Reset(iso, Object::New(iso));
|
||||
g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
CHECK(g4s1.handle.IsWeak());
|
||||
CHECK(g4s2.handle.IsWeak());
|
||||
}
|
||||
|
||||
WeakCallCounterAndPersistent<Value> root(&counter);
|
||||
root.handle.Reset(iso, g1s1.handle); // make a root.
|
||||
|
||||
// Connect groups. We're building the following cycle:
|
||||
// G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
|
||||
// groups.
|
||||
{
|
||||
UniqueId id1 = MakeUniqueId(g1s1.handle);
|
||||
UniqueId id2 = MakeUniqueId(g2s1.handle);
|
||||
UniqueId id3 = MakeUniqueId(g3s1.handle);
|
||||
UniqueId id4 = MakeUniqueId(g4s1.handle);
|
||||
iso->SetObjectGroupId(g1s1.handle, id1);
|
||||
iso->SetObjectGroupId(g1s2.handle, id1);
|
||||
iso->SetReferenceFromGroup(id1, g2s1.handle);
|
||||
iso->SetObjectGroupId(g2s1.handle, id2);
|
||||
iso->SetObjectGroupId(g2s2.handle, id2);
|
||||
iso->SetReferenceFromGroup(id2, g3s1.handle);
|
||||
iso->SetObjectGroupId(g3s1.handle, id3);
|
||||
iso->SetObjectGroupId(g3s2.handle, id3);
|
||||
iso->SetReferenceFromGroup(id3, g4s1.handle);
|
||||
iso->SetObjectGroupId(g4s1.handle, id4);
|
||||
iso->SetObjectGroupId(g4s2.handle, id4);
|
||||
iso->SetReferenceFromGroup(id4, g1s1.handle);
|
||||
}
|
||||
// Do a single full GC
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
|
||||
// All object should be alive.
|
||||
CHECK_EQ(0, counter.NumberOfWeakCalls());
|
||||
|
||||
// Weaken the root.
|
||||
root.handle.SetWeak(&root, &WeakPointerCallback,
|
||||
v8::WeakCallbackType::kParameter);
|
||||
|
||||
// Groups are deleted, rebuild groups.
|
||||
{
|
||||
UniqueId id1 = MakeUniqueId(g1s1.handle);
|
||||
UniqueId id2 = MakeUniqueId(g2s1.handle);
|
||||
UniqueId id3 = MakeUniqueId(g3s1.handle);
|
||||
UniqueId id4 = MakeUniqueId(g4s1.handle);
|
||||
iso->SetObjectGroupId(g1s1.handle, id1);
|
||||
iso->SetObjectGroupId(g1s2.handle, id1);
|
||||
iso->SetReferenceFromGroup(id1, g2s1.handle);
|
||||
iso->SetObjectGroupId(g2s1.handle, id2);
|
||||
iso->SetObjectGroupId(g2s2.handle, id2);
|
||||
iso->SetReferenceFromGroup(id2, g3s1.handle);
|
||||
iso->SetObjectGroupId(g3s1.handle, id3);
|
||||
iso->SetObjectGroupId(g3s2.handle, id3);
|
||||
iso->SetReferenceFromGroup(id3, g4s1.handle);
|
||||
iso->SetObjectGroupId(g4s1.handle, id4);
|
||||
iso->SetObjectGroupId(g4s2.handle, id4);
|
||||
iso->SetReferenceFromGroup(id4, g1s1.handle);
|
||||
}
|
||||
|
||||
CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
|
||||
|
||||
// All objects should be gone. 9 global handles in total.
|
||||
CHECK_EQ(9, counter.NumberOfWeakCalls());
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(ScriptException) {
|
||||
LocalContext env;
|
||||
v8::HandleScope scope(env->GetIsolate());
|
||||
|
@ -1570,88 +1570,6 @@ TEST(HeapSnapshotRetainedObjectInfo) {
|
||||
CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native"));
|
||||
}
|
||||
|
||||
|
||||
class GraphWithImplicitRefs {
|
||||
public:
|
||||
static const int kObjectsCount = 4;
|
||||
explicit GraphWithImplicitRefs(LocalContext* env) {
|
||||
CHECK(!instance_);
|
||||
instance_ = this;
|
||||
isolate_ = (*env)->GetIsolate();
|
||||
for (int i = 0; i < kObjectsCount; i++) {
|
||||
objects_[i].Reset(isolate_, v8::Object::New(isolate_));
|
||||
}
|
||||
(*env)
|
||||
->Global()
|
||||
->Set(isolate_->GetCurrentContext(), v8_str("root_object"),
|
||||
v8::Local<v8::Value>::New(isolate_, objects_[0]))
|
||||
.FromJust();
|
||||
}
|
||||
~GraphWithImplicitRefs() {
|
||||
instance_ = NULL;
|
||||
}
|
||||
|
||||
static void gcPrologue(v8::Isolate* isolate, v8::GCType type,
|
||||
v8::GCCallbackFlags flags) {
|
||||
instance_->AddImplicitReferences();
|
||||
}
|
||||
|
||||
private:
|
||||
void AddImplicitReferences() {
|
||||
// 0 -> 1
|
||||
isolate_->SetObjectGroupId(objects_[0],
|
||||
v8::UniqueId(1));
|
||||
isolate_->SetReferenceFromGroup(
|
||||
v8::UniqueId(1), objects_[1]);
|
||||
// Adding two more references: 1 -> 2, 1 -> 3
|
||||
isolate_->SetReference(objects_[1].As<v8::Object>(),
|
||||
objects_[2]);
|
||||
isolate_->SetReference(objects_[1].As<v8::Object>(),
|
||||
objects_[3]);
|
||||
}
|
||||
|
||||
v8::Persistent<v8::Value> objects_[kObjectsCount];
|
||||
static GraphWithImplicitRefs* instance_;
|
||||
v8::Isolate* isolate_;
|
||||
};
|
||||
|
||||
GraphWithImplicitRefs* GraphWithImplicitRefs::instance_ = NULL;
|
||||
|
||||
|
||||
TEST(HeapSnapshotImplicitReferences) {
|
||||
LocalContext env;
|
||||
v8::HandleScope scope(env->GetIsolate());
|
||||
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
|
||||
|
||||
GraphWithImplicitRefs graph(&env);
|
||||
env->GetIsolate()->AddGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue);
|
||||
|
||||
const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot();
|
||||
CHECK(ValidateSnapshot(snapshot));
|
||||
|
||||
const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot);
|
||||
const v8::HeapGraphNode* obj0 = GetProperty(
|
||||
global_object, v8::HeapGraphEdge::kProperty, "root_object");
|
||||
CHECK(obj0);
|
||||
CHECK_EQ(v8::HeapGraphNode::kObject, obj0->GetType());
|
||||
const v8::HeapGraphNode* obj1 = GetProperty(
|
||||
obj0, v8::HeapGraphEdge::kInternal, "native");
|
||||
CHECK(obj1);
|
||||
int implicit_targets_count = 0;
|
||||
for (int i = 0, count = obj1->GetChildrenCount(); i < count; ++i) {
|
||||
const v8::HeapGraphEdge* prop = obj1->GetChild(i);
|
||||
v8::String::Utf8Value prop_name(prop->GetName());
|
||||
if (prop->GetType() == v8::HeapGraphEdge::kInternal &&
|
||||
strcmp("native", *prop_name) == 0) {
|
||||
++implicit_targets_count;
|
||||
}
|
||||
}
|
||||
CHECK_EQ(2, implicit_targets_count);
|
||||
env->GetIsolate()->RemoveGCPrologueCallback(
|
||||
&GraphWithImplicitRefs::gcPrologue);
|
||||
}
|
||||
|
||||
|
||||
TEST(DeleteAllHeapSnapshots) {
|
||||
LocalContext env;
|
||||
v8::HandleScope scope(env->GetIsolate());
|
||||
|
Loading…
Reference in New Issue
Block a user