OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / dalvik / vm / alloc / Alloc.c
1 /*
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 #include "alloc/HeapSource.h"
23
24 #if WITH_HPROF && WITH_HPROF_STACK
25 #include "hprof/Hprof.h"
26 #endif
27
28
29 /*
30  * Initialize the GC universe.
31  *
32  * We're currently using a memory-mapped arena to keep things off of the
33  * main heap.  This needs to be replaced with something real.
34  */
35 bool dvmGcStartup(void)
36 {
37     dvmInitMutex(&gDvm.gcHeapLock);
38
39     return dvmHeapStartup();
40 }
41
42 /*
43  * Post-zygote heap initialization, including starting
44  * the HeapWorker thread.
45  */
46 bool dvmGcStartupAfterZygote(void)
47 {
48     if (!dvmHeapWorkerStartup()) {
49         return false;
50     }
51     return dvmHeapStartupAfterZygote();
52 }
53
54 /*
55  * Shutdown the threads internal to the garbage collector.
56  */
57 void dvmGcThreadShutdown(void)
58 {
59     dvmHeapWorkerShutdown();
60     dvmHeapThreadShutdown();
61 }
62
63 /*
64  * Shut the GC down.
65  */
66 void dvmGcShutdown(void)
67 {
68     //TODO: grab and destroy the lock
69     dvmHeapShutdown();
70 }
71
72 /*
73  * Do any last-minute preparation before we call fork() for the first time.
74  */
75 bool dvmGcPreZygoteFork(void)
76 {
77     return dvmHeapSourceStartupBeforeFork();
78 }
79
80 /*
81  * Create a "stock instance" of an exception class.
82  */
83 static Object* createStockException(const char* descriptor, const char* msg)
84 {
85     Thread* self = dvmThreadSelf();
86     StringObject* msgStr = NULL;
87     ClassObject* clazz;
88     Method* init;
89     Object* obj;
90
91     /* find class, initialize if necessary */
92     clazz = dvmFindSystemClass(descriptor);
93     if (clazz == NULL) {
94         LOGE("Unable to find %s\n", descriptor);
95         return NULL;
96     }
97
98     init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
99             "(Ljava/lang/String;)V");
100     if (init == NULL) {
101         LOGE("Unable to find String-arg constructor for %s\n", descriptor);
102         return NULL;
103     }
104
105     obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
106     if (obj == NULL)
107         return NULL;
108
109     if (msg == NULL) {
110         msgStr = NULL;
111     } else {
112         msgStr = dvmCreateStringFromCstr(msg);
113         if (msgStr == NULL) {
114             LOGW("Could not allocate message string \"%s\"\n", msg);
115             dvmReleaseTrackedAlloc(obj, self);
116             return NULL;
117         }
118     }
119
120     JValue unused;
121     dvmCallMethod(self, init, obj, &unused, msgStr);
122     if (dvmCheckException(self)) {
123         dvmReleaseTrackedAlloc((Object*) msgStr, self);
124         dvmReleaseTrackedAlloc(obj, self);
125         return NULL;
126     }
127
128     dvmReleaseTrackedAlloc((Object*) msgStr, self);     // okay if msgStr NULL
129     return obj;
130 }
131
132 /*
133  * Create some "stock" exceptions.  These can be thrown when the system is
134  * too screwed up to allocate and initialize anything, or when we don't
135  * need a meaningful stack trace.
136  *
137  * We can't do this during the initial startup because we need to execute
138  * the constructors.
139  */
140 bool dvmCreateStockExceptions(void)
141 {
142     /*
143      * Pre-allocate some throwables.  These need to be explicitly added
144      * to the GC's root set (see dvmHeapMarkRootSet()).
145      */
146     gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
147         "[memory exhausted]");
148     dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
149     gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
150         "[pre-allocated]");
151     dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
152     gDvm.noClassDefFoundErrorObj =
153         createStockException("Ljava/lang/NoClassDefFoundError;",
154             "[generic]");
155     dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
156
157     if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
158         gDvm.noClassDefFoundErrorObj == NULL)
159     {
160         LOGW("Unable to create stock exceptions\n");
161         return false;
162     }
163
164     return true;
165 }
166
167
168 /*
169  * Create an instance of the specified class.
170  *
171  * Returns NULL and throws an exception on failure.
172  */
173 Object* dvmAllocObject(ClassObject* clazz, int flags)
174 {
175     Object* newObj;
176
177     assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
178
179     if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
180         flags |= ALLOC_FINALIZABLE;
181     }
182
183     /* allocate on GC heap; memory is zeroed out */
184     newObj = dvmMalloc(clazz->objectSize, flags);
185     if (newObj != NULL) {
186         DVM_OBJECT_INIT(newObj, clazz);
187 #if WITH_HPROF && WITH_HPROF_STACK
188         hprofFillInStackTrace(newObj);
189 #endif
190         dvmTrackAllocation(clazz, clazz->objectSize);
191     }
192
193     return newObj;
194 }
195
196 /*
197  * Create a copy of an object, for Object.clone().
198  *
199  * We use the size actually allocated, rather than obj->clazz->objectSize,
200  * because the latter doesn't work for array objects.
201  */
202 Object* dvmCloneObject(Object* obj)
203 {
204     Object* copy;
205     int size;
206     int flags;
207
208     assert(dvmIsValidObject(obj));
209
210     /* Class.java shouldn't let us get here (java.lang.Class is final
211      * and does not implement Clonable), but make extra sure.
212      * A memcpy() clone will wreak havoc on a ClassObject's "innards".
213      */
214     assert(obj->clazz != gDvm.classJavaLangClass);
215
216     if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE))
217         flags = ALLOC_DEFAULT | ALLOC_FINALIZABLE;
218     else
219         flags = ALLOC_DEFAULT;
220
221     if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
222         size = dvmArrayObjectSize((ArrayObject *)obj);
223     } else {
224         size = obj->clazz->objectSize;
225     }
226
227     copy = dvmMalloc(size, flags);
228     if (copy == NULL)
229         return NULL;
230 #if WITH_HPROF && WITH_HPROF_STACK
231     hprofFillInStackTrace(copy);
232     dvmTrackAllocation(obj->clazz, size);
233 #endif
234
235     memcpy(copy, obj, size);
236     DVM_LOCK_INIT(&copy->lock);
237     dvmWriteBarrierObject(copy);
238
239     return copy;
240 }
241
242
243 /*
244  * Track an object that was allocated internally and isn't yet part of the
245  * VM root set.
246  *
247  * We could do this per-thread or globally.  If it's global we don't have
248  * to do the thread lookup but we do have to synchronize access to the list.
249  *
250  * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
251  * usually be NULL since we're being called from dvmMalloc().
252  */
253 void dvmAddTrackedAlloc(Object* obj, Thread* self)
254 {
255     if (self == NULL)
256         self = dvmThreadSelf();
257
258     assert(self != NULL);
259     if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
260         LOGE("threadid=%d: unable to add %p to internal ref table\n",
261             self->threadId, obj);
262         dvmDumpThread(self, false);
263         dvmAbort();
264     }
265 }
266
267 /*
268  * Stop tracking an object.
269  *
270  * We allow attempts to delete NULL "obj" so that callers don't have to wrap
271  * calls with "if != NULL".
272  */
273 void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
274 {
275     if (obj == NULL)
276         return;
277
278     if (self == NULL)
279         self = dvmThreadSelf();
280     assert(self != NULL);
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  */
295 void dvmCollectGarbage(bool collectSoftReferences)
296 {
297     dvmLockHeap();
298     while (gDvm.gcHeap->gcRunning) {
299         dvmWaitForConcurrentGcToComplete();
300     }
301     dvmCollectGarbageInternal(collectSoftReferences, GC_EXPLICIT);
302     dvmUnlockHeap();
303 }
304
305 typedef struct {
306     const ClassObject *clazz;
307     size_t count;
308 } CountContext;
309
310 static void countInstancesOfClassCallback(void *ptr, void *arg)
311 {
312     CountContext *ctx = arg;
313     const Object *obj = ptr;
314
315     assert(ctx != NULL);
316     if (obj->clazz == ctx->clazz) {
317         ctx->count += 1;
318     }
319 }
320
321 size_t dvmCountInstancesOfClass(const ClassObject *clazz)
322 {
323     CountContext ctx = { clazz, 0 };
324     HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
325     dvmLockHeap();
326     dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
327     dvmUnlockHeap();
328     return ctx.count;
329 }
330
331 static void countAssignableInstancesOfClassCallback(void *ptr, void *arg)
332 {
333     CountContext *ctx = arg;
334     const Object *obj = ptr;
335
336     assert(ctx != NULL);
337     if (dvmInstanceof(obj->clazz, ctx->clazz)) {
338         ctx->count += 1;
339     }
340 }
341
342 size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
343 {
344     CountContext ctx = { clazz, 0 };
345     HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
346     dvmLockHeap();
347     dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);
348     dvmUnlockHeap();
349     return ctx.count;
350 }