f244f0c5ef
For each Managed<T> (which is a Foreign), we create a weak global handle with a finalizer which deletes the referenced C++ object once the Foreign is dead. Before calling this finalizer, the garbage collector needs to mark the referenced object black (i.e. live), because the finalizer might resurrect it. Since this is never done for managed objects, we can use the more lightweight phantom handle semantics, which allows the referenced object to be garbage collected right away. However, we can't access the global handle via the WeakCallbackInfo, because the global handle will already be garbage collected. So we need to store it explicitly. This is solved by storing the global handle together with the finalizer. In order to implement this, ownership of the ManagedObjectFinalizer is moved from the isolate to the managed object. R=ulan@chromium.org, mtrofin@chromium.org BUG=v8:6505, chromium:734345 Change-Id: I94a245df601f70e19355d82439d30099e159231b Reviewed-on: https://chromium-review.googlesource.com/539578 Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#46036}
79 lines
2.1 KiB
C++
79 lines
2.1 KiB
C++
// Copyright 2016 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "src/managed.h"
|
|
|
|
#include "src/objects-inl.h"
|
|
#include "test/cctest/cctest.h"
|
|
|
|
using namespace v8::base;
|
|
using namespace v8::internal;
|
|
|
|
class DeleteRecorder {
|
|
public:
|
|
explicit DeleteRecorder(bool* deleted) : deleted_(deleted) {
|
|
*deleted_ = false;
|
|
}
|
|
~DeleteRecorder() { *deleted_ = true; }
|
|
static void Deleter(Isolate::ManagedObjectFinalizer* finalizer) {
|
|
delete *reinterpret_cast<DeleteRecorder**>(finalizer);
|
|
}
|
|
|
|
private:
|
|
bool* deleted_;
|
|
};
|
|
|
|
TEST(ManagedCollect) {
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
bool deleted1 = false;
|
|
bool deleted2 = false;
|
|
DeleteRecorder* d1 = new DeleteRecorder(&deleted1);
|
|
DeleteRecorder* d2 = new DeleteRecorder(&deleted2);
|
|
Isolate::ManagedObjectFinalizer finalizer(d2, DeleteRecorder::Deleter);
|
|
isolate->RegisterForReleaseAtTeardown(&finalizer);
|
|
{
|
|
HandleScope scope(isolate);
|
|
auto handle = Managed<DeleteRecorder>::New(isolate, d1);
|
|
USE(handle);
|
|
}
|
|
|
|
CcTest::CollectAllAvailableGarbage();
|
|
|
|
CHECK(deleted1);
|
|
CHECK(!deleted2);
|
|
isolate->UnregisterFromReleaseAtTeardown(&finalizer);
|
|
delete d2;
|
|
CHECK(deleted2);
|
|
}
|
|
|
|
TEST(DisposeCollect) {
|
|
v8::Isolate::CreateParams create_params;
|
|
create_params.array_buffer_allocator =
|
|
CcTest::InitIsolateOnce()->array_buffer_allocator();
|
|
|
|
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
|
isolate->Enter();
|
|
Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
|
bool deleted1 = false;
|
|
bool deleted2 = false;
|
|
DeleteRecorder* d1 = new DeleteRecorder(&deleted1);
|
|
DeleteRecorder* d2 = new DeleteRecorder(&deleted2);
|
|
{
|
|
HandleScope scope(i_isolate);
|
|
auto handle = Managed<DeleteRecorder>::New(i_isolate, d1);
|
|
USE(handle);
|
|
}
|
|
Isolate::ManagedObjectFinalizer finalizer(d2, DeleteRecorder::Deleter);
|
|
i_isolate->RegisterForReleaseAtTeardown(&finalizer);
|
|
|
|
isolate->Exit();
|
|
isolate->Dispose();
|
|
CHECK(deleted1);
|
|
CHECK(deleted2);
|
|
}
|