Revision: 16588
Author: [email protected]
Date: Mon Sep 9 09:25:23 2013 UTC
Log: new persistent semantics
adds copying and autodispose as traits
[email protected], [email protected], [email protected]
BUG=
Review URL: https://codereview.chromium.org/23401003
http://code.google.com/p/v8/source/detail?r=16588
Modified:
/branches/bleeding_edge/include/v8.h
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/global-handles.cc
/branches/bleeding_edge/src/global-handles.h
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/include/v8.h Mon Sep 9 07:52:52 2013 UTC
+++ /branches/bleeding_edge/include/v8.h Mon Sep 9 09:25:23 2013 UTC
@@ -120,7 +120,10 @@
template <class T> class Handle;
template <class T> class Local;
template <class T> class Eternal;
-template <class T> class Persistent;
+template<class T> class NonCopyablePersistentTraits;
+template<class T,
+ class M = NonCopyablePersistentTraits<T> > class Persistent;
+template<class T, class P> class WeakCallbackObject;
class FunctionTemplate;
class ObjectTemplate;
class Data;
@@ -142,6 +145,7 @@
template<typename T> class CustomArguments;
class PropertyCallbackArguments;
class FunctionCallbackArguments;
+class GlobalHandles;
}
@@ -169,27 +173,6 @@
intptr_t data_;
};
-
-// --- Weak Handles ---
-
-
-/**
- * A weak reference callback function.
- *
- * This callback should either explicitly invoke Dispose on |object| if
- * V8 wrapper is not needed anymore, or 'revive' it by invocation of
MakeWeak.
- *
- * \param object the weak global object to be reclaimed by the garbage
collector
- * \param parameter the value passed in when making the weak global object
- */
-template<typename T, typename P>
-class WeakReferenceCallbacks {
- public:
- typedef void (*Revivable)(Isolate* isolate,
- Persistent<T>* object,
- P* parameter);
-};
-
// --- Handles ---
#define TYPE_CHECK(T, S) \
@@ -230,13 +213,6 @@
*/
V8_INLINE(Handle()) : val_(0) {}
-#ifdef V8_USE_UNSAFE_HANDLES
- /**
- * Creates a new handle for the specified value.
- */
- V8_INLINE(explicit Handle(T* val)) : val_(val) {}
-#endif
-
/**
* Creates a handle for the contents of the specified handle. This
* constructor allows you to pass handles as arguments by value and
@@ -285,7 +261,6 @@
return *a == *b;
}
-#ifndef V8_USE_UNSAFE_HANDLES
template <class S> V8_INLINE(
bool operator==(const Persistent<S>& that) const) {
internal::Object** a = reinterpret_cast<internal::Object**>(**this);
@@ -294,7 +269,6 @@
if (b == 0) return false;
return *a == *b;
}
-#endif
/**
* Checks whether two handles are different.
@@ -306,12 +280,10 @@
return !operator==(that);
}
-#ifndef V8_USE_UNSAFE_HANDLES
template <class S> V8_INLINE(
bool operator!=(const Persistent<S>& that) const) {
return !operator==(that);
}
-#endif
template <class S> V8_INLINE(static Handle<T> Cast(Handle<S> that)) {
#ifdef V8_ENABLE_CHECKS
@@ -326,11 +298,9 @@
return Handle<S>::Cast(*this);
}
-#ifndef V8_USE_UNSAFE_HANDLES
V8_INLINE(static Handle<T> New(Isolate* isolate, Handle<T> that)) {
return New(isolate, that.val_);
}
- // TODO(dcarney): remove before cutover
V8_INLINE(static Handle<T> New(Isolate* isolate, const Persistent<T>&
that)) {
return New(isolate, that.val_);
}
@@ -343,11 +313,10 @@
* Creates a new handle for the specified value.
*/
V8_INLINE(explicit Handle(T* val)) : val_(val) {}
-#endif
private:
friend class Utils;
- template<class F> friend class Persistent;
+ template<class F, class M> friend class Persistent;
template<class F> friend class Local;
template<class F> friend class FunctionCallbackInfo;
template<class F> friend class PropertyCallbackInfo;
@@ -359,9 +328,7 @@
friend class Context;
friend class HandleScope;
-#ifndef V8_USE_UNSAFE_HANDLES
V8_INLINE(static Handle<T> New(Isolate* isolate, T* that));
-#endif
T* val_;
};
@@ -374,7 +341,6 @@
* handle scope are destroyed when the handle scope is destroyed. Hence it
* is not necessary to explicitly deallocate local handles.
*/
-// TODO(dcarney): deprecate entire class
template <class T> class Local : public Handle<T> {
public:
V8_INLINE(Local());
@@ -389,10 +355,6 @@
}
-#ifdef V8_USE_UNSAFE_HANDLES
- template <class S> V8_INLINE(Local(S* that) : Handle<T>(that)) { }
-#endif
-
template <class S> V8_INLINE(static Local<T> Cast(Local<S> that)) {
#ifdef V8_ENABLE_CHECKS
// If we're going to perform the type check then we have to check
@@ -401,12 +363,10 @@
#endif
return Local<T>(T::Cast(*that));
}
-#ifndef V8_USE_UNSAFE_HANDLES
template <class S> V8_INLINE(Local(Handle<S> that))
: Handle<T>(reinterpret_cast<T*>(*that)) {
TYPE_CHECK(T, S);
}
-#endif
template <class S> V8_INLINE(Local<S> As()) {
return Local<S>::Cast(*this);
@@ -419,21 +379,20 @@
*/
V8_INLINE(static Local<T> New(Handle<T> that));
V8_INLINE(static Local<T> New(Isolate* isolate, Handle<T> that));
-#ifndef V8_USE_UNSAFE_HANDLES
- // TODO(dcarney): remove before cutover
- V8_INLINE(static Local<T> New(Isolate* isolate, const Persistent<T>&
that));
+ template<class M>
+ V8_INLINE(static Local<T> New(Isolate* isolate,
+ const Persistent<T, M>& that));
#ifndef V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
private:
#endif
template <class S> V8_INLINE(Local(S* that) : Handle<T>(that)) { }
-#endif
private:
friend class Utils;
template<class F> friend class Eternal;
- template<class F> friend class Persistent;
+ template<class F, class M> friend class Persistent;
template<class F> friend class Handle;
template<class F> friend class FunctionCallbackInfo;
template<class F> friend class PropertyCallbackInfo;
@@ -468,6 +427,61 @@
};
+template<class T, class P>
+class WeakCallbackData {
+ public:
+ typedef void (*Callback)(const WeakCallbackData<T, P>& data);
+
+ V8_INLINE(Isolate* GetIsolate()) const { return isolate_; }
+ V8_INLINE(Local<T> GetValue()) const { return handle_; }
+ V8_INLINE(P* GetParameter()) const { return parameter_; }
+
+ private:
+ friend class internal::GlobalHandles;
+ WeakCallbackData(Isolate* isolate, Local<T> handle, P* parameter)
+ : isolate_(isolate), handle_(handle), parameter_(parameter) { }
+ Isolate* isolate_;
+ Local<T> handle_;
+ P* parameter_;
+};
+
+
+// TODO(dcarney): Remove this class.
+template<typename T,
+ typename P,
+ typename M = NonCopyablePersistentTraits<T> >
+class WeakReferenceCallbacks {
+ public:
+ typedef void (*Revivable)(Isolate* isolate,
+ Persistent<T, M>* object,
+ P* parameter);
+};
+
+
+/**
+ * Default traits for Persistent. This class does not allow
+ * use of the copy constructor or assignment operator.
+ * At present kResetInDestructor is not set, but that will change in a
future
+ * version.
+ */
+template<class T>
+class NonCopyablePersistentTraits {
+ public:
+ typedef Persistent<T, NonCopyablePersistentTraits<T> >
NonCopyablePersistent;
+ static const bool kResetInDestructor = false;
+ template<class S, class M>
+ V8_INLINE(static void Copy(const Persistent<S, M>& source,
+ NonCopyablePersistent* dest)) {
+ Uncompilable<Object>();
+ }
+ // TODO(dcarney): come up with a good compile error here.
+ template<class O>
+ V8_INLINE(static void Uncompilable()) {
+ TYPE_CHECK(O, Primitive);
+ }
+};
+
+
/**
* 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
@@ -477,106 +491,92 @@
* A persistent handle contains a reference to a storage cell within
* the v8 engine which holds an object value and which is updated by
* the garbage collector whenever the object is moved. A new storage
- * cell can be created using Persistent::New and existing handles can
- * be disposed using Persistent::Dispose. Since persistent handles
- * are passed by value you may have many persistent handle objects
- * that point to the same storage cell. For instance, if you pass a
- * persistent handle as an argument to a function you will not get two
- * different storage cells but rather two references to the same
- * storage cell.
+ * cell can be created using the constructor or Persistent::Reset and
+ * existing handles can be disposed using Persistent::Reset.
+ *
+ * Copy, assignment and destructor bevavior is controlled by the traits
+ * class M.
*/
-template <class T> class Persistent // NOLINT
-#ifdef V8_USE_UNSAFE_HANDLES
- : public Handle<T> {
-#else
- { // NOLINT
-#endif
+template <class T, class M> class Persistent {
public:
-#ifndef V8_USE_UNSAFE_HANDLES
+ /**
+ * A Persistent with no storage cell.
+ */
V8_INLINE(Persistent()) : val_(0) { }
- // TODO(dcarney): add this back before cutover.
-// V8_INLINE(~Persistent()) {
-// Dispose();
-// }
- V8_INLINE(bool IsEmpty() const) { return val_ == 0; }
- // TODO(dcarney): remove somehow before cutover
- // The handle should either be 0, or a pointer to a live cell.
- V8_INLINE(void Clear()) { val_ = 0; }
-
/**
- * A constructor that creates a new global cell pointing to that. In
contrast
- * to the copy constructor, this creates a new persistent handle which
needs
- * to be separately disposed.
+ * Construct a Persistent from a Handle.
+ * When the Handle is non-empty, a new storage cell is created
+ * pointing to the same object, and no flags are set.
*/
template <class S> V8_INLINE(Persistent(Isolate* isolate, Handle<S>
that))
- : val_(New(isolate, *that)) { }
-
- template <class S> V8_INLINE(Persistent(Isolate* isolate,
- const Persistent<S>& that)) //
NOLINT
- : val_(New(isolate, *that)) { }
-
-#else
+ : val_(New(isolate, *that)) {
+ TYPE_CHECK(T, S);
+ }
+ /**
+ * Construct a Persistent from a Persistent.
+ * When the Persistent is non-empty, a new storage cell is created
+ * pointing to the same object, and no flags are set.
+ */
+ template <class S, class M2>
+ V8_INLINE(Persistent(Isolate* isolate, const Persistent<S, M2>& that))
+ : val_(New(isolate, *that)) {
+ TYPE_CHECK(T, S);
+ }
/**
- * Creates an empty persistent handle that doesn't point to any
- * storage cell.
+ * The copy constructors and assignment operator create a Persistent
+ * exactly as the Persistent constructor, but the Copy function from the
+ * traits class is called, allowing the setting of flags based on the
+ * copied Persistent.
*/
- V8_INLINE(Persistent()) : Handle<T>() { }
-
+ V8_INLINE(Persistent(const Persistent& that)) : val_(0) {
+ Copy(that);
+ }
+ template <class S, class M2>
+ V8_INLINE(Persistent(const Persistent<S, M2>& that)) : val_(0) {
+ Copy(that);
+ }
+ V8_INLINE(Persistent& operator=(const Persistent& that)) { // NOLINT
+ Copy(that);
+ return *this;
+ }
+ template <class S, class M2>
+ V8_INLINE(Persistent& operator=(const Persistent<S, M2>& that)) { //
NOLINT
+ Copy(that);
+ return *this;
+ }
/**
- * Creates a persistent handle for the same storage cell as the
- * specified handle. This constructor allows you to pass persistent
- * handles as arguments by value and to assign between persistent
- * handles. However, attempting to assign between incompatible
- * persistent handles, for instance from a Persistent<String> to a
- * Persistent<Number> will cause a compile-time error. Assigning
- * between compatible persistent handles, for instance assigning a
- * Persistent<String> to a variable declared as Persistent<Value>,
- * is allowed as String is a subclass of Value.
+ * The destructor will dispose the Persistent based on the
+ * kResetInDestructor flags in the traits class. Since not calling
dispose
+ * can result in a memory leak, it is recommended to always set this
flag.
*/
- template <class S> V8_INLINE(Persistent(Persistent<S> that))
- : Handle<T>(reinterpret_cast<T*>(*that)) {
- /**
- * This check fails when trying to convert between incompatible
- * handles. For example, converting from a Handle<String> to a
- * Handle<Number>.
- */
- TYPE_CHECK(T, S);
+ V8_INLINE(~Persistent()) {
+ if (M::kResetInDestructor) Reset();
}
- template <class S> V8_INLINE(Persistent(S* that)) : Handle<T>(that) { }
-
+ /**
+ * If non-empty, destroy the underlying storage cell
+ * IsEmpty() will return true after this call.
+ */
+ V8_INLINE(void Reset());
+ template <class S>
/**
- * A constructor that creates a new global cell pointing to that. In
contrast
- * to the copy constructor, this creates a new persistent handle which
needs
- * to be separately disposed.
+ * If non-empty, destroy the underlying storage cell
+ * and create a new one with the contents of other if other is non empty
*/
- template <class S> V8_INLINE(Persistent(Isolate* isolate, Handle<S>
that))
- : Handle<T>(New(isolate, that)) { }
-
+ V8_INLINE(void Reset(Isolate* isolate, const Handle<S>& other));
/**
- * "Casts" a plain handle which is known to be a persistent handle
- * to a persistent handle.
+ * If non-empty, destroy the underlying storage cell
+ * and create a new one with the contents of other if other is non empty
*/
- template <class S> explicit V8_INLINE(Persistent(Handle<S> that))
- : Handle<T>(*that) { }
-
-#endif
-
-#ifdef V8_USE_UNSAFE_HANDLES
- template <class S> V8_INLINE(static Persistent<T> Cast(Persistent<S>
that)) {
-#ifdef V8_ENABLE_CHECKS
- // If we're going to perform the type check then we have to check
- // that the handle isn't empty before doing the checked cast.
- if (that.IsEmpty()) return Persistent<T>();
-#endif
- return Persistent<T>(T::Cast(*that));
- }
+ template <class S, class M2>
+ V8_INLINE(void Reset(Isolate* isolate, const Persistent<S, M2>& other));
+ // TODO(dcarney): deprecate
+ V8_INLINE(void Dispose()) { Reset(); }
+ V8_DEPRECATED(V8_INLINE(void Dispose(Isolate* isolate))) { Reset(); }
- template <class S> V8_INLINE(Persistent<S> As()) {
- return Persistent<S>::Cast(*this);
- }
+ V8_INLINE(bool IsEmpty() const) { return val_ == 0; }
-#else
+ // TODO(dcarney): this is pretty useless, fix or remove
template <class S>
V8_INLINE(static Persistent<T>& Cast(Persistent<S>& that)) { // NOLINT
#ifdef V8_ENABLE_CHECKS
@@ -587,20 +587,13 @@
return reinterpret_cast<Persistent<T>&>(that);
}
+ // TODO(dcarney): this is pretty useless, fix or remove
template <class S> V8_INLINE(Persistent<S>& As()) { // NOLINT
return Persistent<S>::Cast(*this);
}
-#endif
-
-#ifdef V8_USE_UNSAFE_HANDLES
- V8_DEPRECATED(static Persistent<T> New(Handle<T> that));
- V8_INLINE(static Persistent<T> New(Isolate* isolate, Handle<T> that));
- V8_INLINE(static Persistent<T> New(Isolate* isolate, Persistent<T>
that));
-#endif
-#ifndef V8_USE_UNSAFE_HANDLES
- template <class S> V8_INLINE(
- bool operator==(const Persistent<S>& that) const) {
+ template <class S, class M2> V8_INLINE(
+ bool operator==(const Persistent<S, M2>& that) const) {
internal::Object** a = reinterpret_cast<internal::Object**>(**this);
internal::Object** b = reinterpret_cast<internal::Object**>(*that);
if (a == 0) return b == 0;
@@ -616,54 +609,37 @@
return *a == *b;
}
- template <class S> V8_INLINE(
- bool operator!=(const Persistent<S>& that) const) {
+ template <class S, class M2> V8_INLINE(
+ bool operator!=(const Persistent<S, M2>& that) const) {
return !operator==(that);
}
template <class S> V8_INLINE(bool operator!=(const Handle<S>& that)
const) {
return !operator==(that);
}
-#endif
- V8_INLINE(void Dispose());
+ template<typename P>
+ V8_INLINE(void SetWeak(
+ P* parameter,
+ typename WeakCallbackData<T, P>::Callback callback));
- /**
- * Releases the storage cell referenced by this persistent handle.
- * Does not remove the reference to the cell from any handles.
- * This handle's reference, and any other references to the storage
- * cell remain and IsEmpty will still return false.
- */
- V8_DEPRECATED(V8_INLINE(void Dispose(Isolate* isolate))) { Dispose(); }
+ template<typename S, typename P>
+ V8_INLINE(void SetWeak(
+ P* parameter,
+ typename WeakCallbackData<S, P>::Callback callback));
- /**
- * Make the reference to this object weak. When only weak handles
- * refer to the object, the garbage collector will perform a
- * callback to the given V8::NearDeathCallback function, passing
- * it the object reference and the given parameters.
- */
+ // TODO(dcarney): deprecate
template<typename S, typename P>
V8_INLINE(void MakeWeak(
- P* parameters,
+ P* parameter,
typename WeakReferenceCallbacks<S, P>::Revivable callback));
+ // TODO(dcarney): deprecate
template<typename P>
V8_INLINE(void MakeWeak(
- P* parameters,
+ P* parameter,
typename WeakReferenceCallbacks<T, P>::Revivable callback));
- template<typename S, typename P>
- V8_DEPRECATED(void MakeWeak(
- Isolate* isolate,
- P* parameters,
- typename WeakReferenceCallbacks<S, P>::Revivable callback));
-
- template<typename P>
- V8_DEPRECATED(void MakeWeak(
- Isolate* isolate,
- P* parameters,
- typename WeakReferenceCallbacks<T, P>::Revivable callback));
-
V8_INLINE(void ClearWeak());
V8_DEPRECATED(V8_INLINE(void ClearWeak(Isolate* isolate))) {
ClearWeak(); }
@@ -735,68 +711,35 @@
return WrapperClassId();
}
- /**
- * Disposes the current contents of the handle and replaces it.
- */
- V8_INLINE(void Reset(Isolate* isolate, const Handle<T>& other));
-
-#ifndef V8_USE_UNSAFE_HANDLES
- V8_INLINE(void Reset(Isolate* isolate, const Persistent<T>& other));
-#endif
-
- /**
- * Returns the underlying raw pointer and clears the handle. The caller
is
- * responsible of eventually destroying the underlying object (by
creating a
- * Persistent handle which points to it and Disposing it). In the future,
- * destructing a Persistent will also Dispose it. With this function, the
- * embedder can let the Persistent go out of scope without it getting
- * disposed.
- */
+ // TODO(dcarney): remove
V8_INLINE(T* ClearAndLeak());
-#ifndef V8_USE_UNSAFE_HANDLES
-
- private:
- // TODO(dcarney): make unlinkable before cutover
- V8_INLINE(Persistent(const Persistent& that)) : val_(that.val_) {}
- // TODO(dcarney): make unlinkable before cutover
- V8_INLINE(Persistent& operator=(const Persistent& that)) { // NOLINT
- this->val_ = that.val_;
- return *this;
- }
+ // TODO(dcarney): remove
+ V8_INLINE(void Clear()) { val_ = 0; }
- public:
+ // TODO(dcarney): remove
#ifndef V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
private:
#endif
- // TODO(dcarney): remove before cutover
template <class S> V8_INLINE(Persistent(S* that)) : val_(that) { }
- // TODO(dcarney): remove before cutover
V8_INLINE(T* operator*() const) { return val_; }
-
- private:
- // TODO(dcarney): remove before cutover
- V8_INLINE(T* operator->() const) { return val_; }
- public:
-#endif
private:
friend class Utils;
template<class F> friend class Handle;
template<class F> friend class Local;
- template<class F> friend class Persistent;
+ template<class F1, class F2> friend class Persistent;
template<class F> friend class ReturnValue;
V8_INLINE(static T* New(Isolate* isolate, T* that));
+ template<class S, class M2>
+ V8_INLINE(void Copy(const Persistent<S, M2>& that));
-#ifndef V8_USE_UNSAFE_HANDLES
T* val_;
-#endif
};
-
/**
* A stack-allocated class that governs a number of local handles.
* After a handle scope has been created, all local handles will be
@@ -4719,10 +4662,13 @@
static internal::Object** GlobalizeReference(internal::Isolate* isolate,
internal::Object** handle);
+ static internal::Object** CopyPersistent(internal::Object** handle);
static void DisposeGlobal(internal::Object** global_handle);
typedef WeakReferenceCallbacks<Value, void>::Revivable RevivableCallback;
+ typedef WeakCallbackData<Value, void>::Callback WeakCallback;
static void MakeWeak(internal::Object** global_handle,
void* data,
+ WeakCallback weak_callback,
RevivableCallback weak_reference_callback);
static void ClearWeak(internal::Object** global_handle);
static void Eternalize(Isolate* isolate,
@@ -4733,7 +4679,7 @@
template <class T> friend class Handle;
template <class T> friend class Local;
template <class T> friend class Eternal;
- template <class T> friend class Persistent;
+ template <class T, class M> friend class Persistent;
friend class Context;
};
@@ -5074,11 +5020,7 @@
}
// TODO(dcarney): deprecate
V8_INLINE(Scope(Isolate* isolate, Persistent<Context>& context)) //
NOLINT
-#ifndef V8_USE_UNSAFE_HANDLES
: context_(Handle<Context>::New(isolate, context)) {
-#else
- : context_(Local<Context>::New(isolate, context)) {
-#endif
context_->Enter();
}
V8_INLINE(~Scope()) { context_->Exit(); }
@@ -5568,9 +5510,9 @@
return New(isolate, that.val_);
}
-#ifndef V8_USE_UNSAFE_HANDLES
template <class T>
-Local<T> Local<T>::New(Isolate* isolate, const Persistent<T>& that) {
+template <class M>
+Local<T> Local<T>::New(Isolate* isolate, const Persistent<T, M>& that) {
return New(isolate, that.val_);
}
@@ -5582,7 +5524,6 @@
return Handle<T>(reinterpret_cast<T*>(HandleScope::CreateHandle(
reinterpret_cast<internal::Isolate*>(isolate), *p)));
}
-#endif
template <class T>
@@ -5609,27 +5550,8 @@
}
-#ifdef V8_USE_UNSAFE_HANDLES
-template <class T>
-Persistent<T> Persistent<T>::New(Handle<T> that) {
- return New(Isolate::GetCurrent(), that.val_);
-}
-
-
-template <class T>
-Persistent<T> Persistent<T>::New(Isolate* isolate, Handle<T> that) {
- return New(Isolate::GetCurrent(), that.val_);
-}
-
-template <class T>
-Persistent<T> Persistent<T>::New(Isolate* isolate, Persistent<T> that) {
- return New(Isolate::GetCurrent(), that.val_);
-}
-#endif
-
-
-template <class T>
-T* Persistent<T>::New(Isolate* isolate, T* that) {
+template <class T, class M>
+T* Persistent<T, M>::New(Isolate* isolate, T* that) {
if (that == NULL) return NULL;
internal::Object** p = reinterpret_cast<internal::Object**>(that);
return reinterpret_cast<T*>(
@@ -5638,8 +5560,20 @@
}
-template <class T>
-bool Persistent<T>::IsIndependent() const {
+template <class T, class M>
+template <class S, class M2>
+void Persistent<T, M>::Copy(const Persistent<S, M2>& that) {
+ TYPE_CHECK(T, S);
+ Reset();
+ if (that.IsEmpty()) return;
+ internal::Object** p = reinterpret_cast<internal::Object**>(that.val_);
+ this->val_ = reinterpret_cast<T*>(V8::CopyPersistent(p));
+ M::Copy(that, this);
+}
+
+
+template <class T, class M>
+bool Persistent<T, M>::IsIndependent() const {
typedef internal::Internals I;
if (this->IsEmpty()) return false;
return I::GetNodeFlag(reinterpret_cast<internal::Object**>(this->val_),
@@ -5647,8 +5581,8 @@
}
-template <class T>
-bool Persistent<T>::IsNearDeath() const {
+template <class T, class M>
+bool Persistent<T, M>::IsNearDeath() const {
typedef internal::Internals I;
if (this->IsEmpty()) return false;
uint8_t node_state =
@@ -5658,8 +5592,8 @@
}
-template <class T>
-bool Persistent<T>::IsWeak() const {
+template <class T, class M>
+bool Persistent<T, M>::IsWeak() const {
typedef internal::Internals I;
if (this->IsEmpty()) return false;
return I::GetNodeState(reinterpret_cast<internal::Object**>(this->val_))
==
@@ -5667,66 +5601,89 @@
}
-template <class T>
-void Persistent<T>::Dispose() {
+template <class T, class M>
+void Persistent<T, M>::Reset() {
if (this->IsEmpty()) return;
V8::DisposeGlobal(reinterpret_cast<internal::Object**>(this->val_));
-#ifndef V8_USE_UNSAFE_HANDLES
val_ = 0;
-#endif
}
-template <class T>
+template <class T, class M>
+template <class S>
+void Persistent<T, M>::Reset(Isolate* isolate, const Handle<S>& other) {
+ TYPE_CHECK(T, S);
+ Reset();
+ if (other.IsEmpty()) return;
+ this->val_ = New(isolate, other.val_);
+}
+
+
+template <class T, class M>
+template <class S, class M2>
+void Persistent<T, M>::Reset(Isolate* isolate,
+ const Persistent<S, M2>& other) {
+ TYPE_CHECK(T, S);
+ Reset();
+ if (other.IsEmpty()) return;
+ this->val_ = New(isolate, other.val_);
+}
+
+
+template <class T, class M>
template <typename S, typename P>
-void Persistent<T>::MakeWeak(
- P* parameters,
- typename WeakReferenceCallbacks<S, P>::Revivable callback) {
+void Persistent<T, M>::SetWeak(
+ P* parameter,
+ typename WeakCallbackData<S, P>::Callback callback) {
TYPE_CHECK(S, T);
- typedef typename WeakReferenceCallbacks<Value, void>::Revivable
Revivable;
+ typedef typename WeakCallbackData<Value, void>::Callback Callback;
V8::MakeWeak(reinterpret_cast<internal::Object**>(this->val_),
- parameters,
- reinterpret_cast<Revivable>(callback));
+ parameter,
+ reinterpret_cast<Callback>(callback),
+ NULL);
}
-template <class T>
+template <class T, class M>
template <typename P>
-void Persistent<T>::MakeWeak(
- P* parameters,
- typename WeakReferenceCallbacks<T, P>::Revivable callback) {
- MakeWeak<T, P>(parameters, callback);
+void Persistent<T, M>::SetWeak(
+ P* parameter,
+ typename WeakCallbackData<T, P>::Callback callback) {
+ SetWeak<T, P>(parameter, callback);
}
-template <class T>
+template <class T, class M>
template <typename S, typename P>
-void Persistent<T>::MakeWeak(
- Isolate* isolate,
+void Persistent<T, M>::MakeWeak(
P* parameters,
typename WeakReferenceCallbacks<S, P>::Revivable callback) {
- MakeWeak<S, P>(parameters, callback);
+ TYPE_CHECK(S, T);
+ typedef typename WeakReferenceCallbacks<Value, void>::Revivable
Revivable;
+ V8::MakeWeak(reinterpret_cast<internal::Object**>(this->val_),
+ parameters,
+ NULL,
+ reinterpret_cast<Revivable>(callback));
}
-template <class T>
-template<typename P>
-void Persistent<T>::MakeWeak(
- Isolate* isolate,
+template <class T, class M>
+template <typename P>
+void Persistent<T, M>::MakeWeak(
P* parameters,
typename WeakReferenceCallbacks<T, P>::Revivable callback) {
- MakeWeak<P>(parameters, callback);
+ MakeWeak<T, P>(parameters, callback);
}
-template <class T>
-void Persistent<T>::ClearWeak() {
+template <class T, class M>
+void Persistent<T, M>::ClearWeak() {
V8::ClearWeak(reinterpret_cast<internal::Object**>(this->val_));
}
-template <class T>
-void Persistent<T>::MarkIndependent() {
+template <class T, class M>
+void Persistent<T, M>::MarkIndependent() {
typedef internal::Internals I;
if (this->IsEmpty()) return;
I::UpdateNodeFlag(reinterpret_cast<internal::Object**>(this->val_),
@@ -5735,64 +5692,27 @@
}
-template <class T>
-void Persistent<T>::MarkPartiallyDependent() {
+template <class T, class M>
+void Persistent<T, M>::MarkPartiallyDependent() {
typedef internal::Internals I;
if (this->IsEmpty()) return;
I::UpdateNodeFlag(reinterpret_cast<internal::Object**>(this->val_),
true,
I::kNodeIsPartiallyDependentShift);
}
-
-
-template <class T>
-void Persistent<T>::Reset(Isolate* isolate, const Handle<T>& other) {
- Dispose();
-#ifdef V8_USE_UNSAFE_HANDLES
- *this = *New(isolate, other);
-#else
- if (other.IsEmpty()) {
- this->val_ = NULL;
- return;
- }
- internal::Object** p = reinterpret_cast<internal::Object**>(other.val_);
- this->val_ = reinterpret_cast<T*>(
-
V8::GlobalizeReference(reinterpret_cast<internal::Isolate*>(isolate), p));
-#endif
-}
-
-
-#ifndef V8_USE_UNSAFE_HANDLES
-template <class T>
-void Persistent<T>::Reset(Isolate* isolate, const Persistent<T>& other) {
- Dispose();
- if (other.IsEmpty()) {
- this->val_ = NULL;
- return;
- }
- internal::Object** p = reinterpret_cast<internal::Object**>(other.val_);
- this->val_ = reinterpret_cast<T*>(
-
V8::GlobalizeReference(reinterpret_cast<internal::Isolate*>(isolate), p));
-}
-#endif
-template <class T>
-T* Persistent<T>::ClearAndLeak() {
+template <class T, class M>
+T* Persistent<T, M>::ClearAndLeak() {
T* old;
-#ifdef V8_USE_UNSAFE_HANDLES
- old = **this;
- *this = Persistent<T>();
-#else
old = val_;
val_ = NULL;
-#endif
return old;
}
-template <class T>
-void Persistent<T>::SetWrapperClassId(uint16_t class_id) {
+template <class T, class M>
+void Persistent<T, M>::SetWrapperClassId(uint16_t class_id) {
typedef internal::Internals I;
if (this->IsEmpty()) return;
internal::Object** obj =
reinterpret_cast<internal::Object**>(this->val_);
@@ -5801,8 +5721,8 @@
}
-template <class T>
-uint16_t Persistent<T>::WrapperClassId() const {
+template <class T, class M>
+uint16_t Persistent<T, M>::WrapperClassId() const {
typedef internal::Internals I;
if (this->IsEmpty()) return 0;
internal::Object** obj =
reinterpret_cast<internal::Object**>(this->val_);
=======================================
--- /branches/bleeding_edge/src/api.cc Mon Sep 9 07:52:52 2013 UTC
+++ /branches/bleeding_edge/src/api.cc Mon Sep 9 09:25:23 2013 UTC
@@ -658,13 +658,24 @@
#endif // DEBUG
return result.location();
}
+
+
+i::Object** V8::CopyPersistent(i::Object** obj) {
+ i::Handle<i::Object> result = i::GlobalHandles::CopyGlobal(obj);
+#ifdef DEBUG
+ (*obj)->Verify();
+#endif // DEBUG
+ return result.location();
+}
void V8::MakeWeak(i::Object** object,
void* parameters,
+ WeakCallback weak_callback,
RevivableCallback weak_reference_callback) {
i::GlobalHandles::MakeWeak(object,
parameters,
+ weak_callback,
weak_reference_callback);
}
@@ -5434,26 +5445,6 @@
return env;
}
-
-#ifdef V8_USE_UNSAFE_HANDLES
-Persistent<Context> v8::Context::New(
- v8::ExtensionConfiguration* extensions,
- v8::Handle<ObjectTemplate> global_template,
- v8::Handle<Value> global_object) {
- i::Isolate::EnsureDefaultIsolate();
- i::Isolate* isolate = i::Isolate::Current();
- Isolate* external_isolate = reinterpret_cast<Isolate*>(isolate);
- EnsureInitializedForIsolate(isolate, "v8::Context::New()");
- LOG_API(isolate, "Context::New");
- ON_BAILOUT(isolate, "v8::Context::New()", return Persistent<Context>());
- i::HandleScope scope(isolate);
- i::Handle<i::Context> env =
- CreateEnvironment(isolate, extensions, global_template,
global_object);
- if (env.is_null()) return Persistent<Context>();
- return Persistent<Context>::New(external_isolate, Utils::ToLocal(env));
-}
-#endif
-
Local<Context> v8::Context::New(
v8::Isolate* external_isolate,
=======================================
--- /branches/bleeding_edge/src/global-handles.cc Thu Aug 29 15:03:37 2013
UTC
+++ /branches/bleeding_edge/src/global-handles.cc Mon Sep 9 09:25:23 2013
UTC
@@ -90,7 +90,7 @@
set_partially_dependent(false);
set_in_new_space_list(false);
parameter_or_next_free_.next_free = NULL;
- weak_reference_callback_ = NULL;
+ weak_callback_ = NULL;
}
#endif
@@ -111,7 +111,7 @@
set_partially_dependent(false);
set_state(NORMAL);
parameter_or_next_free_.parameter = NULL;
- weak_reference_callback_ = NULL;
+ weak_callback_ = NULL;
IncreaseBlockUses();
}
@@ -123,7 +123,7 @@
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
set_independent(false);
set_partially_dependent(false);
- weak_reference_callback_ = NULL;
+ weak_callback_ = NULL;
DecreaseBlockUses();
}
@@ -168,6 +168,13 @@
void set_in_new_space_list(bool v) {
flags_ = IsInNewSpaceList::update(flags_, v);
}
+
+ bool is_revivable_callback() {
+ return IsRevivableCallback::decode(flags_);
+ }
+ void set_revivable_callback(bool v) {
+ flags_ = IsRevivableCallback::update(flags_, v);
+ }
bool IsNearDeath() const {
// Check for PENDING to ensure correct answer when processing
callbacks.
@@ -228,11 +235,20 @@
}
void MakeWeak(void* parameter,
- RevivableCallback weak_reference_callback) {
+ WeakCallback weak_callback,
+ RevivableCallback revivable_callback) {
+ ASSERT((weak_callback == NULL) != (revivable_callback == NULL));
ASSERT(state() != FREE);
set_state(WEAK);
set_parameter(parameter);
- weak_reference_callback_ = weak_reference_callback;
+ if (weak_callback != NULL) {
+ weak_callback_ = weak_callback;
+ set_revivable_callback(false);
+ } else {
+ weak_callback_ =
+ reinterpret_cast<WeakCallback>(revivable_callback);
+ set_revivable_callback(true);
+ }
}
void ClearWeakness() {
@@ -243,7 +259,7 @@
bool PostGarbageCollectionProcessing(Isolate* isolate) {
if (state() != Node::PENDING) return false;
- if (weak_reference_callback_ == NULL) {
+ if (weak_callback_ == NULL) {
Release();
return false;
}
@@ -262,19 +278,31 @@
// Leaving V8.
VMState<EXTERNAL> state(isolate);
HandleScope handle_scope(isolate);
- weak_reference_callback_(reinterpret_cast<v8::Isolate*>(isolate),
-
reinterpret_cast<Persistent<Value>*>(&object),
- par);
+ if (is_revivable_callback()) {
+ RevivableCallback revivable =
+ reinterpret_cast<RevivableCallback>(weak_callback_);
+ revivable(reinterpret_cast<v8::Isolate*>(isolate),
+ reinterpret_cast<Persistent<Value>*>(&object),
+ par);
+ } else {
+ Handle<Object> handle(*object, isolate);
+ v8::WeakCallbackData<v8::Value, void> data(
+ reinterpret_cast<v8::Isolate*>(isolate),
+ v8::Utils::ToLocal(handle),
+ par);
+ weak_callback_(data);
+ }
}
// Absence of explicit cleanup or revival of weak handle
// in most of the cases would lead to memory leak.
ASSERT(state() != NEAR_DEATH);
return true;
}
+
+ inline GlobalHandles* GetGlobalHandles();
private:
inline NodeBlock* FindBlock();
- inline GlobalHandles* GetGlobalHandles();
inline void IncreaseBlockUses();
inline void DecreaseBlockUses();
@@ -297,11 +325,12 @@
class IsIndependent: public BitField<bool, 4, 1> {};
class IsPartiallyDependent: public BitField<bool, 5, 1> {};
class IsInNewSpaceList: public BitField<bool, 6, 1> {};
+ class IsRevivableCallback: public BitField<bool, 7, 1> {};
uint8_t flags_;
// Handle specific callback - might be a weak reference in disguise.
- RevivableCallback weak_reference_callback_;
+ WeakCallback weak_callback_;
// Provided data for callback. In FREE state, this is used for
// the free list link.
@@ -478,6 +507,12 @@
}
return result->handle();
}
+
+
+Handle<Object> GlobalHandles::CopyGlobal(Object** location) {
+ ASSERT(location != NULL);
+ return
Node::FromLocation(location)->GetGlobalHandles()->Create(*location);
+}
void GlobalHandles::Destroy(Object** location) {
@@ -487,9 +522,10 @@
void GlobalHandles::MakeWeak(Object** location,
void* parameter,
- RevivableCallback weak_reference_callback) {
- ASSERT(weak_reference_callback != NULL);
- Node::FromLocation(location)->MakeWeak(parameter,
weak_reference_callback);
+ WeakCallback weak_callback,
+ RevivableCallback revivable_callback) {
+ Node::FromLocation(location)->MakeWeak(
+ parameter, weak_callback, revivable_callback);
}
=======================================
--- /branches/bleeding_edge/src/global-handles.h Mon Aug 26 09:41:22 2013
UTC
+++ /branches/bleeding_edge/src/global-handles.h Mon Sep 9 09:25:23 2013
UTC
@@ -128,9 +128,13 @@
// Creates a new global handle that is alive until Destroy is called.
Handle<Object> Create(Object* value);
+ // Copy a global handle
+ static Handle<Object> CopyGlobal(Object** location);
+
// Destroy a global handle.
static void Destroy(Object** location);
+ typedef WeakCallbackData<v8::Value, void>::Callback WeakCallback;
typedef WeakReferenceCallbacks<v8::Value, void>::Revivable
RevivableCallback;
// Make the global handle weak and set the callback parameter for the
@@ -141,7 +145,14 @@
// reason is that Smi::FromInt(0) does not change during garage
collection.
static void MakeWeak(Object** location,
void* parameter,
- RevivableCallback weak_reference_callback);
+ WeakCallback weak_callback,
+ RevivableCallback revivable_callback);
+
+ static inline void MakeWeak(Object** location,
+ void* parameter,
+ RevivableCallback revivable_callback) {
+ MakeWeak(location, parameter, NULL, revivable_callback);
+ }
void RecordStats(HeapStats* stats);
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Mon Sep 9 07:52:52
2013 UTC
+++ /branches/bleeding_edge/test/cctest/test-api.cc Mon Sep 9 09:25:23
2013 UTC
@@ -3246,13 +3246,8 @@
v8::HandleScope scope(isolate);
v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
v8::Persistent<String> global_string(isolate, local);
-#ifdef V8_USE_UNSAFE_HANDLES
- v8::Persistent<Value> global_value =
- v8::Persistent<Value>::Cast(global_string);
-#else
v8::Persistent<Value>& global_value =
v8::Persistent<Value>::Cast(global_string);
-#endif
CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
CHECK(global_string == v8::Persistent<String>::Cast(global_value));
global_string.Dispose();
@@ -12669,6 +12664,75 @@
CheckSurvivingGlobalObjectsCount(0);
}
}
+
+template<class T>
+struct CopyablePersistentTraits {
+ typedef Persistent<T, CopyablePersistentTraits<T> > CopyablePersistent;
+ static const bool kResetInDestructor = true;
+ template<class S, class M>
+ V8_INLINE(static void Copy(const Persistent<S, M>& source,
+ CopyablePersistent* dest)) {
+ // do nothing, just allow copy
+ }
+};
+
+
+TEST(CopyablePersistent) {
+ LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
+ i::GlobalHandles* globals =
+ reinterpret_cast<i::Isolate*>(isolate)->global_handles();
+ int initial_handles = globals->global_handles_count();
+ {
+ v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> >
handle1;
+ {
+ v8::HandleScope scope(isolate);
+ handle1.Reset(isolate, v8::Object::New());
+ }
+ CHECK_EQ(initial_handles + 1, globals->global_handles_count());
+ v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> >
handle2;
+ handle2 = handle1;
+ CHECK(handle1 == handle2);
+ CHECK_EQ(initial_handles + 2, globals->global_handles_count());
+ v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> >
+ handle3(handle2);
+ CHECK(handle1 == handle3);
+ CHECK_EQ(initial_handles + 3, globals->global_handles_count());
+ }
+ // Verify autodispose
+ CHECK_EQ(initial_handles, globals->global_handles_count());
+}
+
+
+static void WeakApiCallback(
+ const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data)
{
+ Local<Value> value = data.GetValue()->Get(v8_str("key"));
+ CHECK_EQ(231,
static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
+ data.GetParameter()->Reset();
+ delete data.GetParameter();
+}
+
+
+TEST(WeakCallbackApi) {
+ LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
+ i::GlobalHandles* globals =
+ reinterpret_cast<i::Isolate*>(isolate)->global_handles();
+ int initial_handles = globals->global_handles_count();
+ {
+ v8::HandleScope scope(isolate);
+ v8::Local<v8::Object> obj = v8::Object::New();
+ obj->Set(v8_str("key"), v8::Integer::New(231, isolate));
+ v8::Persistent<v8::Object>* handle =
+ new v8::Persistent<v8::Object>(isolate, obj);
+ handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
+
WeakApiCallback);
+ }
+ reinterpret_cast<i::Isolate*>(isolate)->heap()->
+ CollectAllGarbage(i::Heap::kNoGCFlags);
+ // Verify disposed.
+ CHECK_EQ(initial_handles, globals->global_handles_count());
+}
v8::Persistent<v8::Object> some_object;
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.