Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da26c666 authored by Mathias Agopian's avatar Mathias Agopian Committed by Android (Google) Code Review
Browse files

Merge "Fix some issues with RefBase debugging."

parents 7f5a4dde f14a1046
Loading
Loading
Loading
Loading
+101 −176
Original line number Diff line number Diff line
@@ -22,16 +22,16 @@
#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>

#include <utils/StrongPointer.h>

// ---------------------------------------------------------------------------
namespace android {

class TextOutput;
TextOutput& printStrongPointer(TextOutput& to, const void* val);
TextOutput& printWeakPointer(TextOutput& to, const void* val);

template<typename T> class wp;

// ---------------------------------------------------------------------------

#define COMPARE_WEAK(_op_)                                      \
@@ -50,15 +50,15 @@ inline bool operator _op_ (const U* o) const { \
    return m_ptr _op_ o;                                        \
}

#define COMPARE(_op_)                                           \
COMPARE_WEAK(_op_)                                              \
inline bool operator _op_ (const wp<T>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}                                                               \
template<typename U>                                            \
inline bool operator _op_ (const wp<U>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}
// ---------------------------------------------------------------------------

class ReferenceMover;
class ReferenceConverterBase {
public:
    virtual size_t getReferenceTypeSize() const = 0;
    virtual void* getReferenceBase(void const*) const = 0;
    inline virtual ~ReferenceConverterBase() { }
};

// ---------------------------------------------------------------------------

@@ -115,6 +115,8 @@ public:
        getWeakRefs()->trackMe(enable, retain); 
    }

    typedef RefBase basetype;

protected:
                            RefBase();
    virtual                 ~RefBase();
@@ -137,6 +139,11 @@ protected:
    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
    virtual void            onLastWeakRef(const void* id);

private:
    friend class ReferenceMover;
    static void moveReferences(void* d, void const* s, size_t n,
            const ReferenceConverterBase& caster);

private:
    friend class weakref_type;
    class weakref_impl;
@@ -167,73 +174,20 @@ public:
        return mCount;
    }

    typedef LightRefBase<T> basetype;

protected:
    inline ~LightRefBase() { }

private:
    mutable volatile int32_t mCount;
};

// ---------------------------------------------------------------------------

template <typename T>
class sp
{
public:
    typedef typename RefBase::weakref_type weakref_type;
    
    inline sp() : m_ptr(0) { }

    sp(T* other);
    sp(const sp<T>& other);
    template<typename U> sp(U* other);
    template<typename U> sp(const sp<U>& other);

    ~sp();
    
    // Assignment

    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);
    
    template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (U* other);
    
    //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other);
    
    // Reset
    
    void clear();
    
    // Accessors

    inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }

    // Operators
        
    COMPARE(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=)
    friend class ReferenceMover;
    inline static void moveReferences(void* d, void const* s, size_t n,
            const ReferenceConverterBase& caster) { }

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;

    // Optimization for wp::promote().
    sp(T* p, weakref_type* refs);
    
    T*              m_ptr;
    mutable volatile int32_t mCount;
};

template <typename T>
TextOutput& operator<<(TextOutput& to, const sp<T>& val);

// ---------------------------------------------------------------------------

template <typename T>
@@ -329,112 +283,11 @@ private:
template <typename T>
TextOutput& operator<<(TextOutput& to, const wp<T>& val);

#undef COMPARE
#undef COMPARE_WEAK

// ---------------------------------------------------------------------------
// No user serviceable parts below here.

template<typename T>
sp<T>::sp(T* other)
    : m_ptr(other)
{
    if (other) other->incStrong(this);
}

template<typename T>
sp<T>::sp(const sp<T>& other)
    : m_ptr(other.m_ptr)
{
    if (m_ptr) m_ptr->incStrong(this);
}

template<typename T> template<typename U>
sp<T>::sp(U* other) : m_ptr(other)
{
    if (other) other->incStrong(this);
}

template<typename T> template<typename U>
sp<T>::sp(const sp<U>& other)
    : m_ptr(other.m_ptr)
{
    if (m_ptr) m_ptr->incStrong(this);
}

template<typename T>
sp<T>::~sp()
{
    if (m_ptr) m_ptr->decStrong(this);
}

