/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __GCObject__
#define __GCObject__

#ifdef __GNUC__
    #define GNUC_ONLY(x) x
#else
    #define GNUC_ONLY(x)
#endif

// These are declared but not implemented so we can catch uses of them
// as link errors.   If we remove these we run the risk of new (GC*) being
// compiled as a call to placement new.
void *operator new(size_t size, MMgc::GC *gc);
void *operator new(size_t size, MMgc::GC *gc, int flags);

namespace MMgc
{
    /**
     * Base class for GC pointer containing structures that aren't
     * directly heap allocated but are used to compose other GCObject
     * or GCRoots.  In practice this introduces the GCMember local
     * definition and hides new/delete.
     */    
    class GCInlineObject
    {
    public:
#ifdef GCDEBUG
        /**
         * The function gcTraceOffsetIsTraced is overriden in classes
         * with generated tracers (its declared by GC_DATA_BEGIN).  In
         * classes with manual tracers this implementation here is
         * used and it returns kPassDueToManualTrace which tells the
         * safety check to stop the checking process.  We can't
         * perform the safety check unless the entire class is
         * annotated with the exactgc system. Note that the form of
         * the generated function is:

           GCTracerCheckResult result;
           if((result = super->gcTraceOffsetIsTraced(off)) != MMgc::kOffsetNotFound) 
               return result;
           if((someStruct.gcTraceOffsetIsTraced(off, offsetof(MyClass, someStruct))) != MMgc::kOffsetNotFound)
               return result;
           return GC::CheckOffsetIsInList(off,myOffsets);

           * Its important for "super" above to never to be
           * GCInlineObject or GCTraceableBase because we would always
           * return kPassDueToManualTracer and skip the safety
           * checking.  The trace gen script accounts for this by not
           * generating the super call when the base class doesn't
           * have a tracer (ie GCInlineObject or GCTraceableBase and
           * its immediate subclasses).
         */
        GCTracerCheckResult gcTraceOffsetIsTraced(uint32_t) const 
        {
            return kPassDueToManualTracer;
        }
#endif

        void gcTrace(GC*, size_t cursor=0)
        {
            (void)cursor;
            GCAssertMsg(false, "This class needs a gcTrace, did you forget to annotate it or write a custom gcTrace?");
        }

        //  GCObject's local definition of GCMember
        template<class T>
        class GCMember : public GCMemberBase<T>
        {
        public:

            template<class T2>
            void operator=(const GCRef<T2>& other);

            void operator=(T* tNew);

            //  Since we're locking up the copy constructor, we need to explicitly define the default constructor
            explicit GCMember();
        
            template<class T2>
            explicit GCMember(const GCRef<T2>& other);

            explicit GCMember(T* valuePtr);
            
            explicit GCMember(const GCMember<T>& other);
        };
    private:
        // Private and unimplemented to prevent heap allocation.
        static void *operator new(size_t size) GNUC_ONLY(throw());
        static void operator delete(void *gcObject);
    };

    /**
     * Base class for GC managed objects that aren't finalized and are
     * conservatively traced.
     */
    class GCObject
    {
    public:

        // Methods used by GCMember<T>
        REALLY_INLINE static void WriteBarrier(void **address, void *value)
        {
            GC::WriteBarrier(address, value);
        }

        REALLY_INLINE static void WriteBarrier_dtor(void **address)
        {
            *address = NULL;
        }
        
        // These are noops overridden by RCObject to do the right thing.
        REALLY_INLINE void IncrementRef() {}
        REALLY_INLINE void DecrementRef() {}
                        
        //  GCObject's local definition of GCMember
        template<class T>
        class GCMember : public GCMemberBase<T>
        {
        public:
                        
            template<class T2>
            void operator =(const GCRef<T2>& other);

            void operator=(T* tNew);

            //  Since we're locking up the copy constructor, we need to explicitly define the default constructor
            explicit GCMember();
        
            template<class T2>
            explicit GCMember(const GCRef<T2>& other);

            explicit GCMember(T* valuePtr);
            
            explicit GCMember(const GCMember<T>& other);
        };
        
        // 'throw()' annotation to avoid GCC warning: 'operator new' must not return NULL unless it is declared 'throw()' (or -fcheck-new is in effect)
        static void *operator new(size_t size, GC *gc, size_t extra) GNUC_ONLY(throw());

        static void *operator new(size_t size, GC *gc) GNUC_ONLY(throw());

        static void operator delete(void *gcObject);

