Index: src/global-handles.cc |
diff --git a/src/global-handles.cc b/src/global-handles.cc |
index 574b2489ea2bc1e21dc8d917a2935700a050bdee..c5da3d21e675b761753c00467c8fd1726e2c7471 100644 |
--- a/src/global-handles.cc |
+++ b/src/global-handles.cc |
@@ -33,7 +33,14 @@ class GlobalHandles::Node { |
NORMAL, // Normal global handle. |
WEAK, // Flagged as weak but not yet finalized. |
PENDING, // Has been recognized as only reachable by weak handles. |
- NEAR_DEATH // Callback has informed the handle is near death. |
+ NEAR_DEATH, // Callback has informed the handle is near death. |
+ NUMBER_OF_NODE_STATES |
+ }; |
+ |
+ enum WeaknessType { |
+ NORMAL_WEAK, // Embedder gets a handle to the dying object. |
+ PHANTOM_WEAK, // Embedder gets the parameter they passed in earlier. |
+ INTERNAL_FIELDS_WEAK // Embedded gets 1 or 2 internal fields from dying object. |
}; |
// Maps handle location (slot) to the containing node. |
@@ -92,6 +99,12 @@ class GlobalHandles::Node { |
IncreaseBlockUses(); |
} |
+ void Zap() { |
+ DCHECK(state() != FREE); |
+ // Zap the values for eager trapping. |
+ object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); |
+ } |
+ |
void Release() { |
DCHECK(state() != FREE); |
set_state(FREE); |
@@ -146,11 +159,11 @@ class GlobalHandles::Node { |
flags_ = IsInNewSpaceList::update(flags_, v); |
} |
- bool is_zapped_during_weak_callback() { |
- return IsZappedDuringWeakCallback::decode(flags_); |
+ WeaknessType weakness_type() const { |
+ return NodeWeaknessType::decode(flags_); |
} |
- void set_is_zapped_during_weak_callback(bool v) { |
- flags_ = IsZappedDuringWeakCallback::update(flags_, v); |
+ void set_weakness_type(WeaknessType t) { |
+ flags_ = NodeWeaknessType::update(flags_, t); |
} |
bool IsNearDeath() const { |
@@ -194,6 +207,7 @@ class GlobalHandles::Node { |
// Callback parameter accessors. |
void set_parameter(void* parameter) { |
DCHECK(state() != FREE); |
+ DCHECK(weakness_type() == NORMAL_WEAK || weakness_type() == PHANTOM_WEAK); |
parameter_or_next_free_.parameter = parameter; |
} |
void* parameter() const { |
@@ -201,6 +215,22 @@ class GlobalHandles::Node { |
return parameter_or_next_free_.parameter; |
} |
+ void set_internal_fields(int internal_field_index1, int internal_field_index2) { |
+ DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK); |
+ parameter_or_next_free_.internal_field_indeces.internal_field1 = internal_field_index1; |
+ parameter_or_next_free_.internal_field_indeces.internal_field2 = internal_field_index2; |
+ } |
+ |
+ int internal_field1() const { |
+ DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK); |
+ return parameter_or_next_free_.internal_field_indeces.internal_field1; |
+ } |
+ |
+ int internal_field2() const { |
+ DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK); |
+ return parameter_or_next_free_.internal_field_indeces.internal_field2; |
+ } |
+ |
// Accessors for next free node in the free list. |
Node* next_free() { |
DCHECK(state() == FREE); |
@@ -211,17 +241,35 @@ class GlobalHandles::Node { |
parameter_or_next_free_.next_free = value; |
} |
- void MakeWeak(void* parameter, WeakCallback weak_callback, |
- bool is_zapped_during_weak_callback = false) { |
+ void MakeWeak(void* parameter, WeakCallback weak_callback) { |
DCHECK(weak_callback != NULL); |
DCHECK(state() != FREE); |
CHECK(object_ != NULL); |
set_state(WEAK); |
+ set_weakness_type(Node::NORMAL_WEAK); |
set_parameter(parameter); |
- set_is_zapped_during_weak_callback(is_zapped_during_weak_callback); |
weak_callback_ = weak_callback; |
} |
+ void MakePhantom(void* parameter, PhantomCallback phantom_callback, |
+ int internal_field_index1, int internal_field_index2) { |
+ //FIXME: Where to put the indeces... |
+ DCHECK(phantom_callback != NULL); |
+ DCHECK(state() != FREE); |
+ CHECK(object_ != NULL); |
+ set_state(WEAK); |
+ if (parameter != NULL) { |
+ DCHECK(internal_field_index1 == v8::Object::kNoInternalFieldIndex); |
+ DCHECK(internal_field_index2 == v8::Object::kNoInternalFieldIndex); |
+ set_weakness_type(Node::PHANTOM_WEAK); |
+ set_parameter(parameter); |
+ } else { |
+ set_weakness_type(Node::INTERNAL_FIELDS_WEAK); |
+ set_internal_fields(internal_field_index1, internal_field_index2); |
+ } |
+ weak_callback_ = reinterpret_cast<WeakCallback>(phantom_callback); |
+ } |
+ |
void* ClearWeakness() { |
DCHECK(state() != FREE); |
void* p = parameter(); |
@@ -236,11 +284,8 @@ class GlobalHandles::Node { |
Release(); |
return false; |
} |
- void* param = parameter(); |
set_state(NEAR_DEATH); |
- set_parameter(NULL); |
- Object** object = location(); |
{ |
// Check that we are not passing a finalized external string to |
// the callback. |
@@ -251,25 +296,48 @@ class GlobalHandles::Node { |
// Leaving V8. |
VMState<EXTERNAL> vmstate(isolate); |
HandleScope handle_scope(isolate); |
- if (is_zapped_during_weak_callback()) { |
- // Phantom weak pointer case. |
- DCHECK(*object == Smi::FromInt(kPhantomReferenceZap)); |
- // Make data with a null handle. |
- v8::WeakCallbackData<v8::Value, void> data( |
- reinterpret_cast<v8::Isolate*>(isolate), v8::Local<v8::Object>(), |
- param); |
- weak_callback_(data); |
- if (state() != FREE) { |
- // Callback does not have to clear the global handle if it is a |
- // phantom handle. |
- Release(); |
- } |
- } else { |
+ if (weakness_type() == Node::NORMAL_WEAK) { |
+ Object** object = location(); |
Handle<Object> handle(*object, isolate); |
v8::WeakCallbackData<v8::Value, void> data( |
reinterpret_cast<v8::Isolate*>(isolate), v8::Utils::ToLocal(handle), |
- param); |
+ parameter()); |
+ set_parameter(NULL); |
weak_callback_(data); |
+ } else { |
+ v8::PhantomCallbackData<void>::Callback callback = |
+ reinterpret_cast<v8::PhantomCallbackData<void>::Callback>(weak_callback_); |
+ if (weakness_type() == Node::PHANTOM_WEAK) { |
+ // Phantom weak pointer case. |
+ DCHECK(*location() == Smi::FromInt(kPhantomReferenceZap)); |
+ // Make data with a null handle. |
+ v8::PhantomCallbackData<void> data( |
+ reinterpret_cast<v8::Isolate*>(isolate), parameter()); |
+ callback(data); |
+ if (state() != FREE) { |
+ // Callback does not have to clear the global handle if it is a |
+ // phantom handle. |
+ Release(); |
+ } |
+ set_parameter(NULL); |
+ } else { |
+ DCHECK(weakness_type() == Node::INTERNAL_FIELDS_WEAK); |
+ // Phantom weak pointer case, passing internal fields instead of parameter. |
+ Handle<Object> handle(object(), isolate); |
+ Handle<JSObject> jsobject = Handle<JSObject>::cast(handle); |
+ v8::PhantomCallbackData<void> data( |
+ reinterpret_cast<v8::Isolate*>(isolate), |
+ jsobject->GetInternalField(internal_field1()), |
+ jsobject->GetInternalField(internal_field2())); |
+ // In the future, we want to delay the callback. In that case we will zap |
+ // when we queue up, to stop the C++ side accessing the dead V8 object, |
+ // but we will call Release only after the callback (allowing the node |
+ // to be reused). |
+ Zap(); |
+ callback(data); |
+ Release(); |
+ set_internal_fields(v8::Object::kNoInternalFieldIndex, v8::Object::kNoInternalFieldIndex); |
+ } |
} |
} |
// Absence of explicit cleanup or revival of weak handle |
@@ -300,11 +368,11 @@ class GlobalHandles::Node { |
// This stores three flags (independent, partially_dependent and |
// in_new_space_list) and a State. |
- class NodeState : public BitField<State, 0, 4> {}; |
- class IsIndependent : public BitField<bool, 4, 1> {}; |
- class IsPartiallyDependent : public BitField<bool, 5, 1> {}; |
- class IsInNewSpaceList : public BitField<bool, 6, 1> {}; |
- class IsZappedDuringWeakCallback : public BitField<bool, 7, 1> {}; |
+ class NodeState : public BitField<State, 0, 3> {}; |
+ class IsIndependent : public BitField<bool, 3, 1> {}; |
+ class IsPartiallyDependent : public BitField<bool, 4, 1> {}; |
+ class IsInNewSpaceList : public BitField<bool, 5, 1> {}; |
+ class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {}; |
uint8_t flags_; |
@@ -315,6 +383,10 @@ class GlobalHandles::Node { |
// the free list link. |
union { |
void* parameter; |
+ struct { |
+ uint16_t internal_field1; |
+ uint16_t internal_field2; |
+ } internal_field_indeces; |
Node* next_free; |
} parameter_or_next_free_; |
@@ -500,9 +572,17 @@ void GlobalHandles::Destroy(Object** location) { |
void GlobalHandles::MakeWeak(Object** location, void* parameter, |
- WeakCallback weak_callback, PhantomState phantom) { |
+ WeakCallback weak_callback) { |
+ Node::FromLocation(location)->MakeWeak(parameter, weak_callback); |
+} |
+ |
+ |
+void GlobalHandles::MakePhantom(Object** location, void* parameter, |
+ PhantomCallback phantom_callback, |
+ int internal_field_index1, |
+ int internal_field_index2) { |
Node::FromLocation(location) |
- ->MakeWeak(parameter, weak_callback, phantom == Phantom); |
+ ->MakePhantom(parameter, phantom_callback, internal_field_index1, internal_field_index2); |
} |
@@ -540,9 +620,22 @@ void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) { |
for (NodeIterator it(this); !it.done(); it.Advance()) { |
Node* node = it.node(); |
if (node->IsWeakRetainer()) { |
- if (node->state() == Node::PENDING && |
- node->is_zapped_during_weak_callback()) { |
- *(node->location()) = Smi::FromInt(kPhantomReferenceZap); |
+ // Weakness type can be normal, phantom or internal fields. |
+ // For normal weakness we mark through the handle so that |
+ // the object and things reachable from it are available |
+ // to the callback. |
+ // In the case of phantom we can zap the object handle now |
+ // and we won't need it, so we don't need to mark through it. |
+ // In the internal fields case we will need the internal |
+ // fields, so we can't zap the handle, but we don't need to |
+ // mark through it, because it will die in this GC round. |
+ v->VisitPointer(node->location()); |
+ if (node->state() == Node::PENDING) { |
+ if (node->weakness_type() == Node::PHANTOM_WEAK) { |
+ *(node->location()) = Smi::FromInt(kPhantomReferenceZap); |
jochen (gone - plz use gerrit)
2014/11/24 12:27:53
if you zap the handle here, how can you get to obj
Erik Corry
2014/11/24 12:38:26
For the INTERNAL_FIELDS case we don't zap here.
|
+ } else if (node->weakness_type() == Node::NORMAL_WEAK) { |
+ v->VisitPointer(node->location()); |
+ } |
} else { |
v->VisitPointer(node->location()); |
} |
@@ -591,10 +684,14 @@ void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) { |
DCHECK(node->is_in_new_space_list()); |
if ((node->is_independent() || node->is_partially_dependent()) && |
node->IsWeakRetainer()) { |
- if (node->is_zapped_during_weak_callback()) { |
+ if (node->weakness_type() == Node::PHANTOM_WEAK) { |
*(node->location()) = Smi::FromInt(kPhantomReferenceZap); |
- } else { |
+ } else if (node->weakness_type() == Node::NORMAL_WEAK) { |
v->VisitPointer(node->location()); |
+ } else { |
+ // For this case we don't need to trace through, but we don't |
+ // zap yet. |
+ DCHECK(node->weakness_type() == Node::INTERNAL_FIELDS_WEAK); |
} |
} |
} |