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