Commit 00a589d9 authored by jochen's avatar jochen Committed by Commit bot

[api] Bring back finalizers on global handles

Seems like node.js depends on it in many places. At least try to get rid
of WeakCallbackData vs WeakCallbackInfo

BUG=
R=hpayer@chromium.org
LOG=y

Review URL: https://codereview.chromium.org/1883173002

Cr-Commit-Position: refs/heads/master@{#35528}
parent 3533c084
...@@ -480,9 +480,12 @@ class WeakCallbackData { ...@@ -480,9 +480,12 @@ class WeakCallbackData {
template <class T> template <class T>
using PhantomCallbackData = WeakCallbackInfo<T>; using PhantomCallbackData = WeakCallbackInfo<T>;
// kParameter will pass a void* parameter back to the callback, kInternalFields
enum class WeakCallbackType { kParameter, kInternalFields }; // will pass the first two internal fields back to the callback, kFinalizer
// will pass a void* parameter back, but is invoked before the object is
// actually collected, so it can be resurrected. In the last case, it is not
// possible to request a second pass callback.
enum class WeakCallbackType { kParameter, kInternalFields, kFinalizer };
/** /**
* An object reference that is independent of any handle scope. Where * An object reference that is independent of any handle scope. Where
......
...@@ -197,14 +197,16 @@ class GlobalHandles::Node { ...@@ -197,14 +197,16 @@ class GlobalHandles::Node {
bool IsRetainer() const { bool IsRetainer() const {
return state() != FREE && return state() != FREE &&
!(state() == NEAR_DEATH && weakness_type() != NORMAL_WEAK); !(state() == NEAR_DEATH && weakness_type() != NORMAL_WEAK &&
weakness_type() != FINALIZER_WEAK);
} }
bool IsStrongRetainer() const { return state() == NORMAL; } bool IsStrongRetainer() const { return state() == NORMAL; }
bool IsWeakRetainer() const { bool IsWeakRetainer() const {
return state() == WEAK || state() == PENDING || return state() == WEAK || state() == PENDING ||
(state() == NEAR_DEATH && weakness_type() == NORMAL_WEAK); (state() == NEAR_DEATH && weakness_type() == NORMAL_WEAK &&
weakness_type() != FINALIZER_WEAK);
} }
void MarkPending() { void MarkPending() {
...@@ -272,8 +274,11 @@ class GlobalHandles::Node { ...@@ -272,8 +274,11 @@ class GlobalHandles::Node {
set_weakness_type(PHANTOM_WEAK); set_weakness_type(PHANTOM_WEAK);
break; break;
case v8::WeakCallbackType::kInternalFields: case v8::WeakCallbackType::kInternalFields:
set_weakness_type(PHANTOM_WEAK_2_INTERNAL_FIELDS); set_weakness_type(PHANTOM_WEAK_2_INTERNAL_FIELDS);
break; break;
case v8::WeakCallbackType::kFinalizer:
set_weakness_type(NORMAL_WEAK);
break;
} }
set_parameter(parameter); set_parameter(parameter);
weak_callback_ = reinterpret_cast<WeakCallback>(phantom_callback); weak_callback_ = reinterpret_cast<WeakCallback>(phantom_callback);
...@@ -332,18 +337,30 @@ class GlobalHandles::Node { ...@@ -332,18 +337,30 @@ class GlobalHandles::Node {
ExternalOneByteString::cast(object_)->resource() != NULL); ExternalOneByteString::cast(object_)->resource() != NULL);
DCHECK(!object_->IsExternalTwoByteString() || DCHECK(!object_->IsExternalTwoByteString() ||
ExternalTwoByteString::cast(object_)->resource() != NULL); ExternalTwoByteString::cast(object_)->resource() != NULL);
if (weakness_type() != NORMAL_WEAK) return false; if (weakness_type() != NORMAL_WEAK && weakness_type() != FINALIZER_WEAK) {
return false;
}
// Leaving V8. // Leaving V8.
VMState<EXTERNAL> vmstate(isolate); VMState<EXTERNAL> vmstate(isolate);
HandleScope handle_scope(isolate); HandleScope handle_scope(isolate);
Object** object = location(); if (weakness_type() == NORMAL_WEAK) {
Handle<Object> handle(*object, isolate); Object** object = location();
v8::WeakCallbackData<v8::Value, void> data( Handle<Object> handle(*object, isolate);
reinterpret_cast<v8::Isolate*>(isolate), parameter(), v8::WeakCallbackData<v8::Value, void> data(
v8::Utils::ToLocal(handle)); reinterpret_cast<v8::Isolate*>(isolate), parameter(),
set_parameter(NULL); v8::Utils::ToLocal(handle));
weak_callback_(data); set_parameter(NULL);
weak_callback_(data);
} else {
void* internal_fields[v8::kInternalFieldsInWeakCallback] = {nullptr,
nullptr};
v8::WeakCallbackInfo<void> data(reinterpret_cast<v8::Isolate*>(isolate),
parameter(), internal_fields, nullptr);
auto callback = reinterpret_cast<v8::WeakCallbackInfo<void>::Callback>(
weak_callback_);
callback(data);
}
// Absence of explicit cleanup or revival of weak handle // Absence of explicit cleanup or revival of weak handle
// in most of the cases would lead to memory leak. // in most of the cases would lead to memory leak.
...@@ -650,9 +667,10 @@ void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) { ...@@ -650,9 +667,10 @@ void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
if (node->IsWeakRetainer()) { if (node->IsWeakRetainer()) {
// Pending weak phantom handles die immediately. Everything else survives. // Pending weak phantom handles die immediately. Everything else survives.
if (node->state() == Node::PENDING && if (node->state() == Node::PENDING &&
node->weakness_type() != NORMAL_WEAK) { node->weakness_type() != NORMAL_WEAK &&
node->CollectPhantomCallbackData(isolate(), node->weakness_type() != FINALIZER_WEAK) {
&pending_phantom_callbacks_); node->CollectPhantomCallbackData(isolate(),
&pending_phantom_callbacks_);
} else { } else {
v->VisitPointer(node->location()); v->VisitPointer(node->location());
} }
...@@ -711,7 +729,8 @@ void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) { ...@@ -711,7 +729,8 @@ void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
node->IsWeakRetainer()) { node->IsWeakRetainer()) {
// Pending weak phantom handles die immediately. Everything else survives. // Pending weak phantom handles die immediately. Everything else survives.
if (node->state() == Node::PENDING && if (node->state() == Node::PENDING &&
node->weakness_type() != NORMAL_WEAK) { node->weakness_type() != NORMAL_WEAK &&
node->weakness_type() != FINALIZER_WEAK) {
node->CollectPhantomCallbackData(isolate(), node->CollectPhantomCallbackData(isolate(),
&pending_phantom_callbacks_); &pending_phantom_callbacks_);
} else { } else {
...@@ -754,7 +773,8 @@ void GlobalHandles::IterateNewSpaceWeakUnmodifiedRoots(ObjectVisitor* v) { ...@@ -754,7 +773,8 @@ void GlobalHandles::IterateNewSpaceWeakUnmodifiedRoots(ObjectVisitor* v) {
node->IsWeakRetainer()) { node->IsWeakRetainer()) {
// Pending weak phantom handles die immediately. Everything else survives. // Pending weak phantom handles die immediately. Everything else survives.
if (node->state() == Node::PENDING && if (node->state() == Node::PENDING &&
node->weakness_type() != NORMAL_WEAK) { node->weakness_type() != NORMAL_WEAK &&
node->weakness_type() != FINALIZER_WEAK) {
node->CollectPhantomCallbackData(isolate(), node->CollectPhantomCallbackData(isolate(),
&pending_phantom_callbacks_); &pending_phantom_callbacks_);
} else { } else {
......
...@@ -96,7 +96,6 @@ struct ObjectGroupRetainerInfo { ...@@ -96,7 +96,6 @@ struct ObjectGroupRetainerInfo {
RetainedObjectInfo* info; RetainedObjectInfo* info;
}; };
enum WeaknessType { enum WeaknessType {
NORMAL_WEAK, // Embedder gets a handle to the dying object. NORMAL_WEAK, // Embedder gets a handle to the dying object.
// In the following cases, the embedder gets the parameter they passed in // In the following cases, the embedder gets the parameter they passed in
...@@ -105,10 +104,11 @@ enum WeaknessType { ...@@ -105,10 +104,11 @@ enum WeaknessType {
// objects through this interface would be GC unsafe so in that case the // objects through this interface would be GC unsafe so in that case the
// embedder gets a null pointer instead. // embedder gets a null pointer instead.
PHANTOM_WEAK, PHANTOM_WEAK,
PHANTOM_WEAK_2_INTERNAL_FIELDS PHANTOM_WEAK_2_INTERNAL_FIELDS,
// Like NORMAL_WEAK, but uses WeakCallbackInfo instead of WeakCallbackData.
FINALIZER_WEAK,
}; };
class GlobalHandles { class GlobalHandles {
public: public:
~GlobalHandles(); ~GlobalHandles();
......
...@@ -417,3 +417,36 @@ TEST(WeakPersistentSmi) { ...@@ -417,3 +417,36 @@ TEST(WeakPersistentSmi) {
// Should not crash. // Should not crash.
g.SetWeak<void>(nullptr, &WeakCallback, v8::WeakCallbackType::kParameter); g.SetWeak<void>(nullptr, &WeakCallback, v8::WeakCallbackType::kParameter);
} }
void finalizer(const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
data.GetParameter()->ClearWeak();
v8::Local<v8::Object> o =
v8::Local<v8::Object>::New(data.GetIsolate(), *data.GetParameter());
o->Set(data.GetIsolate()->GetCurrentContext(), v8_str("finalizer"),
v8_str("was here"))
.FromJust();
}
TEST(FinalizerWeakness) {
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::Global<v8::Object> g;
int identity;
{
v8::HandleScope scope(isolate);
v8::Local<v8::Object> o = v8::Object::New(isolate);
identity = o->GetIdentityHash();
g.Reset(isolate, o);
g.SetWeak(&g, finalizer, v8::WeakCallbackType::kFinalizer);
}
CcTest::i_isolate()->heap()->CollectAllAvailableGarbage();
CHECK(!g.IsEmpty());
v8::HandleScope scope(isolate);
v8::Local<v8::Object> o = v8::Local<v8::Object>::New(isolate, g);
CHECK_EQ(identity, o->GetIdentityHash());
CHECK(o->Has(isolate->GetCurrentContext(), v8_str("finalizer")).FromJust());
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment