blob: 6c6abce30f7936cdec739f7195a3da8ace0271b6 [file] [log] [blame]
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -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 */
The Android Open Source Project89c1feb2008-12-17 18:03:55 -080016
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -070017/*
18 * Main interpreter entry point and support functions.
19 *
20 * The entry point selects the "standard" or "debug" interpreter and
21 * facilitates switching between them. The standard interpreter may
22 * use the "fast" or "portable" implementation.
23 *
24 * Some debugger support functions are included here. Ideally their
25 * entire existence would be "#ifdef WITH_DEBUGGER", but we're not that
26 * aggressive in other parts of the code yet.
27 */
28#include "Dalvik.h"
29#include "interp/InterpDefs.h"
30
31
32/*
33 * ===========================================================================
34 * Debugger support
35 * ===========================================================================
36 */
37
Andy McFadden96516932009-10-28 17:39:02 -070038// fwd
39static BreakpointSet* dvmBreakpointSetAlloc(void);
40static void dvmBreakpointSetFree(BreakpointSet* pSet);
41
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -070042/*
Andy McFadden96516932009-10-28 17:39:02 -070043 * Initialize global breakpoint structures.
44 */
45bool dvmBreakpointStartup(void)
46{
47#ifdef WITH_DEBUGGER
48 gDvm.breakpointSet = dvmBreakpointSetAlloc();
49 return (gDvm.breakpointSet != NULL);
50#else
51 return true;
52#endif
53}
54
55/*
56 * Free resources.
57 */
58void dvmBreakpointShutdown(void)
59{
60#ifdef WITH_DEBUGGER
61 dvmBreakpointSetFree(gDvm.breakpointSet);
62#endif
63}
64
65
66#ifdef WITH_DEBUGGER
67/*
68 * This represents a breakpoint inserted in the instruction stream.
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -070069 *
Andy McFadden96516932009-10-28 17:39:02 -070070 * The debugger may ask us to create the same breakpoint multiple times.
71 * We only remove the breakpoint when the last instance is cleared.
72 */
73typedef struct {
74 u2* addr; /* absolute memory address */
75 u1 originalOpCode; /* original 8-bit opcode value */
76 int setCount; /* #of times this breakpoint was set */
77} Breakpoint;
78
79/*
80 * Set of breakpoints.
81 */
82struct BreakpointSet {
83 /* grab lock before reading or writing anything else in here */
84 pthread_mutex_t lock;
85
86 /* vector of breakpoint structures */
87 int alloc;
88 int count;
89 Breakpoint* breakpoints;
90};
91
92/*
93 * Initialize a BreakpointSet. Initially empty.
94 */
95static BreakpointSet* dvmBreakpointSetAlloc(void)
96{
97 BreakpointSet* pSet = (BreakpointSet*) calloc(1, sizeof(*pSet));
98
99 dvmInitMutex(&pSet->lock);
100 /* leave the rest zeroed -- will alloc on first use */
101
102 return pSet;
103}
104
105/*
106 * Free storage associated with a BreakpointSet.
107 */
108static void dvmBreakpointSetFree(BreakpointSet* pSet)
109{
110 if (pSet == NULL)
111 return;
112
113 free(pSet->breakpoints);
114 free(pSet);
115}
116
117/*
118 * Lock the breakpoint set.
119 */
120static void dvmBreakpointSetLock(BreakpointSet* pSet)
121{
122 dvmLockMutex(&pSet->lock);
123}
124
125/*
126 * Unlock the breakpoint set.
127 */
128static void dvmBreakpointSetUnlock(BreakpointSet* pSet)
129{
130 dvmUnlockMutex(&pSet->lock);
131}
132
133/*
134 * Return the #of breakpoints.
135 */
136static int dvmBreakpointSetCount(const BreakpointSet* pSet)
137{
138 return pSet->count;
139}
140
141/*
142 * See if we already have an entry for this address.
143 *
144 * The BreakpointSet's lock must be acquired before calling here.
145 *
146 * Returns the index of the breakpoint entry, or -1 if not found.
147 */
148static int dvmBreakpointSetFind(const BreakpointSet* pSet, const u2* addr)
149{
150 int i;
151
152 for (i = 0; i < pSet->count; i++) {
153 Breakpoint* pBreak = &pSet->breakpoints[i];
154 if (pBreak->addr == addr)
155 return i;
156 }
157
158 return -1;
159}
160
161/*
162 * Retrieve the opcode that was originally at the specified location.
163 *
164 * The BreakpointSet's lock must be acquired before calling here.
165 *
166 * Returns "true" with the opcode in *pOrig on success.
167 */
168static bool dvmBreakpointSetOriginalOpCode(const BreakpointSet* pSet,
169 const u2* addr, u1* pOrig)
170{
171 int idx = dvmBreakpointSetFind(pSet, addr);
172 if (idx < 0)
173 return false;
174
175 *pOrig = pSet->breakpoints[idx].originalOpCode;
176 return true;
177}
178
179/*
180 * Add a breakpoint at a specific address. If the address is already
181 * present in the table, this just increments the count.
182 *
183 * For a new entry, this will extract and preserve the current opcode from
184 * the instruction stream, and replace it with a breakpoint opcode.
185 *
186 * The BreakpointSet's lock must be acquired before calling here.
187 *
188 * Returns "true" on success.
189 */
190static bool dvmBreakpointSetAdd(BreakpointSet* pSet, Method* method,
191 unsigned int instrOffset)
192{
193 const int kBreakpointGrowth = 10;
194 const u2* addr = method->insns + instrOffset;
195 int idx = dvmBreakpointSetFind(pSet, addr);
196 Breakpoint* pBreak;
197
198 if (idx < 0) {
199 if (pSet->count == pSet->alloc) {
200 int newSize = pSet->alloc + kBreakpointGrowth;
201 Breakpoint* newVec;
202
203 LOGV("+++ increasing breakpoint set size to %d\n", newSize);
204
205 /* pSet->breakpoints will be NULL on first entry */
206 newVec = realloc(pSet->breakpoints, newSize * sizeof(Breakpoint));
207 if (newVec == NULL)
208 return false;
209
210 pSet->breakpoints = newVec;
211 pSet->alloc = newSize;
212 }
213
214 pBreak = &pSet->breakpoints[pSet->count++];
215 pBreak->addr = (u2*)addr;
216 pBreak->originalOpCode = *(u1*)addr;
217 pBreak->setCount = 1;
218
219 /*
220 * Change the opcode. We must ensure that the BreakpointSet
221 * updates happen before we change the opcode.
222 */
223 MEM_BARRIER();
224 assert(*(u1*)addr != OP_BREAKPOINT);
225 dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr, OP_BREAKPOINT);
226 } else {
227 pBreak = &pSet->breakpoints[idx];
228 pBreak->setCount++;
229
230 /* verify instruction stream has break op */
231 assert(*(u1*)addr == OP_BREAKPOINT);
232 }
233
234 return true;
235}
236
237/*
238 * Remove one instance of the specified breakpoint. When the count
239 * reaches zero, the entry is removed from the table, and the original
240 * opcode is restored.
241 *
242 * The BreakpointSet's lock must be acquired before calling here.
243 */
244static void dvmBreakpointSetRemove(BreakpointSet* pSet, Method* method,
245 unsigned int instrOffset)
246{
247 const u2* addr = method->insns + instrOffset;
248 int idx = dvmBreakpointSetFind(pSet, addr);
249
250 if (idx < 0) {
251 /* breakpoint not found in set -- unexpected */
252 if (*(u1*)addr == OP_BREAKPOINT) {
253 LOGE("Unable to restore breakpoint opcode (%s.%s +%u)\n",
254 method->clazz->descriptor, method->name, instrOffset);
255 dvmAbort();
256 } else {
257 LOGW("Breakpoint was already restored? (%s.%s +%u)\n",
258 method->clazz->descriptor, method->name, instrOffset);
259 }
260 } else {
261 Breakpoint* pBreak = &pSet->breakpoints[idx];
262 if (pBreak->setCount == 1) {
263 /*
264 * Must restore opcode before removing set entry.
265 */
266 dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr,
267 pBreak->originalOpCode);
268 MEM_BARRIER();
269
270 if (idx != pSet->count-1) {
271 /* shift down */
272 memmove(&pSet->breakpoints[idx], &pSet->breakpoints[idx+1],
273 (pSet->count-1 - idx) * sizeof(pSet->breakpoints[0]));
274 }
275 pSet->count--;
276 pSet->breakpoints[pSet->count].addr = (u2*) 0xdecadead; // debug
277 } else {
278 pBreak->setCount--;
279 assert(pBreak->setCount > 0);
280 }
281 }
282}
283
284/*
285 * Restore the original opcode on any breakpoints that are in the specified
286 * method. The breakpoints are NOT removed from the set.
287 *
288 * The BreakpointSet's lock must be acquired before calling here.
289 */
290static void dvmBreakpointSetUndo(BreakpointSet* pSet, Method* method)
291{
292 const u2* start = method->insns;
293 const u2* end = method->insns + dvmGetMethodInsnsSize(method);
294
295 int i;
296 for (i = 0; i < pSet->count; i++) {
297 Breakpoint* pBreak = &pSet->breakpoints[i];
298 if (pBreak->addr >= start && pBreak->addr < end) {
299 LOGV("UNDO %s.%s [%d]\n",
300 method->clazz->descriptor, method->name, i);
301 dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)pBreak->addr,
302 pBreak->originalOpCode);
303 }
304 }
305}
306
307/*
308 * Put the breakpoint opcode back into the instruction stream, and check
309 * to see if the original opcode has changed.
310 *
311 * The BreakpointSet's lock must be acquired before calling here.
312 */
313static void dvmBreakpointSetRedo(BreakpointSet* pSet, Method* method)
314{
315 const u2* start = method->insns;
316 const u2* end = method->insns + dvmGetMethodInsnsSize(method);
317
318 int i;
319 for (i = 0; i < pSet->count; i++) {
320 Breakpoint* pBreak = &pSet->breakpoints[i];
321 if (pBreak->addr >= start && pBreak->addr < end) {
322 LOGV("REDO %s.%s [%d]\n",
323 method->clazz->descriptor, method->name, i);
324 u1 currentOpCode = *(u1*)pBreak->addr;
325 if (pBreak->originalOpCode != currentOpCode) {
326 /* verifier can drop in a throw-verification-error */
327 LOGD("NOTE: updating originalOpCode from 0x%02x to 0x%02x\n",
328 pBreak->originalOpCode, currentOpCode);
329 pBreak->originalOpCode = currentOpCode;
330 }
331 dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)pBreak->addr,
332 OP_BREAKPOINT);
333 }
334 }
335}
336
337#endif /*WITH_DEBUGGER*/
338
339
340/*
341 * Do any debugger-attach-time initialization.
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700342 */
343void dvmInitBreakpoints(void)
344{
345#ifdef WITH_DEBUGGER
Andy McFadden96516932009-10-28 17:39:02 -0700346 /* quick sanity check */
347 BreakpointSet* pSet = gDvm.breakpointSet;
348 dvmBreakpointSetLock(pSet);
349 if (dvmBreakpointSetCount(pSet) != 0) {
350 LOGW("WARNING: %d leftover breakpoints\n", dvmBreakpointSetCount(pSet));
351 /* generally not good, but we can keep going */
352 }
353 dvmBreakpointSetUnlock(pSet);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700354#else
355 assert(false);
356#endif
357}
358
359/*
360 * Add an address to the list, putting it in the first non-empty slot.
361 *
362 * Sometimes the debugger likes to add two entries for one breakpoint.
363 * We add two entries here, so that we get the right behavior when it's
364 * removed twice.
365 *
366 * This will only be run from the JDWP thread, and it will happen while
367 * we are updating the event list, which is synchronized. We're guaranteed
368 * to be the only one adding entries, and the lock ensures that nobody
369 * will be trying to remove them while we're in here.
370 *
371 * "addr" is the absolute address of the breakpoint bytecode.
372 */
Andy McFadden96516932009-10-28 17:39:02 -0700373void dvmAddBreakAddr(Method* method, unsigned int instrOffset)
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700374{
375#ifdef WITH_DEBUGGER
Andy McFadden96516932009-10-28 17:39:02 -0700376 BreakpointSet* pSet = gDvm.breakpointSet;
377 dvmBreakpointSetLock(pSet);
378 dvmBreakpointSetAdd(pSet, method, instrOffset);
379 dvmBreakpointSetUnlock(pSet);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700380#else
381 assert(false);
382#endif
383}
384
385/*
386 * Remove an address from the list by setting the entry to NULL.
387 *
388 * This can be called from the JDWP thread (because the debugger has
389 * cancelled the breakpoint) or from an event thread (because it's a
390 * single-shot breakpoint, e.g. "run to line"). We only get here as
391 * the result of removing an entry from the event list, which is
392 * synchronized, so it should not be possible for two threads to be
393 * updating breakpoints at the same time.
394 */
Andy McFadden96516932009-10-28 17:39:02 -0700395void dvmClearBreakAddr(Method* method, unsigned int instrOffset)
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700396{
397#ifdef WITH_DEBUGGER
Andy McFadden96516932009-10-28 17:39:02 -0700398 BreakpointSet* pSet = gDvm.breakpointSet;
399 dvmBreakpointSetLock(pSet);
400 dvmBreakpointSetRemove(pSet, method, instrOffset);
401 dvmBreakpointSetUnlock(pSet);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700402
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700403#else
404 assert(false);
405#endif
406}
407
Andy McFadden96516932009-10-28 17:39:02 -0700408#ifdef WITH_DEBUGGER
409/*
410 * Get the original opcode from under a breakpoint.
411 */
412u1 dvmGetOriginalOpCode(const u2* addr)
413{
414 BreakpointSet* pSet = gDvm.breakpointSet;
415 u1 orig = 0;
416
417 dvmBreakpointSetLock(pSet);
418 if (!dvmBreakpointSetOriginalOpCode(pSet, addr, &orig)) {
419 orig = *(u1*)addr;
420 if (orig == OP_BREAKPOINT) {
421 LOGE("GLITCH: can't find breakpoint, opcode is still set\n");
422 dvmAbort();
423 }
424 }
425 dvmBreakpointSetUnlock(pSet);
426
427 return orig;
428}
429
430/*
431 * Temporarily "undo" any breakpoints set in a specific method. Used
432 * during verification.
433 *
434 * Locks the breakpoint set, and leaves it locked.
435 */
436void dvmUndoBreakpoints(Method* method)
437{
438 BreakpointSet* pSet = gDvm.breakpointSet;
439
440 dvmBreakpointSetLock(pSet);
441 dvmBreakpointSetUndo(pSet, method);
442 /* lock remains held */
443}
444
445/*
446 * "Redo" the breakpoints cleared by a previous "undo", re-inserting the
447 * breakpoint opcodes and updating the "original opcode" values.
448 *
449 * Unlocks the breakpoint set, which must be held by a previous "undo".
450 */
451void dvmRedoBreakpoints(Method* method)
452{
453 BreakpointSet* pSet = gDvm.breakpointSet;
454
455 /* lock already held */
456 dvmBreakpointSetRedo(pSet, method);
457 dvmBreakpointSetUnlock(pSet);
458}
459#endif
460
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700461/*
462 * Add a single step event. Currently this is a global item.
463 *
464 * We set up some initial values based on the thread's current state. This
465 * won't work well if the thread is running, so it's up to the caller to
466 * verify that it's suspended.
467 *
468 * This is only called from the JDWP thread.
469 */
470bool dvmAddSingleStep(Thread* thread, int size, int depth)
471{
472#ifdef WITH_DEBUGGER
473 StepControl* pCtrl = &gDvm.stepControl;
474
475 if (pCtrl->active && thread != pCtrl->thread) {
476 LOGW("WARNING: single-step active for %p; adding %p\n",
477 pCtrl->thread, thread);
478
479 /*
480 * Keep going, overwriting previous. This can happen if you
481 * suspend a thread in Object.wait, hit the single-step key, then
482 * switch to another thread and do the same thing again.
483 * The first thread's step is still pending.
484 *
485 * TODO: consider making single-step per-thread. Adds to the
486 * overhead, but could be useful in rare situations.
487 */
488 }
489
490 pCtrl->size = size;
491 pCtrl->depth = depth;
492 pCtrl->thread = thread;
493
494 /*
495 * We may be stepping into or over method calls, or running until we
496 * return from the current method. To make this work we need to track
497 * the current line, current method, and current stack depth. We need
498 * to be checking these after most instructions, notably those that
499 * call methods, return from methods, or are on a different line from the
500 * previous instruction.
501 *
502 * We have to start with a snapshot of the current state. If we're in
503 * an interpreted method, everything we need is in the current frame. If
504 * we're in a native method, possibly with some extra JNI frames pushed
505 * on by PushLocalFrame, we want to use the topmost native method.
506 */
507 const StackSaveArea* saveArea;
508 void* fp;
509 void* prevFp = NULL;
Ben Cheng38329f52009-07-07 14:19:20 -0700510
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700511 for (fp = thread->curFrame; fp != NULL; fp = saveArea->prevFrame) {
512 const Method* method;
513
514 saveArea = SAVEAREA_FROM_FP(fp);
515 method = saveArea->method;
516
517 if (!dvmIsBreakFrame(fp) && !dvmIsNativeMethod(method))
518 break;
519 prevFp = fp;
520 }
521 if (fp == NULL) {
522 LOGW("Unexpected: step req in native-only threadid=%d\n",
523 thread->threadId);
524 return false;
525 }
526 if (prevFp != NULL) {
527 /*
528 * First interpreted frame wasn't the one at the bottom. Break
529 * frames are only inserted when calling from native->interp, so we
530 * don't need to worry about one being here.
531 */
532 LOGV("##### init step while in native method\n");
533 fp = prevFp;
534 assert(!dvmIsBreakFrame(fp));
535 assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method));
536 saveArea = SAVEAREA_FROM_FP(fp);
537 }
538
539 /*
540 * Pull the goodies out. "xtra.currentPc" should be accurate since
541 * we update it on every instruction while the debugger is connected.
542 */
543 pCtrl->method = saveArea->method;
544 // Clear out any old address set
545 if (pCtrl->pAddressSet != NULL) {
546 // (discard const)
547 free((void *)pCtrl->pAddressSet);
548 pCtrl->pAddressSet = NULL;
549 }
550 if (dvmIsNativeMethod(pCtrl->method)) {
551 pCtrl->line = -1;
552 } else {
553 pCtrl->line = dvmLineNumFromPC(saveArea->method,
554 saveArea->xtra.currentPc - saveArea->method->insns);
Ben Cheng38329f52009-07-07 14:19:20 -0700555 pCtrl->pAddressSet
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700556 = dvmAddressSetForLine(saveArea->method, pCtrl->line);
557 }
558 pCtrl->frameDepth = dvmComputeVagueFrameDepth(thread, thread->curFrame);
559 pCtrl->active = true;
560
561 LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s\n",
562 pCtrl->thread, pCtrl->method, pCtrl->method->name,
563 pCtrl->line, pCtrl->frameDepth,
564 dvmJdwpStepDepthStr(pCtrl->depth),
565 dvmJdwpStepSizeStr(pCtrl->size));
566
567 return true;
568#else
569 assert(false);
570 return false;
571#endif
572}
573
574/*
575 * Disable a single step event.
576 */
577void dvmClearSingleStep(Thread* thread)
578{
579#ifdef WITH_DEBUGGER
580 UNUSED_PARAMETER(thread);
581
582 gDvm.stepControl.active = false;
583#else
584 assert(false);
585#endif
586}
587
588
589/*
590 * Recover the "this" pointer from the current interpreted method. "this"
591 * is always in "in0" for non-static methods.
592 *
593 * The "ins" start at (#of registers - #of ins). Note in0 != v0.
594 *
595 * This works because "dx" guarantees that it will work. It's probably
596 * fairly common to have a virtual method that doesn't use its "this"
597 * pointer, in which case we're potentially wasting a register. However,
598 * the debugger doesn't treat "this" as just another argument. For
599 * example, events (such as breakpoints) can be enabled for specific
600 * values of "this". There is also a separate StackFrame.ThisObject call
601 * in JDWP that is expected to work for any non-native non-static method.
602 *
603 * Because we need it when setting up debugger event filters, we want to
604 * be able to do this quickly.
605 */
606Object* dvmGetThisPtr(const Method* method, const u4* fp)
607{
608 if (dvmIsStaticMethod(method))
609 return NULL;
610 return (Object*)fp[method->registersSize - method->insSize];
611}
612
613
614#if defined(WITH_TRACKREF_CHECKS)
615/*
616 * Verify that all internally-tracked references have been released. If
617 * they haven't, print them and abort the VM.
618 *
619 * "debugTrackedRefStart" indicates how many refs were on the list when
620 * we were first invoked.
621 */
622void dvmInterpCheckTrackedRefs(Thread* self, const Method* method,
623 int debugTrackedRefStart)
624{
625 if (dvmReferenceTableEntries(&self->internalLocalRefTable)
626 != (size_t) debugTrackedRefStart)
627 {
628 char* desc;
629 Object** top;
630 int count;
631
632 count = dvmReferenceTableEntries(&self->internalLocalRefTable);
633
634 LOGE("TRACK: unreleased internal reference (prev=%d total=%d)\n",
635 debugTrackedRefStart, count);
636 desc = dexProtoCopyMethodDescriptor(&method->prototype);
637 LOGE(" current method is %s.%s %s\n", method->clazz->descriptor,
638 method->name, desc);
639 free(desc);
640 top = self->internalLocalRefTable.table + debugTrackedRefStart;
641 while (top < self->internalLocalRefTable.nextEntry) {
642 LOGE(" %p (%s)\n",
643 *top,
644 ((*top)->clazz != NULL) ? (*top)->clazz->descriptor : "");
645 top++;
646 }
647 dvmDumpThread(self, false);
648
649 dvmAbort();
650 }
651 //LOGI("TRACK OK\n");
652}
653#endif
654
655
656#ifdef LOG_INSTR
657/*
658 * Dump the v-registers. Sent to the ILOG log tag.
659 */
660void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly)
661{
662 int i, localCount;
663
664 localCount = method->registersSize - method->insSize;
665
666 LOG(LOG_VERBOSE, LOG_TAG"i", "Registers (fp=%p):\n", framePtr);
667 for (i = method->registersSize-1; i >= 0; i--) {
668 if (i >= localCount) {
669 LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d in%-2d : 0x%08x\n",
670 i, i-localCount, framePtr[i]);
671 } else {
672 if (inOnly) {
673 LOG(LOG_VERBOSE, LOG_TAG"i", " [...]\n");
674 break;
675 }
676 const char* name = "";
677 int j;
678#if 0 // "locals" structure has changed -- need to rewrite this
679 DexFile* pDexFile = method->clazz->pDexFile;
680 const DexCode* pDexCode = dvmGetMethodCode(method);
681 int localsSize = dexGetLocalsSize(pDexFile, pDexCode);
682 const DexLocal* locals = dvmDexGetLocals(pDexFile, pDexCode);
683 for (j = 0; j < localsSize, j++) {
684 if (locals[j].registerNum == (u4) i) {
685 name = dvmDexStringStr(locals[j].pName);
686 break;
687 }
688 }
689#endif
690 LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d : 0x%08x %s\n",
691 i, framePtr[i], name);
692 }
693 }
694}
695#endif
696
697
698/*
699 * ===========================================================================
700 * Entry point and general support functions
701 * ===========================================================================
702 */
703
Ben Cheng38329f52009-07-07 14:19:20 -0700704/*
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700705 * Construct an s4 from two consecutive half-words of switch data.
706 * This needs to check endianness because the DEX optimizer only swaps
707 * half-words in instruction stream.
708 *
709 * "switchData" must be 32-bit aligned.
710 */
711#if __BYTE_ORDER == __LITTLE_ENDIAN
712static inline s4 s4FromSwitchData(const void* switchData) {
713 return *(s4*) switchData;
714}
715#else
716static inline s4 s4FromSwitchData(const void* switchData) {
717 u2* data = switchData;
718 return data[0] | (((s4) data[1]) << 16);
Jay Freeman (saurik)ffa5c292008-11-16 13:51:51 +0000719}
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700720#endif
721
722/*
723 * Find the matching case. Returns the offset to the handler instructions.
724 *
725 * Returns 3 if we don't find a match (it's the size of the packed-switch
726 * instruction).
727 */
728s4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal)
729{
730 const int kInstrLen = 3;
731 u2 size;
732 s4 firstKey;
733 const s4* entries;
734
735 /*
736 * Packed switch data format:
737 * ushort ident = 0x0100 magic value
738 * ushort size number of entries in the table
739 * int first_key first (and lowest) switch case value
740 * int targets[size] branch targets, relative to switch opcode
741 *
742 * Total size is (4+size*2) 16-bit code units.
743 */
744 if (*switchData++ != kPackedSwitchSignature) {
745 /* should have been caught by verifier */
746 dvmThrowException("Ljava/lang/InternalError;",
747 "bad packed switch magic");
748 return kInstrLen;
749 }
750
751 size = *switchData++;
752 assert(size > 0);
753
754 firstKey = *switchData++;
755 firstKey |= (*switchData++) << 16;
756
757 if (testVal < firstKey || testVal >= firstKey + size) {
758 LOGVV("Value %d not found in switch (%d-%d)\n",
759 testVal, firstKey, firstKey+size-1);
760 return kInstrLen;
761 }
762
763 /* The entries are guaranteed to be aligned on a 32-bit boundary;
764 * we can treat them as a native int array.
765 */
766 entries = (const s4*) switchData;
767 assert(((u4)entries & 0x3) == 0);
768
769 assert(testVal - firstKey >= 0 && testVal - firstKey < size);
770 LOGVV("Value %d found in slot %d (goto 0x%02x)\n",
771 testVal, testVal - firstKey,
772 s4FromSwitchData(&entries[testVal - firstKey]));
773 return s4FromSwitchData(&entries[testVal - firstKey]);
774}
775
776/*
777 * Find the matching case. Returns the offset to the handler instructions.
778 *
779 * Returns 3 if we don't find a match (it's the size of the sparse-switch
780 * instruction).
781 */
782s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal)
783{
784 const int kInstrLen = 3;
785 u2 ident, size;
786 const s4* keys;
787 const s4* entries;
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700788
789 /*
790 * Sparse switch data format:
791 * ushort ident = 0x0200 magic value
792 * ushort size number of entries in the table; > 0
793 * int keys[size] keys, sorted low-to-high; 32-bit aligned
794 * int targets[size] branch targets, relative to switch opcode
795 *
796 * Total size is (2+size*4) 16-bit code units.
797 */
798
799 if (*switchData++ != kSparseSwitchSignature) {
800 /* should have been caught by verifier */
801 dvmThrowException("Ljava/lang/InternalError;",
802 "bad sparse switch magic");
803 return kInstrLen;
804 }
805
806 size = *switchData++;
807 assert(size > 0);
Ben Cheng38329f52009-07-07 14:19:20 -0700808
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700809 /* The keys are guaranteed to be aligned on a 32-bit boundary;
810 * we can treat them as a native int array.
811 */
812 keys = (const s4*) switchData;
813 assert(((u4)keys & 0x3) == 0);
814
815 /* The entries are guaranteed to be aligned on a 32-bit boundary;
816 * we can treat them as a native int array.
817 */
818 entries = keys + size;
819 assert(((u4)entries & 0x3) == 0);
820
821 /*
Andy McFadden62f19152009-10-21 16:59:31 -0700822 * Binary-search through the array of keys, which are guaranteed to
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700823 * be sorted low-to-high.
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700824 */
Andy McFadden62f19152009-10-21 16:59:31 -0700825 int lo = 0;
826 int hi = size - 1;
827 while (lo <= hi) {
828 int mid = (lo + hi) >> 1;
829
830 s4 foundVal = s4FromSwitchData(&keys[mid]);
831 if (testVal < foundVal) {
832 hi = mid - 1;
833 } else if (testVal > foundVal) {
834 lo = mid + 1;
835 } else {
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700836 LOGVV("Value %d found in entry %d (goto 0x%02x)\n",
Andy McFadden62f19152009-10-21 16:59:31 -0700837 testVal, mid, s4FromSwitchData(&entries[mid]));
838 return s4FromSwitchData(&entries[mid]);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700839 }
840 }
841
842 LOGVV("Value %d not found in switch\n", testVal);
843 return kInstrLen;
844}
845
846/*
Andy McFadden6f214502009-06-30 16:14:30 -0700847 * Copy data for a fill-array-data instruction. On a little-endian machine
848 * we can just do a memcpy(), on a big-endian system we have work to do.
849 *
850 * The trick here is that dexopt has byte-swapped each code unit, which is
851 * exactly what we want for short/char data. For byte data we need to undo
852 * the swap, and for 4- or 8-byte values we need to swap pieces within
853 * each word.
854 */
855static void copySwappedArrayData(void* dest, const u2* src, u4 size, u2 width)
856{
857#if __BYTE_ORDER == __LITTLE_ENDIAN
858 memcpy(dest, src, size*width);
859#else
860 int i;
861
862 switch (width) {
863 case 1:
864 /* un-swap pairs of bytes as we go */
865 for (i = (size-1) & ~1; i >= 0; i -= 2) {
866 ((u1*)dest)[i] = ((u1*)src)[i+1];
867 ((u1*)dest)[i+1] = ((u1*)src)[i];
868 }
869 /*
870 * "src" is padded to end on a two-byte boundary, but we don't want to
871 * assume "dest" is, so we handle odd length specially.
872 */
873 if ((size & 1) != 0) {
874 ((u1*)dest)[size-1] = ((u1*)src)[size];
875 }
876 break;
877 case 2:
878 /* already swapped correctly */
879 memcpy(dest, src, size*width);
880 break;
881 case 4:
882 /* swap word halves */
883 for (i = 0; i < (int) size; i++) {
884 ((u4*)dest)[i] = (src[(i << 1) + 1] << 16) | src[i << 1];
885 }
886 break;
887 case 8:
888 /* swap word halves and words */
889 for (i = 0; i < (int) (size << 1); i += 2) {
890 ((int*)dest)[i] = (src[(i << 1) + 3] << 16) | src[(i << 1) + 2];
891 ((int*)dest)[i+1] = (src[(i << 1) + 1] << 16) | src[i << 1];
892 }
893 break;
894 default:
895 LOGE("Unexpected width %d in copySwappedArrayData\n", width);
896 dvmAbort();
897 break;
898 }
899#endif
900}
901
902/*
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700903 * Fill the array with predefined constant values.
904 *
905 * Returns true if job is completed, otherwise false to indicate that
906 * an exception has been thrown.
907 */
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800908bool dvmInterpHandleFillArrayData(ArrayObject* arrayObj, const u2* arrayData)
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700909{
910 u2 width;
911 u4 size;
912
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800913 if (arrayObj == NULL) {
914 dvmThrowException("Ljava/lang/NullPointerException;", NULL);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700915 return false;
916 }
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800917
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700918 /*
919 * Array data table format:
920 * ushort ident = 0x0300 magic value
921 * ushort width width of each element in the table
922 * uint size number of elements in the table
923 * ubyte data[size*width] table of data values (may contain a single-byte
924 * padding at the end)
925 *
926 * Total size is 4+(width * size + 1)/2 16-bit code units.
927 */
928 if (arrayData[0] != kArrayDataSignature) {
929 dvmThrowException("Ljava/lang/InternalError;", "bad array data magic");
930 return false;
931 }
932
933 width = arrayData[1];
934 size = arrayData[2] | (((u4)arrayData[3]) << 16);
935
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800936 if (size > arrayObj->length) {
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700937 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL);
938 return false;
939 }
Andy McFadden6f214502009-06-30 16:14:30 -0700940 copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700941 return true;
942}
943
944/*
945 * Find the concrete method that corresponds to "methodIdx". The code in
946 * "method" is executing invoke-method with "thisClass" as its first argument.
947 *
948 * Returns NULL with an exception raised on failure.
949 */
950Method* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx,
951 const Method* method, DvmDex* methodClassDex)
952{
953 Method* absMethod;
954 Method* methodToCall;
955 int i, vtableIndex;
956
957 /*
958 * Resolve the method. This gives us the abstract method from the
959 * interface class declaration.
960 */
961 absMethod = dvmDexGetResolvedMethod(methodClassDex, methodIdx);
962 if (absMethod == NULL) {
963 absMethod = dvmResolveInterfaceMethod(method->clazz, methodIdx);
964 if (absMethod == NULL) {
965 LOGV("+ unknown method\n");
966 return NULL;
967 }
968 }
969
970 /* make sure absMethod->methodIndex means what we think it means */
971 assert(dvmIsAbstractMethod(absMethod));
972
973 /*
974 * Run through the "this" object's iftable. Find the entry for
975 * absMethod's class, then use absMethod->methodIndex to find
976 * the method's entry. The value there is the offset into our
977 * vtable of the actual method to execute.
978 *
979 * The verifier does not guarantee that objects stored into
980 * interface references actually implement the interface, so this
981 * check cannot be eliminated.
982 */
983 for (i = 0; i < thisClass->iftableCount; i++) {
984 if (thisClass->iftable[i].clazz == absMethod->clazz)
985 break;
986 }
987 if (i == thisClass->iftableCount) {
988 /* impossible in verified DEX, need to check for it in unverified */
989 dvmThrowException("Ljava/lang/IncompatibleClassChangeError;",
990 "interface not implemented");
991 return NULL;
992 }
993
994 assert(absMethod->methodIndex <
995 thisClass->iftable[i].clazz->virtualMethodCount);
996
997 vtableIndex =
998 thisClass->iftable[i].methodIndexArray[absMethod->methodIndex];
999 assert(vtableIndex >= 0 && vtableIndex < thisClass->vtableCount);
1000 methodToCall = thisClass->vtable[vtableIndex];
1001
1002#if 0
1003 /* this can happen when there's a stale class file */
1004 if (dvmIsAbstractMethod(methodToCall)) {
1005 dvmThrowException("Ljava/lang/AbstractMethodError;",
1006 "interface method not implemented");
1007 return NULL;
1008 }
1009#else
1010 assert(!dvmIsAbstractMethod(methodToCall) ||
1011 methodToCall->nativeFunc != NULL);
1012#endif
1013
1014 LOGVV("+++ interface=%s.%s concrete=%s.%s\n",
1015 absMethod->clazz->descriptor, absMethod->name,
1016 methodToCall->clazz->descriptor, methodToCall->name);
1017 assert(methodToCall != NULL);
1018
1019 return methodToCall;
1020}
1021
1022
Andy McFaddenb51ea112009-05-08 16:50:17 -07001023
1024/*
1025 * Helpers for dvmThrowVerificationError().
1026 *
1027 * Each returns a newly-allocated string.
1028 */
1029#define kThrowShow_accessFromClass 1
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001030static char* classNameFromIndex(const Method* method, int ref,
1031 VerifyErrorRefType refType, int flags)
Andy McFaddenb51ea112009-05-08 16:50:17 -07001032{
1033 static const int kBufLen = 256;
1034 const DvmDex* pDvmDex = method->clazz->pDvmDex;
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001035
1036 if (refType == VERIFY_ERROR_REF_FIELD) {
1037 /* get class ID from field ID */
1038 const DexFieldId* pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
1039 ref = pFieldId->classIdx;
1040 } else if (refType == VERIFY_ERROR_REF_METHOD) {
1041 /* get class ID from method ID */
1042 const DexMethodId* pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
1043 ref = pMethodId->classIdx;
1044 }
1045
Andy McFaddenb51ea112009-05-08 16:50:17 -07001046 const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref);
1047 char* dotClassName = dvmDescriptorToDot(className);
1048 if (flags == 0)
1049 return dotClassName;
1050
1051 char* result = (char*) malloc(kBufLen);
1052
1053 if ((flags & kThrowShow_accessFromClass) != 0) {
1054 char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
1055 snprintf(result, kBufLen, "tried to access class %s from class %s",
1056 dotClassName, dotFromName);
1057 free(dotFromName);
1058 } else {
1059 assert(false); // should've been caught above
1060 result[0] = '\0';
1061 }
1062
1063 free(dotClassName);
1064 return result;
1065}
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001066static char* fieldNameFromIndex(const Method* method, int ref,
1067 VerifyErrorRefType refType, int flags)
Andy McFaddenb51ea112009-05-08 16:50:17 -07001068{
1069 static const int kBufLen = 256;
1070 const DvmDex* pDvmDex = method->clazz->pDvmDex;
1071 const DexFieldId* pFieldId;
1072 const char* className;
1073 const char* fieldName;
1074
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001075 if (refType != VERIFY_ERROR_REF_FIELD) {
1076 LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_FIELD, refType);
1077 return NULL; /* no message */
1078 }
1079
Andy McFaddenb51ea112009-05-08 16:50:17 -07001080 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
1081 className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx);
1082 fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
1083
1084 char* dotName = dvmDescriptorToDot(className);
1085 char* result = (char*) malloc(kBufLen);
1086
1087 if ((flags & kThrowShow_accessFromClass) != 0) {
1088 char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
1089 snprintf(result, kBufLen, "tried to access field %s.%s from class %s",
1090 dotName, fieldName, dotFromName);
1091 free(dotFromName);
1092 } else {
1093 snprintf(result, kBufLen, "%s.%s", dotName, fieldName);
1094 }
1095
1096 free(dotName);
1097 return result;
1098}
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001099static char* methodNameFromIndex(const Method* method, int ref,
1100 VerifyErrorRefType refType, int flags)
Andy McFaddenb51ea112009-05-08 16:50:17 -07001101{
1102 static const int kBufLen = 384;
1103 const DvmDex* pDvmDex = method->clazz->pDvmDex;
1104 const DexMethodId* pMethodId;
1105 const char* className;
1106 const char* methodName;
1107
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001108 if (refType != VERIFY_ERROR_REF_METHOD) {
1109 LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_METHOD,refType);
1110 return NULL; /* no message */
1111 }
1112
Andy McFaddenb51ea112009-05-08 16:50:17 -07001113 pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
1114 className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx);
1115 methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
1116
1117 char* dotName = dvmDescriptorToDot(className);
1118 char* result = (char*) malloc(kBufLen);
1119
1120 if ((flags & kThrowShow_accessFromClass) != 0) {
1121 char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
1122 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
1123 snprintf(result, kBufLen,
1124 "tried to access method %s.%s:%s from class %s",
1125 dotName, methodName, desc, dotFromName);
1126 free(dotFromName);
1127 free(desc);
1128 } else {
1129 snprintf(result, kBufLen, "%s.%s", dotName, methodName);
1130 }
1131
1132 free(dotName);
1133 return result;
1134}
1135
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001136/*
Andy McFadden3a1aedb2009-05-07 13:30:23 -07001137 * Throw an exception for a problem identified by the verifier.
1138 *
1139 * This is used by the invoke-verification-error instruction. It always
1140 * throws an exception.
1141 *
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001142 * "kind" indicates the kind of failure encountered by the verifier. It
1143 * has two parts, an error code and an indication of the reference type.
Andy McFadden3a1aedb2009-05-07 13:30:23 -07001144 */
Andy McFaddenb51ea112009-05-08 16:50:17 -07001145void dvmThrowVerificationError(const Method* method, int kind, int ref)
Andy McFadden3a1aedb2009-05-07 13:30:23 -07001146{
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001147 const int typeMask = 0xff << kVerifyErrorRefTypeShift;
1148 VerifyError errorKind = kind & ~typeMask;
1149 VerifyErrorRefType refType = kind >> kVerifyErrorRefTypeShift;
Andy McFaddenb51ea112009-05-08 16:50:17 -07001150 const char* exceptionName = "Ljava/lang/VerifyError;";
1151 char* msg = NULL;
1152
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001153 switch ((VerifyError) errorKind) {
Andy McFaddenb51ea112009-05-08 16:50:17 -07001154 case VERIFY_ERROR_NO_CLASS:
1155 exceptionName = "Ljava/lang/NoClassDefFoundError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001156 msg = classNameFromIndex(method, ref, refType, 0);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001157 break;
1158 case VERIFY_ERROR_NO_FIELD:
1159 exceptionName = "Ljava/lang/NoSuchFieldError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001160 msg = fieldNameFromIndex(method, ref, refType, 0);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001161 break;
1162 case VERIFY_ERROR_NO_METHOD:
1163 exceptionName = "Ljava/lang/NoSuchMethodError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001164 msg = methodNameFromIndex(method, ref, refType, 0);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001165 break;
1166 case VERIFY_ERROR_ACCESS_CLASS:
1167 exceptionName = "Ljava/lang/IllegalAccessError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001168 msg = classNameFromIndex(method, ref, refType,
1169 kThrowShow_accessFromClass);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001170 break;
1171 case VERIFY_ERROR_ACCESS_FIELD:
1172 exceptionName = "Ljava/lang/IllegalAccessError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001173 msg = fieldNameFromIndex(method, ref, refType,
1174 kThrowShow_accessFromClass);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001175 break;
1176 case VERIFY_ERROR_ACCESS_METHOD:
1177 exceptionName = "Ljava/lang/IllegalAccessError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001178 msg = methodNameFromIndex(method, ref, refType,
1179 kThrowShow_accessFromClass);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001180 break;
1181 case VERIFY_ERROR_CLASS_CHANGE:
1182 exceptionName = "Ljava/lang/IncompatibleClassChangeError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001183 msg = classNameFromIndex(method, ref, refType, 0);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001184 break;
1185 case VERIFY_ERROR_INSTANTIATION:
1186 exceptionName = "Ljava/lang/InstantiationError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -07001187 msg = classNameFromIndex(method, ref, refType, 0);
Andy McFaddenb51ea112009-05-08 16:50:17 -07001188 break;
1189
1190 case VERIFY_ERROR_GENERIC:
1191 /* generic VerifyError; use default exception, no message */
1192 break;
1193 case VERIFY_ERROR_NONE:
1194 /* should never happen; use default exception */
1195 assert(false);
1196 msg = strdup("weird - no error specified");
1197 break;
1198
1199 /* no default clause -- want warning if enum updated */
1200 }
1201
1202 dvmThrowException(exceptionName, msg);
1203 free(msg);
Andy McFadden3a1aedb2009-05-07 13:30:23 -07001204}
1205
Andy McFadden3a1aedb2009-05-07 13:30:23 -07001206/*
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001207 * Main interpreter loop entry point. Select "standard" or "debug"
1208 * interpreter and switch between them as required.
1209 *
1210 * This begins executing code at the start of "method". On exit, "pResult"
1211 * holds the return value of the method (or, if "method" returns NULL, it
1212 * holds an undefined value).
1213 *
1214 * The interpreted stack frame, which holds the method arguments, has
1215 * already been set up.
1216 */
1217void dvmInterpret(Thread* self, const Method* method, JValue* pResult)
1218{
1219 InterpState interpState;
1220 bool change;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001221#if defined(WITH_JIT)
Bill Buzbee342806d2009-12-08 12:37:13 -08001222 /* Target-specific save/restore */
1223 extern void dvmJitCalleeSave(double *saveArea);
1224 extern void dvmJitCalleeRestore(double *saveArea);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001225 /* Interpreter entry points from compiled code */
1226 extern void dvmJitToInterpNormal();
1227 extern void dvmJitToInterpNoChain();
1228 extern void dvmJitToInterpPunt();
1229 extern void dvmJitToInterpSingleStep();
1230 extern void dvmJitToTraceSelect();
Ben Cheng38329f52009-07-07 14:19:20 -07001231 extern void dvmJitToPatchPredictedChain();
Jeff Hao97319a82009-08-12 16:57:15 -07001232#if defined(WITH_SELF_VERIFICATION)
1233 extern void dvmJitToBackwardBranch();
1234#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001235
Ben Cheng38329f52009-07-07 14:19:20 -07001236 /*
Ben Chengba4fc8b2009-06-01 13:00:29 -07001237 * Reserve a static entity here to quickly setup runtime contents as
1238 * gcc will issue block copy instructions.
1239 */
1240 static struct JitToInterpEntries jitToInterpEntries = {
1241 dvmJitToInterpNormal,
1242 dvmJitToInterpNoChain,
1243 dvmJitToInterpPunt,
1244 dvmJitToInterpSingleStep,
1245 dvmJitToTraceSelect,
Ben Cheng38329f52009-07-07 14:19:20 -07001246 dvmJitToPatchPredictedChain,
Jeff Hao97319a82009-08-12 16:57:15 -07001247#if defined(WITH_SELF_VERIFICATION)
1248 dvmJitToBackwardBranch,
1249#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001250 };
Ben Cheng7a0bcd02010-01-22 16:45:45 -08001251
1252 assert(self->inJitCodeCache == NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001253#endif
1254
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001255
1256#if defined(WITH_TRACKREF_CHECKS)
1257 interpState.debugTrackedRefStart =
1258 dvmReferenceTableEntries(&self->internalLocalRefTable);
1259#endif
1260#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
1261 interpState.debugIsMethodEntry = true;
1262#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001263#if defined(WITH_JIT)
Bill Buzbee342806d2009-12-08 12:37:13 -08001264 dvmJitCalleeSave(interpState.calleeSave);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001265 interpState.jitState = gDvmJit.pJitEntryTable ? kJitNormal : kJitOff;
1266
1267 /* Setup the Jit-to-interpreter entry points */
1268 interpState.jitToInterpEntries = jitToInterpEntries;
Bill Buzbee48f18242009-06-19 16:02:27 -07001269
1270 /*
1271 * Initialize the threshold filter [don't bother to zero out the
1272 * actual table. We're looking for matches, and an occasional
1273 * false positive is acceptible.
1274 */
1275 interpState.lastThreshFilter = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001276#endif
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001277
1278 /*
1279 * Initialize working state.
1280 *
1281 * No need to initialize "retval".
1282 */
1283 interpState.method = method;
1284 interpState.fp = (u4*) self->curFrame;
1285 interpState.pc = method->insns;
1286 interpState.entryPoint = kInterpEntryInstr;
1287
1288 if (dvmDebuggerOrProfilerActive())
1289 interpState.nextMode = INTERP_DBG;
1290 else
1291 interpState.nextMode = INTERP_STD;
1292
1293 assert(!dvmIsNativeMethod(method));
1294
1295 /*
1296 * Make sure the class is ready to go. Shouldn't be possible to get
1297 * here otherwise.
1298 */
1299 if (method->clazz->status < CLASS_INITIALIZING ||
1300 method->clazz->status == CLASS_ERROR)
1301 {
1302 LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)\n",
1303 method->clazz->descriptor, method->clazz->status);
1304 dvmDumpThread(self, false);
1305 dvmAbort();
1306 }
1307
1308 typedef bool (*Interpreter)(Thread*, InterpState*);
1309 Interpreter stdInterp;
1310 if (gDvm.executionMode == kExecutionModeInterpFast)
1311 stdInterp = dvmMterpStd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001312#if defined(WITH_JIT)
1313 else if (gDvm.executionMode == kExecutionModeJit)
1314/* If profiling overhead can be kept low enough, we can use a profiling
1315 * mterp fast for both Jit and "fast" modes. If overhead is too high,
1316 * create a specialized profiling interpreter.
1317 */
1318 stdInterp = dvmMterpStd;
1319#endif
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001320 else
1321 stdInterp = dvmInterpretStd;
1322
1323 change = true;
1324 while (change) {
1325 switch (interpState.nextMode) {
1326 case INTERP_STD:
1327 LOGVV("threadid=%d: interp STD\n", self->threadId);
1328 change = (*stdInterp)(self, &interpState);
1329 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001330#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) || defined(WITH_JIT)
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001331 case INTERP_DBG:
1332 LOGVV("threadid=%d: interp DBG\n", self->threadId);
1333 change = dvmInterpretDbg(self, &interpState);
1334 break;
1335#endif
1336 default:
1337 dvmAbort();
1338 }
1339 }
1340
1341 *pResult = interpState.retval;
Bill Buzbee342806d2009-12-08 12:37:13 -08001342#if defined(WITH_JIT)
1343 dvmJitCalleeRestore(interpState.calleeSave);
1344#endif
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001345}