        GCWeakRef *GetWeakRef() const;

        //  Create a GCRef from "this" with parameter for auto template specialization.
        template <class T>
        REALLY_INLINE GCRef<T> GetThisRef(const T *ths) const
        {
            GCAssert(ths == (const T*)this);
            GCRef<T> ref(const_cast<T*>(ths));
            return ref;
        }
    };

    /**
     * Base class for objects that have no GC pointers in them.  A
     * LeafObject has all the same APIs as GCObject except it does not
     * define GCMember as it makes no sense for a LeafObject to have a
     * GCMember.
     */
    class LeafObject
    {
    public:

        // Methods used by GCMember<T>
        REALLY_INLINE static void WriteBarrier(void **address, void *value)
        {
            GC::WriteBarrier(address, value);
        }

        REALLY_INLINE static void WriteBarrier_dtor(void **address)
        {
            *address = NULL;
        }
        
        // These are noops overridden by RCObject to do the right thing.
        REALLY_INLINE void IncrementRef() {}
        REALLY_INLINE void DecrementRef() {}

        static void *operator new(size_t size, GC *gc) GNUC_ONLY(throw())
        {
            return gc->Alloc(size, GC::kZero, kLeafObjectNewPartition);
        }
        
        // On purpose! Forward thinking 
        //        static void operator delete(void *gcObject);

        GCWeakRef *GetWeakRef() const
        {
            return GC::GetWeakRef(this);
        }

        //  Create a GCRef from "this" with parameter for auto template specialization.
        template <class T>
        REALLY_INLINE GCRef<T> GetThisRef(const T *ths) const
        {
            GCAssert(ths == (const T*)this);
            GCRef<T> ref(const_cast<T*>(ths));
            return ref;
        }
    };

    /**
     * LeafVector provides a zero overhead fixed length array of
     * primitives that don't need to be scanned by the GC for
     * pointers.  The New factory method safely calculates the amount
     * of space needed, ie it checks for overflow.  Zeroing of memory
     * is not done by default, GC::kZero can be passed in the optional
     * 'flags' template parameter to have the memory zeroed.
     * 
     * LeafVectors are not subclassable and access to the array of
     * elements must happen via the AsArray method.
     */
    template<class T, GC::AllocFlags flags=GC::kNoFlags>
    class LeafVector : public LeafObject
    {
    public:

        /**
         * Return a pointer to the first element
         */
        T* AsArray() 
        { 
#ifdef GCDEBUG
            // check that the apiEnforcement field is untouched
            for(char *dummy = (char*)&apiEnforcement, *end=(char*)(&apiEnforcement+1); dummy < end; dummy++)
            {
                GCAssertMsg(*dummy == GCHeap::LeafApiEnforcementPoison, "LeafVector underwrite, make sure AsArray is being used");
            }
#endif
            return elements;
        }

        /**
         * Allocate a LeafVector that can store 'count' elements of T.
         * A count of zero will allocate space for 1 element.
         */
        static LeafVector<T,flags>* New(GC *gc, size_t count)
        {
            return new (gc, count) LeafVector<T,flags>();
        }

        // On purpose! Forward thinking 
        //        static void operator delete(void *gcObject);
        
    private:

        // 'throw()' annotation to avoid GCC warning: 'operator new' must not return NULL unless it is declared 'throw()' (or -fcheck-new is in effect)
        static void *operator new(size_t size, GC *gc, size_t count) GNUC_ONLY(throw())
        {
            // Account for element already built into size, if you ask for 0 you get 1.
            if(count > 0)
                count--;
            size_t arraySize = GCHeap::CheckForCallocSizeOverflow(sizeof(T), count);
            size_t bytes = GCHeap::CheckForAllocSizeOverflow(size, arraySize);
            return gc->Alloc(bytes, flags & GC::kZero, kLeafVectorNewPartition);
        }

        // Private ctor to prevent subclassing.
        LeafVector() 
        {
#ifdef GCDEBUG
            VMPI_memset(&apiEnforcement, GCHeap::LeafApiEnforcementPoison, sizeof(T));
#endif
        }

#ifdef GCDEBUG
        // prevent raw casting from LeafVector to T*
        T apiEnforcement;
#endif
        T elements[1];
    };

    // GCTraceableBase is internal to MMgc.

    class GCTraceableBase
    {
        friend class GC;
#ifdef GCDEBUG
    protected:
        // See comments for GCInlineObject gcTraceOffsetIsTraced.
        virtual GCTracerCheckResult gcTraceOffsetIsTraced(uint32_t) const 
        { 
            return kPassDueToManualTracer; 
        }
#endif

