OSDN Git Service

am e732bb04: am 1c7705b6: Merge change I96996494 into eclair-mr2
[android-x86/dalvik.git] / vm / DvmDex.c
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * VM-specific state associated with a DEX file.
19  */
20 #include "Dalvik.h"
21
22
23 /*
24  * Create auxillary data structures.
25  *
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
29  * of native memory.
30  *
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.
34  *
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
38  * at dexopt time.
39  */
40 static DvmDex* allocateAuxStructures(DexFile* pDexFile)
41 {
42     DvmDex* pDvmDex;
43     const DexHeader* pHeader;
44     u4 stringCount, classCount, methodCount, fieldCount;
45
46     pDvmDex = (DvmDex*) calloc(1, sizeof(DvmDex));
47     if (pDvmDex == NULL)
48         return NULL;
49
50     pDvmDex->pDexFile = pDexFile;
51     pDvmDex->pHeader = pDexFile->pHeader;
52
53     pHeader = pDvmDex->pHeader;
54
55     stringCount = pHeader->stringIdsSize;
56     classCount = pHeader->typeIdsSize;
57     methodCount = pHeader->methodIdsSize;
58     fieldCount = pHeader->fieldIdsSize;
59
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;
72 #endif
73
74     pDvmDex->pResStrings = (struct StringObject**)
75         calloc(stringCount, sizeof(struct StringObject*));
76
77     pDvmDex->pResClasses = (struct ClassObject**)
78         calloc(classCount, sizeof(struct ClassObject*));
79
80     pDvmDex->pResMethods = (struct Method**)
81         calloc(methodCount, sizeof(struct Method*));
82
83     pDvmDex->pResFields = (struct Field**)
84         calloc(fieldCount, sizeof(struct Field*));
85
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);
89
90     pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE);
91
92     if (pDvmDex->pResStrings == NULL ||
93         pDvmDex->pResClasses == NULL ||
94         pDvmDex->pResMethods == NULL ||
95         pDvmDex->pResFields == NULL ||
96         pDvmDex->pInterfaceCache == NULL)
97     {
98         LOGE("Alloc failure in allocateAuxStructures\n");
99         free(pDvmDex->pResStrings);
100         free(pDvmDex->pResClasses);
101         free(pDvmDex->pResMethods);
102         free(pDvmDex->pResFields);
103         free(pDvmDex);
104         return NULL;
105     }
106
107     return pDvmDex;
108
109 }
110
111 /*
112  * Given an open optimized DEX file, map it into read-only shared memory and
113  * parse the contents.
114  *
115  * Returns nonzero on error.
116  */
117 int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex)
118 {
119     DvmDex* pDvmDex;
120     DexFile* pDexFile;
121     MemMapping memMap;
122     int parseFlags = kDexParseDefault;
123     int result = -1;
124
125     if (gDvm.verifyDexChecksum)
126         parseFlags |= kDexParseVerifyChecksum;
127
128     if (lseek(fd, 0, SEEK_SET) < 0) {
129         LOGE("lseek rewind failed\n");
130         goto bail;
131     }
132
133     if (sysMapFileInShmemWritableReadOnly(fd, &memMap) != 0) {
134         LOGE("Unable to map file\n");
135         goto bail;
136     }
137
138     pDexFile = dexFileParse(memMap.addr, memMap.length, parseFlags);
139     if (pDexFile == NULL) {
140         LOGE("DEX parse failed\n");
141         sysReleaseShmem(&memMap);
142         goto bail;
143     }
144
145     pDvmDex = allocateAuxStructures(pDexFile);
146     if (pDvmDex == NULL) {
147         dexFileFree(pDexFile);
148         sysReleaseShmem(&memMap);
149         goto bail;
150     }
151
152     /* tuck this into the DexFile so it gets released later */
153     sysCopyMap(&pDvmDex->memMap, &memMap);
154     *ppDvmDex = pDvmDex;
155     result = 0;
156
157 bail:
158     return result;
159 }
160
161 /*
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.
166  *
167  * Returns nonzero on error.
168  */
169 int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex)
170 {
171     DvmDex* pDvmDex;
172     DexFile* pDexFile;
173     int parseFlags = kDexParseDefault;
174     int result = -1;
175
176     /* -- file is incomplete, new checksum has not yet been calculated
177     if (gDvm.verifyDexChecksum)
178         parseFlags |= kDexParseVerifyChecksum;
179     */
180
181     pDexFile = dexFileParse(addr, len, parseFlags);
182     if (pDexFile == NULL) {
183         LOGE("DEX parse failed\n");
184         goto bail;
185     }
186     pDvmDex = allocateAuxStructures(pDexFile);
187     if (pDvmDex == NULL) {
188         dexFileFree(pDexFile);
189         goto bail;
190     }
191
192     *ppDvmDex = pDvmDex;
193     result = 0;
194
195 bail:
196     return result;
197 }
198
199 /*
200  * Free up the DexFile and any associated data structures.
201  *
202  * Note we may be called with a partially-initialized DvmDex.
203  */
204 void dvmDexFileFree(DvmDex* pDvmDex)
205 {
206     if (pDvmDex == NULL)
207         return;
208
209     dexFileFree(pDvmDex->pDexFile);
210
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);
217
218     sysReleaseShmem(&pDvmDex->memMap);
219     free(pDvmDex);
220 }
221
222
223 /*
224  * Change the byte at the specified address to a new value.  If the location
225  * already has the new value, do nothing.
226  *
227  * This requires changing the access permissions to read-write, updating
228  * the value, and then resetting the permissions.
229  *
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.
234  *
235  * TODO: if we're back to the original state of the page, use
236  * madvise(MADV_DONTNEED) to release the private/dirty copy.
237  *
238  * Returns "true" on success.
239  */
240 bool dvmDexChangeDex1(DvmDex* pDvmDex, u1* addr, u1 newVal)
241 {
242     if (*addr == newVal) {
243         LOGV("+++ byte at %p is already 0x%02x\n", addr, newVal);
244         return true;
245     }
246
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) */
251     }
252
253     *addr = newVal;
254
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 */
258     }
259
260     return true;
261 }
262
263 /*
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.
266  *
267  * Otherwise works like dvmDexChangeDex1.
268  */
269 bool dvmDexChangeDex2(DvmDex* pDvmDex, u2* addr, u2 newVal)
270 {
271     if (*addr == newVal) {
272         LOGV("+++ value at %p is already 0x%04x\n", addr, newVal);
273         return true;
274     }
275
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) */
280     }
281
282     *addr = newVal;
283
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 */
287     }
288
289     return true;
290 }
291