template<typename T>
sp<T>& sp<T>::operator = (const sp<T>& other) {
    T* otherPtr(other.m_ptr);
    if (otherPtr) otherPtr->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = otherPtr;
    return *this;
}

template<typename T>
sp<T>& sp<T>::operator = (T* other)
{
    if (other) other->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = other;
    return *this;
}

template<typename T> template<typename U>
sp<T>& sp<T>::operator = (const sp<U>& other)
{
    U* otherPtr(other.m_ptr);
    if (otherPtr) otherPtr->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = otherPtr;
    return *this;
}

template<typename T> template<typename U>
sp<T>& sp<T>::operator = (U* other)
{
    if (other) other->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = other;
    return *this;
}

template<typename T>    
void sp<T>::force_set(T* other)
{
    other->forceIncStrong(this);
    m_ptr = other;
}

template<typename T>
void sp<T>::clear()
{
    if (m_ptr) {
        m_ptr->decStrong(this);
        m_ptr = 0;
    }
}

template<typename T>
sp<T>::sp(T* p, weakref_type* refs)
    : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
{
}

template <typename T>
inline TextOutput& operator<<(TextOutput& to, const sp<T>& val)
{
   return printStrongPointer(to, val.get());
}

// ---------------------------------------------------------------------------

template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
@@ -572,7 +425,8 @@ void wp<T>::set_object_and_refs(T* other, weakref_type* refs)
template<typename T>
sp<T> wp<T>::promote() const
{
    return sp<T>(m_ptr, m_refs);
    T* p = (m_ptr && m_refs->attemptIncStrong(this)) ? m_ptr : 0;
    return sp<T>(p, true);
}

template<typename T>
@@ -590,6 +444,77 @@ inline TextOutput& operator<<(TextOutput& to, const wp<T>& val)
    return printWeakPointer(to, val.unsafe_get());
}

// ---------------------------------------------------------------------------

// this class just serves as a namespace so TYPE::moveReferences can stay
// private.

class ReferenceMover {
    // StrongReferenceCast and WeakReferenceCast do the impedance matching
    // between the generic (void*) implementation in Refbase and the strongly typed
    // template specializations below.

    template <typename TYPE>
    struct StrongReferenceCast : public ReferenceConverterBase {
        virtual size_t getReferenceTypeSize() const { return sizeof( sp<TYPE> ); }
        virtual void* getReferenceBase(void const* p) const {
            sp<TYPE> const* sptr(reinterpret_cast<sp<TYPE> const*>(p));
            return static_cast<typename TYPE::basetype *>(sptr->get());
        }
    };

    template <typename TYPE>
    struct WeakReferenceCast : public ReferenceConverterBase {
        virtual size_t getReferenceTypeSize() const { return sizeof( wp<TYPE> ); }
        virtual void* getReferenceBase(void const* p) const {
            wp<TYPE> const* sptr(reinterpret_cast<wp<TYPE> const*>(p));
            return static_cast<typename TYPE::basetype *>(sptr->unsafe_get());
        }
    };

public:
    template<typename TYPE> static inline
    void move_references(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
        memmove(d, s, n*sizeof(sp<TYPE>));
        StrongReferenceCast<TYPE> caster;
        TYPE::moveReferences(d, s, n, caster);
    }
    template<typename TYPE> static inline
    void move_references(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
        memmove(d, s, n*sizeof(wp<TYPE>));
        WeakReferenceCast<TYPE> caster;
        TYPE::moveReferences(d, s, n, caster);
    }
};

// specialization for moving sp<> and wp<> types.
// these are used by the [Sorted|Keyed]Vector<> implementations
// sp<> and wp<> need to be handled specially, because they do not
// have trivial copy operation in the general case (see RefBase.cpp
// when DEBUG ops are enabled), but can be implemented very
// efficiently in most cases.

template<typename TYPE> inline
void move_forward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
    ReferenceMover::move_references(d, s, n);
}

template<typename TYPE> inline
void move_backward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
    ReferenceMover::move_references(d, s, n);
}

template<typename TYPE> inline
void move_forward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
    ReferenceMover::move_references(d, s, n);
}

