blob: 9079da141bd275ea9722985dda39453fc143c2c5 [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;
Ben Cheng3f02aa42009-08-14 13:52:09 -070048 // Power of 2?
49 assert(gDvmJit.jitTableSize &&
50 !(gDvmJit.jitTableSize & (gDvmJit.jitTableSize - 1)));
Ben Chengba4fc8b2009-06-01 13:00:29 -070051 dvmLockMutex(&gDvmJit.tableLock);
Bill Buzbee716f1202009-07-23 13:22:09 -070052 pJitTable = (JitEntry*)
Bill Buzbee27176222009-06-09 09:20:16 -070053 calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
Ben Chengba4fc8b2009-06-01 13:00:29 -070054 if (!pJitTable) {
55 LOGE("jit table allocation failed\n");
56 res = false;
57 goto done;
58 }
Ben Chengba4fc8b2009-06-01 13:00:29 -070059 /*
60 * NOTE: the profile table must only be allocated once, globally.
61 * Profiling is turned on and off by nulling out gDvm.pJitProfTable
62 * and then restoring its original value. However, this action
63 * is not syncronized for speed so threads may continue to hold
64 * and update the profile table after profiling has been turned
65 * off by null'ng the global pointer. Be aware.
66 */
67 pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
68 if (!pJitProfTable) {
69 LOGE("jit prof table allocation failed\n");
70 res = false;
71 goto done;
72 }
73 memset(pJitProfTable,0,JIT_PROF_SIZE);
Bill Buzbee27176222009-06-09 09:20:16 -070074 for (i=0; i < gDvmJit.jitTableSize; i++) {
Bill Buzbee716f1202009-07-23 13:22:09 -070075 pJitTable[i].u.info.chain = gDvmJit.jitTableSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -070076 }
77 /* Is chain field wide enough for termination pattern? */
Ben Cheng3f02aa42009-08-14 13:52:09 -070078 assert(pJitTable[0].u.info.chain == gDvmJit.jitTableSize);
Ben Chengba4fc8b2009-06-01 13:00:29 -070079
80done:
81 gDvmJit.pJitEntryTable = pJitTable;
Bill Buzbee27176222009-06-09 09:20:16 -070082 gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
83 gDvmJit.jitTableEntriesUsed = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -070084 gDvmJit.pProfTableCopy = gDvmJit.pProfTable = pJitProfTable;
85 dvmUnlockMutex(&gDvmJit.tableLock);
86 }
87 return res;
88}
89
90/*
91 * If one of our fixed tables or the translation buffer fills up,
92 * call this routine to avoid wasting cycles on future translation requests.
93 */
94void dvmJitStopTranslationRequests()
95{
96 /*
97 * Note 1: This won't necessarily stop all translation requests, and
98 * operates on a delayed mechanism. Running threads look to the copy
99 * of this value in their private InterpState structures and won't see
100 * this change until it is refreshed (which happens on interpreter
101 * entry).
102 * Note 2: This is a one-shot memory leak on this table. Because this is a
103 * permanent off switch for Jit profiling, it is a one-time leak of 1K
104 * bytes, and no further attempt will be made to re-allocate it. Can't
105 * free it because some thread may be holding a reference.
106 */
107 gDvmJit.pProfTable = gDvmJit.pProfTableCopy = NULL;
108}
109
110#if defined(EXIT_STATS)
111/* Convenience function to increment counter from assembly code */
112void dvmBumpNoChain()
113{
114 gDvm.jitNoChainExit++;
115}
116
117/* Convenience function to increment counter from assembly code */
118void dvmBumpNormal()
119{
120 gDvm.jitNormalExit++;
121}
122
123/* Convenience function to increment counter from assembly code */
124void dvmBumpPunt(int from)
125{
126 gDvm.jitPuntExit++;
127}
128#endif
129
130/* Dumps debugging & tuning stats to the log */
131void dvmJitStats()
132{
133 int i;
134 int hit;
135 int not_hit;
136 int chains;
137 if (gDvmJit.pJitEntryTable) {
138 for (i=0, chains=hit=not_hit=0;
Bill Buzbee27176222009-06-09 09:20:16 -0700139 i < (int) gDvmJit.jitTableSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700140 i++) {
141 if (gDvmJit.pJitEntryTable[i].dPC != 0)
142 hit++;
143 else
144 not_hit++;
Bill Buzbee716f1202009-07-23 13:22:09 -0700145 if (gDvmJit.pJitEntryTable[i].u.info.chain != gDvmJit.jitTableSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700146 chains++;
147 }
148 LOGD(
149 "JIT: %d traces, %d slots, %d chains, %d maxQ, %d thresh, %s",
150 hit, not_hit + hit, chains, gDvmJit.compilerMaxQueued,
151 gDvmJit.threshold, gDvmJit.blockingMode ? "Blocking" : "Non-blocking");
152#if defined(EXIT_STATS)
153 LOGD(
154 "JIT: Lookups: %d hits, %d misses; %d NoChain, %d normal, %d punt",
155 gDvmJit.addrLookupsFound, gDvmJit.addrLookupsNotFound,
156 gDvmJit.noChainExit, gDvmJit.normalExit, gDvmJit.puntExit);
157#endif
158 LOGD("JIT: %d Translation chains", gDvmJit.translationChains);
159#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -0700160 LOGD("JIT: Invoke: %d chainable, %d pred. chain, %d native, "
161 "%d return",
162 gDvmJit.invokeChain, gDvmJit.invokePredictedChain,
163 gDvmJit.invokeNative, gDvmJit.returnOp);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700164#endif
Ben Chenge80cd942009-07-17 15:54:23 -0700165 if (gDvmJit.profile) {
Bill Buzbee716f1202009-07-23 13:22:09 -0700166 dvmCompilerSortAndPrintTraceProfiles();
Bill Buzbee6e963e12009-06-17 16:56:19 -0700167 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700168 }
169}
170
Bill Buzbee716f1202009-07-23 13:22:09 -0700171
Ben Chengba4fc8b2009-06-01 13:00:29 -0700172/*
173 * Final JIT shutdown. Only do this once, and do not attempt to restart
174 * the JIT later.
175 */
176void dvmJitShutdown(void)
177{
178 /* Shutdown the compiler thread */
179 dvmCompilerShutdown();
180
181 dvmCompilerDumpStats();
182
183 dvmDestroyMutex(&gDvmJit.tableLock);
184
185 if (gDvmJit.pJitEntryTable) {
186 free(gDvmJit.pJitEntryTable);
187 gDvmJit.pJitEntryTable = NULL;
188 }
189
190 if (gDvmJit.pProfTable) {
191 free(gDvmJit.pProfTable);
192 gDvmJit.pProfTable = NULL;
193 }
194}
195
Ben Chengba4fc8b2009-06-01 13:00:29 -0700196/*
197 * Adds to the current trace request one instruction at a time, just
198 * before that instruction is interpreted. This is the primary trace
199 * selection function. NOTE: return instruction are handled a little
200 * differently. In general, instructions are "proposed" to be added
201 * to the current trace prior to interpretation. If the interpreter
202 * then successfully completes the instruction, is will be considered
203 * part of the request. This allows us to examine machine state prior
204 * to interpretation, and also abort the trace request if the instruction
205 * throws or does something unexpected. However, return instructions
206 * will cause an immediate end to the translation request - which will
207 * be passed to the compiler before the return completes. This is done
208 * in response to special handling of returns by the interpreter (and
209 * because returns cannot throw in a way that causes problems for the
210 * translated code.
211 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700212int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
213{
214 int flags,i,len;
215 int switchInterp = false;
216 int debugOrProfile = (gDvm.debuggerActive || self->suspendCount
217#if defined(WITH_PROFILER)
218 || gDvm.activeProfilers
219#endif
220 );
221
222 switch (interpState->jitState) {
223 char* nopStr;
224 int target;
225 int offset;
226 DecodedInstruction decInsn;
227 case kJitTSelect:
228 dexDecodeInstruction(gDvm.instrFormat, pc, &decInsn);
229#if defined(SHOW_TRACE)
230 LOGD("TraceGen: adding %s",getOpcodeName(decInsn.opCode));
231#endif
232 flags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
233 len = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, pc);
234 offset = pc - interpState->method->insns;
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700235 if (pc != interpState->currRunHead + interpState->currRunLen) {
236 int currTraceRun;
237 /* We need to start a new trace run */
238 currTraceRun = ++interpState->currTraceRun;
239 interpState->currRunLen = 0;
240 interpState->currRunHead = (u2*)pc;
241 interpState->trace[currTraceRun].frag.startOffset = offset;
242 interpState->trace[currTraceRun].frag.numInsts = 0;
243 interpState->trace[currTraceRun].frag.runEnd = false;
244 interpState->trace[currTraceRun].frag.hint = kJitHintNone;
245 }
246 interpState->trace[interpState->currTraceRun].frag.numInsts++;
247 interpState->totalTraceLen++;
248 interpState->currRunLen += len;
249 if ( ((flags & kInstrUnconditional) == 0) &&
Bill Buzbeef4ce16f2009-07-28 13:28:25 -0700250 /* don't end trace on INVOKE_DIRECT_EMPTY */
251 (decInsn.opCode != OP_INVOKE_DIRECT_EMPTY) &&
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700252 ((flags & (kInstrCanBranch |
253 kInstrCanSwitch |
254 kInstrCanReturn |
255 kInstrInvoke)) != 0)) {
256 interpState->jitState = kJitTSelectEnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700257#if defined(SHOW_TRACE)
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700258 LOGD("TraceGen: ending on %s, basic block end",
259 getOpcodeName(decInsn.opCode));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700260#endif
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700261 }
262 if (decInsn.opCode == OP_THROW) {
263 interpState->jitState = kJitTSelectEnd;
264 }
265 if (interpState->totalTraceLen >= JIT_MAX_TRACE_LEN) {
266 interpState->jitState = kJitTSelectEnd;
267 }
268 if (debugOrProfile) {
269 interpState->jitState = kJitTSelectAbort;
270 switchInterp = !debugOrProfile;
271 break;
272 }
273 if ((flags & kInstrCanReturn) != kInstrCanReturn) {
274 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700275 }
276 /* NOTE: intentional fallthrough for returns */
277 case kJitTSelectEnd:
278 {
279 if (interpState->totalTraceLen == 0) {
280 switchInterp = !debugOrProfile;
281 break;
282 }
283 JitTraceDescription* desc =
284 (JitTraceDescription*)malloc(sizeof(JitTraceDescription) +
285 sizeof(JitTraceRun) * (interpState->currTraceRun+1));
286 if (desc == NULL) {
287 LOGE("Out of memory in trace selection");
288 dvmJitStopTranslationRequests();
289 interpState->jitState = kJitTSelectAbort;
290 switchInterp = !debugOrProfile;
291 break;
292 }
293 interpState->trace[interpState->currTraceRun].frag.runEnd =
294 true;
295 interpState->jitState = kJitNormal;
296 desc->method = interpState->method;
297 memcpy((char*)&(desc->trace[0]),
298 (char*)&(interpState->trace[0]),
299 sizeof(JitTraceRun) * (interpState->currTraceRun+1));
300#if defined(SHOW_TRACE)
301 LOGD("TraceGen: trace done, adding to queue");
302#endif
303 dvmCompilerWorkEnqueue(
304 interpState->currTraceHead,kWorkOrderTrace,desc);
305 if (gDvmJit.blockingMode) {
306 dvmCompilerDrainQueue();
307 }
308 switchInterp = !debugOrProfile;
309 }
310 break;
311 case kJitSingleStep:
312 interpState->jitState = kJitSingleStepEnd;
313 break;
314 case kJitSingleStepEnd:
315 interpState->entryPoint = kInterpEntryResume;
316 switchInterp = !debugOrProfile;
317 break;
318 case kJitTSelectAbort:
319#if defined(SHOW_TRACE)
320 LOGD("TraceGen: trace abort");
321#endif
322 interpState->jitState = kJitNormal;
323 switchInterp = !debugOrProfile;
324 break;
325 case kJitNormal:
Ben Cheng38329f52009-07-07 14:19:20 -0700326 switchInterp = !debugOrProfile;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700327 break;
328 default:
329 dvmAbort();
330 }
331 return switchInterp;
332}
333
Bill Buzbee716f1202009-07-23 13:22:09 -0700334static inline JitEntry *findJitEntry(const u2* pc)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700335{
336 int idx = dvmJitHash(pc);
337
338 /* Expect a high hit rate on 1st shot */
339 if (gDvmJit.pJitEntryTable[idx].dPC == pc)
340 return &gDvmJit.pJitEntryTable[idx];
341 else {
Bill Buzbee27176222009-06-09 09:20:16 -0700342 int chainEndMarker = gDvmJit.jitTableSize;
Bill Buzbee716f1202009-07-23 13:22:09 -0700343 while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
344 idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700345 if (gDvmJit.pJitEntryTable[idx].dPC == pc)
346 return &gDvmJit.pJitEntryTable[idx];
347 }
348 }
349 return NULL;
350}
351
Bill Buzbee716f1202009-07-23 13:22:09 -0700352JitEntry *dvmFindJitEntry(const u2* pc)
Bill Buzbee27176222009-06-09 09:20:16 -0700353{
354 return findJitEntry(pc);
355}
356
357/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700358 * If a translated code address exists for the davik byte code
359 * pointer return it. This routine needs to be fast.
360 */
361void* dvmJitGetCodeAddr(const u2* dPC)
362{
363 int idx = dvmJitHash(dPC);
364
Bill Buzbee46cd5b62009-06-05 15:36:06 -0700365 /* If anything is suspended, don't re-enter the code cache */
366 if (gDvm.sumThreadSuspendCount > 0) {
367 return NULL;
368 }
369
Ben Chengba4fc8b2009-06-01 13:00:29 -0700370 /* Expect a high hit rate on 1st shot */
371 if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
372#if defined(EXIT_STATS)
373 gDvmJit.addrLookupsFound++;
374#endif
375 return gDvmJit.pJitEntryTable[idx].codeAddress;
376 } else {
Bill Buzbee27176222009-06-09 09:20:16 -0700377 int chainEndMarker = gDvmJit.jitTableSize;
Bill Buzbee716f1202009-07-23 13:22:09 -0700378 while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
379 idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700380 if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
381#if defined(EXIT_STATS)
382 gDvmJit.addrLookupsFound++;
383#endif
384 return gDvmJit.pJitEntryTable[idx].codeAddress;
385 }
386 }
387 }
388#if defined(EXIT_STATS)
389 gDvmJit.addrLookupsNotFound++;
390#endif
391 return NULL;
392}
393
394/*
Bill Buzbee716f1202009-07-23 13:22:09 -0700395 * Find an entry in the JitTable, creating if necessary.
396 * Returns null if table is full.
397 */
398JitEntry *dvmJitLookupAndAdd(const u2* dPC)
399{
400 u4 chainEndMarker = gDvmJit.jitTableSize;
401 u4 idx = dvmJitHash(dPC);
402
403 /* Walk the bucket chain to find an exact match for our PC */
404 while ((gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) &&
405 (gDvmJit.pJitEntryTable[idx].dPC != dPC)) {
406 idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
407 }
408
409 if (gDvmJit.pJitEntryTable[idx].dPC != dPC) {
410 /*
411 * No match. Aquire jitTableLock and find the last
412 * slot in the chain. Possibly continue the chain walk in case
413 * some other thread allocated the slot we were looking
414 * at previuosly (perhaps even the dPC we're trying to enter).
415 */
416 dvmLockMutex(&gDvmJit.tableLock);
417 /*
418 * At this point, if .dPC is NULL, then the slot we're
419 * looking at is the target slot from the primary hash
420 * (the simple, and common case). Otherwise we're going
421 * to have to find a free slot and chain it.
422 */
423 MEM_BARRIER(); /* Make sure we reload [].dPC after lock */
424 if (gDvmJit.pJitEntryTable[idx].dPC != NULL) {
425 u4 prev;
426 while (gDvmJit.pJitEntryTable[idx].u.info.chain != chainEndMarker) {
427 if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
428 /* Another thread got there first for this dPC */
429 dvmUnlockMutex(&gDvmJit.tableLock);
430 return &gDvmJit.pJitEntryTable[idx];
431 }
432 idx = gDvmJit.pJitEntryTable[idx].u.info.chain;
433 }
434 /* Here, idx should be pointing to the last cell of an
435 * active chain whose last member contains a valid dPC */
436 assert(gDvmJit.pJitEntryTable[idx].dPC != NULL);
437 /* Linear walk to find a free cell and add it to the end */
438 prev = idx;
439 while (true) {
440 idx++;
441 if (idx == chainEndMarker)
442 idx = 0; /* Wraparound */
443 if ((gDvmJit.pJitEntryTable[idx].dPC == NULL) ||
444 (idx == prev))
445 break;
446 }
447 if (idx != prev) {
448 JitEntryInfoUnion oldValue;
449 JitEntryInfoUnion newValue;
450 /*
451 * Although we hold the lock so that noone else will
452 * be trying to update a chain field, the other fields
453 * packed into the word may be in use by other threads.
454 */
455 do {
456 oldValue = gDvmJit.pJitEntryTable[prev].u;
457 newValue = oldValue;
458 newValue.info.chain = idx;
459 } while (!ATOMIC_CMP_SWAP(
460 &gDvmJit.pJitEntryTable[prev].u.infoWord,
461 oldValue.infoWord, newValue.infoWord));
462 }
463 }
464 if (gDvmJit.pJitEntryTable[idx].dPC == NULL) {
465 /* Allocate the slot */
466 gDvmJit.pJitEntryTable[idx].dPC = dPC;
467 gDvmJit.jitTableEntriesUsed++;
468 } else {
469 /* Table is full */
470 idx = chainEndMarker;
471 }
472 dvmUnlockMutex(&gDvmJit.tableLock);
473 }
474 return (idx == chainEndMarker) ? NULL : &gDvmJit.pJitEntryTable[idx];
475}
476/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700477 * Register the translated code pointer into the JitTable.
478 * NOTE: Once a codeAddress field transitions from NULL to
479 * JIT'd code, it must not be altered without first halting all
Bill Buzbee716f1202009-07-23 13:22:09 -0700480 * threads. This routine should only be called by the compiler
481 * thread.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700482 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700483void dvmJitSetCodeAddr(const u2* dPC, void *nPC, JitInstructionSetType set) {
484 JitEntryInfoUnion oldValue;
485 JitEntryInfoUnion newValue;
486 JitEntry *jitEntry = dvmJitLookupAndAdd(dPC);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700487 assert(jitEntry);
Bill Buzbee716f1202009-07-23 13:22:09 -0700488 /* Note: order of update is important */
489 do {
490 oldValue = jitEntry->u;
491 newValue = oldValue;
492 newValue.info.instructionSet = set;
493 } while (!ATOMIC_CMP_SWAP(
494 &jitEntry->u.infoWord,
495 oldValue.infoWord, newValue.infoWord));
496 jitEntry->codeAddress = nPC;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700497}
498
499/*
500 * Determine if valid trace-bulding request is active. Return true
501 * if we need to abort and switch back to the fast interpreter, false
502 * otherwise. NOTE: may be called even when trace selection is not being
503 * requested
504 */
505
Ben Chengba4fc8b2009-06-01 13:00:29 -0700506bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState)
507{
Bill Buzbee48f18242009-06-19 16:02:27 -0700508 bool res = false; /* Assume success */
509 int i;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700510 if (gDvmJit.pJitEntryTable != NULL) {
Bill Buzbee48f18242009-06-19 16:02:27 -0700511 /* Two-level filtering scheme */
512 for (i=0; i< JIT_TRACE_THRESH_FILTER_SIZE; i++) {
513 if (interpState->pc == interpState->threshFilter[i]) {
514 break;
515 }
516 }
517 if (i == JIT_TRACE_THRESH_FILTER_SIZE) {
518 /*
519 * Use random replacement policy - otherwise we could miss a large
520 * loop that contains more traces than the size of our filter array.
521 */
522 i = rand() % JIT_TRACE_THRESH_FILTER_SIZE;
523 interpState->threshFilter[i] = interpState->pc;
524 res = true;
525 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700526 /*
527 * If the compiler is backlogged, or if a debugger or profiler is
528 * active, cancel any JIT actions
529 */
Bill Buzbee48f18242009-06-19 16:02:27 -0700530 if ( res || (gDvmJit.compilerQueueLength >= gDvmJit.compilerHighWater) ||
Ben Chengba4fc8b2009-06-01 13:00:29 -0700531 gDvm.debuggerActive || self->suspendCount
532#if defined(WITH_PROFILER)
533 || gDvm.activeProfilers
534#endif
535 ) {
536 if (interpState->jitState != kJitOff) {
537 interpState->jitState = kJitNormal;
538 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700539 } else if (interpState->jitState == kJitTSelectRequest) {
Bill Buzbee716f1202009-07-23 13:22:09 -0700540 JitEntry *slot = dvmJitLookupAndAdd(interpState->pc);
541 if (slot == NULL) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700542 /*
Bill Buzbee716f1202009-07-23 13:22:09 -0700543 * Table is full. This should have been
544 * detected by the compiler thread and the table
545 * resized before we run into it here. Assume bad things
546 * are afoot and disable profiling.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700547 */
548 interpState->jitState = kJitTSelectAbort;
Bill Buzbee716f1202009-07-23 13:22:09 -0700549 LOGD("JIT: JitTable full, disabling profiling");
550 dvmJitStopTranslationRequests();
551 } else if (slot->u.info.traceRequested) {
552 /* Trace already requested - revert to interpreter */
553 interpState->jitState = kJitTSelectAbort;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700554 } else {
Bill Buzbee716f1202009-07-23 13:22:09 -0700555 /* Mark request */
556 JitEntryInfoUnion oldValue;
557 JitEntryInfoUnion newValue;
558 do {
559 oldValue = slot->u;
560 newValue = oldValue;
561 newValue.info.traceRequested = true;
562 } while (!ATOMIC_CMP_SWAP( &slot->u.infoWord,
563 oldValue.infoWord, newValue.infoWord));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700564 }
565 }
566 switch (interpState->jitState) {
567 case kJitTSelectRequest:
568 interpState->jitState = kJitTSelect;
569 interpState->currTraceHead = interpState->pc;
570 interpState->currTraceRun = 0;
571 interpState->totalTraceLen = 0;
572 interpState->currRunHead = interpState->pc;
573 interpState->currRunLen = 0;
574 interpState->trace[0].frag.startOffset =
575 interpState->pc - interpState->method->insns;
576 interpState->trace[0].frag.numInsts = 0;
577 interpState->trace[0].frag.runEnd = false;
578 interpState->trace[0].frag.hint = kJitHintNone;
579 break;
580 case kJitTSelect:
581 case kJitTSelectAbort:
582 res = true;
583 case kJitSingleStep:
584 case kJitSingleStepEnd:
585 case kJitOff:
586 case kJitNormal:
587 break;
588 default:
589 dvmAbort();
590 }
591 }
592 return res;
593}
594
Bill Buzbee27176222009-06-09 09:20:16 -0700595/*
596 * Resizes the JitTable. Must be a power of 2, and returns true on failure.
597 * Stops all threads, and thus is a heavyweight operation.
598 */
599bool dvmJitResizeJitTable( unsigned int size )
600{
Bill Buzbee716f1202009-07-23 13:22:09 -0700601 JitEntry *pNewTable;
602 JitEntry *pOldTable;
Bill Buzbee27176222009-06-09 09:20:16 -0700603 u4 newMask;
Bill Buzbee716f1202009-07-23 13:22:09 -0700604 unsigned int oldSize;
Bill Buzbee27176222009-06-09 09:20:16 -0700605 unsigned int i;
606
Ben Cheng3f02aa42009-08-14 13:52:09 -0700607 assert(gDvmJit.pJitEntryTable != NULL);
Bill Buzbee27176222009-06-09 09:20:16 -0700608 assert(size && !(size & (size - 1))); /* Is power of 2? */
609
610 LOGD("Jit: resizing JitTable from %d to %d", gDvmJit.jitTableSize, size);
611
612 newMask = size - 1;
613
614 if (size <= gDvmJit.jitTableSize) {
615 return true;
616 }
617
Bill Buzbee716f1202009-07-23 13:22:09 -0700618 pNewTable = (JitEntry*)calloc(size, sizeof(*pNewTable));
Bill Buzbee27176222009-06-09 09:20:16 -0700619 if (pNewTable == NULL) {
620 return true;
621 }
622 for (i=0; i< size; i++) {
Bill Buzbee716f1202009-07-23 13:22:09 -0700623 pNewTable[i].u.info.chain = size; /* Initialize chain termination */
Bill Buzbee27176222009-06-09 09:20:16 -0700624 }
625
626 /* Stop all other interpreting/jit'ng threads */
627 dvmSuspendAllThreads(SUSPEND_FOR_JIT);
628
Bill Buzbee716f1202009-07-23 13:22:09 -0700629 pOldTable = gDvmJit.pJitEntryTable;
630 oldSize = gDvmJit.jitTableSize;
Bill Buzbee27176222009-06-09 09:20:16 -0700631
632 dvmLockMutex(&gDvmJit.tableLock);
Bill Buzbee27176222009-06-09 09:20:16 -0700633 gDvmJit.pJitEntryTable = pNewTable;
634 gDvmJit.jitTableSize = size;
635 gDvmJit.jitTableMask = size - 1;
Bill Buzbee716f1202009-07-23 13:22:09 -0700636 gDvmJit.jitTableEntriesUsed = 0;
Bill Buzbee27176222009-06-09 09:20:16 -0700637 dvmUnlockMutex(&gDvmJit.tableLock);
638
Bill Buzbee716f1202009-07-23 13:22:09 -0700639 for (i=0; i < oldSize; i++) {
640 if (pOldTable[i].dPC) {
641 JitEntry *p;
642 u2 chain;
643 p = dvmJitLookupAndAdd(pOldTable[i].dPC);
644 p->dPC = pOldTable[i].dPC;
645 /*
646 * Compiler thread may have just updated the new entry's
647 * code address field, so don't blindly copy null.
648 */
649 if (pOldTable[i].codeAddress != NULL) {
650 p->codeAddress = pOldTable[i].codeAddress;
651 }
652 /* We need to preserve the new chain field, but copy the rest */
653 dvmLockMutex(&gDvmJit.tableLock);
654 chain = p->u.info.chain;
655 p->u = pOldTable[i].u;
656 p->u.info.chain = chain;
657 dvmUnlockMutex(&gDvmJit.tableLock);
658 }
659 }
660
661 free(pOldTable);
662
Bill Buzbee27176222009-06-09 09:20:16 -0700663 /* Restart the world */
664 dvmResumeAllThreads(SUSPEND_FOR_JIT);
665
666 return false;
667}
668
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700669/*
670 * Float/double conversion requires clamping to min and max of integer form. If
671 * target doesn't support this normally, use these.
672 */
673s8 dvmJitd2l(double d)
674{
Bill Buzbee9727c3d2009-08-01 11:32:36 -0700675 static const double kMaxLong = (double)(s8)0x7fffffffffffffffULL;
676 static const double kMinLong = (double)(s8)0x8000000000000000ULL;
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700677 if (d >= kMaxLong)
Bill Buzbee9727c3d2009-08-01 11:32:36 -0700678 return (s8)0x7fffffffffffffffULL;
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700679 else if (d <= kMinLong)
Bill Buzbee9727c3d2009-08-01 11:32:36 -0700680 return (s8)0x8000000000000000ULL;
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700681 else if (d != d) // NaN case
682 return 0;
683 else
684 return (s8)d;
685}
686
687s8 dvmJitf2l(float f)
688{
Bill Buzbee9727c3d2009-08-01 11:32:36 -0700689 static const float kMaxLong = (float)(s8)0x7fffffffffffffffULL;
690 static const float kMinLong = (float)(s8)0x8000000000000000ULL;
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700691 if (f >= kMaxLong)
Bill Buzbee9727c3d2009-08-01 11:32:36 -0700692 return (s8)0x7fffffffffffffffULL;
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700693 else if (f <= kMinLong)
Bill Buzbee9727c3d2009-08-01 11:32:36 -0700694 return (s8)0x8000000000000000ULL;
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700695 else if (f != f) // NaN case
696 return 0;
697 else
698 return (s8)f;
699}
700
Bill Buzbee27176222009-06-09 09:20:16 -0700701
Ben Chengba4fc8b2009-06-01 13:00:29 -0700702#endif /* WITH_JIT */