blob: 658b771eb20634c9aec9484f56e5be6d6b93a8a2 [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
38/*
39 * Initialize the breakpoint address lookup table when the debugger attaches.
40 *
41 * This shouldn't be necessary -- the global area is initially zeroed out,
42 * and the events should be cleaning up after themselves.
43 */
44void dvmInitBreakpoints(void)
45{
46#ifdef WITH_DEBUGGER
47 memset(gDvm.debugBreakAddr, 0, sizeof(gDvm.debugBreakAddr));
48#else
49 assert(false);
50#endif
51}
52
53/*
54 * Add an address to the list, putting it in the first non-empty slot.
55 *
56 * Sometimes the debugger likes to add two entries for one breakpoint.
57 * We add two entries here, so that we get the right behavior when it's
58 * removed twice.
59 *
60 * This will only be run from the JDWP thread, and it will happen while
61 * we are updating the event list, which is synchronized. We're guaranteed
62 * to be the only one adding entries, and the lock ensures that nobody
63 * will be trying to remove them while we're in here.
64 *
65 * "addr" is the absolute address of the breakpoint bytecode.
66 */
67void dvmAddBreakAddr(Method* method, int instrOffset)
68{
69#ifdef WITH_DEBUGGER
70 const u2* addr = method->insns + instrOffset;
71 const u2** ptr = gDvm.debugBreakAddr;
72 int i;
73
74 LOGV("BKP: add %p %s.%s (%s:%d)\n",
75 addr, method->clazz->descriptor, method->name,
76 dvmGetMethodSourceFile(method), dvmLineNumFromPC(method, instrOffset));
77
78 method->debugBreakpointCount++;
79 for (i = 0; i < MAX_BREAKPOINTS; i++, ptr++) {
80 if (*ptr == NULL) {
81 *ptr = addr;
82 break;
83 }
84 }
85 if (i == MAX_BREAKPOINTS) {
86 /* no room; size is too small or we're not cleaning up properly */
87 LOGE("ERROR: max breakpoints exceeded\n");
88 assert(false);
89 }
90#else
91 assert(false);
92#endif
93}
94
95/*
96 * Remove an address from the list by setting the entry to NULL.
97 *
98 * This can be called from the JDWP thread (because the debugger has
99 * cancelled the breakpoint) or from an event thread (because it's a
100 * single-shot breakpoint, e.g. "run to line"). We only get here as
101 * the result of removing an entry from the event list, which is
102 * synchronized, so it should not be possible for two threads to be
103 * updating breakpoints at the same time.
104 */
105void dvmClearBreakAddr(Method* method, int instrOffset)
106{
107#ifdef WITH_DEBUGGER
108 const u2* addr = method->insns + instrOffset;
109 const u2** ptr = gDvm.debugBreakAddr;
110 int i;
111
112 LOGV("BKP: clear %p %s.%s (%s:%d)\n",
113 addr, method->clazz->descriptor, method->name,
114 dvmGetMethodSourceFile(method), dvmLineNumFromPC(method, instrOffset));
115
116 method->debugBreakpointCount--;
117 assert(method->debugBreakpointCount >= 0);
118 for (i = 0; i < MAX_BREAKPOINTS; i++, ptr++) {
119 if (*ptr == addr) {
120 *ptr = NULL;
121 break;
122 }
123 }
124 if (i == MAX_BREAKPOINTS) {
125 /* didn't find it */
126 LOGE("ERROR: breakpoint on %p not found\n", addr);
127 assert(false);
128 }
129#else
130 assert(false);
131#endif
132}
133
134/*
135 * Add a single step event. Currently this is a global item.
136 *
137 * We set up some initial values based on the thread's current state. This
138 * won't work well if the thread is running, so it's up to the caller to
139 * verify that it's suspended.
140 *
141 * This is only called from the JDWP thread.
142 */
143bool dvmAddSingleStep(Thread* thread, int size, int depth)
144{
145#ifdef WITH_DEBUGGER
146 StepControl* pCtrl = &gDvm.stepControl;
147
148 if (pCtrl->active && thread != pCtrl->thread) {
149 LOGW("WARNING: single-step active for %p; adding %p\n",
150 pCtrl->thread, thread);
151
152 /*
153 * Keep going, overwriting previous. This can happen if you
154 * suspend a thread in Object.wait, hit the single-step key, then
155 * switch to another thread and do the same thing again.
156 * The first thread's step is still pending.
157 *
158 * TODO: consider making single-step per-thread. Adds to the
159 * overhead, but could be useful in rare situations.
160 */
161 }
162
163 pCtrl->size = size;
164 pCtrl->depth = depth;
165 pCtrl->thread = thread;
166
167 /*
168 * We may be stepping into or over method calls, or running until we
169 * return from the current method. To make this work we need to track
170 * the current line, current method, and current stack depth. We need
171 * to be checking these after most instructions, notably those that
172 * call methods, return from methods, or are on a different line from the
173 * previous instruction.
174 *
175 * We have to start with a snapshot of the current state. If we're in
176 * an interpreted method, everything we need is in the current frame. If
177 * we're in a native method, possibly with some extra JNI frames pushed
178 * on by PushLocalFrame, we want to use the topmost native method.
179 */
180 const StackSaveArea* saveArea;
181 void* fp;
182 void* prevFp = NULL;
Ben Cheng38329f52009-07-07 14:19:20 -0700183
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700184 for (fp = thread->curFrame; fp != NULL; fp = saveArea->prevFrame) {
185 const Method* method;
186
187 saveArea = SAVEAREA_FROM_FP(fp);
188 method = saveArea->method;
189
190 if (!dvmIsBreakFrame(fp) && !dvmIsNativeMethod(method))
191 break;
192 prevFp = fp;
193 }
194 if (fp == NULL) {
195 LOGW("Unexpected: step req in native-only threadid=%d\n",
196 thread->threadId);
197 return false;
198 }
199 if (prevFp != NULL) {
200 /*
201 * First interpreted frame wasn't the one at the bottom. Break
202 * frames are only inserted when calling from native->interp, so we
203 * don't need to worry about one being here.
204 */
205 LOGV("##### init step while in native method\n");
206 fp = prevFp;
207 assert(!dvmIsBreakFrame(fp));
208 assert(dvmIsNativeMethod(SAVEAREA_FROM_FP(fp)->method));
209 saveArea = SAVEAREA_FROM_FP(fp);
210 }
211
212 /*
213 * Pull the goodies out. "xtra.currentPc" should be accurate since
214 * we update it on every instruction while the debugger is connected.
215 */
216 pCtrl->method = saveArea->method;
217 // Clear out any old address set
218 if (pCtrl->pAddressSet != NULL) {
219 // (discard const)
220 free((void *)pCtrl->pAddressSet);
221 pCtrl->pAddressSet = NULL;
222 }
223 if (dvmIsNativeMethod(pCtrl->method)) {
224 pCtrl->line = -1;
225 } else {
226 pCtrl->line = dvmLineNumFromPC(saveArea->method,
227 saveArea->xtra.currentPc - saveArea->method->insns);
Ben Cheng38329f52009-07-07 14:19:20 -0700228 pCtrl->pAddressSet
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700229 = dvmAddressSetForLine(saveArea->method, pCtrl->line);
230 }
231 pCtrl->frameDepth = dvmComputeVagueFrameDepth(thread, thread->curFrame);
232 pCtrl->active = true;
233
234 LOGV("##### step init: thread=%p meth=%p '%s' line=%d frameDepth=%d depth=%s size=%s\n",
235 pCtrl->thread, pCtrl->method, pCtrl->method->name,
236 pCtrl->line, pCtrl->frameDepth,
237 dvmJdwpStepDepthStr(pCtrl->depth),
238 dvmJdwpStepSizeStr(pCtrl->size));
239
240 return true;
241#else
242 assert(false);
243 return false;
244#endif
245}
246
247/*
248 * Disable a single step event.
249 */
250void dvmClearSingleStep(Thread* thread)
251{
252#ifdef WITH_DEBUGGER
253 UNUSED_PARAMETER(thread);
254
255 gDvm.stepControl.active = false;
256#else
257 assert(false);
258#endif
259}
260
261
262/*
263 * Recover the "this" pointer from the current interpreted method. "this"
264 * is always in "in0" for non-static methods.
265 *
266 * The "ins" start at (#of registers - #of ins). Note in0 != v0.
267 *
268 * This works because "dx" guarantees that it will work. It's probably
269 * fairly common to have a virtual method that doesn't use its "this"
270 * pointer, in which case we're potentially wasting a register. However,
271 * the debugger doesn't treat "this" as just another argument. For
272 * example, events (such as breakpoints) can be enabled for specific
273 * values of "this". There is also a separate StackFrame.ThisObject call
274 * in JDWP that is expected to work for any non-native non-static method.
275 *
276 * Because we need it when setting up debugger event filters, we want to
277 * be able to do this quickly.
278 */
279Object* dvmGetThisPtr(const Method* method, const u4* fp)
280{
281 if (dvmIsStaticMethod(method))
282 return NULL;
283 return (Object*)fp[method->registersSize - method->insSize];
284}
285
286
287#if defined(WITH_TRACKREF_CHECKS)
288/*
289 * Verify that all internally-tracked references have been released. If
290 * they haven't, print them and abort the VM.
291 *
292 * "debugTrackedRefStart" indicates how many refs were on the list when
293 * we were first invoked.
294 */
295void dvmInterpCheckTrackedRefs(Thread* self, const Method* method,
296 int debugTrackedRefStart)
297{
298 if (dvmReferenceTableEntries(&self->internalLocalRefTable)
299 != (size_t) debugTrackedRefStart)
300 {
301 char* desc;
302 Object** top;
303 int count;
304
305 count = dvmReferenceTableEntries(&self->internalLocalRefTable);
306
307 LOGE("TRACK: unreleased internal reference (prev=%d total=%d)\n",
308 debugTrackedRefStart, count);
309 desc = dexProtoCopyMethodDescriptor(&method->prototype);
310 LOGE(" current method is %s.%s %s\n", method->clazz->descriptor,
311 method->name, desc);
312 free(desc);
313 top = self->internalLocalRefTable.table + debugTrackedRefStart;
314 while (top < self->internalLocalRefTable.nextEntry) {
315 LOGE(" %p (%s)\n",
316 *top,
317 ((*top)->clazz != NULL) ? (*top)->clazz->descriptor : "");
318 top++;
319 }
320 dvmDumpThread(self, false);
321
322 dvmAbort();
323 }
324 //LOGI("TRACK OK\n");
325}
326#endif
327
328
329#ifdef LOG_INSTR
330/*
331 * Dump the v-registers. Sent to the ILOG log tag.
332 */
333void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly)
334{
335 int i, localCount;
336
337 localCount = method->registersSize - method->insSize;
338
339 LOG(LOG_VERBOSE, LOG_TAG"i", "Registers (fp=%p):\n", framePtr);
340 for (i = method->registersSize-1; i >= 0; i--) {
341 if (i >= localCount) {
342 LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d in%-2d : 0x%08x\n",
343 i, i-localCount, framePtr[i]);
344 } else {
345 if (inOnly) {
346 LOG(LOG_VERBOSE, LOG_TAG"i", " [...]\n");
347 break;
348 }
349 const char* name = "";
350 int j;
351#if 0 // "locals" structure has changed -- need to rewrite this
352 DexFile* pDexFile = method->clazz->pDexFile;
353 const DexCode* pDexCode = dvmGetMethodCode(method);
354 int localsSize = dexGetLocalsSize(pDexFile, pDexCode);
355 const DexLocal* locals = dvmDexGetLocals(pDexFile, pDexCode);
356 for (j = 0; j < localsSize, j++) {
357 if (locals[j].registerNum == (u4) i) {
358 name = dvmDexStringStr(locals[j].pName);
359 break;
360 }
361 }
362#endif
363 LOG(LOG_VERBOSE, LOG_TAG"i", " v%-2d : 0x%08x %s\n",
364 i, framePtr[i], name);
365 }
366 }
367}
368#endif
369
370
371/*
372 * ===========================================================================
373 * Entry point and general support functions
374 * ===========================================================================
375 */
376
Ben Cheng38329f52009-07-07 14:19:20 -0700377/*
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700378 * Construct an s4 from two consecutive half-words of switch data.
379 * This needs to check endianness because the DEX optimizer only swaps
380 * half-words in instruction stream.
381 *
382 * "switchData" must be 32-bit aligned.
383 */
384#if __BYTE_ORDER == __LITTLE_ENDIAN
385static inline s4 s4FromSwitchData(const void* switchData) {
386 return *(s4*) switchData;
387}
388#else
389static inline s4 s4FromSwitchData(const void* switchData) {
390 u2* data = switchData;
391 return data[0] | (((s4) data[1]) << 16);
Jay Freeman (saurik)ffa5c292008-11-16 13:51:51 +0000392}
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700393#endif
394
395/*
396 * Find the matching case. Returns the offset to the handler instructions.
397 *
398 * Returns 3 if we don't find a match (it's the size of the packed-switch
399 * instruction).
400 */
401s4 dvmInterpHandlePackedSwitch(const u2* switchData, s4 testVal)
402{
403 const int kInstrLen = 3;
404 u2 size;
405 s4 firstKey;
406 const s4* entries;
407
408 /*
409 * Packed switch data format:
410 * ushort ident = 0x0100 magic value
411 * ushort size number of entries in the table
412 * int first_key first (and lowest) switch case value
413 * int targets[size] branch targets, relative to switch opcode
414 *
415 * Total size is (4+size*2) 16-bit code units.
416 */
417 if (*switchData++ != kPackedSwitchSignature) {
418 /* should have been caught by verifier */
419 dvmThrowException("Ljava/lang/InternalError;",
420 "bad packed switch magic");
421 return kInstrLen;
422 }
423
424 size = *switchData++;
425 assert(size > 0);
426
427 firstKey = *switchData++;
428 firstKey |= (*switchData++) << 16;
429
430 if (testVal < firstKey || testVal >= firstKey + size) {
431 LOGVV("Value %d not found in switch (%d-%d)\n",
432 testVal, firstKey, firstKey+size-1);
433 return kInstrLen;
434 }
435
436 /* The entries are guaranteed to be aligned on a 32-bit boundary;
437 * we can treat them as a native int array.
438 */
439 entries = (const s4*) switchData;
440 assert(((u4)entries & 0x3) == 0);
441
442 assert(testVal - firstKey >= 0 && testVal - firstKey < size);
443 LOGVV("Value %d found in slot %d (goto 0x%02x)\n",
444 testVal, testVal - firstKey,
445 s4FromSwitchData(&entries[testVal - firstKey]));
446 return s4FromSwitchData(&entries[testVal - firstKey]);
447}
448
449/*
450 * Find the matching case. Returns the offset to the handler instructions.
451 *
452 * Returns 3 if we don't find a match (it's the size of the sparse-switch
453 * instruction).
454 */
455s4 dvmInterpHandleSparseSwitch(const u2* switchData, s4 testVal)
456{
457 const int kInstrLen = 3;
458 u2 ident, size;
459 const s4* keys;
460 const s4* entries;
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700461
462 /*
463 * Sparse switch data format:
464 * ushort ident = 0x0200 magic value
465 * ushort size number of entries in the table; > 0
466 * int keys[size] keys, sorted low-to-high; 32-bit aligned
467 * int targets[size] branch targets, relative to switch opcode
468 *
469 * Total size is (2+size*4) 16-bit code units.
470 */
471
472 if (*switchData++ != kSparseSwitchSignature) {
473 /* should have been caught by verifier */
474 dvmThrowException("Ljava/lang/InternalError;",
475 "bad sparse switch magic");
476 return kInstrLen;
477 }
478
479 size = *switchData++;
480 assert(size > 0);
Ben Cheng38329f52009-07-07 14:19:20 -0700481
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700482 /* The keys are guaranteed to be aligned on a 32-bit boundary;
483 * we can treat them as a native int array.
484 */
485 keys = (const s4*) switchData;
486 assert(((u4)keys & 0x3) == 0);
487
488 /* The entries are guaranteed to be aligned on a 32-bit boundary;
489 * we can treat them as a native int array.
490 */
491 entries = keys + size;
492 assert(((u4)entries & 0x3) == 0);
493
494 /*
Andy McFadden62f19152009-10-21 16:59:31 -0700495 * Binary-search through the array of keys, which are guaranteed to
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700496 * be sorted low-to-high.
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700497 */
Andy McFadden62f19152009-10-21 16:59:31 -0700498 int lo = 0;
499 int hi = size - 1;
500 while (lo <= hi) {
501 int mid = (lo + hi) >> 1;
502
503 s4 foundVal = s4FromSwitchData(&keys[mid]);
504 if (testVal < foundVal) {
505 hi = mid - 1;
506 } else if (testVal > foundVal) {
507 lo = mid + 1;
508 } else {
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700509 LOGVV("Value %d found in entry %d (goto 0x%02x)\n",
Andy McFadden62f19152009-10-21 16:59:31 -0700510 testVal, mid, s4FromSwitchData(&entries[mid]));
511 return s4FromSwitchData(&entries[mid]);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700512 }
513 }
514
515 LOGVV("Value %d not found in switch\n", testVal);
516 return kInstrLen;
517}
518
519/*
Andy McFadden6f214502009-06-30 16:14:30 -0700520 * Copy data for a fill-array-data instruction. On a little-endian machine
521 * we can just do a memcpy(), on a big-endian system we have work to do.
522 *
523 * The trick here is that dexopt has byte-swapped each code unit, which is
524 * exactly what we want for short/char data. For byte data we need to undo
525 * the swap, and for 4- or 8-byte values we need to swap pieces within
526 * each word.
527 */
528static void copySwappedArrayData(void* dest, const u2* src, u4 size, u2 width)
529{
530#if __BYTE_ORDER == __LITTLE_ENDIAN
531 memcpy(dest, src, size*width);
532#else
533 int i;
534
535 switch (width) {
536 case 1:
537 /* un-swap pairs of bytes as we go */
538 for (i = (size-1) & ~1; i >= 0; i -= 2) {
539 ((u1*)dest)[i] = ((u1*)src)[i+1];
540 ((u1*)dest)[i+1] = ((u1*)src)[i];
541 }
542 /*
543 * "src" is padded to end on a two-byte boundary, but we don't want to
544 * assume "dest" is, so we handle odd length specially.
545 */
546 if ((size & 1) != 0) {
547 ((u1*)dest)[size-1] = ((u1*)src)[size];
548 }
549 break;
550 case 2:
551 /* already swapped correctly */
552 memcpy(dest, src, size*width);
553 break;
554 case 4:
555 /* swap word halves */
556 for (i = 0; i < (int) size; i++) {
557 ((u4*)dest)[i] = (src[(i << 1) + 1] << 16) | src[i << 1];
558 }
559 break;
560 case 8:
561 /* swap word halves and words */
562 for (i = 0; i < (int) (size << 1); i += 2) {
563 ((int*)dest)[i] = (src[(i << 1) + 3] << 16) | src[(i << 1) + 2];
564 ((int*)dest)[i+1] = (src[(i << 1) + 1] << 16) | src[i << 1];
565 }
566 break;
567 default:
568 LOGE("Unexpected width %d in copySwappedArrayData\n", width);
569 dvmAbort();
570 break;
571 }
572#endif
573}
574
575/*
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700576 * Fill the array with predefined constant values.
577 *
578 * Returns true if job is completed, otherwise false to indicate that
579 * an exception has been thrown.
580 */
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800581bool dvmInterpHandleFillArrayData(ArrayObject* arrayObj, const u2* arrayData)
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700582{
583 u2 width;
584 u4 size;
585
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800586 if (arrayObj == NULL) {
587 dvmThrowException("Ljava/lang/NullPointerException;", NULL);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700588 return false;
589 }
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800590
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700591 /*
592 * Array data table format:
593 * ushort ident = 0x0300 magic value
594 * ushort width width of each element in the table
595 * uint size number of elements in the table
596 * ubyte data[size*width] table of data values (may contain a single-byte
597 * padding at the end)
598 *
599 * Total size is 4+(width * size + 1)/2 16-bit code units.
600 */
601 if (arrayData[0] != kArrayDataSignature) {
602 dvmThrowException("Ljava/lang/InternalError;", "bad array data magic");
603 return false;
604 }
605
606 width = arrayData[1];
607 size = arrayData[2] | (((u4)arrayData[3]) << 16);
608
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800609 if (size > arrayObj->length) {
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700610 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL);
611 return false;
612 }
Andy McFadden6f214502009-06-30 16:14:30 -0700613 copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700614 return true;
615}
616
617/*
618 * Find the concrete method that corresponds to "methodIdx". The code in
619 * "method" is executing invoke-method with "thisClass" as its first argument.
620 *
621 * Returns NULL with an exception raised on failure.
622 */
623Method* dvmInterpFindInterfaceMethod(ClassObject* thisClass, u4 methodIdx,
624 const Method* method, DvmDex* methodClassDex)
625{
626 Method* absMethod;
627 Method* methodToCall;
628 int i, vtableIndex;
629
630 /*
631 * Resolve the method. This gives us the abstract method from the
632 * interface class declaration.
633 */
634 absMethod = dvmDexGetResolvedMethod(methodClassDex, methodIdx);
635 if (absMethod == NULL) {
636 absMethod = dvmResolveInterfaceMethod(method->clazz, methodIdx);
637 if (absMethod == NULL) {
638 LOGV("+ unknown method\n");
639 return NULL;
640 }
641 }
642
643 /* make sure absMethod->methodIndex means what we think it means */
644 assert(dvmIsAbstractMethod(absMethod));
645
646 /*
647 * Run through the "this" object's iftable. Find the entry for
648 * absMethod's class, then use absMethod->methodIndex to find
649 * the method's entry. The value there is the offset into our
650 * vtable of the actual method to execute.
651 *
652 * The verifier does not guarantee that objects stored into
653 * interface references actually implement the interface, so this
654 * check cannot be eliminated.
655 */
656 for (i = 0; i < thisClass->iftableCount; i++) {
657 if (thisClass->iftable[i].clazz == absMethod->clazz)
658 break;
659 }
660 if (i == thisClass->iftableCount) {
661 /* impossible in verified DEX, need to check for it in unverified */
662 dvmThrowException("Ljava/lang/IncompatibleClassChangeError;",
663 "interface not implemented");
664 return NULL;
665 }
666
667 assert(absMethod->methodIndex <
668 thisClass->iftable[i].clazz->virtualMethodCount);
669
670 vtableIndex =
671 thisClass->iftable[i].methodIndexArray[absMethod->methodIndex];
672 assert(vtableIndex >= 0 && vtableIndex < thisClass->vtableCount);
673 methodToCall = thisClass->vtable[vtableIndex];
674
675#if 0
676 /* this can happen when there's a stale class file */
677 if (dvmIsAbstractMethod(methodToCall)) {
678 dvmThrowException("Ljava/lang/AbstractMethodError;",
679 "interface method not implemented");
680 return NULL;
681 }
682#else
683 assert(!dvmIsAbstractMethod(methodToCall) ||
684 methodToCall->nativeFunc != NULL);
685#endif
686
687 LOGVV("+++ interface=%s.%s concrete=%s.%s\n",
688 absMethod->clazz->descriptor, absMethod->name,
689 methodToCall->clazz->descriptor, methodToCall->name);
690 assert(methodToCall != NULL);
691
692 return methodToCall;
693}
694
695
Andy McFaddenb51ea112009-05-08 16:50:17 -0700696
697/*
698 * Helpers for dvmThrowVerificationError().
699 *
700 * Each returns a newly-allocated string.
701 */
702#define kThrowShow_accessFromClass 1
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700703static char* classNameFromIndex(const Method* method, int ref,
704 VerifyErrorRefType refType, int flags)
Andy McFaddenb51ea112009-05-08 16:50:17 -0700705{
706 static const int kBufLen = 256;
707 const DvmDex* pDvmDex = method->clazz->pDvmDex;
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700708
709 if (refType == VERIFY_ERROR_REF_FIELD) {
710 /* get class ID from field ID */
711 const DexFieldId* pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
712 ref = pFieldId->classIdx;
713 } else if (refType == VERIFY_ERROR_REF_METHOD) {
714 /* get class ID from method ID */
715 const DexMethodId* pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
716 ref = pMethodId->classIdx;
717 }
718
Andy McFaddenb51ea112009-05-08 16:50:17 -0700719 const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref);
720 char* dotClassName = dvmDescriptorToDot(className);
721 if (flags == 0)
722 return dotClassName;
723
724 char* result = (char*) malloc(kBufLen);
725
726 if ((flags & kThrowShow_accessFromClass) != 0) {
727 char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
728 snprintf(result, kBufLen, "tried to access class %s from class %s",
729 dotClassName, dotFromName);
730 free(dotFromName);
731 } else {
732 assert(false); // should've been caught above
733 result[0] = '\0';
734 }
735
736 free(dotClassName);
737 return result;
738}
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700739static char* fieldNameFromIndex(const Method* method, int ref,
740 VerifyErrorRefType refType, int flags)
Andy McFaddenb51ea112009-05-08 16:50:17 -0700741{
742 static const int kBufLen = 256;
743 const DvmDex* pDvmDex = method->clazz->pDvmDex;
744 const DexFieldId* pFieldId;
745 const char* className;
746 const char* fieldName;
747
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700748 if (refType != VERIFY_ERROR_REF_FIELD) {
749 LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_FIELD, refType);
750 return NULL; /* no message */
751 }
752
Andy McFaddenb51ea112009-05-08 16:50:17 -0700753 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
754 className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx);
755 fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
756
757 char* dotName = dvmDescriptorToDot(className);
758 char* result = (char*) malloc(kBufLen);
759
760 if ((flags & kThrowShow_accessFromClass) != 0) {
761 char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
762 snprintf(result, kBufLen, "tried to access field %s.%s from class %s",
763 dotName, fieldName, dotFromName);
764 free(dotFromName);
765 } else {
766 snprintf(result, kBufLen, "%s.%s", dotName, fieldName);
767 }
768
769 free(dotName);
770 return result;
771}
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700772static char* methodNameFromIndex(const Method* method, int ref,
773 VerifyErrorRefType refType, int flags)
Andy McFaddenb51ea112009-05-08 16:50:17 -0700774{
775 static const int kBufLen = 384;
776 const DvmDex* pDvmDex = method->clazz->pDvmDex;
777 const DexMethodId* pMethodId;
778 const char* className;
779 const char* methodName;
780
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700781 if (refType != VERIFY_ERROR_REF_METHOD) {
782 LOGW("Expected ref type %d, got %d\n", VERIFY_ERROR_REF_METHOD,refType);
783 return NULL; /* no message */
784 }
785
Andy McFaddenb51ea112009-05-08 16:50:17 -0700786 pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
787 className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx);
788 methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
789
790 char* dotName = dvmDescriptorToDot(className);
791 char* result = (char*) malloc(kBufLen);
792
793 if ((flags & kThrowShow_accessFromClass) != 0) {
794 char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
795 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
796 snprintf(result, kBufLen,
797 "tried to access method %s.%s:%s from class %s",
798 dotName, methodName, desc, dotFromName);
799 free(dotFromName);
800 free(desc);
801 } else {
802 snprintf(result, kBufLen, "%s.%s", dotName, methodName);
803 }
804
805 free(dotName);
806 return result;
807}
808
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700809/*
Andy McFadden3a1aedb2009-05-07 13:30:23 -0700810 * Throw an exception for a problem identified by the verifier.
811 *
812 * This is used by the invoke-verification-error instruction. It always
813 * throws an exception.
814 *
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700815 * "kind" indicates the kind of failure encountered by the verifier. It
816 * has two parts, an error code and an indication of the reference type.
Andy McFadden3a1aedb2009-05-07 13:30:23 -0700817 */
Andy McFaddenb51ea112009-05-08 16:50:17 -0700818void dvmThrowVerificationError(const Method* method, int kind, int ref)
Andy McFadden3a1aedb2009-05-07 13:30:23 -0700819{
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700820 const int typeMask = 0xff << kVerifyErrorRefTypeShift;
821 VerifyError errorKind = kind & ~typeMask;
822 VerifyErrorRefType refType = kind >> kVerifyErrorRefTypeShift;
Andy McFaddenb51ea112009-05-08 16:50:17 -0700823 const char* exceptionName = "Ljava/lang/VerifyError;";
824 char* msg = NULL;
825
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700826 switch ((VerifyError) errorKind) {
Andy McFaddenb51ea112009-05-08 16:50:17 -0700827 case VERIFY_ERROR_NO_CLASS:
828 exceptionName = "Ljava/lang/NoClassDefFoundError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700829 msg = classNameFromIndex(method, ref, refType, 0);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700830 break;
831 case VERIFY_ERROR_NO_FIELD:
832 exceptionName = "Ljava/lang/NoSuchFieldError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700833 msg = fieldNameFromIndex(method, ref, refType, 0);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700834 break;
835 case VERIFY_ERROR_NO_METHOD:
836 exceptionName = "Ljava/lang/NoSuchMethodError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700837 msg = methodNameFromIndex(method, ref, refType, 0);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700838 break;
839 case VERIFY_ERROR_ACCESS_CLASS:
840 exceptionName = "Ljava/lang/IllegalAccessError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700841 msg = classNameFromIndex(method, ref, refType,
842 kThrowShow_accessFromClass);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700843 break;
844 case VERIFY_ERROR_ACCESS_FIELD:
845 exceptionName = "Ljava/lang/IllegalAccessError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700846 msg = fieldNameFromIndex(method, ref, refType,
847 kThrowShow_accessFromClass);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700848 break;
849 case VERIFY_ERROR_ACCESS_METHOD:
850 exceptionName = "Ljava/lang/IllegalAccessError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700851 msg = methodNameFromIndex(method, ref, refType,
852 kThrowShow_accessFromClass);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700853 break;
854 case VERIFY_ERROR_CLASS_CHANGE:
855 exceptionName = "Ljava/lang/IncompatibleClassChangeError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700856 msg = classNameFromIndex(method, ref, refType, 0);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700857 break;
858 case VERIFY_ERROR_INSTANTIATION:
859 exceptionName = "Ljava/lang/InstantiationError;";
Andy McFaddenaf0e8382009-08-28 10:38:37 -0700860 msg = classNameFromIndex(method, ref, refType, 0);
Andy McFaddenb51ea112009-05-08 16:50:17 -0700861 break;
862
863 case VERIFY_ERROR_GENERIC:
864 /* generic VerifyError; use default exception, no message */
865 break;
866 case VERIFY_ERROR_NONE:
867 /* should never happen; use default exception */
868 assert(false);
869 msg = strdup("weird - no error specified");
870 break;
871
872 /* no default clause -- want warning if enum updated */
873 }
874
875 dvmThrowException(exceptionName, msg);
876 free(msg);
Andy McFadden3a1aedb2009-05-07 13:30:23 -0700877}
878
Andy McFadden3a1aedb2009-05-07 13:30:23 -0700879/*
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700880 * Main interpreter loop entry point. Select "standard" or "debug"
881 * interpreter and switch between them as required.
882 *
883 * This begins executing code at the start of "method". On exit, "pResult"
884 * holds the return value of the method (or, if "method" returns NULL, it
885 * holds an undefined value).
886 *
887 * The interpreted stack frame, which holds the method arguments, has
888 * already been set up.
889 */
890void dvmInterpret(Thread* self, const Method* method, JValue* pResult)
891{
892 InterpState interpState;
893 bool change;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700894#if defined(WITH_JIT)
895 /* Interpreter entry points from compiled code */
896 extern void dvmJitToInterpNormal();
897 extern void dvmJitToInterpNoChain();
898 extern void dvmJitToInterpPunt();
899 extern void dvmJitToInterpSingleStep();
900 extern void dvmJitToTraceSelect();
Ben Cheng38329f52009-07-07 14:19:20 -0700901 extern void dvmJitToPatchPredictedChain();
Jeff Hao97319a82009-08-12 16:57:15 -0700902#if defined(WITH_SELF_VERIFICATION)
903 extern void dvmJitToBackwardBranch();
904#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700905
Ben Cheng38329f52009-07-07 14:19:20 -0700906 /*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700907 * Reserve a static entity here to quickly setup runtime contents as
908 * gcc will issue block copy instructions.
909 */
910 static struct JitToInterpEntries jitToInterpEntries = {
911 dvmJitToInterpNormal,
912 dvmJitToInterpNoChain,
913 dvmJitToInterpPunt,
914 dvmJitToInterpSingleStep,
915 dvmJitToTraceSelect,
Ben Cheng38329f52009-07-07 14:19:20 -0700916 dvmJitToPatchPredictedChain,
Jeff Hao97319a82009-08-12 16:57:15 -0700917#if defined(WITH_SELF_VERIFICATION)
918 dvmJitToBackwardBranch,
919#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700920 };
921#endif
922
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700923
924#if defined(WITH_TRACKREF_CHECKS)
925 interpState.debugTrackedRefStart =
926 dvmReferenceTableEntries(&self->internalLocalRefTable);
927#endif
928#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
929 interpState.debugIsMethodEntry = true;
930#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700931#if defined(WITH_JIT)
932 interpState.jitState = gDvmJit.pJitEntryTable ? kJitNormal : kJitOff;
933
934 /* Setup the Jit-to-interpreter entry points */
935 interpState.jitToInterpEntries = jitToInterpEntries;
Bill Buzbee48f18242009-06-19 16:02:27 -0700936
937 /*
938 * Initialize the threshold filter [don't bother to zero out the
939 * actual table. We're looking for matches, and an occasional
940 * false positive is acceptible.
941 */
942 interpState.lastThreshFilter = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700943#endif
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700944
945 /*
946 * Initialize working state.
947 *
948 * No need to initialize "retval".
949 */
950 interpState.method = method;
951 interpState.fp = (u4*) self->curFrame;
952 interpState.pc = method->insns;
953 interpState.entryPoint = kInterpEntryInstr;
954
955 if (dvmDebuggerOrProfilerActive())
956 interpState.nextMode = INTERP_DBG;
957 else
958 interpState.nextMode = INTERP_STD;
959
960 assert(!dvmIsNativeMethod(method));
961
962 /*
963 * Make sure the class is ready to go. Shouldn't be possible to get
964 * here otherwise.
965 */
966 if (method->clazz->status < CLASS_INITIALIZING ||
967 method->clazz->status == CLASS_ERROR)
968 {
969 LOGE("ERROR: tried to execute code in unprepared class '%s' (%d)\n",
970 method->clazz->descriptor, method->clazz->status);
971 dvmDumpThread(self, false);
972 dvmAbort();
973 }
974
975 typedef bool (*Interpreter)(Thread*, InterpState*);
976 Interpreter stdInterp;
977 if (gDvm.executionMode == kExecutionModeInterpFast)
978 stdInterp = dvmMterpStd;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700979#if defined(WITH_JIT)
980 else if (gDvm.executionMode == kExecutionModeJit)
981/* If profiling overhead can be kept low enough, we can use a profiling
982 * mterp fast for both Jit and "fast" modes. If overhead is too high,
983 * create a specialized profiling interpreter.
984 */
985 stdInterp = dvmMterpStd;
986#endif
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700987 else
988 stdInterp = dvmInterpretStd;
989
990 change = true;
991 while (change) {
992 switch (interpState.nextMode) {
993 case INTERP_STD:
994 LOGVV("threadid=%d: interp STD\n", self->threadId);
995 change = (*stdInterp)(self, &interpState);
996 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700997#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) || defined(WITH_JIT)
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700998 case INTERP_DBG:
999 LOGVV("threadid=%d: interp DBG\n", self->threadId);
1000 change = dvmInterpretDbg(self, &interpState);
1001 break;
1002#endif
1003 default:
1004 dvmAbort();
1005 }
1006 }
1007
1008 *pResult = interpState.retval;
1009}