    public:
        virtual ~GCTraceableBase() { /* must be empty */ }

        // The gcTrace method will be called to exactly mark the object.  It must trace
        // all locations in the object that may contain pointers to managed objects.
        //
        // The gcTrace method may be called multiple times on a single object,
        // in order to allow a large object to be marked piecemeal.  On the
        // first call 'cursor' will be 0, on the next it will be 1, and so on.
        // Any value must be accepted for 'cursor' but unless it is 0 then it
        // will be one greater than it was on the last invocation for the same
        // object.  On each invocation the method should attempt to do marking
        // work corresponding roughly to kLargestAlloc/sizeof(void*) words.
        //
        // The method must return 'true' if there is more marking work to be done,
        // otherwise 'false'.  If 'true' is returned then the object will be re-visited
        // with cursor incremented.
        //
        // Note that marking may start over without first reaching the end
        // of the object, as a result of updates interleaved with marking or
        // mark stack overflow.  A restarted marking is indicated by a cursor == 0.
        //
        // The base version of this method aborts the process - you must
        // override if there's a chance that it can be called, and you
        // must never delegate to the base method.

        virtual bool gcTrace(GC* gc, size_t cursor);
        
        // The class must have an empty operator 'delete' to prevent the C++
        // compiler from inserting a call to the system's delete operator into
        // the base class destructor.
        static void operator delete(void *) { /* must be empty */ }

        // Methods used by GCMember<T>
        REALLY_INLINE static void WriteBarrier(void **address, void *value)
        {
            GC::WriteBarrier(address, value);
        }

        REALLY_INLINE static void WriteBarrier_dtor(void **address)
        {
            *address = NULL;
        }
        
        // These are noops overridden by RCObject to do the right thing.
        REALLY_INLINE void IncrementRef() {}
        REALLY_INLINE void DecrementRef() {}

        template<class T>
        class GCMember : public GCMemberBase<T>
        {
        public:
            template<class T2>
            void operator=(const GCRef<T2>& other);

            void operator=(T* tNew);

            //  Since we're locking up the copy constructor, we need to explicitly define the default constructor
            explicit GCMember();

            template <class T2>
            explicit GCMember(const GCRef<T2>& other);
            
            explicit GCMember(T* valuePtr);
            
            explicit GCMember(const GCMember<T>& other);
        };
    };

    /**
     * Base class for GC-managed objects that are not finalizable but have
     * a virtual gcTrace method.  This must be used as the most base class
     * instead of GCObject, it can't be mixed in later.
     *
     * Note that subtypes that want to be traced exactly must pass the kExact flag
     * as the second argument to the 'new' operator.
     *
     * The following two invariants must hold for exactly traced objects and their
     * tracer (see also Bugzilla 
     *
     *   - The tracer must always be able to interpret a pointer field that is
     *     all-bits-zero, because the GC may see the object and call the tracer
     *     before the constructor that initializes the field is run.
     *
     *   - No exactly traced field must ever contain a bogus value.  That's generally
     *     not hard to ensure but there are three cases to watch out for:
     *
     *     - in a "tagged union" setting, a separate tag field directs the
     *       interpretation of the pointer field.  The tag and the payload must
     *       always be set together, without any chance of the GC getting to
     *       run after one is set and before the other is set.
     *
     *     - in a "counted array" setting, a separate count field directs the
     *       interpretation of an array field (frequently a trailing array).
     *       This is like the tagged union case, but if the count is stored in
     *       a separate object it is important that the separate object pointer
     *       is not NULL, as the GC would not check that (in a GC_POINTERS setting,
     *       for example).
     *
     *     - it must be true also when the object is about to be freed, as with
     *       a call to GC::Free, because GC::Free cannot guarantee that the object
     *       will in fact be freed.
     *
     * Note that the C++ constructor settings syntax can obscure what's going
     * on, as it makes assignments and calls less visible.
     *
     *
     * The operators and methods here are exactly like those of GCObject.
     */
    class GCTraceableObject : public GCTraceableBase
    {
    public:
        // This class can only have an empty destructor.
        
        static void *operator new(size_t size, GC *gc, GCExactFlag flag, size_t extra) GNUC_ONLY(throw());
        static void *operator new(size_t size, GC *gc, size_t extra) GNUC_ONLY(throw());
        static void *operator new(size_t size, GC *gc, GCExactFlag flag) GNUC_ONLY(throw());
        static void *operator new(size_t size, GC *gc) GNUC_ONLY(throw());
        static void operator delete(void *gcObject);
        
