diff options
Diffstat (limited to 'src/qml/memory/qv4heap_p.h')
-rw-r--r-- | src/qml/memory/qv4heap_p.h | 110 |
1 files changed, 107 insertions, 3 deletions
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index ed7a531766..5a3797f397 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -52,6 +52,17 @@ #include <QtCore/QString> #include <private/qv4global_p.h> +#include <QSharedPointer> + +// To check if Heap::Base::init is called (meaning, all subclasses did their init and called their +// parent's init all up the inheritance chain), define QML_CHECK_INIT_DESTROY_CALLS below. +#undef QML_CHECK_INIT_DESTROY_CALLS + +#if defined(_MSC_VER) && (_MSC_VER < 1900) // broken compilers: +# define V4_ASSERT_IS_TRIVIAL(x) +#else // working compilers: +# define V4_ASSERT_IS_TRIVIAL(x) Q_STATIC_ASSERT(std::is_trivial< x >::value); +#endif QT_BEGIN_NAMESPACE @@ -77,6 +88,8 @@ struct VTable namespace Heap { struct Q_QML_EXPORT Base { + void *operator new(size_t) = delete; + quintptr mm_data; // vtable and markbit inline ReturnedValue asReturnedValue() const; @@ -119,13 +132,48 @@ struct Q_QML_EXPORT Base { void *operator new(size_t, Managed *m) { return m; } void *operator new(size_t, Heap::Base *m) { return m; } void operator delete(void *, Heap::Base *) {} + + void init() { _setInitialized(); } + void destroy() { _setDestroyed(); } +#ifdef QML_CHECK_INIT_DESTROY_CALLS + enum { Uninitialized = 0, Initialized, Destroyed } _livenessStatus; + void _checkIsInitialized() { + if (_livenessStatus == Uninitialized) + fprintf(stderr, "ERROR: use of object '%s' before call to init() !!\n", + vtable()->className); + else if (_livenessStatus == Destroyed) + fprintf(stderr, "ERROR: use of object '%s' after call to destroy() !!\n", + vtable()->className); + Q_ASSERT(_livenessStatus = Initialized); + } + void _checkIsDestroyed() { + if (_livenessStatus == Initialized) + fprintf(stderr, "ERROR: object '%s' was never destroyed completely !!\n", + vtable()->className); + Q_ASSERT(_livenessStatus == Destroyed); + } + void _setInitialized() { Q_ASSERT(_livenessStatus == Uninitialized); _livenessStatus = Initialized; } + void _setDestroyed() { + if (_livenessStatus == Uninitialized) + fprintf(stderr, "ERROR: attempting to destroy an uninitialized object '%s' !!\n", + vtable()->className); + else if (_livenessStatus == Destroyed) + fprintf(stderr, "ERROR: attempting to destroy repeatedly object '%s' !!\n", + vtable()->className); + Q_ASSERT(_livenessStatus == Initialized); + _livenessStatus = Destroyed; + } +#else + Q_ALWAYS_INLINE void _checkIsInitialized() {} + Q_ALWAYS_INLINE void _checkIsDestroyed() {} + Q_ALWAYS_INLINE void _setInitialized() {} + Q_ALWAYS_INLINE void _setDestroyed() {} +#endif }; +V4_ASSERT_IS_TRIVIAL(Base) template <typename T> struct Pointer { - Pointer() {} - Pointer(T *t) : ptr(t) {} - T *operator->() const { return ptr; } operator T *() const { return ptr; } @@ -136,9 +184,65 @@ struct Pointer { T *ptr; }; +V4_ASSERT_IS_TRIVIAL(Pointer<void>) } +#ifdef QT_NO_QOBJECT +template <class T> +struct QQmlQPointer { +}; +#else +template <class T> +struct QQmlQPointer { + void init() + { + d = nullptr; + qObject = nullptr; + } + + void init(T *o) + { + Q_ASSERT(d == nullptr); + Q_ASSERT(qObject == nullptr); + if (o) { + d = QtSharedPointer::ExternalRefCountData::getAndRef(o); + qObject = o; + } + } + + void destroy() + { + if (d && !d->weakref.deref()) + delete d; + d = nullptr; + qObject = nullptr; + } + + T *data() const { + return d == nullptr || d->strongref.load() == 0 ? nullptr : qObject; + } + operator T*() const { return data(); } + inline T* operator->() const { return data(); } + QQmlQPointer &operator=(T *o) + { + if (d) + destroy(); + init(o); + return *this; + } + bool isNull() const Q_DECL_NOTHROW + { + return d == nullptr || qObject == nullptr || d->strongref.load() == 0; + } + +private: + QtSharedPointer::ExternalRefCountData *d; + QObject *qObject; +}; +V4_ASSERT_IS_TRIVIAL(QQmlQPointer<QObject>) +#endif + } QT_END_NAMESPACE |