template<typename TYPE> inline
void move_backward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
    ReferenceMover::move_references(d, s, n);
}


}; // namespace android

// ---------------------------------------------------------------------------
+224 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2005 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_STRONG_POINTER_H
#define ANDROID_STRONG_POINTER_H

#include <cutils/atomic.h>

#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>

// ---------------------------------------------------------------------------
namespace android {

class TextOutput;
TextOutput& printStrongPointer(TextOutput& to, const void* val);

template<typename T> class wp;

// ---------------------------------------------------------------------------

#define COMPARE(_op_)                                           \
inline bool operator _op_ (const sp<T>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}                                                               \
inline bool operator _op_ (const T* o) const {                  \
    return m_ptr _op_ o;                                        \
}                                                               \
template<typename U>                                            \
inline bool operator _op_ (const sp<U>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}                                                               \
template<typename U>                                            \
inline bool operator _op_ (const U* o) const {                  \
    return m_ptr _op_ o;                                        \
}                                                               \
inline bool operator _op_ (const wp<T>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}                                                               \
template<typename U>                                            \
inline bool operator _op_ (const wp<U>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}

// ---------------------------------------------------------------------------

template <typename T>
class sp
{
public:
    inline sp() : m_ptr(0) { }

    sp(T* other);
    sp(const sp<T>& other);
    template<typename U> sp(U* other);
    template<typename U> sp(const sp<U>& other);

    ~sp();

    // Assignment

    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);

    template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (U* other);

    //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other);

    // Reset

    void clear();

    // Accessors

    inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }

    // Operators

    COMPARE(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=)

private:    
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;

    // Optimization for wp::promote().
    sp(T* p, bool);

    T*              m_ptr;
};

#undef COMPARE

template <typename T>
TextOutput& operator<<(TextOutput& to, const sp<T>& val);

// ---------------------------------------------------------------------------
// No user serviceable parts below here.

template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
  {
    if (other) other->incStrong(this);
  }

template<typename T>
sp<T>::sp(const sp<T>& other)
: m_ptr(other.m_ptr)
  {
    if (m_ptr) m_ptr->incStrong(this);
  }

template<typename T> template<typename U>
sp<T>::sp(U* other) : m_ptr(other)
{
    if (other) other->incStrong(this);
}

template<typename T> template<typename U>
sp<T>::sp(const sp<U>& other)
: m_ptr(other.m_ptr)
  {
    if (m_ptr) m_ptr->incStrong(this);
  }

template<typename T>
sp<T>::~sp()
{
    if (m_ptr) m_ptr->decStrong(this);
}

template<typename T>
sp<T>& sp<T>::operator = (const sp<T>& other) {
    T* otherPtr(other.m_ptr);
    if (otherPtr) otherPtr->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = otherPtr;
    return *this;
}

template<typename T>
sp<T>& sp<T>::operator = (T* other)
{
    if (other) other->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = other;
    return *this;
}

template<typename T> template<typename U>
sp<T>& sp<T>::operator = (const sp<U>& other)
{
    U* otherPtr(other.m_ptr);
    if (otherPtr) otherPtr->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = otherPtr;
    return *this;
}

template<typename T> template<typename U>
sp<T>& sp<T>::operator = (U* other)
{
    if (other) other->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = other;
    return *this;
}

template<typename T>    
void sp<T>::force_set(T* other)
{
    other->forceIncStrong(this);
    m_ptr = other;
}

template<typename T>
void sp<T>::clear()
{
    if (m_ptr) {
        m_ptr->decStrong(this);
        m_ptr = 0;
    }
}

template<typename T>
sp<T>::sp(T* p, bool)
: m_ptr(p)
  {
  }

template <typename T>
inline TextOutput& operator<<(TextOutput& to, const sp<T>& val)
{
    return printStrongPointer(to, val.get());
}

}; // namespace android

// ---------------------------------------------------------------------------

#endif // ANDROID_STRONG_POINTER_H
+0 −13
Original line number Diff line number Diff line
@@ -37,18 +37,6 @@ template <typename T> struct trait_trivial_move { enum { value = false }; };
template <typename T> struct trait_pointer      { enum { value = false }; };    
template <typename T> struct trait_pointer<T*>  { enum { value = true }; };

