void CDotOutput::simpleCall(const CModel* pModel) { std::ofstream os; os.open("CopasiDependencies.dot", std::ios::out); setSkipDependenciesOnCompartments(true); setOnlyAlgebraicDependencies(true); writeDependencies(os, pModel); os.close(); }
/* * Do the actual optimization. This is executed in the dexopt process. * * For best use of disk/memory, we want to extract once and perform * optimizations in place. If the file has to expand or contract * to match local structure padding/alignment expectations, we want * to do the rewrite as part of the extract, rather than extracting * into a temp file and slurping it back out. (The structure alignment * is currently correct for all platforms, and this isn't expected to * change, so we should be okay with having it already extracted.) * * Returns "true" on success. */ bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength, const char* fileName, u4 modWhen, u4 crc, bool isBootstrap) { DexClassLookup* pClassLookup = NULL; RegisterMapBuilder* pRegMapBuilder = NULL; u4 headerFlags = 0; assert(gDvm.optimizing); LOGV("Continuing optimization (%s, isb=%d)\n", fileName, isBootstrap); assert(dexOffset >= 0); /* quick test so we don't blow up on empty file */ if (dexLength < (int) sizeof(DexHeader)) { LOGE("too small to be DEX\n"); return false; } if (dexOffset < (int) sizeof(DexOptHeader)) { LOGE("not enough room for opt header\n"); return false; } bool result = false; /* * Drop this into a global so we don't have to pass it around. We could * also add a field to DexFile, but since it only pertains to DEX * creation that probably doesn't make sense. */ gDvm.optimizingBootstrapClass = isBootstrap; { /* * Map the entire file (so we don't have to worry about page * alignment). The expectation is that the output file contains * our DEX data plus room for a small header. */ bool success; void* mapAddr; mapAddr = mmap(NULL, dexOffset + dexLength, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (mapAddr == MAP_FAILED) { LOGE("unable to mmap DEX cache: %s\n", strerror(errno)); goto bail; } /* * Rewrite the file. Byte reordering, structure realigning, * class verification, and bytecode optimization are all performed * here. * * In theory the file could change size and bits could shift around. * In practice this would be annoying to deal with, so the file * layout is designed so that it can always be rewritten in place. * * This sets "headerFlags" and creates the class lookup table as * part of doing the processing. */ success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength, &headerFlags, &pClassLookup); if (success) { DvmDex* pDvmDex = NULL; u1* dexAddr = ((u1*) mapAddr) + dexOffset; if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) { LOGE("Unable to create DexFile\n"); success = false; } else { /* * 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. */ if (gDvm.generateRegisterMaps) { pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex); if (pRegMapBuilder == NULL) { LOGE("Failed generating register maps\n"); success = false; } } DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader; updateChecksum(dexAddr, dexLength, pHeader); dvmDexFileFree(pDvmDex); } } /* unmap the read-write version, forcing writes to disk */ if (msync(mapAddr, dexOffset + dexLength, MS_SYNC) != 0) { LOGW("msync failed: %s\n", strerror(errno)); // weird, but keep going } #if 1 /* * This causes clean shutdown to fail, because we have loaded classes * that point into it. For the optimizer this isn't a problem, * because it's more efficient for the process to simply exit. * Exclude this code when doing clean shutdown for valgrind. */ if (munmap(mapAddr, dexOffset + dexLength) != 0) { LOGE("munmap failed: %s\n", strerror(errno)); goto bail; } #endif if (!success) goto bail; } /* get start offset, and adjust deps start for 64-bit alignment */ off_t depsOffset, optOffset, endOffset, adjOffset; int depsLength, optLength; u4 optChecksum; depsOffset = lseek(fd, 0, SEEK_END); if (depsOffset < 0) { LOGE("lseek to EOF failed: %s\n", strerror(errno)); goto bail; } adjOffset = (depsOffset + 7) & ~(0x07); if (adjOffset != depsOffset) { LOGV("Adjusting deps start from %d to %d\n", (int) depsOffset, (int) adjOffset); depsOffset = adjOffset; lseek(fd, depsOffset, SEEK_SET); } /* * Append the dependency list. */ if (writeDependencies(fd, modWhen, crc) != 0) { LOGW("Failed writing dependencies\n"); goto bail; } /* compute deps length, then adjust opt start for 64-bit alignment */ optOffset = lseek(fd, 0, SEEK_END); depsLength = optOffset - depsOffset; 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 optimized pre-computed data structures. */ if (!writeOptData(fd, pClassLookup, pRegMapBuilder)) { LOGW("Failed writing opt data\n"); goto bail; } endOffset = lseek(fd, 0, SEEK_END); optLength = endOffset - optOffset; /* compute checksum from start of deps to end of opt area */ if (!computeFileChecksum(fd, depsOffset, (optOffset+optLength) - depsOffset, &optChecksum)) { goto bail; } /* * Output the "opt" header with all values filled in and a correct * magic number. */ DexOptHeader optHdr; memset(&optHdr, 0xff, sizeof(optHdr)); memcpy(optHdr.magic, DEX_OPT_MAGIC, 4); memcpy(optHdr.magic+4, DEX_OPT_MAGIC_VERS, 4); optHdr.dexOffset = (u4) dexOffset; optHdr.dexLength = (u4) dexLength; optHdr.depsOffset = (u4) depsOffset; optHdr.depsLength = (u4) depsLength; 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; LOGV("Successfully wrote DEX header\n"); result = true; //dvmRegisterMapDumpStats(); bail: dvmFreeRegisterMapBuilder(pRegMapBuilder); free(pClassLookup); return result; }