        GCWeakRef *GetWeakRef() const;
    };

    /**
     * Baseclass for GC managed objects that are finalized.
     *
     * Note that subtypes that want to be traced exactly must pass the kExact flag
     * as the second argument to the 'new' operator.
     *
     * Invariants that must hold for exactly traced objects are documented above,
     * for GCTraceableObject.
     *
     */
    class GCFinalizedObject : public GCTraceableBase
    {
    public:
        // This class can only have an empty destructor.

        //  Create a GCRef from "this" with parameter for auto template specialization.
        template <class T>
        REALLY_INLINE GCRef<T> GetThisRef(const T *ths) const
        {
            GCAssert(ths == (const T*) this);
            GCRef<T> ref(const_cast<T*>(ths));
            return ref;
        }

        GCWeakRef *GetWeakRef() const;

        static void* operator new(size_t size, GC *gc, GCExactFlag flag, size_t extra);
        static void* operator new(size_t size, GC *gc, size_t extra);
        static void* operator new(size_t size, GC *gc, GCExactFlag flag);
        static void* operator new(size_t size, GC *gc);
        static void* operator new(size_t size, GC *gc, GCExactFlag, GCNoFinalizeFlag, size_t extra);
        static void* operator new(size_t size, GC *gc, GCNoFinalizeFlag, size_t extra);
        static void* operator new(size_t size, GC *gc, GCExactFlag, GCNoFinalizeFlag);
        static void* operator new(size_t size, GC *gc, GCNoFinalizeFlag);
        static void operator delete (void *gcObject);
    };

    REALLY_INLINE void *GCObject::operator new(size_t size, GC *gc, size_t extra) GNUC_ONLY(throw())
    {
        return gc->AllocExtraPtrZero(size, extra, kGCObjectNewPartition);
    }

    REALLY_INLINE void *GCObject::operator new(size_t size, GC *gc) GNUC_ONLY(throw())
    {
        return gc->AllocPtrZero(size, kGCObjectNewPartition);
    }

    REALLY_INLINE void GCObject::operator delete(void *gcObject)
    {
        GC::GetGC(gcObject)->FreeFromDelete(gcObject);
    }

    REALLY_INLINE GCWeakRef* GCObject::GetWeakRef() const
    {
        return GC::GetWeakRef(this);
    }

    REALLY_INLINE void *GCTraceableObject::operator new(size_t size, GC *gc, size_t extra) GNUC_ONLY(throw())
    {
        return gc->AllocExtraPtrZero(size, extra, kGCTraceableObjectNewPartition);
    }
    
    REALLY_INLINE void *GCTraceableObject::operator new(size_t size, GC *gc) GNUC_ONLY(throw())
    {
        return gc->AllocPtrZero(size, kGCTraceableObjectNewPartition);
    }
    
    REALLY_INLINE void *GCTraceableObject::operator new(size_t size, GC *gc, GCExactFlag, size_t extra) GNUC_ONLY(throw())
    {
        return gc->AllocExtraPtrZeroExact(size, extra, kGCTraceableObjectNewPartition);
    }
    
    REALLY_INLINE void *GCTraceableObject::operator new(size_t size, GC *gc, GCExactFlag) GNUC_ONLY(throw())
    {
        return gc->AllocPtrZeroExact(size, kGCTraceableObjectNewPartition);
    }
    
    REALLY_INLINE void GCTraceableObject::operator delete(void *gcObject)
    {
        GC::GetGC(gcObject)->FreeFromDelete(gcObject);
    }
    
    REALLY_INLINE GCWeakRef* GCTraceableObject::GetWeakRef() const
    {
        return GC::GetWeakRef(this);
    }
    
    REALLY_INLINE GCWeakRef* GCFinalizedObject::GetWeakRef() const
    {
        return GC::GetWeakRef(this);
    }

    REALLY_INLINE void* GCFinalizedObject::operator new(size_t size, GC *gc, size_t extra)
    {
        return gc->AllocExtraPtrZeroFinalized(size, extra, kGCFinalizedObjectNewPartition);
    }

    REALLY_INLINE void* GCFinalizedObject::operator new(size_t size, GC *gc)
    {
        return gc->AllocPtrZeroFinalized(size, kGCFinalizedObjectNewPartition);
    }

