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