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