    REALLY_INLINE void* GCFinalizedObject::operator new(size_t size, GC *gc, GCExactFlag, size_t extra)
    {
        return gc->AllocExtraPtrZeroFinalizedExact(size, extra, kGCFinalizedObjectNewPartition);
    }
    
    REALLY_INLINE void* GCFinalizedObject::operator new(size_t size, GC *gc, GCExactFlag)
    {
        return gc->AllocPtrZeroFinalizedExact(size, kGCFinalizedObjectNewPartition);
    }
    
    REALLY_INLINE void* GCFinalizedObject::operator new(size_t size, GC *gc, GCNoFinalizeFlag, size_t extra)
    {
        return gc->AllocExtraPtrZero(size, extra, kGCFinalizedObjectNewPartition);
    }
    
    REALLY_INLINE void* GCFinalizedObject::operator new(size_t size, GC *gc, GCNoFinalizeFlag)
    {
        return gc->AllocPtrZero(size, kGCFinalizedObjectNewPartition);
    }
    
    REALLY_INLINE void* GCFinalizedObject::operator new(size_t size, GC *gc, GCExactFlag, GCNoFinalizeFlag, size_t extra)
    {
        return gc->AllocExtraPtrZeroExact(size, extra, kGCFinalizedObjectNewPartition);
    }
    
    REALLY_INLINE void* GCFinalizedObject::operator new(size_t size, GC *gc, GCExactFlag, GCNoFinalizeFlag)
    {
        return gc->AllocPtrZeroExact(size, kGCFinalizedObjectNewPartition);
    }
    
    REALLY_INLINE void GCFinalizedObject::operator delete (void *gcObject)
    {
        GC::GetGC(gcObject)->FreeFromDelete(gcObject);
    }

    /**
     * Base class for reference counted objects.
     *
     * This object always has a finalizer (the C++ destructor).  The C++ destructor /must/
     * leave the object with all-fields-zero.
     *
     * Reference counting is deferred: when an object's reference count drops to zero it
     * is inserted into the zero-count table (the ZCT), see ZCT.h etc.  If the reference
     * count grows above zero the object is removed from the ZCT again.  Every new object
     * is added to the ZCT initially - reference counts start at zero.
     *
     * Occasionally the ZCT is reaped: objects in the ZCT that are not referenced from stack
     * memory or special ZCT roots, and that are not explicitly pinned by client code, are
     * deleted by calling their finalizers and reclaiming their memory.   A finalizer may
     * make the reference counts of more referenced objects drop to zero, whereupon they
     * too are entered into the ZCT (and may be deleted by the ongoing reap, or a later
     * reap).
     *
     * (Under complicated scenarios it is possible for an object allocated during reaping
     * to be erroneously deleted, see https://bugzilla.mozilla.org/show_bug.cgi?id=506644,
     * so client code may want to take note of that.)
     *
     *
     * Invariants on 'composite'.
     *
     * The field 'compsite' holds reference counts, the ZCT index, and flag bits.  We depend
     * on object layout being such that this field is the second word of the object.  This
     * field is used for a heuristic defense-in-depth mechanism:
     *
     *  - In release builds its value is zero iff the object's destructor has been run and
     *    the object has not been reallocated (ie the object may or may not yet have been
     *    placed on a free list).
     *  - In debug builds its value is zero iff the object's destructor has been run and the
     *    object has not yet been put on the free list or been reallocated.  Once it's been
     *    put on the free list the composite word is a cookie: GCHeap::GCFreedPoison or
     *    GCHeap::GCSweptPoison.
     *
     * The RC operations check whether the object is free - and if it is, then the operations
     * have no effect.  This is useful because of the current finalization semantics:
     * finalization and destruction are intertwined, so that the C++ destructor performs both
     * jobs.  Thus an object can't be finalized without being destroyed.  Finalizers run
     * in arbitrary order; thus a finalizer for an object that's part of an object network
     * will not know whether it is safe to operate on other objects in that network.  The
     * extra guards on RC operations makes this safer.  It only works because all objects that
     * are finalizable are finalized together, before any of them are swept or reallocated.
     * It is also an expense that everyone pays for.  The only fix is a change to how
     * finalization is handled.
     */

    class RCObject : public GCFinalizedObject
    {
        friend class GC;
        friend class ZCT;
    public:
        REALLY_INLINE static void *operator new(size_t size, GC *gc, size_t extra)
        {
            return gc->AllocExtraRCObject(size, extra, kRCObjectNewPartition);
        }

