blob: 8a5843b4463c269fa6f3a4878b1f960c88b9c2fb [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00:29 -07001/*
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#ifdef WITH_JIT
17
18/*
19 * Target independent portion of Android's Jit
20 */
21
22#include "Dalvik.h"
23#include "Jit.h"
24
25
26#include "dexdump/OpCodeNames.h"
27#include <unistd.h>
28#include <pthread.h>
29#include <sys/time.h>
30#include <signal.h>
31#include "compiler/Compiler.h"
Bill Buzbee6e963e12009-06-17 16:56:19 -070032#include "compiler/CompilerUtility.h"
33#include "compiler/CompilerIR.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070034#include <errno.h>
35
Ben Chengba4fc8b2009-06-01 13:00:29 -070036int dvmJitStartup(void)
37{
38 unsigned int i;
39 bool res = true; /* Assume success */
40
41 // Create the compiler thread and setup miscellaneous chores */
42 res &= dvmCompilerStartup();
43
44 dvmInitMutex(&gDvmJit.tableLock);
45 if (res && gDvm.executionMode == kExecutionModeJit) {
Bill Buzbee716f1202009-07-23 13:22:09 -070046 JitEntry *pJitTable = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -070047 unsigned char *pJitProfTable = NULL;
Bill Buzbee27176222009-06-09 09:20:16 -070048 assert(gDvm.jitTableSize &&
49 !(gDvm.jitTableSize & (gDvmJit.jitTableSize - 1))); // Power of 2?
Ben Chengba4fc8b2009-06-01 13:00:29 -070050 dvmLockMutex(&gDvmJit.tableLock);
Bill Buzbee716f1202009-07-23 13:22:09 -070051 pJitTable = (JitEntry*)
Bill Buzbee27176222009-06-09 09:20:16 -070052 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
Ben Chengba4fc8b2009-06-01 13:00:29 -070053 if (!pJitTable) {
54 LOGE("jit table allocation failed\n");
55 res = false;
56 goto done;
57 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070058 /*
59 * NOTE: the profile table must only be allocated once, globally.
60 * Profiling is turned on and off by nulling out gDvm.pJitProfTable
61 * and then restoring its original value. However, this action
62 * is not syncronized for speed so threads may continue to hold
63 * and update the profile table after profiling has been turned
64 * off by null'ng the global pointer. Be aware.
65 */
66 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
67 if (!pJitProfTable) {
68 LOGE("jit prof table allocation failed\n");
69 res = false;
70 goto done;
71 }
72 memset(pJitProfTable,0,JIT_PROF_SIZE);
Bill Buzbee27176222009-06-09 09:20:16 -070073 for (i=0; i < gDvmJit.jitTableSize; i++) {
Bill Buzbee716f1202009-07-23 13:22:09 -070074 pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -070075 }
76 /* Is chain field wide enough for termination pattern? */
Bill Buzbee716f1202009-07-23 13:22:09 -070077 assert(pJitTable[0].u.info.chain == gDvm.maxJitTableEntries);
Ben Chengba4fc8b2009-06-01 13:00:29 -070078
79done:
80 gDvmJit.pJitEntryTable = pJitTable;
Bill Buzbee27176222009-06-09 09:20:16 -070081 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
82 gDvmJit.jitTableEntriesUsed = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -070083 gDvmJit.pProfTableCopy = gDvmJit.pProfTable = pJitProfTable;
84 dvmUnlockMutex(&gDvmJit.tableLock);
85 }
86 return res;
87}
88
89/*
90 * If one of our fixed tables or the translation buffer fills up,
91 * call this routine to avoid wasting cycles on future translation requests.
92 */
93void dvmJitStopTranslationRequests()
94{
95 /*
96 * Note 1: This won't necessarily stop all translation requests, and
97 * operates on a delayed mechanism. Running threads look to the copy
98 * of this value in their private InterpState structures and won't see
99 * this change until it is refreshed (which happens on interpreter
100 * entry).
101 * Note 2: This is a one-shot memory leak on this table. Because this is a
102 * permanent off switch for Jit profiling, it is a one-time leak of 1K
103 * bytes, and no further attempt will be made to re-allocate it. Can't
104 * free it because some thread may be holding a reference.
105 */
106 gDvmJit.pProfTable = gDvmJit.pProfTableCopy = NULL;
107}
108
109#if defined(EXIT_STATS)
110/* Convenience function to increment counter from assembly code */
111void dvmBumpNoChain()
112{
113 gDvm.jitNoChainExit++;
114}
115
116/* Convenience function to increment counter from assembly code */
117void dvmBumpNormal()
118{
119 gDvm.jitNormalExit++;
120}
121
122/* Convenience function to increment counter from assembly code */
123void dvmBumpPunt(int from)
124{
125 gDvm.jitPuntExit++;
126}
127#endif
128
129/* Dumps debugging & tuning stats to the log */
130void dvmJitStats()
131{
132 int i;
133 int hit;
134 int not_hit;
135 int chains;
136 if (gDvmJit.pJitEntryTable) {
137 for (i=0, chains=hit=not_hit=0;
Bill Buzbee27176222009-06-09 09:20:16 -0700138 i < (int) gDvmJit.jitTableSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700139 i++) {
140 if (gDvmJit.pJitEntryTable[i].dPC != 0)
141 hit++;
142 else
143 not_hit++;
Bill Buzbee716f1202009-07-23 13:22:09 -0700144 if (gDvmJit.pJitEntryTable[i].u.info.chain != gDvmJit.jitTableSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700145 chains++;
146 }
147 LOGD(
148 "JIT: %d traces, %d slots, %d chains, %d maxQ, %d thresh, %s",
149 hit, not_hit + hit, chains, gDvmJit.compilerMaxQueued,
150 gDvmJit.threshold, gDvmJit.blockingMode ? "Blocking" : "Non-blocking");
151#if defined(EXIT_STATS)
152 LOGD(
153 "JIT: Lookups: %d hits, %d misses; %d NoChain, %d normal, %d punt",
154 gDvmJit.addrLookupsFound, gDvmJit.addrLookupsNotFound,
155 gDvmJit.noChainExit, gDvmJit.normalExit, gDvmJit.puntExit);
156#endif
157 LOGD("JIT: %d Translation chains", gDvmJit.translationChains);
158#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -0700159 LOGD("JIT: Invoke: %d chainable, %d pred. chain, %d native, "
160 "%d return",
161 gDvmJit.invokeChain, gDvmJit.invokePredictedChain,
162 gDvmJit.invokeNative, gDvmJit.returnOp);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700163#endif
Ben Chenge80cd942009-07-17 15:54:23 -0700164 if (gDvmJit.profile) {
Bill Buzbee716f1202009-07-23 13:22:09 -0700165 dvmCompilerSortAndPrintTraceProfiles();
Bill Buzbee6e963e12009-06-17 16:56:19 -0700166 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700167 }
168}
169
Bill Buzbee716f1202009-07-23 13:22:09 -0700170
Ben Chengba4fc8b2009-06-01 13:00:29 -0700171/*
172 * Final JIT shutdown. Only do this once, and do not attempt to restart
173 * the JIT later.
174 */
175void dvmJitShutdown(void)
176{
177 /* Shutdown the compiler thread */
178 dvmCompilerShutdown();
179
180 dvmCompilerDumpStats();
181
182 dvmDestroyMutex(&gDvmJit.tableLock);
183
184 if (gDvmJit.pJitEntryTable) {
185 free(gDvmJit.pJitEntryTable);
186 gDvmJit.pJitEntryTable = NULL;
187 }
188
189 if (gDvmJit.pProfTable) {
190 free(gDvmJit.pProfTable);
191 gDvmJit.pProfTable = NULL;
192 }
193}
194
Ben Chengba4fc8b2009-06-01 13:00:29 -0700195/*
196 * Adds to the current trace request one instruction at a time, just
197 * before that instruction is interpreted. This is the primary trace
198 * selection function. NOTE: return instruction are handled a little
199 * differently. In general, instructions are "proposed" to be added
200 * to the current trace prior to interpretation. If the interpreter
201 * then successfully completes the instruction, is will be considered
202 * part of the request. This allows us to examine machine state prior
203 * to interpretation, and also abort the trace request if the instruction
204 * throws or does something unexpected. However, return instructions
205 * will cause an immediate end to the translation request - which will
206 * be passed to the compiler before the return completes. This is done
207 * in response to special handling of returns by the interpreter (and
208 * because returns cannot throw in a way that causes problems for the
209 * translated code.
210 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700211int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
212{
213 int flags,i,len;
214 int switchInterp = false;
215 int debugOrProfile = (gDvm.debuggerActive || self->suspendCount
216#if defined(WITH_PROFILER)
217 || gDvm.activeProfilers
218#endif
219 );
220
221 switch (interpState->jitState) {
222 char* nopStr;
223 int target;
224 int offset;
225 DecodedInstruction decInsn;
226 case kJitTSelect:
227 dexDecodeInstruction(gDvm.instrFormat, pc, &decInsn);
228#if defined(SHOW_TRACE)
229 LOGD("TraceGen: adding %s",getOpcodeName(decInsn.opCode));
230#endif
231 flags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
232 len = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, pc);
233 offset = pc - interpState->method->insns;
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700234 if (pc != interpState->currRunHead + interpState->currRunLen) {
235 int currTraceRun;
236 /* We need to start a new trace run */
237 currTraceRun = ++interpState->currTraceRun;
238 interpState->currRunLen = 0;
239 interpState->currRunHead = (u2*)pc;
240 interpState->trace[currTraceRun].frag.startOffset = offset;
241 interpState->trace[currTraceRun].frag.numInsts = 0;
242 interpState->trace[currTraceRun].frag.runEnd = false;
243 interpState->trace[currTraceRun].frag.hint = kJitHintNone;
244 }
245 interpState->trace[interpState->currTraceRun].frag.numInsts++;
246 interpState->totalTraceLen++;
247 interpState->currRunLen += len;
248 if ( ((flags & kInstrUnconditional) == 0) &&
249 ((flags & (kInstrCanBranch |
250 kInstrCanSwitch |
251 kInstrCanReturn |
252 kInstrInvoke)) != 0)) {
253 interpState->jitState = kJitTSelectEnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700254#if defined(SHOW_TRACE)
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700255 LOGD("TraceGen: ending on %s, basic block end",
256 getOpcodeName(decInsn.opCode));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700257#endif
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700258 }
259 if (decInsn.opCode == OP_THROW) {
260 interpState->jitState = kJitTSelectEnd;
261 }
262 if (interpState->totalTraceLen >= JIT_MAX_TRACE_LEN) {
263 interpState->jitState = kJitTSelectEnd;
264 }
265 if (debugOrProfile) {
266 interpState->jitState = kJitTSelectAbort;
267 switchInterp = !debugOrProfile;
268 break;
269 }
270 if ((flags & kInstrCanReturn) != kInstrCanReturn) {
271 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700272 }
273 /* NOTE: intentional fallthrough for returns */
274 case kJitTSelectEnd:
275 {
276 if (interpState->totalTraceLen == 0) {
277 switchInterp = !debugOrProfile;
278 break;
279 }
280 JitTraceDescription* desc =
281 (JitTraceDescription*)malloc(sizeof(JitTraceDescription) +
282 sizeof(JitTraceRun) * (interpState->currTraceRun+1));
283 if (desc == NULL) {
284 LOGE("Out of memory in trace selection");
285 dvmJitStopTranslationRequests();
286 interpState->jitState = kJitTSelectAbort;
287 switchInterp = !debugOrProfile;
288 break;
289 }
290 interpState->trace[interpState->currTraceRun].frag.runEnd =
291 true;
292 interpState->jitState = kJitNormal;
293 desc->method = interpState->method;
294 memcpy((char*)&(desc->trace[0]),
295 (char*)&(interpState->trace[0]),
296 sizeof(JitTraceRun) * (interpState->currTraceRun+1));
297#if defined(SHOW_TRACE)
298 LOGD("TraceGen: trace done, adding to queue");
299#endif
300 dvmCompilerWorkEnqueue(
301 interpState->currTraceHead,kWorkOrderTrace,desc);
302 if (gDvmJit.blockingMode) {
303 dvmCompilerDrainQueue();
304 }
305 switchInterp = !debugOrProfile;
306 }
307 break;
308 case kJitSingleStep:
309 interpState->jitState = kJitSingleStepEnd;
310 break;
311 case kJitSingleStepEnd:
312 interpState->entryPoint = kInterpEntryResume;
313 switchInterp = !debugOrProfile;
314 break;
315 case kJitTSelectAbort:
316#if defined(SHOW_TRACE)
317 LOGD("TraceGen: trace abort");
318#endif
319 interpState->jitState = kJitNormal;
320 switchInterp = !debugOrProfile;
321 break;
322 case kJitNormal:
Ben Cheng38329f52009-07-07 14:19:20 -0700323 switchInterp = !debugOrProfile;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700324 break;
325 default:
326 dvmAbort();
327 }
328 return switchInterp;
329}
330
Bill Buzbee716f1202009-07-23 13:22:09 -0700331static inline JitEntry *findJitEntry(const u2* pc)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700332{
333 int idx = dvmJitHash(pc);
334
335 /* Expect a high hit rate on 1st shot */
336 if (gDvmJit.pJitEntryTable[idx].dPC == pc)
337 return &gDvmJit.pJitEntryTable[idx];
338 else {
Bill Buzbee27176222009-06-09 09:20:16 -0700339 int chainEndMarker = gDvmJit.jitTableSize;
Bill Buzbee716f1202009-07-23 13:22:09 -0700340 while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
341 idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700342 if (gDvmJit.pJitEntryTable[idx].dPC == pc)
343 return &gDvmJit.pJitEntryTable[idx];
344 }
345 }
346 return NULL;
347}
348
Bill Buzbee716f1202009-07-23 13:22:09 -0700349JitEntry *dvmFindJitEntry(const u2* pc)
Bill Buzbee27176222009-06-09 09:20:16 -0700350{
351 return findJitEntry(pc);
352}
353
354/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700355 * If a translated code address exists for the davik byte code
356 * pointer return it. This routine needs to be fast.
357 */
358void* dvmJitGetCodeAddr(const u2* dPC)
359{
360 int idx = dvmJitHash(dPC);
361
Bill Buzbee46cd5b62009-06-05 15:36:06 -0700362 /* If anything is suspended, don't re-enter the code cache */
363 if (gDvm.sumThreadSuspendCount > 0) {
364 return NULL;
365 }
366
Ben Chengba4fc8b2009-06-01 13:00:29 -0700367 /* Expect a high hit rate on 1st shot */
368 if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
369#if defined(EXIT_STATS)
370 gDvmJit.addrLookupsFound++;
371#endif
372 return gDvmJit.pJitEntryTable[idx].codeAddress;
373 } else {
Bill Buzbee27176222009-06-09 09:20:16 -0700374 int chainEndMarker = gDvmJit.jitTableSize;
Bill Buzbee716f1202009-07-23 13:22:09 -0700375 while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
376 idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700377 if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
378#if defined(EXIT_STATS)
379 gDvmJit.addrLookupsFound++;
380#endif
381 return gDvmJit.pJitEntryTable[idx].codeAddress;
382 }
383 }
384 }
385#if defined(EXIT_STATS)
386 gDvmJit.addrLookupsNotFound++;
387#endif
388 return NULL;
389}
390
391/*
Bill Buzbee716f1202009-07-23 13:22:09 -0700392 * Find an entry in the JitTable, creating if necessary.
393 * Returns null if table is full.
394 */
395JitEntry *dvmJitLookupAndAdd(const u2* dPC)
396{
397 u4 chainEndMarker = gDvmJit.jitTableSize;
398 u4 idx = dvmJitHash(dPC);
399
400 /* Walk the bucket chain to find an exact match for our PC */
401 while ((gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) &&
402 (gDvmJit.pJitEntryTable[idx].dPC != dPC)) {
403 idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
404 }
405
406 if (gDvmJit.pJitEntryTable[idx].dPC != dPC) {
407 /*
408 * No match. Aquire jitTableLock and find the last
409 * slot in the chain. Possibly continue the chain walk in case
410 * some other thread allocated the slot we were looking
411 * at previuosly (perhaps even the dPC we're trying to enter).
412 */
413 dvmLockMutex(&gDvmJit.tableLock);
414 /*
415 * At this point, if .dPC is NULL, then the slot we're
416 * looking at is the target slot from the primary hash
417 * (the simple, and common case). Otherwise we're going
418 * to have to find a free slot and chain it.
419 */
420 MEM_BARRIER(); /* Make sure we reload [].dPC after lock */
421 if (gDvmJit.pJitEntryTable[idx].dPC != NULL) {
422 u4 prev;
423 while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
424 if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
425 /* Another thread got there first for this dPC */
426 dvmUnlockMutex(&gDvmJit.tableLock);
427 return &gDvmJit.pJitEntryTable[idx];
428 }
429 idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
430 }
431 /* Here, idx should be pointing to the last cell of an
432 * active chain whose last member contains a valid dPC */
433 assert(gDvmJit.pJitEntryTable[idx].dPC != NULL);
434 /* Linear walk to find a free cell and add it to the end */
435 prev = idx;
436 while (true) {
437 idx++;
438 if (idx == chainEndMarker)
439 idx = 0; /* Wraparound */
440 if ((gDvmJit.pJitEntryTable[idx].dPC == NULL) ||
441 (idx == prev))
442 break;
443 }
444 if (idx != prev) {
445 JitEntryInfoUnion oldValue;
446 JitEntryInfoUnion newValue;
447 /*
448 * Although we hold the lock so that noone else will
449 * be trying to update a chain field, the other fields
450 * packed into the word may be in use by other threads.
451 */
452 do {
453 oldValue = gDvmJit.pJitEntryTable[prev].u;
454 newValue = oldValue;
455 newValue.info.chain = idx;
456 } while (!ATOMIC_CMP_SWAP(
457 &gDvmJit.pJitEntryTable[prev].u.infoWord,
458 oldValue.infoWord, newValue.infoWord));
459 }
460 }
461 if (gDvmJit.pJitEntryTable[idx].dPC == NULL) {
462 /* Allocate the slot */
463 gDvmJit.pJitEntryTable[idx].dPC = dPC;
464 gDvmJit.jitTableEntriesUsed++;
465 } else {
466 /* Table is full */
467 idx = chainEndMarker;
468 }
469 dvmUnlockMutex(&gDvmJit.tableLock);
470 }
471 return (idx == chainEndMarker) ? NULL : &gDvmJit.pJitEntryTable[idx];
472}
473/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700474 * Register the translated code pointer into the JitTable.
475 * NOTE: Once a codeAddress field transitions from NULL to
476 * JIT'd code, it must not be altered without first halting all
Bill Buzbee716f1202009-07-23 13:22:09 -0700477 * threads. This routine should only be called by the compiler
478 * thread.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700479 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700480void dvmJitSetCodeAddr(const u2* dPC, void *nPC, JitInstructionSetType set) {
481 JitEntryInfoUnion oldValue;
482 JitEntryInfoUnion newValue;
483 JitEntry *jitEntry = dvmJitLookupAndAdd(dPC);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700484 assert(jitEntry);
Bill Buzbee716f1202009-07-23 13:22:09 -0700485 /* Note: order of update is important */
486 do {
487 oldValue = jitEntry->u;
488 newValue = oldValue;
489 newValue.info.instructionSet = set;
490 } while (!ATOMIC_CMP_SWAP(
491 &jitEntry->u.infoWord,
492 oldValue.infoWord, newValue.infoWord));
493 jitEntry->codeAddress = nPC;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700494}
495
496/*
497 * Determine if valid trace-bulding request is active. Return true
498 * if we need to abort and switch back to the fast interpreter, false
499 * otherwise. NOTE: may be called even when trace selection is not being
500 * requested
501 */
502
Ben Chengba4fc8b2009-06-01 13:00:29 -0700503bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState)
504{
Bill Buzbee48f18242009-06-19 16:02:27 -0700505 bool res = false; /* Assume success */
506 int i;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700507 if (gDvmJit.pJitEntryTable != NULL) {
Bill Buzbee48f18242009-06-19 16:02:27 -0700508 /* Two-level filtering scheme */
509 for (i=0; i< JIT_TRACE_THRESH_FILTER_SIZE; i++) {
510 if (interpState->pc == interpState->threshFilter[i]) {
511 break;
512 }
513 }
514 if (i == JIT_TRACE_THRESH_FILTER_SIZE) {
515 /*
516 * Use random replacement policy - otherwise we could miss a large
517 * loop that contains more traces than the size of our filter array.
518 */
519 i = rand() % JIT_TRACE_THRESH_FILTER_SIZE;
520 interpState->threshFilter[i] = interpState->pc;
521 res = true;
522 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700523 /*
524 * If the compiler is backlogged, or if a debugger or profiler is
525 * active, cancel any JIT actions
526 */
Bill Buzbee48f18242009-06-19 16:02:27 -0700527 if ( res || (gDvmJit.compilerQueueLength >= gDvmJit.compilerHighWater) ||
Ben Chengba4fc8b2009-06-01 13:00:29 -0700528 gDvm.debuggerActive || self->suspendCount
529#if defined(WITH_PROFILER)
530 || gDvm.activeProfilers
531#endif
532 ) {
533 if (interpState->jitState != kJitOff) {
534 interpState->jitState = kJitNormal;
535 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700536 } else if (interpState->jitState == kJitTSelectRequest) {
Bill Buzbee716f1202009-07-23 13:22:09 -0700537 JitEntry *slot = dvmJitLookupAndAdd(interpState->pc);
538 if (slot == NULL) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700539 /*
Bill Buzbee716f1202009-07-23 13:22:09 -0700540 * Table is full. This should have been
541 * detected by the compiler thread and the table
542 * resized before we run into it here. Assume bad things
543 * are afoot and disable profiling.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700544 */
545 interpState->jitState = kJitTSelectAbort;
Bill Buzbee716f1202009-07-23 13:22:09 -0700546 LOGD("JIT: JitTable full, disabling profiling");
547 dvmJitStopTranslationRequests();
548 } else if (slot->u.info.traceRequested) {
549 /* Trace already requested - revert to interpreter */
550 interpState->jitState = kJitTSelectAbort;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700551 } else {
Bill Buzbee716f1202009-07-23 13:22:09 -0700552 /* Mark request */
553 JitEntryInfoUnion oldValue;
554 JitEntryInfoUnion newValue;
555 do {
556 oldValue = slot->u;
557 newValue = oldValue;
558 newValue.info.traceRequested = true;
559 } while (!ATOMIC_CMP_SWAP( &slot->u.infoWord,
560 oldValue.infoWord, newValue.infoWord));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700561 }
562 }
563 switch (interpState->jitState) {
564 case kJitTSelectRequest:
565 interpState->jitState = kJitTSelect;
566 interpState->currTraceHead = interpState->pc;
567 interpState->currTraceRun = 0;
568 interpState->totalTraceLen = 0;
569 interpState->currRunHead = interpState->pc;
570 interpState->currRunLen = 0;
571 interpState->trace[0].frag.startOffset =
572 interpState->pc - interpState->method->insns;
573 interpState->trace[0].frag.numInsts = 0;
574 interpState->trace[0].frag.runEnd = false;
575 interpState->trace[0].frag.hint = kJitHintNone;
576 break;
577 case kJitTSelect:
578 case kJitTSelectAbort:
579 res = true;
580 case kJitSingleStep:
581 case kJitSingleStepEnd:
582 case kJitOff:
583 case kJitNormal:
584 break;
585 default:
586 dvmAbort();
587 }
588 }
589 return res;
590}
591
Bill Buzbee27176222009-06-09 09:20:16 -0700592/*
593 * Resizes the JitTable. Must be a power of 2, and returns true on failure.
594 * Stops all threads, and thus is a heavyweight operation.
595 */
596bool dvmJitResizeJitTable( unsigned int size )
597{
Bill Buzbee716f1202009-07-23 13:22:09 -0700598 JitEntry *pNewTable;
599 JitEntry *pOldTable;
Bill Buzbee27176222009-06-09 09:20:16 -0700600 u4 newMask;
Bill Buzbee716f1202009-07-23 13:22:09 -0700601 unsigned int oldSize;
Bill Buzbee27176222009-06-09 09:20:16 -0700602 unsigned int i;
603
604 assert(gDvm.pJitEntryTable != NULL);
605 assert(size && !(size & (size - 1))); /* Is power of 2? */
606
607 LOGD("Jit: resizing JitTable from %d to %d", gDvmJit.jitTableSize, size);
608
609 newMask = size - 1;
610
611 if (size <= gDvmJit.jitTableSize) {
612 return true;
613 }
614
Bill Buzbee716f1202009-07-23 13:22:09 -0700615 pNewTable = (JitEntry*)calloc(size, sizeof(*pNewTable));
Bill Buzbee27176222009-06-09 09:20:16 -0700616 if (pNewTable == NULL) {
617 return true;
618 }
619 for (i=0; i< size; i++) {
Bill Buzbee716f1202009-07-23 13:22:09 -0700620 pNewTable[i].u.info.chain = size; /* Initialize chain termination */
Bill Buzbee27176222009-06-09 09:20:16 -0700621 }
622
623 /* Stop all other interpreting/jit'ng threads */
624 dvmSuspendAllThreads(SUSPEND_FOR_JIT);
625
Bill Buzbee716f1202009-07-23 13:22:09 -0700626 pOldTable = gDvmJit.pJitEntryTable;
627 oldSize = gDvmJit.jitTableSize;
Bill Buzbee27176222009-06-09 09:20:16 -0700628
629 dvmLockMutex(&gDvmJit.tableLock);
Bill Buzbee27176222009-06-09 09:20:16 -0700630 gDvmJit.pJitEntryTable = pNewTable;
631 gDvmJit.jitTableSize = size;
632 gDvmJit.jitTableMask = size - 1;
Bill Buzbee716f1202009-07-23 13:22:09 -0700633 gDvmJit.jitTableEntriesUsed = 0;
Bill Buzbee27176222009-06-09 09:20:16 -0700634 dvmUnlockMutex(&gDvmJit.tableLock);
635
Bill Buzbee716f1202009-07-23 13:22:09 -0700636 for (i=0; i < oldSize; i++) {
637 if (pOldTable[i].dPC) {
638 JitEntry *p;
639 u2 chain;
640 p = dvmJitLookupAndAdd(pOldTable[i].dPC);
641 p->dPC = pOldTable[i].dPC;
642 /*
643 * Compiler thread may have just updated the new entry's
644 * code address field, so don't blindly copy null.
645 */
646 if (pOldTable[i].codeAddress != NULL) {
647 p->codeAddress = pOldTable[i].codeAddress;
648 }
649 /* We need to preserve the new chain field, but copy the rest */
650 dvmLockMutex(&gDvmJit.tableLock);
651 chain = p->u.info.chain;
652 p->u = pOldTable[i].u;
653 p->u.info.chain = chain;
654 dvmUnlockMutex(&gDvmJit.tableLock);
655 }
656 }
657
658 free(pOldTable);
659
Bill Buzbee27176222009-06-09 09:20:16 -0700660 /* Restart the world */
661 dvmResumeAllThreads(SUSPEND_FOR_JIT);
662
663 return false;
664}
665
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700666/*
667 * Float/double conversion requires clamping to min and max of integer form. If
668 * target doesn't support this normally, use these.
669 */
670s8 dvmJitd2l(double d)
671{
672 static const double kMaxLong = (double)0x7fffffffffffffffULL;
673 static const double kMinLong = (double)0x8000000000000000ULL;
674 if (d >= kMaxLong)
675 return 0x7fffffffffffffffULL;
676 else if (d <= kMinLong)
677 return 0x8000000000000000ULL;
678 else if (d != d) // NaN case
679 return 0;
680 else
681 return (s8)d;
682}
683
684s8 dvmJitf2l(float f)
685{
686 static const float kMaxLong = (float)0x7fffffffffffffffULL;
687 static const float kMinLong = (float)0x8000000000000000ULL;
688 if (f >= kMaxLong)
689 return 0x7fffffffffffffffULL;
690 else if (f <= kMinLong)
691 return 0x8000000000000000ULL;
692 else if (f != f) // NaN case
693 return 0;
694 else
695 return (s8)f;
696}
697
Bill Buzbee27176222009-06-09 09:20:16 -0700698
Ben Chengba4fc8b2009-06-01 13:00:29 -0700699#endif /* WITH_JIT */