/*
 * Copyright (C) 2008 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.
 */
/*
 * Garbage-collecting allocator.
 */
#ifndef _DALVIK_ALLOC_ALLOC
#define _DALVIK_ALLOC_ALLOC

#include <stdlib.h>

/*
 * Initialization.
 */
bool dvmGcStartup(void);
bool dvmCreateStockExceptions(void);
bool dvmGcStartupAfterZygote(void);
void dvmGcShutdown(void);

/*
 * Do any last-minute preparation before we call fork() for the first time.
 */
bool dvmGcPreZygoteFork(void);

/*
 * Basic allocation function.
 *
 * The new object will be added to the "tracked alloc" table unless
 * flags is ALLOC_DONT_TRACK or ALLOC_NO_GC.
 *
 * Returns NULL and throws an exception on failure.
 */
void* dvmMalloc(size_t size, int flags);

/*
 * Allocate a new object.
 *
 * The new object will be added to the "tracked alloc" table unless
 * flags is ALLOC_DONT_TRACK or ALLOC_NO_GC.
 *
 * Returns NULL and throws an exception on failure.
 */
Object* dvmAllocObject(ClassObject* clazz, int flags);

/*
 * Clear flags set by dvmMalloc.  Pass in a bit mask of the flags that
 * should be cleared.
 */
void dvmClearAllocFlags(Object* obj, int mask);

/* flags for dvmMalloc */
enum {
    ALLOC_DEFAULT       = 0x00,
    ALLOC_NO_GC         = 0x01,     /* do not garbage collect this object */
    ALLOC_DONT_TRACK    = 0x02,     /* don't add to internal tracking list */
    ALLOC_FINALIZABLE   = 0x04,     /* call finalize() before freeing */
    // ALLOC_NO_MOVE?
};

/*
 * Call when a request is so far off that we can't call dvmMalloc().  Throws
 * an exception with the specified message.
 */
void dvmThrowBadAllocException(const char* msg);

/*
 * Track an object reference that is currently only visible internally.
 * This is called automatically by dvmMalloc() unless ALLOC_DONT_TRACK
 * is set.
 *
 * The "self" argument is allowed as an optimization; it may be NULL.
 */
void dvmAddTrackedAlloc(Object* obj, Thread* self);

/*
 * Remove an object from the internal tracking list.
 *
 * Does nothing if "obj" is NULL.
 *
 * The "self" argument is allowed as an optimization; it may be NULL.
 */
void dvmReleaseTrackedAlloc(Object* obj, Thread* self);

/*
 * Like dvmReleaseTrackedAlloc, but only does the release if "allocFlags"
 * indicates that it's necessary to do so.
 */
INLINE void dvmReleaseTrackedAllocIFN(Object* obj, Thread* self, int allocFlags)
{
    if ((allocFlags & (ALLOC_NO_GC|ALLOC_DONT_TRACK)) == 0)
        dvmReleaseTrackedAlloc(obj, self);
}

/*
 * Returns true iff <obj> points to a valid allocated object.
 */
bool dvmIsValidObject(const Object* obj);

/*
 * Create a copy of an object.
 *
 * The new object will be added to the "tracked alloc" table.
 */
Object* dvmCloneObject(Object* obj);

/*
 * Validate the object pointer.  Returns "false" and throws an exception if
 * "obj" is null or invalid.
 *
 * This may be used in performance critical areas as a null-pointer check;
 * anything else here should be for debug builds only.  In particular, for
 * "release" builds we want to skip the call to dvmIsValidObject() -- the
 * classfile validation will screen out code that puts invalid data into
 * object reference registers.
 */
INLINE int dvmValidateObject(Object* obj)
{
    if (obj == NULL) {
        dvmThrowException("Ljava/lang/NullPointerException;", NULL);
        return false;
    }
#ifdef WITH_EXTRA_OBJECT_VALIDATION
    if (!dvmIsValidObject(obj)) {
        dvmAbort();
        dvmThrowException("Ljava/lang/InternalError;",
            "VM detected invalid object ptr");
        return false;
    }
#endif
#ifndef NDEBUG
    /* check for heap corruption */
    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
        dvmAbort();
        dvmThrowException("Ljava/lang/InternalError;",
            "VM detected invalid object class ptr");
        return false;
    }
#endif
    return true;
}

/*
 * Determine the exact number of GC heap bytes used by an object.  (Internal
 * to heap code except for debugging.)
 */
size_t dvmObjectSizeInHeap(const Object* obj);

/*
 * Gets the current ideal heap utilization, represented as a number
 * between zero and one.
 */
float dvmGetTargetHeapUtilization(void);

/*
 * Sets the new ideal heap utilization, represented as a number
 * between zero and one.
 */
void dvmSetTargetHeapUtilization(float newTarget);

/*
 * If set is true, sets the new minimum heap size to size; always
 * returns the current (or previous) size.  If size is zero,
 * removes the current minimum constraint (if present).
 */
size_t dvmMinimumHeapSize(size_t size, bool set);

/*
 * Updates the internal count of externally-allocated memory.  If there's
 * enough room for that memory, returns true.  If not, returns false and
 * does not update the count.
 *
 * May cause a GC as a side-effect.
 */
bool dvmTrackExternalAllocation(size_t n);

/*
 * Reduces the internal count of externally-allocated memory.
 */
void dvmTrackExternalFree(size_t n);

/*
 * Returns the number of externally-allocated bytes being tracked by
 * dvmTrackExternalAllocation/Free().
 */
size_t dvmGetExternalBytesAllocated(void);

#endif /*_DALVIK_ALLOC_ALLOC*/