        REALLY_INLINE static void *operator new(size_t size, GC *gc)
        {
            return gc->AllocRCObject(size, kRCObjectNewPartition);
        }
 
        REALLY_INLINE static void *operator new(size_t size, GC *gc, GCExactFlag, size_t extra)
        {
            return gc->AllocExtraRCObjectExact(size, extra, kRCObjectNewPartition);
        }
        
        REALLY_INLINE static void *operator new(size_t size, GC *gc, GCExactFlag)
        {
            return gc->AllocRCObjectExact(size, kRCObjectNewPartition);
        }
    public:

        // Used by GCMember<T>
        REALLY_INLINE static void WriteBarrier(void **address, void *value)
        {
            GC::WriteBarrierRC(address, value);
        }

        REALLY_INLINE static void WriteBarrier_dtor(void **address)
        {
            GC::WriteBarrierRC_dtor(address);
        }

        REALLY_INLINE RCObject()
        {
            composite = 1;
            GC::GetGC(this)->AddToZCT(this REFCOUNT_PROFILING_ARG(true));
        }

        REALLY_INLINE ~RCObject()
        {
            // The ZCT reaper removes the object from the ZCT before deleting it,
            // but when non-GC code explicitly deletes the object we may find that
            // it is already in the ZCT.  So remove it if necessary.
            if (InZCT())
                GC::GetGC(this)->RemoveFromZCT(this REFCOUNT_PROFILING_ARG(true));
            // We'd like to assert this but can't, for the moment.  The case is handled
            // in the allocator instead, see call paths ending at AbortFree.
            //GCAssert((GC::GetGC(this)->GetGCBits(this) & (kMark|kQueued)) != kQueued);
            composite = 0;
        }

        /**
         * @return true if the object is currently pinned (explicitly or by
         *         the ZCT's stack pinner).
         */
        REALLY_INLINE bool IsPinned()
        {
            return (composite & STACK_PIN) != 0;
        }

#ifdef GCDEBUG
        REALLY_INLINE bool IsGCPoisoned() {
            return composite == uint32_t(GCHeap::GCFreedPoison) || composite == uint32_t(GCHeap::GCSweptPoison);
        }
#endif
        
        /**
         * Explicitly pin the object, protecting it from ZCT reaping.  The pin
         * flag /will/ be cleared if the object is subsequently added to the
         * ZCT and reaping is not ongoing.  It is not advised to call Pin()
         * except from prereap() callback handlers.
         */
        void Pin()
        {
#ifdef GCDEBUG
            // This is a deleted object so ignore it.
            if(IsGCPoisoned())
                return;
#endif
            // This is a deleted/free object so ignore it.
            if (getCompositeSafe() == 0)
                return;

            composite |= STACK_PIN;
        }

        /**
         * Explicitly unpin the object, allowing it to be reaped by the ZCT.
         * It is not advised to unpin objects that weren't pinned explicitly
         * by a call to Pin(), and calls to Unpin() should come from postreap()
         * callback handlers.
         */
        void Unpin()
        {
#ifdef GCDEBUG
            // This is a deleted object so ignore it.
            if(IsGCPoisoned())
                return;
#endif
            // This is a deleted/free object so ignore it.
            if (composite == 0)
                return;

            composite &= ~STACK_PIN;
        }

        /**
         * @return the object's current reference count.  The value is not
         * valid unless Sticky() returns 0.
         */
        REALLY_INLINE uint32_t RefCount() const
        {
            return (composite & RCBITS) - 1;
        }

        /**
         * @return non-zero if the object is sticky (RC operations have no effect because
         *         the RC field is invalid, either as a consequence of an RC overflow or
         *         because the sticky bit was set explicitly).
         */
        REALLY_INLINE uint32_t Sticky() const
        {
            return composite & STICKYFLAG;
        }

        /**
         * Make RC operations on the object be no-ops.
         */
        REALLY_INLINE void Stick()
        {
#ifdef GCDEBUG
            // This is a deleted object so ignore it.
            if(IsGCPoisoned())
                return;
#endif
            // This is a deleted/free object so ignore it.
            if (composite == 0)
                return;

            if (InZCT())
                GC::GetGC(this)->RemoveFromZCT(this REFCOUNT_PROFILING_ARG(true));
            composite |= STICKYFLAG;
        }

