• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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