 Chromium Code Reviews
 Chromium Code Reviews Issue 753553002:
  Phantom references support internal fields  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master
    
  
    Issue 753553002:
  Phantom references support internal fields  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master| 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); | 
| } | 
| } | 
| } |