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