// sp<> can be trivially moved
template <typename T> class sp;
template <typename T> struct trait_trivial_move< sp<T> >{
    enum { value = true }; 
};

// wp<> can be trivially moved
template <typename T> class wp;
template <typename T> struct trait_trivial_move< wp<T> >{ 
    enum { value = true }; 
};

template <typename TYPE>
struct traits {
    enum {
@@ -217,7 +205,6 @@ void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
    }
}


// ---------------------------------------------------------------------------

/*
+101 −70
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@

#include <utils/Atomic.h>
#include <utils/CallStack.h>
#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/threads.h>
#include <utils/TextOutput.h>
@@ -35,6 +34,7 @@

// compile with refcounting debugging enabled
#define DEBUG_REFS                      0
#define DEBUG_REFS_FATAL_SANITY_CHECKS  0
#define DEBUG_REFS_ENABLED_BY_DEFAULT   1
#define DEBUG_REFS_CALLSTACK_ENABLED    1

@@ -70,8 +70,10 @@ public:

    void addStrongRef(const void* /*id*/) { }
    void removeStrongRef(const void* /*id*/) { }
    void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
    void addWeakRef(const void* /*id*/) { }
    void removeWeakRef(const void* /*id*/) { }
    void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
    void printRefs() const { }
    void trackMe(bool, bool) { }

@@ -87,40 +89,74 @@ public:
        , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
        , mRetain(false)
    {
        //LOGI("NEW weakref_impl %p for RefBase %p", this, base);
    }
    
    ~weakref_impl()
    {
        LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
        LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
        bool dumpStack = false;
        if (!mRetain && mStrongRefs != NULL) {
            dumpStack = true;
#if DEBUG_REFS_FATAL_SANITY_CHECKS
            LOG_ALWAYS_FATAL("Strong references remain!");
#else
            LOGE("Strong references remain!");
#endif
        }

    void addStrongRef(const void* id)
    {
        if (!mRetain && mWeakRefs != NULL) {
            dumpStack = true;
#if DEBUG_REFS_FATAL_SANITY_CHECKS
            LOG_ALWAYS_FATAL("Weak references remain!");
#else
            LOGE("Weak references remain!");
#endif
        }

        if (dumpStack) {
            CallStack stack;
            stack.update();
            stack.dump();
        }
    }

    void addStrongRef(const void* id) {
        //LOGD_IF(mTrackEnabled,
        //        "addStrongRef: RefBase=%p, id=%p", mBase, id);
        addRef(&mStrongRefs, id, mStrong);
    }

    void removeStrongRef(const void* id)
    {
        if (!mRetain)
    void removeStrongRef(const void* id) {
        //LOGD_IF(mTrackEnabled,
        //        "removeStrongRef: RefBase=%p, id=%p", mBase, id);
        if (!mRetain) {
            removeRef(&mStrongRefs, id);
        else
        } else {
            addRef(&mStrongRefs, id, -mStrong);
        }
    }

    void addWeakRef(const void* id)
    {
    void renameStrongRefId(const void* old_id, const void* new_id) {
        //LOGD_IF(mTrackEnabled,
        //        "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
        //        mBase, old_id, new_id);
        renameRefsId(mStrongRefs, old_id, new_id);
    }

    void addWeakRef(const void* id) {
        addRef(&mWeakRefs, id, mWeak);
    }

    void removeWeakRef(const void* id)
    {
        if (!mRetain)
    void removeWeakRef(const void* id) {
        if (!mRetain) {
            removeRef(&mWeakRefs, id);
        else
        } else {
            addRef(&mWeakRefs, id, -mWeak);
        }
    }

    void renameWeakRefId(const void* old_id, const void* new_id) {
        renameRefsId(mWeakRefs, old_id, new_id);
    }

    void trackMe(bool track, bool retain)
    { 
@@ -133,8 +169,7 @@ public:
        String8 text;

        {
            AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex);
    
            Mutex::Autolock _l(const_cast<weakref_impl*>(this)->mMutex);
            char buf[128];
            sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
            text.append(buf);
@@ -173,6 +208,7 @@ private:
    {
        if (mTrackEnabled) {
            AutoMutex _l(mMutex);

            ref_entry* ref = new ref_entry;
            // Reference count at the time of the snapshot, but before the
            // update.  Positive value means we increment, negative--we
@@ -182,7 +218,6 @@ private:
#if DEBUG_REFS_CALLSTACK_ENABLED
            ref->stack.update(2);
#endif
            
            ref->next = *refs;
            *refs = ref;
        }
@@ -200,13 +235,37 @@ private:
                    delete ref;
                    return;
                }
                
                refs = &ref->next;
                ref = *refs;
            }

            LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
#if DEBUG_REFS_FATAL_SANITY_CHECKS
            LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p"
                    "(weakref_type %p) that doesn't exist!",
                    id, mBase, this);
#endif

            LOGE("RefBase: removing id %p on RefBase %p"
                    "(weakref_type %p) that doesn't exist!",
                    id, mBase, this);

            CallStack stack;
            stack.update();
            stack.dump();
        }
    }

    void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
    {
        if (mTrackEnabled) {
            AutoMutex _l(mMutex);
            ref_entry* ref = r;
            while (ref != NULL) {
                if (ref->id == old_id) {
                    ref->id = new_id;
                }
                ref = ref->next;
            }
        }
    }

@@ -236,44 +295,6 @@ private:
    // on removeref that match the address ones.
    bool mRetain;

#if 0
    void addRef(KeyedVector<const void*, int32_t>* refs, const void* id)
    {
        AutoMutex _l(mMutex);
        ssize_t i = refs->indexOfKey(id);
        if (i >= 0) {
            ++(refs->editValueAt(i));
        } else {
            i = refs->add(id, 1);
        }
    }

    void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id)
    {
        AutoMutex _l(mMutex);
        ssize_t i = refs->indexOfKey(id);
        LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id);
        if (i >= 0) {
            int32_t val = --(refs->editValueAt(i));
            if (val == 0) {
                refs->removeItemsAt(i);
            }
        }
    }

    void printRefs(const KeyedVector<const void*, int32_t>& refs)
    {
        const size_t N=refs.size();
        for (size_t i=0; i<N; i++) {
            printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i));
        }
    }

    mutable Mutex mMutex;
    KeyedVector<const void*, int32_t> mStrongRefs;
    KeyedVector<const void*, int32_t> mWeakRefs;
