2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * VM-specific state associated with a DEX file.
24 * Create auxillary data structures.
26 * We need a 4-byte pointer for every reference to a class, method, field,
27 * or string constant. Summed up over all loaded DEX files (including the
28 * whoppers in the boostrap class path), this adds up to be quite a bit
31 * For more traditional VMs these values could be stuffed into the loaded
32 * class file constant pool area, but we don't have that luxury since our
33 * classes are memory-mapped read-only.
35 * The DEX optimizer will remove the need for some of these (e.g. we won't
36 * use the entry for virtual methods that are only called through
37 * invoke-virtual-quick), creating the possibility of some space reduction
40 static DvmDex* allocateAuxStructures(DexFile* pDexFile)
43 const DexHeader* pHeader;
44 u4 stringCount, classCount, methodCount, fieldCount;
46 pDvmDex = (DvmDex*) calloc(1, sizeof(DvmDex));
50 pDvmDex->pDexFile = pDexFile;
51 pDvmDex->pHeader = pDexFile->pHeader;
53 pHeader = pDvmDex->pHeader;
55 stringCount = pHeader->stringIdsSize;
56 classCount = pHeader->typeIdsSize;
57 methodCount = pHeader->methodIdsSize;
58 fieldCount = pHeader->fieldIdsSize;
60 #if (DVM_RESOLVER_CACHE == DVM_RC_REDUCING) || \
61 (DVM_RESOLVER_CACHE == DVM_RC_EXPANDING)
62 if (pDexFile->indexMap.stringReducedCount > 0)
63 stringCount = pDexFile->indexMap.stringReducedCount;
64 if (pDexFile->indexMap.classReducedCount > 0)
65 classCount = pDexFile->indexMap.classReducedCount;
66 if (pDexFile->indexMap.methodReducedCount > 0)
67 methodCount = pDexFile->indexMap.methodReducedCount;
68 if (pDexFile->indexMap.fieldReducedCount > 0)
69 fieldCount = pDexFile->indexMap.fieldReducedCount;
70 #elif (DVM_RESOLVER_CACHE == DVM_RC_NO_CACHE)
71 stringCount = classCount = methodCount = fieldCount = 0;
74 pDvmDex->pResStrings = (struct StringObject**)
75 calloc(stringCount, sizeof(struct StringObject*));
77 pDvmDex->pResClasses = (struct ClassObject**)
78 calloc(classCount, sizeof(struct ClassObject*));
80 pDvmDex->pResMethods = (struct Method**)
81 calloc(methodCount, sizeof(struct Method*));
83 pDvmDex->pResFields = (struct Field**)
84 calloc(fieldCount, sizeof(struct Field*));
86 LOGV("+++ DEX %p: allocateAux %d+%d+%d+%d * 4 = %d bytes\n",
87 pDvmDex, stringCount, classCount, methodCount, fieldCount,
88 (stringCount + classCount + methodCount + fieldCount) * 4);
90 pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE);
92 if (pDvmDex->pResStrings == NULL ||
93 pDvmDex->pResClasses == NULL ||
94 pDvmDex->pResMethods == NULL ||
95 pDvmDex->pResFields == NULL ||
96 pDvmDex->pInterfaceCache == NULL)
98 LOGE("Alloc failure in allocateAuxStructures\n");
99 free(pDvmDex->pResStrings);
100 free(pDvmDex->pResClasses);
101 free(pDvmDex->pResMethods);
102 free(pDvmDex->pResFields);
112 * Given an open optimized DEX file, map it into read-only shared memory and
113 * parse the contents.
115 * Returns nonzero on error.
117 int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex)
122 int parseFlags = kDexParseDefault;
125 if (gDvm.verifyDexChecksum)
126 parseFlags |= kDexParseVerifyChecksum;
128 if (lseek(fd, 0, SEEK_SET) < 0) {
129 LOGE("lseek rewind failed\n");
133 if (sysMapFileInShmemWritableReadOnly(fd, &memMap) != 0) {
134 LOGE("Unable to map file\n");
138 pDexFile = dexFileParse(memMap.addr, memMap.length, parseFlags);
139 if (pDexFile == NULL) {
140 LOGE("DEX parse failed\n");
141 sysReleaseShmem(&memMap);
145 pDvmDex = allocateAuxStructures(pDexFile);
146 if (pDvmDex == NULL) {
147 dexFileFree(pDexFile);
148 sysReleaseShmem(&memMap);
152 /* tuck this into the DexFile so it gets released later */
153 sysCopyMap(&pDvmDex->memMap, &memMap);
162 * Create a DexFile structure for a "partial" DEX. This is one that is in
163 * the process of being optimized. The optimization header isn't finished
164 * and we won't have any of the auxillary data tables, so we have to do
165 * the initialization slightly differently.
167 * Returns nonzero on error.
169 int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex)
173 int parseFlags = kDexParseDefault;
176 /* -- file is incomplete, new checksum has not yet been calculated
177 if (gDvm.verifyDexChecksum)
178 parseFlags |= kDexParseVerifyChecksum;
181 pDexFile = dexFileParse(addr, len, parseFlags);
182 if (pDexFile == NULL) {
183 LOGE("DEX parse failed\n");
186 pDvmDex = allocateAuxStructures(pDexFile);
187 if (pDvmDex == NULL) {
188 dexFileFree(pDexFile);
200 * Free up the DexFile and any associated data structures.
202 * Note we may be called with a partially-initialized DvmDex.
204 void dvmDexFileFree(DvmDex* pDvmDex)
209 dexFileFree(pDvmDex->pDexFile);
211 LOGV("+++ DEX %p: freeing aux structs\n", pDvmDex);
212 free(pDvmDex->pResStrings);
213 free(pDvmDex->pResClasses);
214 free(pDvmDex->pResMethods);
215 free(pDvmDex->pResFields);
216 dvmFreeAtomicCache(pDvmDex->pInterfaceCache);
218 sysReleaseShmem(&pDvmDex->memMap);
224 * Change the byte at the specified address to a new value. If the location
225 * already has the new value, do nothing.
227 * This requires changing the access permissions to read-write, updating
228 * the value, and then resetting the permissions.
230 * This does not make any synchronization guarantees. It's important for the
231 * caller(s) to work out mutual exclusion, at least on a page granularity,
232 * to avoid a race where one threads sets read-write, another thread sets
233 * read-only, and then the first thread does a write.
235 * TODO: if we're back to the original state of the page, use
236 * madvise(MADV_DONTNEED) to release the private/dirty copy.
238 * Returns "true" on success.
240 bool dvmDexChangeDex1(DvmDex* pDvmDex, u1* addr, u1 newVal)
242 if (*addr == newVal) {
243 LOGV("+++ byte at %p is already 0x%02x\n", addr, newVal);
247 LOGV("+++ change byte at %p from 0x%02x to 0x%02x\n", addr, *addr, newVal);
248 if (sysChangeMapAccess(addr, 1, true, &pDvmDex->memMap) != 0) {
249 LOGD("NOTE: DEX page access change (->RW) failed\n");
250 /* expected on files mounted from FAT; keep going (may crash) */
255 if (sysChangeMapAccess(addr, 1, false, &pDvmDex->memMap) != 0) {
256 LOGD("NOTE: DEX page access change (->RO) failed\n");
257 /* expected on files mounted from FAT; keep going */
264 * Change the 2-byte value at the specified address to a new value. If the
265 * location already has the new value, do nothing.
267 * Otherwise works like dvmDexChangeDex1.
269 bool dvmDexChangeDex2(DvmDex* pDvmDex, u2* addr, u2 newVal)
271 if (*addr == newVal) {
272 LOGV("+++ value at %p is already 0x%04x\n", addr, newVal);
276 LOGV("+++ change 2byte at %p from 0x%04x to 0x%04x\n", addr, *addr, newVal);
277 if (sysChangeMapAccess(addr, 2, true, &pDvmDex->memMap) != 0) {
278 LOGD("NOTE: DEX page access change (->RW) failed\n");
279 /* expected on files mounted from FAT; keep going (may crash) */
284 if (sysChangeMapAccess(addr, 2, false, &pDvmDex->memMap) != 0) {
285 LOGD("NOTE: DEX page access change (->RO) failed\n");
286 /* expected on files mounted from FAT; keep going */