blob: f70b9787b6f6c1d1558df4ff6b4253fc5d6acdb1 [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00:29 -07001/*
2 * Copyright (C) 2009 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#include <sys/mman.h>
18#include <errno.h>
19
20#include "Dalvik.h"
21#include "interp/Jit.h"
22#include "CompilerInternals.h"
23
24
25static inline bool workQueueLength(void)
26{
27 return gDvmJit.compilerQueueLength;
28}
29
30static CompilerWorkOrder workDequeue(void)
31{
32 assert(gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex].kind
33 != kWorkOrderInvalid);
34 CompilerWorkOrder work =
35 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex];
36 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex++].kind =
37 kWorkOrderInvalid;
38 if (gDvmJit.compilerWorkDequeueIndex == COMPILER_WORK_QUEUE_SIZE) {
39 gDvmJit.compilerWorkDequeueIndex = 0;
40 }
41 gDvmJit.compilerQueueLength--;
42
43 /* Remember the high water mark of the queue length */
44 if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
45 gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
46
47 return work;
48}
49
50bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
51{
52 int cc;
53 int i;
54 int numWork;
55
56 dvmLockMutex(&gDvmJit.compilerLock);
57
58 /* Queue full */
59 if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
60 gDvmJit.codeCacheFull == true) {
61 dvmUnlockMutex(&gDvmJit.compilerLock);
62 return false;
63 }
64
65 for (numWork = gDvmJit.compilerQueueLength,
66 i = gDvmJit.compilerWorkDequeueIndex;
67 numWork > 0;
68 numWork--) {
69 /* Already enqueued */
70 if (gDvmJit.compilerWorkQueue[i++].pc == pc)
71 goto done;
72 /* Wrap around */
73 if (i == COMPILER_WORK_QUEUE_SIZE)
74 i = 0;
75 }
76
77 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex].pc = pc;
78 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex].kind = kind;
79 gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex].info = info;
80 gDvmJit.compilerWorkEnqueueIndex++;
81 if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
82 gDvmJit.compilerWorkEnqueueIndex = 0;
83 gDvmJit.compilerQueueLength++;
84 cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
85 assert(cc == 0);
86
87done:
88 dvmUnlockMutex(&gDvmJit.compilerLock);
89 return true;
90}
91
92/* Block until queue length is 0 */
93void dvmCompilerDrainQueue(void)
94{
95 dvmLockMutex(&gDvmJit.compilerLock);
96 while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
97 pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
98 }
99 dvmUnlockMutex(&gDvmJit.compilerLock);
100}
101
102static void *compilerThreadStart(void *arg)
103{
104 dvmLockMutex(&gDvmJit.compilerLock);
105 /*
106 * Since the compiler thread will not touch any objects on the heap once
107 * being created, we just fake its state as VMWAIT so that it can be a
108 * bit late when there is suspend request pending.
109 */
110 dvmChangeStatus(NULL, THREAD_VMWAIT);
111 while (!gDvmJit.haltCompilerThread) {
112 if (workQueueLength() == 0) {
113 int cc;
114 cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
115 assert(cc == 0);
116 pthread_cond_wait(&gDvmJit.compilerQueueActivity,
117 &gDvmJit.compilerLock);
118 continue;
119 } else {
120 do {
121 void *compiledCodePtr;
122 CompilerWorkOrder work = workDequeue();
123 dvmUnlockMutex(&gDvmJit.compilerLock);
124 /* Check whether there is a suspend request on me */
125 dvmCheckSuspendPending(NULL);
Bill Buzbee27176222009-06-09 09:20:16 -0700126 /* Is JitTable filling up? */
127 if (gDvmJit.jitTableEntriesUsed >
128 (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
129 dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
130 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700131 if (gDvmJit.haltCompilerThread) {
132 LOGD("Compiler shutdown in progress - discarding request");
133 } else {
134 compiledCodePtr = dvmCompilerDoWork(&work);
135 /* Compilation is successful */
136 if (compiledCodePtr) {
137 dvmJitSetCodeAddr(work.pc, compiledCodePtr);
138 }
139 }
140 free(work.info);
141 dvmLockMutex(&gDvmJit.compilerLock);
142 } while (workQueueLength() != 0);
143 }
144 }
145 pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
146 dvmUnlockMutex(&gDvmJit.compilerLock);
Ben Chengef00a852009-06-22 22:53:35 -0700147
148 LOGD("Compiler thread shutting down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700149 return NULL;
150}
151
152bool dvmCompilerSetupCodeCache(void)
153{
154 extern void dvmCompilerTemplateStart(void);
155 extern void dmvCompilerTemplateEnd(void);
156
157 /* Allocate the code cache */
158 gDvmJit.codeCache = mmap(0, CODE_CACHE_SIZE,
159 PROT_READ | PROT_WRITE | PROT_EXEC,
160 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
161 if (gDvmJit.codeCache == MAP_FAILED) {
162 LOGE("Failed to create the code cache: %s\n", strerror(errno));
163 return false;
164 }
165
166 /* Copy the template code into the beginning of the code cache */
167 int templateSize = (intptr_t) dmvCompilerTemplateEnd -
168 (intptr_t) dvmCompilerTemplateStart;
169 memcpy((void *) gDvmJit.codeCache,
170 (void *) dvmCompilerTemplateStart,
171 templateSize);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700172
173 gDvmJit.templateSize = templateSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700174 gDvmJit.codeCacheByteUsed = templateSize;
175
176 /* Flush dcache and invalidate the icache to maintain coherence */
177 cacheflush((intptr_t) gDvmJit.codeCache,
178 (intptr_t) gDvmJit.codeCache + CODE_CACHE_SIZE, 0);
179 return true;
180}
181
182bool dvmCompilerStartup(void)
183{
184 /* Make sure the BBType enum is in sane state */
Ben Cheng1efc9c52009-06-08 18:25:27 -0700185 assert(CHAINING_CELL_NORMAL == 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700186
187 /* Architecture-specific chores to initialize */
188 if (!dvmCompilerArchInit())
189 goto fail;
190
191 /*
192 * Setup the code cache if it is not done so already. For apps it should be
193 * done by the Zygote already, but for command-line dalvikvm invocation we
194 * need to do it here.
195 */
196 if (gDvmJit.codeCache == NULL) {
197 if (!dvmCompilerSetupCodeCache())
198 goto fail;
199 }
200
201 /* Allocate the initial arena block */
202 if (dvmCompilerHeapInit() == false) {
203 goto fail;
204 }
205
206 dvmInitMutex(&gDvmJit.compilerLock);
207 pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
208 pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
209
210 dvmLockMutex(&gDvmJit.compilerLock);
211
212 gDvmJit.haltCompilerThread = false;
213
214 /* Reset the work queue */
215 memset(gDvmJit.compilerWorkQueue, 0,
216 sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
217 gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
218 gDvmJit.compilerQueueLength = 0;
219 gDvmJit.compilerHighWater =
220 COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
221
222 assert(gDvmJit.compilerHighWater < COMPILER_WORK_QUEUE_SIZE);
223 if (!dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
224 compilerThreadStart, NULL)) {
225 dvmUnlockMutex(&gDvmJit.compilerLock);
226 goto fail;
227 }
228
Ben Cheng8b258bf2009-06-24 17:27:07 -0700229 /* Track method-level compilation statistics */
230 gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
231
Ben Chengba4fc8b2009-06-01 13:00:29 -0700232 dvmUnlockMutex(&gDvmJit.compilerLock);
233
234 return true;
235
236fail:
237 return false;
238}
239
240void dvmCompilerShutdown(void)
241{
242 void *threadReturn;
243
244 if (gDvmJit.compilerHandle) {
245
246 gDvmJit.haltCompilerThread = true;
247
248 dvmLockMutex(&gDvmJit.compilerLock);
249 pthread_cond_signal(&gDvmJit.compilerQueueActivity);
250 dvmUnlockMutex(&gDvmJit.compilerLock);
251
Ben Chengef00a852009-06-22 22:53:35 -0700252 if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
253 LOGW("Compiler thread join failed\n");
254 else
255 LOGD("Compiler thread has shut down\n");
Ben Chengba4fc8b2009-06-01 13:00:29 -0700256 }
257}