        /**
         * Increment the object's reference count.
         *
         * OPTIMIZEME: this is too expensive and too large.  It should be
         * possible to do better if we play around with the positive/negative
         * boundary (eg, operations that don't cross that boundary are
         * cheap, and those that do aren't), but the special-casing of
         * composite==0 and invariants throughtout the system relying on
         * composite==0 make it hard.  We need profiling data on the breakdown
         * of the frequency of various paths through this function.
         */
        REALLY_INLINE void IncrementRef()
        {
#ifdef GCDEBUG
            // This is a deleted object so ignore it.
            if(IsGCPoisoned())
                return;
#endif
            // This is a deleted/free object so ignore it.
            if (composite == 0)
                return;

            REFCOUNT_PROFILING_ONLY( GC::GetGC(this)->policy.signalIncrementRef(); )
            if(Sticky())
                return;
#ifdef GCDEBUG
            GC* gc = GC::GetGC(this);
            GCAssert(gc->IsRCObjectSafe(this));
#endif

            composite++;
            if((composite&RCBITS) == RCBITS) {
                composite |= STICKYFLAG;
            } else if(InZCT()) {
                GCAssert(RefCount() == 1);
                GC::GetGC(this)->RemoveFromZCT(this);
            }

#ifdef MMGC_RC_HISTORY
            if(GC::GetGC(this)->keepDRCHistory && GCHeap::GetGCHeap()->GetProfiler())
                history.Add(GCHeap::GetGCHeap()->GetProfiler()->GetStackTrace());
#endif
        }

        /**
         * Decrement the object's reference count.
         *
         * OPTIMIZEME: this is too expensive and too large.  It should be
         * possible to do better if we play around with the positive/negative
         * boundary (eg, operations that don't cross that boundary are
         * cheap, and those that do aren't), but the special-casing of
         * composite==0 and invariants throughtout the system relying on
         * composite==0 make it hard.  We need profiling data on the breakdown
         * of the frequency of various paths through this function.
         */
        REALLY_INLINE void DecrementRef()
        {
#ifdef GCDEBUG
            // This is a deleted object so ignore it.
            if(IsGCPoisoned())
                return;
#endif
            // This is a deleted/free object so ignore it.
            if (composite == 0)
                return;

            REFCOUNT_PROFILING_ONLY( GC::GetGC(this)->policy.signalDecrementRef(); )
            if(Sticky())
                return;

#ifdef GCDEBUG
            GC* gc = GC::GetGC(this);
            GCAssert(gc->IsRCObjectSafe(this));

            // ???
            if(gc->Destroying())
                return;

            if(RefCount() == 0) {
#ifdef MMGC_RC_HISTORY
                DumpHistory();
#endif
                GCAssert(false);
            }
#endif

            if (RefCount() == 0)
            {
                // This is a defensive measure.  If DecrementRef is
                // ever called on a zero ref-count object, composite--
                // will cause an underflow, flipping all kinds of bits
                // in bad ways and resulting in a crash later.  Often,
                // such a DecrementRef bug would be caught by the
                // GCDEBUG asserts above, but sometimes we have
                // release-only crashers like this.  Better to fail
                // gracefully at the point of failure, rather than
                // push the failure to some later point.
                return;
            }

            composite--;

#ifdef MMGC_RC_HISTORY
            if(GC::GetGC(this)->keepDRCHistory && GCHeap::GetGCHeap()->GetProfiler())
                history.Add(GCHeap::GetGCHeap()->GetProfiler()->GetStackTrace());
#endif

            if(RefCount() == 0)
                GC::GetGC(this)->AddToZCT(this);
        }

#ifdef MMGC_RC_HISTORY
        void DumpHistory();
#endif

    private:

        // @return non-zero if the object is in the ZCT
        uint32_t InZCT() const
        {
            return composite & ZCTFLAG;
        }

        // Clear the ZCT flag and the ZCT index
        void ClearZCTFlag()
        {
            composite &= ~(ZCTFLAG|ZCT_INDEX);
        }

        // @return the ZCT index.  This is only valid if InZCT returns non-zero.
        uint32_t getZCTIndex() const
        {
            return (composite & ZCT_INDEX) >> 8;
        }

        // Set the ZCT index and the ZCT flag and clear the pinned flag.
        void setZCTIndexAndUnpin(uint32_t index)
        {
            GCAssert(index <= (ZCT_INDEX>>8));
            composite = (composite&~(ZCT_INDEX|STACK_PIN)) | ((index<<8)|ZCTFLAG);
        }

