Alloc.cpp revision 2494c5038e668add68c74dea83aca05187a89e7c
160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky/*
260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Copyright (C) 2008 The Android Open Source Project
360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky *
460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Licensed under the Apache License, Version 2.0 (the "License");
560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * you may not use this file except in compliance with the License.
660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * You may obtain a copy of the License at
760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky *
860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky *      http://www.apache.org/licenses/LICENSE-2.0
960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky *
1060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Unless required by applicable law or agreed to in writing, software
1160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * distributed under the License is distributed on an "AS IS" BASIS,
1260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * See the License for the specific language governing permissions and
1460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * limitations under the License.
1560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky */
1660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky/*
1760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Garbage-collecting memory allocator.
1860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky */
1960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky#include "Dalvik.h"
202e402d5b5f2fce8bfe29509cc771b9919946003bEli Bendersky#include "alloc/Heap.h"
212e402d5b5f2fce8bfe29509cc771b9919946003bEli Bendersky#include "alloc/HeapInternal.h"
2260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky#include "alloc/HeapSource.h"
2360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
2460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky/*
2560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Initialize the GC universe.
26ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky *
2760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * We're currently using a memory-mapped arena to keep things off of the
288a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky * main heap.  This needs to be replaced with something real.
298a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky */
308a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Benderskybool dvmGcStartup(void)
3160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky{
3260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    dvmInitMutex(&gDvm.gcHeapLock);
3360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
34ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky    return dvmHeapStartup();
3560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky}
3660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
37ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky/*
38ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky * Post-zygote heap initialization, including starting
39ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky * the HeapWorker thread.
4060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky */
41ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Benderskybool dvmGcStartupAfterZygote(void)
42ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky{
4360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (!dvmHeapWorkerStartup()) {
44ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky        return false;
45ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky    }
4660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    return dvmHeapStartupAfterZygote();
4760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky}
4860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
4974b3c8da4800c7e8ba8f019879db29738ecc5f74Benjamin Kramer/*
502e402d5b5f2fce8bfe29509cc771b9919946003bEli Bendersky * Shutdown the threads internal to the garbage collector.
5160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky */
5260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskyvoid dvmGcThreadShutdown(void)
5360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky{
5460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    dvmHeapWorkerShutdown();
5560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    dvmHeapThreadShutdown();
5660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky}
5760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
5860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky/*
5960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Shut the GC down.
6060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky */
61ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Benderskyvoid dvmGcShutdown(void)
6260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky{
638a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky    //TODO: grab and destroy the lock
648a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky    dvmHeapShutdown();
658a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky}
6660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
6790e01ac0ea5bdc6dd6bccd9c59c3acb04e339666NAKAMURA Takumi/*
6890e01ac0ea5bdc6dd6bccd9c59c3acb04e339666NAKAMURA Takumi * Do any last-minute preparation before we call fork() for the first time.
6990e01ac0ea5bdc6dd6bccd9c59c3acb04e339666NAKAMURA Takumi */
7060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskybool dvmGcPreZygoteFork(void)
7160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky{
720b821eff4c9c8d3b7ac872691bc453337ad3d03aDavid Tweed    return dvmHeapSourceStartupBeforeFork();
730b821eff4c9c8d3b7ac872691bc453337ad3d03aDavid Tweed}
740b821eff4c9c8d3b7ac872691bc453337ad3d03aDavid Tweed
7560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky/*
7660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Create a "stock instance" of an exception class.
7760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky */
7860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskystatic Object* createStockException(const char* descriptor, const char* msg)
7960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky{
8060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    Thread* self = dvmThreadSelf();
81ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky    StringObject* msgStr = NULL;
8260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    ClassObject* clazz;
83ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky    Method* init;
8460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    Object* obj;
8560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
8660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    /* find class, initialize if necessary */
8760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    clazz = dvmFindSystemClass(descriptor);
8860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (clazz == NULL) {
8960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        LOGE("Unable to find %s\n", descriptor);
9060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        return NULL;
9160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    }
922e402d5b5f2fce8bfe29509cc771b9919946003bEli Bendersky
9360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
9460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky            "(Ljava/lang/String;)V");
9560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (init == NULL) {
9660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        LOGE("Unable to find String-arg constructor for %s\n", descriptor);
9760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        return NULL;
98ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky    }
99ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky
10060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
10160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (obj == NULL)
102ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky        return NULL;
10360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
1048a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky    if (msg == NULL) {
1058a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky        msgStr = NULL;
1068a0329e6ffc290fb177fd058a64b4cf81d4b620aEli Bendersky    } else {
10760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        msgStr = dvmCreateStringFromCstr(msg);
10890e01ac0ea5bdc6dd6bccd9c59c3acb04e339666NAKAMURA Takumi        if (msgStr == NULL) {
109d9a8d43ed3e7c6c32f52ab5d0f627f7b1cdb6aacNAKAMURA Takumi            LOGW("Could not allocate message string \"%s\"\n", msg);
11060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky            dvmReleaseTrackedAlloc(obj, self);
111d9a8d43ed3e7c6c32f52ab5d0f627f7b1cdb6aacNAKAMURA Takumi            return NULL;
1128ff0631967c64d51b193b862aa0a6f1e8eb06f78NAKAMURA Takumi        }
1138ff0631967c64d51b193b862aa0a6f1e8eb06f78NAKAMURA Takumi    }
11460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
115b2ac7c09b17efadea2a9f90f45801d9d2ee687aaEli Bendersky    JValue unused;
116b2ac7c09b17efadea2a9f90f45801d9d2ee687aaEli Bendersky    dvmCallMethod(self, init, obj, &unused, msgStr);
117b2ac7c09b17efadea2a9f90f45801d9d2ee687aaEli Bendersky    if (dvmCheckException(self)) {
11860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        dvmReleaseTrackedAlloc((Object*) msgStr, self);
11960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        dvmReleaseTrackedAlloc(obj, self);
12060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        return NULL;
12160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    }
12260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
12360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    dvmReleaseTrackedAlloc((Object*) msgStr, self);     // okay if msgStr NULL
124ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky    return obj;
125ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky}
12660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
12760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky/*
12860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Create some "stock" exceptions.  These can be thrown when the system is
12960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * too screwed up to allocate and initialize anything, or when we don't
13060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * need a meaningful stack trace.
13174b3c8da4800c7e8ba8f019879db29738ecc5f74Benjamin Kramer *
13260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * We can't do this during the initial startup because we need to execute
13360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * the constructors.
134ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky */
13560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Benderskybool dvmCreateStockExceptions(void)
13660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky{
13760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    /*
138ba42625074aa7f4f1324a5d6666bd0e302b57f2bEli Bendersky     * Pre-allocate some throwables.  These need to be explicitly added
13960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky     * to the GC's root set (see dvmHeapMarkRootSet()).
14060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky     */
14160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
14260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        "[memory exhausted]");
14360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
14460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
14560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        "[pre-allocated]");
14660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
14760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    gDvm.noClassDefFoundErrorObj =
14860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        createStockException("Ljava/lang/NoClassDefFoundError;",
14960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky            "[generic]");
15060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
15160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
15260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
15360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        gDvm.noClassDefFoundErrorObj == NULL)
15460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    {
15560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        LOGW("Unable to create stock exceptions\n");
15660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        return false;
15760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    }
15860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
15960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    return true;
16060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky}
16160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
16260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
16360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky/*
16460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Create an instance of the specified class.
16560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky *
16660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Returns NULL and throws an exception on failure.
16760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky */
16860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli BenderskyObject* dvmAllocObject(ClassObject* clazz, int flags)
16960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky{
17060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    Object* newObj;
17160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
17260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
17360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
17460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    /* allocate on GC heap; memory is zeroed out */
17560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    newObj = (Object*)dvmMalloc(clazz->objectSize, flags);
17660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (newObj != NULL) {
17760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        DVM_OBJECT_INIT(newObj, clazz);
17860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        dvmTrackAllocation(clazz, clazz->objectSize);   /* notify DDMS */
17960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    }
18060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
18160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    return newObj;
18260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky}
18360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
18460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky/*
18560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * Create a copy of an object, for Object.clone().
18660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky *
18760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * We use the size actually allocated, rather than obj->clazz->objectSize,
18860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky * because the latter doesn't work for array objects.
18960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky */
19060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli BenderskyObject* dvmCloneObject(Object* obj, int flags)
19160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky{
19260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    ClassObject* clazz;
19360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    Object* copy;
19460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    size_t size;
19560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
19660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    assert(dvmIsValidObject(obj));
19760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    clazz = obj->clazz;
19860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
19960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    /* Class.java shouldn't let us get here (java.lang.Class is final
20060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky     * and does not implement Clonable), but make extra sure.
20160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky     * A memcpy() clone will wreak havoc on a ClassObject's "innards".
20260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky     */
20360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    assert(clazz != gDvm.classJavaLangClass);
20460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
20560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
20660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        size = dvmArrayObjectSize((ArrayObject *)obj);
20760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    } else {
20860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        size = clazz->objectSize;
20960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    }
21060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
21160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    copy = (Object*)dvmMalloc(size, flags);
21260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (copy == NULL)
21360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        return NULL;
21460bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
21560bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    /* We assume that memcpy will copy obj by words. */
21660bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    memcpy(copy, obj, size);
21760bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    DVM_LOCK_INIT(&copy->lock);
21860bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    dvmWriteBarrierObject(copy);
21960bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky
22060bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    /* Mark the clone as finalizable if appropriate. */
22160bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
22260bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky        dvmSetFinalizable(copy);
22360bdc5b16e2fc17be184b515a00c2e2a2eb40b89Eli Bendersky    }
224
225    dvmTrackAllocation(clazz, size);    /* notify DDMS */
226
227    return copy;
228}
229
230
231/*
232 * Track an object that was allocated internally and isn't yet part of the
233 * VM root set.
234 *
235 * We could do this per-thread or globally.  If it's global we don't have
236 * to do the thread lookup but we do have to synchronize access to the list.
237 *
238 * "obj" must not be NULL.
239 *
240 * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
241 * usually be NULL since we're being called from dvmMalloc().
242 */
243void dvmAddTrackedAlloc(Object* obj, Thread* self)
244{
245    if (self == NULL)
246        self = dvmThreadSelf();
247
248    assert(obj != NULL);
249    assert(self != NULL);
250    if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
251        LOGE("threadid=%d: unable to add %p to internal ref table\n",
252            self->threadId, obj);
253        dvmDumpThread(self, false);
254        dvmAbort();
255    }
256}
257
258/*
259 * Stop tracking an object.
260 *
261 * We allow attempts to delete NULL "obj" so that callers don't have to wrap
262 * calls with "if != NULL".
263 */
264void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
265{
266    if (obj == NULL)
267        return;
268
269    if (self == NULL)
270        self = dvmThreadSelf();
271    assert(self != NULL);
272
273    if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
274            self->internalLocalRefTable.table, obj))
275    {
276        LOGE("threadid=%d: failed to remove %p from internal ref table\n",
277            self->threadId, obj);
278        dvmAbort();
279    }
280}
281
282
283/*
284 * Explicitly initiate garbage collection.
285 */
286void dvmCollectGarbage(void)
287{
288    if (gDvm.disableExplicitGc) {
289        return;
290    }
291    dvmLockHeap();
292    dvmWaitForConcurrentGcToComplete();
293    dvmCollectGarbageInternal(GC_EXPLICIT);
294    dvmUnlockHeap();
295}
296
297typedef struct {
298    const ClassObject *clazz;
299    size_t count;
300} CountContext;
301
302static void countInstancesOfClassCallback(void *ptr, void *arg)
303{
304    CountContext *ctx = (CountContext *)arg;
305    const Object *obj = (const Object *)ptr;
306
307    assert(ctx != NULL);
308    if (obj->clazz == ctx->clazz) {
309        ctx->count += 1;
310    }
311}
312
313size_t dvmCountInstancesOfClass(const ClassObject *clazz)
314{
315    CountContext ctx = { clazz, 0 };
316    dvmLockHeap();
317    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
318    dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
319    dvmUnlockHeap();
320    return ctx.count;
321}
322
323static void countAssignableInstancesOfClassCallback(void *ptr, void *arg)
324{
325    CountContext *ctx = (CountContext *)arg;
326    const Object *obj = (const Object *)ptr;
327
328    assert(ctx != NULL);
329    if (obj->clazz != NULL && dvmInstanceof(obj->clazz, ctx->clazz)) {
330        ctx->count += 1;
331    }
332}
333
334size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
335{
336    CountContext ctx = { clazz, 0 };
337    dvmLockHeap();
338    HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
339    dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);
340    dvmUnlockHeap();
341    return ctx.count;
342}
343
344bool dvmIsHeapAddress(void *address)
345{
346    return dvmHeapSourceContainsAddress(address);
347}
348