const DexClassDef* pClassDef, bool doVerify, bool doOpt);
static void updateChecksum(u1* addr, int len, DexHeader* pHeader);
static int writeDependencies(int fd, u4 modWhen, u4 crc);
-static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,\
- const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder);
+static bool writeOptData(int fd, const DexClassLookup* pClassLookup,\
+ const RegisterMapBuilder* pRegMapBuilder);
static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
* changes doing anything" purposes its best if we just make
* everything crash when a DEX they're using gets updated.
*/
- LOGD("Stale deps in cache file; removing and retrying\n");
+ LOGD("ODEX file is stale or bad; removing and retrying (%s)\n",
+ cacheFileName);
if (ftruncate(fd, 0) != 0) {
LOGW("Warning: unable to truncate cache file '%s': %s\n",
cacheFileName, strerror(errno));
const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
{
DexClassLookup* pClassLookup = NULL;
- IndexMapSet* pIndexMapSet = NULL;
RegisterMapBuilder* pRegMapBuilder = NULL;
u4 headerFlags = 0;
success = false;
} else {
/*
- * If configured to do so, scan the instructions, looking
- * for ways to reduce the size of the resolved-constant table.
- * This is done post-optimization, across the instructions
- * in all methods in all classes (even the ones that failed
- * to load).
- */
- pIndexMapSet = dvmRewriteConstants(pDvmDex);
-
- /*
* If configured to do so, generate register map output
* for all verified classes. The register maps were
* generated during verification, and will now be serialized.
}
/* get start offset, and adjust deps start for 64-bit alignment */
- off_t depsOffset, auxOffset, endOffset, adjOffset;
- int depsLength, auxLength;
+ off_t depsOffset, optOffset, endOffset, adjOffset;
+ int depsLength, optLength;
u4 optChecksum;
depsOffset = lseek(fd, 0, SEEK_END);
goto bail;
}
- /* compute deps length, then adjust aux start for 64-bit alignment */
- auxOffset = lseek(fd, 0, SEEK_END);
- depsLength = auxOffset - depsOffset;
+ /* compute deps length, then adjust opt start for 64-bit alignment */
+ optOffset = lseek(fd, 0, SEEK_END);
+ depsLength = optOffset - depsOffset;
- adjOffset = (auxOffset + 7) & ~(0x07);
- if (adjOffset != auxOffset) {
- LOGV("Adjusting aux start from %d to %d\n",
- (int) auxOffset, (int) adjOffset);
- auxOffset = adjOffset;
- lseek(fd, auxOffset, SEEK_SET);
+ adjOffset = (optOffset + 7) & ~(0x07);
+ if (adjOffset != optOffset) {
+ LOGV("Adjusting opt start from %d to %d\n",
+ (int) optOffset, (int) adjOffset);
+ optOffset = adjOffset;
+ lseek(fd, optOffset, SEEK_SET);
}
/*
- * Append any auxillary pre-computed data structures.
+ * Append any optimized pre-computed data structures.
*/
- if (!writeAuxData(fd, pClassLookup, pIndexMapSet, pRegMapBuilder)) {
- LOGW("Failed writing aux data\n");
+ if (!writeOptData(fd, pClassLookup, pRegMapBuilder)) {
+ LOGW("Failed writing opt data\n");
goto bail;
}
endOffset = lseek(fd, 0, SEEK_END);
- auxLength = endOffset - auxOffset;
+ optLength = endOffset - optOffset;
- /* compute checksum from start of deps to end of aux area */
+ /* compute checksum from start of deps to end of opt area */
if (!computeFileChecksum(fd, depsOffset,
- (auxOffset+auxLength) - depsOffset, &optChecksum))
+ (optOffset+optLength) - depsOffset, &optChecksum))
{
goto bail;
}
optHdr.dexLength = (u4) dexLength;
optHdr.depsOffset = (u4) depsOffset;
optHdr.depsLength = (u4) depsLength;
- optHdr.auxOffset = (u4) auxOffset;
- optHdr.auxLength = (u4) auxLength;
+ optHdr.optOffset = (u4) optOffset;
+ optHdr.optLength = (u4) optLength;
optHdr.flags = headerFlags;
optHdr.checksum = optChecksum;
+ fsync(fd); /* ensure previous writes go before header is written */
+
lseek(fd, 0, SEEK_SET);
if (sysWriteFully(fd, &optHdr, sizeof(optHdr), "DexOpt opt header") != 0)
goto bail;
//dvmRegisterMapDumpStats();
bail:
- dvmFreeIndexMapSet(pIndexMapSet);
dvmFreeRegisterMapBuilder(pRegMapBuilder);
free(pClassLookup);
return result;
const char* classDescriptor;
bool verified = false;
+ if (clazz->pDvmDex->pDexFile != pDexFile) {
+ /*
+ * The current DEX file defined a class that is also present in the
+ * bootstrap class path. The class loader favored the bootstrap
+ * version, which means that we have a pointer to a class that is
+ * (a) not the one we want to examine, and (b) mapped read-only,
+ * so we will seg fault if we try to rewrite instructions inside it.
+ */
+ LOGD("DexOpt: not verifying/optimizing '%s': multiple definitions\n",
+ clazz->descriptor);
+ return;
+ }
+
classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
/*
* First, try to verify it.
*/
if (doVerify) {
- if (clazz->pDvmDex->pDexFile != pDexFile) {
- LOGD("DexOpt: not verifying '%s': multiple definitions\n",
- classDescriptor);
+ if (dvmVerifyClass(clazz)) {
+ /*
+ * Set the "is preverified" flag in the DexClassDef. We
+ * do it here, rather than in the ClassObject structure,
+ * because the DexClassDef is part of the odex file.
+ */
+ assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
+ pClassDef->accessFlags);
+ ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISPREVERIFIED;
+ verified = true;
} else {
- if (dvmVerifyClass(clazz)) {
- /*
- * Set the "is preverified" flag in the DexClassDef. We
- * do it here, rather than in the ClassObject structure,
- * because the DexClassDef is part of the odex file.
- */
- assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
- pClassDef->accessFlags);
- ((DexClassDef*)pClassDef)->accessFlags |= CLASS_ISPREVERIFIED;
- verified = true;
- } else {
- // TODO: log when in verbose mode
- LOGV("DexOpt: '%s' failed verification\n", classDescriptor);
- }
+ // TODO: log when in verbose mode
+ LOGV("DexOpt: '%s' failed verification\n", classDescriptor);
}
}
* Read and do trivial verification on the opt header. The header is
* always in host byte order.
*/
- if (read(fd, &optHdr, sizeof(optHdr)) != sizeof(optHdr)) {
+ actual = read(fd, &optHdr, sizeof(optHdr));
+ if (actual < 0) {
LOGE("DexOpt: failed reading opt header: %s\n", strerror(errno));
goto bail;
+ } else if (actual != sizeof(optHdr)) {
+ LOGE("DexOpt: failed reading opt header (got %d of %zd)\n",
+ (int) actual, sizeof(optHdr));
+ goto bail;
}
magic = optHdr.magic;
- if (memcmp(magic, DEX_OPT_MAGIC, 4) != 0) {
+ if (memcmp(magic, DEX_MAGIC, 4) == 0) {
+ /* somebody probably pointed us at the wrong file */
+ LOGD("DexOpt: expected optimized DEX, found unoptimized\n");
+ goto bail;
+ } else if (memcmp(magic, DEX_OPT_MAGIC, 4) != 0) {
/* not a DEX file, or previous attempt was interrupted */
LOGD("DexOpt: incorrect opt magic number (0x%02x %02x %02x %02x)\n",
magic[0], magic[1], magic[2], magic[3]);
goto bail;
}
actual = read(fd, depData, optHdr.depsLength);
- if (actual != (ssize_t) optHdr.depsLength) {
- LOGW("DexOpt: failed reading deps: %d of %d (err=%s)\n",
- (int) actual, optHdr.depsLength, strerror(errno));
+ if (actual < 0) {
+ LOGW("DexOpt: failed reading deps: %s\n", strerror(errno));
+ goto bail;
+ } else if (actual != (ssize_t) optHdr.depsLength) {
+ LOGW("DexOpt: failed reading deps: got %d of %d\n",
+ (int) actual, optHdr.depsLength);
goto bail;
}
header.ts.type = type;
header.ts.size = (u4) size;
if (sysWriteFully(fd, &header, sizeof(header),
- "DexOpt aux chunk header write") != 0)
+ "DexOpt opt chunk header write") != 0)
{
return false;
}
if (size > 0) {
- if (sysWriteFully(fd, data, size, "DexOpt aux chunk write") != 0)
+ if (sysWriteFully(fd, data, size, "DexOpt opt chunk write") != 0)
return false;
}
}
/*
- * Write aux data.
+ * Write opt data.
*
* We have different pieces, some of which may be optional. To make the
* most effective use of space, we use a "chunk" format, with a 4-byte
* type and a 4-byte length. We guarantee 64-bit alignment for the data,
* so it can be used directly when the file is mapped for reading.
*/
-static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,
- const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder)
+static bool writeOptData(int fd, const DexClassLookup* pClassLookup,
+ const RegisterMapBuilder* pRegMapBuilder)
{
/* pre-computed class lookup hash table */
if (!writeChunk(fd, (u4) kDexChunkClassLookup,
return false;
}
- /* remapped constants (optional) */
- if (pIndexMapSet != NULL) {
- if (!writeChunk(fd, pIndexMapSet->chunkType,
- pIndexMapSet->chunkData, pIndexMapSet->chunkDataLen))
- {
- return false;
- }
- }
-
/* register maps (optional) */
if (pRegMapBuilder != NULL) {
if (!writeChunk(fd, (u4) kDexChunkRegisterMaps,
/*
* Update the Adler-32 checksum stored in the DEX file. This covers the
* swapped and optimized DEX data, but does not include the opt header
- * or auxillary data.
+ * or optimized data.
*/
static void updateChecksum(u1* addr, int len, DexHeader* pHeader)
{