blob: d086b998f1329affa8b12e782f4c5837cff09a95 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Convert the output from "dx" into a locally-optimized DEX file.
19 *
20 * TODO: the format of the optimized header is currently "whatever we
21 * happen to write", since the VM that writes it is by definition the same
22 * as the VM that reads it. Still, it should be better documented and
23 * more rigorously structured.
24 */
25#include "Dalvik.h"
26#include "libdex/InstrUtils.h"
27#include "libdex/OptInvocation.h"
28
29#include <zlib.h>
30
31#include <stdlib.h>
32#include <unistd.h>
33#include <sys/mman.h>
34#include <sys/stat.h>
35#include <sys/file.h>
36#include <sys/wait.h>
37#include <fcntl.h>
38#include <errno.h>
39
40/*
41 * Virtual/direct calls to "method" are replaced with an execute-inline
42 * instruction with index "idx".
43 */
44typedef struct InlineSub {
45 Method* method;
46 int inlineIdx;
47} InlineSub;
48
49
50/* fwd */
51static int writeDependencies(int fd, u4 modWhen, u4 crc);
52static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,\
53 const IndexMapSet* pIndexMapSet);
54static void logFailedWrite(size_t expected, ssize_t actual, const char* msg,
55 int err);
56
57static bool rewriteDex(u1* addr, int len, bool doVerify, bool doOpt,\
58 u4* pHeaderFlags, DexClassLookup** ppClassLookup);
59static void updateChecksum(u1* addr, int len, DexHeader* pHeader);
60static bool loadAllClasses(DvmDex* pDvmDex);
61static void optimizeLoadedClasses(DexFile* pDexFile);
62static void optimizeClass(ClassObject* clazz, const InlineSub* inlineSubs);
63static bool optimizeMethod(Method* method, const InlineSub* inlineSubs);
64static void rewriteInstField(Method* method, u2* insns, OpCode newOpc);
65static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc);
66static bool rewriteDirectInvoke(Method* method, u2* insns);
67static bool rewriteExecuteInline(Method* method, u2* insns,
68 MethodType methodType, const InlineSub* inlineSubs);
69
70
71/*
72 * Return the fd of an open file in the DEX file cache area. If the cache
73 * file doesn't exist or is out of date, this will remove the old entry,
74 * create a new one (writing only the file header), and return with the
75 * "new file" flag set.
76 *
77 * It's possible to execute from an unoptimized DEX file directly,
78 * assuming the byte ordering and structure alignment is correct, but
79 * disadvantageous because some significant optimizations are not possible.
80 * It's not generally possible to do the same from an uncompressed Jar
81 * file entry, because we have to guarantee 32-bit alignment in the
82 * memory-mapped file.
83 *
84 * For a Jar/APK file (a zip archive with "classes.dex" inside), "modWhen"
85 * and "crc32" come from the Zip directory entry. For a stand-alone DEX
86 * file, it's the modification date of the file and the Adler32 from the
87 * DEX header (which immediately follows the magic). If these don't
88 * match what's stored in the opt header, we reject the file immediately.
89 *
90 * On success, the file descriptor will be positioned just past the "opt"
91 * file header, and will be locked with flock. "*pCachedName" will point
92 * to newly-allocated storage.
93 */
94int dvmOpenCachedDexFile(const char* fileName, const char* cacheFileName,
95 u4 modWhen, u4 crc, bool isBootstrap, bool* pNewFile, bool createIfMissing)
96{
97 int fd, cc;
98 struct stat fdStat, fileStat;
99 bool readOnly = false;
100
101 *pNewFile = false;
102
103retry:
104 /*
105 * Try to open the cache file. If we've been asked to,
106 * create it if it doesn't exist.
107 */
108 fd = createIfMissing ? open(cacheFileName, O_CREAT|O_RDWR, 0644) : -1;
109 if (fd < 0) {
110 fd = open(cacheFileName, O_RDONLY, 0);
111 if (fd < 0) {
112 if (createIfMissing) {
113 LOGE("Can't open dex cache '%s': %s\n",
114 cacheFileName, strerror(errno));
115 }
116 return fd;
117 }
118 readOnly = true;
119 }
120
121 /*
122 * Grab an exclusive lock on the cache file. If somebody else is
123 * working on it, we'll block here until they complete. Because
124 * we're waiting on an external resource, we go into VMWAIT mode.
125 */
126 int oldStatus;
127 LOGV("DexOpt: locking cache file %s (fd=%d, boot=%d)\n",
128 cacheFileName, fd, isBootstrap);
129 oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
130 cc = flock(fd, LOCK_EX | LOCK_NB);
131 if (cc != 0) {
132 LOGD("DexOpt: sleeping on flock(%s)\n", cacheFileName);
133 cc = flock(fd, LOCK_EX);
134 }
135 dvmChangeStatus(NULL, oldStatus);
136 if (cc != 0) {
137 LOGE("Can't lock dex cache '%s': %d\n", cacheFileName, cc);
138 close(fd);
139 return -1;
140 }
141 LOGV("DexOpt: locked cache file\n");
142
143 /*
144 * Check to see if the fd we opened and locked matches the file in
145 * the filesystem. If they don't, then somebody else unlinked ours
146 * and created a new file, and we need to use that one instead. (If
147 * we caught them between the unlink and the create, we'll get an
148 * ENOENT from the file stat.)
149 */
150 cc = fstat(fd, &fdStat);
151 if (cc != 0) {
152 LOGE("Can't stat open file '%s'\n", cacheFileName);
153 LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
154 goto close_fail;
155 }
156 cc = stat(cacheFileName, &fileStat);
157 if (cc != 0 ||
158 fdStat.st_dev != fileStat.st_dev || fdStat.st_ino != fileStat.st_ino)
159 {
160 LOGD("DexOpt: our open cache file is stale; sleeping and retrying\n");
161 LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
162 flock(fd, LOCK_UN);
163 close(fd);
164 usleep(250 * 1000); /* if something is hosed, don't peg machine */
165 goto retry;
166 }
167
168 /*
169 * We have the correct file open and locked. If the file size is zero,
170 * then it was just created by us, and we want to fill in some fields
171 * in the "opt" header and set "*pNewFile". Otherwise, we want to
172 * verify that the fields in the header match our expectations, and
173 * reset the file if they don't.
174 */
175 if (fdStat.st_size == 0) {
176 if (readOnly) {
177 LOGW("DexOpt: file has zero length and isn't writable\n");
178 goto close_fail;
179 }
180 cc = dexOptCreateEmptyHeader(fd);
181 if (cc != 0)
182 goto close_fail;
183 *pNewFile = true;
184 LOGV("DexOpt: successfully initialized new cache file\n");
185 } else {
186 bool expectVerify, expectOpt;
187
188 if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
189 expectVerify = false;
190 else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
191 expectVerify = !isBootstrap;
192 else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
193 expectVerify = true;
194
195 if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
196 expectOpt = false;
197 else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
198 expectOpt = expectVerify;
199 else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
200 expectOpt = true;
201
202 LOGV("checking deps, expecting vfy=%d opt=%d\n",
203 expectVerify, expectOpt);
204
205 if (!dvmCheckOptHeaderAndDependencies(fd, true, modWhen, crc,
206 expectVerify, expectOpt))
207 {
208 if (readOnly) {
209 /*
210 * We could unlink and rewrite the file if we own it or
211 * the "sticky" bit isn't set on the directory. However,
212 * we're not able to truncate it, which spoils things. So,
213 * give up now.
214 */
215 if (createIfMissing) {
216 LOGW("Cached DEX '%s' (%s) is stale and not writable\n",
217 fileName, cacheFileName);
218 }
219 goto close_fail;
220 }
221
222 /*
223 * If we truncate the existing file before unlinking it, any
224 * process that has it mapped will fail when it tries to touch
225 * the pages.
226 *
227 * This is very important. The zygote process will have the
228 * boot DEX files (core, framework, etc.) mapped early. If
229 * (say) core.dex gets updated, and somebody launches an app
230 * that uses App.dex, then App.dex gets reoptimized because it's
231 * dependent upon the boot classes. However, dexopt will be
232 * using the *new* core.dex to do the optimizations, while the
233 * app will actually be running against the *old* core.dex
234 * because it starts from zygote.
235 *
236 * Even without zygote, it's still possible for a class loader
237 * to pull in an APK that was optimized against an older set
238 * of DEX files. We must ensure that everything fails when a
239 * boot DEX gets updated, and for general "why aren't my
240 * changes doing anything" purposes its best if we just make
241 * everything crash when a DEX they're using gets updated.
242 */
243 LOGD("Stale deps in cache file; removing and retrying\n");
244 if (ftruncate(fd, 0) != 0) {
245 LOGW("Warning: unable to truncate cache file '%s': %s\n",
246 cacheFileName, strerror(errno));
247 /* keep going */
248 }
249 if (unlink(cacheFileName) != 0) {
250 LOGW("Warning: unable to remove cache file '%s': %d %s\n",
251 cacheFileName, errno, strerror(errno));
252 /* keep going; permission failure should probably be fatal */
253 }
254 LOGVV("DexOpt: unlocking cache file %s\n", cacheFileName);
255 flock(fd, LOCK_UN);
256 close(fd);
257 goto retry;
258 } else {
259 LOGV("DexOpt: good deps in cache file\n");
260 }
261 }
262
263 assert(fd >= 0);
264 return fd;
265
266close_fail:
267 flock(fd, LOCK_UN);
268 close(fd);
269 return -1;
270}
271
272/*
273 * Unlock the file descriptor.
274 *
275 * Returns "true" on success.
276 */
277bool dvmUnlockCachedDexFile(int fd)
278{
279 LOGVV("DexOpt: unlocking cache file fd=%d\n", fd);
280 return (flock(fd, LOCK_UN) == 0);
281}
282
283
284/*
285 * Given a descriptor for a file with DEX data in it, produce an
286 * optimized version.
287 *
288 * The file pointed to by "fd" is expected to be a locked shared resource
289 * (or private); we make no efforts to enforce multi-process correctness
290 * here.
291 *
292 * "fileName" is only used for debug output. "modWhen" and "crc" are stored
293 * in the dependency set.
294 *
295 * The "isBootstrap" flag determines how the optimizer and verifier handle
296 * package-scope access checks. When optimizing, we only load the bootstrap
297 * class DEX files and the target DEX, so the flag determines whether the
298 * target DEX classes are given a (synthetic) non-NULL classLoader pointer.
299 * This only really matters if the target DEX contains classes that claim to
300 * be in the same package as bootstrap classes.
301 *
302 * The optimizer will need to load every class in the target DEX file.
303 * This is generally undesirable, so we start a subprocess to do the
304 * work and wait for it to complete.
305 *
306 * Returns "true" on success. All data will have been written to "fd".
307 */
308bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,
309 const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
310{
311 const char* lastPart = strrchr(fileName, '/');
312 if (lastPart != NULL)
313 lastPart++;
314 else
315 lastPart = fileName;
316
317 /*
318 * For basic optimizations (byte-swapping and structure aligning) we
319 * don't need to fork(). It looks like fork+exec is causing problems
320 * with gdb on our bewildered Linux distro, so in some situations we
321 * want to avoid this.
322 *
323 * For optimization and/or verification, we need to load all the classes.
324 *
325 * We don't check gDvm.generateRegisterMaps, since that is dependent
326 * upon the verifier state.
327 */
328 if (gDvm.classVerifyMode == VERIFY_MODE_NONE &&
329 (gDvm.dexOptMode == OPTIMIZE_MODE_NONE ||
330 gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED))
331 {
332 LOGD("DexOpt: --- BEGIN (quick) '%s' ---\n", lastPart);
333 return dvmContinueOptimization(fd, dexOffset, dexLength,
334 fileName, modWhen, crc, isBootstrap);
335 }
336
337
338 LOGD("DexOpt: --- BEGIN '%s' (bootstrap=%d) ---\n", lastPart, isBootstrap);
339
340 pid_t pid;
341
342 /*
343 * This could happen if something in our bootclasspath, which we thought
344 * was all optimized, got rejected.
345 */
346 if (gDvm.optimizing) {
347 LOGW("Rejecting recursive optimization attempt on '%s'\n", fileName);
348 return false;
349 }
350
351 pid = fork();
352 if (pid == 0) {
353 static const int kUseValgrind = 0;
354 static const char* kDexOptBin = "/bin/dexopt";
355 static const char* kValgrinder = "/usr/bin/valgrind";
356 static const int kFixedArgCount = 10;
357 static const int kValgrindArgCount = 5;
358 static const int kMaxIntLen = 12; // '-'+10dig+'\0' -OR- 0x+8dig
359 int bcpSize = dvmGetBootPathSize();
360 int argc = kFixedArgCount + bcpSize
361 + (kValgrindArgCount * kUseValgrind);
362 char* argv[argc+1]; // last entry is NULL
363 char values[argc][kMaxIntLen];
364 char* execFile;
365 char* androidRoot;
366 int flags;
367
368 /* full path to optimizer */
369 androidRoot = getenv("ANDROID_ROOT");
370 if (androidRoot == NULL) {
371 LOGW("ANDROID_ROOT not set, defaulting to /system\n");
372 androidRoot = "/system";
373 }
374 execFile = malloc(strlen(androidRoot) + strlen(kDexOptBin) + 1);
375 strcpy(execFile, androidRoot);
376 strcat(execFile, kDexOptBin);
377
378 /*
379 * Create arg vector.
380 */
381 int curArg = 0;
382
383 if (kUseValgrind) {
384 /* probably shouldn't ship the hard-coded path */
385 argv[curArg++] = (char*)kValgrinder;
386 argv[curArg++] = "--tool=memcheck";
387 argv[curArg++] = "--leak-check=yes"; // check for leaks too
388 argv[curArg++] = "--leak-resolution=med"; // increase from 2 to 4
389 argv[curArg++] = "--num-callers=16"; // default is 12
390 assert(curArg == kValgrindArgCount);
391 }
392 argv[curArg++] = execFile;
393
394 argv[curArg++] = "--dex";
395
396 sprintf(values[2], "%d", DALVIK_VM_BUILD);
397 argv[curArg++] = values[2];
398
399 sprintf(values[3], "%d", fd);
400 argv[curArg++] = values[3];
401
402 sprintf(values[4], "%d", (int) dexOffset);
403 argv[curArg++] = values[4];
404
405 sprintf(values[5], "%d", (int) dexLength);
406 argv[curArg++] = values[5];
407
408 argv[curArg++] = (char*)fileName;
409
410 sprintf(values[7], "%d", (int) modWhen);
411 argv[curArg++] = values[7];
412
413 sprintf(values[8], "%d", (int) crc);
414 argv[curArg++] = values[8];
415
416 flags = 0;
417 if (gDvm.dexOptMode != OPTIMIZE_MODE_NONE) {
418 flags |= DEXOPT_OPT_ENABLED;
419 if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)
420 flags |= DEXOPT_OPT_ALL;
421 }
422 if (gDvm.classVerifyMode != VERIFY_MODE_NONE) {
423 flags |= DEXOPT_VERIFY_ENABLED;
424 if (gDvm.classVerifyMode == VERIFY_MODE_ALL)
425 flags |= DEXOPT_VERIFY_ALL;
426 }
427 if (isBootstrap)
428 flags |= DEXOPT_IS_BOOTSTRAP;
429 if (gDvm.generateRegisterMaps)
430 flags |= DEXOPT_GEN_REGISTER_MAP;
431 sprintf(values[9], "%d", flags);
432 argv[curArg++] = values[9];
433
434 assert(((!kUseValgrind && curArg == kFixedArgCount) ||
435 ((kUseValgrind && curArg == kFixedArgCount+kValgrindArgCount))));
436
437 ClassPathEntry* cpe;
438 for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
439 argv[curArg++] = cpe->fileName;
440 }
441 assert(curArg == argc);
442
443 argv[curArg] = NULL;
444
445 if (kUseValgrind)
446 execv(kValgrinder, argv);
447 else
448 execv(execFile, argv);
449
450 LOGE("execv '%s'%s failed: %s\n", execFile,
451 kUseValgrind ? " [valgrind]" : "", strerror(errno));
452 exit(1);
453 } else {
454 LOGV("DexOpt: waiting for verify+opt, pid=%d\n", (int) pid);
455 int status;
456 pid_t gotPid;
457 int oldStatus;
458
459 /*
460 * Wait for the optimization process to finish. We go into VMWAIT
461 * mode here so GC suspension won't have to wait for us.
462 */
463 oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
464 while (true) {
465 gotPid = waitpid(pid, &status, 0);
466 if (gotPid == -1 && errno == EINTR) {
467 LOGD("waitpid interrupted, retrying\n");
468 } else {
469 break;
470 }
471 }
472 dvmChangeStatus(NULL, oldStatus);
473 if (gotPid != pid) {
474 LOGE("waitpid failed: wanted %d, got %d: %s\n",
475 (int) pid, (int) gotPid, strerror(errno));
476 return false;
477 }
478
479 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
480 LOGD("DexOpt: --- END '%s' (success) ---\n", lastPart);
481 return true;
482 } else {
483 LOGW("DexOpt: --- END '%s' --- status=0x%04x, process failed\n",
484 lastPart, status);
485 return false;
486 }
487 }
488}
489
490/*
491 * Do the actual optimization. This is called directly for "minimal"
492 * optimization, or from a newly-created process for "full" optimization.
493 *
494 * For best use of disk/memory, we want to extract once and perform
495 * optimizations in place. If the file has to expand or contract
496 * to match local structure padding/alignment expectations, we want
497 * to do the rewrite as part of the extract, rather than extracting
498 * into a temp file and slurping it back out. (The structure alignment
499 * is currently correct for all platforms, and this isn't expected to
500 * change, so we should be okay with having it already extracted.)
501 *
502 * Returns "true" on success.
503 */
504bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
505 const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
506{
507 DexClassLookup* pClassLookup = NULL;
508 IndexMapSet* pIndexMapSet = NULL;
509 bool doVerify, doOpt;
510 u4 headerFlags = 0;
511
512 if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
513 doVerify = false;
514 else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
515 doVerify = !isBootstrap;
516 else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
517 doVerify = true;
518
519 if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
520 doOpt = false;
521 else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
522 doOpt = doVerify;
523 else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
524 doOpt = true;
525
526 LOGV("Continuing optimization (%s, isb=%d, vfy=%d, opt=%d)\n",
527 fileName, isBootstrap, doVerify, doOpt);
528
529 assert(dexOffset >= 0);
530
531 /* quick test so we don't blow up on empty file */
532 if (dexLength < (int) sizeof(DexHeader)) {
533 LOGE("too small to be DEX\n");
534 return false;
535 }
536 if (dexOffset < (int) sizeof(DexOptHeader)) {
537 LOGE("not enough room for opt header\n");
538 return false;
539 }
540
541 bool result = false;
542
543 /*
544 * Drop this into a global so we don't have to pass it around. We could
545 * also add a field to DexFile, but since it only pertains to DEX
546 * creation that probably doesn't make sense.
547 */
548 gDvm.optimizingBootstrapClass = isBootstrap;
549
550 {
551 /*
552 * Map the entire file (so we don't have to worry about page
553 * alignment). The expectation is that the output file contains
554 * our DEX data plus room for a small header.
555 */
556 bool success;
557 void* mapAddr;
558 mapAddr = mmap(NULL, dexOffset + dexLength, PROT_READ|PROT_WRITE,
559 MAP_SHARED, fd, 0);
560 if (mapAddr == MAP_FAILED) {
561 LOGE("unable to mmap DEX cache: %s\n", strerror(errno));
562 goto bail;
563 }
564
565 /*
566 * Rewrite the file. Byte reordering, structure realigning,
567 * class verification, and bytecode optimization are all performed
568 * here.
569 */
570 success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
571 doVerify, doOpt, &headerFlags, &pClassLookup);
572
573 if (success) {
574 DvmDex* pDvmDex = NULL;
575 u1* dexAddr = ((u1*) mapAddr) + dexOffset;
576
577 if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
578 LOGE("Unable to create DexFile\n");
579 } else {
580 /*
581 * If configured to do so, scan the instructions, looking
582 * for ways to reduce the size of the resolved-constant table.
583 * This is done post-optimization, across the instructions
584 * in all methods in all classes (even the ones that failed
585 * to load).
586 */
587 pIndexMapSet = dvmRewriteConstants(pDvmDex);
588
589 updateChecksum(dexAddr, dexLength,
590 (DexHeader*) pDvmDex->pHeader);
591
592 dvmDexFileFree(pDvmDex);
593 }
594 }
595
596 /* unmap the read-write version, forcing writes to disk */
597 if (msync(mapAddr, dexOffset + dexLength, MS_SYNC) != 0) {
598 LOGW("msync failed: %s\n", strerror(errno));
599 // weird, but keep going
600 }
601#if 1
602 /*
603 * This causes clean shutdown to fail, because we have loaded classes
604 * that point into it. For the optimizer this isn't a problem,
605 * because it's more efficient for the process to simply exit.
606 * Exclude this code when doing clean shutdown for valgrind.
607 */
608 if (munmap(mapAddr, dexOffset + dexLength) != 0) {
609 LOGE("munmap failed: %s\n", strerror(errno));
610 goto bail;
611 }
612#endif
613
614 if (!success)
615 goto bail;
616 }
617
618 /* get start offset, and adjust deps start for 64-bit alignment */
619 off_t depsOffset, auxOffset, endOffset, adjOffset;
620 int depsLength, auxLength;
621
622 depsOffset = lseek(fd, 0, SEEK_END);
623 if (depsOffset < 0) {
624 LOGE("lseek to EOF failed: %s\n", strerror(errno));
625 goto bail;
626 }
627 adjOffset = (depsOffset + 7) & ~(0x07);
628 if (adjOffset != depsOffset) {
629 LOGV("Adjusting deps start from %d to %d\n",
630 (int) depsOffset, (int) adjOffset);
631 depsOffset = adjOffset;
632 lseek(fd, depsOffset, SEEK_SET);
633 }
634
635 /*
636 * Append the dependency list.
637 */
638 if (writeDependencies(fd, modWhen, crc) != 0) {
639 LOGW("Failed writing dependencies\n");
640 goto bail;
641 }
642
643
644 /* compute deps length, and adjust aux start for 64-bit alignment */
645 auxOffset = lseek(fd, 0, SEEK_END);
646 depsLength = auxOffset - depsOffset;
647
648 adjOffset = (auxOffset + 7) & ~(0x07);
649 if (adjOffset != auxOffset) {
650 LOGV("Adjusting aux start from %d to %d\n",
651 (int) auxOffset, (int) adjOffset);
652 auxOffset = adjOffset;
653 lseek(fd, auxOffset, SEEK_SET);
654 }
655
656 /*
657 * Append any auxillary pre-computed data structures.
658 */
659 if (!writeAuxData(fd, pClassLookup, pIndexMapSet)) {
660 LOGW("Failed writing aux data\n");
661 goto bail;
662 }
663
664 endOffset = lseek(fd, 0, SEEK_END);
665 auxLength = endOffset - auxOffset;
666
667 /*
668 * Output the "opt" header with all values filled in and a correct
669 * magic number.
670 */
671 DexOptHeader optHdr;
672 memset(&optHdr, 0xff, sizeof(optHdr));
673 memcpy(optHdr.magic, DEX_OPT_MAGIC, 4);
674 memcpy(optHdr.magic+4, DEX_OPT_MAGIC_VERS, 4);
675 optHdr.dexOffset = (u4) dexOffset;
676 optHdr.dexLength = (u4) dexLength;
677 optHdr.depsOffset = (u4) depsOffset;
678 optHdr.depsLength = (u4) depsLength;
679 optHdr.auxOffset = (u4) auxOffset;
680 optHdr.auxLength = (u4) auxLength;
681
682 optHdr.flags = headerFlags;
683
684 ssize_t actual;
685 lseek(fd, 0, SEEK_SET);
686 actual = write(fd, &optHdr, sizeof(optHdr));
687 if (actual != sizeof(optHdr)) {
688 logFailedWrite(sizeof(optHdr), actual, "opt header", errno);
689 goto bail;
690 }
691
692 LOGV("Successfully wrote DEX header\n");
693 result = true;
694
695bail:
696 dvmFreeIndexMapSet(pIndexMapSet);
697 free(pClassLookup);
698 return result;
699}
700
701
702/*
703 * Get the cache file name from a ClassPathEntry.
704 */
705static const char* getCacheFileName(const ClassPathEntry* cpe)
706{
707 switch (cpe->kind) {
708 case kCpeJar:
709 return dvmGetJarFileCacheFileName((JarFile*) cpe->ptr);
710 case kCpeDex:
711 return dvmGetRawDexFileCacheFileName((RawDexFile*) cpe->ptr);
712 default:
713 LOGE("DexOpt: unexpected cpe kind %d\n", cpe->kind);
714 dvmAbort();
715 return NULL;
716 }
717}
718
719/*
720 * Get the SHA-1 signature.
721 */
722static const u1* getSignature(const ClassPathEntry* cpe)
723{
724 DvmDex* pDvmDex;
725
726 switch (cpe->kind) {
727 case kCpeJar:
728 pDvmDex = dvmGetJarFileDex((JarFile*) cpe->ptr);
729 break;
730 case kCpeDex:
731 pDvmDex = dvmGetRawDexFileDex((RawDexFile*) cpe->ptr);
732 break;
733 default:
734 LOGE("unexpected cpe kind %d\n", cpe->kind);
735 dvmAbort();
736 pDvmDex = NULL; // make gcc happy
737 }
738
739 assert(pDvmDex != NULL);
740 return pDvmDex->pDexFile->pHeader->signature;
741}
742
743
744/*
745 * Dependency layout:
746 * 4b Source file modification time, in seconds since 1970 UTC
747 * 4b CRC-32 from Zip entry, or Adler32 from source DEX header
748 * 4b Dalvik VM build number
749 * 4b Number of dependency entries that follow
750 * Dependency entries:
751 * 4b Name length (including terminating null)
752 * var Full path of cache entry (null terminated)
753 * 20b SHA-1 signature from source DEX file
754 *
755 * If this changes, update DEX_OPT_MAGIC_VERS.
756 */
757static const size_t kMinDepSize = 4 * 4;
758static const size_t kMaxDepSize = 4 * 4 + 1024; // sanity check
759
760/*
761 * Read the "opt" header, verify it, then read the dependencies section
762 * and verify that data as well.
763 *
764 * If "sourceAvail" is "true", this will verify that "modWhen" and "crc"
765 * match up with what is stored in the header. If they don't, we reject
766 * the file so that it can be recreated from the updated original. If
767 * "sourceAvail" isn't set, e.g. for a .odex file, we ignore these arguments.
768 *
769 * On successful return, the file will be seeked immediately past the
770 * "opt" header.
771 */
772bool dvmCheckOptHeaderAndDependencies(int fd, bool sourceAvail, u4 modWhen,
773 u4 crc, bool expectVerify, bool expectOpt)
774{
775 DexOptHeader optHdr;
776 u1* depData = NULL;
777 const u1* magic;
778 off_t posn;
779 int result = false;
780 ssize_t actual;
781
782 /*
783 * Start at the start. The "opt" header, when present, will always be
784 * the first thing in the file.
785 */
786 if (lseek(fd, 0, SEEK_SET) != 0) {
787 LOGE("DexOpt: failed to seek to start of file: %s\n", strerror(errno));
788 goto bail;
789 }
790
791 /*
792 * Read and do trivial verification on the opt header. The header is
793 * always in host byte order.
794 */
795 if (read(fd, &optHdr, sizeof(optHdr)) != sizeof(optHdr)) {
796 LOGE("DexOpt: failed reading opt header: %s\n", strerror(errno));
797 goto bail;
798 }
799
800 magic = optHdr.magic;
801 if (memcmp(magic, DEX_OPT_MAGIC, 4) != 0) {
802 /* not a DEX file, or previous attempt was interrupted */
803 LOGD("DexOpt: incorrect opt magic number (0x%02x %02x %02x %02x)\n",
804 magic[0], magic[1], magic[2], magic[3]);
805 goto bail;
806 }
807 if (memcmp(magic+4, DEX_OPT_MAGIC_VERS, 4) != 0) {
808 LOGW("DexOpt: stale opt version (0x%02x %02x %02x %02x)\n",
809 magic[4], magic[5], magic[6], magic[7]);
810 goto bail;
811 }
812 if (optHdr.depsLength < kMinDepSize || optHdr.depsLength > kMaxDepSize) {
813 LOGW("DexOpt: weird deps length %d, bailing\n", optHdr.depsLength);
814 goto bail;
815 }
816
817 /*
818 * Do the header flags match up with what we want?
819 *
820 * This is useful because it allows us to automatically regenerate
821 * a file when settings change (e.g. verification is now mandatory),
822 * but can cause difficulties if the bootstrap classes we depend upon
823 * were handled differently than the current options specify. We get
824 * upset because they're not verified or optimized, but we're not able
825 * to regenerate them because the installer won't let us.
826 *
827 * (This is also of limited value when !sourceAvail.)
828 *
829 * So, for now, we essentially ignore "expectVerify" and "expectOpt"
830 * by limiting the match mask.
831 *
832 * The only thing we really can't handle is incorrect byte-ordering.
833 */
834 const u4 matchMask = DEX_OPT_FLAG_BIG;
835 u4 expectedFlags = 0;
836#if __BYTE_ORDER != __LITTLE_ENDIAN
837 expectedFlags |= DEX_OPT_FLAG_BIG;
838#endif
839 if (expectVerify)
840 expectedFlags |= DEX_FLAG_VERIFIED;
841 if (expectOpt)
842 expectedFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
843 if ((expectedFlags & matchMask) != (optHdr.flags & matchMask)) {
844 LOGI("DexOpt: header flag mismatch (0x%02x vs 0x%02x, mask=0x%02x)\n",
845 expectedFlags, optHdr.flags, matchMask);
846 goto bail;
847 }
848
849 posn = lseek(fd, optHdr.depsOffset, SEEK_SET);
850 if (posn < 0) {
851 LOGW("DexOpt: seek to deps failed: %s\n", strerror(errno));
852 goto bail;
853 }
854
855 /*
856 * Read all of the dependency stuff into memory.
857 */
858 depData = (u1*) malloc(optHdr.depsLength);
859 if (depData == NULL) {
860 LOGW("DexOpt: unable to allocate %d bytes for deps\n",
861 optHdr.depsLength);
862 goto bail;
863 }
864 actual = read(fd, depData, optHdr.depsLength);
865 if (actual != (ssize_t) optHdr.depsLength) {
866 LOGW("DexOpt: failed reading deps: %d of %d (err=%s)\n",
867 (int) actual, optHdr.depsLength, strerror(errno));
868 goto bail;
869 }
870
871 /*
872 * Verify simple items.
873 */
874 const u1* ptr;
875 u4 val;
876
877 ptr = depData;
878 val = read4LE(&ptr);
879 if (sourceAvail && val != modWhen) {
880 LOGI("DexOpt: source file mod time mismatch (%08x vs %08x)\n",
881 val, modWhen);
882 goto bail;
883 }
884 val = read4LE(&ptr);
885 if (sourceAvail && val != crc) {
886 LOGI("DexOpt: source file CRC mismatch (%08x vs %08x)\n", val, crc);
887 goto bail;
888 }
889 val = read4LE(&ptr);
890 if (val != DALVIK_VM_BUILD) {
891 LOGI("DexOpt: VM build mismatch (%d vs %d)\n", val, DALVIK_VM_BUILD);
892 goto bail;
893 }
894
895 /*
896 * Verify dependencies on other cached DEX files. It must match
897 * exactly with what is currently defined in the bootclasspath.
898 */
899 ClassPathEntry* cpe;
900 u4 numDeps;
901
902 numDeps = read4LE(&ptr);
903 LOGV("+++ DexOpt: numDeps = %d\n", numDeps);
904 for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
905 const char* cacheFileName = getCacheFileName(cpe);
906 const u1* signature = getSignature(cpe);
907 size_t len = strlen(cacheFileName) +1;
908 u4 storedStrLen;
909
910 if (numDeps == 0) {
911 /* more entries in bootclasspath than in deps list */
912 LOGI("DexOpt: not all deps represented\n");
913 goto bail;
914 }
915
916 storedStrLen = read4LE(&ptr);
917 if (len != storedStrLen ||
918 strcmp(cacheFileName, (const char*) ptr) != 0)
919 {
920 LOGI("DexOpt: mismatch dep name: '%s' vs. '%s'\n",
921 cacheFileName, ptr);
922 goto bail;
923 }
924
925 ptr += storedStrLen;
926
927 if (memcmp(signature, ptr, kSHA1DigestLen) != 0) {
928 LOGI("DexOpt: mismatch dep signature for '%s'\n", cacheFileName);
929 goto bail;
930 }
931 ptr += kSHA1DigestLen;
932
933 LOGV("DexOpt: dep match on '%s'\n", cacheFileName);
934
935 numDeps--;
936 }
937
938 if (numDeps != 0) {
939 /* more entries in deps list than in classpath */
940 LOGI("DexOpt: Some deps went away\n");
941 goto bail;
942 }
943
944 // consumed all data and no more?
945 if (ptr != depData + optHdr.depsLength) {
946 LOGW("DexOpt: Spurious dep data? %d vs %d\n",
947 (int) (ptr - depData), optHdr.depsLength);
948 assert(false);
949 }
950
951 result = true;
952
953bail:
954 free(depData);
955 return result;
956}
957
958/*
959 * Write the dependency info to "fd" at the current file position.
960 */
961static int writeDependencies(int fd, u4 modWhen, u4 crc)
962{
963 u1* buf = NULL;
964 ssize_t actual;
965 int result = -1;
966 ssize_t bufLen;
967 ClassPathEntry* cpe;
968 int i, numDeps;
969
970 /*
971 * Count up the number of completed entries in the bootclasspath.
972 */
973 numDeps = 0;
974 bufLen = 0;
975 for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
976 const char* cacheFileName = getCacheFileName(cpe);
977 LOGV("+++ DexOpt: found dep '%s'\n", cacheFileName);
978
979 numDeps++;
980 bufLen += strlen(cacheFileName) +1;
981 }
982
983 bufLen += 4*4 + numDeps * (4+kSHA1DigestLen);
984
985 buf = malloc(bufLen);
986
987 set4LE(buf+0, modWhen);
988 set4LE(buf+4, crc);
989 set4LE(buf+8, DALVIK_VM_BUILD);
990 set4LE(buf+12, numDeps);
991
992 // TODO: do we want to add dvmGetInlineOpsTableLength() here? Won't
993 // help us if somebody replaces an existing entry, but it'd catch
994 // additions/removals.
995
996 u1* ptr = buf + 4*4;
997 for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {
998 const char* cacheFileName = getCacheFileName(cpe);
999 const u1* signature = getSignature(cpe);
1000 int len = strlen(cacheFileName) +1;
1001
1002 if (ptr + 4 + len + kSHA1DigestLen > buf + bufLen) {
1003 LOGE("DexOpt: overran buffer\n");
1004 dvmAbort();
1005 }
1006
1007 set4LE(ptr, len);
1008 ptr += 4;
1009 memcpy(ptr, cacheFileName, len);
1010 ptr += len;
1011 memcpy(ptr, signature, kSHA1DigestLen);
1012 ptr += kSHA1DigestLen;
1013 }
1014
1015 assert(ptr == buf + bufLen);
1016
1017 actual = write(fd, buf, bufLen);
1018 if (actual != bufLen) {
1019 result = (errno != 0) ? errno : -1;
1020 logFailedWrite(bufLen, actual, "dep info", errno);
1021 } else {
1022 result = 0;
1023 }
1024
1025 free(buf);
1026 return result;
1027}
1028
1029
1030/*
1031 * Write a block of data in "chunk" format.
1032 *
1033 * The chunk header fields are always in "native" byte order. If "size"
1034 * is not a multiple of 8 bytes, the data area is padded out.
1035 */
1036static bool writeChunk(int fd, u4 type, const void* data, size_t size)
1037{
1038 ssize_t actual;
1039 union { /* save a syscall by grouping these together */
1040 char raw[8];
1041 struct {
1042 u4 type;
1043 u4 size;
1044 } ts;
1045 } header;
1046
1047 assert(sizeof(header) == 8);
1048
1049 LOGV("Writing chunk, type=%.4s size=%d\n", (char*) &type, size);
1050
1051 header.ts.type = type;
1052 header.ts.size = (u4) size;
1053 actual = write(fd, &header, sizeof(header));
1054 if (actual != sizeof(header)) {
1055 logFailedWrite(size, actual, "aux chunk header write", errno);
1056 return false;
1057 }
1058
1059 if (size > 0) {
1060 actual = write(fd, data, size);
1061 if (actual != (ssize_t) size) {
1062 logFailedWrite(size, actual, "aux chunk write", errno);
1063 return false;
1064 }
1065 }
1066
1067 /* if necessary, pad to 64-bit alignment */
1068 if ((size & 7) != 0) {
1069 int padSize = 8 - (size & 7);
1070 LOGV("size was %d, inserting %d pad bytes\n", size, padSize);
1071 lseek(fd, padSize, SEEK_CUR);
1072 }
1073
1074 assert( ((int)lseek(fd, 0, SEEK_CUR) & 7) == 0);
1075
1076 return true;
1077}
1078
1079/*
1080 * Write aux data.
1081 *
1082 * We have different pieces, some of which may be optional. To make the
1083 * most effective use of space, we use a "chunk" format, with a 4-byte
1084 * type and a 4-byte length. We guarantee 64-bit alignment for the data,
1085 * so it can be used directly when the file is mapped for reading.
1086 */
1087static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,
1088 const IndexMapSet* pIndexMapSet)
1089{
1090 /* pre-computed class lookup hash table */
1091 if (!writeChunk(fd, (u4) kDexChunkClassLookup, pClassLookup,
1092 pClassLookup->size))
1093 {
1094 return false;
1095 }
1096
1097 /* remapped constants (optional) */
1098 if (pIndexMapSet != NULL) {
1099 if (!writeChunk(fd, pIndexMapSet->chunkType, pIndexMapSet->chunkData,
1100 pIndexMapSet->chunkDataLen))
1101 {
1102 return false;
1103 }
1104 }
1105
1106 /* write the end marker */
1107 if (!writeChunk(fd, (u4) kDexChunkEnd, NULL, 0)) {
1108 return false;
1109 }
1110
1111 return true;
1112}
1113
1114/*
1115 * Log a failed write.
1116 */
1117static void logFailedWrite(size_t expected, ssize_t actual, const char* msg,
1118 int err)
1119{
1120 LOGE("Write failed: %s (%d of %d): %s\n",
1121 msg, (int)actual, (int)expected, strerror(err));
1122}
1123
1124
1125/*
1126 * ===========================================================================
1127 * Optimizations
1128 * ===========================================================================
1129 */
1130
1131/*
1132 * Perform in-place rewrites on a memory-mapped DEX file.
1133 *
1134 * This happens in a short-lived child process, so we can go nutty with
1135 * loading classes and allocating memory.
1136 */
1137static bool rewriteDex(u1* addr, int len, bool doVerify, bool doOpt,
1138 u4* pHeaderFlags, DexClassLookup** ppClassLookup)
1139{
1140 u8 prepWhen, loadWhen, verifyWhen, optWhen;
1141 DvmDex* pDvmDex = NULL;
1142 bool result = false;
1143
1144 *pHeaderFlags = 0;
1145
1146 LOGV("+++ swapping bytes\n");
1147 if (dexFixByteOrdering(addr, len) != 0)
1148 goto bail;
1149#if __BYTE_ORDER != __LITTLE_ENDIAN
1150 *pHeaderFlags |= DEX_OPT_FLAG_BIG;
1151#endif
1152
1153 /*
1154 * Now that the DEX file can be read directly, create a DexFile for it.
1155 */
1156 if (dvmDexFileOpenPartial(addr, len, &pDvmDex) != 0) {
1157 LOGE("Unable to create DexFile\n");
1158 goto bail;
1159 }
1160
1161 /*
1162 * Create the class lookup table.
1163 */
1164 //startWhen = dvmGetRelativeTimeUsec();
1165 *ppClassLookup = dexCreateClassLookup(pDvmDex->pDexFile);
1166 if (*ppClassLookup == NULL)
1167 goto bail;
1168
1169 /*
1170 * Bail out early if they don't want The Works. The current implementation
1171 * doesn't fork a new process if this flag isn't set, so we really don't
1172 * want to continue on with the crazy class loading.
1173 */
1174 if (!doVerify && !doOpt) {
1175 result = true;
1176 goto bail;
1177 }
1178
1179 /* this is needed for the next part */
1180 pDvmDex->pDexFile->pClassLookup = *ppClassLookup;
1181
1182 prepWhen = dvmGetRelativeTimeUsec();
1183
1184 /*
1185 * Load all classes found in this DEX file. If they fail to load for
1186 * some reason, they won't get verified (which is as it should be).
1187 */
1188 if (!loadAllClasses(pDvmDex))
1189 goto bail;
1190 loadWhen = dvmGetRelativeTimeUsec();
1191
1192 /*
1193 * Verify all classes in the DEX file. Export the "is verified" flag
1194 * to the DEX file we're creating.
1195 */
1196 if (doVerify) {
1197 dvmVerifyAllClasses(pDvmDex->pDexFile);
1198 *pHeaderFlags |= DEX_FLAG_VERIFIED;
1199 }
1200 verifyWhen = dvmGetRelativeTimeUsec();
1201
1202 /*
1203 * Optimize the classes we successfully loaded. If the opt mode is
1204 * OPTIMIZE_MODE_VERIFIED, each class must have been successfully
1205 * verified or we'll skip it.
1206 */
1207#ifndef PROFILE_FIELD_ACCESS
1208 if (doOpt) {
1209 optimizeLoadedClasses(pDvmDex->pDexFile);
1210 *pHeaderFlags |= DEX_OPT_FLAG_FIELDS | DEX_OPT_FLAG_INVOCATIONS;
1211 }
1212#endif
1213 optWhen = dvmGetRelativeTimeUsec();
1214
1215 LOGD("DexOpt: load %dms, verify %dms, opt %dms\n",
1216 (int) (loadWhen - prepWhen) / 1000,
1217 (int) (verifyWhen - loadWhen) / 1000,
1218 (int) (optWhen - verifyWhen) / 1000);
1219
1220 result = true;
1221
1222bail:
1223 /* free up storage */
1224 dvmDexFileFree(pDvmDex);
1225
1226 return result;
1227}
1228
1229/*
1230 * Update the Adler-32 checksum stored in the DEX file. This covers the
1231 * swapped and optimized DEX data, but does not include the opt header
1232 * or auxillary data.
1233 */
1234static void updateChecksum(u1* addr, int len, DexHeader* pHeader)
1235{
1236 /*
1237 * Rewrite the checksum. We leave the SHA-1 signature alone.
1238 */
1239 uLong adler = adler32(0L, Z_NULL, 0);
1240 const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
1241
1242 adler = adler32(adler, addr + nonSum, len - nonSum);
1243 pHeader->checksum = adler;
1244}
1245
1246/*
1247 * Try to load all classes in the specified DEX. If they have some sort
1248 * of broken dependency, e.g. their superclass lives in a different DEX
1249 * that wasn't previously loaded into the bootstrap class path, loading
1250 * will fail. This is the desired behavior.
1251 *
1252 * We have no notion of class loader at this point, so we load all of
1253 * the classes with the bootstrap class loader. It turns out this has
1254 * exactly the behavior we want, and has no ill side effects because we're
1255 * running in a separate process and anything we load here will be forgotten.
1256 *
1257 * We set the CLASS_MULTIPLE_DEFS flag here if we see multiple definitions.
1258 * This works because we only call here as part of optimization / pre-verify,
1259 * not during verification as part of loading a class into a running VM.
1260 *
1261 * This returns "false" if the world is too screwed up to do anything
1262 * useful at all.
1263 */
1264static bool loadAllClasses(DvmDex* pDvmDex)
1265{
1266 u4 count = pDvmDex->pDexFile->pHeader->classDefsSize;
1267 u4 idx;
1268 int loaded = 0;
1269
1270 LOGV("DexOpt: +++ trying to load %d classes\n", count);
1271
1272 dvmSetBootPathExtraDex(pDvmDex);
1273
1274 /*
1275 * We have some circularity issues with Class and Object that are most
1276 * easily avoided by ensuring that Object is never the first thing we
1277 * try to find. Take care of that here. (We only need to do this when
1278 * loading classes from the DEX file that contains Object, and only
1279 * when Object comes first in the list, but it costs very little to
1280 * do it in all cases.)
1281 */
1282 if (dvmFindSystemClass("Ljava/lang/Class;") == NULL) {
1283 LOGE("ERROR: java.lang.Class does not exist!\n");
1284 return false;
1285 }
1286
1287 for (idx = 0; idx < count; idx++) {
1288 const DexClassDef* pClassDef;
1289 const char* classDescriptor;
1290 ClassObject* newClass;
1291
1292 pClassDef = dexGetClassDef(pDvmDex->pDexFile, idx);
1293 classDescriptor =
1294 dexStringByTypeIdx(pDvmDex->pDexFile, pClassDef->classIdx);
1295
1296 LOGV("+++ loading '%s'", classDescriptor);
1297 //newClass = dvmDefineClass(pDexFile, classDescriptor,
1298 // NULL);
1299 newClass = dvmFindSystemClassNoInit(classDescriptor);
1300 if (newClass == NULL) {
1301 LOGV("DexOpt: failed loading '%s'\n", classDescriptor);
1302 dvmClearOptException(dvmThreadSelf());
1303 } else if (newClass->pDvmDex != pDvmDex) {
1304 /*
1305 * We don't load the new one, and we tag the first one found
1306 * with the "multiple def" flag so the resolver doesn't try
1307 * to make it available.
1308 */
1309 LOGD("DexOpt: '%s' has an earlier definition; blocking out\n",
1310 classDescriptor);
1311 SET_CLASS_FLAG(newClass, CLASS_MULTIPLE_DEFS);
1312 } else {
1313 loaded++;
1314 }
1315 }
1316 LOGV("DexOpt: +++ successfully loaded %d classes\n", loaded);
1317
1318 dvmSetBootPathExtraDex(NULL);
1319 return true;
1320}
1321
1322
1323/*
1324 * Create a table of inline substitutions.
1325 *
1326 * TODO: this is currently just a linear array. We will want to put this
1327 * into a hash table as the list size increases.
1328 */
1329static InlineSub* createInlineSubsTable(void)
1330{
1331 const InlineOperation* ops = dvmGetInlineOpsTable();
1332 const int count = dvmGetInlineOpsTableLength();
1333 InlineSub* table;
1334 Method* method;
1335 ClassObject* clazz;
1336 int i, tableIndex;
1337
1338 /*
1339 * Allocate for optimism: one slot per entry, plus an end-of-list marker.
1340 */
1341 table = malloc(sizeof(InlineSub) * (count+1));
1342
1343 tableIndex = 0;
1344 for (i = 0; i < count; i++) {
1345 clazz = dvmFindClassNoInit(ops[i].classDescriptor, NULL);
1346 if (clazz == NULL) {
1347 LOGV("DexOpt: can't inline for class '%s': not found\n",
1348 ops[i].classDescriptor);
1349 dvmClearOptException(dvmThreadSelf());
1350 } else {
1351 /*
1352 * Method could be virtual or direct. Try both. Don't use
1353 * the "hier" versions.
1354 */
1355 method = dvmFindDirectMethodByDescriptor(clazz, ops[i].methodName,
1356 ops[i].methodSignature);
1357 if (method == NULL)
1358 method = dvmFindVirtualMethodByDescriptor(clazz, ops[i].methodName,
1359 ops[i].methodSignature);
1360 if (method == NULL) {
1361 LOGW("DexOpt: can't inline %s.%s %s: method not found\n",
1362 ops[i].classDescriptor, ops[i].methodName,
1363 ops[i].methodSignature);
1364 } else {
1365 if (!dvmIsFinalClass(clazz) && !dvmIsFinalMethod(method)) {
1366 LOGW("DexOpt: WARNING: inline op on non-final class/method "
1367 "%s.%s\n",
1368 clazz->descriptor, method->name);
1369 /* fail? */
1370 }
1371 if (dvmIsSynchronizedMethod(method) ||
1372 dvmIsDeclaredSynchronizedMethod(method))
1373 {
1374 LOGW("DexOpt: WARNING: inline op on synchronized method "
1375 "%s.%s\n",
1376 clazz->descriptor, method->name);
1377 /* fail? */
1378 }
1379
1380 table[tableIndex].method = method;
1381 table[tableIndex].inlineIdx = i;
1382 tableIndex++;
1383
1384 LOGV("DexOpt: will inline %d: %s.%s %s\n", i,
1385 ops[i].classDescriptor, ops[i].methodName,
1386 ops[i].methodSignature);
1387 }
1388 }
1389 }
1390
1391 /* mark end of table */
1392 table[tableIndex].method = NULL;
1393 LOGV("DexOpt: inline table has %d entries\n", tableIndex);
1394
1395 return table;
1396}
1397
1398/*
1399 * Run through all classes that were successfully loaded from this DEX
1400 * file and optimize their code sections.
1401 */
1402static void optimizeLoadedClasses(DexFile* pDexFile)
1403{
1404 u4 count = pDexFile->pHeader->classDefsSize;
1405 u4 idx;
1406 InlineSub* inlineSubs = NULL;
1407
1408 LOGV("DexOpt: +++ optimizing up to %d classes\n", count);
1409 assert(gDvm.dexOptMode != OPTIMIZE_MODE_NONE);
1410
1411 inlineSubs = createInlineSubsTable();
1412
1413 for (idx = 0; idx < count; idx++) {
1414 const DexClassDef* pClassDef;
1415 const char* classDescriptor;
1416 ClassObject* clazz;
1417
1418 pClassDef = dexGetClassDef(pDexFile, idx);
1419 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
1420
1421 /* all classes are loaded into the bootstrap class loader */
1422 clazz = dvmLookupClass(classDescriptor, NULL, false);
1423 if (clazz != NULL) {
1424 if ((pClassDef->accessFlags & CLASS_ISPREVERIFIED) == 0 &&
1425 gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
1426 {
1427 LOGV("DexOpt: not optimizing '%s': not verified\n",
1428 classDescriptor);
1429 } else if (clazz->pDvmDex->pDexFile != pDexFile) {
1430 /* shouldn't be here -- verifier should have caught */
1431 LOGD("DexOpt: not optimizing '%s': multiple definitions\n",
1432 classDescriptor);
1433 } else {
1434 optimizeClass(clazz, inlineSubs);
1435
1436 /* set the flag whether or not we actually did anything */
1437 ((DexClassDef*)pClassDef)->accessFlags |=
1438 CLASS_ISOPTIMIZED;
1439 }
1440 } else {
1441 LOGV("DexOpt: not optimizing unavailable class '%s'\n",
1442 classDescriptor);
1443 }
1444 }
1445
1446 free(inlineSubs);
1447}
1448
1449/*
1450 * Optimize the specified class.
1451 */
1452static void optimizeClass(ClassObject* clazz, const InlineSub* inlineSubs)
1453{
1454 int i;
1455
1456 for (i = 0; i < clazz->directMethodCount; i++) {
1457 if (!optimizeMethod(&clazz->directMethods[i], inlineSubs))
1458 goto fail;
1459 }
1460 for (i = 0; i < clazz->virtualMethodCount; i++) {
1461 if (!optimizeMethod(&clazz->virtualMethods[i], inlineSubs))
1462 goto fail;
1463 }
1464
1465 return;
1466
1467fail:
1468 LOGV("DexOpt: ceasing optimization attempts on %s\n", clazz->descriptor);
1469}
1470
1471/*
1472 * Optimize instructions in a method.
1473 *
1474 * Returns "true" if all went well, "false" if we bailed out early when
1475 * something failed.
1476 */
1477static bool optimizeMethod(Method* method, const InlineSub* inlineSubs)
1478{
1479 u4 insnsSize;
1480 u2* insns;
1481 u2 inst;
1482
1483 if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
1484 return true;
1485
1486 insns = (u2*) method->insns;
1487 assert(insns != NULL);
1488 insnsSize = dvmGetMethodInsnsSize(method);
1489
1490 while (insnsSize > 0) {
1491 int width;
1492
1493 inst = *insns & 0xff;
1494
1495 switch (inst) {
1496 case OP_IGET:
1497 case OP_IGET_BOOLEAN:
1498 case OP_IGET_BYTE:
1499 case OP_IGET_CHAR:
1500 case OP_IGET_SHORT:
1501 rewriteInstField(method, insns, OP_IGET_QUICK);
1502 break;
1503 case OP_IGET_WIDE:
1504 rewriteInstField(method, insns, OP_IGET_WIDE_QUICK);
1505 break;
1506 case OP_IGET_OBJECT:
1507 rewriteInstField(method, insns, OP_IGET_OBJECT_QUICK);
1508 break;
1509 case OP_IPUT:
1510 case OP_IPUT_BOOLEAN:
1511 case OP_IPUT_BYTE:
1512 case OP_IPUT_CHAR:
1513 case OP_IPUT_SHORT:
1514 rewriteInstField(method, insns, OP_IPUT_QUICK);
1515 break;
1516 case OP_IPUT_WIDE:
1517 rewriteInstField(method, insns, OP_IPUT_WIDE_QUICK);
1518 break;
1519 case OP_IPUT_OBJECT:
1520 rewriteInstField(method, insns, OP_IPUT_OBJECT_QUICK);
1521 break;
1522
1523 case OP_INVOKE_VIRTUAL:
1524 if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL,inlineSubs))
1525 {
1526 if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_VIRTUAL_QUICK))
1527 return false;
1528 }
1529 break;
1530 case OP_INVOKE_VIRTUAL_RANGE:
1531 if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_VIRTUAL_QUICK_RANGE))
1532 return false;
1533 break;
1534 case OP_INVOKE_SUPER:
1535 if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK))
1536 return false;
1537 break;
1538 case OP_INVOKE_SUPER_RANGE:
1539 if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE))
1540 return false;
1541 break;
1542
1543 case OP_INVOKE_DIRECT:
1544 if (!rewriteExecuteInline(method, insns, METHOD_DIRECT, inlineSubs))
1545 {
1546 if (!rewriteDirectInvoke(method, insns))
1547 return false;
1548 }
1549 break;
1550 case OP_INVOKE_STATIC:
1551 rewriteExecuteInline(method, insns, METHOD_STATIC, inlineSubs);
1552 break;
1553
1554 default:
1555 // ignore this instruction
1556 ;
1557 }
1558
1559 if (*insns == kPackedSwitchSignature) {
1560 width = 4 + insns[1] * 2;
1561 } else if (*insns == kSparseSwitchSignature) {
1562 width = 2 + insns[1] * 4;
1563 } else if (*insns == kArrayDataSignature) {
1564 u2 elemWidth = insns[1];
1565 u4 len = insns[2] | (((u4)insns[3]) << 16);
1566 width = 4 + (elemWidth * len + 1) / 2;
1567 } else {
1568 width = dexGetInstrWidth(gDvm.instrWidth, inst);
1569 }
1570 assert(width > 0);
1571
1572 insns += width;
1573 insnsSize -= width;
1574 }
1575
1576 assert(insnsSize == 0);
1577 return true;
1578}
1579
1580
1581/*
1582 * If "referrer" and "resClass" don't come from the same DEX file, and
1583 * the DEX we're working on is not destined for the bootstrap class path,
1584 * tweak the class loader so package-access checks work correctly.
1585 *
1586 * Only do this if we're doing pre-verification or optimization.
1587 */
1588static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
1589{
1590 if (!gDvm.optimizing)
1591 return;
1592 assert(referrer->classLoader == NULL);
1593 assert(resClass->classLoader == NULL);
1594
1595 if (!gDvm.optimizingBootstrapClass) {
1596 /* class loader for an array class comes from element type */
1597 if (dvmIsArrayClass(resClass))
1598 resClass = resClass->elementClass;
1599 if (referrer->pDvmDex != resClass->pDvmDex)
1600 resClass->classLoader = (Object*) 0xdead3333;
1601 }
1602}
1603
1604/*
1605 * Undo the effects of tweakLoader.
1606 */
1607static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
1608{
1609 if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
1610 return;
1611
1612 if (dvmIsArrayClass(resClass))
1613 resClass = resClass->elementClass;
1614 resClass->classLoader = NULL;
1615}
1616
1617
1618/*
1619 * Alternate version of dvmResolveClass for use with verification and
1620 * optimization. Performs access checks on every resolve, and refuses
1621 * to acknowledge the existence of classes defined in more than one DEX
1622 * file.
1623 *
1624 * Exceptions caused by failures are cleared before returning.
1625 */
1626ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx)
1627{
1628 DvmDex* pDvmDex = referrer->pDvmDex;
1629 ClassObject* resClass;
1630
1631 /*
1632 * Check the table first. If not there, do the lookup by name.
1633 */
1634 resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
1635 if (resClass == NULL) {
1636 const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
1637 if (className[0] != '\0' && className[1] == '\0') {
1638 /* primitive type */
1639 resClass = dvmFindPrimitiveClass(className[0]);
1640 } else {
1641 resClass = dvmFindClassNoInit(className, referrer->classLoader);
1642 }
1643 if (resClass == NULL) {
1644 /* not found, exception should be raised */
1645 LOGV("DexOpt: class %d (%s) not found\n",
1646 classIdx,
1647 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
1648 dvmClearOptException(dvmThreadSelf());
1649 return NULL;
1650 }
1651
1652 /*
1653 * Add it to the resolved table so we're faster on the next lookup.
1654 */
1655 dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
1656 }
1657
1658 /* multiple definitions? */
1659 if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
1660 LOGI("DexOpt: not resolving ambiguous class '%s'\n",
1661 resClass->descriptor);
1662 return NULL;
1663 }
1664
1665 /* access allowed? */
1666 tweakLoader(referrer, resClass);
1667 bool allowed = dvmCheckClassAccess(referrer, resClass);
1668 untweakLoader(referrer, resClass);
1669 if (!allowed) {
1670 LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
1671 referrer->descriptor, resClass->descriptor);
1672 return NULL;
1673 }
1674
1675 return resClass;
1676}
1677
1678/*
1679 * Alternate version of dvmResolveInstField().
1680 */
1681InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx)
1682{
1683 DvmDex* pDvmDex = referrer->pDvmDex;
1684 InstField* resField;
1685
1686 resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
1687 if (resField == NULL) {
1688 const DexFieldId* pFieldId;
1689 ClassObject* resClass;
1690
1691 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
1692
1693 /*
1694 * Find the field's class.
1695 */
1696 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx);
1697 if (resClass == NULL) {
1698 //dvmClearOptException(dvmThreadSelf());
1699 assert(!dvmCheckException(dvmThreadSelf()));
1700 return NULL;
1701 }
1702
1703 resField = dvmFindInstanceFieldHier(resClass,
1704 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
1705 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
1706 if (resField == NULL) {
1707 LOGD("DexOpt: couldn't find field %s.%s\n",
1708 resClass->descriptor,
1709 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
1710 return NULL;
1711 }
1712
1713 /*
1714 * Add it to the resolved table so we're faster on the next lookup.
1715 */
1716 dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
1717 }
1718
1719 /* access allowed? */
1720 tweakLoader(referrer, resField->field.clazz);
1721 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
1722 untweakLoader(referrer, resField->field.clazz);
1723 if (!allowed) {
1724 LOGI("DexOpt: access denied from %s to field %s.%s\n",
1725 referrer->descriptor, resField->field.clazz->descriptor,
1726 resField->field.name);
1727 return NULL;
1728 }
1729
1730 return resField;
1731}
1732
1733/*
1734 * Alternate version of dvmResolveStaticField().
1735 *
1736 * Does not force initialization of the resolved field's class.
1737 */
1738StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx)
1739{
1740 DvmDex* pDvmDex = referrer->pDvmDex;
1741 StaticField* resField;
1742
1743 resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
1744 if (resField == NULL) {
1745 const DexFieldId* pFieldId;
1746 ClassObject* resClass;
1747
1748 pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
1749
1750 /*
1751 * Find the field's class.
1752 */
1753 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx);
1754 if (resClass == NULL) {
1755 //dvmClearOptException(dvmThreadSelf());
1756 assert(!dvmCheckException(dvmThreadSelf()));
1757 return NULL;
1758 }
1759
1760 resField = dvmFindStaticFieldHier(resClass,
1761 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
1762 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
1763 if (resField == NULL) {
1764 LOGD("DexOpt: couldn't find static field\n");
1765 return NULL;
1766 }
1767
1768 /*
1769 * Add it to the resolved table so we're faster on the next lookup.
1770 *
1771 * We can only do this if we're in "dexopt", because the presence
1772 * of a valid value in the resolution table implies that the class
1773 * containing the static field has been initialized.
1774 */
1775 if (gDvm.optimizing)
1776 dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
1777 }
1778
1779 /* access allowed? */
1780 tweakLoader(referrer, resField->field.clazz);
1781 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
1782 untweakLoader(referrer, resField->field.clazz);
1783 if (!allowed) {
1784 LOGI("DexOpt: access denied from %s to field %s.%s\n",
1785 referrer->descriptor, resField->field.clazz->descriptor,
1786 resField->field.name);
1787 return NULL;
1788 }
1789
1790 return resField;
1791}
1792
1793
1794/*
1795 * Rewrite an iget/iput instruction. These all have the form:
1796 * op vA, vB, field@CCCC
1797 *
1798 * Where vA holds the value, vB holds the object reference, and CCCC is
1799 * the field reference constant pool offset. We want to replace CCCC
1800 * with the byte offset from the start of the object.
1801 *
1802 * "clazz" is the referring class. We need this because we verify
1803 * access rights here.
1804 */
1805static void rewriteInstField(Method* method, u2* insns, OpCode newOpc)
1806{
1807 ClassObject* clazz = method->clazz;
1808 u2 fieldIdx = insns[1];
1809 InstField* field;
1810 int byteOffset;
1811
1812 field = dvmOptResolveInstField(clazz, fieldIdx);
1813 if (field == NULL) {
1814 LOGI("DexOpt: unable to optimize field ref 0x%04x at 0x%02x in %s.%s\n",
1815 fieldIdx, (int) (insns - method->insns), clazz->descriptor,
1816 method->name);
1817 return;
1818 }
1819
1820 if (field->byteOffset >= 65536) {
1821 LOGI("DexOpt: field offset exceeds 64K (%d)\n", field->byteOffset);
1822 return;
1823 }
1824
1825 insns[0] = (insns[0] & 0xff00) | (u2) newOpc;
1826 insns[1] = (u2) field->byteOffset;
1827 LOGVV("DexOpt: rewrote access to %s.%s --> %d\n",
1828 field->field.clazz->descriptor, field->field.name,
1829 field->byteOffset);
1830}
1831
1832/*
1833 * Alternate version of dvmResolveMethod().
1834 *
1835 * Doesn't throw exceptions, and checks access on every lookup.
1836 */
1837Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
1838 MethodType methodType)
1839{
1840 DvmDex* pDvmDex = referrer->pDvmDex;
1841 Method* resMethod;
1842
1843 assert(methodType != METHOD_INTERFACE);
1844
1845 LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
1846 referrer->descriptor);
1847
1848 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
1849 if (resMethod == NULL) {
1850 const DexMethodId* pMethodId;
1851 ClassObject* resClass;
1852
1853 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
1854
1855 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx);
1856 if (resClass == NULL) {
1857 /* can't find the class that the method is a part of */
1858 LOGV("DexOpt: can't find called method's class (?.%s)\n",
1859 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
1860 return NULL;
1861 }
1862 if (dvmIsInterfaceClass(resClass)) {
1863 /* method is part of an interface; this is wrong method for that */
1864 LOGW("DexOpt: method is in an interface\n");
1865 return NULL;
1866 }
1867
1868 /*
1869 * We need to chase up the class hierarchy to find methods defined
1870 * in super-classes. (We only want to check the current class
1871 * if we're looking for a constructor.)
1872 */
1873 DexProto proto;
1874 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
1875
1876 if (methodType == METHOD_DIRECT) {
1877 resMethod = dvmFindDirectMethod(resClass,
1878 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
1879 } else if (methodType == METHOD_STATIC) {
1880 resMethod = dvmFindDirectMethodHier(resClass,
1881 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
1882 } else {
1883 resMethod = dvmFindVirtualMethodHier(resClass,
1884 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
1885 }
1886
1887 if (resMethod == NULL) {
1888 LOGV("DexOpt: couldn't find method '%s'\n",
1889 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
1890 return NULL;
1891 }
1892
1893 /* see if this is a pure-abstract method */
1894 if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
1895 LOGW("DexOpt: pure-abstract method '%s' in %s\n",
1896 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
1897 resClass->descriptor);
1898 return NULL;
1899 }
1900
1901 /*
1902 * Add it to the resolved table so we're faster on the next lookup.
1903 *
1904 * We can only do this for static methods if we're not in "dexopt",
1905 * because the presence of a valid value in the resolution table
1906 * implies that the class containing the static field has been
1907 * initialized.
1908 */
1909 if (methodType != METHOD_STATIC || gDvm.optimizing)
1910 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
1911 }
1912
1913 LOGVV("--- found method %d (%s.%s)\n",
1914 methodIdx, resMethod->clazz->descriptor, resMethod->name);
1915
1916 /* access allowed? */
1917 tweakLoader(referrer, resMethod->clazz);
1918 bool allowed = dvmCheckMethodAccess(referrer, resMethod);
1919 untweakLoader(referrer, resMethod->clazz);
1920 if (!allowed) {
1921 IF_LOGI() {
1922 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1923 LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n",
1924 resMethod->clazz->descriptor, resMethod->name, desc,
1925 referrer->descriptor);
1926 free(desc);
1927 }
1928 return NULL;
1929 }
1930
1931 return resMethod;
1932}
1933
1934/*
1935 * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
1936 * invoke-super/range. These all have the form:
1937 * op vAA, meth@BBBB, reg stuff @CCCC
1938 *
1939 * We want to replace the method constant pool index BBBB with the
1940 * vtable index.
1941 */
1942static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc)
1943{
1944 ClassObject* clazz = method->clazz;
1945 Method* baseMethod;
1946 u2 methodIdx = insns[1];
1947
1948 baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL);
1949 if (baseMethod == NULL) {
1950 LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n",
1951 methodIdx,
1952 (int) (insns - method->insns), clazz->descriptor,
1953 method->name);
1954 return false;
1955 }
1956
1957 assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
1958 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
1959 (insns[0] & 0xff) == OP_INVOKE_SUPER ||
1960 (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
1961
1962 /*
1963 * Note: Method->methodIndex is a u2 and is range checked during the
1964 * initial load.
1965 */
1966 insns[0] = (insns[0] & 0xff00) | (u2) newOpc;
1967 insns[1] = baseMethod->methodIndex;
1968
1969 //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s\n",
1970 // method->clazz->descriptor, method->name,
1971 // baseMethod->clazz->descriptor, baseMethod->name);
1972
1973 return true;
1974}
1975
1976/*
1977 * Rewrite invoke-direct, which has the form:
1978 * op vAA, meth@BBBB, reg stuff @CCCC
1979 *
1980 * There isn't a lot we can do to make this faster, but in some situations
1981 * we can make it go away entirely.
1982 *
1983 * This must only be used when the invoked method does nothing and has
1984 * no return value (the latter being very important for verification).
1985 */
1986static bool rewriteDirectInvoke(Method* method, u2* insns)
1987{
1988 ClassObject* clazz = method->clazz;
1989 Method* calledMethod;
1990 u2 methodIdx = insns[1];
1991
1992 calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT);
1993 if (calledMethod == NULL) {
1994 LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n",
1995 methodIdx,
1996 (int) (insns - method->insns), clazz->descriptor,
1997 method->name);
1998 return false;
1999 }
2000
2001 /* TODO: verify that java.lang.Object() is actually empty! */
2002 if (calledMethod->clazz == gDvm.classJavaLangObject &&
2003 dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
2004 {
2005 /*
2006 * Replace with "empty" instruction. DO NOT disturb anything
2007 * else about it, as we want it to function the same as
2008 * OP_INVOKE_DIRECT when debugging is enabled.
2009 */
2010 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT);
2011 insns[0] = (insns[0] & 0xff00) | (u2) OP_INVOKE_DIRECT_EMPTY;
2012
2013 //LOGI("DexOpt: marked-empty call to %s.%s --> %s.%s\n",
2014 // method->clazz->descriptor, method->name,
2015 // calledMethod->clazz->descriptor, calledMethod->name);
2016 }
2017
2018 return true;
2019}
2020
2021/*
2022 * Resolve an interface method reference.
2023 *
2024 * Returns NULL if the method was not found. Does not throw an exception.
2025 */
2026Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
2027{
2028 DvmDex* pDvmDex = referrer->pDvmDex;
2029 Method* resMethod;
2030 int i;
2031
2032 LOGVV("--- resolving interface method %d (referrer=%s)\n",
2033 methodIdx, referrer->descriptor);
2034
2035 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
2036 if (resMethod == NULL) {
2037 const DexMethodId* pMethodId;
2038 ClassObject* resClass;
2039
2040 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
2041
2042 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx);
2043 if (resClass == NULL) {
2044 /* can't find the class that the method is a part of */
2045 dvmClearOptException(dvmThreadSelf());
2046 return NULL;
2047 }
2048 if (!dvmIsInterfaceClass(resClass)) {
2049 /* whoops */
2050 LOGI("Interface method not part of interface class\n");
2051 return NULL;
2052 }
2053
2054 const char* methodName =
2055 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
2056 DexProto proto;
2057 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
2058
2059 LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
2060 methodName, methodSig, resClass->descriptor);
2061 resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
2062 if (resMethod == NULL) {
2063 /* scan superinterfaces and superclass interfaces */
2064 LOGVV("+++ did not resolve immediately\n");
2065 for (i = 0; i < resClass->iftableCount; i++) {
2066 resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
2067 methodName, &proto);
2068 if (resMethod != NULL)
2069 break;
2070 }
2071
2072 if (resMethod == NULL) {
2073 LOGVV("+++ unable to resolve method %s\n", methodName);
2074 return NULL;
2075 }
2076 } else {
2077 LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
2078 resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
2079 }
2080
2081 /* we're expecting this to be abstract */
2082 if (!dvmIsAbstractMethod(resMethod)) {
2083 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
2084 LOGW("Found non-abstract interface method %s.%s %s\n",
2085 resMethod->clazz->descriptor, resMethod->name, desc);
2086 free(desc);
2087 return NULL;
2088 }
2089
2090 /*
2091 * Add it to the resolved table so we're faster on the next lookup.
2092 */
2093 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
2094 }
2095
2096 LOGVV("--- found interface method %d (%s.%s)\n",
2097 methodIdx, resMethod->clazz->descriptor, resMethod->name);
2098
2099 /* interface methods are always public; no need to check access */
2100
2101 return resMethod;
2102}
2103/*
2104 * See if the method being called can be rewritten as an inline operation.
2105 * Works for invoke-virtual, invoke-direct, and invoke-static.
2106 *
2107 * Returns "true" if we replace it.
2108 */
2109static bool rewriteExecuteInline(Method* method, u2* insns,
2110 MethodType methodType, const InlineSub* inlineSubs)
2111{
2112 ClassObject* clazz = method->clazz;
2113 Method* calledMethod;
2114 u2 methodIdx = insns[1];
2115
2116 //return false;
2117
2118 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType);
2119 if (calledMethod == NULL) {
2120 LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
2121 return false;
2122 }
2123
2124 while (inlineSubs->method != NULL) {
2125 /*
2126 if (extra) {
2127 LOGI("comparing %p vs %p %s.%s %s\n",
2128 inlineSubs->method, calledMethod,
2129 inlineSubs->method->clazz->descriptor,
2130 inlineSubs->method->name,
2131 inlineSubs->method->signature);
2132 }
2133 */
2134 if (inlineSubs->method == calledMethod) {
2135 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
2136 (insns[0] & 0xff) == OP_INVOKE_STATIC ||
2137 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
2138 insns[0] = (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE;
2139 insns[1] = (u2) inlineSubs->inlineIdx;
2140
2141 //LOGI("DexOpt: execute-inline %s.%s --> %s.%s\n",
2142 // method->clazz->descriptor, method->name,
2143 // calledMethod->clazz->descriptor, calledMethod->name);
2144 return true;
2145 }
2146
2147 inlineSubs++;
2148 }
2149
2150 return false;
2151}
2152