blob: 97b7a9533f9eda07d0794f1adbdbaf507d5c07f2 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/*
17 * Garbage-collecting memory allocator.
18 */
19#include "Dalvik.h"
20#include "alloc/Heap.h"
21#include "alloc/HeapInternal.h"
22
23#if WITH_HPROF && WITH_HPROF_STACK
24#include "hprof/Hprof.h"
25#endif
26
27
28/*
29 * Initialize the GC universe.
30 *
31 * We're currently using a memory-mapped arena to keep things off of the
32 * main heap. This needs to be replaced with something real.
33 */
34bool dvmGcStartup(void)
35{
36 dvmInitMutex(&gDvm.gcHeapLock);
37
38 return dvmHeapStartup();
39}
40
41/*
42 * Post-zygote heap initialization, including starting
43 * the HeapWorker thread.
44 */
45bool dvmGcStartupAfterZygote(void)
46{
47 if (!dvmHeapWorkerStartup()) {
48 return false;
49 }
Carl Shapiroc8e06c82010-02-04 19:12:55 -080050 dvmHeapStartupAfterZygote();
51 return true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080052}
53
54/*
55 * Shut the GC down.
56 */
57void dvmGcShutdown(void)
58{
59 //TODO: grab and destroy the lock
60 dvmHeapShutdown();
61}
62
63/*
64 * Do any last-minute preparation before we call fork() for the first time.
65 */
66bool dvmGcPreZygoteFork(void)
67{
68 return dvmHeapSourceStartupBeforeFork();
69}
70
71/*
Andy McFadden7fc3ce82009-07-14 15:57:23 -070072 * Create a "stock instance" of an exception class.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080073 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -070074static Object* createStockException(const char* descriptor, const char* msg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080075{
Andy McFadden7fc3ce82009-07-14 15:57:23 -070076 Thread* self = dvmThreadSelf();
77 StringObject* msgStr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080078 ClassObject* clazz;
79 Method* init;
80 Object* obj;
81
Andy McFadden7fc3ce82009-07-14 15:57:23 -070082 /* find class, initialize if necessary */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080083 clazz = dvmFindSystemClass(descriptor);
84 if (clazz == NULL) {
85 LOGE("Unable to find %s\n", descriptor);
86 return NULL;
87 }
88
Andy McFadden7fc3ce82009-07-14 15:57:23 -070089 init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
90 "(Ljava/lang/String;)V");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080091 if (init == NULL) {
Andy McFadden7fc3ce82009-07-14 15:57:23 -070092 LOGE("Unable to find String-arg constructor for %s\n", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080093 return NULL;
94 }
95
96 obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
97 if (obj == NULL)
98 return NULL;
99
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700100 if (msg == NULL) {
101 msgStr = NULL;
102 } else {
103 msgStr = dvmCreateStringFromCstr(msg, ALLOC_DEFAULT);
104 if (msgStr == NULL) {
105 LOGW("Could not allocate message string \"%s\"\n", msg);
106 dvmReleaseTrackedAlloc(obj, self);
107 return NULL;
108 }
109 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800110
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700111 JValue unused;
112 dvmCallMethod(self, init, obj, &unused, msgStr);
113 if (dvmCheckException(self)) {
114 dvmReleaseTrackedAlloc((Object*) msgStr, self);
115 dvmReleaseTrackedAlloc(obj, self);
116 return NULL;
117 }
118
119 dvmReleaseTrackedAlloc((Object*) msgStr, self); // okay if msgStr NULL
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800120 return obj;
121}
122
123/*
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700124 * Create some "stock" exceptions. These can be thrown when the system is
125 * too screwed up to allocate and initialize anything, or when we don't
126 * need a meaningful stack trace.
127 *
128 * We can't do this during the initial startup because we need to execute
129 * the constructors.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800130 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700131bool dvmCreateStockExceptions(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800132{
133 /*
134 * Pre-allocate some throwables. These need to be explicitly added
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700135 * to the GC's root set (see dvmHeapMarkRootSet()).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800136 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700137 gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
138 "[memory exhausted]");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800139 dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700140 gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
141 "[pre-allocated]");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800142 dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700143 gDvm.noClassDefFoundErrorObj =
Andy McFadden4c691d12009-12-10 15:11:18 -0800144 createStockException("Ljava/lang/NoClassDefFoundError;",
145 "[generic]");
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700146 dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
147
148 if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
149 gDvm.noClassDefFoundErrorObj == NULL)
150 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800151 LOGW("Unable to create stock exceptions\n");
152 return false;
153 }
154
155 return true;
156}
157
158
159/*
160 * Create an instance of the specified class.
161 *
162 * Returns NULL and throws an exception on failure.
163 */
164Object* dvmAllocObject(ClassObject* clazz, int flags)
165{
166 Object* newObj;
167
168 assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
169
170 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
171 flags |= ALLOC_FINALIZABLE;
172 }
173
174 /* allocate on GC heap; memory is zeroed out */
175 newObj = dvmMalloc(clazz->objectSize, flags);
176 if (newObj != NULL) {
177 DVM_OBJECT_INIT(newObj, clazz);
178 LOGVV("AllocObject: %s (%d)\n", clazz->descriptor,
179 (int) clazz->objectSize);
180#if WITH_HPROF && WITH_HPROF_STACK
181 hprofFillInStackTrace(newObj);
182#endif
183 dvmTrackAllocation(clazz, clazz->objectSize);
184 }
185
186 return newObj;
187}
188
189/*
190 * Create a copy of an object, for Object.clone().
191 *
192 * We use the size actually allocated, rather than obj->clazz->objectSize,
193 * because the latter doesn't work for array objects.
194 */
195Object* dvmCloneObject(Object* obj)
196{
197 Object* copy;
198 int size;
199 int flags;
200
201 assert(dvmIsValidObject(obj));
202
203 /* Class.java shouldn't let us get here (java.lang.Class is final
204 * and does not implement Clonable), but make extra sure.
205 * A memcpy() clone will wreak havoc on a ClassObject's "innards".
206 */
207 assert(obj->clazz != gDvm.classJavaLangClass);
208
209 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE))
210 flags = ALLOC_DEFAULT | ALLOC_FINALIZABLE;
211 else
212 flags = ALLOC_DEFAULT;
213
214//TODO: use clazz->objectSize for non-arrays
215 size = dvmObjectSizeInHeap(obj);
216
217 copy = dvmMalloc(size, flags);
218 if (copy == NULL)
219 return NULL;
220#if WITH_HPROF && WITH_HPROF_STACK
221 hprofFillInStackTrace(copy);
222 dvmTrackAllocation(obj->clazz, size);
223#endif
224
225 memcpy(copy, obj, size);
226 DVM_LOCK_INIT(&copy->lock);
227
228 //LOGV("CloneObject: %p->%p %s (%d)\n", obj, copy, obj->clazz->name, size);
229
230 // TODO: deal with reference classes
231
232 /* don't call dvmReleaseTrackedAlloc -- the caller must do that */
233
234 return copy;
235}
236
237
238/*
239 * Track an object that was allocated internally and isn't yet part of the
240 * VM root set.
241 *
242 * We could do this per-thread or globally. If it's global we don't have
243 * to do the thread lookup but we do have to synchronize access to the list.
244 *
245 * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
246 * usually be NULL since we're being called from dvmMalloc().
247 */
248void dvmAddTrackedAlloc(Object* obj, Thread* self)
249{
250 if (self == NULL)
251 self = dvmThreadSelf();
252
253 //LOGI("TRACK ADD %p\n", obj);
254
255 assert(self != NULL);
256 if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
257 LOGE("threadid=%d: unable to add %p to internal ref table\n",
258 self->threadId, obj);
259 dvmDumpThread(self, false);
260 dvmAbort();
261 }
262}
263
264/*
265 * Stop tracking an object.
266 *
267 * We allow attempts to delete NULL "obj" so that callers don't have to wrap
268 * calls with "if != NULL".
269 */
270void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
271{
272 if (obj == NULL)
273 return;
274
275 if (self == NULL)
276 self = dvmThreadSelf();
277 assert(self != NULL);
278
279 //LOGI("TRACK REM %p (%s)\n", obj,
280 // (obj->clazz != NULL) ? obj->clazz->name : "");
281
282 if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
283 self->internalLocalRefTable.table, obj))
284 {
285 LOGE("threadid=%d: failed to remove %p from internal ref table\n",
286 self->threadId, obj);
287 dvmAbort();
288 }
289}
290
291
292/*
293 * Explicitly initiate garbage collection.
294 */
295void dvmCollectGarbage(bool collectSoftReferences)
296{
297 dvmLockHeap();
298
299 LOGVV("Explicit GC\n");
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800300 dvmCollectGarbageInternal(collectSoftReferences, GC_EXPLICIT);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800301
302 dvmUnlockHeap();
303}