blob: d209e4a493025030919d1558ed57131d1c7876d5 [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 }
50 return dvmHeapStartupAfterZygote();
51}
52
53/*
54 * Shut the GC down.
55 */
56void dvmGcShutdown(void)
57{
58 //TODO: grab and destroy the lock
59 dvmHeapShutdown();
60}
61
62/*
63 * Do any last-minute preparation before we call fork() for the first time.
64 */
65bool dvmGcPreZygoteFork(void)
66{
67 return dvmHeapSourceStartupBeforeFork();
68}
69
70/*
Andy McFadden7fc3ce82009-07-14 15:57:23 -070071 * Create a "stock instance" of an exception class.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080072 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -070073static Object* createStockException(const char* descriptor, const char* msg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080074{
Andy McFadden7fc3ce82009-07-14 15:57:23 -070075 Thread* self = dvmThreadSelf();
76 StringObject* msgStr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080077 ClassObject* clazz;
78 Method* init;
79 Object* obj;
80
Andy McFadden7fc3ce82009-07-14 15:57:23 -070081 /* find class, initialize if necessary */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080082 clazz = dvmFindSystemClass(descriptor);
83 if (clazz == NULL) {
84 LOGE("Unable to find %s\n", descriptor);
85 return NULL;
86 }
87
Andy McFadden7fc3ce82009-07-14 15:57:23 -070088 init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
89 "(Ljava/lang/String;)V");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080090 if (init == NULL) {
Andy McFadden7fc3ce82009-07-14 15:57:23 -070091 LOGE("Unable to find String-arg constructor for %s\n", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080092 return NULL;
93 }
94
95 obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
96 if (obj == NULL)
97 return NULL;
98
Andy McFadden7fc3ce82009-07-14 15:57:23 -070099 if (msg == NULL) {
100 msgStr = NULL;
101 } else {
102 msgStr = dvmCreateStringFromCstr(msg, ALLOC_DEFAULT);
103 if (msgStr == NULL) {
104 LOGW("Could not allocate message string \"%s\"\n", msg);
105 dvmReleaseTrackedAlloc(obj, self);
106 return NULL;
107 }
108 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800109
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700110 JValue unused;
111 dvmCallMethod(self, init, obj, &unused, msgStr);
112 if (dvmCheckException(self)) {
113 dvmReleaseTrackedAlloc((Object*) msgStr, self);
114 dvmReleaseTrackedAlloc(obj, self);
115 return NULL;
116 }
117
118 dvmReleaseTrackedAlloc((Object*) msgStr, self); // okay if msgStr NULL
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800119 return obj;
120}
121
122/*
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700123 * Create some "stock" exceptions. These can be thrown when the system is
124 * too screwed up to allocate and initialize anything, or when we don't
125 * need a meaningful stack trace.
126 *
127 * We can't do this during the initial startup because we need to execute
128 * the constructors.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800129 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700130bool dvmCreateStockExceptions(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800131{
132 /*
133 * Pre-allocate some throwables. These need to be explicitly added
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700134 * to the GC's root set (see dvmHeapMarkRootSet()).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800135 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700136 gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
137 "[memory exhausted]");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800138 dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700139 gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
140 "[pre-allocated]");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800141 dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700142 gDvm.noClassDefFoundErrorObj =
Andy McFadden4c691d12009-12-10 15:11:18 -0800143 createStockException("Ljava/lang/NoClassDefFoundError;",
144 "[generic]");
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700145 dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
146
147 if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
148 gDvm.noClassDefFoundErrorObj == NULL)
149 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800150 LOGW("Unable to create stock exceptions\n");
151 return false;
152 }
153
154 return true;
155}
156
157
158/*
159 * Create an instance of the specified class.
160 *
161 * Returns NULL and throws an exception on failure.
162 */
163Object* dvmAllocObject(ClassObject* clazz, int flags)
164{
165 Object* newObj;
166
167 assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
168
169 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
170 flags |= ALLOC_FINALIZABLE;
171 }
172
173 /* allocate on GC heap; memory is zeroed out */
174 newObj = dvmMalloc(clazz->objectSize, flags);
175 if (newObj != NULL) {
176 DVM_OBJECT_INIT(newObj, clazz);
177 LOGVV("AllocObject: %s (%d)\n", clazz->descriptor,
178 (int) clazz->objectSize);
179#if WITH_HPROF && WITH_HPROF_STACK
180 hprofFillInStackTrace(newObj);
181#endif
182 dvmTrackAllocation(clazz, clazz->objectSize);
183 }
184
185 return newObj;
186}
187
188/*
189 * Create a copy of an object, for Object.clone().
190 *
191 * We use the size actually allocated, rather than obj->clazz->objectSize,
192 * because the latter doesn't work for array objects.
193 */
194Object* dvmCloneObject(Object* obj)
195{
196 Object* copy;
197 int size;
198 int flags;
199
200 assert(dvmIsValidObject(obj));
201
202 /* Class.java shouldn't let us get here (java.lang.Class is final
203 * and does not implement Clonable), but make extra sure.
204 * A memcpy() clone will wreak havoc on a ClassObject's "innards".
205 */
206 assert(obj->clazz != gDvm.classJavaLangClass);
207
208 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE))
209 flags = ALLOC_DEFAULT | ALLOC_FINALIZABLE;
210 else
211 flags = ALLOC_DEFAULT;
212
213//TODO: use clazz->objectSize for non-arrays
214 size = dvmObjectSizeInHeap(obj);
215
216 copy = dvmMalloc(size, flags);
217 if (copy == NULL)
218 return NULL;
219#if WITH_HPROF && WITH_HPROF_STACK
220 hprofFillInStackTrace(copy);
221 dvmTrackAllocation(obj->clazz, size);
222#endif
223
224 memcpy(copy, obj, size);
225 DVM_LOCK_INIT(&copy->lock);
226
227 //LOGV("CloneObject: %p->%p %s (%d)\n", obj, copy, obj->clazz->name, size);
228
229 // TODO: deal with reference classes
230
231 /* don't call dvmReleaseTrackedAlloc -- the caller must do that */
232
233 return copy;
234}
235
236
237/*
238 * Track an object that was allocated internally and isn't yet part of the
239 * VM root set.
240 *
241 * We could do this per-thread or globally. If it's global we don't have
242 * to do the thread lookup but we do have to synchronize access to the list.
243 *
244 * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
245 * usually be NULL since we're being called from dvmMalloc().
246 */
247void dvmAddTrackedAlloc(Object* obj, Thread* self)
248{
249 if (self == NULL)
250 self = dvmThreadSelf();
251
252 //LOGI("TRACK ADD %p\n", obj);
253
254 assert(self != NULL);
255 if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
256 LOGE("threadid=%d: unable to add %p to internal ref table\n",
257 self->threadId, obj);
258 dvmDumpThread(self, false);
259 dvmAbort();
260 }
261}
262
263/*
264 * Stop tracking an object.
265 *
266 * We allow attempts to delete NULL "obj" so that callers don't have to wrap
267 * calls with "if != NULL".
268 */
269void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
270{
271 if (obj == NULL)
272 return;
273
274 if (self == NULL)
275 self = dvmThreadSelf();
276 assert(self != NULL);
277
278 //LOGI("TRACK REM %p (%s)\n", obj,
279 // (obj->clazz != NULL) ? obj->clazz->name : "");
280
281 if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
282 self->internalLocalRefTable.table, obj))
283 {
284 LOGE("threadid=%d: failed to remove %p from internal ref table\n",
285 self->threadId, obj);
286 dvmAbort();
287 }
288}
289
290
291/*
292 * Explicitly initiate garbage collection.
293 */
294void dvmCollectGarbage(bool collectSoftReferences)
295{
296 dvmLockHeap();
297
298 LOGVV("Explicit GC\n");
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800299 dvmCollectGarbageInternal(collectSoftReferences, GC_EXPLICIT);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800300
301 dvmUnlockHeap();
302}