• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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  */
dvmGcStartup(void)34 bool 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  */
dvmGcStartupAfterZygote(void)45 bool dvmGcStartupAfterZygote(void)
46 {
47     if (!dvmHeapWorkerStartup()) {
48         return false;
49     }
50     return dvmHeapStartupAfterZygote();
51 }
52 
53 /*
54  * Shut the GC down.
55  */
dvmGcShutdown(void)56 void 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  */
dvmGcPreZygoteFork(void)65 bool dvmGcPreZygoteFork(void)
66 {
67     return dvmHeapSourceStartupBeforeFork();
68 }
69 
70 /*
71  * Create a "stock instance" of an exception class.  These won't have
72  * useful stack traces in them, but they can be thrown when everything
73  * else is not working in a container class.
74  */
createStockException(const char * descriptor)75 static Object* createStockException(const char* descriptor)
76 {
77     ClassObject* clazz;
78     Method* init;
79     Object* obj;
80 
81     clazz = dvmFindSystemClass(descriptor);
82     if (clazz == NULL) {
83         LOGE("Unable to find %s\n", descriptor);
84         return NULL;
85     }
86 
87     init = dvmFindDirectMethodByDescriptor(clazz, "<init>", "()V");
88     if (init == NULL) {
89         LOGE("Unable to find nullary constructor for %s\n", descriptor);
90         return NULL;
91     }
92 
93     obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
94     if (obj == NULL)
95         return NULL;
96 
97     Thread* self = dvmThreadSelf();
98     JValue unused;
99     dvmCallMethod(self, init, obj, &unused);
100     if (dvmCheckException(self))
101         return NULL;
102 
103     return obj;
104 }
105 
106 /*
107  * "Late" initialization.  We had to defer this until we were able to
108  * interpret code.
109  */
dvmGcLateInit(void)110 bool dvmGcLateInit(void)
111 {
112     /*
113      * Pre-allocate some throwables.  These need to be explicitly added
114      * to the root set by the GC.
115      */
116     gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;");
117     dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
118     gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;");
119     dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
120     if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL) {
121         LOGW("Unable to create stock exceptions\n");
122         return false;
123     }
124 
125     return true;
126 }
127 
128 
129 /*
130  * Create an instance of the specified class.
131  *
132  * Returns NULL and throws an exception on failure.
133  */
dvmAllocObject(ClassObject * clazz,int flags)134 Object* dvmAllocObject(ClassObject* clazz, int flags)
135 {
136     Object* newObj;
137 
138     assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
139 
140     if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
141         flags |= ALLOC_FINALIZABLE;
142     }
143 
144     /* allocate on GC heap; memory is zeroed out */
145     newObj = dvmMalloc(clazz->objectSize, flags);
146     if (newObj != NULL) {
147         DVM_OBJECT_INIT(newObj, clazz);
148         LOGVV("AllocObject: %s (%d)\n", clazz->descriptor,
149             (int) clazz->objectSize);
150 #if WITH_HPROF && WITH_HPROF_STACK
151         hprofFillInStackTrace(newObj);
152 #endif
153         dvmTrackAllocation(clazz, clazz->objectSize);
154     }
155 
156     return newObj;
157 }
158 
159 /*
160  * Create a copy of an object, for Object.clone().
161  *
162  * We use the size actually allocated, rather than obj->clazz->objectSize,
163  * because the latter doesn't work for array objects.
164  */
dvmCloneObject(Object * obj)165 Object* dvmCloneObject(Object* obj)
166 {
167     Object* copy;
168     int size;
169     int flags;
170 
171     assert(dvmIsValidObject(obj));
172 
173     /* Class.java shouldn't let us get here (java.lang.Class is final
174      * and does not implement Clonable), but make extra sure.
175      * A memcpy() clone will wreak havoc on a ClassObject's "innards".
176      */
177     assert(obj->clazz != gDvm.classJavaLangClass);
178 
179     if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE))
180         flags = ALLOC_DEFAULT | ALLOC_FINALIZABLE;
181     else
182         flags = ALLOC_DEFAULT;
183 
184 //TODO: use clazz->objectSize for non-arrays
185     size = dvmObjectSizeInHeap(obj);
186 
187     copy = dvmMalloc(size, flags);
188     if (copy == NULL)
189         return NULL;
190 #if WITH_HPROF && WITH_HPROF_STACK
191     hprofFillInStackTrace(copy);
192     dvmTrackAllocation(obj->clazz, size);
193 #endif
194 
195     memcpy(copy, obj, size);
196     DVM_LOCK_INIT(&copy->lock);
197 
198     //LOGV("CloneObject: %p->%p %s (%d)\n", obj, copy, obj->clazz->name, size);
199 
200     // TODO: deal with reference classes
201 
202     /* don't call dvmReleaseTrackedAlloc -- the caller must do that */
203 
204     return copy;
205 }
206 
207 
208 /*
209  * Track an object that was allocated internally and isn't yet part of the
210  * VM root set.
211  *
212  * We could do this per-thread or globally.  If it's global we don't have
213  * to do the thread lookup but we do have to synchronize access to the list.
214  *
215  * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
216  * usually be NULL since we're being called from dvmMalloc().
217  */
dvmAddTrackedAlloc(Object * obj,Thread * self)218 void dvmAddTrackedAlloc(Object* obj, Thread* self)
219 {
220     if (self == NULL)
221         self = dvmThreadSelf();
222 
223     //LOGI("TRACK ADD %p\n", obj);
224 
225     assert(self != NULL);
226     if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
227         LOGE("threadid=%d: unable to add %p to internal ref table\n",
228             self->threadId, obj);
229         dvmDumpThread(self, false);
230         dvmAbort();
231     }
232 }
233 
234 /*
235  * Stop tracking an object.
236  *
237  * We allow attempts to delete NULL "obj" so that callers don't have to wrap
238  * calls with "if != NULL".
239  */
dvmReleaseTrackedAlloc(Object * obj,Thread * self)240 void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
241 {
242     if (obj == NULL)
243         return;
244 
245     if (self == NULL)
246         self = dvmThreadSelf();
247     assert(self != NULL);
248 
249     //LOGI("TRACK REM %p (%s)\n", obj,
250     //    (obj->clazz != NULL) ? obj->clazz->name : "");
251 
252     if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
253             self->internalLocalRefTable.table, obj))
254     {
255         LOGE("threadid=%d: failed to remove %p from internal ref table\n",
256             self->threadId, obj);
257         dvmAbort();
258     }
259 }
260 
261 
262 /*
263  * Explicitly initiate garbage collection.
264  */
dvmCollectGarbage(bool collectSoftReferences)265 void dvmCollectGarbage(bool collectSoftReferences)
266 {
267     dvmLockHeap();
268 
269     LOGVV("Explicit GC\n");
270     dvmCollectGarbageInternal(collectSoftReferences);
271 
272     dvmUnlockHeap();
273 }
274