OSDN Git Service

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