#endif

#endif
};

@@ -282,7 +303,6 @@ private:
void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->addWeakRef(id);
    refs->incWeak(id);
    
    refs->addStrongRef(id);
@@ -314,14 +334,12 @@ void RefBase::decStrong(const void* id) const
            delete this;
        }
    }
    refs->removeWeakRef(id);
    refs->decWeak(id);
}

void RefBase::forceIncStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->addWeakRef(id);
    refs->incWeak(id);
    
    refs->addStrongRef(id);
@@ -433,7 +451,6 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id)
        }
    }
    
    impl->addWeakRef(id);
    impl->addStrongRef(id);

#if PRINT_REFS
@@ -498,14 +515,11 @@ RefBase::weakref_type* RefBase::getWeakRefs() const
RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
//    LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
}

RefBase::~RefBase()
{
//    LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);
    if (mRefs->mWeak == 0) {
//        LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);
        delete mRefs;
    }
}
@@ -534,6 +548,23 @@ void RefBase::onLastWeakRef(const void* /*id*/)

// ---------------------------------------------------------------------------

void RefBase::moveReferences(void* dst, void const* src, size_t n,
        const ReferenceConverterBase& caster)
{
#if DEBUG_REFS
    const size_t itemSize = caster.getReferenceTypeSize();
    for (size_t i=0 ; i<n ; i++) {
        void*       d = reinterpret_cast<void      *>(intptr_t(dst) + i*itemSize);
        void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize);
        RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d)));
        ref->mRefs->renameStrongRefId(s, d);
        ref->mRefs->renameWeakRefId(s, d);
    }
#endif
}

// ---------------------------------------------------------------------------

TextOutput& printStrongPointer(TextOutput& to, const void* val)
{
    to << "sp<>(" << val << ")";