        // Set the ZCT index and the ZCT flag.  If reaping==0 then clear the pinned flag,
        // otherwise preserve the pinned flag.
        void setZCTIndexAndMaybeUnpin(uint32_t index, uint32_t reaping)
        {
            GCAssert(reaping == 0 || reaping == 1);
            GCAssert(index <= (ZCT_INDEX>>8));
            composite = (composite&~(ZCT_INDEX|((~reaping&1)<<STACK_PIN_SHIFT))) | ((index<<8)|ZCTFLAG);
        }

        // Before we read composite tell valgrind its okay if
        // composite isn't defined.  Deleted RCObject pointers can
        // live on the stack so this read is always okay since we
        // check the page header and found this to be a committed
        // RCObject page.
        REALLY_INLINE uint32_t getCompositeSafe()
        {
            uint32_t *c = &composite;
            VALGRIND_MAKE_MEM_DEFINED(c, sizeof(c));
            return *c;
        }

        // Fields in 'composite'
        static const uint32_t ZCTFLAG            = 0x80000000;          // The object is in the ZCT
        static const uint32_t STICKYFLAG         = 0x40000000;          // The object is sticky (RC overflow)
        static const uint32_t STACK_PIN          = 0x20000000;          // The object has been pinned
        static const uint32_t STACK_PIN_SHIFT    = 29;
        static const uint32_t RCBITS             = 0x000000FF;          // 8 bits for the reference count
        static const uint32_t ZCT_INDEX          = 0x0FFFFF00;          // 20 bits for the ZCT index
        static const uint32_t ZCT_CAPACITY       = (ZCT_INDEX>>8) + 1;

        uint32_t composite;
#ifdef MMGC_RC_HISTORY
        // addref/decref stack traces
        BasicList<StackTrace*> history;
#endif // MMGC_MEMORY_INFO
    };

    template<class T, bool checkMissingWB=true>
    class RCPtr
    {
    public:
        RCPtr()
        {
            if(checkMissingWB)
                GCAssertMsg(GC::GetActiveGC() == NULL
                            || !GC::GetActiveGC()->IsPointerToGCPage(this),
                            "Need to use GCMember<> on GC memory");
            t = NULL;
        }
        RCPtr(T _t) : t(_t)
        {
            if(checkMissingWB)
                GCAssertMsg(GC::GetActiveGC() == NULL
                            || !GC::GetActiveGC()->IsPointerToGCPage(this),
                            "Need to use GCMember<> on GC memory");
            if(valid())
                t->IncrementRef();
        }
        ~RCPtr()
        {
            if(valid())
                t->DecrementRef();

            // 02may06 grandma : I want to enable
            //  class DataIOBase { GCMember<PlayerToplevel> const m_toplevel; }
            //
            // DataIOBase is a virtual base class, so we don't know if the
            // subclass is GCObject or not. We need it to be const, or
            // a GCObject would require a GCMember<>, and if it's const, we
            // cannot zero it out during ~DataIOBase. The simplest solution
            // seemed to be zeroing out the member here.

            t = NULL;
        }

        T operator=(T tNew)
        {
            if(valid())
                t->DecrementRef();
            t = tNew;
            if(valid())
                t->IncrementRef();
            // this cast is safe b/c other wise compilation would fail
            return (T) t;
        }

        RCPtr<T>& operator=(const RCPtr<T>& other)
        {
            if(valid())
                t->DecrementRef();
            t = other.t;
            if(valid())
                t->IncrementRef();
            return *this;
        }

        operator T() const
        {
            return (T) t;
        }

        bool operator!=(T other) { return other != t; }

        T operator->() const
        {
            return (T) t;
        }

        void Clear() { t = NULL; }

    private:
        // Hidden and meant not to be used at all.
        RCPtr(const RCPtr<T>& other);

        inline bool valid() { return (uintptr_t)t > 1; }
        T t;
    };

///////////////////////////////////////////////////////////////////////////
//
// NOTE!!  DRC and DRC_NOWB are deprecated!  Use GCMember<> when possible.

#ifndef AVMSHELL_BUILD
    // put spaces around the template arg to avoid possible digraph warnings
    #define DRC(_type) MMgc::RCPtr< _type, true >

    // This is a temporary bandaid for places where DRC is asserting due to
    // it being used on GC memory, use DRCWB instead.
    #define DRC_NOWB(_type) MMgc::RCPtr< _type, false >
#endif // AVMSHELL_BUILD

#undef GNUC_ONLY

}


#endif /* __GCObject__ */
