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_;
};
}
};
-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);
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
// 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();
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,
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 P, typename Q>
+void PersistentBase<T>::SetPhantom(
+ 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 U, typename V>
+template <typename P, typename Q, typename R>
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, 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));
}
}
-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);
+ }
}
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));
}
// 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 {
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);
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);
}
}
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();
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(
// 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_;
}
-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_);
}
}
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
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).
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;
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
};
// 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);
class NodeBlock;
class NodeIterator;
class PendingPhantomCallback;
- class PendingInternalFieldsCallback;
Isolate* isolate_;
List<ObjectGroupConnection> implicit_ref_connections_;
List<PendingPhantomCallback> pending_phantom_callbacks_;
- List<PendingInternalFieldsCallback> pending_internal_fields_callbacks_;
friend class Isolate;
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) {}
};
-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 {
};
-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());
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();
}