blob: 807afad6a476bf5f51847f97b6aa1496f7dbc710 [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 {
Andy McFaddend22748a2010-04-22 17:08:11 -070074 Method* method; /* method we're associated with */
Andy McFadden96516932009-10-28 17:39:02 -070075 u2* addr; /* absolute memory address */
76 u1 originalOpCode; /* original 8-bit opcode value */
77 int setCount; /* #of times this breakpoint was set */
78} Breakpoint;
79
80/*
81 * Set of breakpoints.
82 */
83struct BreakpointSet {
84 /* grab lock before reading or writing anything else in here */
85 pthread_mutex_t lock;
86
87 /* vector of breakpoint structures */
88 int alloc;
89 int count;
90 Breakpoint* breakpoints;
91};
92
93/*
94 * Initialize a BreakpointSet. Initially empty.
95 */
96static BreakpointSet* dvmBreakpointSetAlloc(void)
97{
98 BreakpointSet* pSet = (BreakpointSet*) calloc(1, sizeof(*pSet));
99
100 dvmInitMutex(&pSet->lock);
101 /* leave the rest zeroed -- will alloc on first use */
102
103 return pSet;
104}
105
106/*
107 * Free storage associated with a BreakpointSet.
108 */
109static void dvmBreakpointSetFree(BreakpointSet* pSet)
110{
111 if (pSet == NULL)
112 return;
113
114 free(pSet->breakpoints);
115 free(pSet);
116}
117
118/*
119 * Lock the breakpoint set.
Andy McFaddend22748a2010-04-22 17:08:11 -0700120 *
121 * It's not currently necessary to switch to VMWAIT in the event of
122 * contention, because nothing in here can block. However, it's possible
123 * that the bytecode-updater code could become fancier in the future, so
124 * we do the trylock dance as a bit of future-proofing.
Andy McFadden96516932009-10-28 17:39:02 -0700125 */
126static void dvmBreakpointSetLock(BreakpointSet* pSet)
127{
Andy McFaddend22748a2010-04-22 17:08:11 -0700128 if (dvmTryLockMutex(&pSet->lock) != 0) {
129 Thread* self = dvmThreadSelf();
130 int oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
131 dvmLockMutex(&pSet->lock);
132 dvmChangeStatus(self, oldStatus);
133 }
Andy McFadden96516932009-10-28 17:39:02 -0700134}
135
136/*
137 * Unlock the breakpoint set.
138 */
139static void dvmBreakpointSetUnlock(BreakpointSet* pSet)
140{
141 dvmUnlockMutex(&pSet->lock);
142}
143
144/*
145 * Return the #of breakpoints.
146 */
147static int dvmBreakpointSetCount(const BreakpointSet* pSet)
148{
149 return pSet->count;
150}
151
152/*
153 * See if we already have an entry for this address.
154 *
155 * The BreakpointSet's lock must be acquired before calling here.
156 *
157 * Returns the index of the breakpoint entry, or -1 if not found.
158 */
159static int dvmBreakpointSetFind(const BreakpointSet* pSet, const u2* addr)
160{
161 int i;
162
163 for (i = 0; i < pSet->count; i++) {
164 Breakpoint* pBreak = &pSet->breakpoints[i];
165 if (pBreak->addr == addr)
166 return i;
167 }
168
169 return -1;
170}
171
172/*
173 * Retrieve the opcode that was originally at the specified location.
174 *
175 * The BreakpointSet's lock must be acquired before calling here.
176 *
177 * Returns "true" with the opcode in *pOrig on success.
178 */
179static bool dvmBreakpointSetOriginalOpCode(const BreakpointSet* pSet,
180 const u2* addr, u1* pOrig)
181{
182 int idx = dvmBreakpointSetFind(pSet, addr);
183 if (idx < 0)
184 return false;
185
186 *pOrig = pSet->breakpoints[idx].originalOpCode;
187 return true;
188}
189
190/*
191 * Add a breakpoint at a specific address. If the address is already
192 * present in the table, this just increments the count.
193 *
194 * For a new entry, this will extract and preserve the current opcode from
195 * the instruction stream, and replace it with a breakpoint opcode.
196 *
197 * The BreakpointSet's lock must be acquired before calling here.
198 *
199 * Returns "true" on success.
200 */
201static bool dvmBreakpointSetAdd(BreakpointSet* pSet, Method* method,
202 unsigned int instrOffset)
203{
204 const int kBreakpointGrowth = 10;
205 const u2* addr = method->insns + instrOffset;
206 int idx = dvmBreakpointSetFind(pSet, addr);
207 Breakpoint* pBreak;
208
209 if (idx < 0) {
210 if (pSet->count == pSet->alloc) {
211 int newSize = pSet->alloc + kBreakpointGrowth;
212 Breakpoint* newVec;
213
214 LOGV("+++ increasing breakpoint set size to %d\n", newSize);
215
216 /* pSet->breakpoints will be NULL on first entry */
217 newVec = realloc(pSet->breakpoints, newSize * sizeof(Breakpoint));
218 if (newVec == NULL)
219 return false;
220
221 pSet->breakpoints = newVec;
222 pSet->alloc = newSize;
223 }
224
225 pBreak = &pSet->breakpoints[pSet->count++];
Andy McFaddend22748a2010-04-22 17:08:11 -0700226 pBreak->method = method;
Andy McFadden96516932009-10-28 17:39:02 -0700227 pBreak->addr = (u2*)addr;
228 pBreak->originalOpCode = *(u1*)addr;
229 pBreak->setCount = 1;
230
231 /*
232 * Change the opcode. We must ensure that the BreakpointSet
233 * updates happen before we change the opcode.
Andy McFaddend22748a2010-04-22 17:08:11 -0700234 *
235 * If the method has not been verified, we do NOT insert the
236 * breakpoint yet, since that will screw up the verifier. The
237 * debugger is allowed to insert breakpoints in unverified code,
238 * but since we don't execute unverified code we don't need to
239 * alter the bytecode yet.
240 *
241 * The class init code will "flush" all relevant breakpoints when
242 * verification completes.
Andy McFadden96516932009-10-28 17:39:02 -0700243 */
244 MEM_BARRIER();
245 assert(*(u1*)addr != OP_BREAKPOINT);
Andy McFaddend22748a2010-04-22 17:08:11 -0700246 if (dvmIsClassVerified(method->clazz)) {
247 LOGV("Class %s verified, adding breakpoint at %p\n",
248 method->clazz->descriptor, addr);
249 dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr, OP_BREAKPOINT);
250 } else {
251 LOGV("Class %s NOT verified, deferring breakpoint at %p\n",
252 method->clazz->descriptor, addr);
253 }
Andy McFadden96516932009-10-28 17:39:02 -0700254 } else {
255 pBreak = &pSet->breakpoints[idx];
256 pBreak->setCount++;
257
Andy McFaddend22748a2010-04-22 17:08:11 -0700258 /*
259 * Instruction stream may not have breakpoint opcode yet -- flush
260 * may be pending during verification of class.
261 */
262 //assert(*(u1*)addr == OP_BREAKPOINT);
Andy McFadden96516932009-10-28 17:39:02 -0700263 }
264
265 return true;
266}
267
268/*
269 * Remove one instance of the specified breakpoint. When the count
270 * reaches zero, the entry is removed from the table, and the original
271 * opcode is restored.
272 *
273 * The BreakpointSet's lock must be acquired before calling here.
274 */
275static void dvmBreakpointSetRemove(BreakpointSet* pSet, Method* method,
276 unsigned int instrOffset)
277{
278 const u2* addr = method->insns + instrOffset;
279 int idx = dvmBreakpointSetFind(pSet, addr);
280
281 if (idx < 0) {
282 /* breakpoint not found in set -- unexpected */
283 if (*(u1*)addr == OP_BREAKPOINT) {
284 LOGE("Unable to restore breakpoint opcode (%s.%s +%u)\n",
285 method->clazz->descriptor, method->name, instrOffset);
286 dvmAbort();
287 } else {
288 LOGW("Breakpoint was already restored? (%s.%s +%u)\n",
289 method->clazz->descriptor, method->name, instrOffset);
290 }
291 } else {
292 Breakpoint* pBreak = &pSet->breakpoints[idx];
293 if (pBreak->setCount == 1) {
294 /*
295 * Must restore opcode before removing set entry.
Andy McFaddend22748a2010-04-22 17:08:11 -0700296 *
297 * If the breakpoint was never flushed, we could be ovewriting
298 * a value with the same value. Not a problem, though we
299 * could end up causing a copy-on-write here when we didn't
300 * need to. (Not worth worrying about.)
Andy McFadden96516932009-10-28 17:39:02 -0700301 */
302 dvmDexChangeDex1(method->clazz->pDvmDex, (u1*)addr,
303 pBreak->originalOpCode);
304 MEM_BARRIER();
305
306 if (idx != pSet->count-1) {
307 /* shift down */
308 memmove(&pSet->breakpoints[idx], &pSet->breakpoints[idx+1],
309 (pSet->count-1 - idx) * sizeof(pSet->breakpoints[0]));
310 }
311 pSet->count--;
312 pSet->breakpoints[pSet->count].addr = (u2*) 0xdecadead; // debug
313 } else {
314 pBreak->setCount--;
315 assert(pBreak->setCount > 0);
316 }
317 }
318}
319
320/*
Andy McFaddend22748a2010-04-22 17:08:11 -0700321 * Flush any breakpoints associated with methods in "clazz". We want to
322 * change the opcode, which might not have happened when the breakpoint
323 * was initially set because the class was in the process of being
324 * verified.
Andy McFadden96516932009-10-28 17:39:02 -0700325 *
326 * The BreakpointSet's lock must be acquired before calling here.
327 */
Andy McFaddend22748a2010-04-22 17:08:11 -0700328static void dvmBreakpointSetFlush(BreakpointSet* pSet, ClassObject* clazz)
Andy McFadden96516932009-10-28 17:39:02 -0700329{
Andy McFadden96516932009-10-28 17:39:02 -0700330 int i;
331 for (i = 0; i < pSet->count; i++) {
332 Breakpoint* pBreak = &pSet->breakpoints[i];
Andy McFaddend22748a2010-04-22 17:08:11 -0700333 if (pBreak->method->clazz == clazz) {
334 /*
335 * The breakpoint is associated with a method in this class.
336 * It might already be there or it might not; either way,
337 * flush it out.
338 */
339 LOGV("Flushing breakpoint at %p for %s\n",
340 pBreak->addr, clazz->descriptor);
341 dvmDexChangeDex1(clazz->pDvmDex, (u1*)pBreak->addr, OP_BREAKPOINT);
Andy McFadden96516932009-10-28 17:39:02 -0700342 }
343 }
344}
Andy McFadden96516932009-10-28 17:39:02 -0700345#endif /*WITH_DEBUGGER*/
346
347
348/*
349 * Do any debugger-attach-time initialization.
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700350 */
351void dvmInitBreakpoints(void)
352{
353#ifdef WITH_DEBUGGER
Andy McFadden96516932009-10-28 17:39:02 -0700354 /* quick sanity check */
355 BreakpointSet* pSet = gDvm.breakpointSet;
356 dvmBreakpointSetLock(pSet);
357 if (dvmBreakpointSetCount(pSet) != 0) {
358 LOGW("WARNING: %d leftover breakpoints\n", dvmBreakpointSetCount(pSet));
359 /* generally not good, but we can keep going */
360 }
361 dvmBreakpointSetUnlock(pSet);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700362#else
363 assert(false);
364#endif
365}
366
367/*
368 * Add an address to the list, putting it in the first non-empty slot.
369 *
370 * Sometimes the debugger likes to add two entries for one breakpoint.
371 * We add two entries here, so that we get the right behavior when it's
372 * removed twice.
373 *
374 * This will only be run from the JDWP thread, and it will happen while
375 * we are updating the event list, which is synchronized. We're guaranteed
376 * to be the only one adding entries, and the lock ensures that nobody
377 * will be trying to remove them while we're in here.
378 *
379 * "addr" is the absolute address of the breakpoint bytecode.
380 */
Andy McFadden96516932009-10-28 17:39:02 -0700381void dvmAddBreakAddr(Method* method, unsigned int instrOffset)
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700382{
383#ifdef WITH_DEBUGGER
Andy McFadden96516932009-10-28 17:39:02 -0700384 BreakpointSet* pSet = gDvm.breakpointSet;
385 dvmBreakpointSetLock(pSet);
386 dvmBreakpointSetAdd(pSet, method, instrOffset);
387 dvmBreakpointSetUnlock(pSet);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700388#else
389 assert(false);
390#endif
391}
392
393/*
394 * Remove an address from the list by setting the entry to NULL.
395 *
396 * This can be called from the JDWP thread (because the debugger has
397 * cancelled the breakpoint) or from an event thread (because it's a
398 * single-shot breakpoint, e.g. "run to line"). We only get here as
399 * the result of removing an entry from the event list, which is
400 * synchronized, so it should not be possible for two threads to be
401 * updating breakpoints at the same time.
402 */
Andy McFadden96516932009-10-28 17:39:02 -0700403void dvmClearBreakAddr(Method* method, unsigned int instrOffset)
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700404{
405#ifdef WITH_DEBUGGER
Andy McFadden96516932009-10-28 17:39:02 -0700406 BreakpointSet* pSet = gDvm.breakpointSet;
407 dvmBreakpointSetLock(pSet);
408 dvmBreakpointSetRemove(pSet, method, instrOffset);
409 dvmBreakpointSetUnlock(pSet);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700410
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700411#else
412 assert(false);
413#endif
414}
415
Andy McFadden96516932009-10-28 17:39:02 -0700416#ifdef WITH_DEBUGGER
417/*
418 * Get the original opcode from under a breakpoint.
419 */
420u1 dvmGetOriginalOpCode(const u2* addr)
421{
422 BreakpointSet* pSet = gDvm.breakpointSet;
423 u1 orig = 0;
424
425 dvmBreakpointSetLock(pSet);
426 if (!dvmBreakpointSetOriginalOpCode(pSet, addr, &orig)) {
427 orig = *(u1*)addr;
428 if (orig == OP_BREAKPOINT) {
429 LOGE("GLITCH: can't find breakpoint, opcode is still set\n");
430 dvmAbort();
431 }
432 }
433 dvmBreakpointSetUnlock(pSet);
434
435 return orig;
436}
437
438/*
Andy McFaddend22748a2010-04-22 17:08:11 -0700439 * Flush any breakpoints associated with methods in "clazz".
Andy McFadden96516932009-10-28 17:39:02 -0700440 *
Andy McFaddend22748a2010-04-22 17:08:11 -0700441 * We don't want to modify the bytecode of a method before the verifier
442 * gets a chance to look at it, so we postpone opcode replacement until
443 * after verification completes.
Andy McFadden96516932009-10-28 17:39:02 -0700444 */
Andy McFaddend22748a2010-04-22 17:08:11 -0700445void dvmFlushBreakpoints(ClassObject* clazz)
Andy McFadden96516932009-10-28 17:39:02 -0700446{
447 BreakpointSet* pSet = gDvm.breakpointSet;
448
Andy McFaddend22748a2010-04-22 17:08:11 -0700449 if (pSet == NULL)
450 return;
451
452 assert(dvmIsClassVerified(clazz));
Andy McFadden96516932009-10-28 17:39:02 -0700453 dvmBreakpointSetLock(pSet);
Andy McFaddend22748a2010-04-22 17:08:11 -0700454 dvmBreakpointSetFlush(pSet, clazz);
Andy McFadden96516932009-10-28 17:39:02 -0700455 dvmBreakpointSetUnlock(pSet);
456}
457#endif
458
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700459/*
460 * Add a single step event. Currently this is a global item.
461 *
462 * We set up some initial values based on the thread's current state. This
463 * won't work well if the thread is running, so it's up to the caller to
464 * verify that it's suspended.
465 *
466 * This is only called from the JDWP thread.
467 */
468bool dvmAddSingleStep(Thread* thread, int size, int depth)
469{
470#ifdef WITH_DEBUGGER
471 StepControl* pCtrl = &gDvm.stepControl;
472
473 if (pCtrl->active && thread != pCtrl->thread) {
474 LOGW("WARNING: single-step active for %p; adding %p\n",
475 pCtrl->thread, thread);
476
477 /*
478 * Keep going, overwriting previous. This can happen if you
479 * suspend a thread in Object.wait, hit the single-step key, then
480 * switch to another thread and do the same thing again.
481 * The first thread's step is still pending.
482 *
483 * TODO: consider making single-step per-thread. Adds to the
484 * overhead, but could be useful in rare situations.
485 */
486 }
487
488 pCtrl->size = size;
489 pCtrl->depth = depth;
490 pCtrl->thread = thread;
491
492 /*
493 * We may be stepping into or over method calls, or running until we
494 * return from the current method. To make this work we need to track
495 * the current line, current method, and current stack depth. We need
496 * to be checking these after most instructions, notably those that
497 * call methods, return from methods, or are on a different line from the
498 * previous instruction.
499 *
500 * We have to start with a snapshot of the current state. If we're in
501 * an interpreted method, everything we need is in the current frame. If
502 * we're in a native method, possibly with some extra JNI frames pushed
503 * on by PushLocalFrame, we want to use the topmost native method.
504 */
505 const StackSaveArea* saveArea;
506 void* fp;
507 void* prevFp = NULL;
Ben Cheng38329f52009-07-07 14:19:20 -0700508
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700509 for (fp = thread->curFrame; fp != NULL; fp = saveArea->prevFrame) {
510 const Method* method;
511
512 saveArea = SAVEAREA_FROM_FP(fp);
513 method = saveArea->method;
514
515 if (!dvmIsBreakFrame(fp) && !dvmIsNativeMethod(method))
516 break;
517 prevFp = fp;
518 }
519 if (fp == NULL) {
520 LOGW("Unexpected: step req in native-only threadid=%d\n",
521 thread->threadId);
522 return false;
523 }
524 if (prevFp != NULL) {
525 /*
526 * First interpreted frame wasn't the one at the bottom. Break
527 * frames are only inserted when calling from native->interp, so we
528 * don't need to worry about one being here.
529 */
530 LOGV("##### init step while in native method\n");
531 fp = prevFp;
532 assert(!dvmIsBreakFrame(fp));
533 assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method));
534 saveArea = SAVEAREA_FROM_FP(fp);
535 }
536
537 /*
538 * Pull the goodies out. "xtra.currentPc" should be accurate since
539 * we update it on every instruction while the debugger is connected.
540 */
541 pCtrl->method = saveArea->method;
542 // Clear out any old address set
543 if (pCtrl->pAddressSet != NULL) {
544 // (discard const)
545 free((void *)pCtrl->pAddressSet);
546 pCtrl->pAddressSet = NULL;
547 }
548 if (dvmIsNativeMethod(pCtrl->method)) {
549 pCtrl->line = -1;
550 } else {
551 pCtrl->line = dvmLineNumFromPC(saveArea->method,
552 saveArea->xtra.currentPc - saveArea->method->insns);
Ben Cheng38329f52009-07-07 14:19:20 -0700553 pCtrl->pAddressSet
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700554 = dvmAddressSetForLine(saveArea->method, pCtrl->line);
555 }
556 pCtrl->frameDepth = dvmComputeVagueFrameDepth(thread, thread->curFrame);
557 pCtrl->active = true;
558
559 LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s\n",
560 pCtrl->thread, pCtrl->method, pCtrl->method->name,
561 pCtrl->line, pCtrl->frameDepth,
562 dvmJdwpStepDepthStr(pCtrl->depth),
563 dvmJdwpStepSizeStr(pCtrl->size));
564
565 return true;
566#else
567 assert(false);
568 return false;
569#endif
570}
571
572/*
573 * Disable a single step event.
574 */
575void dvmClearSingleStep(Thread* thread)
576{
577#ifdef WITH_DEBUGGER
578 UNUSED_PARAMETER(thread);
579
580 gDvm.stepControl.active = false;
581#else
582 assert(false);
583#endif
584}
585
586
587/*
588 * Recover the "this" pointer from the current interpreted method. "this"
589 * is always in "in0" for non-static methods.
590 *
591 * The "ins" start at (#of registers - #of ins). Note in0 != v0.
592 *
593 * This works because "dx" guarantees that it will work. It's probably
594 * fairly common to have a virtual method that doesn't use its "this"
595 * pointer, in which case we're potentially wasting a register. However,
596 * the debugger doesn't treat "this" as just another argument. For
597 * example, events (such as breakpoints) can be enabled for specific
598 * values of "this". There is also a separate StackFrame.ThisObject call
599 * in JDWP that is expected to work for any non-native non-static method.
600 *
601 * Because we need it when setting up debugger event filters, we want to
602 * be able to do this quickly.
603 */
604Object* dvmGetThisPtr(const Method* method, const u4* fp)
605{
606 if (dvmIsStaticMethod(method))
607 return NULL;
608 return (Object*)fp[method->registersSize - method->insSize];
609}
610
611
612#if defined(WITH_TRACKREF_CHECKS)
613/*
614 * Verify that all internally-tracked references have been released. If
615 * they haven't, print them and abort the VM.
616 *
617 * "debugTrackedRefStart" indicates how many refs were on the list when
618 * we were first invoked.
619 */
620void dvmInterpCheckTrackedRefs(Thread* self, const Method* method,
621 int debugTrackedRefStart)
622{
623 if (dvmReferenceTableEntries(&self->internalLocalRefTable)
624 != (size_t) debugTrackedRefStart)
625 {
626 char* desc;
627 Object** top;
628 int count;
629
630 count = dvmReferenceTableEntries(&self->internalLocalRefTable);
631
632 LOGE("TRACK: unreleased internal reference (prev=%d total=%d)\n",
633 debugTrackedRefStart, count);
634 desc = dexProtoCopyMethodDescriptor(&method->prototype);
635 LOGE(" current method is %s.%s %s\n", method->clazz->descriptor,
636 method->name, desc);
637 free(desc);
638 top = self->internalLocalRefTable.table + debugTrackedRefStart;
639 while (top < self->internalLocalRefTable.nextEntry) {
640 LOGE(" %p (%s)\n",
641 *top,
642 ((*top)->clazz != NULL) ? (*top)->clazz->descriptor : "");
643 top++;
644 }
645 dvmDumpThread(self, false);
646
647 dvmAbort();
648 }
649 //LOGI("TRACK OK\n");
650}
651#endif
652
653
654#ifdef LOG_INSTR
655/*
656 * Dump the v-registers. Sent to the ILOG log tag.
657 */
658void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly)
659{
660 int i, localCount;
661
662 localCount = method->registersSize - method->insSize;
663
664 LOG(LOG_VERBOSE, LOG_TAG"i", "Registers (fp=%p):\n", framePtr);
665 for (i = method->registersSize-1; i >= 0; i--) {
666 if (i >= localCount) {
667 LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d in%-2d : 0x%08x\n",
668 i, i-localCount, framePtr[i]);
669 } else {
670 if (inOnly) {
671 LOG(LOG_VERBOSE, LOG_TAG"i", " [...]\n");
672 break;
673 }
674 const char* name = "";
675 int j;
676#if 0 // "locals" structure has changed -- need to rewrite this
677 DexFile* pDexFile = method->clazz->pDexFile;
678 const DexCode* pDexCode = dvmGetMethodCode(method);
679 int localsSize = dexGetLocalsSize(pDexFile, pDexCode);
680 const DexLocal* locals = dvmDexGetLocals(pDexFile, pDexCode);
681 for (j = 0; j < localsSize, j++) {
682 if (locals[j].registerNum == (u4) i) {
683 name = dvmDexStringStr(locals[j].pName);
684 break;
685 }
686 }
687#endif
688 LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d : 0x%08x %s\n",
689 i, framePtr[i], name);
690 }
691 }
692}
693#endif
694
695
696/*
697 * ===========================================================================
698 * Entry point and general support functions
699 * ===========================================================================
700 */
701
Ben Cheng38329f52009-07-07 14:19:20 -0700702/*
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700703 * Construct an s4 from two consecutive half-words of switch data.
704 * This needs to check endianness because the DEX optimizer only swaps
705 * half-words in instruction stream.
706 *
707 * "switchData" must be 32-bit aligned.
708 */
709#if __BYTE_ORDER == __LITTLE_ENDIAN
710static inline s4 s4FromSwitchData(const void* switchData) {
711 return *(s4*) switchData;
712}
713#else
714static inline s4 s4FromSwitchData(const void* switchData) {
715 u2* data = switchData;
716 return data[0] | (((s4) data[1]) << 16);
Jay Freeman (saurik)ffa5c292008-11-16 13:51:51 +0000717}
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700718#endif
719
720/*
721 * Find the matching case. Returns the offset to the handler instructions.
722 *
723 * Returns 3 if we don't find a match (it's the size of the packed-switch
724 * instruction).
725 */
726s4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal)
727{
728 const int kInstrLen = 3;
729 u2 size;
730 s4 firstKey;
731 const s4* entries;
732
733 /*
734 * Packed switch data format:
735 * ushort ident = 0x0100 magic value
736 * ushort size number of entries in the table
737 * int first_key first (and lowest) switch case value
738 * int targets[size] branch targets, relative to switch opcode
739 *
740 * Total size is (4+size*2) 16-bit code units.
741 */
742 if (*switchData++ != kPackedSwitchSignature) {
743 /* should have been caught by verifier */
744 dvmThrowException("Ljava/lang/InternalError;",
745 "bad packed switch magic");
746 return kInstrLen;
747 }
748
749 size = *switchData++;
750 assert(size > 0);
751
752 firstKey = *switchData++;
753 firstKey |= (*switchData++) << 16;
754
755 if (testVal < firstKey || testVal >= firstKey + size) {
756 LOGVV("Value %d not found in switch (%d-%d)\n",
757 testVal, firstKey, firstKey+size-1);
758 return kInstrLen;
759 }
760
761 /* The entries are guaranteed to be aligned on a 32-bit boundary;
762 * we can treat them as a native int array.
763 */
764 entries = (const s4*) switchData;
765 assert(((u4)entries & 0x3) == 0);
766
767 assert(testVal - firstKey >= 0 && testVal - firstKey < size);
768 LOGVV("Value %d found in slot %d (goto 0x%02x)\n",
769 testVal, testVal - firstKey,
770 s4FromSwitchData(&entries[testVal - firstKey]));
771 return s4FromSwitchData(&entries[testVal - firstKey]);
772}
773
774/*
775 * Find the matching case. Returns the offset to the handler instructions.
776 *
777 * Returns 3 if we don't find a match (it's the size of the sparse-switch
778 * instruction).
779 */
780s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal)
781{
782 const int kInstrLen = 3;
783 u2 ident, size;
784 const s4* keys;
785 const s4* entries;
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700786
787 /*
788 * Sparse switch data format:
789 * ushort ident = 0x0200 magic value
790 * ushort size number of entries in the table; > 0
791 * int keys[size] keys, sorted low-to-high; 32-bit aligned
792 * int targets[size] branch targets, relative to switch opcode
793 *
794 * Total size is (2+size*4) 16-bit code units.
795 */
796
797 if (*switchData++ != kSparseSwitchSignature) {
798 /* should have been caught by verifier */
799 dvmThrowException("Ljava/lang/InternalError;",
800 "bad sparse switch magic");
801 return kInstrLen;
802 }
803
804 size = *switchData++;
805 assert(size > 0);
Ben Cheng38329f52009-07-07 14:19:20 -0700806
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700807 /* The keys are guaranteed to be aligned on a 32-bit boundary;
808 * we can treat them as a native int array.
809 */
810 keys = (const s4*) switchData;
811 assert(((u4)keys & 0x3) == 0);
812
813 /* The entries are guaranteed to be aligned on a 32-bit boundary;
814 * we can treat them as a native int array.
815 */
816 entries = keys + size;
817 assert(((u4)entries & 0x3) == 0);
818
819 /*
Andy McFadden62f19152009-10-21 16:59:31 -0700820 * Binary-search through the array of keys, which are guaranteed to
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700821 * be sorted low-to-high.
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700822 */
Andy McFadden62f19152009-10-21 16:59:31 -0700823 int lo = 0;
824 int hi = size - 1;
825 while (lo <= hi) {
826 int mid = (lo + hi) >> 1;
827
828 s4 foundVal = s4FromSwitchData(&keys[mid]);
829 if (testVal < foundVal) {
830 hi = mid - 1;
831 } else if (testVal > foundVal) {
832 lo = mid + 1;
833 } else {
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700834 LOGVV("Value %d found in entry %d (goto 0x%02x)\n",
Andy McFadden62f19152009-10-21 16:59:31 -0700835 testVal, mid, s4FromSwitchData(&entries[mid]));
836 return s4FromSwitchData(&entries[mid]);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700837 }
838 }
839
840 LOGVV("Value %d not found in switch\n", testVal);
841 return kInstrLen;
842}
843
844/*
Andy McFadden6f214502009-06-30 16:14:30 -0700845 * Copy data for a fill-array-data instruction. On a little-endian machine
846 * we can just do a memcpy(), on a big-endian system we have work to do.
847 *
848 * The trick here is that dexopt has byte-swapped each code unit, which is
849 * exactly what we want for short/char data. For byte data we need to undo
850 * the swap, and for 4- or 8-byte values we need to swap pieces within
851 * each word.
852 */
853static void copySwappedArrayData(void* dest, const u2* src, u4 size, u2 width)
854{
855#if __BYTE_ORDER == __LITTLE_ENDIAN
856 memcpy(dest, src, size*width);
857#else
858 int i;
859
860 switch (width) {
861 case 1:
862 /* un-swap pairs of bytes as we go */
863 for (i = (size-1) & ~1; i >= 0; i -= 2) {
864 ((u1*)dest)[i] = ((u1*)src)[i+1];
865 ((u1*)dest)[i+1] = ((u1*)src)[i];
866 }
867 /*
868 * "src" is padded to end on a two-byte boundary, but we don't want to
869 * assume "dest" is, so we handle odd length specially.
870 */
871 if ((size & 1) != 0) {
872 ((u1*)dest)[size-1] = ((u1*)src)[size];
873 }
874 break;
875 case 2:
876 /* already swapped correctly */
877 memcpy(dest, src, size*width);
878 break;
879 case 4:
880 /* swap word halves */
881 for (i = 0; i < (int) size; i++) {
882 ((u4*)dest)[i] = (src[(i << 1) + 1] << 16) | src[i << 1];
883 }
884 break;
885 case 8:
886 /* swap word halves and words */
887 for (i = 0; i < (int) (size << 1); i += 2) {
888 ((int*)dest)[i] = (src[(i << 1) + 3] << 16) | src[(i << 1) + 2];
889 ((int*)dest)[i+1] = (src[(i << 1) + 1] << 16) | src[i << 1];
890 }
891 break;
892 default:
893 LOGE("Unexpected width %d in copySwappedArrayData\n", width);
894 dvmAbort();
895 break;
896 }
897#endif
898}
899
900/*
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700901 * Fill the array with predefined constant values.
902 *
903 * Returns true if job is completed, otherwise false to indicate that
904 * an exception has been thrown.
905 */
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800906bool dvmInterpHandleFillArrayData(ArrayObject* arrayObj, const u2* arrayData)
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700907{
908 u2 width;
909 u4 size;
910
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800911 if (arrayObj == NULL) {
912 dvmThrowException("Ljava/lang/NullPointerException;", NULL);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700913 return false;
914 }
Barry Hayes7dc96602010-02-24 09:19:07 -0800915 assert (!IS_CLASS_FLAG_SET(((Object *)arrayObj)->clazz,
916 CLASS_ISOBJECTARRAY));
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();
Ben Cheng40094c12010-02-24 20:58:44 -08001230 extern void dvmJitToInterpTraceSelectNoChain();
1231 extern void dvmJitToInterpTraceSelect();
Ben Cheng38329f52009-07-07 14:19:20 -07001232 extern void dvmJitToPatchPredictedChain();
Jeff Hao97319a82009-08-12 16:57:15 -07001233#if defined(WITH_SELF_VERIFICATION)
Ben Cheng40094c12010-02-24 20:58:44 -08001234 extern void dvmJitToInterpBackwardBranch();
Jeff Hao97319a82009-08-12 16:57:15 -07001235#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001236
Ben Cheng38329f52009-07-07 14:19:20 -07001237 /*
Ben Chengba4fc8b2009-06-01 13:00:29 -07001238 * Reserve a static entity here to quickly setup runtime contents as
1239 * gcc will issue block copy instructions.
1240 */
1241 static struct JitToInterpEntries jitToInterpEntries = {
1242 dvmJitToInterpNormal,
1243 dvmJitToInterpNoChain,
1244 dvmJitToInterpPunt,
1245 dvmJitToInterpSingleStep,
Ben Cheng40094c12010-02-24 20:58:44 -08001246 dvmJitToInterpTraceSelectNoChain,
1247 dvmJitToInterpTraceSelect,
Ben Cheng38329f52009-07-07 14:19:20 -07001248 dvmJitToPatchPredictedChain,
Jeff Hao97319a82009-08-12 16:57:15 -07001249#if defined(WITH_SELF_VERIFICATION)
Ben Cheng40094c12010-02-24 20:58:44 -08001250 dvmJitToInterpBackwardBranch,
Jeff Hao97319a82009-08-12 16:57:15 -07001251#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001252 };
Ben Cheng7a0bcd02010-01-22 16:45:45 -08001253
1254 assert(self->inJitCodeCache == NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001255#endif
1256
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001257
1258#if defined(WITH_TRACKREF_CHECKS)
1259 interpState.debugTrackedRefStart =
1260 dvmReferenceTableEntries(&self->internalLocalRefTable);
1261#endif
1262#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
1263 interpState.debugIsMethodEntry = true;
1264#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001265#if defined(WITH_JIT)
Bill Buzbee342806d2009-12-08 12:37:13 -08001266 dvmJitCalleeSave(interpState.calleeSave);
Ben Chenga4973592010-03-31 11:59:18 -07001267 /* Initialize the state to kJitNot */
1268 interpState.jitState = kJitNot;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001269
1270 /* Setup the Jit-to-interpreter entry points */
1271 interpState.jitToInterpEntries = jitToInterpEntries;
Bill Buzbee48f18242009-06-19 16:02:27 -07001272
1273 /*
1274 * Initialize the threshold filter [don't bother to zero out the
1275 * actual table. We're looking for matches, and an occasional
1276 * false positive is acceptible.
1277 */
1278 interpState.lastThreshFilter = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001279#endif
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001280
1281 /*
1282 * Initialize working state.
1283 *
1284 * No need to initialize "retval".
1285 */
1286 interpState.method = method;
1287 interpState.fp = (u4*) self->curFrame;
1288 interpState.pc = method->insns;
1289 interpState.entryPoint = kInterpEntryInstr;
1290
1291 if (dvmDebuggerOrProfilerActive())
1292 interpState.nextMode = INTERP_DBG;
1293 else
1294 interpState.nextMode = INTERP_STD;
1295
1296 assert(!dvmIsNativeMethod(method));
1297
1298 /*
1299 * Make sure the class is ready to go. Shouldn't be possible to get
1300 * here otherwise.
1301 */
1302 if (method->clazz->status < CLASS_INITIALIZING ||
1303 method->clazz->status == CLASS_ERROR)
1304 {
1305 LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)\n",
1306 method->clazz->descriptor, method->clazz->status);
1307 dvmDumpThread(self, false);
1308 dvmAbort();
1309 }
1310
1311 typedef bool (*Interpreter)(Thread*, InterpState*);
1312 Interpreter stdInterp;
1313 if (gDvm.executionMode == kExecutionModeInterpFast)
1314 stdInterp = dvmMterpStd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001315#if defined(WITH_JIT)
1316 else if (gDvm.executionMode == kExecutionModeJit)
1317/* If profiling overhead can be kept low enough, we can use a profiling
1318 * mterp fast for both Jit and "fast" modes. If overhead is too high,
1319 * create a specialized profiling interpreter.
1320 */
1321 stdInterp = dvmMterpStd;
1322#endif
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001323 else
1324 stdInterp = dvmInterpretStd;
1325
1326 change = true;
1327 while (change) {
1328 switch (interpState.nextMode) {
1329 case INTERP_STD:
1330 LOGVV("threadid=%d: interp STD\n", self->threadId);
1331 change = (*stdInterp)(self, &interpState);
1332 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001333#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) || defined(WITH_JIT)
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001334 case INTERP_DBG:
1335 LOGVV("threadid=%d: interp DBG\n", self->threadId);
1336 change = dvmInterpretDbg(self, &interpState);
1337 break;
1338#endif
1339 default:
1340 dvmAbort();
1341 }
1342 }
1343
1344 *pResult = interpState.retval;
Bill Buzbee342806d2009-12-08 12:37:13 -08001345#if defined(WITH_JIT)
1346 dvmJitCalleeRestore(interpState.calleeSave);
1347#endif
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001348}