Unify phantom and internal fields weak handle callbacks

R=dcarney@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#26022}
This commit is contained in:
erikcorry 2015-01-12 04:11:49 -08:00 committed by Commit bot
parent a4124b3bfc
commit 7db1759b65
6 changed files with 154 additions and 212 deletions

View File

@ -137,15 +137,18 @@ class PropertyCallbackArguments;
class FunctionCallbackArguments;
class GlobalHandles;
template <typename T>
class CallbackData {
public:
V8_INLINE v8::Isolate* GetIsolate() const { return isolate_; }
protected:
explicit CallbackData(v8::Isolate* isolate) : isolate_(isolate) {}
explicit CallbackData(v8::Isolate* isolate, T* parameter)
: isolate_(isolate), parameter_(parameter) {}
V8_INLINE T* GetParameter() const { return parameter_; }
private:
v8::Isolate* isolate_;
T* parameter_;
};
}
@ -425,23 +428,28 @@ template <class T> class Eternal {
};
template <typename T>
class PhantomCallbackData : public internal::CallbackData {
template <typename T, typename U = void, typename V = void>
class PhantomCallbackData : public internal::CallbackData<T> {
public:
typedef void (*Callback)(const PhantomCallbackData<T>& data);
typedef void (*Callback)(const PhantomCallbackData<T, U, V>& data);
V8_INLINE T* GetParameter() const { return parameter_; }
V8_INLINE U* GetInternalField1() const { return internal_field1_; }
V8_INLINE V* GetInternalField2() const { return internal_field2_; }
PhantomCallbackData<T>(Isolate* isolate, T* parameter)
: internal::CallbackData(isolate), parameter_(parameter) {}
PhantomCallbackData(Isolate* isolate, T* parameter, U* internal_field1,
V* internal_field2)
: internal::CallbackData<T>(isolate, parameter),
internal_field1_(internal_field1),
internal_field2_(internal_field2) {}
private:
T* parameter_;
U* internal_field1_;
V* internal_field2_;
};
template <class T, class P>
class WeakCallbackData : public PhantomCallbackData<P> {
class WeakCallbackData : public internal::CallbackData<P> {
public:
typedef void (*Callback)(const WeakCallbackData<T, P>& data);
@ -450,31 +458,11 @@ class WeakCallbackData : public PhantomCallbackData<P> {
private:
friend class internal::GlobalHandles;
WeakCallbackData(Isolate* isolate, P* parameter, Local<T> handle)
: PhantomCallbackData<P>(isolate, parameter), handle_(handle) {}
: internal::CallbackData<P>(isolate, parameter), handle_(handle) {}
Local<T> handle_;
};
template <typename T, typename U>
class InternalFieldsCallbackData : public internal::CallbackData {
public:
typedef void (*Callback)(const InternalFieldsCallbackData<T, U>& data);
InternalFieldsCallbackData(Isolate* isolate, T* internalField1,
U* internalField2)
: internal::CallbackData(isolate),
internal_field1_(internalField1),
internal_field2_(internalField2) {}
V8_INLINE T* GetInternalField1() const { return internal_field1_; }
V8_INLINE U* GetInternalField2() const { return internal_field2_; }
private:
T* internal_field1_;
U* internal_field2_;
};
/**
* An object reference that is independent of any handle scope. Where
* a Local handle only lives as long as the HandleScope in which it was
@ -562,13 +550,17 @@ template <class T> class PersistentBase {
// specify a parameter for the callback or the location of two internal
// fields in the dying object.
template <typename P>
V8_INLINE void SetPhantom(P* parameter,
typename PhantomCallbackData<P>::Callback callback);
V8_INLINE void SetPhantom(
P* parameter,
typename PhantomCallbackData<P, void, void>::Callback callback);
template <typename P, typename Q>
V8_INLINE void SetPhantom(
void (*callback)(const InternalFieldsCallbackData<P, Q>&),
int internal_field_index1, int internal_field_index2);
P* parameter, int internal_field_index1,
typename PhantomCallbackData<P, Q, void>::Callback callback);
template <typename P, typename Q, typename R>
V8_INLINE void SetPhantom(
P* parameter, int internal_field_index1, int internal_field_index2,
typename PhantomCallbackData<P, Q, R>::Callback callback);
template<typename P>
V8_INLINE P* ClearWeak();
@ -5595,13 +5587,13 @@ class V8_EXPORT V8 {
typedef WeakCallbackData<Value, void>::Callback WeakCallback;
static void MakeWeak(internal::Object** global_handle, void* data,
WeakCallback weak_callback);
static void MakePhantom(internal::Object** global_handle, void* data,
PhantomCallbackData<void>::Callback weak_callback);
static void MakePhantom(
internal::Object** global_handle,
InternalFieldsCallbackData<void, void>::Callback weak_callback,
internal::Object** global_handle, void* data,
// Must be 0 or kNoInternalFieldIndex.
int internal_field_index1,
int internal_field_index2 = Object::kNoInternalFieldIndex);
// Must be 1 or kNoInternalFieldIndex.
int internal_field_index2,
PhantomCallbackData<void, void, void>::Callback weak_callback);
static void* ClearWeak(internal::Object** global_handle);
static void Eternalize(Isolate* isolate,
Value* handle,
@ -6489,22 +6481,36 @@ void PersistentBase<T>::SetWeak(
template <class T>
template <typename P>
void PersistentBase<T>::SetPhantom(
P* parameter, typename PhantomCallbackData<P>::Callback callback) {
typedef typename PhantomCallbackData<void>::Callback Callback;
P* parameter,
typename PhantomCallbackData<P, void, void>::Callback callback) {
typedef typename PhantomCallbackData<void, void, void>::Callback Callback;
V8::MakePhantom(reinterpret_cast<internal::Object**>(this->val_), parameter,
Object::kNoInternalFieldIndex, Object::kNoInternalFieldIndex,
reinterpret_cast<Callback>(callback));
}
template <class T>
template <typename U, typename V>
template <typename P, typename Q>
void PersistentBase<T>::SetPhantom(
void (*callback)(const InternalFieldsCallbackData<U, V>&),
int internal_field_index1, int internal_field_index2) {
typedef typename InternalFieldsCallbackData<void, void>::Callback Callback;
V8::MakePhantom(reinterpret_cast<internal::Object**>(this->val_),
reinterpret_cast<Callback>(callback), internal_field_index1,
internal_field_index2);
P* parameter, int internal_field_index1,
typename PhantomCallbackData<P, Q, void>::Callback callback) {
typedef typename PhantomCallbackData<void, void, void>::Callback Callback;
V8::MakePhantom(reinterpret_cast<internal::Object**>(this->val_), parameter,
internal_field_index1, Object::kNoInternalFieldIndex,
reinterpret_cast<Callback>(callback));
}
template <class T>
template <typename P, typename Q, typename R>
void PersistentBase<T>::SetPhantom(
P* parameter, int internal_field_index1, int internal_field_index2,
typename PhantomCallbackData<P, Q, R>::Callback callback) {
typedef typename PhantomCallbackData<void, void, void>::Callback Callback;
V8::MakePhantom(reinterpret_cast<internal::Object**>(this->val_), parameter,
internal_field_index1, internal_field_index2,
reinterpret_cast<Callback>(callback));
}

View File

@ -408,18 +408,22 @@ void V8::MakeWeak(i::Object** object, void* parameter,
}
void V8::MakePhantom(i::Object** object, void* parameter,
PhantomCallbackData<void>::Callback weak_callback) {
i::GlobalHandles::MakePhantom(object, parameter, weak_callback);
}
void V8::MakePhantom(
i::Object** object,
InternalFieldsCallbackData<void, void>::Callback weak_callback,
int internal_field_index1, int internal_field_index2) {
i::GlobalHandles::MakePhantom(object, weak_callback, internal_field_index1,
internal_field_index2);
i::Object** object, void* parameter, int internal_field_index1,
int internal_field_index2,
PhantomCallbackData<void, void, void>::Callback weak_callback) {
if (internal_field_index1 == 0) {
if (internal_field_index2 == 1) {
i::GlobalHandles::MakePhantom(object, parameter, 2, weak_callback);
} else {
DCHECK_EQ(internal_field_index2, Object::kNoInternalFieldIndex);
i::GlobalHandles::MakePhantom(object, parameter, 1, weak_callback);
}
} else {
DCHECK_EQ(internal_field_index1, Object::kNoInternalFieldIndex);
DCHECK_EQ(internal_field_index2, Object::kNoInternalFieldIndex);
i::GlobalHandles::MakePhantom(object, parameter, 0, weak_callback);
}
}

View File

@ -716,7 +716,7 @@ DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
debug_info_ = Handle<DebugInfo>::cast(global_handles->Create(debug_info));
typedef PhantomCallbackData<void>::Callback Callback;
GlobalHandles::MakePhantom(
reinterpret_cast<Object**>(debug_info_.location()), this,
reinterpret_cast<Object**>(debug_info_.location()), this, 0,
reinterpret_cast<Callback>(Debug::HandlePhantomDebugInfo));
}

View File

@ -203,7 +203,6 @@ class GlobalHandles::Node {
// Callback parameter accessors.
void set_parameter(void* parameter) {
DCHECK(IsInUse());
DCHECK(weakness_type() == NORMAL_WEAK || weakness_type() == PHANTOM_WEAK);
parameter_or_next_free_.parameter = parameter;
}
void* parameter() const {
@ -211,30 +210,6 @@ 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);
// These are stored in an int16_t.
DCHECK(internal_field_index1 < 1 << 16);
DCHECK(internal_field_index1 >= -(1 << 16));
DCHECK(internal_field_index2 < 1 << 16);
DCHECK(internal_field_index2 >= -(1 << 16));
parameter_or_next_free_.internal_field_indeces.internal_field1 =
static_cast<int16_t>(internal_field_index1);
parameter_or_next_free_.internal_field_indeces.internal_field2 =
static_cast<int16_t>(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);
@ -255,23 +230,22 @@ class GlobalHandles::Node {
weak_callback_ = weak_callback;
}
void MakePhantom(void* parameter,
PhantomCallbackData<void>::Callback phantom_callback,
int16_t internal_field_index1,
int16_t internal_field_index2) {
void MakePhantom(void* parameter, int number_of_internal_fields,
PhantomCallbackData<void>::Callback phantom_callback) {
DCHECK(number_of_internal_fields >= 0);
DCHECK(number_of_internal_fields <= 2);
DCHECK(phantom_callback != NULL);
DCHECK(IsInUse());
CHECK(object_ != NULL);
set_state(WEAK);
if (parameter == NULL) {
set_weakness_type(INTERNAL_FIELDS_WEAK);
set_internal_fields(internal_field_index1, internal_field_index2);
if (number_of_internal_fields == 0) {
set_weakness_type(PHANTOM_WEAK_0_INTERNAL_FIELDS);
} else if (number_of_internal_fields == 1) {
set_weakness_type(PHANTOM_WEAK_1_INTERNAL_FIELDS);
} else {
DCHECK(internal_field_index1 == v8::Object::kNoInternalFieldIndex);
DCHECK(internal_field_index2 == v8::Object::kNoInternalFieldIndex);
set_weakness_type(PHANTOM_WEAK);
set_parameter(parameter);
set_weakness_type(PHANTOM_WEAK_2_INTERNAL_FIELDS);
}
set_parameter(parameter);
weak_callback_ = reinterpret_cast<WeakCallback>(phantom_callback);
}
@ -284,63 +258,51 @@ class GlobalHandles::Node {
}
void CollectPhantomCallbackData(
Isolate* isolate, List<PendingPhantomCallback>* pending_phantom_callbacks,
List<PendingInternalFieldsCallback>* pending_internal_fields_callbacks) {
if (state() != Node::PENDING) return;
bool do_release = true;
Isolate* isolate,
List<PendingPhantomCallback>* pending_phantom_callbacks) {
if (state() != PENDING) return;
if (weak_callback_ != NULL) {
if (weakness_type() == NORMAL_WEAK) return;
v8::Isolate* api_isolate = reinterpret_cast<v8::Isolate*>(isolate);
if (weakness_type() == PHANTOM_WEAK) {
// Phantom weak pointer case. Zap with harmless value.
DCHECK(*location() == Smi::FromInt(0));
typedef PhantomCallbackData<void> Data;
DCHECK(weakness_type() == PHANTOM_WEAK_0_INTERNAL_FIELDS ||
weakness_type() == PHANTOM_WEAK_1_INTERNAL_FIELDS ||
weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS);
Data data(api_isolate, parameter());
Data::Callback callback =
reinterpret_cast<Data::Callback>(weak_callback_);
pending_phantom_callbacks->Add(
PendingPhantomCallback(this, data, callback));
// Postpone the release of the handle. The embedder can't use the
// handle (it's zapped), but it may be using the location, and we
// don't want to confuse things by reusing that.
do_release = false;
} else {
DCHECK(weakness_type() == INTERNAL_FIELDS_WEAK);
typedef InternalFieldsCallbackData<void, void> Data;
// Phantom weak pointer case, passing internal fields instead of
// parameter. Don't use a handle here during GC, because it will
// create a handle pointing to a dying object, which can confuse
// the next GC.
Object* internal_field0 = nullptr;
Object* internal_field1 = nullptr;
if (weakness_type() != PHANTOM_WEAK_0_INTERNAL_FIELDS) {
JSObject* jsobject = reinterpret_cast<JSObject*>(object());
DCHECK(jsobject->IsJSObject());
Data data(api_isolate, jsobject->GetInternalField(internal_field1()),
jsobject->GetInternalField(internal_field2()));
Data::Callback callback =
reinterpret_cast<Data::Callback>(weak_callback_);
// 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).
pending_internal_fields_callbacks->Add(
PendingInternalFieldsCallback(data, callback));
DCHECK(jsobject->GetInternalFieldCount() >= 1);
internal_field0 = jsobject->GetInternalField(0);
if (weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS) {
DCHECK(jsobject->GetInternalFieldCount() >= 2);
internal_field1 = jsobject->GetInternalField(1);
}
}
// Zap with harmless value.
*location() = Smi::FromInt(0);
typedef PhantomCallbackData<void, void, void> Data;
if (!internal_field0->IsSmi()) internal_field0 = nullptr;
if (!internal_field1->IsSmi()) internal_field1 = nullptr;
Data data(api_isolate, parameter(), internal_field0, internal_field1);
Data::Callback callback =
reinterpret_cast<Data::Callback>(weak_callback_);
pending_phantom_callbacks->Add(
PendingPhantomCallback(this, data, callback));
DCHECK(IsInUse());
set_state(NEAR_DEATH);
}
// TODO(erikcorry): At the moment the callbacks are not postponed much,
// but if we really postpone them until after the mutator has run, we
// need to divide things up, so that an early callback clears the handle,
// while a later one destroys the objects involved, possibley triggering
// some work when decremented ref counts hit zero.
if (do_release) Release();
}
bool PostGarbageCollectionProcessing(Isolate* isolate) {
// Handles only weak handles (not phantom) that are dying.
if (state() != Node::PENDING) return false;
if (weak_callback_ == NULL) {
Release();
@ -354,11 +316,11 @@ class GlobalHandles::Node {
ExternalOneByteString::cast(object_)->resource() != NULL);
DCHECK(!object_->IsExternalTwoByteString() ||
ExternalTwoByteString::cast(object_)->resource() != NULL);
if (weakness_type() != NORMAL_WEAK) return false;
// Leaving V8.
VMState<EXTERNAL> vmstate(isolate);
HandleScope handle_scope(isolate);
if (weakness_type() == PHANTOM_WEAK) return false;
DCHECK(weakness_type() == NORMAL_WEAK);
Object** object = location();
Handle<Object> handle(*object, isolate);
v8::WeakCallbackData<v8::Value, void> data(
@ -410,10 +372,6 @@ class GlobalHandles::Node {
// the free list link.
union {
void* parameter;
struct {
int16_t internal_field1;
int16_t internal_field2;
} internal_field_indeces;
Node* next_free;
} parameter_or_next_free_;
@ -604,32 +562,21 @@ void GlobalHandles::MakeWeak(Object** location, void* parameter,
}
typedef PhantomCallbackData<void>::Callback GenericCallback;
void GlobalHandles::MakePhantom(
Object** location,
v8::InternalFieldsCallbackData<void, void>::Callback phantom_callback,
int16_t internal_field_index1, int16_t internal_field_index2) {
Node::FromLocation(location)
->MakePhantom(NULL, reinterpret_cast<GenericCallback>(phantom_callback),
internal_field_index1, internal_field_index2);
}
typedef PhantomCallbackData<void, void, void>::Callback GenericCallback;
void GlobalHandles::MakePhantom(Object** location, void* parameter,
int number_of_internal_fields,
GenericCallback phantom_callback) {
Node::FromLocation(location)->MakePhantom(parameter, phantom_callback,
v8::Object::kNoInternalFieldIndex,
v8::Object::kNoInternalFieldIndex);
Node::FromLocation(location)
->MakePhantom(parameter, number_of_internal_fields, phantom_callback);
}
void GlobalHandles::CollectPhantomCallbackData() {
for (NodeIterator it(this); !it.done(); it.Advance()) {
Node* node = it.node();
node->CollectPhantomCallbackData(isolate(), &pending_phantom_callbacks_,
&pending_internal_fields_callbacks_);
node->CollectPhantomCallbackData(isolate(), &pending_phantom_callbacks_);
}
}
@ -668,22 +615,22 @@ void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
for (NodeIterator it(this); !it.done(); it.Advance()) {
Node* node = it.node();
if (node->IsWeakRetainer()) {
// 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.
// Weakness type can be normal or phantom, with or without 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 with no internal fields, 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.
// fields, so we can't zap the handle.
if (node->state() == Node::PENDING) {
if (node->weakness_type() == PHANTOM_WEAK) {
if (node->weakness_type() == PHANTOM_WEAK_0_INTERNAL_FIELDS) {
*(node->location()) = Smi::FromInt(0);
} else if (node->weakness_type() == NORMAL_WEAK) {
v->VisitPointer(node->location());
} else {
DCHECK(node->weakness_type() == INTERNAL_FIELDS_WEAK);
DCHECK(node->weakness_type() == PHANTOM_WEAK_1_INTERNAL_FIELDS ||
node->weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS);
}
} else {
// Node is not pending, so that means the object survived. We still
@ -736,12 +683,13 @@ void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
DCHECK(node->is_in_new_space_list());
if ((node->is_independent() || node->is_partially_dependent()) &&
node->IsWeakRetainer()) {
if (node->weakness_type() == PHANTOM_WEAK) {
if (node->weakness_type() == PHANTOM_WEAK_0_INTERNAL_FIELDS) {
*(node->location()) = Smi::FromInt(0);
} else if (node->weakness_type() == NORMAL_WEAK) {
v->VisitPointer(node->location());
} else {
DCHECK(node->weakness_type() == INTERNAL_FIELDS_WEAK);
DCHECK(node->weakness_type() == PHANTOM_WEAK_1_INTERNAL_FIELDS ||
node->weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS);
// For this case we only need to trace if it's alive: The tracing of
// something that is already alive is just to get the pointer updated
// to the new location of the object).
@ -886,13 +834,9 @@ int GlobalHandles::DispatchPendingPhantomCallbacks() {
int freed_nodes = 0;
while (pending_phantom_callbacks_.length() != 0) {
PendingPhantomCallback callback = pending_phantom_callbacks_.RemoveLast();
DCHECK(callback.node()->IsInUse());
callback.invoke();
freed_nodes++;
}
while (pending_internal_fields_callbacks_.length() != 0) {
PendingInternalFieldsCallback callback =
pending_internal_fields_callbacks_.RemoveLast();
callback.invoke();
DCHECK(!callback.node()->IsInUse());
freed_nodes++;
}
return freed_nodes;

View File

@ -98,9 +98,15 @@ struct ObjectGroupRetainerInfo {
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 // Embedder gets 2 internal fields from dying object.
NORMAL_WEAK, // Embedder gets a handle to the dying object.
// In the following cases, the embedder gets the parameter they passed in
// earlier, and the 0, 1 or 2 first internal fields. Note that the internal
// fields must contain aligned non-V8 pointers. Getting pointers to V8
// objects through this interface would be GC unsafe so in that case the
// embedder gets a null pointer instead.
PHANTOM_WEAK_0_INTERNAL_FIELDS,
PHANTOM_WEAK_1_INTERNAL_FIELDS,
PHANTOM_WEAK_2_INTERNAL_FIELDS
};
@ -139,14 +145,9 @@ class GlobalHandles {
// It would be nice to template this one, but it's really hard to get
// the template instantiator to work right if you do.
static void MakePhantom(Object** location, void* parameter,
PhantomCallbackData<void>::Callback weak_callback);
static void MakePhantom(
Object** location,
v8::InternalFieldsCallbackData<void, void>::Callback weak_callback,
int16_t internal_field_index1,
int16_t internal_field_index2 = v8::Object::kNoInternalFieldIndex);
Object** location, void* parameter, int number_of_internal_fields,
PhantomCallbackData<void, void, void>::Callback weak_callback);
void RecordStats(HeapStats* stats);
@ -302,7 +303,6 @@ class GlobalHandles {
class NodeBlock;
class NodeIterator;
class PendingPhantomCallback;
class PendingInternalFieldsCallback;
Isolate* isolate_;
@ -336,7 +336,6 @@ class GlobalHandles {
List<ObjectGroupConnection> implicit_ref_connections_;
List<PendingPhantomCallback> pending_phantom_callbacks_;
List<PendingInternalFieldsCallback> pending_internal_fields_callbacks_;
friend class Isolate;
@ -346,7 +345,7 @@ class GlobalHandles {
class GlobalHandles::PendingPhantomCallback {
public:
typedef PhantomCallbackData<void> Data;
typedef PhantomCallbackData<void, void, void> Data;
PendingPhantomCallback(Node* node, Data data, Data::Callback callback)
: node_(node), data_(data), callback_(callback) {}
@ -361,20 +360,6 @@ class GlobalHandles::PendingPhantomCallback {
};
class GlobalHandles::PendingInternalFieldsCallback {
public:
typedef InternalFieldsCallbackData<void, void> Data;
PendingInternalFieldsCallback(Data data, Data::Callback callback)
: data_(data), callback_(callback) {}
void invoke() { callback_(data_); }
private:
Data data_;
Data::Callback callback_;
};
class EternalHandles {
public:
enum SingletonHandle {

View File

@ -7796,8 +7796,10 @@ class Trivial2 {
};
void CheckInternalFields(
const v8::InternalFieldsCallbackData<Trivial, Trivial2>& data) {
void CheckInternalFields(const v8::PhantomCallbackData<
v8::Persistent<v8::Object>, Trivial, Trivial2>& data) {
v8::Persistent<v8::Object>* handle = data.GetParameter();
handle->Reset();
Trivial* t1 = data.GetInternalField1();
Trivial2* t2 = data.GetInternalField2();
CHECK_EQ(42, t1->x());
@ -7835,7 +7837,8 @@ void InternalFieldCallback(bool global_gc) {
reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
CHECK_EQ(103, t2->x());
handle.SetPhantom(CheckInternalFields, 0, 1);
handle.SetPhantom<v8::Persistent<v8::Object>, Trivial, Trivial2>(
&handle, 0, 1, CheckInternalFields);
if (!global_gc) {
handle.MarkIndependent();
}